|
|
@@ -1606,11 +1606,13 @@ qi_value_t *qi_deref(qi_state_t *state, qi_value_t *value) {
|
|
|
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);
|
|
|
+ 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_throw_format(state, "reference to undefined symbol: '%s'",
|
|
|
+ value->value.ref.name);
|
|
|
}
|
|
|
|
|
|
qi_value_t *r = symbol->value;
|
|
|
@@ -1626,7 +1628,8 @@ leave:
|
|
|
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 *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;
|
|
|
|
|
|
@@ -1639,13 +1642,15 @@ qi_value_t *qi_set_ref(qi_state_t *state, qi_bool is_pf, qi_value_t *ref, qi_val
|
|
|
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);
|
|
|
+ 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'",
|
|
|
+ qi_throw_format(state,
|
|
|
+ "redeclaration of constant symbol (by reference): '%s'",
|
|
|
ref->value.ref.name);
|
|
|
}
|
|
|
|
|
|
@@ -2132,16 +2137,41 @@ leave:
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
+qi_bool qi_is_iter(qi_state_t *state, qi_value_t *value) {
|
|
|
+ return qi_get_method(state, value, "__begin") != NULL &&
|
|
|
+ qi_get_method(state, value, "__next") != NULL &&
|
|
|
+ qi_get_method(state, value, "__end") != NULL;
|
|
|
+}
|
|
|
+
|
|
|
qi_value_t *qi_iter(qi_state_t *state, qi_value_t *value) {
|
|
|
+ if (qi_is_iter(state, value))
|
|
|
+ return qi_iter_begin(state, value);
|
|
|
+
|
|
|
qi_value_t *meta;
|
|
|
qi_bool fail = false;
|
|
|
- if ((meta = qi_call_meta(state, &fail, value, "__iter", 1, value)))
|
|
|
- return qi_iter(state, meta);
|
|
|
+ if ((meta = qi_call_meta(state, &fail, value, "__iter", 1, value))) {
|
|
|
+ if (!qi_is_iter(state, meta))
|
|
|
+ qi_throw_format(state, "__iter returned not an iterator (%s)",
|
|
|
+ _qi_type(state, meta));
|
|
|
+
|
|
|
+ return meta;
|
|
|
+ }
|
|
|
|
|
|
if (fail)
|
|
|
- qi_throw_format(state, "cannot iterate %s", _qi_type(state, value));
|
|
|
+ goto leave;
|
|
|
+
|
|
|
+ if (value->type == QI_LIST || value->type == QI_TUPLE ||
|
|
|
+ value->type == QI_BYTES || value->type == QI_TABLE) {
|
|
|
+ qi_list_t *pargs = qi_list_make_n(1);
|
|
|
+ qi_list_data(pargs, 0) = value;
|
|
|
+
|
|
|
+ return qi_call(state, state->listiterator, pargs);
|
|
|
+ }
|
|
|
|
|
|
- return qi_to_list(state, value);
|
|
|
+leave:
|
|
|
+ qi_throw_format(state, "cannot iterate %s", _qi_type(state, value));
|
|
|
+
|
|
|
+ return NULL;
|
|
|
}
|
|
|
|
|
|
qi_value_t *qi_index(qi_state_t *state, qi_value_t *value, qi_value_t *index) {
|
|
|
@@ -4316,12 +4346,31 @@ qi_value_t *qi_builtin_table(qi_state_t *state, qi_size_t pargc,
|
|
|
}
|
|
|
|
|
|
qi_value_t *qi_builtin_ref(qi_state_t *state, qi_size_t pargc,
|
|
|
- qi_list_t *pargs) {
|
|
|
+ qi_list_t *pargs) {
|
|
|
qi_value_t *a = qi_list_data(pargs, 0);
|
|
|
|
|
|
return qi_to_ref(state, a);
|
|
|
}
|
|
|
|
|
|
+qi_value_t *qi_builtin_iter(qi_state_t *state, qi_size_t pargc,
|
|
|
+ qi_list_t *pargs) {
|
|
|
+ qi_value_t *a = qi_list_data(pargs, 0);
|
|
|
+
|
|
|
+ return qi_iter(state, a);
|
|
|
+}
|
|
|
+
|
|
|
+qi_value_t *qi_builtin_iter_next(qi_state_t *state, qi_size_t pargc,
|
|
|
+ qi_list_t *pargs) {
|
|
|
+ qi_value_t *a = qi_list_data(pargs, 0);
|
|
|
+
|
|
|
+ if (!qi_is_iter(state, a))
|
|
|
+ qi_throw_format(state,
|
|
|
+ "expected first argument to be an iterator, but got: %s",
|
|
|
+ _qi_type(state, a));
|
|
|
+
|
|
|
+ return qi_iter_next(state, a);
|
|
|
+}
|
|
|
+
|
|
|
qi_value_t *qi_builtin_deref(qi_state_t *state, qi_size_t pargc,
|
|
|
qi_list_t *pargs) {
|
|
|
qi_value_t *a = qi_list_data(pargs, 0);
|
|
|
@@ -4567,6 +4616,8 @@ static void qi_state_setup(qi_state_t *state) {
|
|
|
qi_add_builtin(state, "tuple", 1, qi_builtin_tuple);
|
|
|
qi_add_builtin(state, "table", 1, qi_builtin_table);
|
|
|
qi_add_builtin(state, "ref", 1, qi_builtin_ref);
|
|
|
+ qi_add_builtin(state, "iter", 1, qi_builtin_iter);
|
|
|
+ qi_add_builtin(state, "iter_next", 1, qi_builtin_iter_next);
|
|
|
|
|
|
qi_add_builtin(state, "deref", 1, qi_builtin_deref);
|
|
|
qi_add_builtin(state, "ref_set", 2, qi_builtin_ref_set);
|
|
|
@@ -4585,6 +4636,8 @@ static void qi_state_setup(qi_state_t *state) {
|
|
|
state->_debug_data = NULL;
|
|
|
|
|
|
qi_init_std(state);
|
|
|
+
|
|
|
+ state->listiterator = qi_get(state, "ListIterator");
|
|
|
}
|
|
|
|
|
|
static void _qi_state_init(qi_state_t **state, qi_bool enable_debug) {
|