✨ function closures.
parent
968f7a312d
commit
84f5425804
|
@ -7,8 +7,10 @@
|
||||||
#include "lib/tysy.h"
|
#include "lib/tysy.h"
|
||||||
#include "node.h"
|
#include "node.h"
|
||||||
#include "fun.h"
|
#include "fun.h"
|
||||||
|
#include "locals.h"
|
||||||
|
|
||||||
void compiler_init(compiler_t* compiler,
|
void compiler_init(compiler_t* compiler,
|
||||||
|
int* id,
|
||||||
sym_t* sym,
|
sym_t* sym,
|
||||||
tysy_t* tysy,
|
tysy_t* tysy,
|
||||||
err_t* err)
|
err_t* err)
|
||||||
|
@ -18,11 +20,13 @@ void compiler_init(compiler_t* compiler,
|
||||||
assert(tysy);
|
assert(tysy);
|
||||||
assert(err);
|
assert(err);
|
||||||
|
|
||||||
|
compiler->parent = NULL;
|
||||||
compiler->sym = sym;
|
compiler->sym = sym;
|
||||||
compiler->tysy = tysy;
|
compiler->tysy = tysy;
|
||||||
compiler->err = err;
|
compiler->err = err;
|
||||||
|
|
||||||
compiler->scope = 0;
|
compiler->scope = 0;
|
||||||
|
compiler->id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void compiler_free(compiler_t* compiler)
|
void compiler_free(compiler_t* compiler)
|
||||||
|
@ -281,7 +285,6 @@ int compiler_run(compiler_t* compiler, node_t* node, program_t* program)
|
||||||
compiler->scope,
|
compiler->scope,
|
||||||
SYM_DECL,
|
SYM_DECL,
|
||||||
node);
|
node);
|
||||||
|
|
||||||
if (!entry)
|
if (!entry)
|
||||||
{
|
{
|
||||||
char msg[RZ_STR_LIMIT];
|
char msg[RZ_STR_LIMIT];
|
||||||
|
@ -305,6 +308,15 @@ int compiler_run(compiler_t* compiler, node_t* node, program_t* program)
|
||||||
compiler->scope,
|
compiler->scope,
|
||||||
SYM_DECL,
|
SYM_DECL,
|
||||||
node);
|
node);
|
||||||
|
|
||||||
|
if (0 && compiler->parent && !entry)
|
||||||
|
{
|
||||||
|
entry = sym_try_find_by_name(compiler->parent->sym, name,
|
||||||
|
compiler->scope,
|
||||||
|
SYM_DECL,
|
||||||
|
node);
|
||||||
|
}
|
||||||
|
|
||||||
if (!entry)
|
if (!entry)
|
||||||
{
|
{
|
||||||
char msg[RZ_STR_LIMIT];
|
char msg[RZ_STR_LIMIT];
|
||||||
|
@ -367,29 +379,40 @@ int compiler_run(compiler_t* compiler, node_t* node, program_t* program)
|
||||||
assert(entry);
|
assert(entry);
|
||||||
|
|
||||||
entry->state = SYM_DECL;
|
entry->state = SYM_DECL;
|
||||||
|
entry->id = *compiler->id;
|
||||||
|
|
||||||
// Compile function
|
// Compile function
|
||||||
{
|
{
|
||||||
compiler_t comp;
|
compiler_t comp;
|
||||||
compiler_init(&comp, (sym_t*) fun->sym,
|
compiler_init(&comp, compiler->id, (sym_t*) fun->sym,
|
||||||
compiler->tysy, compiler->err);
|
compiler->tysy, compiler->err);
|
||||||
|
comp.parent = compiler;
|
||||||
|
comp.sym->parent = compiler->sym;
|
||||||
|
|
||||||
tysolver_t tysolver;
|
tysolver_t tysolver;
|
||||||
tysolver_init(&tysolver, (sym_t*) fun->sym, compiler->tysy);
|
tysolver_init(&tysolver, (sym_t*) fun->sym, compiler->tysy);
|
||||||
|
|
||||||
prepass_t pre;
|
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);
|
&tysolver, compiler->err);
|
||||||
|
|
||||||
prepass_run(&pre, (node_t*) node->children.data[2]);
|
|
||||||
|
|
||||||
// self
|
// self
|
||||||
sym_declare((sym_t*) fun->sym, fun_name,
|
int id = sym_declare((sym_t*) fun->sym,
|
||||||
|
(*compiler->id)++,
|
||||||
|
fun_name,
|
||||||
tysy_try_find_type(comp.tysy, "fun"),
|
tysy_try_find_type(comp.tysy, "fun"),
|
||||||
comp.scope,
|
comp.scope,
|
||||||
SYM_DECL,
|
SYM_DECL,
|
||||||
node);
|
node);
|
||||||
|
|
||||||
|
|
||||||
|
fun->base = id;
|
||||||
|
|
||||||
|
prepass_run(&pre, (node_t*) node->children.data[2]);
|
||||||
|
|
||||||
|
fun->arg_base = *compiler->id;
|
||||||
|
|
||||||
compiler_run(&comp, (node_t*) node->children.data[1], &fun->program);
|
compiler_run(&comp, (node_t*) node->children.data[1], &fun->program);
|
||||||
compiler_run(&comp, (node_t*) node->children.data[2], &fun->program);
|
compiler_run(&comp, (node_t*) node->children.data[2], &fun->program);
|
||||||
program_push_instr(&fun->program, OP_RET, RZ_NO_PARAM);
|
program_push_instr(&fun->program, OP_RET, RZ_NO_PARAM);
|
||||||
|
@ -399,11 +422,11 @@ int compiler_run(compiler_t* compiler, node_t* node, program_t* program)
|
||||||
compiler_free(&comp);
|
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);
|
param_t param = program_push_new_value(program, (struct value*) value);
|
||||||
program_push_instr(program, OP_PUSH, param);
|
program_push_instr(program, OP_PUSH, param);
|
||||||
|
program_push_instr(program, OP_MKFUN, RZ_NO_PARAM);
|
||||||
program_push_instr(program, OP_STORE, entry->id);
|
program_push_instr(program, OP_STORE, entry->id);
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_PARAMS: {
|
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];
|
node_t* child = (node_t*) node->children.data[i];
|
||||||
char* name = child->value.data;
|
char* name = child->value.data;
|
||||||
sym_declare(compiler->sym, name, NULL,
|
sym_declare(compiler->sym, (*compiler->id)++, name, NULL,
|
||||||
compiler->scope, SYM_DECL,
|
compiler->scope, SYM_DECL,
|
||||||
child);
|
child);
|
||||||
}
|
}
|
||||||
|
@ -436,6 +459,7 @@ int compiler_run(compiler_t* compiler, node_t* node, program_t* program)
|
||||||
compiler->scope,
|
compiler->scope,
|
||||||
SYM_DECL,
|
SYM_DECL,
|
||||||
node);
|
node);
|
||||||
|
|
||||||
if (!entry)
|
if (!entry)
|
||||||
{
|
{
|
||||||
char msg[RZ_STR_LIMIT];
|
char msg[RZ_STR_LIMIT];
|
||||||
|
|
|
@ -8,15 +8,18 @@
|
||||||
#include "tysy.h"
|
#include "tysy.h"
|
||||||
#include "sym.h"
|
#include "sym.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct compiler {
|
||||||
|
struct compiler* parent;
|
||||||
sym_t* sym;
|
sym_t* sym;
|
||||||
tysy_t* tysy;
|
tysy_t* tysy;
|
||||||
err_t* err;
|
err_t* err;
|
||||||
|
|
||||||
int scope;
|
int scope;
|
||||||
|
int* id;
|
||||||
} compiler_t;
|
} compiler_t;
|
||||||
|
|
||||||
void compiler_init(compiler_t* compiler,
|
void compiler_init(compiler_t* compiler,
|
||||||
|
int* id,
|
||||||
sym_t* sym,
|
sym_t* sym,
|
||||||
tysy_t* tysy,
|
tysy_t* tysy,
|
||||||
err_t* err);
|
err_t* err);
|
||||||
|
|
90
lib/fun.c
90
lib/fun.c
|
@ -1,12 +1,47 @@
|
||||||
#include "fun.h"
|
#include "fun.h"
|
||||||
#include "sym.h"
|
#include "sym.h"
|
||||||
|
#include "locals.h"
|
||||||
|
#include "value.h"
|
||||||
|
|
||||||
void fun_init(fun_t* fun, struct tysy* tysy, err_t* err)
|
void fun_init(fun_t* fun, struct tysy* tysy, err_t* err)
|
||||||
{
|
{
|
||||||
assert(fun);
|
assert(fun);
|
||||||
program_init(&fun->program);
|
program_init(&fun->program);
|
||||||
|
fun->err = err;
|
||||||
fun->sym = malloc(sizeof(sym_t));
|
fun->sym = malloc(sizeof(sym_t));
|
||||||
sym_init((sym_t*) fun->sym, (tysy_t*) tysy, err);
|
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)
|
void fun_free(fun_t* fun)
|
||||||
|
@ -16,4 +51,59 @@ void fun_free(fun_t* fun)
|
||||||
|
|
||||||
sym_free((sym_t*) fun->sym);
|
sym_free((sym_t*) fun->sym);
|
||||||
free(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;
|
||||||
}
|
}
|
||||||
|
|
20
lib/fun.h
20
lib/fun.h
|
@ -6,15 +6,35 @@
|
||||||
#include "err.h"
|
#include "err.h"
|
||||||
|
|
||||||
struct sym;
|
struct sym;
|
||||||
|
struct locals;
|
||||||
|
struct value;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int id;
|
||||||
|
struct value* value;
|
||||||
|
} closure_entry_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
program_t program;
|
program_t program;
|
||||||
|
err_t* err;
|
||||||
struct sym* sym;
|
struct sym* sym;
|
||||||
struct tysy* tysy;
|
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;
|
} fun_t;
|
||||||
|
|
||||||
void fun_init(fun_t* fun, struct tysy* tysy, err_t* err);
|
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_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
|
#endif
|
||||||
|
|
|
@ -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];
|
||||||
|
}
|
|
@ -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
|
|
@ -104,11 +104,12 @@ int loader_ldfile(loader_t* loader, char const* path, int debug)
|
||||||
|
|
||||||
tysolver_t tysolver;
|
tysolver_t tysolver;
|
||||||
tysolver_init(&tysolver, &sym, &tysy);
|
tysolver_init(&tysolver, &sym, &tysy);
|
||||||
|
int id = 0;
|
||||||
|
|
||||||
// prepass
|
// prepass
|
||||||
{
|
{
|
||||||
prepass_t prepass;
|
prepass_t prepass;
|
||||||
prepass_init(&prepass, &sym, &tysy, &tysolver, &err);
|
prepass_init(&prepass, &id, &sym, &tysy, &tysolver, &err);
|
||||||
prepass_run(&prepass, node);
|
prepass_run(&prepass, node);
|
||||||
prepass_free(&prepass);
|
prepass_free(&prepass);
|
||||||
}
|
}
|
||||||
|
@ -116,7 +117,7 @@ int loader_ldfile(loader_t* loader, char const* path, int debug)
|
||||||
// compile
|
// compile
|
||||||
{
|
{
|
||||||
compiler_t compiler;
|
compiler_t compiler;
|
||||||
compiler_init(&compiler, &sym, &tysy, &err);
|
compiler_init(&compiler, &id, &sym, &tysy, &err);
|
||||||
int status = compiler_run(&compiler, node, &mod.program);
|
int status = compiler_run(&compiler, node, &mod.program);
|
||||||
|
|
||||||
if (status != 0)
|
if (status != 0)
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
|
@ -14,7 +14,8 @@
|
||||||
G(OP_BRF), G(OP_BRT), G(OP_BR), \
|
G(OP_BRF), G(OP_BRT), G(OP_BR), \
|
||||||
G(OP_STRCAT), G(OP_STRDUP), \
|
G(OP_STRCAT), G(OP_STRDUP), \
|
||||||
G(OP_LOAD), G(OP_STORE), \
|
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);
|
RZ_ENUM_H(Opcode, OPCODES);
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "node.h"
|
#include "node.h"
|
||||||
|
|
||||||
void prepass_init(prepass_t* prepass,
|
void prepass_init(prepass_t* prepass,
|
||||||
|
int* id,
|
||||||
sym_t* sym,
|
sym_t* sym,
|
||||||
tysy_t* tysy,
|
tysy_t* tysy,
|
||||||
tysolver_t* tysolver,
|
tysolver_t* tysolver,
|
||||||
|
@ -21,6 +22,7 @@ void prepass_init(prepass_t* prepass,
|
||||||
prepass->err = err;
|
prepass->err = err;
|
||||||
|
|
||||||
prepass->scope = 0;
|
prepass->scope = 0;
|
||||||
|
prepass->id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void prepass_free(prepass_t* prepass)
|
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,
|
type_t* type = tysolver_try_solve_node(prepass->tysolver,
|
||||||
(node_t*) node->children.data[1]);
|
(node_t*) node->children.data[1]);
|
||||||
|
|
||||||
sym_declare(prepass->sym, name, type,
|
sym_declare(prepass->sym, (*prepass->id)++, name, type,
|
||||||
prepass->scope, SYM_PRE,
|
prepass->scope, SYM_PRE,
|
||||||
node);
|
node);
|
||||||
|
|
||||||
|
@ -64,7 +66,9 @@ void prepass_run(prepass_t* prepass, node_t* node)
|
||||||
case NODE_FUNDECL: {
|
case NODE_FUNDECL: {
|
||||||
char* name = ((node_t*) node->children.data[0])->value.data;
|
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"),
|
tysy_try_find_type(prepass->tysy, "fun"),
|
||||||
prepass->scope,
|
prepass->scope,
|
||||||
SYM_PRE,
|
SYM_PRE,
|
||||||
|
|
|
@ -13,12 +13,13 @@ typedef struct {
|
||||||
tysy_t* tysy;
|
tysy_t* tysy;
|
||||||
tysolver_t* tysolver;
|
tysolver_t* tysolver;
|
||||||
err_t* err;
|
err_t* err;
|
||||||
|
int* id;
|
||||||
int scope;
|
int scope;
|
||||||
|
|
||||||
} prepass_t;
|
} prepass_t;
|
||||||
|
|
||||||
void prepass_init(prepass_t* prepass,
|
void prepass_init(prepass_t* prepass,
|
||||||
|
int* id,
|
||||||
sym_t* sym,
|
sym_t* sym,
|
||||||
tysy_t* tysy,
|
tysy_t* tysy,
|
||||||
tysolver_t* tysolver,
|
tysolver_t* tysolver,
|
||||||
|
|
21
lib/sym.c
21
lib/sym.c
|
@ -4,10 +4,9 @@
|
||||||
void sym_init(sym_t* sym, tysy_t* tysy, err_t* err)
|
void sym_init(sym_t* sym, tysy_t* tysy, err_t* err)
|
||||||
{
|
{
|
||||||
assert(sym);
|
assert(sym);
|
||||||
|
sym->parent = NULL;
|
||||||
sym->tysy = tysy;
|
sym->tysy = tysy;
|
||||||
sym->err = err;
|
sym->err = err;
|
||||||
|
|
||||||
sym->entries.id_counter = 0;
|
sym->entries.id_counter = 0;
|
||||||
sym->entries.size = 0;
|
sym->entries.size = 0;
|
||||||
sym->entries.cap = 0;
|
sym->entries.cap = 0;
|
||||||
|
@ -30,7 +29,7 @@ void sym_free(sym_t* sym)
|
||||||
sym->entries.cap = 0;
|
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)
|
int scope, int state_flag, node_t* node)
|
||||||
{
|
{
|
||||||
assert(sym);
|
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));
|
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]->name = strdup(name);
|
||||||
sym->entries.data[sym->entries.size]->id = id;
|
sym->entries.data[sym->entries.size]->id = id;
|
||||||
sym->entries.data[sym->entries.size]->type = type;
|
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)
|
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;
|
return NULL;
|
||||||
|
|
|
@ -20,9 +20,10 @@ typedef struct {
|
||||||
node_t* node;
|
node_t* node;
|
||||||
} sym_entry_t;
|
} sym_entry_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct sym {
|
||||||
tysy_t* tysy;
|
tysy_t* tysy;
|
||||||
err_t* err;
|
err_t* err;
|
||||||
|
struct sym* parent;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
int id_counter;
|
int id_counter;
|
||||||
|
@ -35,7 +36,7 @@ typedef struct {
|
||||||
void sym_init(sym_t* sym, tysy_t* tysy, err_t* err);
|
void sym_init(sym_t* sym, tysy_t* tysy, err_t* err);
|
||||||
void sym_free(sym_t* sym);
|
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,
|
int scope, int state_flag,
|
||||||
node_t* node);
|
node_t* node);
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
#define TYPE_KIND(G) \
|
#define TYPE_KIND(G) \
|
||||||
G(TYPE_NUM), G(TYPE_BOOL), G(TYPE_STR), \
|
G(TYPE_NUM), G(TYPE_BOOL), G(TYPE_STR), \
|
||||||
G(TYPE_FUN)
|
G(TYPE_FUN), G(TYPE_REF)
|
||||||
|
|
||||||
RZ_ENUM_H(TypeKind, TYPE_KIND);
|
RZ_ENUM_H(TypeKind, TYPE_KIND);
|
||||||
|
|
||||||
|
|
18
lib/tysy.c
18
lib/tysy.c
|
@ -32,6 +32,13 @@ void tysy_init(tysy_t* tysy)
|
||||||
type_init(ty, TYPE_FUN);
|
type_init(ty, TYPE_FUN);
|
||||||
tysy_register_new_type(tysy, "fun", ty);
|
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)
|
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;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -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_bool(tysy_t* tysy, int value, int line);
|
||||||
value_t* tysy_new_str(tysy_t* tysy, char* 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_fun(tysy_t* tysy, fun_t* fun, int line);
|
||||||
|
value_t* tysy_new_ref(tysy_t* tysy, size_t ref, int line);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
29
lib/value.c
29
lib/value.c
|
@ -12,6 +12,27 @@ void value_init(value_t* value, type_t* type, int line)
|
||||||
value->line = 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)
|
void value_free(value_t* value)
|
||||||
{
|
{
|
||||||
assert(value);
|
assert(value);
|
||||||
|
@ -56,6 +77,10 @@ int value_eq(value_t* value, value_t* rhs)
|
||||||
return value->value.fun == rhs->value.fun;
|
return value->value.fun == rhs->value.fun;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case TYPE_REF: {
|
||||||
|
return value->value.ref == rhs->value.ref;
|
||||||
|
} break;
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
fprintf(stderr, "Cannot compare value of type '%s'.\n",
|
fprintf(stderr, "Cannot compare value of type '%s'.\n",
|
||||||
TypeKindStr[value->type->kind]);
|
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]");
|
return snprintf(buffer, size, "[fun]");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TYPE_REF:
|
||||||
|
return snprintf(buffer, size, "[ref %d]", (int) value->value.ref);
|
||||||
|
break;
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
fprintf(stderr, "Cannot stringify unknown value of type '%s'.\n",
|
fprintf(stderr, "Cannot stringify unknown value of type '%s'.\n",
|
||||||
TypeKindStr[value->type->kind]);
|
TypeKindStr[value->type->kind]);
|
||||||
|
|
|
@ -6,12 +6,13 @@
|
||||||
|
|
||||||
struct program;
|
struct program;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct value {
|
||||||
type_t* type;
|
type_t* type;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
double num;
|
double num;
|
||||||
int bool;
|
int bool;
|
||||||
|
size_t ref;
|
||||||
char* str;
|
char* str;
|
||||||
fun_t* fun;
|
fun_t* fun;
|
||||||
} value;
|
} value;
|
||||||
|
@ -20,6 +21,7 @@ typedef struct {
|
||||||
} value_t;
|
} value_t;
|
||||||
|
|
||||||
void value_init(value_t* value, type_t* type, int line);
|
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);
|
void value_free(value_t* value);
|
||||||
|
|
||||||
int value_eq(value_t* value, value_t* rhs);
|
int value_eq(value_t* value, value_t* rhs);
|
||||||
|
|
219
lib/vm.c
219
lib/vm.c
|
@ -1,5 +1,8 @@
|
||||||
#include "vm.h"
|
#include "vm.h"
|
||||||
#include "lib/commons.h"
|
#include "lib/commons.h"
|
||||||
|
#include "lib/fun.h"
|
||||||
|
#include "lib/heap.h"
|
||||||
|
#include "lib/locals.h"
|
||||||
#include "lib/mod.h"
|
#include "lib/mod.h"
|
||||||
#include "lib/type.h"
|
#include "lib/type.h"
|
||||||
#include "lib/tysy.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);
|
assert(tysy);
|
||||||
|
|
||||||
vm->top_frame = NULL;
|
vm->top_frame = NULL;
|
||||||
|
locals_init(&vm->locals);
|
||||||
vm_frame_push(vm, NULL);
|
vm_frame_push(vm, NULL);
|
||||||
|
|
||||||
vm->tysy = tysy;
|
vm->tysy = tysy;
|
||||||
vm->err = err;
|
vm->err = err;
|
||||||
|
|
||||||
|
heap_init(&vm->heap);
|
||||||
}
|
}
|
||||||
|
|
||||||
void vm_free(vm_t* vm)
|
void vm_free(vm_t* vm)
|
||||||
|
@ -34,21 +40,26 @@ void vm_free(vm_t* vm)
|
||||||
}
|
}
|
||||||
|
|
||||||
vm->top_frame = NULL;
|
vm->top_frame = NULL;
|
||||||
|
|
||||||
|
heap_free(&vm->heap);
|
||||||
|
|
||||||
|
locals_free(&vm->locals);
|
||||||
}
|
}
|
||||||
|
|
||||||
void vm_frame_init(frame_t* frame)
|
void vm_frame_init(frame_t* frame)
|
||||||
{
|
{
|
||||||
assert(frame);
|
assert(frame);
|
||||||
|
|
||||||
|
frame->fun = NULL;
|
||||||
|
|
||||||
frame->pc = 0;
|
frame->pc = 0;
|
||||||
frame->bp = 0;
|
frame->bp = 0;
|
||||||
frame->sp = 0;
|
frame->sp = 0;
|
||||||
|
|
||||||
frame->prev = NULL;
|
frame->prev = NULL;
|
||||||
frame->program = NULL;
|
frame->program = NULL;
|
||||||
frame->locals.cap = 0;
|
|
||||||
frame->locals.size = 0;
|
frame->locals = NULL;
|
||||||
frame->locals.data = NULL;
|
|
||||||
|
|
||||||
frame->alloc.cap = 0;
|
frame->alloc.cap = 0;
|
||||||
frame->alloc.size = 0;
|
frame->alloc.size = 0;
|
||||||
|
@ -57,18 +68,6 @@ void vm_frame_init(frame_t* frame)
|
||||||
|
|
||||||
void vm_frame_free(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)
|
if (frame->prev != NULL)
|
||||||
{
|
{
|
||||||
vm_frame_free((frame_t*) frame->prev);
|
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);
|
assert(vm);
|
||||||
|
|
||||||
|
@ -84,7 +83,17 @@ void vm_frame_push(vm_t* vm, program_t* program)
|
||||||
vm_frame_init(frame);
|
vm_frame_init(frame);
|
||||||
|
|
||||||
frame->prev = (struct frame*) vm->top_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;
|
vm->top_frame = frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,6 +101,13 @@ int vm_frame_pop(vm_t* vm)
|
||||||
{
|
{
|
||||||
assert(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)
|
if (vm->top_frame)
|
||||||
{
|
{
|
||||||
vm_clear_alloc(vm->top_frame);
|
vm_clear_alloc(vm->top_frame);
|
||||||
|
@ -113,57 +129,6 @@ int vm_frame_pop(vm_t* vm)
|
||||||
return 0;
|
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)
|
void vm_push_new(vm_t* vm, value_t* value)
|
||||||
{
|
{
|
||||||
assert(value);
|
assert(value);
|
||||||
|
@ -465,7 +430,25 @@ int vm_exec_instr(vm_t* vm, Opcode op, param_t param)
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case OP_LOAD: {
|
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)
|
if (!local)
|
||||||
{
|
{
|
||||||
|
@ -492,6 +475,7 @@ int vm_exec_instr(vm_t* vm, Opcode op, param_t param)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
assert(local->addr < vm->top_frame->sp);
|
||||||
vm_push(vm, vm->top_frame->stack[local->addr]);
|
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: {
|
case OP_STORE: {
|
||||||
assert(vm->top_frame->sp > 0);
|
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++;
|
vm->top_frame->pc++;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case OP_CALL: {
|
case OP_CALL: {
|
||||||
size_t const ARG_SZ = param + 1;
|
size_t const ARG_SZ = param;
|
||||||
value_t* args[ARG_SZ];
|
value_t* args[ARG_SZ];
|
||||||
|
|
||||||
|
value_t* fun_ref = vm_pop(vm);
|
||||||
|
|
||||||
for (size_t i=0; i<ARG_SZ; i++)
|
for (size_t i=0; i<ARG_SZ; i++)
|
||||||
{
|
{
|
||||||
value_t* val = vm_pop(vm);
|
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);
|
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->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++)
|
for (size_t i=0; i<ARG_SZ; i++)
|
||||||
{
|
{
|
||||||
value_t* arg = args[i];
|
value_t* arg = args[i];
|
||||||
|
size_t addr = fun->arg_base + (ARG_SZ - 1 - i);
|
||||||
|
|
||||||
vm_push(vm, arg);
|
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;
|
} break;
|
||||||
|
|
||||||
case OP_RET: {
|
case OP_RET: {
|
||||||
|
|
||||||
frame_t* frame = (frame_t*) vm->top_frame;
|
frame_t* frame = (frame_t*) vm->top_frame;
|
||||||
frame_t* prev = (frame_t*) vm->top_frame->prev;
|
frame_t* prev = (frame_t*) vm->top_frame->prev;
|
||||||
|
|
||||||
|
|
22
lib/vm.h
22
lib/vm.h
|
@ -8,11 +8,8 @@
|
||||||
#include "tysy.h"
|
#include "tysy.h"
|
||||||
#include "sym.h"
|
#include "sym.h"
|
||||||
#include "program.h"
|
#include "program.h"
|
||||||
|
#include "heap.h"
|
||||||
typedef struct {
|
#include "locals.h"
|
||||||
int id;
|
|
||||||
param_t addr;
|
|
||||||
} local_t;
|
|
||||||
|
|
||||||
typedef struct stack_frame{
|
typedef struct stack_frame{
|
||||||
struct frame* prev;
|
struct frame* prev;
|
||||||
|
@ -22,12 +19,8 @@ typedef struct stack_frame{
|
||||||
size_t pc;
|
size_t pc;
|
||||||
size_t bp;
|
size_t bp;
|
||||||
size_t sp;
|
size_t sp;
|
||||||
|
fun_t* fun;
|
||||||
struct {
|
locals_t* locals;
|
||||||
size_t size;
|
|
||||||
size_t cap;
|
|
||||||
local_t** data;
|
|
||||||
} locals;
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
size_t size;
|
size_t size;
|
||||||
|
@ -42,6 +35,8 @@ typedef struct {
|
||||||
tysy_t* tysy;
|
tysy_t* tysy;
|
||||||
err_t* err;
|
err_t* err;
|
||||||
frame_t* top_frame;
|
frame_t* top_frame;
|
||||||
|
heap_t heap;
|
||||||
|
locals_t locals;
|
||||||
} vm_t;
|
} vm_t;
|
||||||
|
|
||||||
void vm_init(vm_t* vm, sym_t* sym, tysy_t* tysy, err_t* err);
|
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_init(frame_t* frame);
|
||||||
void vm_frame_free(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);
|
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_new(vm_t* vm, value_t* value);
|
||||||
void vm_push(vm_t* vm, value_t* value);
|
void vm_push(vm_t* vm, value_t* value);
|
||||||
value_t* vm_pop(vm_t* vm);
|
value_t* vm_pop(vm_t* vm);
|
||||||
|
|
|
@ -48,6 +48,8 @@ roza_lib = static_library(
|
||||||
|
|
||||||
# exec
|
# exec
|
||||||
'lib/vm.c',
|
'lib/vm.c',
|
||||||
|
'lib/heap.c',
|
||||||
|
'lib/locals.c',
|
||||||
],
|
],
|
||||||
|
|
||||||
dependencies: [
|
dependencies: [
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
# FUNCTIONS
|
# FUNCTIONS
|
||||||
# =========
|
# =========
|
||||||
|
|
||||||
fun double(n)
|
fun double(n)
|
||||||
n * 2
|
n * 2
|
||||||
end
|
end
|
||||||
|
@ -38,7 +37,6 @@ assert max(7, 9) == 9
|
||||||
|
|
||||||
# RECURSIVITY
|
# RECURSIVITY
|
||||||
# ===========
|
# ===========
|
||||||
|
|
||||||
fun fac(n)
|
fun fac(n)
|
||||||
if n == 0 then
|
if n == 0 then
|
||||||
return 1
|
return 1
|
||||||
|
@ -58,3 +56,60 @@ fun fib(n)
|
||||||
end
|
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
|
Loading…
Reference in New Issue