✨ 🐛 function now on the heap.
parent
0a3d7d4aea
commit
7468605289
|
@ -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
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
struct compiler
|
||||
{
|
||||
struct vec var_names;
|
||||
};
|
||||
|
||||
void compiler_init(struct compiler* self);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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; i<args->children.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;
|
||||
|
|
|
@ -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; i<params.size; i++)
|
||||
{
|
||||
|
@ -99,15 +100,21 @@ void exec_execute(struct exec* self,
|
|||
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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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, "<fun:%p>", self->val.fun);
|
||||
} break;
|
||||
|
||||
case TYPE_REF: {
|
||||
str_format(dest, "<ref:%zu>", self->val.ref);
|
||||
} break;
|
||||
|
||||
case TYPE_STRING: {
|
||||
str_format(dest, "%s", self->val.str);
|
||||
} break;
|
||||
|
|
Loading…
Reference in New Issue