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 "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,28 +379,39 @@ 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);
// 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]); prepass_run(&pre, (node_t*) node->children.data[2]);
// self fun->arg_base = *compiler->id;
sym_declare((sym_t*) fun->sym, fun_name,
tysy_try_find_type(comp.tysy, "fun"),
comp.scope,
SYM_DECL,
node);
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);
@ -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];

View File

@ -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);

View File

@ -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;
} }

View File

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

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_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)

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_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);

View File

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

View File

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

View File

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

View File

@ -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);

View File

@ -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);

View File

@ -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;
}

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_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

View File

@ -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]);

View File

@ -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
View File

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

View File

@ -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);

View File

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

View File

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