| @@ -149,20 +149,37 @@ enum l2_opcode { | |||
| L2_OP_NAMESPACE_LOOKUP, | |||
| /* | |||
| * Look up a value from an array; direct_array_lookup <key> | |||
| * Pop <val> | |||
| * Look up a value from an array; array_lookup <key> | |||
| * Pop <arr> | |||
| * Assign <val> to <arr[<key>]> | |||
| * Push <arr[<key>]> | |||
| */ | |||
| L2_OP_ARRAY_LOOKUP, | |||
| /* | |||
| * Set a value in an array; direct_array_set <key> | |||
| * Set a value in an array; array_set <key> | |||
| * Read <val> | |||
| * Read <arr> | |||
| * Push <arr[<key>]> | |||
| * Assign <val> to <arr[<key>]> | |||
| */ | |||
| L2_OP_ARRAY_SET, | |||
| /* | |||
| * Look up a runtime value in an array or object. | |||
| * Pop <key> | |||
| * Pop <container> | |||
| * Push <container[<key>]> | |||
| */ | |||
| L2_OP_DYNAMIC_LOOKUP, | |||
| /* | |||
| * Set a value in an array or object. | |||
| * Pop <val> | |||
| * Pop <key> | |||
| * Pop <arr> | |||
| * Assign <val> to <arr[<key>]> | |||
| */ | |||
| L2_OP_DYNAMIC_SET, | |||
| /* | |||
| * Halt execution. | |||
| */ | |||
| @@ -38,6 +38,8 @@ void l2_gen_namespace_set(struct l2_generator *gen, char **ident); | |||
| void l2_gen_namespace_lookup(struct l2_generator *gen, char **ident); | |||
| void l2_gen_array_lookup(struct l2_generator *gen, int number); | |||
| void l2_gen_array_set(struct l2_generator *gen, int number); | |||
| void l2_gen_dynamic_lookup(struct l2_generator *gen); | |||
| void l2_gen_dynamic_set(struct l2_generator *gen); | |||
| void l2_gen_stack_frame_lookup(struct l2_generator *gen, char **ident); | |||
| void l2_gen_stack_frame_set(struct l2_generator *gen, char **ident); | |||
| void l2_gen_stack_frame_replace(struct l2_generator *gen, char **ident); | |||
| @@ -142,6 +142,14 @@ void l2_gen_array_set(struct l2_generator *gen, int number) { | |||
| put(gen, number); | |||
| } | |||
| void l2_gen_dynamic_lookup(struct l2_generator *gen) { | |||
| put(gen, L2_OP_DYNAMIC_LOOKUP); | |||
| } | |||
| void l2_gen_dynamic_set(struct l2_generator *gen) { | |||
| put(gen, L2_OP_DYNAMIC_SET); | |||
| } | |||
| void l2_gen_stack_frame_lookup(struct l2_generator *gen, char **ident) { | |||
| size_t atom_id = l2_strset_put(&gen->atomset, ident); | |||
| put(gen, L2_OP_STACK_FRAME_LOOKUP); | |||
| @@ -327,6 +327,32 @@ static int parse_arg_level_expression( | |||
| l2_lexer_consume(lexer); // dot-number | |||
| l2_gen_array_lookup(gen, number); | |||
| } else if (tok->kind == L2_TOK_PERIOD && tok2->kind == L2_TOK_OPEN_PAREN) { | |||
| l2_trace_scope("dynamic lookup"); | |||
| l2_lexer_consume(lexer); // '.' | |||
| l2_lexer_consume(lexer); // '(' | |||
| if (parse_expression(lexer, gen, err) < 0) { | |||
| return -1; | |||
| } | |||
| if (l2_lexer_peek(lexer, 1)->kind != L2_TOK_CLOSE_PAREN) { | |||
| l2_parse_err(err, tok, "Expected '(', got %s", | |||
| l2_token_kind_name(tok->kind)); | |||
| return -1; | |||
| } | |||
| l2_lexer_consume(lexer); // ')' | |||
| if (l2_lexer_peek(lexer, 1)->kind == L2_TOK_EQUALS) { | |||
| l2_lexer_consume(lexer); // '=' | |||
| if (parse_expression(lexer, gen, err) < 0) { | |||
| return -1; | |||
| } | |||
| l2_gen_dynamic_set(gen); | |||
| } else { | |||
| l2_gen_dynamic_lookup(gen); | |||
| } | |||
| } else { | |||
| break; | |||
| } | |||
| @@ -211,6 +211,14 @@ void l2_vm_print_op(l2_word *ops, size_t opcount, size_t *ptr) { | |||
| printf("ARRAY_SET %08x\n", ops[(*ptr)++]); | |||
| return; | |||
| case L2_OP_DYNAMIC_LOOKUP: | |||
| printf("DYNAMIC_LOOKUP\n"); | |||
| return; | |||
| case L2_OP_DYNAMIC_SET: | |||
| printf("DYNAMIC_SET\n"); | |||
| return; | |||
| case L2_OP_HALT: | |||
| printf("HALT\n"); | |||
| return; | |||
| @@ -451,6 +451,55 @@ void l2_vm_step(struct l2_vm *vm) { | |||
| } | |||
| break; | |||
| case L2_OP_DYNAMIC_LOOKUP: | |||
| { | |||
| l2_word key_id = vm->stack[--vm->sptr]; | |||
| l2_word container_id = vm->stack[--vm->sptr]; | |||
| struct l2_vm_value *key = &vm->values[key_id]; | |||
| struct l2_vm_value *container = &vm->values[container_id]; | |||
| if ( | |||
| l2_vm_value_type(key) == L2_VAL_TYPE_REAL && | |||
| l2_vm_value_type(container) == L2_VAL_TYPE_ARRAY) { | |||
| // TODO: Error if out of bounds | |||
| vm->stack[vm->sptr++] = container->array->data[(size_t)key->real]; | |||
| } else if ( | |||
| l2_vm_value_type(key) == L2_VAL_TYPE_ATOM && | |||
| l2_vm_value_type(container) == L2_VAL_TYPE_NAMESPACE) { | |||
| // TODO: Error if out of bounds | |||
| vm->stack[vm->sptr++] = l2_vm_namespace_get(vm, container, key->atom); | |||
| } else { | |||
| // TODO: error | |||
| } | |||
| } | |||
| break; | |||
| case L2_OP_DYNAMIC_SET: | |||
| { | |||
| l2_word val = vm->stack[--vm->sptr]; | |||
| l2_word key_id = vm->stack[--vm->sptr]; | |||
| l2_word container_id = vm->stack[--vm->sptr]; | |||
| vm->stack[vm->sptr++] = val; | |||
| struct l2_vm_value *key = &vm->values[key_id]; | |||
| struct l2_vm_value *container = &vm->values[container_id]; | |||
| if ( | |||
| l2_vm_value_type(key) == L2_VAL_TYPE_REAL && | |||
| l2_vm_value_type(container) == L2_VAL_TYPE_ARRAY) { | |||
| // TODO: Error if out of bounds | |||
| container->array->data[(size_t)key->real] = val; | |||
| } else if ( | |||
| l2_vm_value_type(key) == L2_VAL_TYPE_ATOM && | |||
| l2_vm_value_type(container) == L2_VAL_TYPE_NAMESPACE) { | |||
| // TODO: Error if out of bounds | |||
| l2_vm_namespace_set(container, key->atom, val); | |||
| } else { | |||
| // TODO: error | |||
| } | |||
| } | |||
| break; | |||
| case L2_OP_HALT: | |||
| break; | |||
| } | |||
| @@ -0,0 +1,16 @@ | |||
| idx := 0 | |||
| arr := [100 20 30] | |||
| print arr.(idx) | |||
| arr.(+ idx 1) = 50 | |||
| print arr | |||
| print [10 20 30].(+ 1 1) | |||
| obj := {} | |||
| obj.('hello) = "what's up" | |||
| print obj.hello | |||
| get-ident := {'foo} | |||
| obj.(get-ident()) = 100 | |||
| print obj.foo | |||
| @@ -0,0 +1,5 @@ | |||
| 100 | |||
| [100 50 30] | |||
| 30 | |||
| what's up | |||
| 100 | |||
| @@ -132,6 +132,7 @@ describe(exaples) { | |||
| check("namespaces.l2"); | |||
| check("arrays.l2"); | |||
| check("functions.l2"); | |||
| check("dynamic-lookups.l2"); | |||
| if (error_message != NULL) { | |||
| free(error_message); | |||