ADD: simple functions.

main
bog 2023-08-28 13:07:19 +02:00
parent 84b0af8090
commit 9ab09e85f6
27 changed files with 1178 additions and 201 deletions

View File

@ -51,6 +51,7 @@ executable(
'src/vm.c',
'src/symtable.c',
'src/fun.c',
],
dependencies: [
m_dep

View File

@ -341,9 +341,139 @@ void compile_node(compiler* self, node* root, program* prog)
compile_number(self, root, prog, OP_IADD, OP_FADD);
}
}
else if (root->type == NODE_FUN)
{
// init body
compiler comp;
compiler_init(&comp);
program* fun_prog = malloc(sizeof(program));
program_init(fun_prog);
node* block = root->children.data[root->children.size - 1];
// add params
for (size_t i=0; i<root->children.size; i++)
{
node* param = root->children.data[i];
if (param->type == NODE_FUN_PARAM)
{
char const* param_name = param->children.data[0]->value;
type* param_ty =
type_new_from_node(param->children.data[1]);
symtable_declare(comp.sym, param_name
, param_ty
, param->children.data[0]);
type_free(param_ty); free(param_ty);
}
}
// compile body
compile_node(&comp, block, fun_prog);
compiler_free(&comp);
// init fun object
cstatic cs;
cstatic_init(&cs);
fun* fn = malloc(sizeof(fun));
type* ty = cstatic_resolve_new(&cs, self->sym, root);
fun_init(fn, ty, (struct program*) fun_prog);
program_free(fun_prog); free(fun_prog); fun_prog = NULL;
type_free(ty); free(ty);
// create value
value* val = malloc(sizeof(value));
value_init_fun(val, fn, root->lineno);
// push it
program_add_instr(
prog,
OP_PUSH,
program_add_pool(prog, val)
);
value_free(val); free(val);
fun_free(fn); free(fn);
cstatic_free(&cs);
}
else if (root->type == NODE_CALL)
{
//{char c[512]; node_str(root, c, 512); printf("%s\n", c);}
char const* fun_name = root->children.data[0]->value;
node* args = root->children.data[1];
symentry* entry = symtable_find(self->sym, fun_name);
assert(entry);
program_add_instr(prog, OP_LOAD, entry->id);
for (size_t i=0; i<args->children.size; i++)
{
node* arg = args->children.data[i];
compile_node(self, arg, prog);
}
program_add_instr(prog, OP_CALL, args->children.size);
}
else if (root->type == NODE_RETURN)
{
compile_children(self, root, prog);
program_add_instr(prog, OP_RET, NO_PARAM);
}
else if (root->type == NODE_FUN_TYPE)
{
type* ty = malloc(sizeof(type));
type_init(ty, TY_FUNCTION);
node* lhs = root->children.data[0];
size_t lhs_sz = lhs->children.size;
for (size_t i=0; i<lhs_sz; i++)
{
type* sub = type_new_from_node(
lhs->children.data[lhs_sz - 1 - i]);
type_add_sub_type(ty, sub);
type_free(sub); free(sub);
}
if (root->children.data[1]->children.size > 0)
{
node* rhs = root->children.data[1];
size_t rhs_sz = rhs->children.size;
for (size_t i=0; i<rhs_sz; i++)
{
type* sub = type_new_from_node(
rhs->children.data[rhs_sz - 1 - i]);
sub->kind = KIND_RETURN;
type_add_sub_type(ty, sub);
type_free(sub); free(sub);
}
}
value val;
value_init_type(&val,
ty,
root->lineno);
size_t idx = program_add_pool(prog, &val);
program_add_instr(prog, OP_PUSH, idx);
type_free(ty);
free(ty);
value_free(&val);
}
else if (root->type == NODE_TYPE)
{
type* ty = compile_get_type(self, root);
type* ty = type_new_from_node(root);
value val;
value_init_type(&val,
@ -572,71 +702,6 @@ void compile_children(compiler* self, node* root, program* prog)
}
}
type* compile_get_type(compiler* self, node* root)
{
assert(self);
assert(root);
type* ty = malloc(sizeof(type));
if (strcmp(root->value, "int") == 0)
{
type_init(ty, TY_INTEGER);
}
else if (strcmp(root->value, "float") == 0)
{
type_init(ty, TY_FLOAT);
}
else if (strcmp(root->value, "str") == 0)
{
type_init(ty, TY_STRING);
}
else if (strcmp(root->value, "bool") == 0)
{
type_init(ty, TY_BOOLEAN);
}
else if (strcmp(root->value, "type") == 0)
{
type_init(ty, TY_TYPE);
}
else if (strcmp(root->value, "array") == 0)
{
type_init(ty, TY_ARRAY);
ty->kind = KIND_SEQUENTIAL;
}
else if (root->type == NODE_ADD)
{
type_init(ty, TY_TYPE);
ty->kind = KIND_DISJUNCTION;
}
else if (root->type == NODE_MUL)
{
type_init(ty, TY_TYPE);
ty->kind = KIND_CONJUNCTION;
}
else
{
fprintf(stderr,
"E(%d): cannot compile unknown type '%s'.\n",
root->lineno,
NodeTypeStr[root->type]);
}
for (size_t i=0; i<root->children.size; i++)
{
type* sub = compile_get_type(self, root->children.data[i]);
type_add_sub_type(ty, sub);
type_free(sub);
free(sub);
}
return ty;
}
void compile_if(compiler* self, node* root, program* prog)
{
if (root->children.size == 1)

View File

@ -30,8 +30,6 @@ void compiler_pop_info(compiler* self);
void compile_node(compiler* self, node* root, program* prog);
void compile_children(compiler* self, node* root, program* prog);
type* compile_get_type(compiler* self, node* root);
void compile_number(compiler* self, node* root, program* prog,
int integer_op,
int float_op);

View File

@ -4,11 +4,26 @@
void cstatic_init(cstatic* self)
{
assert(self);
self->fun_types.size = 0;
self->fun_types.capacity = 1;
self->fun_types.data = malloc(sizeof(type*) * self->fun_types.capacity);
}
void cstatic_free(cstatic* self)
{
assert(self);
for (size_t i=0; i<self->fun_types.size; i++)
{
type_free(self->fun_types.data[i]);
free(self->fun_types.data[i]);
}
free(self->fun_types.data);
self->fun_types.size = 0;
self->fun_types.capacity = 0;
self->fun_types.data = NULL;
}
type* cstatic_new_type(cstatic* self, int base_type)
@ -35,10 +50,96 @@ type* cstatic_resolve_new(cstatic* self, symtable* sym, node* ast)
assert(self);
assert(ast);
if (ast->type == NODE_FUN)
{
type* ty = cstatic_new_type(self, TY_FUNCTION);
size_t i = 0;
while (i < ast->children.size
&& ast->children.data[i]->type == NODE_FUN_PARAM)
{
type* param_ty =
type_new_from_node(
ast->children.data[i]->children.data[1]
);
type_add_sub_type(ty, param_ty);
type_free(param_ty); free(param_ty);
i++;
}
if (i < ast->children.size
&& ast->children.data[i]->type == NODE_FUN_RET)
{
node* ret = ast->children.data[i];
for (size_t i=0; i<ret->children.size; i++)
{
type* r = type_new_from_node(ret->children.data[i]);
r->kind = KIND_RETURN;
type_add_sub_type(ty, r);
type_free(r); free(r);
}
}
return ty;
}
if (ast->type == NODE_CALL)
{
char const* fun_name = ast->children.data[0]->value;
symentry* entry = symtable_find(sym, fun_name);
assert(entry);
type* fun_type = entry->ty;
assert(fun_type);
size_t ret_count = fun_type->sub_types.size;
if (ret_count > 0)
{
type* ret_type = fun_type->sub_types.data[ret_count - 1];
assert(ret_type);
if (ret_type->kind == KIND_RETURN)
{
type* res = type_new_clone(ret_type);
res->kind = KIND_CONJUNCTION;
return res;
}
}
return NULL;
}
if (ast->type == NODE_RETURN)
{
return cstatic_resolve_new(self, sym, ast->children.data[0]);
}
if (ast->type == NODE_IF)
{
type* ty = cstatic_resolve_new(self,
sym,
ast->children.data[1]);
return ty;
}
if (ast->type == NODE_DO)
{
type* ty = cstatic_resolve_new(self,
sym,
ast->children.data[0]);
return ty;
}
if (ast->type == NODE_IDENT)
{
symentry* entry = symtable_find(sym,
ast->value);
assert(entry);
type* ty = type_new_clone(entry->ty);
return ty;
}
@ -184,7 +285,8 @@ type* cstatic_resolve_new(cstatic* self, symtable* sym, node* ast)
return cstatic_new_type(self, TY_STRING);
}
else if (ast->type == NODE_TYPE)
else if (ast->type == NODE_TYPE
|| ast->type == NODE_FUN_TYPE)
{
return cstatic_new_type(self, TY_TYPE);
}
@ -250,7 +352,7 @@ int cstatic_check(cstatic* self, node* ast, symtable* sym, char* msg, size_t siz
if (!status)
{
return -1;
return 0;
}
}
@ -259,6 +361,157 @@ int cstatic_check(cstatic* self, node* ast, symtable* sym, char* msg, size_t siz
return 1;
}
// Function Stuff
if (ast->type == NODE_FUN)
{
type* ty = cstatic_resolve_new(self, sym, ast);
cstatic_push_fun(self, ty);
type_free(ty); free(ty);
symtable* inner_table = symtable_new_clone(sym);
// function args
for (size_t i=0; i<ast->children.size; i++)
{
node* child = ast->children.data[i];
if (child->type == NODE_FUN_PARAM)
{
char const* name = child->children.data[0]->value;
type* t = type_new_from_node(child->children.data[1]);
symtable_declare_mut(inner_table, name, t, child);
type_free(t); free(t);
}
}
int status = cstatic_check(self,
ast->children.data[ast->children.size - 1],
inner_table,
msg,
size
);
symtable_free(inner_table); free(inner_table);
cstatic_pop_fun(self);
return status;
}
// Function Stuff
if (ast->type == NODE_RETURN)
{
type* ret_ty = cstatic_resolve_new(self, sym, ast);
type* fun_ty = cstatic_top_fun(self);
type* fun_res = NULL;
for (size_t i=0; i<fun_ty->sub_types.size; i++)
{
if (fun_ty->sub_types.data[i]->kind == KIND_RETURN)
{
fun_res = type_new_clone(fun_ty->sub_types.data[i]);
fun_res->kind = KIND_CONJUNCTION;
break;
}
}
assert(fun_res);
int status = cstatic_check_same_type_ptr(
self,
ast,
fun_res,
ret_ty,
sym,
msg,
size
);
if (status)
{
if (fun_res)
{
type_free(fun_res); free(fun_res);
}
type_free(ret_ty); free(ret_ty);
}
return status;
}
if (ast->type == NODE_CALL)
{
char const* fun_name = ast->children.data[0]->value;
symentry* entry = symtable_find(sym, fun_name);
assert(entry);
type* fun_type = entry->ty;
node* args = ast->children.data[1];
size_t arity = 0;
for (size_t i=0; i<fun_type->sub_types.size; i++)
{
type* ty = fun_type->sub_types.data[i];
if (ty->kind != KIND_RETURN)
{
arity++;
}
}
if (arity != args->children.size)
{
snprintf(msg, size, "E(%d): function arity mismatch: "
"expected '%ld', got '%ld'.\n",
args->lineno,
arity,
args->children.size
);
return 0;
}
for (size_t i=0; i<args->children.size; i++)
{
type* sub = type_new_clone(fun_type->sub_types.data[i]);
assert(sub);
type* arg_type = cstatic_resolve_new(
self,
sym,
args->children.data[i]
);
int status = cstatic_check_same_type_ptr(
self,
args->children.data[i],
sub,
arg_type,
sym,
msg,
size
);
if (!status)
{
return 0;
}
type_free(sub); free(sub);
type_free(arg_type); free(arg_type);
}
return 1;
}
// Children
for (size_t i=0; i<ast->children.size; i++)
{
@ -914,3 +1167,38 @@ int cstatic_check_same_type(cstatic* self, node* lhs, node* rhs, symtable* sym,
return 1;
}
void cstatic_push_fun(cstatic* self, type* fun_ty)
{
assert(self);
assert(fun_ty);
if (self->fun_types.size >= self->fun_types.capacity)
{
self->fun_types.capacity *= 2;
self->fun_types.data = realloc(
self->fun_types.data,
sizeof(type*) * self->fun_types.capacity
);
}
self->fun_types.data[self->fun_types.size] = type_new_clone(fun_ty);
self->fun_types.size++;
}
void cstatic_pop_fun(cstatic* self)
{
assert(self->fun_types.size > 0);
type_free(self->fun_types.data[self->fun_types.size - 1]);
free(self->fun_types.data[self->fun_types.size - 1]);
self->fun_types.size--;
}
type* cstatic_top_fun(cstatic* self)
{
assert(self->fun_types.size > 0);
return self->fun_types.data[self->fun_types.size - 1];
}

View File

@ -8,7 +8,11 @@
#define TYPE_END (-1)
typedef struct {
int _unused;
struct {
size_t size;
size_t capacity;
type** data;
} fun_types;
} cstatic;
void cstatic_init(cstatic* self);
@ -33,4 +37,7 @@ int cstatic_check_same_type_ptr(cstatic* self,
int cstatic_check_same_type(cstatic* self, node* lhs, node* rhs, symtable* sym,
char* msg, size_t size);
void cstatic_push_fun(cstatic* self, type* fun_ty);
void cstatic_pop_fun(cstatic* self);
type* cstatic_top_fun(cstatic* self);
#endif

46
src/fun.c Normal file
View File

@ -0,0 +1,46 @@
#include "fun.h"
#include "program.h"
void fun_init(fun* self, type* ty, struct program* prog)
{
assert(self);
self->ty = type_new_clone(ty);
self->prog = program_new_clone(prog);
}
void fun_free(fun* self)
{
assert(self);
type_free(self->ty); free(self->ty);
program_free(self->prog);
free(self->prog);
self->prog = NULL;
}
fun* fun_new_clone(fun* self)
{
assert(self);
fun* clone = malloc(sizeof(fun));
fun_init(clone, self->ty, self->prog);
return clone;
}
size_t fun_str(fun* self, char* buffer, size_t size)
{
assert(self);
assert(buffer);
size_t sz = 0;
sz += snprintf(buffer + sz, size - sz, "function");
return sz;
}
int fun_equals(fun* self, fun* lhs)
{
assert(self);
assert(lhs);
return 0; // TODO to impl
}

21
src/fun.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef FUN_H
#define FUN_H
#include "commons.h"
#include "type.h"
struct program;
typedef struct {
type* ty;
struct program* prog;
} fun;
void fun_init(fun* self, type* ty, struct program* prog);
void fun_free(fun* self);
fun* fun_new_clone(fun* self);
size_t fun_str(fun* self, char* buffer, size_t size);
int fun_equals(fun* self, fun* lhs);
#endif

View File

@ -1,4 +1,5 @@
%{
#include "parser.h"
#include "src/utils.h"
int line = 1;
@ -14,10 +15,12 @@ INTEGER -?[0-9]+
FLOAT -?[0-9]+\.[0-9]+
STRING \"[^"]*\"
TYPE (int|float|bool|str|array|type)
IDENT [_A-Za-z][_A-Za-z0-9]*
IDENT [_A-Za-z][_A-Za-z0-9]*
SEP [\n]|[;]
%%
{COMMENT} {}
{SEP} { line++; return SEP; }
"\n" { line++; }
{WHITESPACES} {}
@ -26,6 +29,9 @@ IDENT [_A-Za-z][_A-Za-z0-9]*
return TYPE;
}
"fun" { return FUN; }
"as" { return AS; }
"return" { return RETURN; }
"while" { return WHILE; }
"break" { return BREAK; }
"continue" { return CONTINUE; }
@ -42,6 +48,7 @@ IDENT [_A-Za-z][_A-Za-z0-9]*
"<" { return LT; }
">" { return GT; }
"," { return COMMA; }
":" { return COLON; }
"+" { return ADD; }
"-" { return SUB; }
"*" { return MUL; }

View File

@ -5,6 +5,7 @@
#include "vm.h"
#include "cstatic.h"
extern FILE* yyin;
extern node* ast;
extern void stack_push(node*);
@ -13,6 +14,8 @@ extern void stack_free();
int main(int argc, char** argv)
{
int DEBUG = argc > 2;
if (argc > 1)
{
yyin = fopen(argv[1], "r");
@ -27,6 +30,16 @@ int main(int argc, char** argv)
ast = stack_pop();
stack_free();
if (DEBUG)
{
size_t const BUF = 1024;
char buffer[BUF];
memset(buffer, 0, BUF);
node_str(ast, buffer, BUF);
printf("-- ast ---\n%s\n\n", buffer);
}
// Static checking
symtable sym;
symtable_init(&sym);
@ -52,24 +65,25 @@ int main(int argc, char** argv)
compile_node(&comp, ast, &prog);
if (DEBUG)
{
size_t const BUF = 1024;
char buffer[BUF];
memset(buffer, 0, BUF);
program_str(&prog, buffer, BUF);
printf("--- program ---\n%s\n", buffer);
}
// Execution
vm v;
vm_init(&v);
vm_exec(&v, &prog);
if (0) // DEBUG
if (DEBUG)
{
size_t const BUF = 1024;
char buffer[BUF];
memset(buffer, 0, BUF);
node_str(ast, buffer, BUF);
printf("-- ast ---\n%s\n\n", buffer);
memset(buffer, 0, BUF);
program_str(&prog, buffer, BUF);
printf("--- program ---\n%s\n", buffer);
memset(buffer, 0, BUF);
vm_str(&v, buffer, BUF);
printf("--- stack ---\n%s\n", buffer);

View File

@ -14,7 +14,9 @@
G(NODE_GT), G(NODE_GE), G(NODE_VARDECL), G(NODE_IDENT), \
G(NODE_CONSTDECL), G(NODE_ASSIGN), G(NODE_DO), G(NODE_IS), \
G(NODE_IF), G(NODE_ELSE), G(NODE_BLOCK), \
G(NODE_WHILE), G(NODE_CONTINUE), G(NODE_BREAK)
G(NODE_WHILE), G(NODE_CONTINUE), G(NODE_BREAK), \
G(NODE_COLON), G(NODE_FUN_TYPE), G(NODE_RETURN), G(NODE_FUN), \
G(NODE_FUN_PARAM), G(NODE_FUN_RET), G(NODE_CALL), G(NODE_ARGS)
#include "mutils.h"

View File

@ -47,7 +47,9 @@
G(OP_ASTORE), \
G(OP_TEQ), \
G(OP_BRF), \
G(OP_BR)
G(OP_BR), \
G(OP_CALL), \
G(OP_RET)
enum Opcodes {

View File

@ -2,7 +2,6 @@
#include <stdio.h>
#include <stdlib.h>
#include "src/node.h"
extern int line;
void yyerror(char const*);
node* ast = NULL;
@ -16,11 +15,13 @@
void stack_free();
%}
%define parse.error verbose
%union {
char* str;
size_t n_children;
};
%token SEP
%token IF_COND
%token ELSE_COND
%token WHILE
@ -29,7 +30,9 @@
%left ASSERT
%token <str> TYPE BOOLEAN INTEGER FLOAT STRING IDENT
%type <n_children> expr exprs prog array builtins
%type <n_children> expr_list type type_list ident if
%type <n_children> expr_list type type_list ident if
%type <n_children> fun_rets fun_params fun_param fun
%type <n_children> fun_ret_list fun_call fun_args any instr
%left EQ NE
%left LT GT LE GE
%left AND
@ -39,11 +42,11 @@
%left POW
%left NOT
%token OPAR CPAR
%token OSQUARE CSQUARE COMMA
%token OSQUARE CSQUARE COMMA COLON
%token LET LET_MUT ASSIGN DO END
%type <n_children> expr_unop block if_rec
%left IS
%token RETURN FUN AS
%%
prog:
@ -76,30 +79,19 @@ prog:
}
;
exprs:
exprs expr { $$ = $1 + $2; }
sep: SEP | sep SEP;
optsep: | sep;
| expr { $$ = $1; }
exprs:
exprs optsep instr sep { $$ = $1 + $3; }
| optsep instr sep { $$ = $2; }
;
any: expr { $$ = $1; } | instr { $$ = $1; };
expr:
CONTINUE {
node* n = malloc(sizeof(node));
node_init(n, NODE_CONTINUE, "", line);
stack_push(n);
$$ = 1;
}
| BREAK {
node* n = malloc(sizeof(node));
node_init(n, NODE_BREAK, "", line);
stack_push(n);
$$ = 1;
}
| WHILE expr block END {
WHILE expr block END {
node* n = malloc(sizeof(node));
node_init(n, NODE_WHILE, "", line);
@ -144,24 +136,6 @@ expr:
$$ = 1;
}
// INDEX
| expr array ASSIGN expr {
node* n = malloc(sizeof(node));
node_init(n, NODE_ASSIGN, "", line);
node* expr_node = stack_pop();
node* array_node = stack_pop();
node* ident_node = stack_pop();
node_add_child(n, ident_node);
node_add_child(n, array_node);
node_add_child(n, expr_node);
stack_push(n);
$$ = 1;
}
| expr array {
node *n = malloc(sizeof(node));
node_init(n, NODE_INDEX, "", line);
@ -185,51 +159,6 @@ expr:
| ident {
}
| LET_MUT ident ASSIGN expr {
node* n = malloc(sizeof(node));
node_init(n, NODE_VARDECL, "", line);
node* rhs = stack_pop();
node* lhs = stack_pop();
node_add_child(n, lhs);
node_add_child(n, rhs);
stack_push(n);
$$ = 1;
}
| LET ident ASSIGN expr {
node* n = malloc(sizeof(node));
node_init(n, NODE_CONSTDECL, "", line);
node* rhs = stack_pop();
node* lhs = stack_pop();
node_add_child(n, lhs);
node_add_child(n, rhs);
stack_push(n);
$$ = 1;
}
| ident ASSIGN expr {
node* n = malloc(sizeof(node));
node_init(n, NODE_ASSIGN, "", line);
node* rhs = stack_pop();
node* lhs = stack_pop();
node_add_child(n, lhs);
node_add_child(n, rhs);
stack_push(n);
$$ = 1;
}
// EXPRESSIONS
| array {
$$ = 1;
@ -239,16 +168,6 @@ expr:
$$ = $1;
}
| ASSERT expr {
node *n = malloc(sizeof(node));
node_init(n, NODE_ASSERT, "", line);
node_add_child(n, stack_pop());
stack_push(n);
$$ = 1;
}
| expr LT expr {
node *n = malloc(sizeof(node));
node_init(n, NODE_LT, "", line);
@ -414,11 +333,113 @@ expr:
}
| expr_unop {}
| fun_call { $$ = $1; }
;
instr:
expr
| RETURN expr {
node* n = malloc(sizeof(node));
node_init(n, NODE_RETURN, "", line);
node_add_child(n, stack_pop());
stack_push(n);
$$ = 1;
}
| ident ASSIGN expr {
node* n = malloc(sizeof(node));
node_init(n, NODE_ASSIGN, "", line);
node* rhs = stack_pop();
node* lhs = stack_pop();
node_add_child(n, lhs);
node_add_child(n, rhs);
stack_push(n);
$$ = 1;
}
| LET_MUT ident ASSIGN expr {
node* n = malloc(sizeof(node));
node_init(n, NODE_VARDECL, "", line);
node* rhs = stack_pop();
node* lhs = stack_pop();
node_add_child(n, lhs);
node_add_child(n, rhs);
stack_push(n);
$$ = 1;
}
| LET ident ASSIGN expr {
node* n = malloc(sizeof(node));
node_init(n, NODE_CONSTDECL, "", line);
node* rhs = stack_pop();
node* lhs = stack_pop();
node_add_child(n, lhs);
node_add_child(n, rhs);
stack_push(n);
$$ = 1;
}
| CONTINUE {
node* n = malloc(sizeof(node));
node_init(n, NODE_CONTINUE, "", line);
stack_push(n);
$$ = 1;
}
| BREAK {
node* n = malloc(sizeof(node));
node_init(n, NODE_BREAK, "", line);
stack_push(n);
$$ = 1;
}
// INDEX
| expr array ASSIGN expr {
node* n = malloc(sizeof(node));
node_init(n, NODE_ASSIGN, "", line);
node* expr_node = stack_pop();
node* array_node = stack_pop();
node* ident_node = stack_pop();
node_add_child(n, ident_node);
node_add_child(n, array_node);
node_add_child(n, expr_node);
stack_push(n);
$$ = 1;
}
| ASSERT expr {
node *n = malloc(sizeof(node));
node_init(n, NODE_ASSERT, "", line);
node_add_child(n, stack_pop());
stack_push(n);
$$ = 1;
}
;
if_rec:
ELSE_COND IF_COND expr block if_rec {
ELSE_COND IF_COND expr block_or_expr if_rec {
node* n = malloc(sizeof(node));
node_init(n, NODE_IF, "", line);
@ -435,7 +456,7 @@ if_rec:
$$ = 1;
}
| ELSE_COND expr END {
| ELSE_COND block_or_expr END {
node* n = malloc(sizeof(node));
node_init(n, NODE_IF, "", line);
@ -449,8 +470,10 @@ if_rec:
}
;
block_or_expr: block | expr;
if:
IF_COND expr block if_rec {
IF_COND expr block_or_expr if_rec {
node* n = malloc(sizeof(node));
node_init(n, NODE_IF, "", line);
@ -467,7 +490,7 @@ if:
$$ = 1;
}
| IF_COND expr block END {
| IF_COND expr block_or_expr END {
node* n = malloc(sizeof(node));
node_init(n, NODE_IF, "", line);
@ -502,8 +525,168 @@ expr_unop:
}
;
type_list:
fun_param:
ident AS type {
node *n = malloc(sizeof(node));
node_init(n, NODE_FUN_PARAM, "", line);
node* type_node = stack_pop();
node* ident_node = stack_pop();
node_add_child(n, ident_node);
node_add_child(n, type_node);
stack_push(n);
$$ = 1;
}
fun_param:
ident AS type
;
fun_params:
{ $$ = 0; }
| fun_param {
$$ = $1;
}
| fun_params COMMA fun_param {
$$ = $1 + $3;
}
;
fun_ret_list:
type { $$ = $1; }
| fun_ret_list COMMA type {
$$ = $1 + $3;
}
;
fun_rets:
{
node* n = malloc(sizeof(node));
node_init(n, NODE_FUN_RET, "", line);
stack_push(n);
$$ = 1;
}
| AS fun_ret_list {
node* n = malloc(sizeof(node));
node_init(n, NODE_FUN_RET, "", line);
node* rets[$2];
for (size_t i=0; i<$2; i++)
{
rets[$2 - 1 - i] = stack_pop();
}
for (size_t i=0; i<$2; i++)
{
node_add_child(n, rets[i]);
}
stack_push(n);
$$ = 1;
}
;
fun:
FUN OPAR fun_params CPAR fun_rets block END {
node* n = malloc(sizeof(node));
node_init(n, NODE_FUN, "", line);
node* block_node = stack_pop();
assert(block_node);
node* ret_node = stack_pop();
assert(ret_node);
if ($3 > 0)
{
node* params[$3];
for (size_t i=0; i<$3; i++)
{
params[i] = stack_pop();
}
for (size_t i=0; i<$3; i++)
{
node_add_child(n, params[$3 - 1 - i]);
}
}
node_add_child(n, ret_node);
node_add_child(n, block_node);
stack_push(n);
$$ = 1;
}
;
fun_args:
expr_list {
node* n = malloc(sizeof(node));
node_init(n, NODE_ARGS, "", line);
size_t const SZ = $1;
node* args[SZ];
for (size_t i=0; i<SZ; i++)
{
args[$1 - 1 - i] = stack_pop();
}
for (size_t i=0; i<SZ; i++)
{
node_add_child(n, args[i]);
}
stack_push(n);
$$ = 1;
}
;
fun_call:
MUL expr {
node* n = malloc(sizeof(node));
node_init(n, NODE_CALL, "", line);
node* args = malloc(sizeof(node));
node_init(args, NODE_ARGS, "", line);
node* fn_expr = stack_pop();
node_add_child(n, fn_expr);
node_add_child(n, args);
stack_push(n);
$$ = 1;
}
| expr fun_args {
node* n = malloc(sizeof(node));
node_init(n, NODE_CALL, "", line);
node* args = stack_pop();
node* fn_expr = stack_pop();
node_add_child(n, fn_expr);
node_add_child(n, args);
stack_push(n);
$$ = 1;
}
;
type_list: { $$ = 0; }
| type { $$ = $1; }
| type_list COMMA type { $$ = $1 + $3; }
;
@ -533,10 +716,55 @@ block:
;
type:
TYPE LT type_list GT {
FUN LT type_list COLON type_list GT {
node* n = malloc(sizeof(node));
node_init(n, NODE_FUN_TYPE, "", line);
node* right = malloc(sizeof(node));
node_init(right, NODE_TYPE, "", line);
size_t SZ = $5;
node* all_right[SZ];
for (size_t i=0; i<SZ; i++)
{
all_right[i] = stack_pop();
}
for (size_t i=0; i<SZ; i++)
{
node_add_child(right, all_right[i]);
}
node* left = malloc(sizeof(node));
node_init(left, NODE_TYPE, "", line);
SZ = $3;
node* all_left[SZ];
for (size_t i=0; i<SZ; i++)
{
all_left[i] = stack_pop();
}
for (size_t i=0; i<SZ; i++)
{
node_add_child(left, all_left[i]);
}
node_add_child(n, left);
node_add_child(n, right);
stack_push(n);
$$ = 1;
}
| TYPE LT type_list GT {
node* n = malloc(sizeof(node));
node_init(n, NODE_TYPE, $1, line);
free($1);
size_t const SZ = $3;
node* all[SZ];
@ -595,6 +823,7 @@ ident: IDENT {
builtins:
type {}
| fun {}
| STRING {
node* n = malloc(sizeof(node));

View File

@ -37,6 +37,27 @@ void program_free(program* self)
self->pool.capacity = 0;
}
program* program_new_clone(program* self)
{
assert(self);
program* clone = malloc(sizeof(program));
program_init(clone);
for (size_t i=0; i < self->instrs.size; i++)
{
program_add_instr(clone, self->instrs.data[i]->opcode
, self->instrs.data[i]->param);
}
for (size_t i=0; i < self->pool.size; i++)
{
assert(self->pool.data[i]);
program_add_pool(clone, self->pool.data[i]);
}
return clone;
}
void program_set_instr(program* self, size_t index, int opcode, int param)
{
assert(self);
@ -99,12 +120,15 @@ size_t program_add_pool(program* self, value* val)
self->pool.capacity *= 2;
self->pool.data = realloc(
self->pool.data,
sizeof(value) * self->pool.capacity
sizeof(value*) * self->pool.capacity
);
}
size_t idx = self->pool.size;
self->pool.data[idx] = value_new_clone(val);
size_t idx = self->pool.size;
value* new_val = value_new_clone(val);
assert(new_val);
self->pool.data[idx] = new_val;
self->pool.size++;
return idx;

View File

@ -29,6 +29,8 @@ typedef struct {
void program_init(program* self);
void program_free(program* self);
program* program_new_clone(program* self);
size_t program_add_instr(program* self, int opcode, int param);
void program_set_instr(program* self, size_t index, int opcode, int param);
void program_set_param(program* self, size_t index, int param);

View File

@ -42,6 +42,36 @@ void symentry_free(symentry* self)
free(self->ty);
}
symtable* symtable_new_clone(symtable* self)
{
symtable* clone = malloc(sizeof(symtable));
symtable_init(clone);
clone->entries.capacity = self->entries.capacity;
clone->entries.data = realloc(clone->entries.data,
sizeof(symentry*) * clone->entries.capacity);
for (size_t i=0; i<self->entries.size; i++)
{
symentry* entry = self->entries.data[i];
symentry* clone_entry = malloc(sizeof(symentry));
clone_entry->id = entry->id;
clone_entry->name = str_new(entry->name);
clone_entry->is_mut = entry->is_mut;
clone_entry->scope = entry->scope;
clone_entry->ty = type_new_clone(entry->ty);
clone_entry->sym_node = node_new_clone(entry->sym_node);
clone->entries.data[i] = clone_entry;
}
clone->entries.size = self->entries.size;
clone->id = self->id;
clone->scope = self->scope;
return clone;
}
size_t symtable_declare_mut(symtable* self, char const* name, type* ty, node* sym_node)
{
assert(self);

View File

@ -29,6 +29,7 @@ void symtable_init(symtable* self);
void symtable_free(symtable* self);
void symentry_free(symentry* self);
symtable* symtable_new_clone(symtable* self);
size_t symtable_declare(symtable* self, char const* name, type* ty, node* sym_node);
size_t symtable_declare_mut(symtable* self, char const* name, type* ty, node* sym_node);
symentry* symtable_find(symtable* self, char const* name);

View File

@ -12,6 +12,103 @@ void type_init(type* self, int base_type)
self->sub_types.data = malloc(sizeof(type*));
}
type* type_init_from_node(node* root)
{
assert(root);
type* ty = malloc(sizeof(type));
if (root->type == NODE_FUN_TYPE)
{
type_init(ty, TY_FUNCTION);
node* params = root->children.data[0];
for (size_t i=0; i< params->children.size; i++)
{
type* t = type_new_from_node(params->children.data[i]);
type_add_sub_type(ty, t);
type_free(t); free(t);
}
node* rets = root->children.data[1];
for (size_t i=0; i< rets->children.size; i++)
{
type* t = type_new_from_node(rets->children.data[i]);
type_add_sub_type(ty, t);
type_free(t); free(t);
}
return ty;
}
else if (strcmp(root->value, "fun") == 0)
{
type_init(ty, TY_FUNCTION);
}
else if (strcmp(root->value, "int") == 0)
{
type_init(ty, TY_INTEGER);
}
else if (strcmp(root->value, "float") == 0)
{
type_init(ty, TY_FLOAT);
}
else if (strcmp(root->value, "str") == 0)
{
type_init(ty, TY_STRING);
}
else if (strcmp(root->value, "bool") == 0)
{
type_init(ty, TY_BOOLEAN);
}
else if (strcmp(root->value, "type") == 0)
{
type_init(ty, TY_TYPE);
}
else if (strcmp(root->value, "array") == 0)
{
type_init(ty, TY_ARRAY);
ty->kind = KIND_SEQUENTIAL;
}
else if (root->type == NODE_ADD)
{
type_init(ty, TY_TYPE);
ty->kind = KIND_DISJUNCTION;
}
else if (root->type == NODE_MUL)
{
type_init(ty, TY_TYPE);
ty->kind = KIND_CONJUNCTION;
}
else
{
char c[512];
node_str(root, c, 512);
printf("errnode = %s\n", c);
fprintf(stderr,
"E(%d): cannot compile unknown type '%s').\n",
root->lineno,
NodeTypeStr[root->type]);
}
for (size_t i=0; i<root->children.size; i++)
{
type* sub = type_new_from_node(root->children.data[i]);
type_add_sub_type(ty, sub);
type_free(sub);
free(sub);
}
return ty;
}
void type_init_array(type* self, type* array_type)
{
assert(self);
@ -35,7 +132,12 @@ void type_free(type* self)
self->sub_types.size = 0;
self->sub_types.capacity = 0;
self->sub_types.data = NULL;
}
type* type_new_from_node(node* root)
{
assert(root);
return type_init_from_node(root);
}
void type_add_sub_type(type* self, type* rhs)
@ -92,7 +194,8 @@ int type_equals(type* self, type* rhs)
return 0;
}
if (self->kind != KIND_SEQUENTIAL)
if (self->kind == KIND_CONJUNCTION
|| self->kind == KIND_DISJUNCTION)
{
for (int i=0; i<TY_TYPE_COUNT; i++)
{
@ -138,10 +241,16 @@ size_t type_str(type* self, char* buffer, size_t size)
sz += snprintf(buffer + sz, size - sz, "<");
}
}
for (size_t i=0; i<self->sub_types.size; i++)
{
if (i > 0)
if ((i == 0 || self->sub_types.data[i - 1 ]->kind != KIND_RETURN)
&& self->sub_types.data[i]->kind == KIND_RETURN)
{
sz += snprintf(buffer + sz, size - sz, " : ");
}
else if (i > 0)
{
sz += snprintf(buffer + sz, size - sz, ", ");
}

View File

@ -2,6 +2,7 @@
#define TYPE_H
#include "commons.h"
#include "node.h"
#define TYPES(G) \
G(TY_NIL), \
@ -11,6 +12,7 @@
G(TY_STRING), \
G(TY_ARRAY), \
G(TY_TYPE), \
G(TY_FUNCTION), \
G(TY_TYPE_COUNT)
enum Types {
@ -22,7 +24,8 @@ extern char const* TypesStr[];
enum TypeKind {
KIND_DISJUNCTION,
KIND_CONJUNCTION,
KIND_SEQUENTIAL
KIND_SEQUENTIAL,
KIND_RETURN
};
typedef struct type {
@ -37,9 +40,11 @@ typedef struct type {
} type;
void type_init(type* self, int base_type);
type* type_init_from_node(node* root);
void type_init_array(type* self, type* array_type);
void type_free(type* self);
type* type_new_from_node(node* root);
void type_add_sub_type(type* self, type* rhs);
type* type_new_clone(type* self);

View File

@ -67,6 +67,17 @@ void value_init_type(value* self, type* ty, int lineno)
type_init(self->type, TY_TYPE);
}
void value_init_fun(value* self, fun* f, int lineno)
{
assert(self);
assert(f);
self->val.fun_val = fun_new_clone(f);
self->lineno = lineno;
self->type = type_new_clone(f->ty);
}
void value_free(value* self)
{
assert(self);
@ -94,6 +105,14 @@ void value_free(value* self)
self->val.array_val = NULL;
}
if (self->type->base_type == TY_FUNCTION
&& self->val.fun_val != NULL)
{
fun_free(self->val.fun_val);
free(self->val.fun_val);
self->val.fun_val = NULL;
}
type_free(self->type);
free(self->type);
self->type = NULL;
@ -121,6 +140,11 @@ value* value_new_clone(value* self)
clone->val.array_val = array_new_clone(self->val.array_val);
}
if (self->type->base_type == TY_FUNCTION)
{
clone->val.fun_val = fun_new_clone(self->val.fun_val);
}
clone->lineno = self->lineno;
return clone;
@ -167,6 +191,11 @@ int value_equals(value* self, value* rhs)
return array_equals(self->val.array_val, rhs->val.array_val);
}
if (self->type->base_type == TY_FUNCTION)
{
return fun_equals(self->val.fun_val, rhs->val.fun_val);
}
size_t const SZ = 512;
char ty_str[SZ];
@ -190,6 +219,12 @@ size_t value_str(value* self, char* buffer, size_t size)
case TY_ARRAY:
return array_str(self->val.array_val, buffer, size);
case TY_FUNCTION:
return fun_str(self->val.fun_val, buffer, size);
case TY_FLOAT:
return snprintf(buffer, size, "%f",
self->val.real_float);
case TY_STRING:
return snprintf(buffer, size, "%s",
self->val.string);

View File

@ -4,6 +4,7 @@
#include "commons.h"
#include "type.h"
#include "array.h"
#include "fun.h"
typedef struct {
type* type;
@ -15,6 +16,8 @@ typedef struct {
char* string;
array* array_val;
type* type_val;
fun* fun_val;
} val;
} value;
@ -24,6 +27,7 @@ void value_init_float(value* self, float real_float, int lineno);
void value_init_string(value* self, char* string, int lineno);
void value_init_array(value* self, array* arr, int lineno);
void value_init_type(value* self, type* ty, int lineno);
void value_init_fun(value* self, fun* f, int lineno);
void value_free(value* self);

View File

@ -109,6 +109,9 @@ void vm_exec(vm* self, program* prog)
case OP_TEQ: vm_teq(self); break;
case OP_CALL: vm_call(self, param); break;
case OP_RET: vm_ret(self); break;
default: {
fprintf(stderr, "unknown opcode %s\n",
OpcodesStr[opcode]);
@ -1142,3 +1145,51 @@ void vm_br(vm* self, int param)
assert(self);
self->pc = param;
}
void vm_call(vm* self, int param)
{
assert(self);
// get function and parameters
value* args[param];
for (int i=0; i<param; i++)
{
args[param - 1 - i] = vm_pop_value(self);
}
value* fun_val = vm_pop_value(self);
fun* f = fun_val->val.fun_val;
// create new ecxecution environment
vm v;
vm_init(&v);
for (int i=0; i<param; i++)
{
vm_set(&v, i, args[i]);
}
// execute function
vm_exec(&v, (program*) f->prog);
value* ret = value_new_clone(v.stack.data[v.stack.size - 1]);
vm_push_value(self, ret);
vm_free(&v);
for (int i=0; i<param; i++)
{
value_free(args[i]); free(args[i]);
}
value_free(fun_val); free(fun_val);
self->pc++;
}
void vm_ret(vm* self)
{
assert(self);
self->pc = self->prog->instrs.size;
}

View File

@ -95,4 +95,7 @@ void vm_teq(vm* self);
void vm_brf(vm* self, int param);
void vm_br(vm* self, int param);
void vm_call(vm* self, int param);
void vm_ret(vm* self);
#endif

1
tests/err_fun.wuz Normal file
View File

@ -0,0 +1 @@
let f = fun () as int return 1.2; end ; f

View File

@ -1,8 +1,8 @@
let x = 0 x + 1.2
let x = false x + "false"
let x=0 let x=7
let x=[1, 2] x[7, 9]
let x = 0 x = 3.2
let x = 0 x = 7
let x=[1, 2] x[0] = 3.2
let x=[3, 4] x[0] = 7
let x = 0 ; x + 1.2
let x = false ; x + "false"
let x=0 ; let x=7
let x=[1, 2] ; x[7, 9]
let x = 0 ; x = 3.2
let x = 0 ; x = 7
let x=[1, 2] ; x[0] = 3.2
let x=[3, 4] ; x[0] = 7

View File

@ -9,7 +9,6 @@ echo -e "\e[34m=== Error Testing ===\e[0m"
for file in $(find . -name "err_*.wuz")
do
LINE=1
while read line;
do
echo "$line" | wuz &> /dev/null

32
tests/test_fun.wuz Normal file
View File

@ -0,0 +1,32 @@
assert fun<int:int> is type
assert fun<int:> is type
assert fun<:int> is type
assert fun<int, int: float, str> is type
assert fun< fun<:> : int> is type
let a = fun (x as int, y as int) as int
0
end
assert a is fun<int, int: int>
assert !(a is fun<:>)
let b = fun (x as int) as int
return x * 7
end
assert 42 == b 6
let c = fun () as int
return 3 * 6
end
assert 18 == *c
let d = fun () as int
return 43
27
end
assert 43 == *d

View File

@ -20,3 +20,4 @@ assert 64 == 2^(3+3)
assert 1 == -2 - -3
assert 5 + 7 == 12