| L2_OP_NAMESPACE_LOOKUP, | 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> | * Pop <arr> | ||||
| * Assign <val> to <arr[<key>]> | |||||
| * Push <arr[<key>]> | |||||
| */ | */ | ||||
| L2_OP_ARRAY_LOOKUP, | 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> | * Read <arr> | ||||
| * Push <arr[<key>]> | |||||
| * Assign <val> to <arr[<key>]> | |||||
| */ | */ | ||||
| L2_OP_ARRAY_SET, | 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. | * Halt execution. | ||||
| */ | */ |
| void l2_gen_namespace_lookup(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_lookup(struct l2_generator *gen, int number); | ||||
| void l2_gen_array_set(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_lookup(struct l2_generator *gen, char **ident); | ||||
| void l2_gen_stack_frame_set(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); | void l2_gen_stack_frame_replace(struct l2_generator *gen, char **ident); |
| put(gen, 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) { | void l2_gen_stack_frame_lookup(struct l2_generator *gen, char **ident) { | ||||
| size_t atom_id = l2_strset_put(&gen->atomset, ident); | size_t atom_id = l2_strset_put(&gen->atomset, ident); | ||||
| put(gen, L2_OP_STACK_FRAME_LOOKUP); | put(gen, L2_OP_STACK_FRAME_LOOKUP); |
| l2_lexer_consume(lexer); // dot-number | l2_lexer_consume(lexer); // dot-number | ||||
| l2_gen_array_lookup(gen, 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 { | } else { | ||||
| break; | break; | ||||
| } | } |
| printf("ARRAY_SET %08x\n", ops[(*ptr)++]); | printf("ARRAY_SET %08x\n", ops[(*ptr)++]); | ||||
| return; | 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: | case L2_OP_HALT: | ||||
| printf("HALT\n"); | printf("HALT\n"); | ||||
| return; | return; |
| } | } | ||||
| break; | 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: | case L2_OP_HALT: | ||||
| break; | break; | ||||
| } | } |
| 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 |
| 100 | |||||
| [100 50 30] | |||||
| 30 | |||||
| what's up | |||||
| 100 |
| check("namespaces.l2"); | check("namespaces.l2"); | ||||
| check("arrays.l2"); | check("arrays.l2"); | ||||
| check("functions.l2"); | check("functions.l2"); | ||||
| check("dynamic-lookups.l2"); | |||||
| if (error_message != NULL) { | if (error_message != NULL) { | ||||
| free(error_message); | free(error_message); |