*/ | */ | ||||
L2_OP_STACK_FRAME_SET, | 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. | * Return from a function. | ||||
* NSPop | * NSPop |
void l2_gen_pop(struct l2_generator *gen); | void l2_gen_pop(struct l2_generator *gen); | ||||
void l2_gen_push(struct l2_generator *gen, l2_word word); | void l2_gen_push(struct l2_generator *gen, l2_word word); | ||||
void l2_gen_ret(struct l2_generator *gen); | 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_number(struct l2_generator *gen, double num); | ||||
void l2_gen_string(struct l2_generator *gen, char **str); | void l2_gen_string(struct l2_generator *gen, char **str); | ||||
void l2_gen_atom(struct l2_generator *gen, char **ident); | void l2_gen_atom(struct l2_generator *gen, char **ident); | ||||
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_direct_array_lookup(struct l2_generator *gen, int number); | 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_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); | void l2_gen_func_call(struct l2_generator *gen); | ||||
#endif | #endif |
L2_TOK_DOT_NUMBER, | L2_TOK_DOT_NUMBER, | ||||
L2_TOK_COLON, | L2_TOK_COLON, | ||||
L2_TOK_COLON_EQ, | L2_TOK_COLON_EQ, | ||||
L2_TOK_EQUALS, | |||||
L2_TOK_EOL, | L2_TOK_EOL, | ||||
L2_TOK_EOF, | L2_TOK_EOF, | ||||
L2_TOK_NUMBER, | L2_TOK_NUMBER, |
l2_word data[]; | 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); | 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 { | struct l2_vm { | ||||
l2_word *ops; | l2_word *ops; |
put(gen, L2_OP_RET); | 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) { | void l2_gen_number(struct l2_generator *gen, double num) { | ||||
uint64_t n; | uint64_t n; | ||||
memcpy(&n, &num, sizeof(num)); | memcpy(&n, &num, sizeof(num)); | ||||
put(gen, L2_OP_STACK_FRAME_LOOKUP); | 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) { | void l2_gen_func_call(struct l2_generator *gen) { | ||||
put(gen, L2_OP_FUNC_CALL); | put(gen, L2_OP_FUNC_CALL); | ||||
} | } |
return "colon"; | return "colon"; | ||||
case L2_TOK_COLON_EQ: | case L2_TOK_COLON_EQ: | ||||
return "colon-equals"; | return "colon-equals"; | ||||
case L2_TOK_EQUALS: | |||||
return "equals"; | |||||
case L2_TOK_EOL: | case L2_TOK_EOL: | ||||
return "end-of-line"; | return "end-of-line"; | ||||
case L2_TOK_EOF: | case L2_TOK_EOF: | ||||
case ',': | case ',': | ||||
case '.': | case '.': | ||||
case ':': | case ':': | ||||
case '=': | |||||
case ';': | case ';': | ||||
case EOF: | case EOF: | ||||
tok->v.str[idx] = '\0'; | tok->v.str[idx] = '\0'; | ||||
} | } | ||||
break; | break; | ||||
case '=': | |||||
read_ch(lexer); | |||||
tok->kind = L2_TOK_EQUALS; | |||||
break; | |||||
case EOF: | case EOF: | ||||
tok->kind = L2_TOK_EOF; | tok->kind = L2_TOK_EOF; | ||||
break; | break; |
// The arguments array will be at the top of the stack | // The arguments array will be at the top of the stack | ||||
char *ident = malloc(2); | char *ident = malloc(2); | ||||
ident[0] = '$'; ident[1] = '\0'; | ident[0] = '$'; ident[1] = '\0'; | ||||
l2_gen_assignment(gen, &ident); | |||||
l2_gen_stack_frame_set(gen, &ident); | |||||
int first = 1; | int first = 1; | ||||
while (1) { | while (1) { | ||||
while (1) { | while (1) { | ||||
struct l2_token *tok = l2_lexer_peek(lexer, 1); | struct l2_token *tok = l2_lexer_peek(lexer, 1); | ||||
struct l2_token *tok2 = l2_lexer_peek(lexer, 2); | 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) { | if (tok->kind == L2_TOK_OPEN_PAREN && tok2->kind == L2_TOK_CLOSE_PAREN) { | ||||
l2_trace_scope("niladic func call"); | l2_trace_scope("niladic func call"); | ||||
l2_gen_push(gen, 0); | l2_gen_push(gen, 0); | ||||
l2_gen_func_call(gen); | 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) { | } else if (tok->kind == L2_TOK_PERIOD && tok2->kind == L2_TOK_IDENT) { | ||||
l2_trace_scope("namespace lookup"); | l2_trace_scope("namespace lookup"); | ||||
l2_trace("ident '%s'", tok2->v.str); | l2_trace("ident '%s'", tok2->v.str); | ||||
return -1; | 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 { | } else { | ||||
if (parse_arg_level_expression(lexer, gen, err) < 0) { | if (parse_arg_level_expression(lexer, gen, err) < 0) { | ||||
return -1; | return -1; |
} | } | ||||
} | } | ||||
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) { | void l2_vm_namespace_set(struct l2_vm_value *v, l2_word key, l2_word val) { | ||||
if (val == 0) { | if (val == 0) { | ||||
del(v->ns, key); | del(v->ns, 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); | |||||
} | |||||
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); | |||||
} | |||||
} | } |
case L2_OP_STACK_FRAME_SET: | 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]]; | struct l2_vm_value *ns = &vm->values[vm->nstack[vm->nsptr - 1]]; | ||||
l2_vm_namespace_set(ns, key, val); | 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; | break; | ||||