functions

main
bog 2024-02-16 22:47:37 +01:00
parent 6642b6613e
commit 09bbc31320
43 changed files with 1616 additions and 420 deletions

View File

@ -4,6 +4,6 @@ project(gux LANGUAGES C)
add_subdirectory(lib)
add_subdirectory(lang)
add_subdirectory(bc)
# add_subdirectory(bc)
add_subdirectory(vm)
add_subdirectory(guxi)

View File

@ -10,6 +10,9 @@ tests: build
install: check tests
sudo cmake --install build
force-install: build
sudo cmake --install build
check:
@cppcheck --enable=all lib lang vm -q \
--suppress=missingIncludeSystem \

View File

@ -1,22 +0,0 @@
cmake_minimum_required(VERSION 3.2)
project(gux-bc LANGUAGES C)
add_library(gux-bc OBJECT
src/compiler.c
src/program.c
src/opcodes.c
)
set_property(TARGET gux-bc PROPERTY C_STANDARD 99)
add_dependencies(gux-bc gux-lang)
target_include_directories(gux-bc
PUBLIC gux-lang
PUBLIC ${CMAKE_SOURCE_DIR}/bc/src
)
target_link_libraries(gux-bc
PUBLIC gux-lang
)

View File

@ -11,15 +11,19 @@ LEXPR ::=
| ASSERT EXPR
| VARDECL
| CONSTDECL
| FUNDECL
| ASSIGN
| break
| continue
| return EXPR?
| FUN
BEXPR ::=
| BLOCK
| IF
| WHILE
IF ::=
| if EXPR BLOCK
| if EXPR BLOCK else BLOCK
@ -27,9 +31,15 @@ IF ::=
WHILE ::= while EXPR BLOCK
FUN ::= fun PARAMS (rarrow TYPE) BLOCK
PARAMS ::=
| opar ident colon TYPE (comma ident colon type)* cpar
BLOCK ::= obrace INSTR* cbrace
VARDECL ::= var ident colon type? assign EXPR
CONSTDECL ::= ident colon type? assign EXPR
VARDECL ::= var ident colon TYPE? assign EXPR
CONSTDECL ::= ident colon TYPE? assign EXPR
FUNDECL ::= fun ident PARAMS (rarrow TYPE) BLOCK
ASSIGN ::= ident assign EXPR
OR ::= AND (or AND)*
@ -40,6 +50,20 @@ TERM ::= FACTOR ((add|sub) FACTOR)*
FACTOR ::= POW ((mul|div|mod) POW)*
POW ::= NOT (pow NOT)?
NOT ::= not* LITERAL
LITERAL ::= ident | BUILTIN | opar EXPR cpar
NOT ::= not* CALL
CALL ::= LITERAL ARGS*
ARGS ::= opar (EXPR (comma EXPR)*)? cpar
LITERAL ::=
| ident
| BUILTIN
| opar EXPR cpar
CALL ::= LITERAL ARGS*
ARGS ::= opar (EXPR (comma EXPR)*)? cpar
BUILTIN ::= bool | int | float | string
TYPE ::=
| type
| opar TYPE+ rarrow TYPE+ cpar

View File

@ -1,24 +1,23 @@
cmake_minimum_required(VERSION 3.2)
project(guxi LANGUAGES C)
project(gux LANGUAGES C)
add_executable(guxi
add_executable(gux
src/main.c
)
set_property(TARGET guxi PROPERTY C_STANDARD 99)
set_property(TARGET gux PROPERTY C_STANDARD 99)
add_dependencies(guxi gux-vm)
add_dependencies(gux gux-vm)
target_include_directories(guxi
PUBLIC gux-vm gux-bc
target_include_directories(gux
PUBLIC gux-vm
)
target_link_libraries(guxi
target_link_libraries(gux
PUBLIC gux-vm
PUBLIC gux-lang
PUBLIC gux-bc
PUBLIC gux-lib
)
install(TARGETS guxi)
install(TARGETS gux)

View File

@ -5,7 +5,7 @@
#include <type_checker.h>
#include <compiler.h>
#include <vm.h>
#include <syms.h>
#include <sym_table.h>
char* load_new_source(char const* path)
{
@ -159,11 +159,8 @@ int main(int argc, char** argv)
printf("%s\n", msg);
}
struct syms syms;
syms_init(&syms);
struct type_checker checker;
type_checker_init(&checker, &syms);
type_checker_init(&checker);
if (type_checker_check(&checker, ast) != 0)
{
@ -172,7 +169,6 @@ int main(int argc, char** argv)
checker.error_line,
checker.error_msg);
syms_free(&syms);
type_checker_free(&checker);
if (ast)
@ -200,7 +196,7 @@ int main(int argc, char** argv)
program_init(&program);
struct compiler compiler;
compiler_init(&compiler, &syms);
compiler_init(&compiler);
if (compiler_compile(&compiler, ast, &program) != 0)
{
@ -211,7 +207,7 @@ int main(int argc, char** argv)
compiler_free(&compiler);
program_free(&program);
syms_free(&syms);
type_checker_free(&checker);
if (ast)
@ -245,7 +241,7 @@ int main(int argc, char** argv)
if (show_syms)
{
char buffer[GUX_STR_SIZE];
syms_str(&syms, buffer, GUX_STR_SIZE);
sym_table_str(&compiler.sym_table, buffer, GUX_STR_SIZE);
printf("%s\n", buffer);
}
@ -265,7 +261,6 @@ int main(int argc, char** argv)
vm_free(&vm);
compiler_free(&compiler);
program_free(&program);
syms_free(&syms);
type_checker_free(&checker);
if (ast)
@ -301,7 +296,6 @@ int main(int argc, char** argv)
vm_free(&vm);
compiler_free(&compiler);
program_free(&program);
syms_free(&syms);
type_checker_free(&checker);
if (ast)

View File

@ -10,9 +10,13 @@ add_library(gux-lang OBJECT
src/parser.c
src/type.c
src/value.c
src/fun.c
src/type_resolver.c
src/type_checker.c
src/syms.c
src/sym_table.c
src/compiler.c
src/program.c
src/opcodes.c
)
set_property(TARGET gux-lang PROPERTY C_STANDARD 99)
@ -42,7 +46,7 @@ add_executable(gux-lang-tests
tests/type.c
tests/value.c
tests/type_checker.c
tests/syms.c
tests/sym_table.c
)
set_property(TARGET gux-lang-tests PROPERTY C_STANDARD 99)

View File

@ -3,14 +3,17 @@
#include "node.h"
#include "opcodes.h"
#include "program.h"
#include "syms.h"
#include "sym_table.h"
#include "type.h"
#include "type_checker.h"
#include "value.h"
#include "vec.h"
#include "fun.h"
void compiler_init(struct compiler* self, struct syms* syms)
void compiler_init(struct compiler* self)
{
assert(self);
self->syms = syms;
sym_table_init(&self->sym_table);
memset(self->error_msg, 0, GUX_STR_SIZE);
self->stack_size = 0;
vec_init(&self->loops, 1);
@ -18,6 +21,7 @@ void compiler_init(struct compiler* self, struct syms* syms)
void compiler_free(struct compiler* self)
{
sym_table_free(&self->sym_table);
vec_free_elements(&self->loops);
vec_free(&self->loops);
assert(self);
@ -33,6 +37,102 @@ int compiler_compile(struct compiler* self,
switch (node->type)
{
case NODE_RETURN: {
if (node->children.size > 0)
{
compiler_compile(self, node->children.data[0], program);
}
compiler_gen_instr(self, program, OP_RET, NO_PARAM);
} break;
case NODE_FUN: {
struct node* params = node->children.data[0];
struct node* body = node->children.data[2];
struct fun* fun = malloc(sizeof(struct fun));
fun_init(fun, node);
sym_table_push_table(&self->sym_table);
struct compiler compiler;
compiler_init(&compiler);
struct vec idents;
vec_init(&idents, 1);
for (size_t i=0; i<params->children.size; i++)
{
struct node* param = params->children.data[i];
if (param->type != NODE_TYPE)
{
vec_push(&idents, param);
}
else
{
for (size_t j=0; j<idents.size; j++)
{
struct node* ident = idents.data[j];
struct type* ty = malloc(sizeof(struct type));
type_init_from_node(ty, param);
sym_table_declare_const(&compiler.sym_table,
ident->value,
ty);
}
vec_free(&idents);
vec_init(&idents, 1);
}
}
vec_free(&idents);
struct type* ty = malloc(sizeof(struct type));
type_init_from_node(ty, node);
sym_table_declare_const(&compiler.sym_table, "this", ty);
if (compiler_compile(&compiler, body, &fun->program) != 0)
{
fun_free(fun);
free(fun);
return 1;
}
compiler_gen_instr(&compiler, &fun->program, OP_RET, NO_PARAM);
struct value* value = malloc(sizeof(struct value));
value_init_new_fun(value, fun, node->line);
compiler_gen_instr(self,
program, OP_PUSH,
program_push_constant(program, value));
compiler_free(&compiler);
sym_table_pop_table(&self->sym_table);
} break;
case NODE_CALL: {
struct node* target = node->children.data[0];
struct node* args = node->children.data[1];
for (size_t i=0; i<args->children.size; i++)
{
struct node* arg = args->children.data[i];
compiler_compile(self, arg, program);
}
struct sym* entry = sym_table_try_by_name(&self->sym_table,
target->value);
assert(entry);
compiler_gen_instr(self, program, OP_LOAD, entry->addr);
compiler_gen_instr(self, program, OP_CALL, args->children.size);
} break;
case NODE_BREAK: {
size_t* addr = malloc(sizeof(size_t));
*addr = compiler_gen_instr(self, program, OP_BR, NO_PARAM);
@ -78,8 +178,8 @@ int compiler_compile(struct compiler* self,
for (size_t i=0; i<loop->to_end.size; i++)
{
size_t goto_end = *(size_t*)loop->to_end.data[i];
instr = program->instructions.data[goto_end];
size_t my_goto_end = *(size_t*)loop->to_end.data[i];
instr = program->instructions.data[my_goto_end];
instr->param = program->instructions.size;
}
@ -114,6 +214,7 @@ int compiler_compile(struct compiler* self,
case NODE_BLOCK: {
int stack_base = self->stack_size;
sym_table_push_table(&self->sym_table);
for (size_t i=0; i<node->children.size; i++)
{
@ -130,13 +231,14 @@ int compiler_compile(struct compiler* self,
compiler_gen_instr(self, program, OP_POP, NO_PARAM);
}
sym_table_pop_table(&self->sym_table);
} break;
case NODE_ASSIGN: {
struct node* ident = node->children.data[0];
struct node* expr = node->children.data[1];
struct syms_entry* entry = syms_try_get(self->syms, ident->value,
node);
struct sym* entry = sym_table_try_by_name(&self->sym_table,
ident->value);
assert(entry);
if (compiler_compile(self, expr, program) != 0)
@ -148,9 +250,8 @@ int compiler_compile(struct compiler* self,
} break;
case NODE_IDENT: {
struct syms_entry* entry = syms_try_get(self->syms,
node->value,
node);
struct sym* entry = sym_table_try_by_name(&self->sym_table,
node->value);
if (!entry)
{
@ -165,6 +266,7 @@ int compiler_compile(struct compiler* self,
case NODE_CONSTDECL:
case NODE_VARDECL: {
int err = compiler_compile(self, node->children.size == 1
? node->children.data[0]
: node->children.data[1],
@ -175,9 +277,15 @@ int compiler_compile(struct compiler* self,
return 1;
}
struct syms_entry* entry = syms_try_get(self->syms,
node->value,
node);
struct type* ty = malloc(sizeof(struct type));
type_init_from_node(ty, node->children.data[0]);
sym_table_declare(&self->sym_table, node->value, ty,
node->type == NODE_VARDECL);
struct sym* entry = sym_table_try_by_name(&self->sym_table,
node->value);
assert(entry);
compiler_gen_instr(self, program, OP_STORE, entry->addr);
@ -487,6 +595,8 @@ size_t compiler_gen_instr(struct compiler* self,
switch (op)
{
case OP_CALL: break;
case OP_LOAD:
case OP_PUSH: self->stack_size += 1; break;
@ -507,6 +617,7 @@ size_t compiler_gen_instr(struct compiler* self,
case OP_BRT:
self->stack_size -= 1; break;
case OP_RET:
case OP_SWAP:
case OP_BR:
case OP_NOT:

View File

@ -4,7 +4,7 @@
#include <commons.h>
#include <node.h>
#include "program.h"
#include "syms.h"
#include "sym_table.h"
struct loop_info {
size_t to_cond;
@ -13,13 +13,13 @@ struct loop_info {
struct compiler {
char error_msg[GUX_STR_SIZE];
struct syms* syms;
struct sym_table sym_table;
int error_line;
int stack_size;
struct vec loops;
};
void compiler_init(struct compiler* self, struct syms* syms);
void compiler_init(struct compiler* self);
void compiler_free(struct compiler* self);
int compiler_compile(struct compiler* self,

39
lang/src/fun.c Normal file
View File

@ -0,0 +1,39 @@
#include "fun.h"
#include "program.h"
void fun_init(struct fun* self, struct node* node)
{
assert(self);
self->node = node;
program_init(&self->program);
}
void fun_free(struct fun* self)
{
program_free(&self->program);
assert(self);
}
struct fun* fun_new_clone(struct fun* self)
{
assert(self);
struct fun* clone = malloc(sizeof(struct fun));
assert(clone);
fun_init(clone, self->node);
for (size_t i=0; i<self->program.instructions.size; i++)
{
struct instruction* instr = self->program.instructions.data[i];
program_push_instr(&clone->program, instr->opcode, instr->param);
}
for (size_t i=0; i<self->program.constant_pool.size; i++)
{
struct value* val = self->program.constant_pool.data[i];
program_push_constant(&clone->program, value_new_clone(val));
}
return clone;
}

16
lang/src/fun.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef FUN_H
#define FUN_H
#include <commons.h>
#include "program.h"
struct fun {
struct node* node;
struct program program;
};
void fun_init(struct fun* self, struct node* node);
void fun_free(struct fun* self);
struct fun* fun_new_clone(struct fun* self);
#endif

View File

@ -12,6 +12,10 @@ void lexer_init(struct lexer* self, char const* source)
vec_init(&self->toks, 1);
lexer_add_tok(self, "->", NODE_RARROW, "", 1);
lexer_add_tok(self, "fun", NODE_FUN, "", 1);
lexer_add_tok(self, "return", NODE_RETURN, "", 1);
lexer_add_tok(self, "continue", NODE_CONTINUE, "", 1);
lexer_add_tok(self, "break", NODE_BREAK, "", 1);
lexer_add_tok(self, "if", NODE_IF, "", 1);
@ -27,6 +31,7 @@ void lexer_init(struct lexer* self, char const* source)
lexer_add_tok(self, "bool", NODE_TYPE, "bool", 1);
lexer_add_tok(self, "string", NODE_TYPE, "string", 1);
lexer_add_tok(self, ",", NODE_COMMA, "", 0);
lexer_add_tok(self, "{", NODE_OBRACE, "", 0);
lexer_add_tok(self, "}", NODE_CBRACE, "", 0);
lexer_add_tok(self, ":", NODE_COLON, "", 0);

View File

@ -28,6 +28,21 @@ void node_free(struct node* self)
vec_free(&self->children);
}
struct node* node_new_clone(struct node* self)
{
assert(self);
struct node* clone = malloc(sizeof(struct node));
node_init(clone, self->type, self->value, self->line);
clone->parent = self->parent;
for (size_t i=0; i<self->children.size; i++)
{
node_add_child(clone, node_new_clone(self->children.data[i]));
}
return clone;
}
struct node* node_add_new_child(struct node* self,
enum NodeType type, char const* value)
{
@ -156,3 +171,21 @@ size_t node_block_index(struct node* self)
return node_block_index(self->parent);
}
void node_try_find_all(struct node* self,
enum NodeType type,
struct vec* res)
{
assert(self);
if (self->type == type)
{
vec_push(res, self);
}
for (size_t i=0; i<self->children.size; i++)
{
struct node* child = self->children.data[i];
node_try_find_all(child, type, res);
}
}

View File

@ -16,7 +16,9 @@
G(NODE_TYPE), G(NODE_VARDECL), G(NODE_CONSTDECL), G(NODE_VAR), \
G(NODE_OBRACE), G(NODE_CBRACE), G(NODE_BLOCK), \
G(NODE_IF), G(NODE_ELSE), G(NODE_COND), G(NODE_WHILE), G(NODE_FOR), \
G(NODE_CONTINUE), G(NODE_BREAK)
G(NODE_CONTINUE), G(NODE_BREAK), G(NODE_RARROW), G(NODE_FUN), \
G(NODE_RETURN), G(NODE_PARAMS), G(NODE_COMMA), G(NODE_CALL), \
G(NODE_ARGS)
GUX_ENUM_H(NodeType, NODE_TYPE);
@ -33,6 +35,8 @@ void node_init(struct node* self, enum NodeType type,
char const* value, int line);
void node_free(struct node* self);
struct node* node_new_clone(struct node* self);
struct node* node_add_new_child(struct node* self,
enum NodeType type, char const* value);
@ -46,4 +50,8 @@ size_t node_parent_index(struct node* self);
size_t node_block_index(struct node* self);
void node_try_find_all(struct node* self,
enum NodeType type,
struct vec* res);
#endif

View File

@ -5,8 +5,8 @@
G(OP_PUSH), G(OP_POP), G(OP_BRF), G(OP_BR), G(OP_HALT), \
G(OP_BRT), G(OP_NOP), G(OP_NOT), G(OP_EQ), \
G(OP_ADD), G(OP_SUB), G(OP_MUL), G(OP_DIV), G(OP_MOD), G(OP_POW), \
G(OP_LT), G(OP_LE), G(OP_GT),G(OP_GE), G(OP_LOAD), G(OP_STORE),\
G(OP_SWAP)
G(OP_LT), G(OP_LE), G(OP_GT),G(OP_GE), G(OP_LOAD), G(OP_STORE), \
G(OP_SWAP), G(OP_CALL), G(OP_RET)
#include <commons.h>

View File

@ -132,11 +132,26 @@ int parser_start_bexpr(struct parser* self)
assert(self);
struct node* tok = self->tokens.data[self->cursor];
if (parser_type_is(self, NODE_FUN, 0)
&& parser_type_is(self, NODE_IDENT, 1))
{
return 1;
}
return tok->type == NODE_OBRACE
|| tok->type == NODE_IF
|| tok->type == NODE_WHILE;
}
int parser_start_type(struct parser* self)
{
assert(self);
struct node* tok = self->tokens.data[self->cursor];
return tok->type == NODE_OPAR
|| tok->type == NODE_TYPE;
}
struct node* parser_try_new_root(struct parser* self, char const* source)
{
assert(self);
@ -217,6 +232,24 @@ struct node* parser_try_new_lexpr(struct parser* self)
{
assert(self);
if (parser_type_is(self, NODE_FUN, 0))
{
return parser_try_new_fun(self);
}
if (parser_try_consume(self, NODE_RETURN) == 0)
{
struct node* node = malloc(sizeof(struct node));
node_init(node, NODE_RETURN, "", parser_current_line(self));
if (!parser_type_is(self, NODE_SEMICOLON, 0))
{
node_add_child(node, parser_try_new_expr(self));
}
return node;
}
if (parser_try_consume(self, NODE_BREAK) == 0)
{
struct node* node = malloc(sizeof(struct node));
@ -279,7 +312,12 @@ struct node* parser_try_new_bexpr(struct parser* self)
{
assert(self);
if (parser_type_is(self, NODE_IF, 0))
if (parser_type_is(self, NODE_FUN, 0)
&& parser_type_is(self, NODE_IDENT, 1))
{
return parser_try_new_fundecl(self);
}
else if (parser_type_is(self, NODE_IF, 0))
{
return parser_try_new_if(self);
}
@ -331,9 +369,149 @@ struct node* parser_try_new_while(struct parser* self)
return node;
}
struct node* parser_try_new_fun(struct parser* self)
{
assert(self);
if (parser_try_consume(self, NODE_FUN) != 0)
{
return NULL;
}
struct node* node = malloc(sizeof(struct node));
node_init(node, NODE_FUN, "", parser_current_line(self));
node_add_child(node, parser_try_new_params(self));
struct node* type = NULL;
if (parser_try_consume(self, NODE_RARROW) == 0)
{
type = parser_try_new_type(self);
}
else
{
type = malloc(sizeof(struct node));
node_init(type, NODE_TYPE, "void", parser_current_line(self));
}
self->cursor++; //type
node_add_child(node, type);
node_add_child(node, parser_try_new_block(self));
return node;
}
struct node* parser_try_new_params(struct parser* self)
{
assert(self);
if (parser_try_consume(self, NODE_OPAR) != 0)
{
return NULL;
}
struct node* node = malloc(sizeof(struct node));
node_init(node, NODE_PARAMS, "", parser_current_line(self));
if (parser_try_consume(self, NODE_CPAR) == 0)
{
return node;
}
struct vec types;
vec_init(&types, 1);
while (1)
{
if (!parser_type_is(self, NODE_IDENT, 0))
{
vec_free_elements(&types);
vec_free(&types);
node_free(node);
free(node);
return NULL;
}
// ident
struct node* current = self->tokens.data[self->cursor];
struct node* ident = malloc(sizeof(struct node));
node_init(ident, NODE_IDENT, current->value,
parser_current_line(self));
node_add_child(node, ident);
self->cursor++; // ident
if (parser_try_consume(self, NODE_COLON) == 0)
{
// type
struct node* type = parser_try_new_type(self);
node_add_child(node, type);
for (size_t i=0; i<types.size; i++)
{
size_t* t = types.data[i];
size_t idx = *t;
node_free(node->children.data[idx]);
free(node->children.data[idx]);
node->children.data[idx] = node_new_clone(type);
}
vec_free(&types);
vec_init(&types, 1);
}
else
{
struct node* type = malloc(sizeof(struct node));
node_init(type, NODE_TYPE, "", parser_current_line(self));
size_t idx = node->children.size;
node_add_child(node, type);
size_t* t = malloc(sizeof(size_t));
*t = idx;
vec_push(&types, t);
}
if (parser_type_is(self, NODE_CPAR, 0))
{
break;
}
if (parser_try_consume(self, NODE_COMMA) != 0)
{
break;
}
}
if (types.size > 0)
{
snprintf(self->error_msg, GUX_STR_SIZE,
"missing type from function parameters");
self->error_line = node->line;
vec_free_elements(&types);
vec_free(&types);
node_free(node);
free(node);
return NULL;
}
vec_free_elements(&types);
vec_free(&types);
if (parser_try_consume(self, NODE_CPAR) != 0)
{
node_free(node);
free(node);
return NULL;
}
return node;
}
struct node* parser_try_new_block(struct parser* self)
{
parser_try_consume(self, NODE_OBRACE);
struct node* node = malloc(sizeof(struct node));
node_init(node, NODE_BLOCK, "", parser_current_line(self));
@ -387,12 +565,13 @@ struct node* parser_try_new_vardecl(struct parser* self)
if (parser_type_is(self, NODE_TYPE, 0))
{
current = self->tokens.data[self->cursor];
/*current = self->tokens.data[self->cursor];
struct node* ty = malloc(sizeof(struct node));
node_init(ty, NODE_TYPE, current->value, parser_current_line(self));
node_add_child(node, ty);
self->cursor++;
self->cursor++;*/
node_add_child(node, parser_try_new_type(self));
}
if (parser_try_consume(self, NODE_ASSIGN) != 0)
@ -424,14 +603,9 @@ struct node* parser_try_new_constdecl(struct parser* self)
return NULL;
}
if (parser_type_is(self, NODE_TYPE, 0))
if (parser_start_type(self))
{
current = self->tokens.data[self->cursor];
struct node* ty = malloc(sizeof(struct node));
node_init(ty, NODE_TYPE, current->value, parser_current_line(self));
node_add_child(node, ty);
self->cursor++;
node_add_child(node, parser_try_new_type(self));
}
if (parser_try_consume(self, NODE_ASSIGN) != 0)
@ -448,6 +622,57 @@ struct node* parser_try_new_constdecl(struct parser* self)
return node;
}
struct node* parser_try_new_fundecl(struct parser* self)
{
assert(self);
if (parser_try_consume(self, NODE_FUN) != 0)
{
return NULL;
}
size_t ident_idx = self->cursor;
self->cursor++; // ident
struct node* node_fun = malloc(sizeof(struct node));
node_init(node_fun, NODE_FUN, "", parser_current_line(self));
struct node* params = parser_try_new_params(self);
if (params == NULL)
{
node_free(node_fun);
free(node_fun);
return NULL;
}
node_add_child(node_fun, params);
struct node* type = NULL;
if (parser_try_consume(self, NODE_RARROW) == 0)
{
type = parser_try_new_type(self);
}
else
{
type = malloc(sizeof(struct node));
node_init(type, NODE_TYPE, "void", parser_current_line(self));
}
self->cursor++; //type
node_add_child(node_fun, type);
node_add_child(node_fun, parser_try_new_block(self));
struct node* node = malloc(sizeof(struct node));
struct node* ident = self->tokens.data[ident_idx];
node_init(node, NODE_CONSTDECL, ident->value, parser_current_line(self));
node_add_child(node, node_fun);
return node;
}
struct node* parser_try_new_or(struct parser* self)
{
struct node* lhs = parser_try_new_and(self);
@ -608,7 +833,68 @@ struct node* parser_try_new_not(struct parser* self)
return node;
}
return parser_try_new_literal(self);
return parser_try_new_call(self);
}
struct node* parser_try_new_call(struct parser* self)
{
assert(self);
struct node* lhs = parser_try_new_literal(self);
if (parser_type_is(self, NODE_OPAR, 0))
{
struct node* node = malloc(sizeof(struct node));
node_init(node, NODE_CALL, "", parser_current_line(self));
node_add_child(node, lhs);
while (parser_type_is(self, NODE_OPAR, 0))
{
struct node* args = parser_try_new_args(self);
node_add_child(node, args);
}
lhs = node;
}
return lhs;
}
struct node* parser_try_new_args(struct parser* self)
{
assert(self);
struct node* node = malloc(sizeof(struct node));
node_init(node, NODE_ARGS, "", parser_current_line(self));
if (parser_try_consume(self, NODE_OPAR) != 0)
{
node_free(node);
free(node);
return NULL;
}
if (parser_try_consume(self, NODE_CPAR) == 0)
{
return node;
}
node_add_child(node, parser_try_new_expr(self));
while (parser_try_consume(self, NODE_COMMA) == 0)
{
node_add_child(node, parser_try_new_expr(self));
}
if (parser_try_consume(self, NODE_CPAR) != 0)
{
node_free(node);
free(node);
return NULL;
}
return node;
}
struct node* parser_try_new_literal(struct parser* self)
@ -661,3 +947,48 @@ struct node* parser_try_new_builtin(struct parser* self)
return NULL;
}
struct node* parser_try_new_type(struct parser* self)
{
assert(self);
if (parser_type_is(self, NODE_OPAR, 0))
{
self->cursor++; // opar
struct node* node = malloc(sizeof(struct node));
node_init(node, NODE_TYPE, "fun", parser_current_line(self));
while (!parser_type_is(self, NODE_RARROW, 0))
{
node_add_child(node, parser_try_new_type(self));
}
struct node* rarrow = malloc(sizeof(struct node));
node_init(rarrow, NODE_RARROW, "", parser_current_line(self));
node_add_child(node, rarrow);
self->cursor++; // rarrow
while (!parser_type_is(self, NODE_CPAR, 0))
{
node_add_child(node, parser_try_new_type(self));
}
if (parser_try_consume(self, NODE_CPAR) != 0)
{
node_free(node);
free(node);
return NULL;
}
return node;
}
else
{
struct node* node = malloc(sizeof(struct node));
struct node* current = self->tokens.data[self->cursor];
node_init(node, NODE_TYPE, current->value, parser_current_line(self));
self->cursor++;
return node;
}
}

View File

@ -25,6 +25,7 @@ int parser_try_consume(struct parser* self, enum NodeType type);
int parser_ensure(struct parser* self, enum NodeType type);
int parser_start_bexpr(struct parser* self);
int parser_start_type(struct parser* self);
struct node* parser_try_new_root(struct parser* self, char const* source);
struct node* parser_try_new_instr(struct parser* self);
@ -33,10 +34,13 @@ struct node* parser_try_new_lexpr(struct parser* self);
struct node* parser_try_new_bexpr(struct parser* self);
struct node* parser_try_new_if(struct parser* self);
struct node* parser_try_new_while(struct parser* self);
struct node* parser_try_new_fun(struct parser* self);
struct node* parser_try_new_params(struct parser* self);
struct node* parser_try_new_block(struct parser* self);
struct node* parser_try_new_assign(struct parser* self);
struct node* parser_try_new_vardecl(struct parser* self);
struct node* parser_try_new_constdecl(struct parser* self);
struct node* parser_try_new_fundecl(struct parser* self);
struct node* parser_try_new_or(struct parser* self);
struct node* parser_try_new_and(struct parser* self);
struct node* parser_try_new_eqne(struct parser* self);
@ -45,7 +49,10 @@ struct node* parser_try_new_term(struct parser* self);
struct node* parser_try_new_factor(struct parser* self);
struct node* parser_try_new_pow(struct parser* self);
struct node* parser_try_new_not(struct parser* self);
struct node* parser_try_new_call(struct parser* self);
struct node* parser_try_new_args(struct parser* self);
struct node* parser_try_new_literal(struct parser* self);
struct node* parser_try_new_builtin(struct parser* self);
struct node* parser_try_new_type(struct parser* self);
#endif

View File

@ -24,6 +24,27 @@ void program_free(struct program* self)
vec_free(&self->instructions);
}
void program_copy(struct program* self, struct program* dest)
{
assert(self);
assert(dest);
program_free(dest);
program_init(dest);
for (size_t i=0; i<self->instructions.size; i++)
{
struct instruction* instr = self->instructions.data[i];
program_push_instr(dest, instr->opcode, instr->param);
}
for (size_t i=0; i<self->constant_pool.size; i++)
{
struct value* constant = value_new_clone(self->constant_pool.data[i]);
program_push_constant(dest, constant);
}
}
size_t program_push_instr(struct program* self, enum Opcodes op, int param)
{
assert(self);
@ -55,7 +76,7 @@ size_t program_str(struct program* self, char* buffer, size_t size)
for (size_t i=0; i<self->constant_pool.size; i++)
{
sz += snprintf(buffer + sz, size - sz, "\t%ld: ", i);
sz += snprintf(buffer + sz, size - sz, "\t%zu: ", i);
sz += value_str(self->constant_pool.data[i], buffer + sz, size - sz);
sz += snprintf(buffer + sz, size - sz, "\n");
}
@ -69,14 +90,14 @@ size_t program_str(struct program* self, char* buffer, size_t size)
if (instr->param != NO_PARAM)
{
sz += snprintf(buffer + sz, size - sz, "\t%ld: %s %d\n",
sz += snprintf(buffer + sz, size - sz, "\t%zu: %s %d\n",
i,
OpcodesStr[instr->opcode] + strlen("OP_"),
instr->param);
}
else
{
sz += snprintf(buffer + sz, size - sz, "\t%ld: %s\n",
sz += snprintf(buffer + sz, size - sz, "\t%zu: %s\n",
i,
OpcodesStr[instr->opcode] + strlen("OP_"));
}

View File

@ -3,7 +3,7 @@
#include <commons.h>
#include <vec.h>
#include <value.h>
#include "value.h"
#include "opcodes.h"
#define NO_PARAM -1
@ -21,6 +21,8 @@ struct program {
void program_init(struct program* self);
void program_free(struct program* self);
void program_copy(struct program* self, struct program* dest);
size_t program_push_instr(struct program* self, enum Opcodes op, int param);
size_t program_push_constant(struct program* self, struct value* value);

156
lang/src/sym_table.c Normal file
View File

@ -0,0 +1,156 @@
#include "sym_table.h"
#include "vec.h"
void sym_table_init(struct sym_table* self)
{
assert(self);
self->root = NULL;
sym_table_push_table(self);
self->addr_counter = 0;
}
void sym_table_free(struct sym_table* self)
{
assert(self);
while (self->root)
{
sym_table_pop_table(self);
}
}
void sym_table_push_table(struct sym_table* self)
{
assert(self);
struct table* next;
next = malloc(sizeof(struct table));
next->prev = NULL;
vec_init(&next->syms, 1);
if (self->root == NULL)
{
self->root = next;
}
else
{
next->prev = self->root;
self->root = next;
}
}
void sym_table_pop_table(struct sym_table* self)
{
assert(self);
if (self->root == NULL)
{
return;
}
struct table* to_rm = self->root;
struct table* next = self->root->prev;
for (size_t i=0; i<to_rm->syms.size; i++)
{
struct sym* sym = to_rm->syms.data[i];
free(sym->name);
type_free(sym->type);
free(sym->type);
}
vec_free_elements(&to_rm->syms);
vec_free(&to_rm->syms);
free(to_rm);
self->root = next;
}
struct sym* sym_table_try_by_name(struct sym_table* self, char* const name)
{
assert(self);
struct table* table = self->root;
while (table)
{
for (size_t i=0; i<table->syms.size; i++)
{
struct sym* sym = table->syms.data[i];
if (strcmp(sym->name, name) == 0)
{
return sym;
}
}
table = table->prev;
}
return NULL;
}
int sym_table_declare_const(struct sym_table* self,
char* const name,
struct type* new_type)
{
return sym_table_declare(self, name, new_type, 0);
}
int sym_table_declare_var(struct sym_table* self,
char* const name,
struct type* new_type)
{
return sym_table_declare(self, name, new_type, 1);
}
int sym_table_declare(struct sym_table* self,
char* const name,
struct type* new_type,
int is_var)
{
assert(self);
assert(strcmp(name, "") != 0);
struct sym* s = sym_table_try_by_name(self, name);
if (s && s->parent == self->root)
{
return 1;
}
struct table* table = self->root;
struct sym* sym = malloc(sizeof(struct sym));
sym->name = strdup(name);
sym->type = new_type;
sym->parent = self->root;
sym->is_var = is_var;
sym->addr = self->addr_counter;
vec_push(&table->syms, sym);
self->addr_counter++;
return 0;
}
size_t sym_table_str(struct sym_table* self, char* buffer, size_t size)
{
assert(self);
assert(buffer);
size_t sz = 0;
sz += snprintf(buffer + sz, size - sz, "SYMBOLS\n");
struct table* table = self->root;
for (size_t i=0; i<table->syms.size; i++)
{
struct sym* sym = table->syms.data[i];
sz += snprintf(buffer + sz, size - sz,
"[%s::%p] -> %d\n",
sym->name, sym->parent, sym->addr);
}
return sz;
}

48
lang/src/sym_table.h Normal file
View File

@ -0,0 +1,48 @@
#ifndef SYM_TABLE_H
#define SYM_TABLE_H
#include <commons.h>
#include <vec.h>
#include <type.h>
struct sym {
struct table* parent;
char* name;
int is_var;
int addr;
struct type* type;
};
struct table {
struct table* prev;
struct vec syms;
};
struct sym_table {
struct table* root;
int addr_counter;
};
void sym_table_init(struct sym_table* self);
void sym_table_free(struct sym_table* self);
void sym_table_push_table(struct sym_table* self);
void sym_table_pop_table(struct sym_table* self);
struct sym* sym_table_try_by_name(struct sym_table* self, char* const name);
int sym_table_declare_const(struct sym_table* self,
char* const name,
struct type* new_type);
int sym_table_declare_var(struct sym_table* self,
char* const name,
struct type* new_type);
int sym_table_declare(struct sym_table* self,
char* const name,
struct type* new_type,
int is_var);
size_t sym_table_str(struct sym_table* self, char* buffer, size_t size);
#endif

View File

@ -1,191 +0,0 @@
#include "syms.h"
#include "commons.h"
#include "type.h"
#include "node.h"
void syms_init(struct syms* self)
{
assert(self);
vec_init(&self->types, 1);
vec_init(&self->entries, 1);
self->addr_counter = 0;
size_t k = 0;
syms_add_type(self, k++, TYPE_INT, 0);
syms_add_type(self, k++, TYPE_FLOAT, 0);
syms_add_type(self, k++, TYPE_BOOL, 0);
syms_add_type(self, k++, TYPE_STRING, 0);
}
void syms_free(struct syms* self)
{
assert(self);
for (size_t i=0; i<self->types.size; i++)
{
struct syms_type* st = self->types.data[i];
type_free(&st->type);
}
vec_free_elements(&self->types);
vec_free(&self->types);
vec_free_elements(&self->entries);
vec_free(&self->entries);
}
void syms_add_type(struct syms* self, size_t id, enum TypeKind type,
int count, ...)
{
va_list va;
va_start(va, count);
struct syms_type* ty = malloc(sizeof(struct syms_type));
ty->id = id;
type_init(&ty->type, type);
for (int i=0; i<count; i++)
{
type_add_subtype(&ty->type, va_arg(va, enum TypeKind));
}
vec_push(&self->types, ty);
va_end(va);
}
size_t syms_type_id(struct syms* self, enum TypeKind type)
{
assert(self);
for (size_t i=0; i<self->types.size; i++)
{
struct syms_type* ty = self->types.data[i];
if (ty->type.kind == type)
{
return ty->id;
}
}
fprintf(stderr, "type not found\n");
abort();
}
struct type* syms_try_type(struct syms* self, size_t id)
{
for (size_t i=0; i<self->types.size; i++)
{
struct syms_type* ty = self->types.data[i];
if (ty->id == id)
{
return &ty->type;
}
}
return NULL;
}
void syms_declare(struct syms* self, char* name,
size_t type, int is_var,
struct node* node)
{
assert(self);
struct syms_entry* entry = malloc(sizeof(struct syms_entry));
size_t sz = strlen(name);
if (sz > GUX_STR_SIZE)
{
sz = GUX_STR_SIZE;
}
memset(entry->name, 0, GUX_STR_SIZE);
memcpy(entry->name, name, sz);
entry->type = type;
entry->addr = self->addr_counter++;
entry->is_var = is_var;
entry->node = node;
entry->depth = 0;
struct node* itr = entry->node;
while (itr != NULL)
{
if (itr->type == NODE_BLOCK)
{
entry->depth++;
}
itr = itr->parent;
}
vec_push(&self->entries, entry);
}
struct syms_entry* syms_try_get(struct syms* self, char* name,
struct node* node)
{
assert(self);
struct syms_entry* res = NULL;
int max_depth = -1;
int depth = node ? node_depth(node) : 0;
for (size_t i=0; i<self->entries.size; i++)
{
struct syms_entry* entry = self->entries.data[i];
if (strcmp(entry->name, name) == 0 && entry->depth > max_depth
&& entry->depth <= depth)
{
if (node && entry->node && entry->depth == depth)
{
struct node* node_block =
node_try_find_parent(node, NODE_BLOCK);
struct node* entry_block =
node_try_find_parent(entry->node, NODE_BLOCK);
if (node_block == entry_block)
{
int node_index = node_block_index(node);
int entry_index = node_block_index(entry->node);
if (entry_index > node_index)
{
continue;
}
}
else
{
continue;
}
}
max_depth = entry->depth;
res = entry;
}
}
return res;
}
size_t syms_str(struct syms* self, char* buffer, size_t size)
{
assert(self);
assert(buffer);
size_t sz = 0;
for (size_t i=0; i<self->entries.size; i++)
{
struct syms_entry* entry = self->entries.data[i];
struct type* type = syms_try_type(self, entry->type);
sz += snprintf(buffer + sz, size - sz, "[%zu] ", entry->addr);
sz += type_str(type, buffer + sz, size - sz);
sz += snprintf(buffer + sz, size - sz, " %s, ", entry->name);
sz += snprintf(buffer + sz, size - sz, " depth=%d, ", entry->depth);
sz += snprintf(buffer + sz, size - sz, " block=%p\n", entry->node);
}
return sz;
}

View File

@ -1,49 +0,0 @@
#ifndef SYMS_H
#define SYMS_H
#include <commons.h>
#include <vec.h>
#include <type.h>
#define SYM_IS_VAR 1
#define SYM_IS_CONST 0
struct syms_type {
size_t id;
struct type type;
};
struct syms_entry {
char name[GUX_STR_SIZE];
size_t type;
size_t addr;
int is_var;
int depth;
struct node* node;
};
struct syms {
struct vec types;
struct vec entries;
size_t addr_counter;
};
void syms_init(struct syms* self);
void syms_free(struct syms* self);
void syms_add_type(struct syms* self, size_t id, enum TypeKind type,
int count, ...);
size_t syms_type_id(struct syms* self, enum TypeKind type);
struct type* syms_try_type(struct syms* self, size_t id);
void syms_declare(struct syms* self, char* name,
size_t type, int is_var,
struct node* node);
struct syms_entry* syms_try_get(struct syms* self, char* name,
struct node* node);
size_t syms_str(struct syms* self, char* buffer, size_t size);
#endif

View File

@ -11,6 +11,96 @@ void type_init(struct type* self, enum TypeKind kind)
vec_init(&self->subtypes, 1);
}
void type_init_from_node(struct type* self, struct node* node)
{
assert(self);
vec_init(&self->subtypes, 1);
if (node->type == NODE_TYPE && strcmp(node->value, "fun") == 0)
{
self->kind = TYPE_FUN;
int input = 1;
struct vec inputs;
vec_init(&inputs, 1);
struct type* output;
for (size_t i=0; i<node->children.size; i++)
{
struct node* comp = node->children.data[i];
if (comp->type == NODE_RARROW)
{
input = 0;
}
else if (input)
{
struct type* sub = malloc(sizeof(struct type));
type_init_from_node(sub, comp);
vec_push(&inputs, sub);
}
else
{
output = malloc(sizeof(struct type));
type_init_from_node(output, comp);
}
}
vec_push(&self->subtypes, output);
for (size_t i=0; i<inputs.size; i++)
{
vec_push(&self->subtypes, inputs.data[i]);
}
vec_free(&inputs);
}
else if (node->type == NODE_FUN)
{
self->kind = TYPE_FUN;
struct node* params = node->children.data[0];
struct node* ret = node->children.data[1];
struct type* ret_ty = malloc(sizeof(struct type));
type_init_from_node(ret_ty, ret);
vec_push(&self->subtypes, ret_ty);
for (size_t i=0; i<params->children.size; i++)
{
struct node* child = params->children.data[i];
if (child->type == NODE_TYPE)
{
struct type* param_ty = malloc(sizeof(struct type));
type_init_from_node(param_ty, child);
vec_push(&self->subtypes, param_ty);
}
}
}
else
{
self->kind = type_kind_from_str(self, node->value, NULL);
}
}
void type_copy(struct type* self, struct type* dest)
{
assert(self);
assert(dest);
type_free(dest);
type_init(dest, self->kind);
for (size_t i=0; i<self->subtypes.size; i++)
{
type_add_subtype(dest, TYPE_VOID);
type_copy(self->subtypes.data[i], dest->subtypes.data[i]);
}
}
void type_free(struct type* self)
{
for (size_t i=0; i<self->subtypes.size; i++)
@ -108,3 +198,38 @@ int type_is(struct type* self, char const* repr)
int result = strcmp(repr, buffer) == 0;
return result;
}
enum TypeKind type_kind_from_str(struct type* self, char const* str, int* err)
{
assert(self);
if (err) { *err = 0; }
if (strcmp(str, "int") == 0) // natives
{
return TYPE_INT;
}
else if (strcmp(str, "float") == 0)
{
return TYPE_FLOAT;
}
else if (strcmp(str, "bool") == 0)
{
return TYPE_BOOL;
}
else if (strcmp(str, "string") == 0)
{
return TYPE_STRING;
}
else if (strcmp(str, "void") == 0)
{
return TYPE_VOID;
}
if (err)
{
*err = 1;
}
return TYPE_VOID;
}

View File

@ -3,10 +3,11 @@
#include <commons.h>
#include <vec.h>
#include "node.h"
#define TYPE_KIND(G) \
G(TYPE_VOID), G(TYPE_BOOL), G(TYPE_INT), \
G(TYPE_FLOAT), G(TYPE_STRING)
G(TYPE_FLOAT), G(TYPE_STRING), G(TYPE_FUN)
GUX_ENUM_H(TypeKind, TYPE_KIND);
@ -16,8 +17,10 @@ struct type {
};
void type_init(struct type* self, enum TypeKind kind);
void type_init_from_node(struct type* self, struct node* node);
void type_free(struct type* self);
void type_copy(struct type* self, struct type* dest);
void type_clear(struct type* self);
int type_equals(struct type* self, struct type* rhs);
@ -25,4 +28,6 @@ void type_add_subtype(struct type* self, enum TypeKind kind);
size_t type_str(struct type* self, char* buffer, size_t size);
int type_is(struct type* self, char const* repr);
enum TypeKind type_kind_from_str(struct type* self, char const* str, int* err);
#endif

View File

@ -1,22 +1,26 @@
#include "type_checker.h"
#include "commons.h"
#include "node.h"
#include "sym_table.h"
#include "type.h"
#include "type_resolver.h"
#include "syms.h"
#include "fun.h"
void type_checker_init(struct type_checker* self, struct syms* syms)
void type_checker_init(struct type_checker* self)
{
assert(self);
self->syms = syms;
type_resolver_init(&self->resolver, self->syms);
sym_table_init(&self->sym_table);
type_resolver_init(&self->resolver, &self->sym_table);
memset(self->error_msg, 0, GUX_STR_SIZE);
vec_init(&self->fun_stack, 1);
}
void type_checker_free(struct type_checker* self)
{
assert(self);
type_resolver_free(&self->resolver);
sym_table_free(&self->sym_table);
vec_free(&self->fun_stack);
}
int type_checker_check(struct type_checker* self,
@ -27,6 +31,167 @@ int type_checker_check(struct type_checker* self,
switch (node->type)
{
case NODE_RETURN: {
struct node* ret = self->fun_stack.data[self->fun_stack.size - 1];
struct type fun_ty;
type_init_from_node(&fun_ty, ret);
struct type ret_ty;
type_init(&ret_ty, TYPE_VOID);
if (type_resolver_resolve(&self->resolver, node, &ret_ty) != 0)
{
return 1;
}
if (!type_equals(&fun_ty, &ret_ty))
{
type_checker_error_msg(self, node, &fun_ty, &ret_ty);
type_free(&ret_ty);
type_free(&fun_ty);
return 1;
}
type_free(&ret_ty);
type_free(&fun_ty);
} return 0;
case NODE_BLOCK: {
sym_table_push_table(&self->sym_table);
for (size_t i=0; i<node->children.size; i++)
{
struct node* child = node->children.data[i];
if ( type_checker_check(self, child) != 0 )
{
return 1;
}
}
sym_table_pop_table(&self->sym_table);
} return 0;
case NODE_ARGS:
case NODE_PARAMS: {
} return 0;
case NODE_CALL: {
struct node* target = node->children.data[0];
struct node* args = node->children.data[1];
struct sym* entry = sym_table_try_by_name(&self->sym_table,
target->value);
if (!entry)
{
self->error_line = node->line;
snprintf(self->error_msg, GUX_STR_SIZE,
"undefined function <%s>", target->value);
return 1;
}
struct type* ty = entry->type;
assert(ty);
if (ty->subtypes.size - 1 != args->children.size)
{
self->error_line = node->line;
snprintf(self->error_msg, GUX_STR_SIZE,
"wrong arity");
return 1;
}
} return 0;
case NODE_FUN: {
sym_table_push_table(&self->sym_table);
struct node* params = node->children.data[0];
struct node* ret_type = node->children.data[1];
struct node* body = node->children.data[2];
{
struct vec names;
vec_init(&names, 1);
for (size_t i=0; i<params->children.size; i++)
{
struct node* param = params->children.data[i];
if (param->type == NODE_TYPE)
{
for (size_t j=0; j<names.size; j++)
{
struct node* n = names.data[j];
struct type* ty = malloc(sizeof(struct type));
type_init_from_node(ty, param);
sym_table_declare_const(&self->sym_table,
n->value,
ty);
}
vec_free(&names);
vec_init(&names, 1);
}
else
{
vec_push(&names, param);
}
}
// check body
vec_push(&self->fun_stack, ret_type);
if (type_checker_check(self, body) != 0)
{
vec_free(&names);
return 1;
}
struct type ret_ty;
type_init_from_node(&ret_ty, ret_type);
struct vec ret_instrs;
vec_init(&ret_instrs, 1);
node_try_find_all(body, NODE_RETURN, &ret_instrs);
if (ret_ty.kind != TYPE_VOID && ret_instrs.size == 0)
{
snprintf(self->error_msg, GUX_STR_SIZE,
"missing return statement");
self->error_line = ret_type->line;
type_free(&ret_ty);
vec_free(&ret_instrs);
vec_free(&names);
return 1;
}
if (ret_ty.kind != TYPE_VOID && ret_instrs.size == 0)
{
snprintf(self->error_msg, GUX_STR_SIZE,
"missing return statement");
self->error_line = ret_type->line;
type_free(&ret_ty);
vec_free(&ret_instrs);
vec_free(&names);
return 1;
}
vec_pop(&self->fun_stack);
type_free(&ret_ty);
vec_free(&ret_instrs);
vec_free(&names);
sym_table_pop_table(&self->sym_table);
}
} return 0;
case NODE_WHILE: {
struct type have;
type_init(&have, TYPE_VOID);
@ -90,8 +255,8 @@ int type_checker_check(struct type_checker* self,
struct node* ident = node->children.data[0];
struct node* expr = node->children.data[1];
struct syms_entry* entry = syms_try_get(self->syms, ident->value,
node);
struct sym* entry = sym_table_try_by_name(&self->sym_table,
ident->value);
if (!entry)
{
@ -111,7 +276,7 @@ int type_checker_check(struct type_checker* self,
return 1;
}
struct type* var_type = syms_try_type(self->syms, entry->type);
struct type* var_type = entry->type;
struct type expr_type;
type_init(&expr_type, TYPE_VOID);
@ -130,11 +295,10 @@ int type_checker_check(struct type_checker* self,
case NODE_VARDECL:
case NODE_CONSTDECL:{
struct syms_entry* entry = syms_try_get(self->syms,
node->value,
node);
struct sym* entry = sym_table_try_by_name(&self->sym_table,
node->value);
if (entry && entry->depth == node_depth(node))
if (entry && entry->parent == self->sym_table.root)
{
snprintf(self->error_msg, GUX_STR_SIZE,
"%s is already defined", node->value);
@ -143,83 +307,60 @@ int type_checker_check(struct type_checker* self,
return 1;
}
char* type_name = NULL;
struct node* expr = NULL;
int is_var = node->type == NODE_VARDECL;
for (size_t i=0; i<node->children.size; i++)
{
type_checker_check(self, node->children.data[i]);
if (type_checker_check(self, node->children.data[i]) != 0)
{
return 1;
}
}
if (node->children.size == 1)
{
expr = node->children.data[0];
struct type ty;
type_init(&ty, TYPE_VOID);
if (type_resolver_resolve(&self->resolver, expr, &ty) != 0)
struct type* ty = malloc(sizeof(struct type));
type_init(ty, TYPE_VOID);
if (type_resolver_resolve(&self->resolver, expr, ty) != 0)
{
type_free(&ty);
type_free(ty);
free(ty);
return 1;
}
syms_declare(self->syms, node->value,
syms_type_id(self->syms, ty.kind), is_var,
node);
sym_table_declare(&self->sym_table,
node->value,
ty, is_var);
type_free(&ty);
}
else if (node->children.size == 2)
{
expr = node->children.data[1];
type_name = ((struct node*) node->children.data[0])->value;
struct type ty;
if (strcmp(type_name, "int") == 0)
{
type_init(&ty, TYPE_INT);
}
else if (strcmp(type_name, "float") == 0)
{
type_init(&ty, TYPE_FLOAT);
}
else if (strcmp(type_name, "bool") == 0)
{
type_init(&ty, TYPE_BOOL);
}
else if (strcmp(type_name, "string") == 0)
{
type_init(&ty, TYPE_STRING);
}
else
{
snprintf(self->error_msg, GUX_STR_SIZE,
"unknown type <%s>",
type_name);
self->error_line = node->line;
return 1;
}
struct type* ty = malloc(sizeof(struct type));
type_init_from_node(ty, node->children.data[0]);
struct type expr_ty;
type_init(&expr_ty, TYPE_VOID);
if (type_resolver_resolve(&self->resolver, expr, &expr_ty) != 0)
{
type_free(&expr_ty);
type_free(&ty);
type_free(ty);
free(ty);
return 1;
}
if (!type_equals(&ty, &expr_ty))
if (!type_equals(ty, &expr_ty))
{
char ty0[GUX_STR_SIZE / 3];
type_str(&expr_ty, ty0, GUX_STR_SIZE/3);
char ty1[GUX_STR_SIZE / 3];
type_str(&ty, ty1, GUX_STR_SIZE/3);
type_str(ty, ty1, GUX_STR_SIZE/3);
snprintf(self->error_msg, GUX_STR_SIZE,
"mismatch type: expected <%s>, got <%s>",
@ -228,16 +369,16 @@ int type_checker_check(struct type_checker* self,
self->error_line = node->line;
type_free(&ty);
type_free(ty);
free(ty);
type_free(&expr_ty);
return 1;
}
syms_declare(self->syms, node->value,
syms_type_id(self->syms, ty.kind), is_var, node);
sym_table_declare(&self->sym_table, node->value,
ty, is_var);
type_free(&ty);
type_free(&expr_ty);
}
} return 0;

View File

@ -7,13 +7,14 @@
#include <type_resolver.h>
struct type_checker {
struct syms* syms;
struct sym_table sym_table;
struct type_resolver resolver;
char error_msg[GUX_STR_SIZE];
int error_line;
struct vec fun_stack;
};
void type_checker_init(struct type_checker* self, struct syms* syms);
void type_checker_init(struct type_checker* self);
void type_checker_free(struct type_checker* self);
int type_checker_check(struct type_checker* self,
@ -27,5 +28,4 @@ void type_checker_error_msg(struct type_checker* self,
struct node* node,
struct type* want,
struct type* have);
#endif

View File

@ -1,12 +1,12 @@
#include "type_resolver.h"
#include "node.h"
#include "syms.h"
#include "type.h"
void type_resolver_init(struct type_resolver* self, struct syms* syms)
void type_resolver_init(struct type_resolver* self,
struct sym_table* sym_table)
{
assert(self);
self->syms = syms;
self->sym_table = sym_table;
}
void type_resolver_free(struct type_resolver* self)
@ -26,12 +26,42 @@ int type_resolver_resolve(struct type_resolver* self,
switch (node->type)
{
case NODE_RETURN: {
if (node->children.size == 0)
{
struct type ty;
type_init(&ty, TYPE_VOID);
type_copy(&ty, type);
type_free(&ty);
return 0;
}
return type_resolver_resolve(self, node->children.data[0], type);
};
case NODE_CALL: {
struct type call_type;
type_init(&call_type, TYPE_VOID);
if (type_resolver_resolve(self, node->children.data[0], &call_type) == 0)
{
type_copy(call_type.subtypes.data[0], type);
}
type_free(&call_type);
} return 0;
case NODE_FUN: {
struct type ty;
type_init_from_node(&ty, node);
type_copy(&ty, type);
type_free(&ty);
} return 0;
case NODE_ASSIGN: {
return type_resolver_resolve(self, node->children.data[1], type);
} return 0;
case NODE_BLOCK: {
size_t last = node->children.size - 1;
return type_resolver_resolve(self, node->children.data[last], type);
@ -39,30 +69,46 @@ int type_resolver_resolve(struct type_resolver* self,
case NODE_VARDECL:
case NODE_CONSTDECL: {
struct type* ty = malloc(sizeof(struct type));
type_init(ty, TYPE_VOID);
if (node->children.size == 1)
{
type_resolver_resolve(self, node->children.data[0], type);
type_resolver_resolve(self, node->children.data[0], ty);
}
else
{
type_resolver_resolve(self, node->children.data[1], type);
type_resolver_resolve(self, node->children.data[1], ty);
}
type_copy(ty, type);
sym_table_declare(self->sym_table, node->value, ty,
node->type == NODE_VARDECL);
} return 0;
case NODE_IDENT: {
struct syms_entry* entry = syms_try_get(self->syms,
node->value,
node);
struct sym* entry = sym_table_try_by_name(self->sym_table,
node->value);
if (strcmp(node->value, "this") == 0)
{
struct node* fun = node_try_find_parent(node, NODE_FUN);
struct type ty;
type_init_from_node(&ty, fun);
type_copy(&ty, type);
type_free(&ty);
return 0;
}
if (!entry)
{
return 1;
}
struct type* ty = syms_try_type(self->syms, entry->type);
type_copy(entry->type, type);
type->kind = ty->kind;
} return 0;
case NODE_EQ:

View File

@ -4,12 +4,14 @@
#include <commons.h>
#include <node.h>
#include <type.h>
#include "sym_table.h"
struct type_resolver {
struct syms* syms;
struct sym_table* sym_table;
};
void type_resolver_init(struct type_resolver* self, struct syms* syms);
void type_resolver_init(struct type_resolver* self,
struct sym_table* sym_table);
void type_resolver_free(struct type_resolver* self);
int type_resolver_resolve(struct type_resolver* self,

View File

@ -1,4 +1,6 @@
#include "value.h"
#include "type.h"
#include "fun.h"
void value_init_bool(struct value* self, int value, int line)
{
@ -37,16 +39,49 @@ void value_init_string(struct value* self, char* value, int line)
self->line = line;
}
void value_init_new_fun(struct value* self, struct fun* value, int line)
{
assert(self);
assert(value->node);
type_init_from_node(&self->type, value->node);
self->data.fun = value;
self->line = line;
}
void value_free(struct value* self)
{
assert(self);
if (self->type.kind == TYPE_STRING)
{
free(self->data.s);
}
else if (self->type.kind == TYPE_FUN)
{
fun_free(self->data.fun);
free(self->data.fun);
}
type_free(&self->type);
}
struct value* value_new_clone(struct value* self)
{
assert(self);
struct value* clone = malloc(sizeof(struct value));
type_init(&clone->type, TYPE_VOID);
type_copy(&self->type, &clone->type);
clone->data = self->data;
if (clone->type.kind == TYPE_FUN)
{
clone->data.fun = fun_new_clone(self->data.fun);
}
return clone;
}
size_t value_str(struct value* self, char* buffer, size_t size)
{
assert(self);
@ -54,6 +89,12 @@ size_t value_str(struct value* self, char* buffer, size_t size)
size_t sz = 0;
if (self->type.kind == TYPE_FUN)
{
sz += snprintf(buffer + sz, size - sz, "<function>");
return sz;
}
if (self->type.subtypes.size == 0)
{
if (self->type.kind == TYPE_VOID)

View File

@ -12,6 +12,7 @@ union value_data {
char* s;
float f;
int i;
struct fun* fun;
};
struct value {
@ -24,9 +25,12 @@ void value_init_bool(struct value* self, int value, int line);
void value_init_int(struct value* self, int value, int line);
void value_init_float(struct value* self, float value, int line);
void value_init_string(struct value* self, char* value, int line);
void value_init_new_fun(struct value* self, struct fun* value, int line);
void value_free(struct value* self);
struct value* value_new_clone(struct value* self);
size_t value_str(struct value* self, char* buffer, size_t size);
struct value* value_try_new_and(struct value* self, struct value* rhs);

View File

@ -130,3 +130,7 @@ Test(lexer, flow_control) {
test_lexer("if else cond while for break continue", 7,
"IF", "ELSE", "COND", "WHILE", "FOR", "BREAK", "CONTINUE");
}
Test(lexer, fun) {
test_lexer("-> fun return,", 4, "RARROW", "FUN", "RETURN", "COMMA");
}

View File

@ -159,3 +159,46 @@ Test(parser, while_break_continue) {
test_parser("ROOT(WHILE(BOOL[true],BLOCK(BREAK,CONTINUE)))",
"while true { break; continue; }");
}
Test(parser, fun) {
test_parser("ROOT(FUN(PARAMS(IDENT[x],TYPE[int],IDENT[y],TYPE[float]),"
"TYPE[int],BLOCK(RETURN(IDENT[x]))))",
"fun (x: int, y: float) -> int { return x; };");
test_parser("ROOT(FUN(PARAMS(IDENT[x],TYPE[int],IDENT[y],TYPE[float]),"
"TYPE[void],BLOCK(RETURN(INT[8]))))",
"fun (x: int, y: float) { return 8; };");
}
Test(parser, types) {
test_parser("ROOT(CONSTDECL[x]("
"TYPE[fun](TYPE[int],TYPE[int],RARROW,TYPE[float]),INT[0]))",
"x : (int int -> float) = 0;");
}
Test(parser, fun_call) {
test_parser("ROOT(CALL(IDENT[k],ARGS))",
"k();");
test_parser("ROOT(CALL(IDENT[f],ARGS(IDENT[x],IDENT[y])))",
"f(x, y);");
test_parser("ROOT(CALL(IDENT[f],ARGS(IDENT[x],IDENT[y]),ARGS(IDENT[z])))",
"f(x, y)(z);");
test_parser("ROOT(CALL(INT[72],ARGS(IDENT[a])))",
"72(a);");
}
Test(parser, fun_decl) {
test_parser("ROOT(CONSTDECL[hello](FUN(PARAMS(IDENT[n],TYPE[int]),"
"TYPE[int],BLOCK(RETURN(IDENT[n])))))",
"fun hello (n: int) -> int { return n; }");
}
Test(parser, param_sugar) {
test_parser("ROOT(CONSTDECL[hello](FUN(PARAMS(IDENT[n],TYPE[int],"
"IDENT[m],TYPE[int],IDENT[k],TYPE[int]),"
"TYPE[int],BLOCK(RETURN(IDENT[n])))))",
"fun hello (n, m, k: int) -> int { return n; }");
}

91
lang/tests/sym_table.c Normal file
View File

@ -0,0 +1,91 @@
#include <criterion/criterion.h>
#include <sym_table.h>
#include <type.h>
Test(sym_table, simple) {
struct sym_table table;
sym_table_init(&table);
struct sym* sym = sym_table_try_by_name(&table, "hello");
cr_assert_eq(sym, 0);
struct type* ty = malloc(sizeof(struct type));
type_init(ty, TYPE_INT);
int err = sym_table_declare_const(&table, "hello", ty);
cr_assert_eq(err, 0);
sym = sym_table_try_by_name(&table, "hello");
cr_assert_neq(sym, 0);
cr_assert_str_eq("hello", sym->name);
sym_table_free(&table);
}
Test(sym_table, already_exists) {
struct sym_table table;
sym_table_init(&table);
struct type* ty = malloc(sizeof(struct type));
type_init(ty, TYPE_INT);
int err = sym_table_declare_const(&table, "hello", ty);
cr_assert_eq(err, 0);
err = sym_table_declare_const(&table, "hello", ty);
cr_assert_eq(err, 1);
sym_table_free(&table);
}
Test(sym_table, scope) {
struct sym_table table;
sym_table_init(&table);
struct type* ty_int = malloc(sizeof(struct type));
type_init(ty_int, TYPE_INT);
sym_table_declare_const(&table, "abc", ty_int);
sym_table_push_table(&table);
struct type* ty_float = malloc(sizeof(struct type));
type_init(ty_float, TYPE_FLOAT);
sym_table_declare_const(&table, "abc", ty_float);
sym_table_push_table(&table);
struct type* ty_string = malloc(sizeof(struct type));
type_init(ty_string, TYPE_STRING);
sym_table_declare_const(&table, "abc", ty_string);
struct sym* sym;
sym = sym_table_try_by_name(&table, "abc");
cr_assert_eq(sym->type->kind, TYPE_STRING);
sym_table_pop_table(&table);
sym = sym_table_try_by_name(&table, "abc");
cr_assert_eq(sym->type->kind, TYPE_FLOAT);
sym_table_pop_table(&table);
sym = sym_table_try_by_name(&table, "abc");
cr_assert_eq(sym->type->kind, TYPE_INT);
sym_table_free(&table);
}
Test(sym_table, outer_scope) {
struct sym_table table;
sym_table_init(&table);
struct type* ty_int = malloc(sizeof(struct type));
type_init(ty_int, TYPE_INT);
sym_table_declare_const(&table, "abc", ty_int);
sym_table_push_table(&table);
sym_table_push_table(&table);
sym_table_push_table(&table);
struct sym* sym = sym_table_try_by_name(&table, "abc");
cr_assert_eq(sym->type->kind, TYPE_INT);
sym_table_free(&table);
}

View File

@ -3,7 +3,7 @@
#include <parser.h>
#include <parser.h>
#include <type_checker.h>
#include <syms.h>
#include <sym_table.h>
static void test_check_ok(char const* source)
{
@ -13,20 +13,16 @@ static void test_check_ok(char const* source)
struct node* ast = parser_try_new_root(&parser, source);
cr_assert_neq(ast, NULL);
struct syms syms;
syms_init(&syms);
struct type_checker tc;
type_checker_init(&tc, &syms);
type_checker_init(&tc);
char buf[GUX_STR_SIZE];
node_str(ast, buf, GUX_STR_SIZE);
cr_assert_eq(type_checker_check(&tc, ast), 0,
"type checker failed: %s", buf);
"%s, %s", source, tc.error_msg);
type_checker_free(&tc);
syms_free(&syms);
node_free(ast);
free(ast);
@ -39,17 +35,14 @@ static void test_check_ko(char const* source)
parser_init(&parser);
struct node* ast = parser_try_new_root(&parser, source);
cr_assert_neq(ast, NULL, "NULL: %s", source);
struct syms syms;
syms_init(&syms);
cr_assert_neq(ast, NULL, "cannot parse: %s", source);
struct type_checker tc;
type_checker_init(&tc, &syms);
type_checker_init(&tc);
cr_assert_neq(type_checker_check(&tc, ast), 0, "%s == null", source);
cr_assert_neq(type_checker_check(&tc, ast), 0,
"%s shouldn't pass check test", source);
syms_free(&syms);
type_checker_free(&tc);
node_free(ast);
@ -178,3 +171,23 @@ Test(type_checker, while_loop) {
test_check_ko("while 5.0 {}");
test_check_ko("while 'bim' {}");
}
Test(type_checker, fun) {
test_check_ok("hello := fun() {};");
test_check_ok("hello := fun() -> void {0;};");
test_check_ok("hello := fun() -> int { return 0; };");
test_check_ok("hello := fun(n: int) -> int { return n * 2; };");
test_check_ko("hello := fun() -> int {};");
test_check_ko("hello := fun() -> bool { return 3.1; };");
test_check_ko("hello := fun() -> bool { return true; return 'salut'; };");
test_check_ko("hello := fun(n: float) -> int { return n; };");
test_check_ok("hello := fun() -> int { return 4;}; x : int = hello();");
test_check_ko("hello := fun() -> float { return 4.2;}; x : int = hello();");
test_check_ko("hello := fun() -> int { return 0;}; hello(1);");
test_check_ko("hello := fun(x: int, y: int) -> int { return 0;}; hello(1);");
}

View File

@ -9,7 +9,7 @@
#include <ctype.h>
#include <stdarg.h>
#define GUX_STR_SIZE 512
#define GUX_STR_SIZE 1024
#define GUX_ENUM_IDENT(X) X
#define GUX_ENUM_STR(X) #X
#define GUX_ENUM_H(Prefix, Types) \
@ -22,4 +22,7 @@
#define GUX_RET_ERROR 1
#define GUX_RET_ASSERT 2
#define GUX_EPRINT(OBJECT, FUNC) \
{char m[512]; FUNC(OBJECT, m, 512); printf("%s\n", m);}
#endif

67
tests/fun.gux Normal file
View File

@ -0,0 +1,67 @@
double := fun (n: int) -> int {
return n * 2;
};
assert double(2) == 4;
assert double(18 + 3) == 42;
assert double(double(-3)) == -12;
fac := fun (n: int) -> int {
if n == 0 { return 1; }
return n * this(n - 1);
};
assert fac(5) == 120;
inner_val := fun () -> int {
n := 28;
return n;
};
assert inner_val() == 28;
inner_fun := fun (n: int) -> int {
f := fun (n: int) -> int {
return n * 2;
};
return f(f(n));
};
assert inner_fun(4) == 16;
twice := fun (n: int, f: (int -> int)) -> int {
return f(f(n));
};
incr := fun (n: int) -> int {
return n + 1;
};
dble := fun (n: int) -> int {
return n * 2;
};
assert twice(4, incr) == 6;
assert twice(4, dble) == 16;
assert twice(3, fun (x: int) -> int {
return x + 1;
} ) == 5;
fun sugar(n: int) -> int {
return n * 2;
}
assert sugar(21) == 42;
fun add3(x, y, z: int) -> int {
return x + y + z;
}
assert add3(2, 4, 6) == 12;
fun empty(n: string) {
return;
}
empty('useless');

View File

@ -5,7 +5,7 @@ TOTAL=0
for file in $(find . -name "*.gux" | sort)
do
MSG=$(guxi $file 2>&1)
MSG=$(gux $file 2>&1)
RET=$?
echo -en "$file -> "

View File

@ -9,13 +9,13 @@ add_library(gux-vm OBJECT
set_property(TARGET gux-vm PROPERTY C_STANDARD 99)
add_dependencies(gux-vm gux-bc)
add_dependencies(gux-vm gux-lang)
target_include_directories(gux-vm
PUBLIC gux-bc
PUBLIC gux-lang
PUBLIC ${CMAKE_SOURCE_DIR}/vm/src
)
target_link_libraries(gux-vm
PUBLIC gux-bc
PUBLIC gux-lang
)

View File

@ -4,6 +4,7 @@
#include "type.h"
#include "value.h"
#include "vec.h"
#include "fun.h"
void vm_init(struct vm* self)
{
@ -11,6 +12,9 @@ void vm_init(struct vm* self)
self->pc = 0;
self->fp = 0;
self->error_line = 0;
memset(self->error_msg, 0, GUX_STR_SIZE);
vm_add_frame(self);
}
@ -33,6 +37,7 @@ void vm_add_frame(struct vm* self)
assert(self);
self->stack[self->fp] = malloc(sizeof(struct frame));
self->stack[self->fp]->sp = 0;
self->stack[self->fp]->return_address = 0;
vec_init(&self->stack[self->fp]->locals, 1);
self->fp++;
@ -73,7 +78,8 @@ int vm_load(struct vm* self, int addr)
}
}
assert(0);
fprintf(stderr, "cannot load addr %d\n", addr);
abort();
}
void vm_store(struct vm* self, int addr)
@ -124,6 +130,71 @@ int vm_exec(struct vm* self, struct program* program)
switch (opcode)
{
case OP_CALL: {
int fun_addr = vm_pop(self);
struct value* fun_val = program->constant_pool.data[fun_addr];
struct fun* fun = fun_val->data.fun;
struct vec args;
vec_init(&args, 1);
for (int i=0; i<param; i++)
{
int* addr = malloc(sizeof(int));
*addr = vm_pop(self);
vec_push(&args, addr);
}
vm_add_frame(self);
struct frame* my_frame = self->stack[self->fp - 1];
for (size_t i=0; i<args.size; i++)
{
size_t k = args.size - 1 - i;
int* addr = args.data[k];
struct value* val =
value_new_clone(program->constant_pool.data[*addr]);
size_t new_addr = program_push_constant(&fun->program, val);
vm_push(self, new_addr);
vm_store(self, i);
}
struct value* new_fun =
value_new_clone(program->constant_pool.data[fun_addr]);
size_t new_addr = program_push_constant(&fun->program, new_fun);
vm_push(self, new_addr);
vm_store(self, args.size);
size_t ret_addr = self->pc;
self->pc = 0;
vm_exec(self, &fun->program);
vec_free_elements(&args);
vec_free(&args);
struct value* ret_val =
fun->program.constant_pool.data[my_frame->stack[my_frame->sp - 1]];
struct value* new_ret = value_new_clone(ret_val);
vm_remove_frame(self);
vm_push(self, program_push_constant(program, new_ret));
self->pc = ret_addr + 1;
} break;
case OP_RET: {
return 0;
} break;
case OP_SWAP: {
assert(frame->sp > 1);
int tmp = frame->stack[frame->sp - 1];

View File

@ -16,6 +16,7 @@ struct frame {
int stack[STACK_DEPTH];
size_t sp;
struct vec locals;
int return_address;
};
struct vm {