|
@@ -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;
|
|
}
|
|
}
|