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