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