From 7468605289a74761c5d8d5b3d0e0f2916b44d44c Mon Sep 17 00:00:00 2001 From: bog Date: Wed, 3 Apr 2024 06:28:03 +0200 Subject: [PATCH] :sparkles: :bug: function now on the heap. --- features/fun.sk | 17 +++++++++++++++++ lib/include/compiler.h | 1 + lib/include/prog.h | 2 +- lib/include/state.h | 5 +++++ lib/include/value.h | 3 ++- lib/src/compiler.c | 18 ++++++++++++++++++ lib/src/exec.c | 22 ++++++++++++++++++---- lib/src/fun.c | 1 - lib/src/state.c | 41 ++++++++++++++++++++++++++++++++++++++++- lib/src/value.c | 10 ++++++++++ 10 files changed, 112 insertions(+), 8 deletions(-) diff --git a/features/fun.sk b/features/fun.sk index 88288db..99ca495 100644 --- a/features/fun.sk +++ b/features/fun.sk @@ -26,3 +26,20 @@ var d = fun(x) end assert d(3) eq 5 + +var e = fun(n) + if n == 0 + 1 + else + n * e(n - 1) + end +end + +assert e(5) eq 120 + +var f = fun(x, n) + x(x(n)) +end + +assert f(fun(x) x * 2 end, 2) eq 8 + diff --git a/lib/include/compiler.h b/lib/include/compiler.h index e1071ab..f4ab2ce 100644 --- a/lib/include/compiler.h +++ b/lib/include/compiler.h @@ -7,6 +7,7 @@ struct compiler { + struct vec var_names; }; void compiler_init(struct compiler* self); diff --git a/lib/include/prog.h b/lib/include/prog.h index 36cdd9e..b255d85 100644 --- a/lib/include/prog.h +++ b/lib/include/prog.h @@ -13,7 +13,7 @@ G(OP_USUB), G(OP_ASSERT_EQ), \ G(OP_NOT), G(OP_AND), G(OP_OR), \ G(OP_BR), G(OP_BRF), G(OP_LT), G(OP_GT), \ G(OP_EQUAL), G(OP_LOCAL_STORE), G(OP_LOCAL_LOAD), \ -G(OP_CALL), G(OP_RET) +G(OP_CALL), G(OP_RET), G(OP_MAKE_REF) SK_ENUM_H(Opcode, OPCODE); diff --git a/lib/include/state.h b/lib/include/state.h index a74f901..5440cc8 100644 --- a/lib/include/state.h +++ b/lib/include/state.h @@ -30,6 +30,7 @@ struct state { struct vec frames; size_t addr; + struct vec globals; }; void stack_value_init(struct stack_value* self, @@ -44,6 +45,9 @@ void frame_free(struct frame* self); void state_init(struct state* self); void state_free(struct state* self); +SK state_make_ref(struct state* self); +struct value* state_try_deref(struct state* self, size_t ref); + struct frame* state_frame(struct state* self); void state_push_frame(struct state* self); void state_pop_frame(struct state* self); @@ -64,6 +68,7 @@ SK state_push_bool(struct state* self, bool boolean, int line); SK state_push_float(struct state* self, double real, int line); SK state_push_string(struct state* self, char const* str, int line); SK state_push_fun(struct state* self, struct fun* fun, int line); +SK state_push_ref(struct state* self, size_t ref, int line); struct local* state_try_get_local(struct state* self, int id); diff --git a/lib/include/value.h b/lib/include/value.h index 0380282..46911e8 100644 --- a/lib/include/value.h +++ b/lib/include/value.h @@ -7,7 +7,7 @@ #define TYPE_KIND(G) \ G(TYPE_INT), G(TYPE_BOOL), G(TYPE_FLOAT), \ -G(TYPE_STRING), G(TYPE_FUN) +G(TYPE_STRING), G(TYPE_FUN), G(TYPE_REF) SK_ENUM_H(TypeKind, TYPE_KIND); @@ -18,6 +18,7 @@ union val bool boolean; char* str; struct fun* fun; + size_t ref; }; struct value diff --git a/lib/src/compiler.c b/lib/src/compiler.c index 4d23e18..c12ee52 100644 --- a/lib/src/compiler.c +++ b/lib/src/compiler.c @@ -4,11 +4,13 @@ void compiler_init(struct compiler* self) { assert(self); + vec_init(&self->var_names); } void compiler_free(struct compiler* self) { assert(self); + vec_free(&self->var_names); } void compiler_compile(struct compiler* self, @@ -90,6 +92,8 @@ void compiler_compile(struct compiler* self, case NODE_VAR_DECL: { struct node* ident = node->children.data[0]; + vec_push(&self->var_names, strdup(ident->token->value)); + struct symbol const* s = sym_try_get(sym, ident->token->value); if (s && s->env == sym->env) @@ -102,10 +106,13 @@ void compiler_compile(struct compiler* self, compiler_compile(self, expr, prog, sym); int id = sym_decl_var(sym, ident->token->value); prog_add_instr(prog, OP_LOCAL_STORE, id); + char* name = vec_pop(&self->var_names); + free(name); } break; case NODE_CONST_DECL: { struct node* ident = node->children.data[0]; + vec_push(&self->var_names, strdup(ident->token->value)); struct symbol const* s = sym_try_get(sym, ident->token->value); if (s && s->env == sym->env) { @@ -116,6 +123,8 @@ void compiler_compile(struct compiler* self, compiler_compile(self, expr, prog, sym); int id = sym_decl_const(sym, ident->token->value); prog_add_instr(prog, OP_LOCAL_STORE, id); + char* name = vec_pop(&self->var_names); + free(name); } break; case NODE_ASSIGN: { @@ -164,6 +173,10 @@ void compiler_compile(struct compiler* self, struct sym mysym; sym_init(&mysym); + char* var_name = + self->var_names.size > 0 ? + self->var_names.data[self->var_names.size - 1] + : NULL; for (size_t i=0; ichildren.size; i++) { @@ -172,6 +185,10 @@ void compiler_compile(struct compiler* self, sym_decl_var(&mysym, name); } + if (var_name) + { + sym_decl_var(&mysym, var_name); + } compiler_compile(self, body, p, &mysym); sym_free(&mysym); fun_init(fun, p); @@ -180,6 +197,7 @@ void compiler_compile(struct compiler* self, val.fun = fun; compiler_compile_value(self, node, prog, TYPE_FUN, val); + prog_add_instr(prog, OP_MAKE_REF, SK_NO_PARAM); } break; case NODE_BOOL: { union val val; diff --git a/lib/src/exec.c b/lib/src/exec.c index f356ff9..c4315dd 100644 --- a/lib/src/exec.c +++ b/lib/src/exec.c @@ -89,7 +89,8 @@ void exec_execute(struct exec* self, vec_push(¶ms, (void*) value_new_clone(state_try_get_value(state, arg))); } - struct value* f = state_try_get_value(state, function); + struct value* f = value_new_clone(state_try_get_value(state, function)); + state_call(state); for (size_t i=0; itype, val->val, val->line); state_local_store(state, i+1); } - + + state_push(state, f->type, f->val, f->line); + state_local_store(state, params.size + 1); + vec_free_elements(¶ms, NULL); vec_free(¶ms); - assert(f->type == TYPE_FUN); + assert(f->type == TYPE_REF); struct exec ex; exec_init(&ex); - exec_execute(&ex, state, f->val.fun->prog); + struct value* fun_val = + state_try_deref(state, f->val.ref); + + exec_execute(&ex, state, fun_val->val.fun->prog); struct value* res = value_new_clone(state_try_get_value( state, @@ -117,6 +124,13 @@ void exec_execute(struct exec* self, state_ret(state); state_push(state, res->type, res->val, res->line); value_free(res); free(res); + + free(f); + self->pc++; + } break; + + case OP_MAKE_REF: { + state_make_ref(state); self->pc++; } break; diff --git a/lib/src/fun.c b/lib/src/fun.c index 99bf8b4..133dfc3 100644 --- a/lib/src/fun.c +++ b/lib/src/fun.c @@ -18,7 +18,6 @@ void fun_free(struct fun* self) struct fun* fun_new_clone(struct fun* self) { (void) self; - struct fun* clone = malloc(sizeof(struct fun)); fun_init(clone, prog_new_clone(self->prog)); return clone; diff --git a/lib/src/state.c b/lib/src/state.c index ae06b9c..336d4d7 100644 --- a/lib/src/state.c +++ b/lib/src/state.c @@ -40,6 +40,7 @@ void state_init(struct state* self) vec_init(&self->frames); self->addr = 1; state_push_frame(self); + vec_init(&self->globals); } void state_free(struct state* self) @@ -47,6 +48,36 @@ void state_free(struct state* self) assert(self); vec_free_elements(&self->frames, (void*) frame_free); vec_free(&self->frames); + + vec_free_elements(&self->globals, (void*) value_free); + vec_free(&self->globals); +} + +SK state_make_ref(struct state* self) +{ + SK val = state_pop(self); + struct value* value = state_try_get_value(self, val); + + struct value* on_heap = value_new_clone(value); + vec_push(&self->globals, on_heap); + + return state_push_ref( + self, + self->globals.size - 1, + on_heap->line + ); +} + +struct value* state_try_deref(struct state* self, size_t ref) +{ + assert(self); + + if (ref >= self->globals.size) + { + return NULL; + } + + return self->globals.data[ref]; } struct frame* state_frame(struct state* self) @@ -177,7 +208,15 @@ SK state_push_fun(struct state* self, struct fun* fun, int line) assert(self); union val val; val.fun = fun; - return state_push(self, TYPE_FUN, val ,line); + return state_push(self, TYPE_FUN, val, line); +} + +SK state_push_ref(struct state* self,size_t ref, int line) +{ + assert(self); + union val val; + val.ref = ref; + return state_push(self, TYPE_REF, val, line); } struct local* state_try_get_local(struct state* self, int id) diff --git a/lib/src/value.c b/lib/src/value.c index 1ccfa90..f76aa4b 100644 --- a/lib/src/value.c +++ b/lib/src/value.c @@ -44,6 +44,12 @@ struct value* value_new_clone(struct value* self) return clone; } break; + case TYPE_REF: { + val.ref = self->val.ref; + value_init(clone, TYPE_REF, val, self->line); + return clone; + } break; + case TYPE_FLOAT: { val.real = self->val.real; value_init(clone, TYPE_FLOAT, val, self->line); @@ -105,6 +111,10 @@ void value_str(struct value* self, struct str* dest) str_format(dest, "", self->val.fun); } break; + case TYPE_REF: { + str_format(dest, "", self->val.ref); + } break; + case TYPE_STRING: { str_format(dest, "%s", self->val.str); } break;