diff --git a/doc/roza.bnf b/doc/roza.bnf index 9ee02d7..32de02b 100644 --- a/doc/roza.bnf +++ b/doc/roza.bnf @@ -2,12 +2,17 @@ MOD ::= EXPR* EXPR ::= | ASSERT | VARDECL +| FUNDECL +| RETURN | VARSET | SCOPE | IF | OR ASSERT ::= assert EXPR VARDECL ::= let ident assign EXPR +FUNDECL ::= fun ident opar PARAMS cpar BLOCK end +PARAMS ::= (ident (comma ident)*)? +RETURN ::= return EXPR VARSET ::= ident assign EXPR BLOCK ::= EXPR* SCOPE ::= begin BLOCK end @@ -23,5 +28,8 @@ TERM ::= FACTOR ((add | sub) FACTOR)* FACTOR ::= POWER ((mul | div | mod) POWER)* POWER ::= UNARY (pow UNARY)? UNARY ::= sub? GROUP | not? GROUP -GROUP ::= BUILTIN | opar EXPR cpar +GROUP ::= LITERAL | opar EXPR cpar +LITERAL ::= BUILTIN | FUNCALL +FUNCALL ::= ident opar ARGS cpar +ARGS ::= (EXPR (comma EXPR)*)? BUILTIN ::= num | bool | str | ident diff --git a/lib/compiler.c b/lib/compiler.c index 675b4d4..5a2fd47 100644 --- a/lib/compiler.c +++ b/lib/compiler.c @@ -1,10 +1,12 @@ #include "compiler.h" #include "lib/commons.h" #include "lib/mod.h" +#include "lib/prepass.h" +#include "lib/sym.h" #include "node.h" +#include "fun.h" void compiler_init(compiler_t* compiler, - mod_t* mod, sym_t* sym, tysy_t* tysy, err_t* err) @@ -14,7 +16,6 @@ void compiler_init(compiler_t* compiler, assert(tysy); assert(err); - compiler->mod = mod; compiler->sym = sym; compiler->tysy = tysy; compiler->err = err; @@ -27,7 +28,7 @@ void compiler_free(compiler_t* compiler) assert(compiler); } -int compiler_run(compiler_t* compiler, node_t* node) +int compiler_run(compiler_t* compiler, node_t* node, program_t* program) { assert(compiler); assert(node); @@ -37,7 +38,7 @@ int compiler_run(compiler_t* compiler, node_t* node) case NODE_MOD: { for (size_t i=0; ichildren.size; i++) { - compiler_run(compiler, (node_t*) node->children.data[i]); + compiler_run(compiler, (node_t*) node->children.data[i], program); } } break; @@ -45,9 +46,10 @@ int compiler_run(compiler_t* compiler, node_t* node) double value = atof(node->value.data); value_t* val = tysy_new_num(compiler->tysy, value, node->line); Opcode op = OP_PUSH; - param_t param = (param_t) mod_push_new_value(compiler->mod, val); + param_t param = (param_t) program_push_new_value(program, + (struct value*) val); - mod_push_instr(compiler->mod, op, param); + program_push_instr(program, op, param); } break; @@ -55,24 +57,26 @@ int compiler_run(compiler_t* compiler, node_t* node) int value = strcmp(node->value.data, "true") == 0; value_t* val = tysy_new_bool(compiler->tysy, value, node->line); Opcode op = OP_PUSH; - param_t param = (param_t) mod_push_new_value(compiler->mod, val); + param_t param = (param_t) program_push_new_value(program, + (struct value*) val); - mod_push_instr(compiler->mod, op, param); + program_push_instr(program, op, param); } break; case NODE_STR: { char* value = node->value.data; value_t* val = tysy_new_str(compiler->tysy, value, node->line); Opcode op = OP_PUSH; - param_t param = (param_t) mod_push_new_value(compiler->mod, val); + param_t param = (param_t) program_push_new_value(program, + (struct value*) val); - mod_push_instr(compiler->mod, op, param); + program_push_instr(program, op, param); } break; case NODE_ASSERT: { assert(node->children.size == 1); - compiler_run(compiler, node_child(node, 0)); - mod_push_instr(compiler->mod, OP_ASSERT, RZ_NO_PARAM); + compiler_run(compiler, node_child(node, 0), program); + program_push_instr(program, OP_ASSERT, RZ_NO_PARAM); } break; case NODE_NE: @@ -81,11 +85,11 @@ int compiler_run(compiler_t* compiler, node_t* node) for (size_t i=0; ichildren.size; i++) { - compiler_run(compiler, node_child(node, i)); + compiler_run(compiler, node_child(node, i), program); } - mod_push_instr(compiler->mod, - node->type == NODE_EQ ? OP_EQ : OP_NE, RZ_NO_PARAM); + program_push_instr(program, + node->type == NODE_EQ ? OP_EQ : OP_NE, RZ_NO_PARAM); } break; case NODE_LT: @@ -96,7 +100,7 @@ int compiler_run(compiler_t* compiler, node_t* node) for (size_t i=0; ichildren.size; i++) { - compiler_run(compiler, node_child(node, i)); + compiler_run(compiler, node_child(node, i), program); } Opcode op; @@ -109,7 +113,7 @@ int compiler_run(compiler_t* compiler, node_t* node) default: assert(0); } - mod_push_instr(compiler->mod, op, RZ_NO_PARAM); + program_push_instr(program, op, RZ_NO_PARAM); } break; @@ -121,7 +125,7 @@ int compiler_run(compiler_t* compiler, node_t* node) case NODE_POW: { for (size_t i=0; ichildren.size; i++) { - compiler_run(compiler, node_child(node, i)); + compiler_run(compiler, node_child(node, i), program); } Opcode op; @@ -156,7 +160,7 @@ int compiler_run(compiler_t* compiler, node_t* node) } } - mod_push_instr(compiler->mod, op, RZ_NO_PARAM); + program_push_instr(program, op, RZ_NO_PARAM); } break; @@ -167,29 +171,29 @@ int compiler_run(compiler_t* compiler, node_t* node) for (size_t i=0; ichildren.size; i++) { - compiler_run(compiler, node_child(node, i)); - size_t addr = mod_push_instr(compiler->mod, OP_BRF, RZ_NO_PARAM); + compiler_run(compiler, node_child(node, i), program); + size_t addr = program_push_instr(program, OP_BRF, RZ_NO_PARAM); to_false[sz++] = addr; } // True case value_t* t = tysy_new_bool(compiler->tysy, 1, node->line); - param_t t_param = mod_push_new_value(compiler->mod, t); - mod_push_instr(compiler->mod, OP_PUSH, t_param); - size_t to_end = mod_push_instr(compiler->mod, OP_BR, RZ_NO_PARAM); + param_t t_param = program_push_new_value(program, (struct value*) t); + program_push_instr(program, OP_PUSH, t_param); + size_t to_end = program_push_instr(program, OP_BR, RZ_NO_PARAM); // False case - size_t program_sz = compiler->mod->program.size; + size_t program_sz = program->size; for (size_t i=0; imod->program.params[to_false[i]] = program_sz; + program->params[to_false[i]] = program_sz; } value_t* f = tysy_new_bool(compiler->tysy, 0, node->line); - param_t f_param = mod_push_new_value(compiler->mod, f); - mod_push_instr(compiler->mod, OP_PUSH, f_param); + param_t f_param = program_push_new_value(program, (struct value*) f); + program_push_instr(program, OP_PUSH, f_param); - compiler->mod->program.params[to_end] = compiler->mod->program.size; + program->params[to_end] = program->size; } break; @@ -200,75 +204,81 @@ int compiler_run(compiler_t* compiler, node_t* node) for (size_t i=0; ichildren.size; i++) { - compiler_run(compiler, node_child(node, i)); - size_t addr = mod_push_instr(compiler->mod, OP_BRT, RZ_NO_PARAM); + compiler_run(compiler, node_child(node, i), program); + size_t addr = program_push_instr(program, OP_BRT, RZ_NO_PARAM); to_true[sz++] = addr; } // False case value_t* f = tysy_new_bool(compiler->tysy, 0, node->line); - param_t f_param = mod_push_new_value(compiler->mod, f); - mod_push_instr(compiler->mod, OP_PUSH, f_param); - size_t to_end = mod_push_instr(compiler->mod, OP_BR, RZ_NO_PARAM); + param_t f_param = program_push_new_value(program, (struct value*) f); + program_push_instr(program, OP_PUSH, f_param); + size_t to_end = program_push_instr(program, OP_BR, RZ_NO_PARAM); // True case - size_t program_sz = compiler->mod->program.size; + size_t program_sz = program->size; for (size_t i=0; imod->program.params[to_true[i]] = program_sz; + program->params[to_true[i]] = program_sz; } value_t* t = tysy_new_bool(compiler->tysy, 1, node->line); - param_t t_param = mod_push_new_value(compiler->mod, t); - mod_push_instr(compiler->mod, OP_PUSH, t_param); + param_t t_param = program_push_new_value(program, (struct value*) t); + program_push_instr(program, OP_PUSH, t_param); - compiler->mod->program.params[to_end] = compiler->mod->program.size; + program->params[to_end] = program->size; } break; case NODE_NOT: { assert(node->children.size > 0); - compiler_run(compiler, (node_t*) node->children.data[0]); - mod_push_instr(compiler->mod, OP_NOT, RZ_NO_PARAM); + compiler_run(compiler, (node_t*) node->children.data[0], program); + program_push_instr(program, OP_NOT, RZ_NO_PARAM); } break; case NODE_VARDECL: { char* name = ((node_t*) node->children.data[0])->value.data; - node_t* block = node_try_find_parent(node, NODE_BLOCK); sym_entry_t* entry = NULL; entry = sym_try_find_by_name(compiler->sym, name, compiler->scope, SYM_PRE, - block); + node); if (!entry) { entry = sym_try_find_by_name(compiler->sym, name, compiler->scope, SYM_DECL, - block); + node); } + if (!entry) + { + char msg[RZ_STR_LIMIT]; + snprintf(msg, RZ_STR_LIMIT, "unknown entry %s\n", name); + err_fatal(compiler->err, msg, node->line); + err_dump(compiler->err); + } + assert(entry); entry->state = SYM_DECL; int id = entry->id; - compiler_run(compiler, (node_t*) node->children.data[1]); - mod_push_instr(compiler->mod, OP_STORE, id); + compiler_run(compiler, (node_t*) node->children.data[1], program); + program_push_instr(program, OP_STORE, id); } break; case NODE_VARSET: { char* name = ((node_t*) node->children.data[0])->value.data; - node_t* block = node_try_find_parent(node, NODE_BLOCK); sym_entry_t* entry = sym_try_find_by_name(compiler->sym, name, compiler->scope, SYM_DECL, - block); + node); if (!entry) { @@ -281,18 +291,18 @@ int compiler_run(compiler_t* compiler, node_t* node) else { int id = entry->id; - compiler_run(compiler, (node_t*) node->children.data[1]); - mod_push_instr(compiler->mod, OP_STORE, id); + compiler_run(compiler, (node_t*) node->children.data[1], program); + program_push_instr(program, OP_STORE, id); } } break; case NODE_IDENT: { char* name = node->value.data; - node_t* block = node_try_find_parent(node, NODE_BLOCK); + sym_entry_t* entry = sym_try_find_by_name(compiler->sym, name, compiler->scope, SYM_DECL, - block); + node); if (!entry) { char msg[RZ_STR_LIMIT]; @@ -305,19 +315,19 @@ int compiler_run(compiler_t* compiler, node_t* node) else { int id = entry->id; - mod_push_instr(compiler->mod, OP_LOAD, id); + program_push_instr(program, OP_LOAD, id); } } break; case NODE_SCOPE: { - compiler_run(compiler, (node_t*) node->children.data[0]); + compiler_run(compiler, (node_t*) node->children.data[0], program); } break; case NODE_BLOCK: { compiler->scope++; for (size_t i=0; ichildren.size; i++) { - compiler_run(compiler, (node_t*) node->children.data[i]); + compiler_run(compiler, (node_t*) node->children.data[i], program); } compiler->scope--; @@ -329,13 +339,102 @@ int compiler_run(compiler_t* compiler, node_t* node) int end_points[IF_LIMIT]; size_t size = 0; - compiler_run_if(compiler, node, end_points, &size); + compiler_run_if(compiler, node, program, end_points, &size); assert(size < IF_LIMIT); for (size_t i=0; imod->program.params[end_points[i]] - = compiler->mod->program.size; + program->params[end_points[i]] = program->size; + } + + } break; + + case NODE_FUNDECL: { + char* fun_name = ((node_t*) node->children.data[0])->value.data; + + fun_t* fun = malloc(sizeof(fun_t)); + fun_init(fun, (struct tysy*) compiler->tysy, compiler->err); + + sym_entry_t* entry = sym_try_find_by_name(compiler->sym, + fun_name, + compiler->scope, + SYM_PRE, + node); + assert(entry); + + entry->state = SYM_DECL; + + // Compile function + { + compiler_t comp; + compiler_init(&comp, (sym_t*) fun->sym, + compiler->tysy, compiler->err); + + tysolver_t tysolver; + tysolver_init(&tysolver, (sym_t*) fun->sym, compiler->tysy); + + prepass_t pre; + prepass_init(&pre, (sym_t*) fun->sym, compiler->tysy, + &tysolver, compiler->err); + + prepass_run(&pre, (node_t*) node->children.data[2]); + compiler_run(&comp, (node_t*) node->children.data[1], &fun->program); + compiler_run(&comp, (node_t*) node->children.data[2], &fun->program); + program_push_instr(&fun->program, OP_RET, RZ_NO_PARAM); + + prepass_free(&pre); + tysolver_free(&tysolver); + 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); + program_push_instr(program, OP_PUSH, param); + + program_push_instr(program, OP_STORE, entry->id); + } break; + + case NODE_PARAMS: { + for (size_t i=0; ichildren.size; i++) + { + node_t* child = (node_t*) node->children.data[i]; + char* name = child->value.data; + sym_declare(compiler->sym, name, NULL, + compiler->scope, SYM_DECL, + child); + } + } break; + + case NODE_RETURN: { + compiler_run(compiler, (node_t*) node->children.data[0], program); + program_push_instr(program, OP_RET, RZ_NO_PARAM); + } break; + + case NODE_FUNCALL: { + char* name = ((node_t*) node->children.data[0])->value.data; + node_t* args = (node_t*) node->children.data[1]; + + for (size_t i=0; ichildren.size; i++) + { + compiler_run(compiler, (node_t*)args->children.data[i], program); + } + + sym_entry_t* entry = sym_try_find_by_name(compiler->sym, + name, + compiler->scope, + SYM_DECL, + node); + if (!entry) + { + char msg[RZ_STR_LIMIT]; + snprintf(msg, RZ_STR_LIMIT, "undefined function '%s'", name); + err_fatal(compiler->err, msg, node->line); + } + else + { + int id = entry->id; + program_push_instr(program, OP_LOAD, id); + program_push_instr(program, OP_CALL, args->children.size); } } break; @@ -350,26 +449,25 @@ int compiler_run(compiler_t* compiler, node_t* node) return 0; } -void compiler_run_if(compiler_t* compiler, node_t* node, +void compiler_run_if(compiler_t* compiler, node_t* node, program_t* program, int* end_points, size_t* sz) { assert(compiler); assert(node); // if - compiler_run(compiler, (node_t*) node->children.data[0]); + compiler_run(compiler, (node_t*) node->children.data[0], program); // if false goto next - int to_next = mod_push_instr(compiler->mod, OP_BRF, RZ_NO_PARAM); + int to_next = program_push_instr(program, OP_BRF, RZ_NO_PARAM); // then - compiler_run(compiler, (node_t*) node->children.data[1]); + compiler_run(compiler, (node_t*) node->children.data[1], program); // goto end - int to_end = mod_push_instr(compiler->mod, OP_BR, RZ_NO_PARAM); + int to_end = program_push_instr(program, OP_BR, RZ_NO_PARAM); end_points[*sz] = to_end; (*sz)++; - compiler->mod->program.params[to_next] - = compiler->mod->program.size; + program->params[to_next] = program->size; if (node->children.size >= 3) { @@ -377,11 +475,11 @@ void compiler_run_if(compiler_t* compiler, node_t* node, if (next->type == NODE_BLOCK) { - compiler_run(compiler, next); + compiler_run(compiler, next, program); } else if (next->type == NODE_IF) { - compiler_run_if(compiler, next, end_points, sz); + compiler_run_if(compiler, next, program, end_points, sz); } } } diff --git a/lib/compiler.h b/lib/compiler.h index d7ea233..2875583 100644 --- a/lib/compiler.h +++ b/lib/compiler.h @@ -9,7 +9,6 @@ #include "sym.h" typedef struct { - mod_t* mod; sym_t* sym; tysy_t* tysy; err_t* err; @@ -18,15 +17,14 @@ typedef struct { } compiler_t; void compiler_init(compiler_t* compiler, - mod_t* mod, sym_t* sym, tysy_t* tysy, err_t* err); void compiler_free(compiler_t* compiler); -int compiler_run(compiler_t* compiler, node_t* node); -void compiler_run_if(compiler_t* compiler, node_t* node, +int compiler_run(compiler_t* compiler, node_t* node, program_t* program); +void compiler_run_if(compiler_t* compiler, node_t* node, program_t* program, int* end_points, size_t* sz); #endif diff --git a/lib/fun.c b/lib/fun.c new file mode 100644 index 0000000..bd4bb35 --- /dev/null +++ b/lib/fun.c @@ -0,0 +1,19 @@ +#include "fun.h" +#include "sym.h" + +void fun_init(fun_t* fun, struct tysy* tysy, err_t* err) +{ + assert(fun); + program_init(&fun->program); + fun->sym = malloc(sizeof(sym_t)); + sym_init((sym_t*) fun->sym, (tysy_t*) tysy, err); +} + +void fun_free(fun_t* fun) +{ + assert(fun); + program_free(&fun->program); + + sym_free((sym_t*) fun->sym); + free(fun->sym); +} diff --git a/lib/fun.h b/lib/fun.h new file mode 100644 index 0000000..1bed6ef --- /dev/null +++ b/lib/fun.h @@ -0,0 +1,20 @@ +#ifndef RZ_FUN_H +#define RZ_FUN_H + +#include "commons.h" +#include "program.h" +#include "err.h" + +struct sym; + +typedef struct { + program_t program; + struct sym* sym; + struct tysy* tysy; +} fun_t; + +void fun_init(fun_t* fun, struct tysy* tysy, err_t* err); +void fun_free(fun_t* fun); + + +#endif diff --git a/lib/lexer.c b/lib/lexer.c index f41e232..4e6219c 100644 --- a/lib/lexer.c +++ b/lib/lexer.c @@ -68,9 +68,12 @@ node_t* lexer_try_new_next(lexer_t* lexer) RZ_TEXT("<", NODE_LT, 0); RZ_TEXT(">", NODE_GT, 0); RZ_TEXT("=", NODE_ASSIGN, 0); + RZ_TEXT(",", NODE_COMMA, 0); // Keywords // ======== + RZ_KEYWORD("fun", NODE_FUN, 0); + RZ_KEYWORD("return", NODE_RETURN, 0); RZ_KEYWORD("if", NODE_IF, 0); RZ_KEYWORD("then", NODE_THEN, 0); RZ_KEYWORD("else", NODE_ELSE, 0); @@ -422,5 +425,6 @@ int lexer_is_sep(lexer_t* lexer, size_t idx) || c == '!' || c == '(' || c == ')' + || c == ',' ; } diff --git a/lib/loader.c b/lib/loader.c index 9cffd61..c8eb307 100644 --- a/lib/loader.c +++ b/lib/loader.c @@ -108,7 +108,7 @@ int loader_ldfile(loader_t* loader, char const* path, int debug) // prepass { prepass_t prepass; - prepass_init(&prepass, &sym, &tysolver, &err); + prepass_init(&prepass, &sym, &tysy, &tysolver, &err); prepass_run(&prepass, node); prepass_free(&prepass); } @@ -116,8 +116,8 @@ int loader_ldfile(loader_t* loader, char const* path, int debug) // compile { compiler_t compiler; - compiler_init(&compiler, &mod, &sym, &tysy, &err); - int status = compiler_run(&compiler, node); + compiler_init(&compiler, &sym, &tysy, &err); + int status = compiler_run(&compiler, node, &mod.program); if (status != 0) { diff --git a/lib/mod.c b/lib/mod.c index 139d036..e0e3039 100644 --- a/lib/mod.c +++ b/lib/mod.c @@ -5,116 +5,16 @@ void mod_init(mod_t* mod) { assert(mod); - mod->program.size = 0; - mod->program.cap = 0; - mod->program.ops = NULL; - mod->program.params = NULL; - - mod->values.size = 0; - mod->values.cap = 0; - mod->values.data = NULL; + program_init(&mod->program); } void mod_free(mod_t* mod) { assert(mod); - free(mod->program.ops); - free(mod->program.params); - mod->program.size = 0; - mod->program.cap = 0; - - for (size_t i=0; ivalues.size; i++) - { - value_free(mod->values.data[i]); - free(mod->values.data[i]); - } - - free(mod->values.data); - mod->values.data = NULL; - mod->values.size = 0; - mod->values.cap = 0; -} - -size_t mod_push_instr(mod_t* mod, Opcode op, param_t param) -{ - assert(mod); - - if (mod->program.cap == 0) - { - mod->program.cap = 2; - mod->program.ops = malloc(sizeof(Opcode) * mod->program.cap); - mod->program.params = malloc(sizeof(param_t) * mod->program.cap); - } - - if (mod->program.size >= mod->program.cap) - { - mod->program.cap *= 2; - mod->program.ops = realloc(mod->program.ops, - sizeof(Opcode) * mod->program.cap); - mod->program.params = realloc(mod->program.params, - sizeof(param_t) * mod->program.cap); - } - - mod->program.ops[mod->program.size] = op; - mod->program.params[mod->program.size] = param; - mod->program.size++; - - return mod->program.size - 1; + program_free(&mod->program); } size_t mod_str(mod_t* mod, char* buffer, size_t size) { - size_t sz = 0; - - sz += snprintf(buffer + sz, size - sz, "======== VALUES ========\n"); - for (size_t i=0; ivalues.size; i++) - { - sz += snprintf(buffer + sz, size - sz, "%d| ", (int) i); - sz += value_str(mod->values.data[i], buffer + sz, size - sz); - sz += snprintf(buffer + sz, size - sz, "\n"); - } - - sz += snprintf(buffer + sz, size - sz, "\n======== PROGRAM ========\n"); - for (size_t i=0; iprogram.size; i++) - { - if (mod->program.params[i] != RZ_NO_PARAM) - { - sz += snprintf(buffer + sz, size - sz, "%d| %s %d\n", - (int) i, - OpcodeStr[mod->program.ops[i]] + strlen("OP_"), - mod->program.params[i]); - } - else - { - sz += snprintf(buffer + sz, size - sz, "%d| %s\n", - (int) i, - OpcodeStr[mod->program.ops[i]] + strlen("OP_")); - } - } - - return sz; -} - -size_t mod_push_new_value(mod_t* mod, value_t* value) -{ - assert(mod); - assert(value); - - if (mod->values.size == 0) - { - mod->values.cap = 2; - mod->values.data = malloc(sizeof(value_t*) * mod->values.cap); - } - - if (mod->values.size >= mod->values.cap) - { - mod->values.cap *= 2; - mod->values.data = realloc(mod->values.data, - sizeof(value_t*) * mod->values.cap); - } - - mod->values.data[mod->values.size] = value; - mod->values.size++; - - return mod->values.size - 1; + return program_str(&mod->program, buffer, size); } diff --git a/lib/mod.h b/lib/mod.h index 2b43ea3..d7f742d 100644 --- a/lib/mod.h +++ b/lib/mod.h @@ -4,28 +4,15 @@ #include "commons.h" #include "opcodes.h" #include "value.h" +#include "program.h" typedef struct { - struct { - size_t size; - size_t cap; - Opcode* ops; - param_t* params; - } program; - - struct { - size_t size; - size_t cap; - value_t** data; - } values; + program_t program; } mod_t; void mod_init(mod_t* mod); void mod_free(mod_t* mod); -size_t mod_push_instr(mod_t* mod, Opcode op, param_t param); size_t mod_str(mod_t* mod, char* buffer, size_t size); -size_t mod_push_new_value(mod_t* mod, value_t* value); - #endif diff --git a/lib/node.h b/lib/node.h index e661b73..5d1f81a 100644 --- a/lib/node.h +++ b/lib/node.h @@ -14,7 +14,9 @@ G(NODE_AND), G(NODE_OR), G(NODE_NOT), \ G(NODE_LET), G(NODE_IDENT), G(NODE_ASSIGN), G(NODE_VARDECL), \ G(NODE_VARSET), G(NODE_BEGIN), G(NODE_END), G(NODE_BLOCK), \ - G(NODE_SCOPE), G(NODE_IF), G(NODE_THEN), G(NODE_ELSE) + G(NODE_SCOPE), G(NODE_IF), G(NODE_THEN), G(NODE_ELSE), \ + G(NODE_FUNDECL), G(NODE_FUN), G(NODE_RETURN), G(NODE_COMMA), \ + G(NODE_PARAMS), G(NODE_FUNCALL), G(NODE_ARGS) RZ_ENUM_H(NodeType, NODE_TYPE); diff --git a/lib/opcodes.h b/lib/opcodes.h index 30626ba..3ac20ba 100644 --- a/lib/opcodes.h +++ b/lib/opcodes.h @@ -13,7 +13,8 @@ G(OP_NOT), \ G(OP_BRF), G(OP_BRT), G(OP_BR), \ G(OP_STRCAT), G(OP_STRDUP), \ - G(OP_LOAD), G(OP_STORE) + G(OP_LOAD), G(OP_STORE), \ + G(OP_CALL), G(OP_RET) RZ_ENUM_H(Opcode, OPCODES); diff --git a/lib/parser.c b/lib/parser.c index 1705c44..f06fb6b 100644 --- a/lib/parser.c +++ b/lib/parser.c @@ -79,6 +79,16 @@ node_t* parser_try_new_expr(parser_t* parser) return parser_try_new_vardecl(parser); } + if (type_1 == NODE_FUN) + { + return parser_try_new_fundecl(parser); + } + + if (type_1 == NODE_RETURN) + { + return parser_try_new_return(parser); + } + if (type_1 == NODE_BEGIN) { return parser_try_new_scope(parser); @@ -118,6 +128,66 @@ node_t* parser_try_new_vardecl(parser_t* parser) return node; } +node_t* parser_try_new_fundecl(parser_t* parser) +{ + assert(parser); + node_t* node = malloc(sizeof(node_t)); + node_init(node, NODE_FUNDECL, "", parser->lexer->line); + + parser_skip(parser, NODE_FUN); + node_t* ident = parser_try_new_consume(parser, NODE_IDENT); + node_add_new_child(node, ident); + + parser_skip(parser, NODE_OPAR); + node_add_new_child(node, parser_try_new_params(parser)); + parser_skip(parser, NODE_CPAR); + + node_add_new_child(node, parser_try_new_block(parser)); + parser_skip(parser, NODE_END); + + return node; +} + +node_t* parser_try_new_params(parser_t* parser) +{ + assert(parser); + + node_t* node = malloc(sizeof(node_t)); + node_init(node, NODE_PARAMS, "", parser->lexer->line); + + int next = lexer_peek(parser->lexer, 1); + + if (next == NODE_CPAR) + { + return node; + } + + node_add_new_child(node, parser_try_new_consume(parser, NODE_IDENT)); + + while (1) + { + int next_1 = lexer_peek(parser->lexer, 1); + + if (next_1 != NODE_COMMA) + { + break; + } + + parser_skip(parser, NODE_COMMA); + node_add_new_child(node, parser_try_new_consume(parser, NODE_IDENT)); + } + + return node; +} + +node_t* parser_try_new_return(parser_t* parser) +{ + assert(parser); + node_t* node = parser_try_new_consume(parser, NODE_RETURN); + node_add_new_child(node, parser_try_new_expr(parser)); + return node; +} + node_t* parser_try_new_varset(parser_t* parser) { assert(parser); @@ -425,11 +495,63 @@ node_t* parser_try_new_group(parser_t* parser) return node; } - node_t* builtin = parser_try_new_builtin(parser); + return parser_try_new_literal(parser); +} - assert(builtin); +node_t* parser_try_new_literal(parser_t* parser) +{ + assert(parser); - return builtin; + int type_1 = lexer_peek(parser->lexer, 1); + int type_2 = lexer_peek(parser->lexer, 2); + + if (type_1 == NODE_IDENT + && type_2 == NODE_OPAR) + { + return parser_try_new_funcall(parser); + } + + return parser_try_new_builtin(parser); +} + +node_t* parser_try_new_funcall(parser_t* parser) +{ + assert(parser); + + node_t* node = malloc(sizeof(node_t)); + node_init(node, NODE_FUNCALL, "", parser->lexer->line); + + node_add_new_child(node, parser_try_new_consume(parser, NODE_IDENT)); + parser_skip(parser, NODE_OPAR); + node_add_new_child(node, parser_try_new_args(parser)); + parser_skip(parser, NODE_CPAR); + + return node; +} + +node_t* parser_try_new_args(parser_t* parser) +{ + assert(parser); + node_t* node = malloc(sizeof(node_t)); + node_init(node, NODE_ARGS, "", parser->lexer->line); + + int next = lexer_peek(parser->lexer, 1); + + if (next == NODE_CPAR) + { + return node; + } + + node_t* arg = parser_try_new_expr(parser); + node_add_new_child(node, arg); + + while ((next = lexer_peek(parser->lexer, 1)) == NODE_COMMA) + { + parser_skip(parser, NODE_COMMA); + node_add_new_child(node, parser_try_new_expr(parser)); + } + + return node; } node_t* parser_try_new_builtin(parser_t* parser) diff --git a/lib/parser.h b/lib/parser.h index f2c139a..dd08e9f 100644 --- a/lib/parser.h +++ b/lib/parser.h @@ -18,6 +18,9 @@ node_t* parser_try_new_mod(parser_t* parser); node_t* parser_try_new_expr(parser_t* parser); node_t* parser_try_new_assert(parser_t* parser); node_t* parser_try_new_vardecl(parser_t* parser); +node_t* parser_try_new_fundecl(parser_t* parser); +node_t* parser_try_new_params(parser_t* parser); +node_t* parser_try_new_return(parser_t* parser); node_t* parser_try_new_varset(parser_t* parser); node_t* parser_try_new_block(parser_t* parser); node_t* parser_try_new_scope(parser_t* parser); @@ -31,6 +34,9 @@ node_t* parser_try_new_factor(parser_t* parser); node_t* parser_try_new_power(parser_t* parser); node_t* parser_try_new_unary(parser_t* parser); node_t* parser_try_new_group(parser_t* parser); +node_t* parser_try_new_literal(parser_t* parser); +node_t* parser_try_new_funcall(parser_t* parser); +node_t* parser_try_new_args(parser_t* parser); node_t* parser_try_new_builtin(parser_t* parser); node_t* parser_try_new_consume(parser_t* parser, NodeType type); diff --git a/lib/prepass.c b/lib/prepass.c index 011dd63..567b5c9 100644 --- a/lib/prepass.c +++ b/lib/prepass.c @@ -1,18 +1,22 @@ #include "prepass.h" #include "lib/sym.h" +#include "lib/tysy.h" #include "node.h" void prepass_init(prepass_t* prepass, sym_t* sym, + tysy_t* tysy, tysolver_t* tysolver, err_t* err) { assert(prepass); assert(sym); + assert(tysy); assert(tysolver); assert(err); prepass->sym = sym; + prepass->tysy = tysy; prepass->tysolver = tysolver; prepass->err = err; @@ -45,7 +49,6 @@ void prepass_run(prepass_t* prepass, node_t* node) case NODE_VARDECL: { char* name = ((node_t*) node->children.data[0])->value.data; - node_t* block = node_try_find_parent(node, NODE_BLOCK); prepass_run(prepass, (node_t*) node->children.data[1]); @@ -54,10 +57,20 @@ void prepass_run(prepass_t* prepass, node_t* node) sym_declare(prepass->sym, name, type, prepass->scope, SYM_PRE, - block); + node); } break; + case NODE_FUNDECL: { + char* name = ((node_t*) node->children.data[0])->value.data; + + sym_declare(prepass->sym, name, + tysy_try_find_type(prepass->tysy, "fun"), + prepass->scope, + SYM_PRE, + node); + } break; + default: { for (size_t i=0; ichildren.size; i++) { diff --git a/lib/prepass.h b/lib/prepass.h index c4e588a..bd2516b 100644 --- a/lib/prepass.h +++ b/lib/prepass.h @@ -6,9 +6,11 @@ #include "node.h" #include "sym.h" #include "tysolver.h" +#include "tysy.h" typedef struct { sym_t* sym; + tysy_t* tysy; tysolver_t* tysolver; err_t* err; @@ -18,6 +20,7 @@ typedef struct { void prepass_init(prepass_t* prepass, sym_t* sym, + tysy_t* tysy, tysolver_t* tysolver, err_t* err); diff --git a/lib/program.c b/lib/program.c new file mode 100644 index 0000000..de08a74 --- /dev/null +++ b/lib/program.c @@ -0,0 +1,131 @@ +#include "program.h" +#include "value.h" + +void program_init(program_t* program) +{ + assert(program); + + program->size = 0; + program->cap = 0; + program->ops = NULL; + program->params = NULL; + + program->values.cap = 0; + program->values.size = 0; + program->values.data = NULL; +} + +void program_free(program_t* program) +{ + assert(program); + + for (size_t i=0; ivalues.size; i++) + { + value_free((value_t*) program->values.data[i]); + free(program->values.data[i]); + program->values.data[i] = NULL; + } + + free(program->values.data); + program->values.data = NULL; + program->values.size = 0; + program->values.cap = 0; + + free(program->ops); + free(program->params); + program->size = 0; + program->cap = 0; +} + +size_t program_push_instr(program_t* program, Opcode op, param_t param) +{ + assert(program); + + if (program->cap == 0) + { + program->cap = 2; + program->ops = malloc(sizeof(Opcode) * program->cap); + program->params = malloc(sizeof(param_t) * program->cap); + } + + if (program->size >= program->cap) + { + program->cap *= 2; + program->ops = realloc(program->ops, + sizeof(Opcode) * program->cap); + program->params = realloc(program->params, + sizeof(param_t) * program->cap); + } + + program->ops[program->size] = op; + program->params[program->size] = param; + program->size++; + + return program->size - 1; +} + +size_t program_push_new_value(program_t* program, struct value* value) +{ + assert(program); + assert(value); + + for (size_t i=0; ivalues.size; i++) + { + assert(program->values.data[i] != value); + } + + if (program->values.size == 0) + { + program->values.cap = 2; + program->values.data = malloc(sizeof(struct value*) + * program->values.cap); + } + + if (program->values.size >= program->values.cap) + { + program->values.cap *= 2; + program->values.data = realloc(program->values.data, + sizeof(struct value*) + * program->values.cap); + } + + program->values.data[program->values.size] = value; + + program->values.size++; + + return program->values.size - 1; +} + +size_t program_str(program_t* program, char* buffer, size_t size) +{ + size_t sz = 0; + + sz += snprintf(buffer + sz, size - sz, "======== VALUES ========\n"); + for (size_t i=0; ivalues.size; i++) + { + sz += snprintf(buffer + sz, size - sz, "%d| ", (int) i); + sz += value_str((value_t*) program->values.data[i], + buffer + sz, size - sz); + sz += snprintf(buffer + sz, size - sz, "\n"); + } + + sz += snprintf(buffer + sz, size - sz, "\n======== PROGRAM ========\n"); + for (size_t i=0; isize; i++) + { + if (program->params[i] != RZ_NO_PARAM) + { + sz += snprintf(buffer + sz, size - sz, "%d| %s %d\n", + (int) i, + OpcodeStr[program->ops[i]] + strlen("OP_"), + program->params[i]); + } + else + { + sz += snprintf(buffer + sz, size - sz, "%d| %s\n", + (int) i, + OpcodeStr[program->ops[i]] + strlen("OP_")); + } + } + + return sz; +} diff --git a/lib/program.h b/lib/program.h new file mode 100644 index 0000000..88ad1b2 --- /dev/null +++ b/lib/program.h @@ -0,0 +1,31 @@ +#ifndef RZ_PROGRAM_H +#define RZ_PROGRAM_H + +#include "commons.h" +#include "opcodes.h" + +struct value; + +typedef struct { + size_t size; + size_t cap; + Opcode* ops; + param_t* params; + + struct { + size_t size; + size_t cap; + struct value** data; + } values; + +} program_t; + +void program_init(program_t* program); +void program_free(program_t* program); + +size_t program_push_instr(program_t* program, Opcode op, param_t param); +size_t program_push_new_value(program_t* program, struct value* value); + +size_t program_str(program_t* program, char* buffer, size_t size); + +#endif diff --git a/lib/sym.c b/lib/sym.c index 4c358a8..deab2b9 100644 --- a/lib/sym.c +++ b/lib/sym.c @@ -1,4 +1,5 @@ #include "sym.h" +#include "lib/node.h" void sym_init(sym_t* sym, tysy_t* tysy, err_t* err) { @@ -30,7 +31,7 @@ void sym_free(sym_t* sym) } int sym_declare(sym_t* sym, char* name, type_t* type, - int scope, int state_flag, node_t* block) + int scope, int state_flag, node_t* node) { assert(sym); assert(name); @@ -39,8 +40,18 @@ int sym_declare(sym_t* sym, char* name, type_t* type, name, scope, state_flag, - block); - if (res && res->block == block) + node); + + node_t* block = node_try_find_parent(node, NODE_BLOCK); + + node_t* res_block; + + if (res) + { + res_block = node_try_find_parent(res->node, NODE_BLOCK); + } + + if (res && res_block == block) { return res->id; } @@ -69,7 +80,7 @@ int sym_declare(sym_t* sym, char* name, type_t* type, sym->entries.data[sym->entries.size]->type = type; sym->entries.data[sym->entries.size]->scope = scope; sym->entries.data[sym->entries.size]->state = state_flag; - sym->entries.data[sym->entries.size]->block = block; + sym->entries.data[sym->entries.size]->node = node; sym->entries.size++; @@ -78,7 +89,7 @@ int sym_declare(sym_t* sym, char* name, type_t* type, sym_entry_t* sym_try_find_by_name(sym_t* sym, char* name, int scope, int state_flag, - node_t* block) + node_t* node) { assert(sym); @@ -88,9 +99,10 @@ sym_entry_t* sym_try_find_by_name(sym_t* sym, char* name, { sym_entry_t* entry = sym->entries.data[i]; - node_t* itr = block; + node_t* itr = node_try_find_parent(node, NODE_BLOCK); + node_t* entry_block = node_try_find_parent(entry->node, NODE_BLOCK); - while (itr && itr != entry->block) + while (itr && itr != entry_block) { itr = (node_t*) itr->parent; } @@ -98,7 +110,7 @@ sym_entry_t* sym_try_find_by_name(sym_t* sym, char* name, if (strcmp(entry->name, name) == 0 && entry->scope == scope && (entry->state & state_flag) != 0 - && (entry->block == itr)) + && (entry_block == itr)) { res = entry; return res; @@ -107,7 +119,7 @@ sym_entry_t* sym_try_find_by_name(sym_t* sym, char* name, if (scope > 0) { - return sym_try_find_by_name(sym, name, scope - 1, state_flag, block); + return sym_try_find_by_name(sym, name, scope - 1, state_flag, node); } return NULL; diff --git a/lib/sym.h b/lib/sym.h index a1ee350..f7561a8 100644 --- a/lib/sym.h +++ b/lib/sym.h @@ -17,7 +17,7 @@ typedef struct { type_t* type; int scope; sym_state_t state; - node_t* block; + node_t* node; } sym_entry_t; typedef struct { @@ -37,11 +37,11 @@ void sym_free(sym_t* sym); int sym_declare(sym_t* sym, char* name, type_t* type, int scope, int state_flag, - node_t* block); + node_t* node); sym_entry_t* sym_try_find_by_name(sym_t* sym, char* name, int scope, int state_flag, - node_t* block); + node_t* node); size_t sym_str(sym_t* sym, char* buffer, size_t size); diff --git a/lib/type.h b/lib/type.h index fb6ec5c..f8958ac 100644 --- a/lib/type.h +++ b/lib/type.h @@ -4,7 +4,8 @@ #include "commons.h" #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) RZ_ENUM_H(TypeKind, TYPE_KIND); diff --git a/lib/tysolver.c b/lib/tysolver.c index 92c2c30..c168185 100644 --- a/lib/tysolver.c +++ b/lib/tysolver.c @@ -49,15 +49,13 @@ type_t* tysolver_try_solve_node(tysolver_t* tysolver, node_t* node) case NODE_IDENT: { char* name = node->value.data; - node_t* block = node_try_find_parent(node, NODE_BLOCK); + sym_entry_t* entry = sym_try_find_by_name(tysolver->sym, name, tysolver->scope, SYM_PRE | SYM_DECL, - block); - assert(entry); - - return entry->type; + node); + return entry ? entry->type : NULL; } break; case NODE_SUB: @@ -121,10 +119,17 @@ type_t* tysolver_try_solve_node(tysolver_t* tysolver, node_t* node) return ty; } break; - case NODE_IF: { + case NODE_IF: + case NODE_FUNCALL: { return NULL; } break; + case NODE_FUNDECL: { + type_t* ty = tysy_try_find_type(tysolver->tysy, "fun"); + assert(ty); + return ty; + } break; + default: { tysolver_error(tysolver, node); } break; diff --git a/lib/tysy.c b/lib/tysy.c index ebb44e6..dbadc04 100644 --- a/lib/tysy.c +++ b/lib/tysy.c @@ -25,6 +25,13 @@ void tysy_init(tysy_t* tysy) type_init(ty, TYPE_STR); tysy_register_new_type(tysy, "str", ty); } + + // fun + { + type_t* ty = malloc(sizeof(type_t)); + type_init(ty, TYPE_FUN); + tysy_register_new_type(tysy, "fun", ty); + } } void tysy_free(tysy_t* tysy) @@ -101,3 +108,14 @@ value_t* tysy_new_str(tysy_t* tysy, char* value, int line) return val; } + +value_t* tysy_new_fun(tysy_t* tysy, fun_t* fun, int line) +{ + assert(tysy); + + value_t* val = malloc(sizeof(value_t)); + value_init(val, tysy_try_find_type(tysy, "fun"), line); + val->value.fun = fun; + + return val; +} diff --git a/lib/tysy.h b/lib/tysy.h index c75a88b..cf69637 100644 --- a/lib/tysy.h +++ b/lib/tysy.h @@ -19,5 +19,6 @@ type_t* tysy_try_find_type(tysy_t* tysy, char* name); 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_str(tysy_t* tysy, char* value, int line); +value_t* tysy_new_fun(tysy_t* tysy, fun_t* fun, int line); #endif diff --git a/lib/value.c b/lib/value.c index e61eb82..a427fdc 100644 --- a/lib/value.c +++ b/lib/value.c @@ -1,4 +1,7 @@ #include "value.h" +#include "lib/commons.h" +#include "lib/type.h" +#include "program.h" void value_init(value_t* value, type_t* type, int line) { @@ -12,10 +15,19 @@ void value_init(value_t* value, type_t* type, int line) void value_free(value_t* value) { assert(value); + assert(value->type); if (value->type->kind == TYPE_STR) { free(value->value.str); + value->value.str = NULL; + } + + if (value->type->kind == TYPE_FUN) + { + fun_free(value->value.fun); + free(value->value.fun); + value->value.fun = NULL; } } @@ -40,6 +52,10 @@ int value_eq(value_t* value, value_t* rhs) return strcmp(value->value.str, rhs->value.str) == 0; } break; + case TYPE_FUN: { + return value->value.fun == rhs->value.fun; + } break; + default: { fprintf(stderr, "Cannot compare value of type '%s'.\n", TypeKindStr[value->type->kind]); @@ -69,6 +85,10 @@ size_t value_str(value_t* value, char* buffer, size_t size) return snprintf(buffer, size, "\"%s\"", value->value.str); break; + case TYPE_FUN: + return snprintf(buffer, size, "[fun]"); + break; + default: { fprintf(stderr, "Cannot stringify unknown value of type '%s'.\n", TypeKindStr[value->type->kind]); diff --git a/lib/value.h b/lib/value.h index 596da5e..ab8bc21 100644 --- a/lib/value.h +++ b/lib/value.h @@ -2,6 +2,9 @@ #define RZ_VALUE_H #include "type.h" +#include "fun.h" + +struct program; typedef struct { type_t* type; @@ -10,6 +13,7 @@ typedef struct { double num; int bool; char* str; + fun_t* fun; } value; int line; diff --git a/lib/vm.c b/lib/vm.c index df50b74..d9bb131 100644 --- a/lib/vm.c +++ b/lib/vm.c @@ -3,6 +3,8 @@ #include "lib/mod.h" #include "lib/type.h" #include "lib/tysy.h" +#include "program.h" +#include "value.h" void vm_init(vm_t* vm, sym_t* sym, tysy_t* tysy, err_t* err) { @@ -11,7 +13,7 @@ void vm_init(vm_t* vm, sym_t* sym, tysy_t* tysy, err_t* err) assert(tysy); vm->top_frame = NULL; - vm_frame_push(vm); + vm_frame_push(vm, NULL); vm->tysy = tysy; vm->err = err; @@ -25,6 +27,12 @@ void vm_free(vm_t* vm) { } + if (vm->top_frame) + { + vm_frame_free(vm->top_frame); + free(vm->top_frame); + } + vm->top_frame = NULL; } @@ -37,9 +45,14 @@ void vm_frame_init(frame_t* frame) frame->sp = 0; frame->prev = NULL; + frame->program = NULL; frame->locals.cap = 0; frame->locals.size = 0; frame->locals.data = NULL; + + frame->alloc.cap = 0; + frame->alloc.size = 0; + frame->alloc.data = NULL; } void vm_frame_free(frame_t* frame) @@ -54,6 +67,8 @@ void vm_frame_free(frame_t* frame) frame->locals.size = 0; frame->locals.cap = 0; + //vm_clear_alloc(frame); + if (frame->prev != NULL) { vm_frame_free((frame_t*) frame->prev); @@ -61,7 +76,7 @@ void vm_frame_free(frame_t* frame) } } -void vm_frame_push(vm_t* vm) +void vm_frame_push(vm_t* vm, program_t* program) { assert(vm); @@ -69,7 +84,7 @@ void vm_frame_push(vm_t* vm) vm_frame_init(frame); frame->prev = (struct frame*) vm->top_frame; - + frame->program = program; vm->top_frame = frame; } @@ -79,11 +94,19 @@ int vm_frame_pop(vm_t* vm) if (vm->top_frame) { - frame_t* frame = vm->top_frame; - vm->top_frame = (frame_t*) vm->top_frame->prev; + vm_clear_alloc(vm->top_frame); + } + + if (vm->top_frame && vm->top_frame->prev) + { + frame_t* prev = (frame_t*) vm->top_frame->prev; + vm->top_frame->prev = NULL; + + vm_frame_free(vm->top_frame); + free(vm->top_frame); + + vm->top_frame = prev; - vm_frame_free(frame); - free(frame); return 1; } @@ -141,32 +164,38 @@ void vm_local_store(vm_t* vm, int id, param_t addr) } } -void vm_push_new_value(vm_t* vm, mod_t* mod, value_t* value) +void vm_push_new(vm_t* vm, value_t* value) { - assert(vm); assert(value); + vm->top_frame->stack[vm->top_frame->sp] = value; - param_t param = mod_push_new_value(mod, value); - vm_push(vm, param); -} + vm_push_alloc(vm->top_frame, value); -void vm_push(vm_t* vm, param_t param) -{ - assert(vm); - assert(vm->top_frame->sp + 1 < RZ_STACK_LIMIT); - - vm->top_frame->stack[vm->top_frame->sp] = param; vm->top_frame->sp++; } -param_t vm_pop(vm_t* vm) +void vm_push(vm_t* vm, value_t* value) +{ + assert(value); + vm->top_frame->stack[vm->top_frame->sp] = value; + vm->top_frame->allocated[vm->top_frame->sp] = 0; + vm->top_frame->sp++; +} + +value_t* vm_pop(vm_t* vm) { assert(vm); - assert(vm->top_frame->sp > 0); - param_t param = vm->top_frame->stack[vm->top_frame->sp - 1]; + + if (vm->top_frame->sp == 0) + { + assert(0); + } + + value_t* val = vm->top_frame->stack[vm->top_frame->sp - 1]; + vm->top_frame->sp--; - return param; + return val; } size_t vm_stack_str(vm_t* vm, char* buffer, size_t size) @@ -184,7 +213,11 @@ size_t vm_stack_str(vm_t* vm, char* buffer, size_t size) for (size_t i=0; itop_frame->sp; i++) { - sz += snprintf(buffer + sz, size - sz, "| %d |\n", vm->top_frame->stack[vm->top_frame->sp - 1 - i]); + value_t* val = vm->top_frame->stack[vm->top_frame->sp - 1 - i]; + + sz += snprintf(buffer + sz, size - sz, "| "); + value_str(val, buffer + sz, size - sz); + sz += snprintf(buffer + sz, size - sz, " |"); } return sz; @@ -194,13 +227,15 @@ int vm_exec_mod(vm_t* vm, mod_t* mod) { assert(vm); vm->top_frame->pc = 0; + vm->top_frame->program = &mod->program; - while (vm->top_frame->pc < mod->program.size) + while (vm->top_frame->pc < vm->top_frame->program->size) { + program_t* program = vm->top_frame->program; + int status = vm_exec_instr(vm, - mod, - mod->program.ops[vm->top_frame->pc], - mod->program.params[vm->top_frame->pc]); + program->ops[vm->top_frame->pc], + program->params[vm->top_frame->pc]); if (status != 0) { @@ -211,7 +246,7 @@ int vm_exec_mod(vm_t* vm, mod_t* mod) return 0; } -int vm_exec_instr(vm_t* vm, mod_t* mod, Opcode op, param_t param) +int vm_exec_instr(vm_t* vm, Opcode op, param_t param) { assert(vm); @@ -224,14 +259,13 @@ int vm_exec_instr(vm_t* vm, mod_t* mod, Opcode op, param_t param) abort(); } - vm->top_frame->stack[vm->top_frame->sp] = param; - vm->top_frame->sp++; + value_t* val = (value_t*) vm->top_frame->program->values.data[param]; + vm_push(vm, val); vm->top_frame->pc++; } break; case OP_ASSERT: { - param_t top = vm_pop(vm); - value_t* value = mod->values.data[top]; + value_t* value = vm_pop(vm); if (value->type->kind != TYPE_BOOL) { @@ -248,20 +282,15 @@ int vm_exec_instr(vm_t* vm, mod_t* mod, Opcode op, param_t param) return -1; } - vm_push(vm, top); + vm_push(vm, value); vm->top_frame->pc++; } break; case OP_NE: case OP_EQ: { - int l = vm_pop(vm); - int r = vm_pop(vm); - assert(l != -1); - assert(r != -1); - - value_t* rhs = mod->values.data[l]; - value_t* lhs = mod->values.data[r]; + value_t* rhs = vm_pop(vm); + value_t* lhs = vm_pop(vm); int same_type = lhs->type->kind == rhs->type->kind; int eq = value_eq(lhs, rhs); @@ -272,20 +301,17 @@ int vm_exec_instr(vm_t* vm, mod_t* mod, Opcode op, param_t param) : (!same_type || !eq)), rhs->line); - vm_push_new_value(vm, mod, res); + vm_push_new(vm, res); vm->top_frame->pc++; } break; - case OP_LT: + case OP_LT: case OP_LE: case OP_GT: case OP_GE: { - int r = vm_pop(vm); - int l = vm_pop(vm); - - value_t* lhs = mod->values.data[l]; - value_t* rhs = mod->values.data[r]; + value_t* rhs = vm_pop(vm); + value_t* lhs = vm_pop(vm); vm_ensure_type(vm, lhs, TYPE_NUM); vm_ensure_type(vm, rhs, TYPE_NUM); @@ -302,7 +328,7 @@ int vm_exec_instr(vm_t* vm, mod_t* mod, Opcode op, param_t param) } value_t* res = tysy_new_bool(vm->tysy, val, lhs->line); - vm_push_new_value(vm, mod, res); + vm_push_new(vm, res); vm->top_frame->pc++; } break; @@ -313,11 +339,8 @@ int vm_exec_instr(vm_t* vm, mod_t* mod, Opcode op, param_t param) case OP_DIV: case OP_MODULO: case OP_POW: { - int r = vm_pop(vm); - int l = vm_pop(vm); - - value_t* lhs = mod->values.data[l]; - value_t* rhs = mod->values.data[r]; + value_t* rhs = vm_pop(vm); + value_t* lhs = vm_pop(vm); vm_ensure_type(vm, lhs, TYPE_NUM); vm_ensure_type(vm, rhs, TYPE_NUM); @@ -336,17 +359,14 @@ int vm_exec_instr(vm_t* vm, mod_t* mod, Opcode op, param_t param) } value_t* res = tysy_new_num(vm->tysy, val, lhs->line); - vm_push_new_value(vm, mod, res); + vm_push_new(vm, res); vm->top_frame->pc++; } break; case OP_STRCAT: { - int r = vm_pop(vm); - int l = vm_pop(vm); - - value_t* lhs = mod->values.data[l]; - value_t* rhs = mod->values.data[r]; + value_t* rhs = vm_pop(vm); + value_t* lhs = vm_pop(vm); vm_ensure_type(vm, lhs, TYPE_STR); vm_ensure_type(vm, rhs, TYPE_STR); @@ -359,17 +379,14 @@ int vm_exec_instr(vm_t* vm, mod_t* mod, Opcode op, param_t param) value_t* value = tysy_new_str(vm->tysy, res.data, lhs->line); str_free(&res); - vm_push_new_value(vm, mod, value); + vm_push_new(vm, value); vm->top_frame->pc++; } break; case OP_STRDUP: { - int r = vm_pop(vm); - int l = vm_pop(vm); - - value_t* lhs = mod->values.data[l]; - value_t* rhs = mod->values.data[r]; + value_t* rhs = vm_pop(vm); + value_t* lhs = vm_pop(vm); if (lhs->type->kind != TYPE_NUM) { @@ -392,43 +409,40 @@ int vm_exec_instr(vm_t* vm, mod_t* mod, Opcode op, param_t param) value_t* value = tysy_new_str(vm->tysy, res.data, lhs->line); str_free(&res); - vm_push_new_value(vm, mod, value); + vm_push_new(vm, value); vm->top_frame->pc++; } break; case OP_USUB: { - int l = vm_pop(vm); - - value_t* lhs = mod->values.data[l]; + value_t* lhs = vm_pop(vm); vm_ensure_type(vm, lhs, TYPE_NUM); double val = -lhs->value.num; value_t* res = tysy_new_num(vm->tysy, val, lhs->line); - vm_push_new_value(vm, mod, res); + vm_push_new(vm, res); vm->top_frame->pc++; } break; case OP_NOT: { - int l = vm_pop(vm); - value_t* lhs = mod->values.data[l]; + value_t* lhs = vm_pop(vm); vm_ensure_type(vm, lhs, TYPE_BOOL); int val = !lhs->value.bool; value_t* res = tysy_new_bool(vm->tysy, val, lhs->line); - vm_push_new_value(vm, mod, res); + vm_push_new(vm, res); vm->top_frame->pc++; } break; case OP_BRT: case OP_BRF: { - param_t p = vm_pop(vm); - value_t* value = mod->values.data[p]; + value_t* value = vm_pop(vm); + vm_ensure_type(vm, value, TYPE_BOOL); if (op == OP_BRT && value->value.bool) @@ -460,11 +474,21 @@ int vm_exec_instr(vm_t* vm, mod_t* mod, Opcode op, param_t param) snprintf(msg, RZ_STR_LIMIT, "Cannot load local variable '%d'.", param); - param_t p = vm->top_frame->stack[vm->top_frame->sp - 1]; - int line = mod->values.data[p]->line; + if (vm->top_frame->sp == 0) + { + err_fatal(vm->err, msg, -1); + err_dump(vm->err); + abort(); + } + else + { + value_t* val = vm->top_frame->stack[vm->top_frame->sp - 1]; + int line = val->line; - err_fatal(vm->err, msg, line); - err_dump(vm->err); + err_fatal(vm->err, msg, line); + err_dump(vm->err); + abort(); + } } else { @@ -480,6 +504,52 @@ int vm_exec_instr(vm_t* vm, mod_t* mod, Opcode op, param_t param) vm->top_frame->pc++; } break; + case OP_CALL: { + size_t const ARG_SZ = param; + value_t* args[ARG_SZ]; + + fun_t* fun = vm_pop(vm)->value.fun; + + for (size_t i=0; itop_frame->pc++; + vm_frame_push(vm, &fun->program); + + for (size_t i=0; itop_frame->sp - 1); + } + + } break; + + case OP_RET: { + + frame_t* frame = (frame_t*) vm->top_frame; + frame_t* prev = (frame_t*) vm->top_frame->prev; + + value_t* ret = frame->stack[frame->sp - 1]; + prev->stack[prev->sp] = ret; + prev->sp++; + + for (size_t i=0; ialloc.size; i++) + { + if (frame->alloc.data[i] == ret) + { + frame->alloc.data[i] = NULL; + vm_push_alloc(prev, ret); + } + } + + vm_frame_pop(vm); + } break; + default: { fprintf(stderr, "Cannot execute unknown opcode '%s'.\n", OpcodeStr[op]); @@ -494,6 +564,7 @@ void vm_ensure_type(vm_t* vm, value_t* value, TypeKind want) { assert(vm); assert(value); + TypeKind got = value->type->kind; int line = value->line; @@ -509,3 +580,43 @@ void vm_ensure_type(vm_t* vm, value_t* value, TypeKind want) err_dump(vm->err); } } + +void vm_push_alloc(frame_t* frame, value_t* value) +{ + assert(frame); + assert(value); + + if (frame->alloc.cap == 0) + { + frame->alloc.cap = 2; + frame->alloc.data = malloc(sizeof(value_t*) * frame->alloc.cap); + } + + if (frame->alloc.size >= frame->alloc.cap) + { + frame->alloc.cap *= 2; + frame->alloc.data = realloc(frame->alloc.data, + sizeof(value_t*) * frame->alloc.cap); + } + + frame->alloc.data[frame->alloc.size] = value; + frame->alloc.size++; +} + +void vm_clear_alloc(frame_t* frame) +{ + assert(frame); + for (size_t i=0; ialloc.size; i++) + { + value_t* val = frame->alloc.data[i]; + + if (val) + { + value_free(val); + free(val); + } + } + + free(frame->alloc.data); + frame->alloc.data = NULL; +} diff --git a/lib/vm.h b/lib/vm.h index 545702a..966def2 100644 --- a/lib/vm.h +++ b/lib/vm.h @@ -7,6 +7,7 @@ #include "err.h" #include "tysy.h" #include "sym.h" +#include "program.h" typedef struct { int id; @@ -15,8 +16,9 @@ typedef struct { typedef struct stack_frame{ struct frame* prev; - - param_t stack[RZ_STACK_LIMIT]; + program_t* program; + value_t* stack[RZ_STACK_LIMIT]; + int allocated[RZ_STACK_LIMIT]; size_t pc; size_t bp; size_t sp; @@ -26,6 +28,13 @@ typedef struct stack_frame{ size_t cap; local_t** data; } locals; + + struct { + size_t size; + size_t cap; + value_t** data; + } alloc; + } frame_t; typedef struct { @@ -41,20 +50,23 @@ void vm_free(vm_t* vm); void vm_frame_init(frame_t* frame); void vm_frame_free(frame_t* frame); -void vm_frame_push(vm_t* vm); +void vm_frame_push(vm_t* vm, program_t* program); 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_value(vm_t* vm, mod_t* mod, value_t* value); -void vm_push(vm_t* vm, param_t param); -param_t vm_pop(vm_t* vm); +void vm_push_new(vm_t* vm, value_t* value); +void vm_push(vm_t* vm, value_t* value); +value_t* vm_pop(vm_t* vm); size_t vm_stack_str(vm_t* vm, char* buffer, size_t size); int vm_exec_mod(vm_t* vm, mod_t* mod); -int vm_exec_instr(vm_t* vm, mod_t* mod, Opcode op, param_t param); +int vm_exec_instr(vm_t* vm, Opcode op, param_t param); void vm_ensure_type(vm_t* vm, value_t* value, TypeKind want); +void vm_push_alloc(frame_t* frame, value_t* value); +void vm_clear_alloc(frame_t* frame); + #endif diff --git a/meson.build b/meson.build index 4832a1e..68584a4 100644 --- a/meson.build +++ b/meson.build @@ -36,8 +36,12 @@ roza_lib = static_library( 'lib/tysy.c', 'lib/tysolver.c', + # types + 'lib/fun.c', + # comp 'lib/opcodes.c', + 'lib/program.c', 'lib/mod.c', 'lib/prepass.c', 'lib/compiler.c', diff --git a/tests/acceptances/fun.roza b/tests/acceptances/fun.roza new file mode 100644 index 0000000..d16b9db --- /dev/null +++ b/tests/acceptances/fun.roza @@ -0,0 +1,37 @@ +# FUNCTIONS +# ========= + +fun double(n) + n * 2 +end + +assert double(4) == 8 +assert 8 == double(4) + +assert double(4) != 10 +assert 9 != double(4) + +assert double(double(double(3))) == 24 + +fun a() + return 45 +end + +assert a() == 45 + +fun b() + return 27 + return 32 +end + +assert b() == 27 + +fun max(m, n) + if m > n then + return m + end + return n +end + +assert max(7, 3) == 7 +assert max(7, 9) == 9 diff --git a/tests/units/lexer.c b/tests/units/lexer.c index 70fe2a2..022ce8e 100644 --- a/tests/units/lexer.c +++ b/tests/units/lexer.c @@ -163,3 +163,10 @@ Test(lexer, blocks) { "THEN", "ELSE"); } + +Test(lexer, fun) { + test_lexer("fun return,", 3, + "FUN", + "RETURN", + "COMMA"); +} diff --git a/tests/units/parser.c b/tests/units/parser.c index e09847f..e509e43 100644 --- a/tests/units/parser.c +++ b/tests/units/parser.c @@ -139,3 +139,32 @@ Test(parser, if_then_else) { "IF(IDENT[z],BLOCK(IDENT[u]),BLOCK(IDENT[v]))))", "if x then y else if z then u else v end"); } + +Test(parser, fun_decl) { + test_parser_ok("MOD(FUNDECL(IDENT[f]," + "PARAMS(IDENT[x])," + "BLOCK(RETURN(IDENT[x]))))", + "fun f(x) return x end"); + + test_parser_ok("MOD(FUNDECL(IDENT[f]," + "PARAMS(IDENT[x],IDENT[y])," + "BLOCK(RETURN(IDENT[x]))))", + "fun f(x, y) return x end"); +} + +Test(parser, fun_call) { + test_parser_ok("MOD(FUNCALL(IDENT[hello],ARGS(" + "NUM[1],BOOL[true],BOOL[false]" + ")))", + "hello(1, true, false)"); + + test_parser_ok("MOD(FUNCALL(IDENT[hello],ARGS(NUM[1])))", + "hello(1)"); + + test_parser_ok("MOD(FUNCALL(IDENT[hello],ARGS))", + "hello()"); + + test_parser_ok("MOD(ASSERT(EQ(FUNCALL(IDENT[hello],ARGS),NUM[1])))", + "assert hello() == 1"); + +}