txlyre 2 weeks ago
parent
commit
6a08e1880b
2 changed files with 142 additions and 7 deletions
  1. 130 3
      qirt.c
  2. 12 4
      qirt.h

+ 130 - 3
qirt.c

@@ -874,6 +874,40 @@ qi_value_t *qi_make_data(qi_state_t *state, unsigned int tag, void *data) {
   return value;
   return value;
 }
 }
 
 
+qi_value_t *qi_make_ref(qi_state_t *state, char *name) {
+  qi_ssize_t scopes_count = qi_list_length(state->scopes);
+
+  qi_scope_t *r = NULL;
+
+  if (scopes_count > 0)
+    for (qi_ssize_t i = scopes_count - 1; i >= 0; i--) {
+      qi_scope_t *scope = qi_list_index(state->scopes, i);
+      if (scope->is_barrier)
+        continue;
+
+      qi_mutex_lock(scope->mutex);
+
+      qi_symbol_t *symbol = qi_table_get(scope->scope, name);
+
+      qi_mutex_unlock(scope->mutex);
+
+      if (symbol) {
+        r = scope;
+
+        break;
+      }
+    }
+
+  if (!r)
+    qi_throw_format(state, "reference to undefined symbol: '%s'", name);
+
+  qi_value_t *value = qi_make_value(QI_REFERENCE);
+  value->value.ref.name = name;
+  value->value.ref.scope = r;
+
+  return value;
+}
+
 static qi_value_t *qi_get_pseudomethod(qi_state_t *state, qi_value_t *value,
 static qi_value_t *qi_get_pseudomethod(qi_state_t *state, qi_value_t *value,
                                        char *name) {
                                        char *name) {
   qi_mutex_lock(state->pseudomethods_mutex);
   qi_mutex_lock(state->pseudomethods_mutex);
@@ -1264,6 +1298,11 @@ char *_qi_repr(qi_state_t *state, qi_list_t *tempstack, qi_value_t *value,
 
 
     return qi_strdup(string);
     return qi_strdup(string);
 
 
+  case QI_REFERENCE:
+    snprintf(string, sizeof(string), "<reference %s>", value->value.ref.name);
+
+    return qi_strdup(string);
+
   default:
   default:
     return qi_strdup("<unknown>");
     return qi_strdup("<unknown>");
   }
   }
@@ -1404,10 +1443,15 @@ qi_value_t *qi_find(qi_state_t *state, char *name) {
 
 
       qi_symbol_t *symbol = qi_table_get(scope->scope, name);
       qi_symbol_t *symbol = qi_table_get(scope->scope, name);
 
 
-      qi_mutex_unlock(scope->mutex);
+      if (symbol) {
+        qi_value_t *value = symbol->value;
 
 
-      if (symbol)
-        return symbol->value;
+        qi_mutex_unlock(scope->mutex);
+
+        return value;
+      }
+
+      qi_mutex_unlock(scope->mutex);
     }
     }
 
 
   return NULL;
   return NULL;
@@ -1549,6 +1593,85 @@ qi_value_t *_qi_set(qi_state_t *state, qi_bool is_pf, qi_bool is_constant,
   return value;
   return value;
 }
 }
 
 
+qi_value_t *qi_deref(qi_state_t *state, qi_value_t *value) {
+  qi_value_t *meta;
+  qi_bool fail = false;
+
+  if ((meta = qi_call_meta(state, &fail, value, "__deref", 1, value)))
+    return meta;
+
+  if (fail)
+    goto leave;
+
+  if (value->type == QI_REFERENCE) {
+    qi_mutex_lock(value->value.ref.scope->mutex);
+
+    qi_symbol_t *symbol = qi_table_get(value->value.ref.scope->scope, value->value.ref.name);
+    if (!symbol) {
+      qi_mutex_unlock(value->value.ref.scope->mutex);
+
+      qi_throw_format(state, "reference to undefined symbol: '%s'", value->value.ref.name);
+    }
+
+    qi_value_t *r = symbol->value;
+
+    qi_mutex_unlock(value->value.ref.scope->mutex);
+
+    return r;
+  }
+
+leave:
+  qi_throw_format(state, "cannot dereference %s", _qi_type(state, value));
+
+  return 0;
+}
+
+qi_value_t *qi_set_ref(qi_state_t *state, qi_bool is_pf, qi_value_t *ref, qi_value_t *value) {
+  qi_value_t *meta;
+  qi_bool fail = false;
+
+  if ((meta = qi_call_meta(state, &fail, ref, "__set_ref", 2, ref, value)))
+    return meta;
+
+  if (fail)
+    goto leave;
+
+  if (ref->type == QI_REFERENCE) {
+    qi_mutex_lock(ref->value.ref.scope->mutex);
+
+    qi_symbol_t *symbol = qi_table_get(ref->value.ref.scope->scope, ref->value.ref.name);
+
+    if (symbol) {
+      if (symbol->is_constant) {
+        qi_mutex_unlock(ref->value.ref.scope->mutex);
+
+        qi_throw_format(state, "redeclaration of constant symbol (by reference): '%s'",
+                        ref->value.ref.name);
+      }
+
+      qi_value_t *old = symbol->value;
+
+      symbol->value = value;
+
+      qi_mutex_unlock(ref->value.ref.scope->mutex);
+
+      return !is_pf ? old : value;
+    }
+
+    symbol = qi_malloc(sizeof(qi_symbol_t));
+    symbol->value = value;
+
+    qi_table_set(ref->value.ref.scope->scope, ref->value.ref.name, symbol);
+
+    qi_mutex_unlock(ref->value.ref.scope->mutex);
+  }
+
+leave:
+  qi_throw_format(state, "cannot set %s by reference", _qi_type(state, ref));
+
+  return 0;
+}
+
 size_t _qi_length(qi_state_t *state, qi_value_t *value) {
 size_t _qi_length(qi_state_t *state, qi_value_t *value) {
   qi_value_t *meta;
   qi_value_t *meta;
   qi_bool fail = false;
   qi_bool fail = false;
@@ -2418,6 +2541,10 @@ static qi_bool _qi_guarded_equals(qi_state_t *state, qi_size_t depth,
     return a->value.data.tag == b->value.data.tag &&
     return a->value.data.tag == b->value.data.tag &&
            a->value.data.data == b->value.data.data;
            a->value.data.data == b->value.data.data;
 
 
+  case QI_REFERENCE:
+    return strcmp(a->value.ref.name, b->value.ref.name) == 0 &&
+           a->value.ref.scope == b->value.ref.scope;
+
   default:
   default:
     return true;
     return true;
   }
   }

+ 12 - 4
qirt.h

@@ -91,16 +91,19 @@ typedef enum {
   QI_TABLE,
   QI_TABLE,
   QI_FUNCTION,
   QI_FUNCTION,
   QI_DATA,
   QI_DATA,
+  QI_REFERENCE,
 
 
   QI_OBJECT
   QI_OBJECT
 } qi_type_t;
 } qi_type_t;
 
 
-static const char qi_type_names[12][10] = {
+static const char qi_type_names[13][10] = {
     "nil",  "boolean", "number", "string",   "bytes", "file",
     "nil",  "boolean", "number", "string",   "bytes", "file",
-    "list", "tuple",   "table",  "function", "data",  "object"};
+    "list", "tuple",   "table",  "function", "data", "reference", "object"};
 
 
 #define qi_repr_type(type) (qi_type_names[(type)])
 #define qi_repr_type(type) (qi_type_names[(type)])
 
 
+typedef struct _qi_scope_t qi_scope_t;
+
 typedef struct _qi_state_t qi_state_t;
 typedef struct _qi_state_t qi_state_t;
 typedef struct _qi_value_t qi_value_t;
 typedef struct _qi_value_t qi_value_t;
 
 
@@ -147,6 +150,10 @@ struct _qi_value_t {
       unsigned int tag;
       unsigned int tag;
       void *data;
       void *data;
     } data;
     } data;
+    struct {
+      char *name;
+      qi_scope_t *scope;
+    } ref;
   } value;
   } value;
 };
 };
 
 
@@ -185,8 +192,6 @@ struct _qi_state_t {
   const char *_debug_data;
   const char *_debug_data;
 };
 };
 
 
-typedef struct _qi_scope_t qi_scope_t;
-
 struct _qi_scope_t {
 struct _qi_scope_t {
   qi_table_t *scope;
   qi_table_t *scope;
   qi_list_t *defers;
   qi_list_t *defers;
@@ -396,6 +401,7 @@ qi_value_t *qi_make_function(qi_state_t *state, char *name, qi_size_t pargc,
 qi_value_t *qi_make_builtin_function(qi_state_t *state, char *name,
 qi_value_t *qi_make_builtin_function(qi_state_t *state, char *name,
                                      qi_size_t pargc, qi_handle_t handle);
                                      qi_size_t pargc, qi_handle_t handle);
 qi_value_t *qi_make_data(qi_state_t *state, unsigned int tag, void *data);
 qi_value_t *qi_make_data(qi_state_t *state, unsigned int tag, void *data);
+qi_value_t *qi_make_ref(qi_state_t *state, char *name);
 qi_value_t *qi_add_pseudomethod(qi_state_t *state, char *name, qi_size_t pargc,
 qi_value_t *qi_add_pseudomethod(qi_state_t *state, char *name, qi_size_t pargc,
                                 qi_handle_t handle);
                                 qi_handle_t handle);
 qi_value_t *qi_get_method(qi_state_t *state, qi_value_t *value, char *name);
 qi_value_t *qi_get_method(qi_state_t *state, qi_value_t *value, char *name);
@@ -417,6 +423,8 @@ void qi_decl(qi_state_t *state, char *name, qi_value_t *value);
 qi_value_t *qi_decl_expr(qi_state_t *state, char *name, qi_value_t *value);
 qi_value_t *qi_decl_expr(qi_state_t *state, char *name, qi_value_t *value);
 qi_value_t *_qi_set(qi_state_t *state, qi_bool is_pf, qi_bool is_constant,
 qi_value_t *_qi_set(qi_state_t *state, qi_bool is_pf, qi_bool is_constant,
                     char *name, qi_value_t *value);
                     char *name, qi_value_t *value);
+qi_value_t *qi_deref(qi_state_t *state, qi_value_t *value);
+qi_value_t *qi_set_ref(qi_state_t *state, qi_bool is_pf, qi_value_t *ref, qi_value_t *value);
 size_t _qi_length(qi_state_t *state, qi_value_t *value);
 size_t _qi_length(qi_state_t *state, qi_value_t *value);
 qi_value_t *qi_del(qi_state_t *state, qi_value_t *value, qi_value_t *index);
 qi_value_t *qi_del(qi_state_t *state, qi_value_t *value, qi_value_t *index);
 qi_bool _qi_truthy(qi_state_t *state, qi_value_t *value);
 qi_bool _qi_truthy(qi_state_t *state, qi_value_t *value);