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.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)
@ -21,6 +24,17 @@ void compiler_free(compiler* self)
free(self->sym);
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++)
{
block_info_free(self->binfo.data[i]);
@ -34,6 +48,39 @@ void compiler_free(compiler* self)
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)
{
assert(self);
@ -167,6 +214,32 @@ void compile_node(compiler* self, node* root, program* prog)
program_add_instr(prog, OP_ADEREF, NO_PARAM);
}
// 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)
{
cstatic cs;
@ -183,7 +256,20 @@ void compile_node(compiler* self, node* root, program* prog)
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);
if (is_fn)
{
compiler_pop_fun(self);
}
program_add_instr(prog, OP_STORE, id);
type_free(ty);
@ -211,7 +297,20 @@ void compile_node(compiler* self, node* root, program* prog)
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);
if (is_fn)
{
compiler_pop_fun(self);
}
program_add_instr(prog, OP_STORE, id);
type_free(ty);
@ -270,6 +369,7 @@ void compile_node(compiler* self, node* root, program* prog)
int lhs = cstatic_resolve_base_type(&cs,
self->sym,
root->children.data[0]);
int rhs = cstatic_resolve_base_type(&cs, self->sym,
root->children.data[1]);
@ -343,64 +443,70 @@ void compile_node(compiler* self, node* root, program* prog)
}
else if (root->type == NODE_FUN)
{
// init body
// prepare compiler
compiler 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++)
{
node* param = root->children.data[i];
if (param->type != NODE_FUN_PARAM) { continue; }
if (param->type == NODE_FUN_PARAM)
{
char const* param_name = param->children.data[0]->value;
type* param_ty =
type_new_from_node(param->children.data[1]);
char* name = param->children.data[0]->value;
type* ty = type_new_from_node(param->children.data[1]);
symtable_declare(comp.sym, param_name
, param_ty
, param->children.data[0]);
symtable_declare(
comp.sym,
name,
ty,
param
);
type_free(param_ty); free(param_ty);
}
type_free(ty); free(ty);
}
char* fun_name = compiler_top_fun(self);
// 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)
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);
fun_free(fn); free(fn);
cstatic_free(&cs);
}
else if (root->type == NODE_CALL)
{

View File

@ -16,11 +16,20 @@ typedef struct {
block_info** data;
} binfo;
struct {
size_t size;
size_t capacity;
char** data;
} fun_stack;
} compiler;
void compiler_init(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_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.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)
@ -16,8 +16,8 @@ void cstatic_free(cstatic* self)
for (size_t i=0; i<self->fun_types.size; i++)
{
type_free(self->fun_types.data[i]);
free(self->fun_types.data[i]);
type_free(self->fun_types.data[i]->ty);
free(self->fun_types.data[i]->ty);
}
free(self->fun_types.data);
@ -63,7 +63,6 @@ type* cstatic_resolve_new(cstatic* self, symtable* sym, node* ast)
type_new_from_node(
ast->children.data[i]->children.data[1]
);
type_add_sub_type(ty, 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)
{
char const* fun_name = ast->children.data[0]->value;
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);
size_t ret_count = fun_type->sub_types.size;
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);
if (ret_type->kind == KIND_RETURN)
@ -160,7 +185,9 @@ type* cstatic_resolve_new(cstatic* self, symtable* sym, node* ast)
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,
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);
cstatic_push_fun(self, ty);
type_free(ty); free(ty);
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,
size
);
symtable_free(inner_table); free(inner_table);
cstatic_pop_fun(self);
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)
{
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;
@ -421,7 +449,7 @@ int cstatic_check(cstatic* self, node* ast, symtable* sym, char* msg, size_t siz
}
assert(fun_res);
assert(ret_ty);
int status = cstatic_check_same_type_ptr(
self,
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;
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];
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++)
{
type* ty = fun_type->sub_types.data[i];
if (ty->kind != KIND_RETURN)
{
arity++;
@ -513,7 +557,7 @@ int cstatic_check(cstatic* self, node* ast, symtable* sym, char* msg, size_t siz
}
// 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],
sym,
@ -524,6 +568,59 @@ int cstatic_check(cstatic* self, node* ast, symtable* sym, char* msg, size_t siz
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
@ -725,36 +822,6 @@ int cstatic_check(cstatic* self, node* ast, symtable* sym, char* msg, size_t siz
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
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;
}
@ -1168,7 +1265,7 @@ int cstatic_check_same_type(cstatic* self, node* lhs, node* rhs, symtable* sym,
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(fun_ty);
@ -1178,11 +1275,18 @@ void cstatic_push_fun(cstatic* self, type* fun_ty)
self->fun_types.capacity *= 2;
self->fun_types.data = realloc(
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++;
}
@ -1191,13 +1295,20 @@ void cstatic_pop_fun(cstatic* self)
{
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]);
self->fun_types.size--;
}
type* cstatic_top_fun(cstatic* self)
fun_info* cstatic_top_fun(cstatic* self)
{
assert(self->fun_types.size > 0);
return self->fun_types.data[self->fun_types.size - 1];

View File

@ -7,11 +7,16 @@
#define TYPE_END (-1)
typedef struct {
type* ty;
char* name;
} fun_info;
typedef struct {
struct {
size_t size;
size_t capacity;
type** data;
fun_info** data;
} fun_types;
} 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);
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,
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,
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);
type* cstatic_top_fun(cstatic* self);
fun_info* cstatic_top_fun(cstatic* self);
#endif

View File

@ -16,7 +16,8 @@
G(NODE_IF), G(NODE_ELSE), G(NODE_BLOCK), \
G(NODE_WHILE), G(NODE_CONTINUE), G(NODE_BREAK), \
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"

View File

@ -29,7 +29,7 @@
%token BREAK
%left ASSERT
%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> fun_rets fun_params fun_param fun
%type <n_children> fun_ret_list fun_call fun_args any instr
@ -595,33 +595,49 @@ fun_rets:
;
fun:
FUN OPAR fun_params CPAR fun_rets block END {
FUN ident fun_body {
node* n = malloc(sizeof(node));
node_init(n, NODE_FUN, "", line);
size_t const SZ = $3;
node* all[SZ];
node* block_node = stack_pop();
assert(block_node);
node* ret_node = stack_pop();
assert(ret_node);
if ($3 > 0)
for (size_t i=0; i<SZ; i++)
{
node* params[$3];
for (size_t i=0; i<$3; i++)
{
params[i] = stack_pop();
}
for (size_t i=0; i<$3; i++)
{
node_add_child(n, params[$3 - 1 - i]);
}
all[SZ - 1 - i] = stack_pop();
}
node_add_child(n, ret_node);
node_add_child(n, block_node);
node* ident_node = stack_pop();
for (size_t i=0; i<SZ; i++)
{
node_add_child(n, all[i]);
}
node* fdecl = malloc(sizeof(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);
@ -629,6 +645,12 @@ fun:
}
;
fun_body:
OPAR fun_params CPAR fun_rets block END {
$$ = $2 + $4 + $5;
}
;
fun_args:
expr_list {
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++)
{
type* t = type_new_from_node(rets->children.data[i]);
t->kind = KIND_RETURN;
type_add_sub_type(ty, t);
type_free(t); free(t);
}

View File

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

View File

@ -30,3 +30,38 @@ end
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