function closures.

main
bog 2023-12-23 21:17:12 +01:00
parent 968f7a312d
commit 84f5425804
23 changed files with 630 additions and 125 deletions

View File

@ -7,8 +7,10 @@
#include "lib/tysy.h"
#include "node.h"
#include "fun.h"
#include "locals.h"
void compiler_init(compiler_t* compiler,
int* id,
sym_t* sym,
tysy_t* tysy,
err_t* err)
@ -18,11 +20,13 @@ void compiler_init(compiler_t* compiler,
assert(tysy);
assert(err);
compiler->parent = NULL;
compiler->sym = sym;
compiler->tysy = tysy;
compiler->err = err;
compiler->scope = 0;
compiler->id = id;
}
void compiler_free(compiler_t* compiler)
@ -281,7 +285,6 @@ int compiler_run(compiler_t* compiler, node_t* node, program_t* program)
compiler->scope,
SYM_DECL,
node);
if (!entry)
{
char msg[RZ_STR_LIMIT];
@ -305,6 +308,15 @@ int compiler_run(compiler_t* compiler, node_t* node, program_t* program)
compiler->scope,
SYM_DECL,
node);
if (0 && compiler->parent && !entry)
{
entry = sym_try_find_by_name(compiler->parent->sym, name,
compiler->scope,
SYM_DECL,
node);
}
if (!entry)
{
char msg[RZ_STR_LIMIT];
@ -367,28 +379,39 @@ int compiler_run(compiler_t* compiler, node_t* node, program_t* program)
assert(entry);
entry->state = SYM_DECL;
entry->id = *compiler->id;
// Compile function
{
compiler_t comp;
compiler_init(&comp, (sym_t*) fun->sym,
compiler_init(&comp, compiler->id, (sym_t*) fun->sym,
compiler->tysy, compiler->err);
comp.parent = compiler;
comp.sym->parent = compiler->sym;
tysolver_t tysolver;
tysolver_init(&tysolver, (sym_t*) fun->sym, compiler->tysy);
prepass_t pre;
prepass_init(&pre, (sym_t*) fun->sym, compiler->tysy,
prepass_init(&pre, compiler->id, (sym_t*) fun->sym, compiler->tysy,
&tysolver, compiler->err);
// self
int id = sym_declare((sym_t*) fun->sym,
(*compiler->id)++,
fun_name,
tysy_try_find_type(comp.tysy, "fun"),
comp.scope,
SYM_DECL,
node);
fun->base = id;
prepass_run(&pre, (node_t*) node->children.data[2]);
// self
sym_declare((sym_t*) fun->sym, fun_name,
tysy_try_find_type(comp.tysy, "fun"),
comp.scope,
SYM_DECL,
node);
fun->arg_base = *compiler->id;
compiler_run(&comp, (node_t*) node->children.data[1], &fun->program);
compiler_run(&comp, (node_t*) node->children.data[2], &fun->program);
@ -399,11 +422,11 @@ int compiler_run(compiler_t* compiler, node_t* node, program_t* program)
compiler_free(&comp);
}
// value_t* value = tysy_new_fun(compiler->tysy, fun, node->line);
param_t param = program_push_new_value(program, (struct value*) value);
program_push_instr(program, OP_PUSH, param);
program_push_instr(program, OP_MKFUN, RZ_NO_PARAM);
program_push_instr(program, OP_STORE, entry->id);
} break;
case NODE_PARAMS: {
@ -411,7 +434,7 @@ int compiler_run(compiler_t* compiler, node_t* node, program_t* program)
{
node_t* child = (node_t*) node->children.data[i];
char* name = child->value.data;
sym_declare(compiler->sym, name, NULL,
sym_declare(compiler->sym, (*compiler->id)++, name, NULL,
compiler->scope, SYM_DECL,
child);
}
@ -436,6 +459,7 @@ int compiler_run(compiler_t* compiler, node_t* node, program_t* program)
compiler->scope,
SYM_DECL,
node);
if (!entry)
{
char msg[RZ_STR_LIMIT];

View File

@ -8,15 +8,18 @@
#include "tysy.h"
#include "sym.h"
typedef struct {
typedef struct compiler {
struct compiler* parent;
sym_t* sym;
tysy_t* tysy;
err_t* err;
int scope;
int* id;
} compiler_t;
void compiler_init(compiler_t* compiler,
int* id,
sym_t* sym,
tysy_t* tysy,
err_t* err);

View File

@ -1,12 +1,47 @@
#include "fun.h"
#include "sym.h"
#include "locals.h"
#include "value.h"
void fun_init(fun_t* fun, struct tysy* tysy, err_t* err)
{
assert(fun);
program_init(&fun->program);
fun->err = err;
fun->sym = malloc(sizeof(sym_t));
sym_init((sym_t*) fun->sym, (tysy_t*) tysy, err);
fun->locals = malloc(sizeof(locals_t));
locals_init((locals_t*) fun->locals);
fun->base = 0;
fun->closure.size = 0;
fun->closure.cap = 0;
fun->closure.data = NULL;
}
fun_t* fun_new_clone(fun_t* fun)
{
assert(fun);
fun_t* clone = malloc(sizeof(fun_t));
fun_init(clone, fun->tysy, fun->err);
locals_free((locals_t*) clone->locals);
free(clone->locals);
clone->locals = (struct locals*) locals_new_clone((locals_t*) fun->locals);
clone->base = fun->base;
clone->arg_base = fun->arg_base;
for (size_t i=0; i<fun->closure.size; i++)
{
fun_capture(clone,
fun->closure.data[i]->id,
fun->closure.data[i]->value);
}
return clone;
}
void fun_free(fun_t* fun)
@ -16,4 +51,59 @@ void fun_free(fun_t* fun)
sym_free((sym_t*) fun->sym);
free(fun->sym);
locals_free((locals_t*) fun->locals);
free(fun->locals);
for (size_t i=0; i<fun->closure.size; i++)
{
value_free((value_t*) fun->closure.data[i]->value);
free(fun->closure.data[i]->value);
free(fun->closure.data[i]);
}
free(fun->closure.data);
fun->closure.data = NULL;
}
void fun_capture(fun_t* fun, int id, struct value* value)
{
assert(fun);
assert(value);
if (fun->closure.data == NULL)
{
fun->closure.cap = 2;
fun->closure.data = malloc(sizeof(closure_entry_t*) * fun->closure.cap);
}
if (fun->closure.size >= fun->closure.cap)
{
fun->closure.cap *= 2;
fun->closure.data = realloc(fun->closure.data,
sizeof(closure_entry_t*) * fun->closure.cap);
}
fun->closure.data[fun->closure.size] = malloc(sizeof(closure_entry_t));
fun->closure.data[fun->closure.size]->id = id;
fun->closure.data[fun->closure.size]->value = value_new_clone(value);
fun->closure.size++;
}
closure_entry_t* fun_try_find_closure(fun_t* fun, int id)
{
assert(fun);
for (size_t i=0; i<fun->closure.size; i++)
{
if (fun->closure.data[i]->id == id)
{
return fun->closure.data[i];
}
}
return NULL;
}

View File

@ -6,15 +6,35 @@
#include "err.h"
struct sym;
struct locals;
struct value;
typedef struct {
int id;
struct value* value;
} closure_entry_t;
typedef struct {
program_t program;
err_t* err;
struct sym* sym;
struct tysy* tysy;
struct locals* locals;
int base;
int arg_base;
struct {
size_t size;
size_t cap;
closure_entry_t** data;
} closure;
} fun_t;
void fun_init(fun_t* fun, struct tysy* tysy, err_t* err);
fun_t* fun_new_clone(fun_t* fun);
void fun_free(fun_t* fun);
void fun_capture(fun_t* fun, int id, struct value* value);
closure_entry_t* fun_try_find_closure(fun_t* fun, int id);
#endif

55
lib/heap.c Normal file
View File

@ -0,0 +1,55 @@
#include "heap.h"
void heap_init(heap_t* heap)
{
assert(heap);
heap->size = 0;
heap->cap = 0;
heap->data = NULL;
}
void heap_free(heap_t* heap)
{
for (size_t i=0; i<heap->size; i++)
{
//value_free(heap->data[i]);
//free(heap->data[i]);
}
free(heap->data);
heap->size = 0;
heap->cap = 0;
heap->data = NULL;
}
size_t heap_alloc(heap_t* heap, value_t* value)
{
assert(heap);
if (heap->data == NULL)
{
heap->cap = 2;
heap->data = malloc(sizeof(value_t*) * heap->cap);
}
if (heap->size >= heap->cap)
{
heap->cap *= 2;
heap->data = realloc(heap->data, sizeof(value_t*) * heap->cap);
}
heap->data[heap->size] = value;
heap->size++;
return heap->size - 1;
}
value_t* heap_deref(heap_t* heap, size_t addr)
{
assert(heap);
assert(addr < heap->size);
return heap->data[addr];
}

19
lib/heap.h Normal file
View File

@ -0,0 +1,19 @@
#ifndef RZ_HEAP_H
#define RZ_HEAP_H
#include "commons.h"
#include "value.h"
typedef struct {
size_t cap;
size_t size;
value_t** data;
} heap_t;
void heap_init(heap_t* heap);
void heap_free(heap_t* heap);
size_t heap_alloc(heap_t* heap, value_t* value);
value_t* heap_deref(heap_t* heap, size_t addr);
#endif

View File

@ -104,11 +104,12 @@ int loader_ldfile(loader_t* loader, char const* path, int debug)
tysolver_t tysolver;
tysolver_init(&tysolver, &sym, &tysy);
int id = 0;
// prepass
{
prepass_t prepass;
prepass_init(&prepass, &sym, &tysy, &tysolver, &err);
prepass_init(&prepass, &id, &sym, &tysy, &tysolver, &err);
prepass_run(&prepass, node);
prepass_free(&prepass);
}
@ -116,7 +117,7 @@ int loader_ldfile(loader_t* loader, char const* path, int debug)
// compile
{
compiler_t compiler;
compiler_init(&compiler, &sym, &tysy, &err);
compiler_init(&compiler, &id, &sym, &tysy, &err);
int status = compiler_run(&compiler, node, &mod.program);
if (status != 0)

90
lib/locals.c Normal file
View File

@ -0,0 +1,90 @@
#include "locals.h"
void locals_init(locals_t* locals)
{
assert(locals);
locals->cap = 0;
locals->size = 0;
locals->data = NULL;
}
locals_t* locals_new_clone(locals_t* locals)
{
assert(locals);
locals_t* clone = malloc(sizeof(locals_t));
locals_init(clone);
for (size_t i=0; i<locals->size; i++)
{
locals_store(clone,
locals->data[i]->id,
locals->data[i]->addr);
}
return clone;
}
void locals_free(locals_t* locals)
{
assert(locals);
for (size_t i=0; i<locals->size; i++)
{
free(locals->data[i]);
}
free(locals->data);
locals->data = NULL;
locals->size = 0;
locals->cap = 0;
}
local_t* locals_try_load(locals_t* locals, int id)
{
assert(locals);
for (size_t i=0; i<locals->size; i++)
{
if (locals->data[i]->id == id)
{
return locals->data[i];
}
}
return NULL;
}
void locals_store(locals_t* locals, int id, int addr)
{
assert(locals);
local_t* loc = locals_try_load(locals, id);
if (!loc)
{
if (locals->data == NULL)
{
locals->cap = 2;
locals->data = malloc(sizeof(local_t*) * locals->cap);
}
if (locals->size >= locals->cap)
{
locals->cap *= 2;
locals->data = realloc(locals->data,
sizeof(local_t*) * locals->cap);
}
locals->data[locals->size] = malloc(sizeof(local_t));
locals->data[locals->size]->id = id;
locals->data[locals->size]->addr = addr;
locals->size++;
}
else
{
loc->id = id;
loc->addr = addr;
}
}

25
lib/locals.h Normal file
View File

@ -0,0 +1,25 @@
#ifndef RZ_LOCALS_H
#define RZ_LOCALS_H
#include "commons.h"
#include "value.h"
typedef struct {
int id;
int addr;
} local_t;
typedef struct {
size_t size;
size_t cap;
local_t** data;
} locals_t;
void locals_init(locals_t* locals);
locals_t* locals_new_clone(locals_t* locals);
void locals_free(locals_t* locals);
local_t* locals_try_load(locals_t* locals, int id);
void locals_store(locals_t* locals, int id, int addr);
#endif

View File

@ -14,7 +14,8 @@
G(OP_BRF), G(OP_BRT), G(OP_BR), \
G(OP_STRCAT), G(OP_STRDUP), \
G(OP_LOAD), G(OP_STORE), \
G(OP_CALL), G(OP_RET)
G(OP_CALL), G(OP_RET), G(OP_MKFUN), \
G(OP_ALLOC), G(OP_DEREF)
RZ_ENUM_H(Opcode, OPCODES);

View File

@ -4,6 +4,7 @@
#include "node.h"
void prepass_init(prepass_t* prepass,
int* id,
sym_t* sym,
tysy_t* tysy,
tysolver_t* tysolver,
@ -21,6 +22,7 @@ void prepass_init(prepass_t* prepass,
prepass->err = err;
prepass->scope = 0;
prepass->id = id;
}
void prepass_free(prepass_t* prepass)
@ -55,7 +57,7 @@ void prepass_run(prepass_t* prepass, node_t* node)
type_t* type = tysolver_try_solve_node(prepass->tysolver,
(node_t*) node->children.data[1]);
sym_declare(prepass->sym, name, type,
sym_declare(prepass->sym, (*prepass->id)++, name, type,
prepass->scope, SYM_PRE,
node);
@ -64,7 +66,9 @@ void prepass_run(prepass_t* prepass, node_t* node)
case NODE_FUNDECL: {
char* name = ((node_t*) node->children.data[0])->value.data;
sym_declare(prepass->sym, name,
sym_declare(prepass->sym,
(*prepass->id)++,
name,
tysy_try_find_type(prepass->tysy, "fun"),
prepass->scope,
SYM_PRE,

View File

@ -13,12 +13,13 @@ typedef struct {
tysy_t* tysy;
tysolver_t* tysolver;
err_t* err;
int* id;
int scope;
} prepass_t;
void prepass_init(prepass_t* prepass,
int* id,
sym_t* sym,
tysy_t* tysy,
tysolver_t* tysolver,

View File

@ -4,10 +4,9 @@
void sym_init(sym_t* sym, tysy_t* tysy, err_t* err)
{
assert(sym);
sym->parent = NULL;
sym->tysy = tysy;
sym->err = err;
sym->entries.id_counter = 0;
sym->entries.size = 0;
sym->entries.cap = 0;
@ -30,7 +29,7 @@ void sym_free(sym_t* sym)
sym->entries.cap = 0;
}
int sym_declare(sym_t* sym, char* name, type_t* type,
int sym_declare(sym_t* sym, int id, char* name, type_t* type,
int scope, int state_flag, node_t* node)
{
assert(sym);
@ -72,9 +71,6 @@ int sym_declare(sym_t* sym, char* name, type_t* type,
sym->entries.data[sym->entries.size] = malloc(sizeof(sym_entry_t));
int id = sym->entries.id_counter;
sym->entries.id_counter++;
sym->entries.data[sym->entries.size]->name = strdup(name);
sym->entries.data[sym->entries.size]->id = id;
sym->entries.data[sym->entries.size]->type = type;
@ -117,9 +113,20 @@ sym_entry_t* sym_try_find_by_name(sym_t* sym, char* name,
}
}
sym_entry_t* result = NULL;
if (scope > 0)
{
return sym_try_find_by_name(sym, name, scope - 1, state_flag, node);
result = sym_try_find_by_name(sym, name, scope - 1, state_flag, node);
if (result) { return result; }
}
if (sym->parent)
{
result = sym_try_find_by_name(sym->parent, name, scope, state_flag, node);
if (result) { return result; }
}
return NULL;

View File

@ -20,9 +20,10 @@ typedef struct {
node_t* node;
} sym_entry_t;
typedef struct {
typedef struct sym {
tysy_t* tysy;
err_t* err;
struct sym* parent;
struct {
int id_counter;
@ -35,7 +36,7 @@ typedef struct {
void sym_init(sym_t* sym, tysy_t* tysy, err_t* err);
void sym_free(sym_t* sym);
int sym_declare(sym_t* sym, char* name, type_t* type,
int sym_declare(sym_t* sym, int id, char* name, type_t* type,
int scope, int state_flag,
node_t* node);

View File

@ -5,7 +5,7 @@
#define TYPE_KIND(G) \
G(TYPE_NUM), G(TYPE_BOOL), G(TYPE_STR), \
G(TYPE_FUN)
G(TYPE_FUN), G(TYPE_REF)
RZ_ENUM_H(TypeKind, TYPE_KIND);

View File

@ -32,6 +32,13 @@ void tysy_init(tysy_t* tysy)
type_init(ty, TYPE_FUN);
tysy_register_new_type(tysy, "fun", ty);
}
// ref
{
type_t* ty = malloc(sizeof(type_t));
type_init(ty, TYPE_REF);
tysy_register_new_type(tysy, "ref", ty);
}
}
void tysy_free(tysy_t* tysy)
@ -119,3 +126,14 @@ value_t* tysy_new_fun(tysy_t* tysy, fun_t* fun, int line)
return val;
}
value_t* tysy_new_ref(tysy_t* tysy, size_t ref, int line)
{
assert(tysy);
value_t* val = malloc(sizeof(value_t));
value_init(val, tysy_try_find_type(tysy, "ref"), line);
val->value.ref = ref;
return val;
}

View File

@ -20,5 +20,6 @@ value_t* tysy_new_num(tysy_t* tysy, double value, int line);
value_t* tysy_new_bool(tysy_t* tysy, int value, int line);
value_t* tysy_new_str(tysy_t* tysy, char* value, int line);
value_t* tysy_new_fun(tysy_t* tysy, fun_t* fun, int line);
value_t* tysy_new_ref(tysy_t* tysy, size_t ref, int line);
#endif

View File

@ -12,6 +12,27 @@ void value_init(value_t* value, type_t* type, int line)
value->line = line;
}
value_t* value_new_clone(value_t* value)
{
assert(value);
value_t* clone = malloc(sizeof(value_t));
value_init(clone, value->type, value->line);
clone->value = value->value;
if (value->type->kind == TYPE_STR)
{
clone->value.str = strdup(value->value.str);
}
if (value->type->kind == TYPE_FUN)
{
clone->value.fun = fun_new_clone(value->value.fun);
}
return clone;
}
void value_free(value_t* value)
{
assert(value);
@ -56,6 +77,10 @@ int value_eq(value_t* value, value_t* rhs)
return value->value.fun == rhs->value.fun;
} break;
case TYPE_REF: {
return value->value.ref == rhs->value.ref;
} break;
default: {
fprintf(stderr, "Cannot compare value of type '%s'.\n",
TypeKindStr[value->type->kind]);
@ -89,6 +114,10 @@ size_t value_str(value_t* value, char* buffer, size_t size)
return snprintf(buffer, size, "[fun]");
break;
case TYPE_REF:
return snprintf(buffer, size, "[ref %d]", (int) value->value.ref);
break;
default: {
fprintf(stderr, "Cannot stringify unknown value of type '%s'.\n",
TypeKindStr[value->type->kind]);

View File

@ -6,12 +6,13 @@
struct program;
typedef struct {
typedef struct value {
type_t* type;
union {
double num;
int bool;
size_t ref;
char* str;
fun_t* fun;
} value;
@ -20,6 +21,7 @@ typedef struct {
} value_t;
void value_init(value_t* value, type_t* type, int line);
value_t* value_new_clone(value_t* value);
void value_free(value_t* value);
int value_eq(value_t* value, value_t* rhs);

219
lib/vm.c
View File

@ -1,5 +1,8 @@
#include "vm.h"
#include "lib/commons.h"
#include "lib/fun.h"
#include "lib/heap.h"
#include "lib/locals.h"
#include "lib/mod.h"
#include "lib/type.h"
#include "lib/tysy.h"
@ -13,10 +16,13 @@ void vm_init(vm_t* vm, sym_t* sym, tysy_t* tysy, err_t* err)
assert(tysy);
vm->top_frame = NULL;
locals_init(&vm->locals);
vm_frame_push(vm, NULL);
vm->tysy = tysy;
vm->err = err;
heap_init(&vm->heap);
}
void vm_free(vm_t* vm)
@ -34,21 +40,26 @@ void vm_free(vm_t* vm)
}
vm->top_frame = NULL;
heap_free(&vm->heap);
locals_free(&vm->locals);
}
void vm_frame_init(frame_t* frame)
{
assert(frame);
frame->fun = NULL;
frame->pc = 0;
frame->bp = 0;
frame->sp = 0;
frame->prev = NULL;
frame->program = NULL;
frame->locals.cap = 0;
frame->locals.size = 0;
frame->locals.data = NULL;
frame->locals = NULL;
frame->alloc.cap = 0;
frame->alloc.size = 0;
@ -57,18 +68,6 @@ void vm_frame_init(frame_t* frame)
void vm_frame_free(frame_t* frame)
{
for (size_t i=0; i<frame->locals.size; i++)
{
free(frame->locals.data[i]);
}
free(frame->locals.data);
frame->locals.data = NULL;
frame->locals.size = 0;
frame->locals.cap = 0;
//vm_clear_alloc(frame);
if (frame->prev != NULL)
{
vm_frame_free((frame_t*) frame->prev);
@ -76,7 +75,7 @@ void vm_frame_free(frame_t* frame)
}
}
void vm_frame_push(vm_t* vm, program_t* program)
void vm_frame_push(vm_t* vm, fun_t* fun)
{
assert(vm);
@ -84,7 +83,17 @@ void vm_frame_push(vm_t* vm, program_t* program)
vm_frame_init(frame);
frame->prev = (struct frame*) vm->top_frame;
frame->program = program;
if (fun != NULL)
{
frame->program = &fun->program;
frame->locals = (locals_t*) fun->locals;
}
else
{
frame->locals = &vm->locals;
}
vm->top_frame = frame;
}
@ -92,6 +101,13 @@ int vm_frame_pop(vm_t* vm)
{
assert(vm);
if (vm->top_frame->fun)
{
fun_free(vm->top_frame->fun);
free(vm->top_frame->fun);
vm->top_frame->fun = NULL;
}
if (vm->top_frame)
{
vm_clear_alloc(vm->top_frame);
@ -113,57 +129,6 @@ int vm_frame_pop(vm_t* vm)
return 0;
}
local_t* vm_try_local_load(vm_t* vm, int id)
{
assert(vm);
for (size_t i=0; i<vm->top_frame->locals.size; i++)
{
if (vm->top_frame->locals.data[i]->id == id)
{
return vm->top_frame->locals.data[i];
}
}
return NULL;
}
void vm_local_store(vm_t* vm, int id, param_t addr)
{
assert(vm);
local_t* loc = vm_try_local_load(vm, id);
if (!loc)
{
if (vm->top_frame->locals.data == NULL)
{
vm->top_frame->locals.cap = 2;
vm->top_frame->locals.data = malloc(sizeof(local_t*)
* vm->top_frame->locals.cap);
}
if (vm->top_frame->locals.size >= vm->top_frame->locals.cap)
{
vm->top_frame->locals.cap *= 2;
vm->top_frame->locals.data = realloc(vm->top_frame->locals.data,
sizeof(local_t*)
* vm->top_frame->locals.cap);
}
vm->top_frame->locals.data[vm->top_frame->locals.size]
= malloc(sizeof(local_t));
vm->top_frame->locals.data[vm->top_frame->locals.size]->id = id;
vm->top_frame->locals.data[vm->top_frame->locals.size]->addr = addr;
vm->top_frame->locals.size++;
}
else
{
loc->id = id;
loc->addr = addr;
}
}
void vm_push_new(vm_t* vm, value_t* value)
{
assert(value);
@ -465,7 +430,25 @@ int vm_exec_instr(vm_t* vm, Opcode op, param_t param)
} break;
case OP_LOAD: {
local_t* local = vm_try_local_load(vm, param);
local_t* local = locals_try_load(vm->top_frame->locals, param);
if (!local && vm->top_frame->fun)
{
fun_t* fun = vm->top_frame->fun;
closure_entry_t* e = fun_try_find_closure(fun, param);
if (e)
{
vm_push(vm, e->value);
vm->top_frame->pc++;
break;
}
}
if (!local)
{
local = locals_try_load(&vm->locals, param);
}
if (!local)
{
@ -492,6 +475,7 @@ int vm_exec_instr(vm_t* vm, Opcode op, param_t param)
}
else
{
assert(local->addr < vm->top_frame->sp);
vm_push(vm, vm->top_frame->stack[local->addr]);
}
@ -500,39 +484,120 @@ int vm_exec_instr(vm_t* vm, Opcode op, param_t param)
case OP_STORE: {
assert(vm->top_frame->sp > 0);
vm_local_store(vm, param, vm->top_frame->sp - 1);
if (vm->top_frame->fun)
{
fun_t* fun = vm->top_frame->fun;
closure_entry_t* closure = fun_try_find_closure(fun, param);
if (closure)
{
value_t* value = vm->top_frame->stack[vm->top_frame->sp - 1];
value_free(closure->value);
free(closure->value);
closure->value = value_new_clone(value);
vm->top_frame->pc++;
break;
}
}
locals_store(vm->top_frame->locals, param, vm->top_frame->sp - 1);
vm->top_frame->pc++;
} break;
case OP_MKFUN: {
value_t* value = vm_pop(vm);
size_t addr = heap_alloc(&vm->heap, value);
value_t* ref = tysy_new_ref(vm->tysy, addr, value->line);
vm_push_new(vm, ref);
frame_t* prev = (frame_t*) vm->top_frame->prev;
locals_t* loc = &vm->locals;
assert(value->type->kind == TYPE_FUN);
fun_t* fun = value->value.fun;
if (vm->top_frame->fun)
{
loc = (locals_t*) vm->top_frame->fun->locals;
}
else if (prev && prev->fun)
{
loc = (locals_t*) prev->fun->locals;
}
else if (prev)
{
loc = prev->locals;
}
if (loc)
{
for (size_t i=0; i<loc->size; i++)
{
int id = vm->top_frame->locals->data[i]->id;
value_t* loc_val = vm->top_frame->stack[addr];
fun_capture(fun, id, loc_val);
}
}
vm->top_frame->pc++;
} break;
case OP_DEREF: {
value_t* value = vm_pop(vm);
assert(value->type->kind == TYPE_REF);
size_t addr = value->value.ref;
vm_push(vm, heap_deref(&vm->heap, addr));
vm->top_frame->pc++;
} break;
case OP_CALL: {
size_t const ARG_SZ = param + 1;
size_t const ARG_SZ = param;
value_t* args[ARG_SZ];
value_t* fun_ref = vm_pop(vm);
for (size_t i=0; i<ARG_SZ; i++)
{
value_t* val = vm_pop(vm);
args[ARG_SZ - 1 - i] = val;
args[i] = val;
}
value_t* fun_val = args[ARG_SZ - 1];
value_t* fun_val = heap_deref(&vm->heap, fun_ref->value.ref);
assert(fun_val->type->kind == TYPE_FUN);
fun_t* fun = fun_val->value.fun;
fun_t* fun = fun_new_clone(fun_val->value.fun);
vm->top_frame->pc++;
vm_frame_push(vm, &fun->program);
vm_frame_push(vm, fun);
vm->top_frame->fun = fun;
vm_push(vm, fun_ref);
locals_store(vm->top_frame->locals, fun->base, vm->top_frame->sp - 1);
for (size_t i=0; i<ARG_SZ; i++)
{
value_t* arg = args[i];
size_t addr = fun->arg_base + (ARG_SZ - 1 - i);
vm_push(vm, arg);
vm_local_store(vm, ARG_SZ - 1 - i, vm->top_frame->sp - 1);
locals_store(vm->top_frame->locals,
addr,
vm->top_frame->sp - 1);
}
} break;
case OP_RET: {
frame_t* frame = (frame_t*) vm->top_frame;
frame_t* prev = (frame_t*) vm->top_frame->prev;

View File

@ -8,11 +8,8 @@
#include "tysy.h"
#include "sym.h"
#include "program.h"
typedef struct {
int id;
param_t addr;
} local_t;
#include "heap.h"
#include "locals.h"
typedef struct stack_frame{
struct frame* prev;
@ -22,12 +19,8 @@ typedef struct stack_frame{
size_t pc;
size_t bp;
size_t sp;
struct {
size_t size;
size_t cap;
local_t** data;
} locals;
fun_t* fun;
locals_t* locals;
struct {
size_t size;
@ -42,6 +35,8 @@ typedef struct {
tysy_t* tysy;
err_t* err;
frame_t* top_frame;
heap_t heap;
locals_t locals;
} vm_t;
void vm_init(vm_t* vm, sym_t* sym, tysy_t* tysy, err_t* err);
@ -50,12 +45,9 @@ void vm_free(vm_t* vm);
void vm_frame_init(frame_t* frame);
void vm_frame_free(frame_t* frame);
void vm_frame_push(vm_t* vm, program_t* program);
void vm_frame_push(vm_t* vm, fun_t* fun);
int vm_frame_pop(vm_t* vm);
local_t* vm_try_local_load(vm_t* vm, int id);
void vm_local_store(vm_t* vm, int id, param_t addr);
void vm_push_new(vm_t* vm, value_t* value);
void vm_push(vm_t* vm, value_t* value);
value_t* vm_pop(vm_t* vm);

View File

@ -48,6 +48,8 @@ roza_lib = static_library(
# exec
'lib/vm.c',
'lib/heap.c',
'lib/locals.c',
],
dependencies: [

View File

@ -1,6 +1,5 @@
# FUNCTIONS
# =========
fun double(n)
n * 2
end
@ -38,7 +37,6 @@ assert max(7, 9) == 9
# RECURSIVITY
# ===========
fun fac(n)
if n == 0 then
return 1
@ -57,4 +55,61 @@ fun fib(n)
return fib(n - 2) + fib(n - 1)
end
assert fib(6) == 13
assert fib(6) == 13
# HIGH ORDER FUNCTIONS
# ====================
fun fi(n)
return n + 1
end
fun fd(n)
return n * 2
end
fun twice(f, x)
return f(f(x))
end
assert twice(fi, 27) == 29
assert twice(fd, 12) == 48
# CLOSURES
# ========
fun make()
let counter = 0
fun inner()
counter = counter + 1
return counter - 1
end
return inner
end
let c = make()
assert c() == 0
assert c() == 1
assert c() == 2
fun make_val(init)
let counter = init
fun inner()
counter = counter + 1
return counter - 1
end
return inner
end
let d = make_val(7)
let e = make_val(3)
assert d() == 7
assert e() == 3
assert d() == 8
assert e() == 4
assert d() == 9
assert e() == 5