printf("Generated bytecode:\n"); | printf("Generated bytecode:\n"); | ||||
l2_vm_print_bytecode((l2_word *)w.mem, w.len / sizeof(l2_word)); | l2_vm_print_bytecode((l2_word *)w.mem, w.len / sizeof(l2_word)); | ||||
fprintf(stderr, "\n"); | |||||
printf("\n"); | |||||
struct l2_vm vm; | struct l2_vm vm; | ||||
l2_vm_init(&vm, (void *)w.mem, w.len / sizeof(l2_word)); | l2_vm_init(&vm, (void *)w.mem, w.len / sizeof(l2_word)); | ||||
step_through(&vm); | |||||
l2_vm_run(&vm); | |||||
free(w.mem); | free(w.mem); | ||||
printf("State after executing:\n"); | |||||
printf("State before GC:\n"); | |||||
l2_vm_print_state(&vm); | l2_vm_print_state(&vm); | ||||
printf("\n"); | |||||
while (l2_vm_gc(&vm)); | while (l2_vm_gc(&vm)); | ||||
printf("State after GC:\n"); | |||||
printf("\nState after GC:\n"); | |||||
l2_vm_print_state(&vm); | l2_vm_print_state(&vm); | ||||
l2_vm_free(&vm); | l2_vm_free(&vm); |
void l2_gen_assignment(struct l2_generator *gen, char **ident); | 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_function(struct l2_generator *gen, l2_word pos); | void l2_gen_function(struct l2_generator *gen, l2_word pos); | ||||
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_func_call(struct l2_generator *gen); | void l2_gen_func_call(struct l2_generator *gen); |
L2_TOK_CLOSE_BRACE, | L2_TOK_CLOSE_BRACE, | ||||
L2_TOK_OPEN_BRACKET, | L2_TOK_OPEN_BRACKET, | ||||
L2_TOK_CLOSE_BRACKET, | L2_TOK_CLOSE_BRACKET, | ||||
L2_TOK_QUOT, | |||||
L2_TOK_COMMA, | L2_TOK_COMMA, | ||||
L2_TOK_PERIOD, | L2_TOK_PERIOD, | ||||
L2_TOK_COLON_EQ, | L2_TOK_COLON_EQ, |
}; | }; | ||||
struct l2_vm_namespace { | struct l2_vm_namespace { | ||||
struct l2_vm_value *parent; | |||||
l2_word parent; | |||||
size_t len; | size_t len; | ||||
size_t size; | size_t size; | ||||
l2_word mask; | l2_word mask; | ||||
}; | }; | ||||
void l2_vm_namespace_set(struct l2_vm_value *ns, l2_word key, l2_word val); | 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_value *ns, l2_word key); | |||||
l2_word l2_vm_namespace_get(struct l2_vm *vm, struct l2_vm_value *ns, l2_word key); | |||||
struct l2_vm { | struct l2_vm { | ||||
l2_word *ops; | l2_word *ops; |
put(gen, L2_OP_ALLOC_REAL_64); | put(gen, L2_OP_ALLOC_REAL_64); | ||||
} | } | ||||
void l2_gen_atom(struct l2_generator *gen, char **str) { | |||||
size_t id = l2_strset_put(&gen->atomset, str); | |||||
put(gen, L2_OP_PUSH); | |||||
put(gen, id); | |||||
put(gen, L2_OP_ALLOC_INTEGER_32); | |||||
} | |||||
void l2_gen_string(struct l2_generator *gen, char **str) { | void l2_gen_string(struct l2_generator *gen, char **str) { | ||||
size_t id = l2_strset_get(&gen->stringset, *str); | size_t id = l2_strset_get(&gen->stringset, *str); | ||||
if (id == 0) { | if (id == 0) { | ||||
put(gen, len); | put(gen, len); | ||||
put(gen, L2_OP_ALLOC_BUFFER_STATIC); | put(gen, L2_OP_ALLOC_BUFFER_STATIC); | ||||
} else { | } else { | ||||
free(*str); | |||||
struct l2_generator_string *s = &gen->strings[id - 1]; | struct l2_generator_string *s = &gen->strings[id - 1]; | ||||
put(gen, L2_OP_PUSH_2); | put(gen, L2_OP_PUSH_2); | ||||
put(gen, s->pos); | put(gen, s->pos); |
return "open-bracket"; | return "open-bracket"; | ||||
case L2_TOK_CLOSE_BRACKET: | case L2_TOK_CLOSE_BRACKET: | ||||
return "close-bracket"; | return "close-bracket"; | ||||
case L2_TOK_QUOT: | |||||
return "single-quote"; | |||||
case L2_TOK_COMMA: | case L2_TOK_COMMA: | ||||
return "comma"; | return "comma"; | ||||
case L2_TOK_PERIOD: | case L2_TOK_PERIOD: | ||||
case '}': | case '}': | ||||
case '[': | case '[': | ||||
case ']': | case ']': | ||||
case '\'': | |||||
case ',': | case ',': | ||||
case '.': | case '.': | ||||
case ':': | case ':': | ||||
} while (peek_ch(lexer) == ';'); | } while (peek_ch(lexer) == ';'); | ||||
break; | break; | ||||
case '\'': | |||||
read_ch(lexer); | |||||
tok->kind = L2_TOK_QUOT; | |||||
break; | |||||
case ',': | case ',': | ||||
read_ch(lexer); | read_ch(lexer); | ||||
tok->kind = L2_TOK_COMMA; | tok->kind = L2_TOK_COMMA; |
static int parse_sub_expression( | static int parse_sub_expression( | ||||
struct l2_lexer *lexer, struct l2_generator *gen, struct l2_parse_error *err) { | struct l2_lexer *lexer, struct l2_generator *gen, struct l2_parse_error *err) { | ||||
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); | |||||
if (tok->kind == L2_TOK_OPEN_PAREN) { | if (tok->kind == L2_TOK_OPEN_PAREN) { | ||||
l2_lexer_consume(lexer); // ( | l2_lexer_consume(lexer); // ( | ||||
tok = l2_lexer_peek(lexer, 1); | tok = l2_lexer_peek(lexer, 1); | ||||
tok2 = l2_lexer_peek(lexer, 2); | |||||
// Special case: (foo) should be interpreted as a function call | // Special case: (foo) should be interpreted as a function call | ||||
if ( | |||||
tok->kind == L2_TOK_IDENT && | |||||
l2_lexer_peek(lexer, 2)->kind == L2_TOK_CLOSE_PAREN) { | |||||
if (tok->kind == L2_TOK_IDENT && tok2->kind == L2_TOK_CLOSE_PAREN) { | |||||
char *ident = l2_token_extract_str(tok); | char *ident = l2_token_extract_str(tok); | ||||
l2_lexer_consume(lexer); // ident | l2_lexer_consume(lexer); // ident | ||||
l2_lexer_consume(lexer); // ) | l2_lexer_consume(lexer); // ) | ||||
l2_lexer_consume(lexer); // ident | l2_lexer_consume(lexer); // ident | ||||
l2_gen_namespace_lookup(gen, &ident); | l2_gen_namespace_lookup(gen, &ident); | ||||
return 0; | return 0; | ||||
} else if (tok->kind == L2_TOK_QUOT && tok2->kind == L2_TOK_IDENT) { | |||||
char *str = l2_token_extract_str(tok2); | |||||
l2_lexer_consume(lexer); // ' | |||||
l2_lexer_consume(lexer); // ident | |||||
l2_gen_atom(gen, &str); | |||||
return 0; | |||||
} else if (tok->kind == L2_TOK_STRING) { | } else if (tok->kind == L2_TOK_STRING) { | ||||
char *str = l2_token_extract_str(tok); | char *str = l2_token_extract_str(tok); | ||||
l2_lexer_consume(lexer); // string | l2_lexer_consume(lexer); // string |
for (l2_word i = 0; ; ++i) { | for (l2_word i = 0; ; ++i) { | ||||
l2_word hash = (key + i) & ns->mask; | l2_word hash = (key + i) & ns->mask; | ||||
l2_word k = ns->data[hash]; | l2_word k = ns->data[hash]; | ||||
if (k == 0) { | |||||
if (ns->parent == NULL) { | |||||
return 0; | |||||
} else { | |||||
return get(ns->parent->data, key); | |||||
} | |||||
if (k == 0 || k == tombstone) { | |||||
return 0; | |||||
} else if (k == key) { | } else if (k == key) { | ||||
return ns->data[ns->size + hash]; | return ns->data[ns->size + hash]; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
void l2_vm_namespace_set(struct l2_vm_value *ns, 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(ns->data, key); | |||||
del(v->data, key); | |||||
} else { | } else { | ||||
ns->data = set(ns->data, key, val); | |||||
v->data = set(v->data, key, val); | |||||
} | } | ||||
} | } | ||||
l2_word l2_vm_namespace_get(struct l2_vm_value *ns, l2_word key) { | |||||
return get(ns->data, key); | |||||
l2_word l2_vm_namespace_get(struct l2_vm *vm, struct l2_vm_value *v, l2_word key) { | |||||
struct l2_vm_namespace *ns = v->data; | |||||
l2_word ret = get(ns, key); | |||||
if (ret == 0 && ns != NULL && ns->parent != 0) { | |||||
return l2_vm_namespace_get(vm, &vm->values[ns->parent], key); | |||||
} | |||||
return ret; | |||||
} | } |
} | } | ||||
struct l2_vm_namespace *ns = (struct l2_vm_namespace *)val->data; | struct l2_vm_namespace *ns = (struct l2_vm_namespace *)val->data; | ||||
printf("NAMESPACE, len %zu\n", ns->len); | |||||
printf("NAMESPACE, len %zu, parent %u\n", ns->len, ns->parent); | |||||
for (size_t i = 0; i < ns->size; ++i) { | |||||
l2_word key = ns->data[i]; | |||||
l2_word val = ns->data[ns->size + i]; | |||||
if (key == 0 || key == ~(l2_word)0) continue; | |||||
printf(" %u: %u\n", key, val); | |||||
} | |||||
} | } | ||||
break; | break; | ||||
} else if (typ == L2_VAL_TYPE_NAMESPACE) { | } else if (typ == L2_VAL_TYPE_NAMESPACE) { | ||||
gc_mark_namespace(vm, val); | gc_mark_namespace(vm, val); | ||||
} else if (typ == L2_VAL_TYPE_FUNCTION) { | } else if (typ == L2_VAL_TYPE_FUNCTION) { | ||||
gc_mark_namespace(vm, &vm->values[val->func.namespace]); | |||||
gc_mark(vm, val->func.namespace); | |||||
} | } | ||||
} | } | ||||
gc_mark(vm, ns->data[ns->size + i]); | gc_mark(vm, ns->data[ns->size + i]); | ||||
} | } | ||||
if (ns->parent != NULL) { | |||||
gc_mark_namespace(vm, ns->parent); | |||||
if (ns->parent != 0) { | |||||
gc_mark(vm, ns->parent); | |||||
} | } | ||||
} | } | ||||
vm->values[ns_id].flags = L2_VAL_TYPE_NAMESPACE; | vm->values[ns_id].flags = L2_VAL_TYPE_NAMESPACE; | ||||
vm->values[ns_id].data = calloc(1, sizeof(struct l2_vm_namespace)); | vm->values[ns_id].data = calloc(1, sizeof(struct l2_vm_namespace)); | ||||
struct l2_vm_namespace *ns = vm->values[ns_id].data; | struct l2_vm_namespace *ns = vm->values[ns_id].data; | ||||
ns->parent = &vm->values[func->func.namespace]; // TODO: This won't work if values is realloc'd | |||||
ns->parent = func->func.namespace; | |||||
vm->nstack[vm->nsptr++] = ns_id; | vm->nstack[vm->nsptr++] = ns_id; | ||||
vm->iptr = func->func.pos; | vm->iptr = func->func.pos; | ||||
{ | { | ||||
l2_word key = vm->stack[vm->sptr - 1]; | l2_word key = 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]]; | ||||
vm->stack[vm->sptr - 1] = l2_vm_namespace_get(ns, key); | |||||
vm->stack[vm->sptr - 1] = l2_vm_namespace_get(vm, ns, key); | |||||
} | } | ||||
break; | break; | ||||
word = alloc_val(vm); | word = alloc_val(vm); | ||||
vm->values[word].flags = L2_VAL_TYPE_INTEGER; | vm->values[word].flags = L2_VAL_TYPE_INTEGER; | ||||
vm->values[word].integer = vm->stack[--vm->sptr]; | vm->values[word].integer = vm->stack[--vm->sptr]; | ||||
vm->stack[vm->sptr] = word; | |||||
vm->sptr += 1; | |||||
vm->stack[vm->sptr++] = word; | |||||
break; | break; | ||||
case L2_OP_ALLOC_INTEGER_64: | case L2_OP_ALLOC_INTEGER_64: |