| @@ -78,6 +78,14 @@ enum l2_opcode { | |||
| */ | |||
| L2_OP_STACK_FRAME_SET, | |||
| /* | |||
| * Replace a value on the stack. | |||
| * Pop <key> | |||
| * Read <val> | |||
| * Assign <val> to stack frame | |||
| */ | |||
| L2_OP_STACK_FRAME_REPLACE, | |||
| /* | |||
| * Return from a function. | |||
| * NSPop | |||
| @@ -27,7 +27,6 @@ void l2_gen_rjmp(struct l2_generator *gen, l2_word len); | |||
| void l2_gen_pop(struct l2_generator *gen); | |||
| void l2_gen_push(struct l2_generator *gen, l2_word word); | |||
| void l2_gen_ret(struct l2_generator *gen); | |||
| void l2_gen_assignment(struct l2_generator *gen, char **ident); | |||
| void l2_gen_number(struct l2_generator *gen, double num); | |||
| void l2_gen_string(struct l2_generator *gen, char **str); | |||
| void l2_gen_atom(struct l2_generator *gen, char **ident); | |||
| @@ -38,6 +37,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_direct_array_lookup(struct l2_generator *gen, int number); | |||
| 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); | |||
| void l2_gen_func_call(struct l2_generator *gen); | |||
| #endif | |||
| @@ -16,6 +16,7 @@ enum l2_token_kind { | |||
| L2_TOK_DOT_NUMBER, | |||
| L2_TOK_COLON, | |||
| L2_TOK_COLON_EQ, | |||
| L2_TOK_EQUALS, | |||
| L2_TOK_EOL, | |||
| L2_TOK_EOF, | |||
| L2_TOK_NUMBER, | |||
| @@ -74,8 +74,9 @@ struct l2_vm_namespace { | |||
| l2_word data[]; | |||
| }; | |||
| void l2_vm_namespace_set(struct l2_vm_value *ns, l2_word key, l2_word val); | |||
| l2_word l2_vm_namespace_get(struct l2_vm *vm, struct l2_vm_value *ns, l2_word key); | |||
| void l2_vm_namespace_set(struct l2_vm_value *ns, l2_word key, l2_word val); | |||
| int l2_vm_namespace_replace(struct l2_vm *vm, struct l2_vm_value *ns, l2_word key, l2_word val); | |||
| struct l2_vm { | |||
| l2_word *ops; | |||
| @@ -54,13 +54,6 @@ void l2_gen_ret(struct l2_generator *gen) { | |||
| put(gen, L2_OP_RET); | |||
| } | |||
| void l2_gen_assignment(struct l2_generator *gen, char **ident) { | |||
| size_t atom_id = l2_strset_put(&gen->atomset, ident); | |||
| put(gen, L2_OP_PUSH); | |||
| put(gen, atom_id); | |||
| put(gen, L2_OP_STACK_FRAME_SET); | |||
| } | |||
| void l2_gen_number(struct l2_generator *gen, double num) { | |||
| uint64_t n; | |||
| memcpy(&n, &num, sizeof(num)); | |||
| @@ -159,6 +152,20 @@ void l2_gen_stack_frame_lookup(struct l2_generator *gen, char **ident) { | |||
| put(gen, L2_OP_STACK_FRAME_LOOKUP); | |||
| } | |||
| void l2_gen_stack_frame_set(struct l2_generator *gen, char **ident) { | |||
| size_t atom_id = l2_strset_put(&gen->atomset, ident); | |||
| put(gen, L2_OP_PUSH); | |||
| put(gen, atom_id); | |||
| put(gen, L2_OP_STACK_FRAME_SET); | |||
| } | |||
| void l2_gen_stack_frame_replace(struct l2_generator *gen, char **ident) { | |||
| size_t atom_id = l2_strset_put(&gen->atomset, ident); | |||
| put(gen, L2_OP_PUSH); | |||
| put(gen, atom_id); | |||
| put(gen, L2_OP_STACK_FRAME_REPLACE); | |||
| } | |||
| void l2_gen_func_call(struct l2_generator *gen) { | |||
| put(gen, L2_OP_FUNC_CALL); | |||
| } | |||
| @@ -67,6 +67,8 @@ const char *l2_token_kind_name(enum l2_token_kind kind) { | |||
| return "colon"; | |||
| case L2_TOK_COLON_EQ: | |||
| return "colon-equals"; | |||
| case L2_TOK_EQUALS: | |||
| return "equals"; | |||
| case L2_TOK_EOL: | |||
| return "end-of-line"; | |||
| case L2_TOK_EOF: | |||
| @@ -254,6 +256,7 @@ static void read_ident(struct l2_lexer *lexer, struct l2_token *tok) { | |||
| case ',': | |||
| case '.': | |||
| case ':': | |||
| case '=': | |||
| case ';': | |||
| case EOF: | |||
| tok->v.str[idx] = '\0'; | |||
| @@ -363,6 +366,11 @@ static void read_tok(struct l2_lexer *lexer, struct l2_token *tok) { | |||
| } | |||
| break; | |||
| case '=': | |||
| read_ch(lexer); | |||
| tok->kind = L2_TOK_EQUALS; | |||
| break; | |||
| case EOF: | |||
| tok->kind = L2_TOK_EOF; | |||
| break; | |||
| @@ -77,7 +77,7 @@ static int parse_function_literal_impl( | |||
| // The arguments array will be at the top of the stack | |||
| char *ident = malloc(2); | |||
| ident[0] = '$'; ident[1] = '\0'; | |||
| l2_gen_assignment(gen, &ident); | |||
| l2_gen_stack_frame_set(gen, &ident); | |||
| int first = 1; | |||
| while (1) { | |||
| @@ -277,6 +277,7 @@ static int parse_arg_level_expression( | |||
| while (1) { | |||
| struct l2_token *tok = l2_lexer_peek(lexer, 1); | |||
| struct l2_token *tok2 = l2_lexer_peek(lexer, 2); | |||
| struct l2_token *tok3 = l2_lexer_peek(lexer, 3); | |||
| if (tok->kind == L2_TOK_OPEN_PAREN && tok2->kind == L2_TOK_CLOSE_PAREN) { | |||
| l2_trace_scope("niladic func call"); | |||
| @@ -285,6 +286,21 @@ static int parse_arg_level_expression( | |||
| l2_gen_push(gen, 0); | |||
| l2_gen_func_call(gen); | |||
| } else if ( | |||
| tok->kind == L2_TOK_PERIOD && tok2->kind == L2_TOK_IDENT && | |||
| tok3->kind == L2_TOK_EQUALS) { | |||
| l2_trace_scope("namespace assign"); | |||
| l2_trace("ident '%s'", tok2->v.str); | |||
| char *ident = l2_token_extract_str(tok2); | |||
| l2_lexer_consume(lexer); // '.' | |||
| l2_lexer_consume(lexer); // ident | |||
| l2_lexer_consume(lexer); // equals | |||
| if (parse_expression(lexer, gen, err) < 0) { | |||
| return -1; | |||
| } | |||
| l2_gen_namespace_set(gen, &ident); | |||
| } else if (tok->kind == L2_TOK_PERIOD && tok2->kind == L2_TOK_IDENT) { | |||
| l2_trace_scope("namespace lookup"); | |||
| l2_trace("ident '%s'", tok2->v.str); | |||
| @@ -345,7 +361,19 @@ static int parse_expression( | |||
| return -1; | |||
| } | |||
| l2_gen_assignment(gen, &ident); | |||
| l2_gen_stack_frame_set(gen, &ident); | |||
| } else if (tok->kind == L2_TOK_IDENT && tok2->kind == L2_TOK_EQUALS) { | |||
| l2_trace_scope("replacement assign expression"); | |||
| l2_trace("ident '%s'", tok->v.str); | |||
| char *ident = l2_token_extract_str(tok); | |||
| l2_lexer_consume(lexer); // ident | |||
| l2_lexer_consume(lexer); // = | |||
| if (parse_expression(lexer, gen, err) < 0) { | |||
| return -1; | |||
| } | |||
| l2_gen_stack_frame_replace(gen, &ident); | |||
| } else { | |||
| if (parse_arg_level_expression(lexer, gen, err) < 0) { | |||
| return -1; | |||
| @@ -98,6 +98,15 @@ static l2_word get(struct l2_vm_namespace *ns, l2_word key) { | |||
| } | |||
| } | |||
| l2_word l2_vm_namespace_get(struct l2_vm *vm, struct l2_vm_value *v, l2_word key) { | |||
| l2_word ret = get(v->ns, key); | |||
| if (ret == 0 && v->extra.ns_parent != 0) { | |||
| return l2_vm_namespace_get(vm, &vm->values[v->extra.ns_parent], key); | |||
| } | |||
| return ret; | |||
| } | |||
| void l2_vm_namespace_set(struct l2_vm_value *v, l2_word key, l2_word val) { | |||
| if (val == 0) { | |||
| del(v->ns, key); | |||
| @@ -106,11 +115,21 @@ void l2_vm_namespace_set(struct l2_vm_value *v, l2_word key, l2_word val) { | |||
| } | |||
| } | |||
| l2_word l2_vm_namespace_get(struct l2_vm *vm, struct l2_vm_value *v, l2_word key) { | |||
| l2_word ret = get(v->ns, key); | |||
| if (ret == 0 && v->extra.ns_parent != 0) { | |||
| return l2_vm_namespace_get(vm, &vm->values[v->extra.ns_parent], key); | |||
| } | |||
| int l2_vm_namespace_replace(struct l2_vm *vm, struct l2_vm_value *v, l2_word key, l2_word val) { | |||
| if (val == 0) { | |||
| del(v->ns, key); | |||
| return 0; | |||
| } else { | |||
| l2_word ret = get(v->ns, key); | |||
| if (ret != 0) { | |||
| v->ns = set(v->ns, key, val); | |||
| return 0; | |||
| } | |||
| return ret; | |||
| if (v->extra.ns_parent == 0) { | |||
| return -1; | |||
| } | |||
| return l2_vm_namespace_replace(vm, &vm->values[v->extra.ns_parent], key, val); | |||
| } | |||
| } | |||
| @@ -299,11 +299,19 @@ void l2_vm_step(struct l2_vm *vm) { | |||
| case L2_OP_STACK_FRAME_SET: | |||
| { | |||
| l2_word key = vm->stack[vm->sptr - 1]; | |||
| l2_word val = vm->stack[vm->sptr - 2]; | |||
| l2_word key = vm->stack[--vm->sptr]; | |||
| l2_word val = vm->stack[vm->sptr - 1]; | |||
| struct l2_vm_value *ns = &vm->values[vm->nstack[vm->nsptr - 1]]; | |||
| l2_vm_namespace_set(ns, key, val); | |||
| vm->sptr -= 1; | |||
| } | |||
| break; | |||
| case L2_OP_STACK_FRAME_REPLACE: | |||
| { | |||
| l2_word key = vm->stack[--vm->sptr]; | |||
| l2_word val = vm->stack[vm->sptr - 1]; | |||
| struct l2_vm_value *ns = &vm->values[vm->nstack[vm->nsptr - 1]]; | |||
| l2_vm_namespace_replace(vm, ns, key, val); // TODO: error if returns -1 | |||
| } | |||
| break; | |||