From 4d0edad298df38195aa0d7e2c0ce486abe559279 Mon Sep 17 00:00:00 2001 From: bog Date: Sun, 7 Apr 2024 20:43:13 +0200 Subject: [PATCH] :sparkles: anonymous modules. --- cli/main.c | 2 +- doc/grammar.bnf | 7 ++- features/mod.sk | 12 ++++ lib/include/compiler.h | 9 ++- lib/include/module.h | 12 ++-- lib/include/node.h | 3 +- lib/include/parser.h | 2 + lib/include/prog.h | 2 +- lib/include/state.h | 6 ++ lib/include/sym.h | 2 + lib/include/token.h | 3 +- lib/include/value.h | 3 +- lib/src/compiler.c | 92 +++++++++++++++++++++++++++ lib/src/exec.c | 24 ++++++- lib/src/lexer.c | 5 +- lib/src/module.c | 62 ++++++++++++++---- lib/src/parser.c | 139 ++++++++++++++++++++++++++++++++++++----- lib/src/state.c | 117 +++++++++++++++++++++++++++++++++- lib/src/sym.c | 27 ++++++++ lib/src/value.c | 17 +++++ tests/lexer.h | 8 +++ tests/parser.h | 14 +++++ 22 files changed, 525 insertions(+), 43 deletions(-) create mode 100644 features/mod.sk diff --git a/cli/main.c b/cli/main.c index 20762b5..acb9732 100644 --- a/cli/main.c +++ b/cli/main.c @@ -8,7 +8,7 @@ int main(int argc, char** argv) { errors_init(); struct module module; - module_init(&module); + module_init(&module, argv[1]); module_load_source(&module, argv[1]); int status = module_compile(&module); diff --git a/doc/grammar.bnf b/doc/grammar.bnf index 038d0a6..1402dab 100644 --- a/doc/grammar.bnf +++ b/doc/grammar.bnf @@ -9,6 +9,8 @@ EXPR ::= | IF | return EXPR | FUN_DECL +| MOD_ACCESS +MOD_ACCESS ::= EXPR mod_access ident FUN_DECL ::= | fun ident opar PARAMS cpar EXPR* end IF ::= if EXPR BLOCK (else (BLOCK | IF))? @@ -32,7 +34,10 @@ LITERAL ::= | ident | FUN | CALL -CALL ::= ident opar ARGS cpar +| MODULE +MODULE ::= module EXPR* end +CALL ::= +| (ident|MOD_ACCESS) opar ARGS cpar ARGS ::= (EXPR (comma EXPR)*)? FUN ::= fun opar PARAMS cpar EXPR* end PARAMS ::= (EXPR (comma EXPR)*)? diff --git a/features/mod.sk b/features/mod.sk new file mode 100644 index 0000000..4fe721b --- /dev/null +++ b/features/mod.sk @@ -0,0 +1,12 @@ +var m = module + var x = 32 + var y = "bim" + + fun add(x, y) + return x + y + end +end + +assert m::x eq 32 +assert m::y eq "bim" +assert m::add(7, 2) eq 9 diff --git a/lib/include/compiler.h b/lib/include/compiler.h index 5206ac5..8fa5c1e 100644 --- a/lib/include/compiler.h +++ b/lib/include/compiler.h @@ -7,11 +7,18 @@ struct state; +struct mod +{ + char* name; + struct module* module; +}; + struct compiler { struct vec var_names; + struct vec modules; }; - +void mod_free(struct mod* self); void compiler_init(struct compiler* self); void compiler_free(struct compiler* self); diff --git a/lib/include/module.h b/lib/include/module.h index 7ed8bf9..68bf8e4 100644 --- a/lib/include/module.h +++ b/lib/include/module.h @@ -8,16 +8,18 @@ struct module { + char* name; struct str source; - struct prog prog; - struct sym sym; - struct state state; + struct prog* prog; + struct sym* sym; + struct state* state; }; -void module_init(struct module* self); +void module_init(struct module* self, char const* name); +struct module* module_new_clone(struct module* self); void module_free(struct module* self); -void module_load_source(struct module* self, +void module_load_source(struct module* self, char const* path); int module_compile(struct module* self); diff --git a/lib/include/node.h b/lib/include/node.h index 2eabd45..f61006d 100644 --- a/lib/include/node.h +++ b/lib/include/node.h @@ -15,7 +15,8 @@ G(NODE_LT), G(NODE_LE), G(NODE_GT), G(NODE_GE), \ G(NODE_EQUAL), G(NODE_NOT_EQUAL), G(NODE_VAR_DECL), \ G(NODE_CONST_DECL), G(NODE_IDENT), G(NODE_ASSIGN), \ G(NODE_BLOCK), G(NODE_IF), G(NODE_FUN), G(NODE_PARAMS), \ -G(NODE_RETURN), G(NODE_CALL), G(NODE_ARGS) +G(NODE_RETURN), G(NODE_CALL), G(NODE_ARGS), G(NODE_MODULE), \ +G(NODE_MOD_ACCESS) SK_ENUM_H(NodeKind, NODE_KIND); diff --git a/lib/include/parser.h b/lib/include/parser.h index c526470..4dc9280 100644 --- a/lib/include/parser.h +++ b/lib/include/parser.h @@ -37,6 +37,8 @@ struct node* parser_try_usub(struct parser* self); struct node* parser_try_not(struct parser* self); struct node* parser_try_pow(struct parser* self); struct node* parser_try_literal(struct parser* self); +struct node* parser_try_mod_access(struct parser* self); +struct node* parser_try_module(struct parser* self); struct node* parser_try_call(struct parser* self); struct node* parser_try_args(struct parser* self); struct node* parser_try_fun(struct parser* self); diff --git a/lib/include/prog.h b/lib/include/prog.h index 3eb2372..c86b6c0 100644 --- a/lib/include/prog.h +++ b/lib/include/prog.h @@ -15,7 +15,7 @@ G(OP_BR), G(OP_BRF), G(OP_LT), G(OP_GT), \ G(OP_EQUAL), G(OP_LOCAL_STORE), G(OP_LOCAL_LOAD), \ G(OP_CALL), G(OP_RET), G(OP_MAKE_REF), \ G(OP_CLOSURE_LOAD), G(OP_CLOSURE_STORE), \ -G(OP_GLOBAL_LOAD) +G(OP_GLOBAL_LOAD), G(OP_MODULE_LOAD) SK_ENUM_H(Opcode, OPCODE); diff --git a/lib/include/state.h b/lib/include/state.h index bb22b4c..0fa7d5b 100644 --- a/lib/include/state.h +++ b/lib/include/state.h @@ -50,9 +50,11 @@ void stack_value_init(struct stack_value* self, void stack_value_free(struct stack_value* self); void frame_init(struct frame* self); +struct frame* frame_new_clone(struct frame* self); void frame_free(struct frame* self); void state_init(struct state* self); +struct state* state_new_clone(struct state* self); void state_free(struct state* self); SK state_make_ref(struct state* self); @@ -79,6 +81,7 @@ SK state_push_float(struct state* self, double real, int line); SK state_push_string(struct state* self, char const* str, int line); SK state_push_fun(struct state* self, struct fun* fun, int line); SK state_push_ref(struct state* self, size_t ref, int line); +SK state_push_mod(struct state* self, struct module* mod, int line); struct local* state_try_get_local(struct state* self, int id); @@ -97,6 +100,9 @@ void state_global_load(struct state* self, void state_closure_load(struct state* self, int id); +void state_module_load(struct state* self, + int id); + TypeKind state_common_num_type(struct state* self, SK lhs, SK rhs); TypeKind state_type(struct state* self, SK value); double state_as_real(struct state* self, SK lhs); diff --git a/lib/include/sym.h b/lib/include/sym.h index 5d0826b..143a926 100644 --- a/lib/include/sym.h +++ b/lib/include/sym.h @@ -36,6 +36,7 @@ struct env* env_new_clone(struct env* self); void env_free(struct env* self); struct symbol* env_try_get(struct env* self, char const* name); +struct symbol* env_try_get_by_id(struct env* self, int id); void symbol_init(struct symbol* self, int id, @@ -57,5 +58,6 @@ void sym_open_scope(struct sym* self); void sym_close_scope(struct sym* self); struct symbol* sym_try_get(struct sym* self, char const* name); +struct symbol* sym_try_get_by_id(struct sym* self, int id); #endif diff --git a/lib/include/token.h b/lib/include/token.h index c86d97c..16e5c2a 100644 --- a/lib/include/token.h +++ b/lib/include/token.h @@ -16,7 +16,8 @@ G(TOKEN_LT), G(TOKEN_LE), G(TOKEN_GT), G(TOKEN_GE), \ G(TOKEN_EQUAL), G(TOKEN_NOT_EQUAL), G(TOKEN_VAR), \ G(TOKEN_CONST), G(TOKEN_ASSIGN), G(TOKEN_IDENT), \ G(TOKEN_BEGIN), G(TOKEN_END), G(TOKEN_IF), G(TOKEN_ELSE), \ -G(TOKEN_FUN), G(TOKEN_RETURN), G(TOKEN_COMMA) +G(TOKEN_FUN), G(TOKEN_RETURN), G(TOKEN_COMMA), G(TOKEN_MODULE), \ +G(TOKEN_MOD_ACCESS) SK_ENUM_H(TokenKind, TOKEN_KIND); diff --git a/lib/include/value.h b/lib/include/value.h index 091b934..96313c0 100644 --- a/lib/include/value.h +++ b/lib/include/value.h @@ -8,7 +8,7 @@ #define TYPE_KIND(G) \ G(TYPE_INT), G(TYPE_BOOL), G(TYPE_FLOAT), \ G(TYPE_STRING), G(TYPE_FUN), G(TYPE_REF), \ -G(TYPE_NATIVE_FUN) +G(TYPE_NATIVE_FUN), G(TYPE_MODULE) SK_ENUM_H(TypeKind, TYPE_KIND); @@ -21,6 +21,7 @@ union val struct fun* fun; struct nfun* nfun; size_t ref; + struct module* mod; }; struct value diff --git a/lib/src/compiler.c b/lib/src/compiler.c index 92e78e5..fa1050f 100644 --- a/lib/src/compiler.c +++ b/lib/src/compiler.c @@ -2,17 +2,26 @@ #include "token.h" #include "state.h" #include "natives.h" +#include "module.h" void compiler_init(struct compiler* self) { assert(self); vec_init(&self->var_names); + vec_init(&self->modules); +} + +void mod_free(struct mod* self) +{ + free(self->name); } void compiler_free(struct compiler* self) { assert(self); vec_free(&self->var_names); + vec_free_elements(&self->modules, (void*) mod_free); + vec_free(&self->modules); } void compiler_compile(struct compiler* self, @@ -209,6 +218,89 @@ void compiler_compile(struct compiler* self, prog_add_instr(prog, OP_RET, SK_NO_PARAM); } break; + case NODE_MODULE: { + char* name = ""; + + if (self->var_names.size > 0) + { + name = self->var_names.data[ + self->var_names.size - 1 + ]; + } + + struct module* mod = malloc(sizeof(struct module)); + module_init(mod, name); + + for (size_t i=0; ichildren.size; i++) + { + struct node* child = node->children.data[i]; + + compiler_compile( + self, + child, + mod->prog, + mod->sym, + mod->state + ); + } + + struct value* val = malloc(sizeof(struct value)); + union val v; + v.mod = mod; + value_init(val, TYPE_MODULE, v, node->token->line); + int id = prog_add_constant(prog, val); + prog_add_instr(prog, OP_PUSH, id); + prog_add_instr(prog, OP_MAKE_REF, SK_NO_PARAM); + + struct mod* mymod = malloc(sizeof(struct mod)); + mymod->name = strdup(name); + mymod->module = mod; + vec_push(&self->modules, mymod); + + } break; + + case NODE_MOD_ACCESS: { + struct node* mod_name = node->children.data[0]; + struct node* target = node->children.data[1]; + + struct mod* mod = NULL; + + for (size_t i=0; imodules.size; i++) + { + struct mod* m = self->modules.data[i]; + + if (strcmp(m->name, mod_name->token->value) == 0) + { + mod = m; + break; + } + } + + if (!mod) + { + errors_push(node->token->line, + "unknown module '%s'.", + mod_name->token->value); + } + + struct symbol* symbol = sym_try_get( + mod->module->sym, + target->token->value + ); + + assert(symbol); + + compiler_compile( + self, + mod_name, + prog, + sym, + state + ); + + prog_add_instr(prog, OP_MODULE_LOAD, symbol->id); + } break; + case NODE_FUN: { struct fun* fun = malloc(sizeof(struct fun)); struct prog* p = malloc(sizeof(struct prog)); diff --git a/lib/src/exec.c b/lib/src/exec.c index 8f73362..e07490e 100644 --- a/lib/src/exec.c +++ b/lib/src/exec.c @@ -2,6 +2,7 @@ #include "sym.h" #include "fun.h" #include "nfun.h" +#include "module.h" void exec_init(struct exec* self) { @@ -55,6 +56,10 @@ void exec_execute(struct exec* self, self->pc++; } break; + case OP_MODULE_LOAD: { + state_module_load(state, param); + self->pc++; + } break; case OP_ASSERT_EQ: { SK rhs = state_pop(state); SK lhs = state_pop(state); @@ -117,7 +122,6 @@ void exec_execute(struct exec* self, state, f->val.ref ); - assert(val_fun); if (val_fun->type == TYPE_NATIVE_FUN) @@ -224,6 +228,24 @@ void exec_execute(struct exec* self, ); } break; + case TYPE_MODULE: { + struct module* mod = + constant->val.mod; + + struct exec exec; + exec_init(&exec); + + exec_execute(&exec, mod->state, mod->prog); + + exec_free(&exec); + + state_push_mod( + state, + mod, + constant->line + ); + } break; + case TYPE_INT: { state_push_int( state, diff --git a/lib/src/lexer.c b/lib/src/lexer.c index f733d6c..d759323 100644 --- a/lib/src/lexer.c +++ b/lib/src/lexer.c @@ -90,7 +90,8 @@ bool lexer_is_sep(struct lexer* self, size_t index) || c == '<' || c == '>' || c == ',' - || c == '='; + || c == '=' + || c == ':'; } bool lexer_next_nth_is(struct lexer* self, TokenKind kind, int nth) @@ -179,6 +180,7 @@ struct token* lexer_try_new_next(struct lexer* self) { return tok; } + SK_SCAN_TEXT("::", TOKEN_MOD_ACCESS); SK_SCAN_TEXT("<=", TOKEN_LE); SK_SCAN_TEXT(">=", TOKEN_GE); SK_SCAN_TEXT("==", TOKEN_EQUAL); @@ -199,6 +201,7 @@ struct token* lexer_try_new_next(struct lexer* self) SK_SCAN_KEYWORD("return", TOKEN_RETURN, NULL); SK_SCAN_KEYWORD("if", TOKEN_IF, NULL); SK_SCAN_KEYWORD("else", TOKEN_ELSE, NULL); + SK_SCAN_KEYWORD("module", TOKEN_MODULE, NULL); SK_SCAN_KEYWORD("begin", TOKEN_BEGIN, NULL); SK_SCAN_KEYWORD("end", TOKEN_END, NULL); SK_SCAN_KEYWORD("var", TOKEN_VAR, NULL); diff --git a/lib/src/module.c b/lib/src/module.c index 9027239..527d395 100644 --- a/lib/src/module.c +++ b/lib/src/module.c @@ -5,24 +5,63 @@ #include "exec.h" #include "natives.h" -void module_init(struct module* self) +void module_init(struct module* self, char const* name) { assert(self); + self->name = strdup(name); str_init(&self->source); - prog_init(&self->prog); - state_init(&self->state); - sym_init(&self->sym); - natives_populate(&self->state, &self->sym); + self->prog = malloc(sizeof(struct prog)); + prog_init(self->prog); + + self->state = malloc(sizeof(struct state)); + state_init(self->state); + + self->sym = malloc(sizeof(struct sym)); + sym_init(self->sym); + + natives_populate(self->state, self->sym); +} + +struct module* module_new_clone(struct module* self) +{ + assert(self); + struct module* clone = malloc(sizeof(struct module)); + module_init(clone, self->name); + + prog_free(clone->prog); + free(clone->prog); + state_free(clone->state); + free(clone->state); + sym_free(clone->sym); + free(clone->sym); + + // struct str source; + if (self->source.value) + { + str_extend(&clone->source, self->source.value); + } + + // struct prog prog; + clone->prog = prog_new_clone(self->prog); + // struct sym sym; + clone->sym = sym_new_clone(self->sym); + // struct state state; + clone->state = state_new_clone(self->state); + return clone; } void module_free(struct module* self) { assert(self); str_free(&self->source); - prog_free(&self->prog); - sym_free(&self->sym); - state_free(&self->state); + prog_free(self->prog); + free(self->prog); + sym_free(self->sym); + free(self->sym); + state_free(self->state); + free(self->state); + free(self->name); } void module_load_source(struct module* self, @@ -59,13 +98,13 @@ int module_compile(struct module* self) struct compiler compiler; compiler_init(&compiler); - compiler_compile(&compiler, root, &self->prog, &self->sym, - &self->state); + compiler_compile(&compiler, root, self->prog, self->sym, + self->state); struct exec exec; exec_init(&exec); - exec_execute(&exec, &self->state, &self->prog); + exec_execute(&exec, self->state, self->prog); if (!errors_ok()) { @@ -82,6 +121,5 @@ free_node: free(root); parser_free(&parser); - return errors_ok() ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/lib/src/parser.c b/lib/src/parser.c index e6a248e..e537554 100644 --- a/lib/src/parser.c +++ b/lib/src/parser.c @@ -116,10 +116,10 @@ struct node* parser_try_expr(struct parser* self) return SK_TRY(parser_try_const_decl); } - if (lexer_next_is(&self->lexer, TOKEN_IDENT) - && lexer_next_nth_is(&self->lexer, TOKEN_ASSIGN, 1)) + // ASSIGN { - return SK_TRY(parser_try_assign); + struct node* n = SK_TRY(parser_try_assign); + if (n) { return n; } } if (lexer_next_is(&self->lexer, TOKEN_VAR)) @@ -356,15 +356,11 @@ struct node* parser_try_if(struct parser* self) struct node* parser_try_assign(struct parser* self) { assert(self); - - if (!lexer_next_is(&self->lexer, TOKEN_IDENT)) + struct node* ident = SK_TRY(parser_try_or); + if (!ident) { return NULL; } - - struct node* ident = malloc(sizeof(struct node)); - node_init(ident, NODE_IDENT, lexer_try_new_next(&self->lexer)); - if (!lexer_next_is(&self->lexer, TOKEN_ASSIGN)) { node_free(ident); free(ident); @@ -886,6 +882,11 @@ struct node* parser_try_literal(struct parser* self) { assert(self); + { + struct node* node = SK_TRY(parser_try_call); + if (node) { return node; } + } + if (lexer_next_is(&self->lexer, TOKEN_OPAR)) { lexer_consume_next(&self->lexer); @@ -908,10 +909,10 @@ struct node* parser_try_literal(struct parser* self) return node; } - if (lexer_next_is(&self->lexer, TOKEN_IDENT) - && lexer_next_nth_is(&self->lexer, TOKEN_OPAR, 1)) + + if (lexer_next_nth_is(&self->lexer, TOKEN_MOD_ACCESS, 1)) { - return SK_TRY(parser_try_call); + return SK_TRY(parser_try_mod_access); } if (lexer_next_is(&self->lexer, TOKEN_IDENT)) @@ -930,10 +931,15 @@ struct node* parser_try_literal(struct parser* self) return SK_TRY(parser_try_fun); } + if (lexer_next_is(&self->lexer, TOKEN_MODULE)) + { + return SK_TRY(parser_try_module); + } + return SK_TRY(parser_try_builtin); } -struct node* parser_try_call(struct parser* self) +struct node* parser_try_mod_access(struct parser* self) { assert(self); @@ -942,8 +948,109 @@ struct node* parser_try_call(struct parser* self) return NULL; } - struct node* ident = malloc(sizeof(struct node)); - node_init(ident, NODE_IDENT, lexer_try_new_next(&self->lexer)); + struct token* lhs_tok = lexer_try_new_next(&self->lexer); + struct node* lhs = malloc(sizeof(struct node)); + node_init(lhs, NODE_IDENT, lhs_tok); + + if (!lhs) + { + token_free(lhs_tok); + free(lhs_tok); + return NULL; + } + + if (!lexer_next_is(&self->lexer, TOKEN_MOD_ACCESS)) + { + node_free(lhs); + free(lhs); + return NULL; + } + struct token* access_tok = lexer_try_new_next(&self->lexer); + + if (!lexer_next_is(&self->lexer, TOKEN_IDENT)) + { + node_free(lhs); + free(lhs); + token_free(access_tok); + free(access_tok); + return NULL; + } + + struct token* rhs_tok = lexer_try_new_next(&self->lexer); + struct node* rhs = malloc(sizeof(struct node)); + node_init(rhs, NODE_IDENT, rhs_tok); + + struct node* node = malloc(sizeof(struct node)); + node_init(node, NODE_MOD_ACCESS, access_tok); + + node_push_new_child(node, lhs); + node_push_new_child(node, rhs); + + return node; +} + +struct node* parser_try_module(struct parser* self) +{ + assert(self); + + if (!lexer_next_is(&self->lexer, TOKEN_MODULE)) + { + return NULL; + } + + struct node* node = malloc(sizeof(struct node)); + node_init(node, NODE_MODULE, lexer_try_new_next(&self->lexer)); + + struct node* expr = NULL; + + do + { + expr = SK_TRY(parser_try_expr); + + if (expr) + { + node_push_new_child(node, expr); + } + } + while (expr); + + if (!lexer_next_is(&self->lexer, TOKEN_END)) + { + node_free(node); + free(node); + return NULL; + } + + lexer_consume_next(&self->lexer); + return node; +} + +struct node* parser_try_call(struct parser* self) +{ + assert(self); + + struct node* lhs = NULL; + + if (lexer_next_is(&self->lexer, TOKEN_IDENT) + && !lexer_next_nth_is(&self->lexer, TOKEN_MOD_ACCESS, 1)) + { + struct node* ident = malloc(sizeof(struct node)); + node_init(ident, NODE_IDENT, + lexer_try_new_next(&self->lexer)); + if (!ident) + { + return NULL; + } + lhs = ident; + } + else + { + lhs = SK_TRY(parser_try_mod_access); + if (!lhs) + { + return NULL; + } + } struct token* tok = malloc(sizeof(struct token)); token_init(tok, TOKEN_BEGIN, "", self->lexer.context.line); @@ -951,7 +1058,7 @@ struct node* parser_try_call(struct parser* self) struct node* node = malloc(sizeof(struct node)); node_init(node, NODE_CALL, tok); - node_push_new_child(node, ident); + node_push_new_child(node, lhs); if (!lexer_next_is(&self->lexer, TOKEN_OPAR)) { diff --git a/lib/src/state.c b/lib/src/state.c index e22f681..d8745da 100644 --- a/lib/src/state.c +++ b/lib/src/state.c @@ -1,4 +1,5 @@ #include "state.h" +#include "module.h" #include "nfun.h" void stack_value_init(struct stack_value* self, @@ -27,6 +28,43 @@ void frame_init(struct frame* self) self->fun = NULL; } +struct frame* frame_new_clone(struct frame* self) +{ + struct frame* clone = malloc(sizeof(struct frame)); + frame_init(clone); + + // struct vec stack_values; + for (size_t i=0; istack_values.size; i++) + { + struct stack_value* sv = self->stack_values.data[i]; + struct stack_value* val = malloc(sizeof(struct stack_value)); + stack_value_init(val, sv->addr, + value_new_clone(sv->value)); + vec_push(&clone->stack_values, val); + } + + // struct vec locals; + for (size_t i=0; ilocals.size; i++) + { + struct local const* loc = self->locals.data[i]; + struct local* local = malloc(sizeof(struct local)); + local->id = loc->id; + local->addr = loc->addr; + vec_push(&clone->locals, local); + } + + // struct vec stack; + for (size_t i=0; istack.size; i++) + { + vec_push(&clone->stack, self->stack.data[i]); + } + + // struct fun* fun; + clone->fun = self->fun; + + return clone; +} + void frame_free(struct frame* self) { vec_free_elements(&self->stack_values, (void*) stack_value_free); @@ -47,6 +85,42 @@ void state_init(struct state* self) vec_init(&self->globals); } +struct state* state_new_clone(struct state* self) +{ + assert(self); + struct state* clone = malloc(sizeof(struct state)); + state_init(clone); + + for (size_t i=0; iframes.size; i++) + { + struct frame* frame = self->frames.data[i]; + vec_push(&clone->frames, frame_new_clone(frame)); + } + + // size_t addr; + clone->addr = self->addr; + // int global_id; + clone->global_id = self->global_id; + // struct vec globals; + for (size_t i=0; iglobals.size; i++) + { + struct global const* glob = self->globals.data[i]; + struct global* global = malloc(sizeof(struct global)); + global->id = glob->id; + global->addr = glob->id; + vec_push(&clone->globals, global); + } + // struct vec global_values; + for (size_t i=0; iglobal_values.size; i++) + { + struct value* val = self->global_values.data[i]; + struct value* value = value_new_clone(val); + vec_push(&clone->global_values, value); + } + + return clone; +} + void state_free(struct state* self) { assert(self); @@ -243,6 +317,14 @@ SK state_push_ref(struct state* self,size_t ref, int line) return state_push(self, TYPE_REF, val, line); } +SK state_push_mod(struct state* self, struct module* mod, int line) +{ + assert(self); + union val val; + val.mod = module_new_clone(mod); + return state_push(self, TYPE_MODULE, val, line); +} + struct local* state_try_get_local(struct state* self, int id) { struct frame* frame = state_frame(self); @@ -357,6 +439,39 @@ void state_closure_load(struct state* self, fprintf(stderr, "cannot load closure %d\n", id); abort(); } + +void state_module_load(struct state* self, + int id) +{ + assert(self); + SK mod = state_pop(self); + struct value* ref_val = state_try_get_value(self, mod); + + struct value* mod_value = state_try_deref(self, ref_val->val.ref); + struct module* module = mod_value->val.mod; + + struct symbol* symbol = sym_try_get_by_id( + module->sym, + id + ); + + struct value* value + = value_new_clone(state_try_get_value(module->state, symbol->id)); + + + if (value->type == TYPE_FUN) + { + state_push_ref(self, + state_add_global(self, value), + value->line); + } + else + { + state_push(self, value->type, value->val, value->line); + free(value); + } +} + TypeKind state_common_num_type(struct state* self, SK lhs, SK rhs) { assert(self); @@ -762,7 +877,7 @@ int state_add_global(struct state* self, vec_push(&self->global_values, value); size_t addr = self->global_values.size - 1; struct global* global = malloc(sizeof(struct global)); - global->id = self->global_id; + global->id = self->global_id; self->global_id++; global->addr = addr; diff --git a/lib/src/sym.c b/lib/src/sym.c index af87085..252db01 100644 --- a/lib/src/sym.c +++ b/lib/src/sym.c @@ -62,6 +62,28 @@ struct symbol* env_try_get(struct env* self, char const* name) return NULL; } +struct symbol* env_try_get_by_id(struct env* self, int id) +{ + assert(self); + + for (size_t i=0; isymbols.size; i++) + { + struct symbol* symbol = self->symbols.data[i]; + + if (symbol->id == id) + { + return symbol; + } + } + + if (self->parent) + { + return env_try_get_by_id(self->parent, id); + } + + return NULL; +} + void symbol_init(struct symbol* self, int id, char const* name, @@ -191,3 +213,8 @@ struct symbol* sym_try_get(struct sym* self, char const* name) { return env_try_get(self->env, name); } + +struct symbol* sym_try_get_by_id(struct sym* self, int id) +{ + return env_try_get_by_id(self->env, id); +} diff --git a/lib/src/value.c b/lib/src/value.c index 6f56c54..fd79403 100644 --- a/lib/src/value.c +++ b/lib/src/value.c @@ -1,5 +1,6 @@ #include "value.h" #include "nfun.h" +#include "module.h" SK_ENUM_C(TypeKind, TYPE_KIND); @@ -34,6 +35,12 @@ void value_free(struct value* self) nfun_free(self->val.nfun); free(self->val.nfun); } + + if (self->type == TYPE_MODULE) + { + module_free(self->val.mod); + free(self->val.mod); + } } struct value* value_new_clone(struct value* self) @@ -81,6 +88,12 @@ struct value* value_new_clone(struct value* self) return clone; } break; + case TYPE_MODULE: { + val.mod = module_new_clone(self->val.mod); + value_init(clone, TYPE_MODULE, val, self->line); + + return clone; + } break; case TYPE_NATIVE_FUN: { val.nfun = malloc(sizeof(struct nfun)); val.nfun->body = self->val.nfun->body; @@ -122,6 +135,10 @@ void value_str(struct value* self, struct str* dest) switch (self->type) { + case TYPE_MODULE: { + str_format(dest, "", self->val.mod); + } break; + case TYPE_FUN: { str_format(dest, "", self->val.fun); } break; diff --git a/tests/lexer.h b/tests/lexer.h index 24e4ffd..e42f1c4 100644 --- a/tests/lexer.h +++ b/tests/lexer.h @@ -144,6 +144,13 @@ static void test_lexer_function() ); } +static void test_lexer_module() +{ + test_lexer("module :: ", 2, + "MODULE", + "MOD_ACCESS" + ); +} void register_lexer() { CU_pSuite suite = CU_add_suite("Lexer", 0, 0); @@ -157,6 +164,7 @@ void register_lexer() CU_add_test(suite, "Blocks", test_lexer_block); CU_add_test(suite, "Conditionnals", test_lexer_cond); CU_add_test(suite, "Functions", test_lexer_function); + CU_add_test(suite, "Modules", test_lexer_module); } #endif diff --git a/tests/parser.h b/tests/parser.h index 946b97a..04e2c11 100644 --- a/tests/parser.h +++ b/tests/parser.h @@ -152,6 +152,19 @@ static void test_parser_function() "hello(x, 2)"); } +static void test_parser_module() +{ + test_parser("ROOT(MODULE(INT[4],STRING[5],BOOL[true]))", + "module 4 \"5\" true end"); + + test_parser("ROOT(ASSIGN(MOD_ACCESS(IDENT[x],IDENT[hello])" + ",INT[3]))", + "x::hello = 3"); + + test_parser("ROOT(CALL(MOD_ACCESS(IDENT[x],IDENT[hello]),ARGS))", + "x::hello()"); +} + void register_parser() { CU_pSuite suite = CU_add_suite("Parser", 0, 0); @@ -165,6 +178,7 @@ void register_parser() CU_add_test(suite, "Blocks", test_parser_block); CU_add_test(suite, "IfExpression", test_parser_if); CU_add_test(suite, "Functions", test_parser_function); + CU_add_test(suite, "Modules", test_parser_module); } #endif