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