| @@ -63,20 +63,21 @@ int main(int argc, char **argv) { | |||
| printf("Generated bytecode:\n"); | |||
| l2_vm_print_bytecode((l2_word *)w.mem, w.len / sizeof(l2_word)); | |||
| fprintf(stderr, "\n"); | |||
| printf("\n"); | |||
| struct l2_vm vm; | |||
| l2_vm_init(&vm, (void *)w.mem, w.len / sizeof(l2_word)); | |||
| step_through(&vm); | |||
| l2_vm_run(&vm); | |||
| free(w.mem); | |||
| printf("State after executing:\n"); | |||
| printf("State before GC:\n"); | |||
| l2_vm_print_state(&vm); | |||
| printf("\n"); | |||
| while (l2_vm_gc(&vm)); | |||
| printf("State after GC:\n"); | |||
| printf("\nState after GC:\n"); | |||
| l2_vm_print_state(&vm); | |||
| l2_vm_free(&vm); | |||
| @@ -30,6 +30,7 @@ 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); | |||
| 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_func_call(struct l2_generator *gen); | |||
| @@ -10,6 +10,7 @@ enum l2_token_kind { | |||
| L2_TOK_CLOSE_BRACE, | |||
| L2_TOK_OPEN_BRACKET, | |||
| L2_TOK_CLOSE_BRACKET, | |||
| L2_TOK_QUOT, | |||
| L2_TOK_COMMA, | |||
| L2_TOK_PERIOD, | |||
| L2_TOK_COLON_EQ, | |||
| @@ -49,7 +49,7 @@ struct l2_vm_array { | |||
| }; | |||
| struct l2_vm_namespace { | |||
| struct l2_vm_value *parent; | |||
| l2_word parent; | |||
| size_t len; | |||
| size_t size; | |||
| l2_word mask; | |||
| @@ -57,7 +57,7 @@ struct l2_vm_namespace { | |||
| }; | |||
| 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 { | |||
| l2_word *ops; | |||
| @@ -63,6 +63,13 @@ void l2_gen_number(struct l2_generator *gen, double num) { | |||
| 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) { | |||
| size_t id = l2_strset_get(&gen->stringset, *str); | |||
| if (id == 0) { | |||
| @@ -92,6 +99,7 @@ void l2_gen_string(struct l2_generator *gen, char **str) { | |||
| put(gen, len); | |||
| put(gen, L2_OP_ALLOC_BUFFER_STATIC); | |||
| } else { | |||
| free(*str); | |||
| struct l2_generator_string *s = &gen->strings[id - 1]; | |||
| put(gen, L2_OP_PUSH_2); | |||
| put(gen, s->pos); | |||
| @@ -34,6 +34,8 @@ const char *l2_token_kind_name(enum l2_token_kind kind) { | |||
| return "open-bracket"; | |||
| case L2_TOK_CLOSE_BRACKET: | |||
| return "close-bracket"; | |||
| case L2_TOK_QUOT: | |||
| return "single-quote"; | |||
| case L2_TOK_COMMA: | |||
| return "comma"; | |||
| case L2_TOK_PERIOD: | |||
| @@ -199,6 +201,7 @@ static void read_ident(struct l2_lexer *lexer, struct l2_token *tok) { | |||
| case '}': | |||
| case '[': | |||
| case ']': | |||
| case '\'': | |||
| case ',': | |||
| case '.': | |||
| case ':': | |||
| @@ -276,6 +279,11 @@ static void read_tok(struct l2_lexer *lexer, struct l2_token *tok) { | |||
| } while (peek_ch(lexer) == ';'); | |||
| break; | |||
| case '\'': | |||
| read_ch(lexer); | |||
| tok->kind = L2_TOK_QUOT; | |||
| break; | |||
| case ',': | |||
| read_ch(lexer); | |||
| tok->kind = L2_TOK_COMMA; | |||
| @@ -88,15 +88,15 @@ static int parse_function( | |||
| static int parse_sub_expression( | |||
| 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 *tok2 = l2_lexer_peek(lexer, 2); | |||
| if (tok->kind == L2_TOK_OPEN_PAREN) { | |||
| l2_lexer_consume(lexer); // ( | |||
| tok = l2_lexer_peek(lexer, 1); | |||
| tok2 = l2_lexer_peek(lexer, 2); | |||
| // 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); | |||
| l2_lexer_consume(lexer); // ident | |||
| l2_lexer_consume(lexer); // ) | |||
| @@ -128,6 +128,12 @@ static int parse_sub_expression( | |||
| l2_lexer_consume(lexer); // ident | |||
| l2_gen_namespace_lookup(gen, &ident); | |||
| 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) { | |||
| char *str = l2_token_extract_str(tok); | |||
| l2_lexer_consume(lexer); // string | |||
| @@ -90,26 +90,28 @@ static l2_word get(struct l2_vm_namespace *ns, l2_word key) { | |||
| for (l2_word i = 0; ; ++i) { | |||
| l2_word hash = (key + i) & ns->mask; | |||
| 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) { | |||
| 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) { | |||
| del(ns->data, key); | |||
| del(v->data, key); | |||
| } 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; | |||
| } | |||
| @@ -55,7 +55,13 @@ void l2_vm_print_val(struct l2_vm_value *val) { | |||
| } | |||
| 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; | |||
| @@ -52,7 +52,7 @@ static void gc_mark(struct l2_vm *vm, l2_word id) { | |||
| } else if (typ == L2_VAL_TYPE_NAMESPACE) { | |||
| gc_mark_namespace(vm, val); | |||
| } else if (typ == L2_VAL_TYPE_FUNCTION) { | |||
| gc_mark_namespace(vm, &vm->values[val->func.namespace]); | |||
| gc_mark(vm, val->func.namespace); | |||
| } | |||
| } | |||
| @@ -82,8 +82,8 @@ static void gc_mark_namespace(struct l2_vm *vm, struct l2_vm_value *val) { | |||
| 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); | |||
| } | |||
| } | |||
| @@ -248,7 +248,7 @@ void l2_vm_step(struct l2_vm *vm) { | |||
| vm->values[ns_id].flags = L2_VAL_TYPE_NAMESPACE; | |||
| vm->values[ns_id].data = calloc(1, sizeof(struct l2_vm_namespace)); | |||
| 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->iptr = func->func.pos; | |||
| @@ -265,7 +265,7 @@ void l2_vm_step(struct l2_vm *vm) { | |||
| { | |||
| l2_word key = vm->stack[vm->sptr - 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; | |||
| @@ -294,8 +294,7 @@ void l2_vm_step(struct l2_vm *vm) { | |||
| word = alloc_val(vm); | |||
| vm->values[word].flags = L2_VAL_TYPE_INTEGER; | |||
| vm->values[word].integer = vm->stack[--vm->sptr]; | |||
| vm->stack[vm->sptr] = word; | |||
| vm->sptr += 1; | |||
| vm->stack[vm->sptr++] = word; | |||
| break; | |||
| case L2_OP_ALLOC_INTEGER_64: | |||