Compare commits

..

2 Commits

Author SHA1 Message Date
bog 968f7a312d recursive functions. 2023-12-20 21:43:48 +01:00
bog e786b8f756 basic functions 2023-12-20 20:54:58 +01:00
31 changed files with 946 additions and 305 deletions

View File

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

View File

@ -1,10 +1,14 @@
#include "compiler.h"
#include "lib/commons.h"
#include "lib/mod.h"
#include "lib/prepass.h"
#include "lib/program.h"
#include "lib/sym.h"
#include "lib/tysy.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 +18,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 +30,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 +40,7 @@ int compiler_run(compiler_t* compiler, node_t* node)
case NODE_MOD: {
for (size_t i=0; i<node->children.size; i++)
{
compiler_run(compiler, (node_t*) node->children.data[i]);
compiler_run(compiler, (node_t*) node->children.data[i], program);
}
} break;
@ -45,9 +48,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 +59,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 +87,11 @@ int compiler_run(compiler_t* compiler, node_t* node)
for (size_t i=0; i<node->children.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 +102,7 @@ int compiler_run(compiler_t* compiler, node_t* node)
for (size_t i=0; i<node->children.size; i++)
{
compiler_run(compiler, node_child(node, i));
compiler_run(compiler, node_child(node, i), program);
}
Opcode op;
@ -109,7 +115,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 +127,7 @@ int compiler_run(compiler_t* compiler, node_t* node)
case NODE_POW: {
for (size_t i=0; i<node->children.size; i++)
{
compiler_run(compiler, node_child(node, i));
compiler_run(compiler, node_child(node, i), program);
}
Opcode op;
@ -156,7 +162,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 +173,29 @@ int compiler_run(compiler_t* compiler, node_t* node)
for (size_t i=0; i<node->children.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; i<sz; i++)
{
compiler->mod->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 +206,81 @@ int compiler_run(compiler_t* compiler, node_t* node)
for (size_t i=0; i<node->children.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; i<sz; i++)
{
compiler->mod->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 +293,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 +317,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; i<node->children.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 +341,112 @@ 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; i<size; i++)
{
compiler->mod->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);
value_t* value = tysy_new_fun(compiler->tysy, fun, node->line);
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]);
// self
sym_declare((sym_t*) fun->sym, fun_name,
tysy_try_find_type(comp.tysy, "fun"),
comp.scope,
SYM_DECL,
node);
compiler_run(&comp, (node_t*) node->children.data[1], &fun->program);
compiler_run(&comp, (node_t*) node->children.data[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; i<node->children.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; i<args->children.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 +461,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 +487,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);
}
}
}

View File

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

19
lib/fun.c Normal file
View File

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

20
lib/fun.h Normal file
View File

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

View File

@ -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 == ','
;
}

View File

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

106
lib/mod.c
View File

@ -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; i<mod->values.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; i<mod->values.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; i<mod->program.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);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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; i<node->children.size; i++)
{

View File

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

131
lib/program.c Normal file
View File

@ -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; i<program->values.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; i<program->values.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; i<program->values.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; i<program->size; 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;
}

31
lib/program.h Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

271
lib/vm.c
View File

@ -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; i<vm->top_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,54 @@ 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 + 1;
value_t* args[ARG_SZ];
for (size_t i=0; i<ARG_SZ; i++)
{
value_t* val = vm_pop(vm);
args[ARG_SZ - 1 - i] = val;
}
value_t* fun_val = args[ARG_SZ - 1];
assert(fun_val->type->kind == TYPE_FUN);
fun_t* fun = fun_val->value.fun;
vm->top_frame->pc++;
vm_frame_push(vm, &fun->program);
for (size_t i=0; i<ARG_SZ; i++)
{
value_t* arg = args[i];
vm_push(vm, arg);
vm_local_store(vm, ARG_SZ - 1 - i, vm->top_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; i<frame->alloc.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 +566,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 +582,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; i<frame->alloc.size; i++)
{
value_t* val = frame->alloc.data[i];
if (val)
{
value_free(val);
free(val);
}
}
free(frame->alloc.data);
frame->alloc.data = NULL;
}

View File

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

View File

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

View File

@ -0,0 +1,60 @@
# 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
# RECURSIVITY
# ===========
fun fac(n)
if n == 0 then
return 1
end
return n * fac(n - 1)
end
assert fac(5) == 120
fun fib(n)
if n == 0 or n == 1 then
return 1
end
return fib(n - 2) + fib(n - 1)
end
assert fib(6) == 13

View File

@ -163,3 +163,10 @@ Test(lexer, blocks) {
"THEN",
"ELSE");
}
Test(lexer, fun) {
test_lexer("fun return,", 3,
"FUN",
"RETURN",
"COMMA");
}

View File

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