ADD: simple functions.
parent
84b0af8090
commit
9ab09e85f6
|
@ -51,6 +51,7 @@ executable(
|
|||
'src/vm.c',
|
||||
|
||||
'src/symtable.c',
|
||||
'src/fun.c',
|
||||
],
|
||||
dependencies: [
|
||||
m_dep
|
||||
|
|
197
src/compiler.c
197
src/compiler.c
|
@ -341,9 +341,139 @@ void compile_node(compiler* self, node* root, program* prog)
|
|||
compile_number(self, root, prog, OP_IADD, OP_FADD);
|
||||
}
|
||||
}
|
||||
else if (root->type == NODE_FUN)
|
||||
{
|
||||
// init body
|
||||
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
|
||||
for (size_t i=0; i<root->children.size; i++)
|
||||
{
|
||||
node* param = root->children.data[i];
|
||||
|
||||
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]);
|
||||
|
||||
symtable_declare(comp.sym, param_name
|
||||
, param_ty
|
||||
, param->children.data[0]);
|
||||
|
||||
type_free(param_ty); free(param_ty);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 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)
|
||||
);
|
||||
|
||||
value_free(val); free(val);
|
||||
fun_free(fn); free(fn);
|
||||
|
||||
cstatic_free(&cs);
|
||||
}
|
||||
else if (root->type == NODE_CALL)
|
||||
{
|
||||
//{char c[512]; node_str(root, c, 512); printf("%s\n", c);}
|
||||
char const* fun_name = root->children.data[0]->value;
|
||||
node* args = root->children.data[1];
|
||||
|
||||
symentry* entry = symtable_find(self->sym, fun_name);
|
||||
assert(entry);
|
||||
|
||||
program_add_instr(prog, OP_LOAD, entry->id);
|
||||
|
||||
for (size_t i=0; i<args->children.size; i++)
|
||||
{
|
||||
node* arg = args->children.data[i];
|
||||
compile_node(self, arg, prog);
|
||||
}
|
||||
|
||||
program_add_instr(prog, OP_CALL, args->children.size);
|
||||
}
|
||||
else if (root->type == NODE_RETURN)
|
||||
{
|
||||
compile_children(self, root, prog);
|
||||
program_add_instr(prog, OP_RET, NO_PARAM);
|
||||
}
|
||||
else if (root->type == NODE_FUN_TYPE)
|
||||
{
|
||||
type* ty = malloc(sizeof(type));
|
||||
type_init(ty, TY_FUNCTION);
|
||||
|
||||
node* lhs = root->children.data[0];
|
||||
|
||||
size_t lhs_sz = lhs->children.size;
|
||||
|
||||
for (size_t i=0; i<lhs_sz; i++)
|
||||
{
|
||||
type* sub = type_new_from_node(
|
||||
lhs->children.data[lhs_sz - 1 - i]);
|
||||
type_add_sub_type(ty, sub);
|
||||
type_free(sub); free(sub);
|
||||
}
|
||||
|
||||
if (root->children.data[1]->children.size > 0)
|
||||
{
|
||||
node* rhs = root->children.data[1];
|
||||
size_t rhs_sz = rhs->children.size;
|
||||
for (size_t i=0; i<rhs_sz; i++)
|
||||
{
|
||||
type* sub = type_new_from_node(
|
||||
rhs->children.data[rhs_sz - 1 - i]);
|
||||
sub->kind = KIND_RETURN;
|
||||
type_add_sub_type(ty, sub);
|
||||
type_free(sub); free(sub);
|
||||
}
|
||||
}
|
||||
|
||||
value val;
|
||||
value_init_type(&val,
|
||||
ty,
|
||||
root->lineno);
|
||||
|
||||
size_t idx = program_add_pool(prog, &val);
|
||||
program_add_instr(prog, OP_PUSH, idx);
|
||||
|
||||
|
||||
type_free(ty);
|
||||
free(ty);
|
||||
|
||||
value_free(&val);
|
||||
}
|
||||
else if (root->type == NODE_TYPE)
|
||||
{
|
||||
type* ty = compile_get_type(self, root);
|
||||
type* ty = type_new_from_node(root);
|
||||
|
||||
value val;
|
||||
value_init_type(&val,
|
||||
|
@ -572,71 +702,6 @@ void compile_children(compiler* self, node* root, program* prog)
|
|||
}
|
||||
}
|
||||
|
||||
type* compile_get_type(compiler* self, node* root)
|
||||
{
|
||||
assert(self);
|
||||
assert(root);
|
||||
type* ty = malloc(sizeof(type));
|
||||
|
||||
if (strcmp(root->value, "int") == 0)
|
||||
{
|
||||
type_init(ty, TY_INTEGER);
|
||||
}
|
||||
|
||||
else if (strcmp(root->value, "float") == 0)
|
||||
{
|
||||
type_init(ty, TY_FLOAT);
|
||||
}
|
||||
|
||||
else if (strcmp(root->value, "str") == 0)
|
||||
{
|
||||
type_init(ty, TY_STRING);
|
||||
}
|
||||
|
||||
else if (strcmp(root->value, "bool") == 0)
|
||||
{
|
||||
type_init(ty, TY_BOOLEAN);
|
||||
}
|
||||
|
||||
else if (strcmp(root->value, "type") == 0)
|
||||
{
|
||||
type_init(ty, TY_TYPE);
|
||||
}
|
||||
|
||||
else if (strcmp(root->value, "array") == 0)
|
||||
{
|
||||
type_init(ty, TY_ARRAY);
|
||||
ty->kind = KIND_SEQUENTIAL;
|
||||
}
|
||||
else if (root->type == NODE_ADD)
|
||||
{
|
||||
type_init(ty, TY_TYPE);
|
||||
ty->kind = KIND_DISJUNCTION;
|
||||
}
|
||||
else if (root->type == NODE_MUL)
|
||||
{
|
||||
type_init(ty, TY_TYPE);
|
||||
ty->kind = KIND_CONJUNCTION;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr,
|
||||
"E(%d): cannot compile unknown type '%s'.\n",
|
||||
root->lineno,
|
||||
NodeTypeStr[root->type]);
|
||||
}
|
||||
|
||||
for (size_t i=0; i<root->children.size; i++)
|
||||
{
|
||||
type* sub = compile_get_type(self, root->children.data[i]);
|
||||
type_add_sub_type(ty, sub);
|
||||
type_free(sub);
|
||||
free(sub);
|
||||
}
|
||||
|
||||
return ty;
|
||||
}
|
||||
|
||||
void compile_if(compiler* self, node* root, program* prog)
|
||||
{
|
||||
if (root->children.size == 1)
|
||||
|
|
|
@ -30,8 +30,6 @@ void compiler_pop_info(compiler* self);
|
|||
void compile_node(compiler* self, node* root, program* prog);
|
||||
void compile_children(compiler* self, node* root, program* prog);
|
||||
|
||||
type* compile_get_type(compiler* self, node* root);
|
||||
|
||||
void compile_number(compiler* self, node* root, program* prog,
|
||||
int integer_op,
|
||||
int float_op);
|
||||
|
|
292
src/cstatic.c
292
src/cstatic.c
|
@ -4,11 +4,26 @@
|
|||
void cstatic_init(cstatic* self)
|
||||
{
|
||||
assert(self);
|
||||
|
||||
self->fun_types.size = 0;
|
||||
self->fun_types.capacity = 1;
|
||||
self->fun_types.data = malloc(sizeof(type*) * self->fun_types.capacity);
|
||||
}
|
||||
|
||||
void cstatic_free(cstatic* self)
|
||||
{
|
||||
assert(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]);
|
||||
}
|
||||
|
||||
free(self->fun_types.data);
|
||||
self->fun_types.size = 0;
|
||||
self->fun_types.capacity = 0;
|
||||
self->fun_types.data = NULL;
|
||||
}
|
||||
|
||||
type* cstatic_new_type(cstatic* self, int base_type)
|
||||
|
@ -35,10 +50,96 @@ type* cstatic_resolve_new(cstatic* self, symtable* sym, node* ast)
|
|||
assert(self);
|
||||
assert(ast);
|
||||
|
||||
if (ast->type == NODE_FUN)
|
||||
{
|
||||
type* ty = cstatic_new_type(self, TY_FUNCTION);
|
||||
|
||||
size_t i = 0;
|
||||
|
||||
while (i < ast->children.size
|
||||
&& ast->children.data[i]->type == NODE_FUN_PARAM)
|
||||
{
|
||||
type* param_ty =
|
||||
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);
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i < ast->children.size
|
||||
&& ast->children.data[i]->type == NODE_FUN_RET)
|
||||
{
|
||||
node* ret = ast->children.data[i];
|
||||
|
||||
for (size_t i=0; i<ret->children.size; i++)
|
||||
{
|
||||
type* r = type_new_from_node(ret->children.data[i]);
|
||||
r->kind = KIND_RETURN;
|
||||
type_add_sub_type(ty, r);
|
||||
type_free(r); free(r);
|
||||
}
|
||||
}
|
||||
|
||||
return ty;
|
||||
}
|
||||
|
||||
if (ast->type == NODE_CALL)
|
||||
{
|
||||
char const* fun_name = ast->children.data[0]->value;
|
||||
|
||||
symentry* entry = symtable_find(sym, fun_name);
|
||||
assert(entry);
|
||||
|
||||
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];
|
||||
assert(ret_type);
|
||||
|
||||
if (ret_type->kind == KIND_RETURN)
|
||||
{
|
||||
type* res = type_new_clone(ret_type);
|
||||
res->kind = KIND_CONJUNCTION;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ast->type == NODE_RETURN)
|
||||
{
|
||||
return cstatic_resolve_new(self, sym, ast->children.data[0]);
|
||||
}
|
||||
|
||||
if (ast->type == NODE_IF)
|
||||
{
|
||||
type* ty = cstatic_resolve_new(self,
|
||||
sym,
|
||||
ast->children.data[1]);
|
||||
return ty;
|
||||
}
|
||||
|
||||
if (ast->type == NODE_DO)
|
||||
{
|
||||
type* ty = cstatic_resolve_new(self,
|
||||
sym,
|
||||
ast->children.data[0]);
|
||||
return ty;
|
||||
}
|
||||
if (ast->type == NODE_IDENT)
|
||||
{
|
||||
symentry* entry = symtable_find(sym,
|
||||
ast->value);
|
||||
assert(entry);
|
||||
type* ty = type_new_clone(entry->ty);
|
||||
return ty;
|
||||
}
|
||||
|
@ -184,7 +285,8 @@ type* cstatic_resolve_new(cstatic* self, symtable* sym, node* ast)
|
|||
return cstatic_new_type(self, TY_STRING);
|
||||
}
|
||||
|
||||
else if (ast->type == NODE_TYPE)
|
||||
else if (ast->type == NODE_TYPE
|
||||
|| ast->type == NODE_FUN_TYPE)
|
||||
{
|
||||
return cstatic_new_type(self, TY_TYPE);
|
||||
}
|
||||
|
@ -250,7 +352,7 @@ int cstatic_check(cstatic* self, node* ast, symtable* sym, char* msg, size_t siz
|
|||
|
||||
if (!status)
|
||||
{
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -259,6 +361,157 @@ int cstatic_check(cstatic* self, node* ast, symtable* sym, char* msg, size_t siz
|
|||
return 1;
|
||||
}
|
||||
|
||||
// Function Stuff
|
||||
if (ast->type == NODE_FUN)
|
||||
{
|
||||
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);
|
||||
|
||||
// function args
|
||||
for (size_t i=0; i<ast->children.size; i++)
|
||||
{
|
||||
node* child = ast->children.data[i];
|
||||
|
||||
if (child->type == NODE_FUN_PARAM)
|
||||
{
|
||||
char const* name = child->children.data[0]->value;
|
||||
type* t = type_new_from_node(child->children.data[1]);
|
||||
|
||||
symtable_declare_mut(inner_table, name, t, child);
|
||||
|
||||
type_free(t); free(t);
|
||||
}
|
||||
}
|
||||
|
||||
int status = cstatic_check(self,
|
||||
ast->children.data[ast->children.size - 1],
|
||||
inner_table,
|
||||
msg,
|
||||
size
|
||||
);
|
||||
|
||||
symtable_free(inner_table); free(inner_table);
|
||||
cstatic_pop_fun(self);
|
||||
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
// Function Stuff
|
||||
if (ast->type == NODE_RETURN)
|
||||
{
|
||||
type* ret_ty = cstatic_resolve_new(self, sym, ast);
|
||||
type* fun_ty = cstatic_top_fun(self);
|
||||
|
||||
type* fun_res = NULL;
|
||||
|
||||
for (size_t i=0; i<fun_ty->sub_types.size; i++)
|
||||
{
|
||||
if (fun_ty->sub_types.data[i]->kind == KIND_RETURN)
|
||||
{
|
||||
fun_res = type_new_clone(fun_ty->sub_types.data[i]);
|
||||
fun_res->kind = KIND_CONJUNCTION;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assert(fun_res);
|
||||
|
||||
int status = cstatic_check_same_type_ptr(
|
||||
self,
|
||||
ast,
|
||||
fun_res,
|
||||
ret_ty,
|
||||
sym,
|
||||
msg,
|
||||
size
|
||||
);
|
||||
|
||||
if (status)
|
||||
{
|
||||
if (fun_res)
|
||||
{
|
||||
type_free(fun_res); free(fun_res);
|
||||
}
|
||||
|
||||
type_free(ret_ty); free(ret_ty);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
if (ast->type == NODE_CALL)
|
||||
{
|
||||
char const* fun_name = ast->children.data[0]->value;
|
||||
symentry* entry = symtable_find(sym, fun_name);
|
||||
assert(entry);
|
||||
|
||||
type* fun_type = entry->ty;
|
||||
|
||||
node* args = ast->children.data[1];
|
||||
size_t arity = 0;
|
||||
|
||||
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++;
|
||||
}
|
||||
}
|
||||
|
||||
if (arity != args->children.size)
|
||||
{
|
||||
snprintf(msg, size, "E(%d): function arity mismatch: "
|
||||
"expected '%ld', got '%ld'.\n",
|
||||
args->lineno,
|
||||
arity,
|
||||
args->children.size
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (size_t i=0; i<args->children.size; i++)
|
||||
{
|
||||
|
||||
type* sub = type_new_clone(fun_type->sub_types.data[i]);
|
||||
assert(sub);
|
||||
|
||||
type* arg_type = cstatic_resolve_new(
|
||||
self,
|
||||
sym,
|
||||
args->children.data[i]
|
||||
);
|
||||
|
||||
int status = cstatic_check_same_type_ptr(
|
||||
self,
|
||||
args->children.data[i],
|
||||
sub,
|
||||
arg_type,
|
||||
sym,
|
||||
msg,
|
||||
size
|
||||
);
|
||||
|
||||
if (!status)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
type_free(sub); free(sub);
|
||||
type_free(arg_type); free(arg_type);
|
||||
|
||||
}
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Children
|
||||
for (size_t i=0; i<ast->children.size; i++)
|
||||
{
|
||||
|
@ -914,3 +1167,38 @@ int cstatic_check_same_type(cstatic* self, node* lhs, node* rhs, symtable* sym,
|
|||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void cstatic_push_fun(cstatic* self, type* fun_ty)
|
||||
{
|
||||
assert(self);
|
||||
assert(fun_ty);
|
||||
|
||||
if (self->fun_types.size >= self->fun_types.capacity)
|
||||
{
|
||||
self->fun_types.capacity *= 2;
|
||||
self->fun_types.data = realloc(
|
||||
self->fun_types.data,
|
||||
sizeof(type*) * self->fun_types.capacity
|
||||
);
|
||||
}
|
||||
|
||||
self->fun_types.data[self->fun_types.size] = type_new_clone(fun_ty);
|
||||
self->fun_types.size++;
|
||||
|
||||
}
|
||||
|
||||
void cstatic_pop_fun(cstatic* self)
|
||||
{
|
||||
assert(self->fun_types.size > 0);
|
||||
|
||||
type_free(self->fun_types.data[self->fun_types.size - 1]);
|
||||
free(self->fun_types.data[self->fun_types.size - 1]);
|
||||
|
||||
self->fun_types.size--;
|
||||
}
|
||||
|
||||
type* cstatic_top_fun(cstatic* self)
|
||||
{
|
||||
assert(self->fun_types.size > 0);
|
||||
return self->fun_types.data[self->fun_types.size - 1];
|
||||
}
|
||||
|
|
|
@ -8,7 +8,11 @@
|
|||
#define TYPE_END (-1)
|
||||
|
||||
typedef struct {
|
||||
int _unused;
|
||||
struct {
|
||||
size_t size;
|
||||
size_t capacity;
|
||||
type** data;
|
||||
} fun_types;
|
||||
} cstatic;
|
||||
|
||||
void cstatic_init(cstatic* self);
|
||||
|
@ -33,4 +37,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_pop_fun(cstatic* self);
|
||||
type* cstatic_top_fun(cstatic* self);
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
#include "fun.h"
|
||||
#include "program.h"
|
||||
|
||||
void fun_init(fun* self, type* ty, struct program* prog)
|
||||
{
|
||||
assert(self);
|
||||
self->ty = type_new_clone(ty);
|
||||
self->prog = program_new_clone(prog);
|
||||
}
|
||||
|
||||
void fun_free(fun* self)
|
||||
{
|
||||
assert(self);
|
||||
type_free(self->ty); free(self->ty);
|
||||
|
||||
program_free(self->prog);
|
||||
free(self->prog);
|
||||
self->prog = NULL;
|
||||
}
|
||||
|
||||
fun* fun_new_clone(fun* self)
|
||||
{
|
||||
assert(self);
|
||||
fun* clone = malloc(sizeof(fun));
|
||||
fun_init(clone, self->ty, self->prog);
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
size_t fun_str(fun* self, char* buffer, size_t size)
|
||||
{
|
||||
assert(self);
|
||||
assert(buffer);
|
||||
size_t sz = 0;
|
||||
|
||||
sz += snprintf(buffer + sz, size - sz, "function");
|
||||
|
||||
return sz;
|
||||
}
|
||||
|
||||
int fun_equals(fun* self, fun* lhs)
|
||||
{
|
||||
assert(self);
|
||||
assert(lhs);
|
||||
return 0; // TODO to impl
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
#ifndef FUN_H
|
||||
#define FUN_H
|
||||
|
||||
#include "commons.h"
|
||||
#include "type.h"
|
||||
|
||||
struct program;
|
||||
|
||||
typedef struct {
|
||||
type* ty;
|
||||
struct program* prog;
|
||||
} fun;
|
||||
|
||||
void fun_init(fun* self, type* ty, struct program* prog);
|
||||
void fun_free(fun* self);
|
||||
|
||||
fun* fun_new_clone(fun* self);
|
||||
size_t fun_str(fun* self, char* buffer, size_t size);
|
||||
int fun_equals(fun* self, fun* lhs);
|
||||
|
||||
#endif
|
|
@ -1,4 +1,5 @@
|
|||
%{
|
||||
|
||||
#include "parser.h"
|
||||
#include "src/utils.h"
|
||||
int line = 1;
|
||||
|
@ -15,9 +16,11 @@ FLOAT -?[0-9]+\.[0-9]+
|
|||
STRING \"[^"]*\"
|
||||
TYPE (int|float|bool|str|array|type)
|
||||
IDENT [_A-Za-z][_A-Za-z0-9]*
|
||||
SEP [\n]|[;]
|
||||
|
||||
%%
|
||||
{COMMENT} {}
|
||||
{SEP} { line++; return SEP; }
|
||||
"\n" { line++; }
|
||||
{WHITESPACES} {}
|
||||
|
||||
|
@ -26,6 +29,9 @@ IDENT [_A-Za-z][_A-Za-z0-9]*
|
|||
return TYPE;
|
||||
}
|
||||
|
||||
"fun" { return FUN; }
|
||||
"as" { return AS; }
|
||||
"return" { return RETURN; }
|
||||
"while" { return WHILE; }
|
||||
"break" { return BREAK; }
|
||||
"continue" { return CONTINUE; }
|
||||
|
@ -42,6 +48,7 @@ IDENT [_A-Za-z][_A-Za-z0-9]*
|
|||
"<" { return LT; }
|
||||
">" { return GT; }
|
||||
"," { return COMMA; }
|
||||
":" { return COLON; }
|
||||
"+" { return ADD; }
|
||||
"-" { return SUB; }
|
||||
"*" { return MUL; }
|
||||
|
|
32
src/main.c
32
src/main.c
|
@ -5,6 +5,7 @@
|
|||
#include "vm.h"
|
||||
#include "cstatic.h"
|
||||
|
||||
|
||||
extern FILE* yyin;
|
||||
extern node* ast;
|
||||
extern void stack_push(node*);
|
||||
|
@ -13,6 +14,8 @@ extern void stack_free();
|
|||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int DEBUG = argc > 2;
|
||||
|
||||
if (argc > 1)
|
||||
{
|
||||
yyin = fopen(argv[1], "r");
|
||||
|
@ -27,6 +30,16 @@ int main(int argc, char** argv)
|
|||
ast = stack_pop();
|
||||
stack_free();
|
||||
|
||||
|
||||
if (DEBUG)
|
||||
{
|
||||
size_t const BUF = 1024;
|
||||
char buffer[BUF];
|
||||
memset(buffer, 0, BUF);
|
||||
node_str(ast, buffer, BUF);
|
||||
printf("-- ast ---\n%s\n\n", buffer);
|
||||
}
|
||||
|
||||
// Static checking
|
||||
symtable sym;
|
||||
symtable_init(&sym);
|
||||
|
@ -52,24 +65,25 @@ int main(int argc, char** argv)
|
|||
|
||||
compile_node(&comp, ast, &prog);
|
||||
|
||||
if (DEBUG)
|
||||
{
|
||||
size_t const BUF = 1024;
|
||||
char buffer[BUF];
|
||||
memset(buffer, 0, BUF);
|
||||
program_str(&prog, buffer, BUF);
|
||||
printf("--- program ---\n%s\n", buffer);
|
||||
}
|
||||
|
||||
// Execution
|
||||
vm v;
|
||||
vm_init(&v);
|
||||
|
||||
vm_exec(&v, &prog);
|
||||
|
||||
if (0) // DEBUG
|
||||
if (DEBUG)
|
||||
{
|
||||
size_t const BUF = 1024;
|
||||
char buffer[BUF];
|
||||
memset(buffer, 0, BUF);
|
||||
node_str(ast, buffer, BUF);
|
||||
printf("-- ast ---\n%s\n\n", buffer);
|
||||
|
||||
memset(buffer, 0, BUF);
|
||||
program_str(&prog, buffer, BUF);
|
||||
printf("--- program ---\n%s\n", buffer);
|
||||
|
||||
memset(buffer, 0, BUF);
|
||||
vm_str(&v, buffer, BUF);
|
||||
printf("--- stack ---\n%s\n", buffer);
|
||||
|
|
|
@ -14,7 +14,9 @@
|
|||
G(NODE_GT), G(NODE_GE), G(NODE_VARDECL), G(NODE_IDENT), \
|
||||
G(NODE_CONSTDECL), G(NODE_ASSIGN), G(NODE_DO), G(NODE_IS), \
|
||||
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_FUN_PARAM), G(NODE_FUN_RET), G(NODE_CALL), G(NODE_ARGS)
|
||||
|
||||
|
||||
#include "mutils.h"
|
||||
|
|
|
@ -47,7 +47,9 @@
|
|||
G(OP_ASTORE), \
|
||||
G(OP_TEQ), \
|
||||
G(OP_BRF), \
|
||||
G(OP_BR)
|
||||
G(OP_BR), \
|
||||
G(OP_CALL), \
|
||||
G(OP_RET)
|
||||
|
||||
|
||||
enum Opcodes {
|
||||
|
|
431
src/parser.y
431
src/parser.y
|
@ -2,7 +2,6 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "src/node.h"
|
||||
|
||||
extern int line;
|
||||
void yyerror(char const*);
|
||||
node* ast = NULL;
|
||||
|
@ -16,11 +15,13 @@
|
|||
void stack_free();
|
||||
%}
|
||||
|
||||
%define parse.error verbose
|
||||
|
||||
%union {
|
||||
char* str;
|
||||
size_t n_children;
|
||||
};
|
||||
|
||||
%token SEP
|
||||
%token IF_COND
|
||||
%token ELSE_COND
|
||||
%token WHILE
|
||||
|
@ -30,6 +31,8 @@
|
|||
%token <str> TYPE BOOLEAN INTEGER FLOAT STRING IDENT
|
||||
%type <n_children> expr exprs prog array builtins
|
||||
%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
|
||||
%left EQ NE
|
||||
%left LT GT LE GE
|
||||
%left AND
|
||||
|
@ -39,11 +42,11 @@
|
|||
%left POW
|
||||
%left NOT
|
||||
%token OPAR CPAR
|
||||
%token OSQUARE CSQUARE COMMA
|
||||
%token OSQUARE CSQUARE COMMA COLON
|
||||
%token LET LET_MUT ASSIGN DO END
|
||||
%type <n_children> expr_unop block if_rec
|
||||
%left IS
|
||||
|
||||
%token RETURN FUN AS
|
||||
%%
|
||||
|
||||
prog:
|
||||
|
@ -76,30 +79,19 @@ prog:
|
|||
}
|
||||
;
|
||||
|
||||
exprs:
|
||||
exprs expr { $$ = $1 + $2; }
|
||||
sep: SEP | sep SEP;
|
||||
optsep: | sep;
|
||||
|
||||
| expr { $$ = $1; }
|
||||
exprs:
|
||||
exprs optsep instr sep { $$ = $1 + $3; }
|
||||
| optsep instr sep { $$ = $2; }
|
||||
|
||||
;
|
||||
|
||||
any: expr { $$ = $1; } | instr { $$ = $1; };
|
||||
|
||||
expr:
|
||||
CONTINUE {
|
||||
node* n = malloc(sizeof(node));
|
||||
node_init(n, NODE_CONTINUE, "", line);
|
||||
stack_push(n);
|
||||
$$ = 1;
|
||||
}
|
||||
|
||||
| BREAK {
|
||||
node* n = malloc(sizeof(node));
|
||||
node_init(n, NODE_BREAK, "", line);
|
||||
stack_push(n);
|
||||
$$ = 1;
|
||||
}
|
||||
|
||||
| WHILE expr block END {
|
||||
WHILE expr block END {
|
||||
node* n = malloc(sizeof(node));
|
||||
node_init(n, NODE_WHILE, "", line);
|
||||
|
||||
|
@ -144,24 +136,6 @@ expr:
|
|||
$$ = 1;
|
||||
}
|
||||
|
||||
// INDEX
|
||||
| expr array ASSIGN expr {
|
||||
node* n = malloc(sizeof(node));
|
||||
node_init(n, NODE_ASSIGN, "", line);
|
||||
|
||||
node* expr_node = stack_pop();
|
||||
node* array_node = stack_pop();
|
||||
node* ident_node = stack_pop();
|
||||
|
||||
node_add_child(n, ident_node);
|
||||
node_add_child(n, array_node);
|
||||
node_add_child(n, expr_node);
|
||||
|
||||
stack_push(n);
|
||||
|
||||
$$ = 1;
|
||||
}
|
||||
|
||||
| expr array {
|
||||
node *n = malloc(sizeof(node));
|
||||
node_init(n, NODE_INDEX, "", line);
|
||||
|
@ -185,51 +159,6 @@ expr:
|
|||
| ident {
|
||||
}
|
||||
|
||||
| LET_MUT ident ASSIGN expr {
|
||||
node* n = malloc(sizeof(node));
|
||||
node_init(n, NODE_VARDECL, "", line);
|
||||
|
||||
node* rhs = stack_pop();
|
||||
node* lhs = stack_pop();
|
||||
|
||||
node_add_child(n, lhs);
|
||||
node_add_child(n, rhs);
|
||||
|
||||
stack_push(n);
|
||||
|
||||
$$ = 1;
|
||||
}
|
||||
|
||||
| LET ident ASSIGN expr {
|
||||
node* n = malloc(sizeof(node));
|
||||
node_init(n, NODE_CONSTDECL, "", line);
|
||||
|
||||
node* rhs = stack_pop();
|
||||
node* lhs = stack_pop();
|
||||
|
||||
node_add_child(n, lhs);
|
||||
node_add_child(n, rhs);
|
||||
|
||||
stack_push(n);
|
||||
|
||||
$$ = 1;
|
||||
}
|
||||
|
||||
| ident ASSIGN expr {
|
||||
node* n = malloc(sizeof(node));
|
||||
node_init(n, NODE_ASSIGN, "", line);
|
||||
|
||||
node* rhs = stack_pop();
|
||||
node* lhs = stack_pop();
|
||||
|
||||
node_add_child(n, lhs);
|
||||
node_add_child(n, rhs);
|
||||
|
||||
stack_push(n);
|
||||
|
||||
$$ = 1;
|
||||
}
|
||||
|
||||
// EXPRESSIONS
|
||||
| array {
|
||||
$$ = 1;
|
||||
|
@ -239,16 +168,6 @@ expr:
|
|||
$$ = $1;
|
||||
}
|
||||
|
||||
| ASSERT expr {
|
||||
node *n = malloc(sizeof(node));
|
||||
node_init(n, NODE_ASSERT, "", line);
|
||||
node_add_child(n, stack_pop());
|
||||
stack_push(n);
|
||||
|
||||
$$ = 1;
|
||||
}
|
||||
|
||||
|
||||
| expr LT expr {
|
||||
node *n = malloc(sizeof(node));
|
||||
node_init(n, NODE_LT, "", line);
|
||||
|
@ -415,10 +334,112 @@ expr:
|
|||
|
||||
| expr_unop {}
|
||||
|
||||
| fun_call { $$ = $1; }
|
||||
|
||||
;
|
||||
|
||||
instr:
|
||||
expr
|
||||
|
||||
| RETURN expr {
|
||||
node* n = malloc(sizeof(node));
|
||||
node_init(n, NODE_RETURN, "", line);
|
||||
|
||||
node_add_child(n, stack_pop());
|
||||
stack_push(n);
|
||||
$$ = 1;
|
||||
}
|
||||
|
||||
| ident ASSIGN expr {
|
||||
node* n = malloc(sizeof(node));
|
||||
node_init(n, NODE_ASSIGN, "", line);
|
||||
|
||||
node* rhs = stack_pop();
|
||||
node* lhs = stack_pop();
|
||||
|
||||
node_add_child(n, lhs);
|
||||
node_add_child(n, rhs);
|
||||
|
||||
stack_push(n);
|
||||
|
||||
$$ = 1;
|
||||
}
|
||||
|
||||
| LET_MUT ident ASSIGN expr {
|
||||
node* n = malloc(sizeof(node));
|
||||
node_init(n, NODE_VARDECL, "", line);
|
||||
|
||||
node* rhs = stack_pop();
|
||||
node* lhs = stack_pop();
|
||||
|
||||
node_add_child(n, lhs);
|
||||
node_add_child(n, rhs);
|
||||
|
||||
stack_push(n);
|
||||
|
||||
$$ = 1;
|
||||
}
|
||||
|
||||
| LET ident ASSIGN expr {
|
||||
node* n = malloc(sizeof(node));
|
||||
node_init(n, NODE_CONSTDECL, "", line);
|
||||
|
||||
node* rhs = stack_pop();
|
||||
node* lhs = stack_pop();
|
||||
|
||||
node_add_child(n, lhs);
|
||||
node_add_child(n, rhs);
|
||||
|
||||
stack_push(n);
|
||||
|
||||
$$ = 1;
|
||||
}
|
||||
|
||||
| CONTINUE {
|
||||
node* n = malloc(sizeof(node));
|
||||
node_init(n, NODE_CONTINUE, "", line);
|
||||
stack_push(n);
|
||||
$$ = 1;
|
||||
}
|
||||
|
||||
| BREAK {
|
||||
node* n = malloc(sizeof(node));
|
||||
node_init(n, NODE_BREAK, "", line);
|
||||
stack_push(n);
|
||||
$$ = 1;
|
||||
}
|
||||
|
||||
|
||||
// INDEX
|
||||
| expr array ASSIGN expr {
|
||||
node* n = malloc(sizeof(node));
|
||||
node_init(n, NODE_ASSIGN, "", line);
|
||||
|
||||
node* expr_node = stack_pop();
|
||||
node* array_node = stack_pop();
|
||||
node* ident_node = stack_pop();
|
||||
|
||||
node_add_child(n, ident_node);
|
||||
node_add_child(n, array_node);
|
||||
node_add_child(n, expr_node);
|
||||
|
||||
stack_push(n);
|
||||
|
||||
$$ = 1;
|
||||
}
|
||||
|
||||
| ASSERT expr {
|
||||
node *n = malloc(sizeof(node));
|
||||
node_init(n, NODE_ASSERT, "", line);
|
||||
node_add_child(n, stack_pop());
|
||||
stack_push(n);
|
||||
|
||||
$$ = 1;
|
||||
}
|
||||
;
|
||||
|
||||
if_rec:
|
||||
ELSE_COND IF_COND expr block if_rec {
|
||||
ELSE_COND IF_COND expr block_or_expr if_rec {
|
||||
node* n = malloc(sizeof(node));
|
||||
node_init(n, NODE_IF, "", line);
|
||||
|
||||
|
@ -435,7 +456,7 @@ if_rec:
|
|||
$$ = 1;
|
||||
}
|
||||
|
||||
| ELSE_COND expr END {
|
||||
| ELSE_COND block_or_expr END {
|
||||
node* n = malloc(sizeof(node));
|
||||
node_init(n, NODE_IF, "", line);
|
||||
|
||||
|
@ -449,8 +470,10 @@ if_rec:
|
|||
}
|
||||
;
|
||||
|
||||
block_or_expr: block | expr;
|
||||
|
||||
if:
|
||||
IF_COND expr block if_rec {
|
||||
IF_COND expr block_or_expr if_rec {
|
||||
node* n = malloc(sizeof(node));
|
||||
node_init(n, NODE_IF, "", line);
|
||||
|
||||
|
@ -467,7 +490,7 @@ if:
|
|||
$$ = 1;
|
||||
}
|
||||
|
||||
| IF_COND expr block END {
|
||||
| IF_COND expr block_or_expr END {
|
||||
node* n = malloc(sizeof(node));
|
||||
node_init(n, NODE_IF, "", line);
|
||||
|
||||
|
@ -502,8 +525,168 @@ expr_unop:
|
|||
}
|
||||
;
|
||||
|
||||
type_list:
|
||||
fun_param:
|
||||
ident AS type {
|
||||
node *n = malloc(sizeof(node));
|
||||
node_init(n, NODE_FUN_PARAM, "", line);
|
||||
|
||||
node* type_node = stack_pop();
|
||||
node* ident_node = stack_pop();
|
||||
|
||||
node_add_child(n, ident_node);
|
||||
node_add_child(n, type_node);
|
||||
|
||||
stack_push(n);
|
||||
|
||||
$$ = 1;
|
||||
}
|
||||
|
||||
fun_param:
|
||||
ident AS type
|
||||
;
|
||||
|
||||
fun_params:
|
||||
{ $$ = 0; }
|
||||
| fun_param {
|
||||
$$ = $1;
|
||||
}
|
||||
|
||||
| fun_params COMMA fun_param {
|
||||
$$ = $1 + $3;
|
||||
}
|
||||
;
|
||||
|
||||
fun_ret_list:
|
||||
type { $$ = $1; }
|
||||
| fun_ret_list COMMA type {
|
||||
$$ = $1 + $3;
|
||||
}
|
||||
;
|
||||
|
||||
fun_rets:
|
||||
{
|
||||
node* n = malloc(sizeof(node));
|
||||
node_init(n, NODE_FUN_RET, "", line);
|
||||
stack_push(n);
|
||||
|
||||
$$ = 1;
|
||||
}
|
||||
|
||||
| AS fun_ret_list {
|
||||
node* n = malloc(sizeof(node));
|
||||
node_init(n, NODE_FUN_RET, "", line);
|
||||
|
||||
node* rets[$2];
|
||||
|
||||
for (size_t i=0; i<$2; i++)
|
||||
{
|
||||
rets[$2 - 1 - i] = stack_pop();
|
||||
}
|
||||
|
||||
for (size_t i=0; i<$2; i++)
|
||||
{
|
||||
node_add_child(n, rets[i]);
|
||||
}
|
||||
|
||||
stack_push(n);
|
||||
|
||||
$$ = 1;
|
||||
}
|
||||
;
|
||||
|
||||
fun:
|
||||
FUN OPAR fun_params CPAR fun_rets block END {
|
||||
node* n = malloc(sizeof(node));
|
||||
node_init(n, NODE_FUN, "", line);
|
||||
|
||||
node* block_node = stack_pop();
|
||||
assert(block_node);
|
||||
|
||||
node* ret_node = stack_pop();
|
||||
assert(ret_node);
|
||||
|
||||
if ($3 > 0)
|
||||
{
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
||||
node_add_child(n, ret_node);
|
||||
node_add_child(n, block_node);
|
||||
|
||||
stack_push(n);
|
||||
|
||||
$$ = 1;
|
||||
}
|
||||
;
|
||||
|
||||
fun_args:
|
||||
expr_list {
|
||||
node* n = malloc(sizeof(node));
|
||||
node_init(n, NODE_ARGS, "", line);
|
||||
size_t const SZ = $1;
|
||||
|
||||
node* args[SZ];
|
||||
|
||||
for (size_t i=0; i<SZ; i++)
|
||||
{
|
||||
args[$1 - 1 - i] = stack_pop();
|
||||
}
|
||||
|
||||
for (size_t i=0; i<SZ; i++)
|
||||
{
|
||||
node_add_child(n, args[i]);
|
||||
}
|
||||
|
||||
stack_push(n);
|
||||
|
||||
$$ = 1;
|
||||
}
|
||||
;
|
||||
|
||||
fun_call:
|
||||
MUL expr {
|
||||
node* n = malloc(sizeof(node));
|
||||
node_init(n, NODE_CALL, "", line);
|
||||
|
||||
node* args = malloc(sizeof(node));
|
||||
node_init(args, NODE_ARGS, "", line);
|
||||
|
||||
node* fn_expr = stack_pop();
|
||||
|
||||
node_add_child(n, fn_expr);
|
||||
node_add_child(n, args);
|
||||
|
||||
stack_push(n);
|
||||
$$ = 1;
|
||||
}
|
||||
|
||||
| expr fun_args {
|
||||
node* n = malloc(sizeof(node));
|
||||
node_init(n, NODE_CALL, "", line);
|
||||
|
||||
node* args = stack_pop();
|
||||
node* fn_expr = stack_pop();
|
||||
|
||||
node_add_child(n, fn_expr);
|
||||
node_add_child(n, args);
|
||||
|
||||
stack_push(n);
|
||||
$$ = 1;
|
||||
}
|
||||
;
|
||||
|
||||
type_list: { $$ = 0; }
|
||||
| type { $$ = $1; }
|
||||
| type_list COMMA type { $$ = $1 + $3; }
|
||||
|
||||
;
|
||||
|
@ -533,10 +716,55 @@ block:
|
|||
;
|
||||
|
||||
type:
|
||||
TYPE LT type_list GT {
|
||||
FUN LT type_list COLON type_list GT {
|
||||
node* n = malloc(sizeof(node));
|
||||
node_init(n, NODE_FUN_TYPE, "", line);
|
||||
|
||||
node* right = malloc(sizeof(node));
|
||||
node_init(right, NODE_TYPE, "", line);
|
||||
|
||||
size_t SZ = $5;
|
||||
node* all_right[SZ];
|
||||
|
||||
for (size_t i=0; i<SZ; i++)
|
||||
{
|
||||
all_right[i] = stack_pop();
|
||||
}
|
||||
|
||||
for (size_t i=0; i<SZ; i++)
|
||||
{
|
||||
node_add_child(right, all_right[i]);
|
||||
}
|
||||
|
||||
node* left = malloc(sizeof(node));
|
||||
node_init(left, NODE_TYPE, "", line);
|
||||
|
||||
SZ = $3;
|
||||
node* all_left[SZ];
|
||||
|
||||
for (size_t i=0; i<SZ; i++)
|
||||
{
|
||||
all_left[i] = stack_pop();
|
||||
}
|
||||
|
||||
for (size_t i=0; i<SZ; i++)
|
||||
{
|
||||
node_add_child(left, all_left[i]);
|
||||
}
|
||||
|
||||
node_add_child(n, left);
|
||||
node_add_child(n, right);
|
||||
|
||||
stack_push(n);
|
||||
|
||||
$$ = 1;
|
||||
}
|
||||
|
||||
| TYPE LT type_list GT {
|
||||
node* n = malloc(sizeof(node));
|
||||
node_init(n, NODE_TYPE, $1, line);
|
||||
free($1);
|
||||
|
||||
size_t const SZ = $3;
|
||||
node* all[SZ];
|
||||
|
||||
|
@ -595,6 +823,7 @@ ident: IDENT {
|
|||
|
||||
builtins:
|
||||
type {}
|
||||
| fun {}
|
||||
|
||||
| STRING {
|
||||
node* n = malloc(sizeof(node));
|
||||
|
|
|
@ -37,6 +37,27 @@ void program_free(program* self)
|
|||
self->pool.capacity = 0;
|
||||
}
|
||||
|
||||
program* program_new_clone(program* self)
|
||||
{
|
||||
assert(self);
|
||||
program* clone = malloc(sizeof(program));
|
||||
program_init(clone);
|
||||
|
||||
for (size_t i=0; i < self->instrs.size; i++)
|
||||
{
|
||||
program_add_instr(clone, self->instrs.data[i]->opcode
|
||||
, self->instrs.data[i]->param);
|
||||
}
|
||||
|
||||
for (size_t i=0; i < self->pool.size; i++)
|
||||
{
|
||||
assert(self->pool.data[i]);
|
||||
program_add_pool(clone, self->pool.data[i]);
|
||||
}
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
void program_set_instr(program* self, size_t index, int opcode, int param)
|
||||
{
|
||||
assert(self);
|
||||
|
@ -99,11 +120,14 @@ size_t program_add_pool(program* self, value* val)
|
|||
self->pool.capacity *= 2;
|
||||
self->pool.data = realloc(
|
||||
self->pool.data,
|
||||
sizeof(value) * self->pool.capacity
|
||||
sizeof(value*) * self->pool.capacity
|
||||
);
|
||||
}
|
||||
|
||||
size_t idx = self->pool.size;
|
||||
self->pool.data[idx] = value_new_clone(val);
|
||||
value* new_val = value_new_clone(val);
|
||||
assert(new_val);
|
||||
self->pool.data[idx] = new_val;
|
||||
|
||||
self->pool.size++;
|
||||
|
||||
|
|
|
@ -29,6 +29,8 @@ typedef struct {
|
|||
void program_init(program* self);
|
||||
void program_free(program* self);
|
||||
|
||||
program* program_new_clone(program* self);
|
||||
|
||||
size_t program_add_instr(program* self, int opcode, int param);
|
||||
void program_set_instr(program* self, size_t index, int opcode, int param);
|
||||
void program_set_param(program* self, size_t index, int param);
|
||||
|
|
|
@ -42,6 +42,36 @@ void symentry_free(symentry* self)
|
|||
free(self->ty);
|
||||
}
|
||||
|
||||
symtable* symtable_new_clone(symtable* self)
|
||||
{
|
||||
symtable* clone = malloc(sizeof(symtable));
|
||||
symtable_init(clone);
|
||||
|
||||
clone->entries.capacity = self->entries.capacity;
|
||||
clone->entries.data = realloc(clone->entries.data,
|
||||
sizeof(symentry*) * clone->entries.capacity);
|
||||
|
||||
for (size_t i=0; i<self->entries.size; i++)
|
||||
{
|
||||
symentry* entry = self->entries.data[i];
|
||||
symentry* clone_entry = malloc(sizeof(symentry));
|
||||
|
||||
clone_entry->id = entry->id;
|
||||
clone_entry->name = str_new(entry->name);
|
||||
clone_entry->is_mut = entry->is_mut;
|
||||
clone_entry->scope = entry->scope;
|
||||
clone_entry->ty = type_new_clone(entry->ty);
|
||||
clone_entry->sym_node = node_new_clone(entry->sym_node);
|
||||
clone->entries.data[i] = clone_entry;
|
||||
}
|
||||
|
||||
clone->entries.size = self->entries.size;
|
||||
clone->id = self->id;
|
||||
clone->scope = self->scope;
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
size_t symtable_declare_mut(symtable* self, char const* name, type* ty, node* sym_node)
|
||||
{
|
||||
assert(self);
|
||||
|
|
|
@ -29,6 +29,7 @@ void symtable_init(symtable* self);
|
|||
void symtable_free(symtable* self);
|
||||
void symentry_free(symentry* self);
|
||||
|
||||
symtable* symtable_new_clone(symtable* self);
|
||||
size_t symtable_declare(symtable* self, char const* name, type* ty, node* sym_node);
|
||||
size_t symtable_declare_mut(symtable* self, char const* name, type* ty, node* sym_node);
|
||||
symentry* symtable_find(symtable* self, char const* name);
|
||||
|
|
113
src/type.c
113
src/type.c
|
@ -12,6 +12,103 @@ void type_init(type* self, int base_type)
|
|||
self->sub_types.data = malloc(sizeof(type*));
|
||||
}
|
||||
|
||||
type* type_init_from_node(node* root)
|
||||
{
|
||||
assert(root);
|
||||
type* ty = malloc(sizeof(type));
|
||||
|
||||
if (root->type == NODE_FUN_TYPE)
|
||||
{
|
||||
type_init(ty, TY_FUNCTION);
|
||||
|
||||
node* params = root->children.data[0];
|
||||
|
||||
for (size_t i=0; i< params->children.size; i++)
|
||||
{
|
||||
type* t = type_new_from_node(params->children.data[i]);
|
||||
type_add_sub_type(ty, t);
|
||||
type_free(t); free(t);
|
||||
}
|
||||
|
||||
node* rets = root->children.data[1];
|
||||
|
||||
for (size_t i=0; i< rets->children.size; i++)
|
||||
{
|
||||
type* t = type_new_from_node(rets->children.data[i]);
|
||||
type_add_sub_type(ty, t);
|
||||
type_free(t); free(t);
|
||||
}
|
||||
|
||||
return ty;
|
||||
}
|
||||
|
||||
else if (strcmp(root->value, "fun") == 0)
|
||||
{
|
||||
type_init(ty, TY_FUNCTION);
|
||||
}
|
||||
|
||||
else if (strcmp(root->value, "int") == 0)
|
||||
{
|
||||
type_init(ty, TY_INTEGER);
|
||||
}
|
||||
|
||||
else if (strcmp(root->value, "float") == 0)
|
||||
{
|
||||
type_init(ty, TY_FLOAT);
|
||||
}
|
||||
|
||||
else if (strcmp(root->value, "str") == 0)
|
||||
{
|
||||
type_init(ty, TY_STRING);
|
||||
}
|
||||
|
||||
else if (strcmp(root->value, "bool") == 0)
|
||||
{
|
||||
type_init(ty, TY_BOOLEAN);
|
||||
}
|
||||
|
||||
else if (strcmp(root->value, "type") == 0)
|
||||
{
|
||||
type_init(ty, TY_TYPE);
|
||||
}
|
||||
|
||||
else if (strcmp(root->value, "array") == 0)
|
||||
{
|
||||
type_init(ty, TY_ARRAY);
|
||||
ty->kind = KIND_SEQUENTIAL;
|
||||
}
|
||||
else if (root->type == NODE_ADD)
|
||||
{
|
||||
type_init(ty, TY_TYPE);
|
||||
ty->kind = KIND_DISJUNCTION;
|
||||
}
|
||||
else if (root->type == NODE_MUL)
|
||||
{
|
||||
type_init(ty, TY_TYPE);
|
||||
ty->kind = KIND_CONJUNCTION;
|
||||
}
|
||||
else
|
||||
{
|
||||
char c[512];
|
||||
node_str(root, c, 512);
|
||||
printf("errnode = %s\n", c);
|
||||
fprintf(stderr,
|
||||
"E(%d): cannot compile unknown type '%s').\n",
|
||||
root->lineno,
|
||||
NodeTypeStr[root->type]);
|
||||
}
|
||||
|
||||
for (size_t i=0; i<root->children.size; i++)
|
||||
{
|
||||
type* sub = type_new_from_node(root->children.data[i]);
|
||||
type_add_sub_type(ty, sub);
|
||||
type_free(sub);
|
||||
free(sub);
|
||||
}
|
||||
|
||||
return ty;
|
||||
}
|
||||
|
||||
void type_init_array(type* self, type* array_type)
|
||||
{
|
||||
assert(self);
|
||||
|
@ -35,7 +132,12 @@ void type_free(type* self)
|
|||
self->sub_types.size = 0;
|
||||
self->sub_types.capacity = 0;
|
||||
self->sub_types.data = NULL;
|
||||
}
|
||||
|
||||
type* type_new_from_node(node* root)
|
||||
{
|
||||
assert(root);
|
||||
return type_init_from_node(root);
|
||||
}
|
||||
|
||||
void type_add_sub_type(type* self, type* rhs)
|
||||
|
@ -92,7 +194,8 @@ int type_equals(type* self, type* rhs)
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (self->kind != KIND_SEQUENTIAL)
|
||||
if (self->kind == KIND_CONJUNCTION
|
||||
|| self->kind == KIND_DISJUNCTION)
|
||||
{
|
||||
for (int i=0; i<TY_TYPE_COUNT; i++)
|
||||
{
|
||||
|
@ -141,7 +244,13 @@ size_t type_str(type* self, char* buffer, size_t size)
|
|||
|
||||
for (size_t i=0; i<self->sub_types.size; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
|
||||
if ((i == 0 || self->sub_types.data[i - 1 ]->kind != KIND_RETURN)
|
||||
&& self->sub_types.data[i]->kind == KIND_RETURN)
|
||||
{
|
||||
sz += snprintf(buffer + sz, size - sz, " : ");
|
||||
}
|
||||
else if (i > 0)
|
||||
{
|
||||
sz += snprintf(buffer + sz, size - sz, ", ");
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define TYPE_H
|
||||
|
||||
#include "commons.h"
|
||||
#include "node.h"
|
||||
|
||||
#define TYPES(G) \
|
||||
G(TY_NIL), \
|
||||
|
@ -11,6 +12,7 @@
|
|||
G(TY_STRING), \
|
||||
G(TY_ARRAY), \
|
||||
G(TY_TYPE), \
|
||||
G(TY_FUNCTION), \
|
||||
G(TY_TYPE_COUNT)
|
||||
|
||||
enum Types {
|
||||
|
@ -22,7 +24,8 @@ extern char const* TypesStr[];
|
|||
enum TypeKind {
|
||||
KIND_DISJUNCTION,
|
||||
KIND_CONJUNCTION,
|
||||
KIND_SEQUENTIAL
|
||||
KIND_SEQUENTIAL,
|
||||
KIND_RETURN
|
||||
};
|
||||
|
||||
typedef struct type {
|
||||
|
@ -37,9 +40,11 @@ typedef struct type {
|
|||
} type;
|
||||
|
||||
void type_init(type* self, int base_type);
|
||||
type* type_init_from_node(node* root);
|
||||
void type_init_array(type* self, type* array_type);
|
||||
void type_free(type* self);
|
||||
|
||||
type* type_new_from_node(node* root);
|
||||
void type_add_sub_type(type* self, type* rhs);
|
||||
|
||||
type* type_new_clone(type* self);
|
||||
|
|
35
src/value.c
35
src/value.c
|
@ -67,6 +67,17 @@ void value_init_type(value* self, type* ty, int lineno)
|
|||
type_init(self->type, TY_TYPE);
|
||||
}
|
||||
|
||||
void value_init_fun(value* self, fun* f, int lineno)
|
||||
{
|
||||
assert(self);
|
||||
assert(f);
|
||||
|
||||
self->val.fun_val = fun_new_clone(f);
|
||||
|
||||
self->lineno = lineno;
|
||||
self->type = type_new_clone(f->ty);
|
||||
}
|
||||
|
||||
void value_free(value* self)
|
||||
{
|
||||
assert(self);
|
||||
|
@ -94,6 +105,14 @@ void value_free(value* self)
|
|||
self->val.array_val = NULL;
|
||||
}
|
||||
|
||||
if (self->type->base_type == TY_FUNCTION
|
||||
&& self->val.fun_val != NULL)
|
||||
{
|
||||
fun_free(self->val.fun_val);
|
||||
free(self->val.fun_val);
|
||||
self->val.fun_val = NULL;
|
||||
}
|
||||
|
||||
type_free(self->type);
|
||||
free(self->type);
|
||||
self->type = NULL;
|
||||
|
@ -121,6 +140,11 @@ value* value_new_clone(value* self)
|
|||
clone->val.array_val = array_new_clone(self->val.array_val);
|
||||
}
|
||||
|
||||
if (self->type->base_type == TY_FUNCTION)
|
||||
{
|
||||
clone->val.fun_val = fun_new_clone(self->val.fun_val);
|
||||
}
|
||||
|
||||
clone->lineno = self->lineno;
|
||||
|
||||
return clone;
|
||||
|
@ -167,6 +191,11 @@ int value_equals(value* self, value* rhs)
|
|||
return array_equals(self->val.array_val, rhs->val.array_val);
|
||||
}
|
||||
|
||||
if (self->type->base_type == TY_FUNCTION)
|
||||
{
|
||||
return fun_equals(self->val.fun_val, rhs->val.fun_val);
|
||||
}
|
||||
|
||||
size_t const SZ = 512;
|
||||
char ty_str[SZ];
|
||||
|
||||
|
@ -190,6 +219,12 @@ size_t value_str(value* self, char* buffer, size_t size)
|
|||
case TY_ARRAY:
|
||||
return array_str(self->val.array_val, buffer, size);
|
||||
|
||||
case TY_FUNCTION:
|
||||
return fun_str(self->val.fun_val, buffer, size);
|
||||
|
||||
case TY_FLOAT:
|
||||
return snprintf(buffer, size, "%f",
|
||||
self->val.real_float);
|
||||
case TY_STRING:
|
||||
return snprintf(buffer, size, "%s",
|
||||
self->val.string);
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "commons.h"
|
||||
#include "type.h"
|
||||
#include "array.h"
|
||||
#include "fun.h"
|
||||
|
||||
typedef struct {
|
||||
type* type;
|
||||
|
@ -15,6 +16,8 @@ typedef struct {
|
|||
char* string;
|
||||
array* array_val;
|
||||
type* type_val;
|
||||
fun* fun_val;
|
||||
|
||||
} val;
|
||||
} value;
|
||||
|
||||
|
@ -24,6 +27,7 @@ void value_init_float(value* self, float real_float, int lineno);
|
|||
void value_init_string(value* self, char* string, int lineno);
|
||||
void value_init_array(value* self, array* arr, int lineno);
|
||||
void value_init_type(value* self, type* ty, int lineno);
|
||||
void value_init_fun(value* self, fun* f, int lineno);
|
||||
|
||||
void value_free(value* self);
|
||||
|
||||
|
|
51
src/vm.c
51
src/vm.c
|
@ -109,6 +109,9 @@ void vm_exec(vm* self, program* prog)
|
|||
|
||||
case OP_TEQ: vm_teq(self); break;
|
||||
|
||||
case OP_CALL: vm_call(self, param); break;
|
||||
case OP_RET: vm_ret(self); break;
|
||||
|
||||
default: {
|
||||
fprintf(stderr, "unknown opcode %s\n",
|
||||
OpcodesStr[opcode]);
|
||||
|
@ -1142,3 +1145,51 @@ void vm_br(vm* self, int param)
|
|||
assert(self);
|
||||
self->pc = param;
|
||||
}
|
||||
|
||||
void vm_call(vm* self, int param)
|
||||
{
|
||||
assert(self);
|
||||
|
||||
// get function and parameters
|
||||
value* args[param];
|
||||
|
||||
for (int i=0; i<param; i++)
|
||||
{
|
||||
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);
|
||||
|
||||
value* ret = value_new_clone(v.stack.data[v.stack.size - 1]);
|
||||
vm_push_value(self, ret);
|
||||
|
||||
vm_free(&v);
|
||||
|
||||
for (int i=0; i<param; i++)
|
||||
{
|
||||
value_free(args[i]); free(args[i]);
|
||||
}
|
||||
|
||||
value_free(fun_val); free(fun_val);
|
||||
|
||||
self->pc++;
|
||||
}
|
||||
|
||||
void vm_ret(vm* self)
|
||||
{
|
||||
assert(self);
|
||||
self->pc = self->prog->instrs.size;
|
||||
}
|
||||
|
|
3
src/vm.h
3
src/vm.h
|
@ -95,4 +95,7 @@ void vm_teq(vm* self);
|
|||
void vm_brf(vm* self, int param);
|
||||
void vm_br(vm* self, int param);
|
||||
|
||||
void vm_call(vm* self, int param);
|
||||
void vm_ret(vm* self);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
let f = fun () as int return 1.2; end ; f
|
|
@ -1,8 +1,8 @@
|
|||
let x = 0 x + 1.2
|
||||
let x = false x + "false"
|
||||
let x=0 let x=7
|
||||
let x=[1, 2] x[7, 9]
|
||||
let x = 0 x = 3.2
|
||||
let x = 0 x = 7
|
||||
let x=[1, 2] x[0] = 3.2
|
||||
let x=[3, 4] x[0] = 7
|
||||
let x = 0 ; x + 1.2
|
||||
let x = false ; x + "false"
|
||||
let x=0 ; let x=7
|
||||
let x=[1, 2] ; x[7, 9]
|
||||
let x = 0 ; x = 3.2
|
||||
let x = 0 ; x = 7
|
||||
let x=[1, 2] ; x[0] = 3.2
|
||||
let x=[3, 4] ; x[0] = 7
|
||||
|
|
|
@ -9,7 +9,6 @@ echo -e "\e[34m=== Error Testing ===\e[0m"
|
|||
for file in $(find . -name "err_*.wuz")
|
||||
do
|
||||
LINE=1
|
||||
|
||||
while read line;
|
||||
do
|
||||
echo "$line" | wuz &> /dev/null
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
assert fun<int:int> is type
|
||||
assert fun<int:> is type
|
||||
assert fun<:int> is type
|
||||
assert fun<int, int: float, str> is type
|
||||
assert fun< fun<:> : int> is type
|
||||
|
||||
let a = fun (x as int, y as int) as int
|
||||
0
|
||||
end
|
||||
|
||||
assert a is fun<int, int: int>
|
||||
assert !(a is fun<:>)
|
||||
|
||||
let b = fun (x as int) as int
|
||||
return x * 7
|
||||
end
|
||||
|
||||
assert 42 == b 6
|
||||
|
||||
let c = fun () as int
|
||||
return 3 * 6
|
||||
end
|
||||
|
||||
assert 18 == *c
|
||||
|
||||
let d = fun () as int
|
||||
return 43
|
||||
27
|
||||
end
|
||||
|
||||
assert 43 == *d
|
||||
|
|
@ -20,3 +20,4 @@ assert 64 == 2^(3+3)
|
|||
assert 1 == -2 - -3
|
||||
|
||||
assert 5 + 7 == 12
|
||||
|
||||
|
|
Loading…
Reference in New Issue