Compare commits

...

4 Commits

Author SHA1 Message Date
bog 3f38358390 ADD: nested functions. 2023-08-29 00:14:24 +02:00
bog bc869aa6e8 ADD: high order functions. 2023-08-28 22:43:37 +02:00
bog 9b31a14723 ADD: recursive functions. 2023-08-28 20:55:37 +02:00
bog 5825f5b316 ADD: syntaxic sugar for function definitions. 2023-08-28 14:49:42 +02:00
9 changed files with 439 additions and 146 deletions

View File

@ -11,6 +11,9 @@ void compiler_init(compiler* self)
self->binfo.capacity = 1; self->binfo.capacity = 1;
self->binfo.data = malloc(sizeof(block_info*) * self->binfo.capacity); self->binfo.data = malloc(sizeof(block_info*) * self->binfo.capacity);
self->fun_stack.size = 0;
self->fun_stack.capacity = 1;
self->fun_stack.data = malloc(sizeof(char*) * self->fun_stack.capacity);
} }
void compiler_free(compiler* self) void compiler_free(compiler* self)
@ -21,6 +24,17 @@ void compiler_free(compiler* self)
free(self->sym); free(self->sym);
self->sym = NULL; self->sym = NULL;
for (size_t i=0; i<self->fun_stack.size; i++)
{
free(self->fun_stack.data[i]);
}
free(self->fun_stack.data);
self->fun_stack.size = 0;
self->fun_stack.capacity = 0;
self->fun_stack.data = NULL;
for (size_t i=0; i<self->binfo.size; i++) for (size_t i=0; i<self->binfo.size; i++)
{ {
block_info_free(self->binfo.data[i]); block_info_free(self->binfo.data[i]);
@ -34,6 +48,39 @@ void compiler_free(compiler* self)
self->binfo.data = NULL; self->binfo.data = NULL;
} }
void compiler_push_fun(compiler* self, char* fun_name)
{
assert(self);
if (self->fun_stack.size >= self->fun_stack.capacity)
{
self->fun_stack.capacity *= 2;
self->fun_stack.data = realloc(
self->fun_stack.data,
sizeof(char*) * self->fun_stack.capacity
);
}
self->fun_stack.data[self->fun_stack.size] = str_new(fun_name);
self->fun_stack.size++;
}
void compiler_pop_fun(compiler* self)
{
assert(self);
assert(self->fun_stack.size > 0);
free(self->fun_stack.data[self->fun_stack.size - 1]);
self->fun_stack.size--;
}
char* compiler_top_fun(compiler* self)
{
assert(self);
assert(self->fun_stack.size > 0);
return self->fun_stack.data[self->fun_stack.size - 1];
}
block_info* compiler_current_info(compiler* self) block_info* compiler_current_info(compiler* self)
{ {
assert(self); assert(self);
@ -167,6 +214,32 @@ void compile_node(compiler* self, node* root, program* prog)
program_add_instr(prog, OP_ADEREF, NO_PARAM); program_add_instr(prog, OP_ADEREF, NO_PARAM);
} }
// Variables stuff // Variables stuff
else if (root->type == NODE_FUNDECL)
{
cstatic cs;
cstatic_init(&cs);
type* ty = cstatic_resolve_new(&cs,
self->sym,
root->children.data[1]);
size_t id = symtable_declare(
self->sym,
root->children.data[0]->value,
ty,
root->children.data[1]
);
compiler_push_fun(self, root->children.data[0]->value);
compile_node(self, root->children.data[1], prog);
compiler_pop_fun(self);
program_add_instr(prog, OP_STORE, id);
type_free(ty);
free(ty);
cstatic_free(&cs);
}
else if (root->type == NODE_CONSTDECL) else if (root->type == NODE_CONSTDECL)
{ {
cstatic cs; cstatic cs;
@ -183,7 +256,20 @@ void compile_node(compiler* self, node* root, program* prog)
root->children.data[1] root->children.data[1]
); );
int is_fn = root->children.data[1]->type == NODE_FUN;
if (is_fn)
{
compiler_push_fun(self, root->children.data[0]->value);
}
compile_node(self, root->children.data[1], prog); compile_node(self, root->children.data[1], prog);
if (is_fn)
{
compiler_pop_fun(self);
}
program_add_instr(prog, OP_STORE, id); program_add_instr(prog, OP_STORE, id);
type_free(ty); type_free(ty);
@ -211,7 +297,20 @@ void compile_node(compiler* self, node* root, program* prog)
root->children.data[1] root->children.data[1]
); );
int is_fn = root->children.data[1]->type == NODE_FUN;
if (is_fn)
{
compiler_push_fun(self, root->children.data[0]->value);
}
compile_node(self, root->children.data[1], prog); compile_node(self, root->children.data[1], prog);
if (is_fn)
{
compiler_pop_fun(self);
}
program_add_instr(prog, OP_STORE, id); program_add_instr(prog, OP_STORE, id);
type_free(ty); type_free(ty);
@ -270,6 +369,7 @@ void compile_node(compiler* self, node* root, program* prog)
int lhs = cstatic_resolve_base_type(&cs, int lhs = cstatic_resolve_base_type(&cs,
self->sym, self->sym,
root->children.data[0]); root->children.data[0]);
int rhs = cstatic_resolve_base_type(&cs, self->sym, int rhs = cstatic_resolve_base_type(&cs, self->sym,
root->children.data[1]); root->children.data[1]);
@ -343,64 +443,70 @@ void compile_node(compiler* self, node* root, program* prog)
} }
else if (root->type == NODE_FUN) else if (root->type == NODE_FUN)
{ {
// init body
// prepare compiler
compiler comp; compiler comp;
compiler_init(&comp); compiler_init(&comp);
program* fun_prog = malloc(sizeof(program));
program_init(fun_prog);
node* block = root->children.data[root->children.size - 1];
// add params // prepare program
program local_prog;
program_init(&local_prog);
// resolve function type
cstatic cs;
cstatic_init(&cs);
type* fn_ty = cstatic_resolve_new(&cs, self->sym, root);
// prepare environment (parameters and function)
for (size_t i=0; i<root->children.size; i++) for (size_t i=0; i<root->children.size; i++)
{ {
node* param = root->children.data[i]; node* param = root->children.data[i];
if (param->type != NODE_FUN_PARAM) { continue; }
if (param->type == NODE_FUN_PARAM) char* name = param->children.data[0]->value;
{ type* ty = type_new_from_node(param->children.data[1]);
char const* param_name = param->children.data[0]->value;
type* param_ty =
type_new_from_node(param->children.data[1]);
symtable_declare(comp.sym, param_name symtable_declare(
, param_ty comp.sym,
, param->children.data[0]); name,
ty,
type_free(param_ty); free(param_ty); param
}
}
// compile body
compile_node(&comp, block, fun_prog);
compiler_free(&comp);
// init fun object
cstatic cs;
cstatic_init(&cs);
fun* fn = malloc(sizeof(fun));
type* ty = cstatic_resolve_new(&cs, self->sym, root);
fun_init(fn, ty, (struct program*) fun_prog);
program_free(fun_prog); free(fun_prog); fun_prog = NULL;
type_free(ty); free(ty);
// create value
value* val = malloc(sizeof(value));
value_init_fun(val, fn, root->lineno);
// push it
program_add_instr(
prog,
OP_PUSH,
program_add_pool(prog, val)
); );
type_free(ty); free(ty);
}
char* fun_name = compiler_top_fun(self);
symtable_declare(
comp.sym,
fun_name,
fn_ty,
root
);
// compile fun block
node* fun_block = root->children.data[root->children.size - 1];
compile_node(&comp, fun_block, &local_prog);
//char c[1024]; node_str(root, c, 1024); printf("%s\n", c);
// create value
fun* fn = malloc(sizeof(fun));
fun_init(fn, fn_ty, (struct program*) &local_prog);
value* val = malloc(sizeof(value));
value_init_fun(val, fn, root->lineno);
cstatic_free(&cs);
// push value
program_add_instr(prog, OP_PUSH, program_add_pool(prog, val));
// free stuff
program_free(&local_prog);
compiler_free(&comp);
type_free(fn_ty); free(fn_ty);
value_free(val); free(val); value_free(val); free(val);
fun_free(fn); free(fn); fun_free(fn); free(fn);
cstatic_free(&cs);
} }
else if (root->type == NODE_CALL) else if (root->type == NODE_CALL)
{ {

View File

@ -16,11 +16,20 @@ typedef struct {
block_info** data; block_info** data;
} binfo; } binfo;
struct {
size_t size;
size_t capacity;
char** data;
} fun_stack;
} compiler; } compiler;
void compiler_init(compiler* self); void compiler_init(compiler* self);
void compiler_free(compiler* self); void compiler_free(compiler* self);
void compiler_push_fun(compiler* self, char* fun_name);
void compiler_pop_fun(compiler* self);
char* compiler_top_fun(compiler* self);
block_info* compiler_current_info(compiler* self); block_info* compiler_current_info(compiler* self);
block_info* compiler_find_info(compiler* self, int kind); block_info* compiler_find_info(compiler* self, int kind);

View File

@ -7,7 +7,7 @@ void cstatic_init(cstatic* self)
self->fun_types.size = 0; self->fun_types.size = 0;
self->fun_types.capacity = 1; self->fun_types.capacity = 1;
self->fun_types.data = malloc(sizeof(type*) * self->fun_types.capacity); self->fun_types.data = malloc(sizeof(fun_info*) * self->fun_types.capacity);
} }
void cstatic_free(cstatic* self) void cstatic_free(cstatic* self)
@ -16,8 +16,8 @@ void cstatic_free(cstatic* self)
for (size_t i=0; i<self->fun_types.size; i++) for (size_t i=0; i<self->fun_types.size; i++)
{ {
type_free(self->fun_types.data[i]); type_free(self->fun_types.data[i]->ty);
free(self->fun_types.data[i]); free(self->fun_types.data[i]->ty);
} }
free(self->fun_types.data); free(self->fun_types.data);
@ -63,7 +63,6 @@ type* cstatic_resolve_new(cstatic* self, symtable* sym, node* ast)
type_new_from_node( type_new_from_node(
ast->children.data[i]->children.data[1] ast->children.data[i]->children.data[1]
); );
type_add_sub_type(ty, param_ty); type_add_sub_type(ty, param_ty);
type_free(param_ty); free(param_ty); type_free(param_ty); free(param_ty);
@ -90,18 +89,44 @@ type* cstatic_resolve_new(cstatic* self, symtable* sym, node* ast)
if (ast->type == NODE_CALL) if (ast->type == NODE_CALL)
{ {
char const* fun_name = ast->children.data[0]->value; char const* fun_name = ast->children.data[0]->value;
symentry* entry = symtable_find(sym, fun_name); symentry* entry = symtable_find(sym, fun_name);
assert(entry); fun_info* info = NULL;
if (self->fun_types.size > 0)
{
info = cstatic_top_fun(self);
}
type* fun_type = NULL;
if (entry)
{
fun_type = entry->ty;
}
else if (info && info->name && strcmp(info->name, fun_name) == 0)
{
fun_type = info->ty;
}
else
{
fprintf(stderr
, "E(%d): cannot call unknown function '%s'.\n"
, ast->children.data[0]->lineno
, fun_name);
assert(0);
}
type* fun_type = entry->ty;
assert(fun_type); assert(fun_type);
size_t ret_count = fun_type->sub_types.size; size_t ret_count = fun_type->sub_types.size;
if (ret_count > 0) if (ret_count > 0)
{ {
type* ret_type = fun_type->sub_types.data[ret_count - 1]; type* ret_type =
fun_type->sub_types.data[ret_count - 1];
assert(ret_type); assert(ret_type);
if (ret_type->kind == KIND_RETURN) if (ret_type->kind == KIND_RETURN)
@ -160,7 +185,9 @@ type* cstatic_resolve_new(cstatic* self, symtable* sym, node* ast)
return ty; return ty;
} }
if (ast->type == NODE_VARDECL) if (ast->type == NODE_VARDECL
|| ast->type == NODE_CONSTDECL
|| ast->type == NODE_FUNDECL)
{ {
type* ty = cstatic_resolve_new(self, type* ty = cstatic_resolve_new(self,
sym, sym,
@ -366,8 +393,6 @@ int cstatic_check(cstatic* self, node* ast, symtable* sym, char* msg, size_t siz
{ {
type* ty = cstatic_resolve_new(self, sym, ast); type* ty = cstatic_resolve_new(self, sym, ast);
cstatic_push_fun(self, ty);
type_free(ty); free(ty); type_free(ty); free(ty);
symtable* inner_table = symtable_new_clone(sym); symtable* inner_table = symtable_new_clone(sym);
@ -394,9 +419,7 @@ int cstatic_check(cstatic* self, node* ast, symtable* sym, char* msg, size_t siz
msg, msg,
size size
); );
symtable_free(inner_table); free(inner_table); symtable_free(inner_table); free(inner_table);
cstatic_pop_fun(self);
return status; return status;
@ -406,7 +429,12 @@ int cstatic_check(cstatic* self, node* ast, symtable* sym, char* msg, size_t siz
if (ast->type == NODE_RETURN) if (ast->type == NODE_RETURN)
{ {
type* ret_ty = cstatic_resolve_new(self, sym, ast); type* ret_ty = cstatic_resolve_new(self, sym, ast);
type* fun_ty = cstatic_top_fun(self);
int status_inner = cstatic_check_children(self, ast, sym, msg, size);
if (!status_inner) { return status_inner; }
type* fun_ty = cstatic_top_fun(self)->ty;
type* fun_res = NULL; type* fun_res = NULL;
@ -421,7 +449,7 @@ int cstatic_check(cstatic* self, node* ast, symtable* sym, char* msg, size_t siz
} }
assert(fun_res); assert(fun_res);
assert(ret_ty);
int status = cstatic_check_same_type_ptr( int status = cstatic_check_same_type_ptr(
self, self,
ast, ast,
@ -449,9 +477,24 @@ int cstatic_check(cstatic* self, node* ast, symtable* sym, char* msg, size_t siz
{ {
char const* fun_name = ast->children.data[0]->value; char const* fun_name = ast->children.data[0]->value;
symentry* entry = symtable_find(sym, fun_name); symentry* entry = symtable_find(sym, fun_name);
assert(entry);
type* fun_type = entry->ty; type* fun_type = NULL;
if (entry)
{
fun_type = entry->ty;
}
else
{
fun_info* info = cstatic_top_fun(self);
if (info && info->name)
{
fun_type = info->ty;
}
}
assert(fun_type);
node* args = ast->children.data[1]; node* args = ast->children.data[1];
size_t arity = 0; size_t arity = 0;
@ -459,6 +502,7 @@ int cstatic_check(cstatic* self, node* ast, symtable* sym, char* msg, size_t siz
for (size_t i=0; i<fun_type->sub_types.size; i++) for (size_t i=0; i<fun_type->sub_types.size; i++)
{ {
type* ty = fun_type->sub_types.data[i]; type* ty = fun_type->sub_types.data[i];
if (ty->kind != KIND_RETURN) if (ty->kind != KIND_RETURN)
{ {
arity++; arity++;
@ -513,7 +557,7 @@ int cstatic_check(cstatic* self, node* ast, symtable* sym, char* msg, size_t siz
} }
// Children // Children
for (size_t i=0; i<ast->children.size; i++) /*for (size_t i=0; i<ast->children.size; i++)
{ {
int status = cstatic_check(self, ast->children.data[i], int status = cstatic_check(self, ast->children.data[i],
sym, sym,
@ -524,6 +568,59 @@ int cstatic_check(cstatic* self, node* ast, symtable* sym, char* msg, size_t siz
return 0; return 0;
} }
}*/
if (ast->type == NODE_VARDECL
|| ast->type == NODE_CONSTDECL
|| ast->type == NODE_FUNDECL)
{
char const* name = ast->children.data[0]->value;
symentry* entry = symtable_find(sym, name);
if (entry && entry->scope >= sym->scope)
{
fprintf(stderr, "E(%d): '%s' is already defined.\n",
ast->lineno,
name);
exit(-1);
}
type* ty = cstatic_resolve_new(self, sym, ast->children.data[1]);
if (ty->base_type == TY_FUNCTION)
{
cstatic_push_fun(self, ast->children.data[0]->value, ty);
int status =
cstatic_check(self, ast->children.data[1], sym, msg, size);
cstatic_pop_fun(self);
if (!status) { return status; }
}
else
{
int status =
cstatic_check(self, ast->children.data[1], sym, msg, size);
if (!status)
{
return status;
}
}
assert(ty);
if (ast->type == NODE_VARDECL)
{
symtable_declare_mut(sym, name, ty, ast->children.data[1]);
}
else
{
symtable_declare(sym, name, ty, ast->children.data[1]);
}
type_free(ty);
free(ty);
return 1;
} }
// Arrays // Arrays
@ -725,36 +822,6 @@ int cstatic_check(cstatic* self, node* ast, symtable* sym, char* msg, size_t siz
return 1; return 1;
} }
if (ast->type == NODE_VARDECL
|| ast->type == NODE_CONSTDECL)
{
char const* name = ast->children.data[0]->value;
symentry* entry = symtable_find(sym, name);
if (entry && entry->scope >= sym->scope)
{
fprintf(stderr, "E(%d): '%s' is already defined.\n",
ast->lineno,
name);
exit(-1);
}
type* ty = cstatic_resolve_new(self, sym, ast->children.data[1]);
assert(ty);
if (ast->type == NODE_VARDECL)
{
symtable_declare_mut(sym, name, ty, ast->children.data[1]);
}
else
{
symtable_declare(sym, name, ty, ast->children.data[1]);
}
type_free(ty);
free(ty);
return 1;
}
// Types Operations // Types Operations
if (ast->type == NODE_MUL) if (ast->type == NODE_MUL)
@ -996,6 +1063,36 @@ int cstatic_check(cstatic* self, node* ast, symtable* sym, char* msg, size_t siz
} }
} }
for (size_t i=0; i<ast->children.size; i++)
{
int status = cstatic_check(self, ast->children.data[i],
sym,
msg, size);
if (!status)
{
return 0;
}
}
return 1;
}
int cstatic_check_children(cstatic* self, node* lhs, symtable* sym, char* msg, size_t size)
{
for (size_t i=0; i<lhs->children.size; i++)
{
int status = cstatic_check(self, lhs->children.data[i],
sym,
msg, size);
if (!status)
{
return 0;
}
}
return 1; return 1;
} }
@ -1168,7 +1265,7 @@ int cstatic_check_same_type(cstatic* self, node* lhs, node* rhs, symtable* sym,
return 1; return 1;
} }
void cstatic_push_fun(cstatic* self, type* fun_ty) void cstatic_push_fun(cstatic* self, char* name, type* fun_ty)
{ {
assert(self); assert(self);
assert(fun_ty); assert(fun_ty);
@ -1178,11 +1275,18 @@ void cstatic_push_fun(cstatic* self, type* fun_ty)
self->fun_types.capacity *= 2; self->fun_types.capacity *= 2;
self->fun_types.data = realloc( self->fun_types.data = realloc(
self->fun_types.data, self->fun_types.data,
sizeof(type*) * self->fun_types.capacity sizeof(fun_info*) * self->fun_types.capacity
); );
} }
self->fun_types.data[self->fun_types.size] = type_new_clone(fun_ty); self->fun_types.data[self->fun_types.size] = malloc(sizeof(fun_info));
self->fun_types.data[self->fun_types.size]->ty = type_new_clone(fun_ty);
if (name)
{
self->fun_types.data[self->fun_types.size]->name = str_new(name);
}
self->fun_types.size++; self->fun_types.size++;
} }
@ -1191,13 +1295,20 @@ void cstatic_pop_fun(cstatic* self)
{ {
assert(self->fun_types.size > 0); assert(self->fun_types.size > 0);
type_free(self->fun_types.data[self->fun_types.size - 1]); type_free(self->fun_types.data[self->fun_types.size - 1]->ty);
free(self->fun_types.data[self->fun_types.size - 1]->ty);
if (self->fun_types.data[self->fun_types.size - 1]->name)
{
free(self->fun_types.data[self->fun_types.size - 1]->name);
}
free(self->fun_types.data[self->fun_types.size - 1]); free(self->fun_types.data[self->fun_types.size - 1]);
self->fun_types.size--; self->fun_types.size--;
} }
type* cstatic_top_fun(cstatic* self) fun_info* cstatic_top_fun(cstatic* self)
{ {
assert(self->fun_types.size > 0); assert(self->fun_types.size > 0);
return self->fun_types.data[self->fun_types.size - 1]; return self->fun_types.data[self->fun_types.size - 1];

View File

@ -7,11 +7,16 @@
#define TYPE_END (-1) #define TYPE_END (-1)
typedef struct {
type* ty;
char* name;
} fun_info;
typedef struct { typedef struct {
struct { struct {
size_t size; size_t size;
size_t capacity; size_t capacity;
type** data; fun_info** data;
} fun_types; } fun_types;
} cstatic; } cstatic;
@ -24,6 +29,8 @@ int cstatic_resolve_base_type(cstatic* self, symtable* sym, node* ast);
type* cstatic_resolve_new(cstatic* self, symtable* sym, node* ast); type* cstatic_resolve_new(cstatic* self, symtable* sym, node* ast);
int cstatic_check(cstatic* self, node* ast, symtable* sym, char* msg, size_t size); int cstatic_check(cstatic* self, node* ast, symtable* sym, char* msg, size_t size);
int cstatic_check_children(cstatic* self, node* lhs, symtable* sym, char* msg, size_t size);
int cstatic_check_type(cstatic* self, node* lhs, symtable* sym, int cstatic_check_type(cstatic* self, node* lhs, symtable* sym,
char* msg, size_t size, type* types, ...); char* msg, size_t size, type* types, ...);
@ -37,7 +44,7 @@ int cstatic_check_same_type_ptr(cstatic* self,
int cstatic_check_same_type(cstatic* self, node* lhs, node* rhs, symtable* sym, int cstatic_check_same_type(cstatic* self, node* lhs, node* rhs, symtable* sym,
char* msg, size_t size); char* msg, size_t size);
void cstatic_push_fun(cstatic* self, type* fun_ty); void cstatic_push_fun(cstatic* self, char* name, type* fun_ty);
void cstatic_pop_fun(cstatic* self); void cstatic_pop_fun(cstatic* self);
type* cstatic_top_fun(cstatic* self); fun_info* cstatic_top_fun(cstatic* self);
#endif #endif

View File

@ -16,7 +16,8 @@
G(NODE_IF), G(NODE_ELSE), G(NODE_BLOCK), \ G(NODE_IF), G(NODE_ELSE), G(NODE_BLOCK), \
G(NODE_WHILE), G(NODE_CONTINUE), G(NODE_BREAK), \ G(NODE_WHILE), G(NODE_CONTINUE), G(NODE_BREAK), \
G(NODE_COLON), G(NODE_FUN_TYPE), G(NODE_RETURN), G(NODE_FUN), \ G(NODE_COLON), G(NODE_FUN_TYPE), G(NODE_RETURN), G(NODE_FUN), \
G(NODE_FUN_PARAM), G(NODE_FUN_RET), G(NODE_CALL), G(NODE_ARGS) G(NODE_FUN_PARAM), G(NODE_FUN_RET), G(NODE_CALL), G(NODE_ARGS), \
G(NODE_FUNDECL)
#include "mutils.h" #include "mutils.h"

View File

@ -29,7 +29,7 @@
%token BREAK %token BREAK
%left ASSERT %left ASSERT
%token <str> TYPE BOOLEAN INTEGER FLOAT STRING IDENT %token <str> TYPE BOOLEAN INTEGER FLOAT STRING IDENT
%type <n_children> expr exprs prog array builtins %type <n_children> expr exprs prog array builtins fun_body
%type <n_children> expr_list type type_list ident if %type <n_children> expr_list type type_list ident if
%type <n_children> fun_rets fun_params fun_param fun %type <n_children> fun_rets fun_params fun_param fun
%type <n_children> fun_ret_list fun_call fun_args any instr %type <n_children> fun_ret_list fun_call fun_args any instr
@ -595,33 +595,49 @@ fun_rets:
; ;
fun: fun:
FUN OPAR fun_params CPAR fun_rets block END { FUN ident fun_body {
node* n = malloc(sizeof(node)); node* n = malloc(sizeof(node));
node_init(n, NODE_FUN, "", line); node_init(n, NODE_FUN, "", line);
size_t const SZ = $3;
node* all[SZ];
node* block_node = stack_pop(); for (size_t i=0; i<SZ; i++)
assert(block_node);
node* ret_node = stack_pop();
assert(ret_node);
if ($3 > 0)
{ {
node* params[$3]; all[SZ - 1 - i] = stack_pop();
for (size_t i=0; i<$3; i++)
{
params[i] = stack_pop();
} }
for (size_t i=0; i<$3; i++) node* ident_node = stack_pop();
for (size_t i=0; i<SZ; i++)
{ {
node_add_child(n, params[$3 - 1 - i]); node_add_child(n, all[i]);
}
} }
node_add_child(n, ret_node); node* fdecl = malloc(sizeof(node));
node_add_child(n, block_node); node_init(fdecl, NODE_FUNDECL, "", line);
node_add_child(fdecl, ident_node);
node_add_child(fdecl, n);
stack_push(fdecl);
$$ = 1;
}
| FUN fun_body {
node* n = malloc(sizeof(node));
node_init(n, NODE_FUN, "", line);
size_t const SZ = $2;
node* all[SZ];
for (size_t i=0; i<SZ; i++)
{
all[SZ - 1 - i] = stack_pop();
}
for (size_t i=0; i<SZ; i++)
{
node_add_child(n, all[i]);
}
stack_push(n); stack_push(n);
@ -629,6 +645,12 @@ fun:
} }
; ;
fun_body:
OPAR fun_params CPAR fun_rets block END {
$$ = $2 + $4 + $5;
}
;
fun_args: fun_args:
expr_list { expr_list {
node* n = malloc(sizeof(node)); node* n = malloc(sizeof(node));

View File

@ -35,6 +35,7 @@ type* type_init_from_node(node* root)
for (size_t i=0; i< rets->children.size; i++) for (size_t i=0; i< rets->children.size; i++)
{ {
type* t = type_new_from_node(rets->children.data[i]); type* t = type_new_from_node(rets->children.data[i]);
t->kind = KIND_RETURN;
type_add_sub_type(ty, t); type_add_sub_type(ty, t);
type_free(t); free(t); type_free(t); free(t);
} }

View File

@ -1150,7 +1150,11 @@ void vm_call(vm* self, int param)
{ {
assert(self); assert(self);
// get function and parameters vm v;
vm_init(&v);
// get arguments
value* args[param]; value* args[param];
for (int i=0; i<param; i++) for (int i=0; i<param; i++)
@ -1158,33 +1162,30 @@ void vm_call(vm* self, int param)
args[param - 1 - i] = vm_pop_value(self); args[param - 1 - i] = vm_pop_value(self);
} }
value* fun_val = vm_pop_value(self);
fun* f = fun_val->val.fun_val;
// create new ecxecution environment
vm v;
vm_init(&v);
for (int i=0; i<param; i++) for (int i=0; i<param; i++)
{ {
vm_set(&v, i, args[i]); vm_set(&v, i, args[i]);
} }
// execute function // get calling function
vm_exec(&v, (program*) f->prog); value* function_val = vm_pop_value(self);
fun* function = function_val->val.fun_val;
vm_set(&v, param, function_val);
value* ret = value_new_clone(v.stack.data[v.stack.size - 1]); // execute and finalize
vm_push_value(self, ret);
vm_exec(&v, (program*) function->prog);
vm_push_value(self, value_new_clone(v.stack.data[v.stack.size - 1]));
// cleanup
vm_free(&v); vm_free(&v);
value_free(function_val); free(function_val);
for (int i=0; i<param; i++) for (int i=0; i<param; i++)
{ {
value_free(args[i]); free(args[i]); value_free(args[i]); free(args[i]);
} }
value_free(fun_val); free(fun_val);
self->pc++; self->pc++;
} }

View File

@ -30,3 +30,38 @@ end
assert 43 == *d assert 43 == *d
fun e (n as int) as int
return n * 2
end
assert 14 == e 7
fun f (n as int) as int
if n == 0
return 1
end
return n * f(n - 1)
end
assert 120 == f 5
fun h (n as int, m as fun<int:int>) as int
return (m (m n))
end
fun i (n as int) as int
return n * 3
end
assert 27 == h 3, i
fun j (n as int) as int
fun j_inner (n as int) as int
return n * 2
end
return j_inner (j_inner n)
end
assert 32 == j 8