From 6e6534acbd2acbd3ff7c6d4ec79adad08701bbec Mon Sep 17 00:00:00 2001 From: bog Date: Wed, 10 Apr 2024 10:53:07 +0200 Subject: [PATCH] :construction: big refactoring of local vars indexes. --- doc/grammar.bnf | 4 +- features/mod.sk | 5 ++ features/other_mod.sk | 18 ++++ features/third_mod.sk | 1 + lib/CMakeLists.txt | 2 + lib/include/compiler.h | 12 +++ lib/include/exec.h | 1 + lib/include/fun.h | 3 + lib/include/natives.h | 5 +- lib/include/nfun.h | 3 +- lib/include/node.h | 2 +- lib/include/parser.h | 1 + lib/include/path.h | 19 ++++ lib/include/prog.h | 2 +- lib/include/state.h | 8 +- lib/include/sym.h | 18 +++- lib/include/token.h | 2 +- lib/src/compiler.c | 196 ++++++++++++++++++++++++++++++++++------- lib/src/exec.c | 190 +++++++++++++++++++++++++++++---------- lib/src/fun.c | 5 ++ lib/src/lexer.c | 1 + lib/src/module.c | 2 +- lib/src/natives.c | 46 +++++++++- lib/src/nfun.c | 3 +- lib/src/parser.c | 33 +++++++ lib/src/path.c | 95 ++++++++++++++++++++ lib/src/state.c | 79 +++++++++++++++-- lib/src/sym.c | 42 ++++++--- tests/lexer.h | 5 +- tests/main.c | 2 + tests/parser.h | 7 ++ tests/path.h | 94 ++++++++++++++++++++ 32 files changed, 788 insertions(+), 118 deletions(-) create mode 100644 features/other_mod.sk create mode 100644 features/third_mod.sk create mode 100644 lib/include/path.h create mode 100644 lib/src/path.c create mode 100644 tests/path.h diff --git a/doc/grammar.bnf b/doc/grammar.bnf index 1402dab..45fd33b 100644 --- a/doc/grammar.bnf +++ b/doc/grammar.bnf @@ -10,6 +10,8 @@ EXPR ::= | return EXPR | FUN_DECL | MOD_ACCESS +| IMPORT +IMPORT ::= import string MOD_ACCESS ::= EXPR mod_access ident FUN_DECL ::= | fun ident opar PARAMS cpar EXPR* end @@ -45,4 +47,4 @@ BUILTIN ::= | int | bool | float -| string +| stri diff --git a/features/mod.sk b/features/mod.sk index 4fe721b..c28d3b2 100644 --- a/features/mod.sk +++ b/features/mod.sk @@ -10,3 +10,8 @@ end assert m::x eq 32 assert m::y eq "bim" assert m::add(7, 2) eq 9 + +import "./other_mod" + +assert other_mod::my_value eq 42 +assert other_mod::f(3) eq 21 diff --git a/features/other_mod.sk b/features/other_mod.sk new file mode 100644 index 0000000..ccc4be4 --- /dev/null +++ b/features/other_mod.sk @@ -0,0 +1,18 @@ +import "./third_mod" + +var my_value = 42 + +fun f(n) + return n * 7 +end + +fun x() + fun y() + third_mod::x + 2 + end + + y() +end + +assert x() eq 39 + diff --git a/features/third_mod.sk b/features/third_mod.sk new file mode 100644 index 0000000..303c10f --- /dev/null +++ b/features/third_mod.sk @@ -0,0 +1 @@ +var x = 37 diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 29c744d..e5c56a6 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -28,6 +28,8 @@ add_library(skopy-lib SHARED src/nfun.c src/natives.c + + src/path.c ) file(GLOB_RECURSE diff --git a/lib/include/compiler.h b/lib/include/compiler.h index 8fa5c1e..593267f 100644 --- a/lib/include/compiler.h +++ b/lib/include/compiler.h @@ -17,6 +17,7 @@ struct compiler { struct vec var_names; struct vec modules; + struct vec funs; }; void mod_free(struct mod* self); void compiler_init(struct compiler* self); @@ -58,5 +59,16 @@ void compiler_compile_if(struct compiler* self, struct sym* sym, struct state* state, struct vec* to_end); + +struct symbol* compiler_find(struct compiler* self, + char* name, + struct sym* sym, + struct node* node); + +void compiler_compile_fun(struct compiler* self, + struct node* node, + struct prog* prog, + struct sym* sym, + struct state* state); #endif diff --git a/lib/include/exec.h b/lib/include/exec.h index f58894f..4ec297a 100644 --- a/lib/include/exec.h +++ b/lib/include/exec.h @@ -16,6 +16,7 @@ void exec_free(struct exec* self); void exec_execute(struct exec* self, struct state* state, + struct sym* sym, struct prog* prog); void exec_capture_env(struct exec* self, diff --git a/lib/include/fun.h b/lib/include/fun.h index e367fab..38528a2 100644 --- a/lib/include/fun.h +++ b/lib/include/fun.h @@ -3,6 +3,8 @@ #include "commons.h" +extern int FunId; + struct closure { int id; @@ -11,6 +13,7 @@ struct closure struct fun { + int id; struct prog* prog; struct sym* sym; struct vec closures; diff --git a/lib/include/natives.h b/lib/include/natives.h index f4050c9..750a53d 100644 --- a/lib/include/natives.h +++ b/lib/include/natives.h @@ -12,6 +12,9 @@ void natives_decl(struct state* state, nfun_body fun, int arity); -SK native_println(struct state* state, struct vec* args); +SK native_println(struct state* state, struct sym* sym, + struct vec* args); +SK native_import(struct state* state, struct sym* sym, + struct vec* args); #endif diff --git a/lib/include/nfun.h b/lib/include/nfun.h index 915a1cd..365a0ee 100644 --- a/lib/include/nfun.h +++ b/lib/include/nfun.h @@ -4,7 +4,7 @@ #include "commons.h" #include "state.h" -typedef SK (*nfun_body)(struct state*, struct vec*); +typedef SK (*nfun_body)(struct state*, struct sym*, struct vec*); struct nfun { @@ -17,5 +17,6 @@ void nfun_free(struct nfun* self); SK nfun_call(struct nfun* self, struct state* state, + struct sym* sym, struct vec* args); #endif diff --git a/lib/include/node.h b/lib/include/node.h index f61006d..35c7934 100644 --- a/lib/include/node.h +++ b/lib/include/node.h @@ -16,7 +16,7 @@ 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_MODULE), \ -G(NODE_MOD_ACCESS) +G(NODE_MOD_ACCESS), G(NODE_IMPORT) SK_ENUM_H(NodeKind, NODE_KIND); diff --git a/lib/include/parser.h b/lib/include/parser.h index 4dc9280..0ec1133 100644 --- a/lib/include/parser.h +++ b/lib/include/parser.h @@ -19,6 +19,7 @@ struct node* parser_try(struct parser* self, struct node* parser_try_parse(struct parser* self); struct node* parser_try_root(struct parser* self); struct node* parser_try_expr(struct parser* self); +struct node* parser_try_import(struct parser* self); struct node* parser_try_fun_decl(struct parser* self); struct node* parser_try_block(struct parser* self); struct node* parser_try_inner_block(struct parser* self); diff --git a/lib/include/path.h b/lib/include/path.h new file mode 100644 index 0000000..85b939b --- /dev/null +++ b/lib/include/path.h @@ -0,0 +1,19 @@ +#ifndef SK_PATH_H +#define SK_PATH_H + +#include "commons.h" + +struct path +{ + struct str* str; +}; + +void path_init(struct path* self, char const* path_text); +void path_free(struct path* self); + +bool path_is_relative(struct path* self); +void path_set_ext(struct path* self, char const* ext); +ssize_t path_try_find_ext(struct path* self); +void path_extract_name(struct path* self, struct str* dest); + +#endif diff --git a/lib/include/prog.h b/lib/include/prog.h index c86b6c0..c161404 100644 --- a/lib/include/prog.h +++ b/lib/include/prog.h @@ -6,7 +6,7 @@ #define SK_NO_PARAM (-1) #define OPCODE(G) \ -G(OP_PUSH), \ +G(OP_PUSH), G(OP_POP), \ G(OP_ADD), G(OP_SUB), G(OP_MUL), \ G(OP_DIV), G(OP_MOD), G(OP_POW), \ G(OP_USUB), G(OP_ASSERT_EQ), \ diff --git a/lib/include/state.h b/lib/include/state.h index 0fa7d5b..42d3bd2 100644 --- a/lib/include/state.h +++ b/lib/include/state.h @@ -24,6 +24,7 @@ struct frame struct vec locals; struct vec stack; struct fun* fun; + struct frame* parent; }; struct global @@ -41,7 +42,7 @@ struct state struct vec global_values; }; -typedef SK (*nfun_body)(struct state*, struct vec*); +typedef SK (*nfun_body)(struct state*, struct sym*, struct vec*); void stack_value_init(struct stack_value* self, size_t addr, @@ -63,6 +64,8 @@ struct value* state_try_deref(struct state* self, size_t ref); struct frame* state_frame(struct state* self); void state_push_frame(struct state* self); void state_pop_frame(struct state* self); +struct value* frame_try_get_value(struct frame* self, SK value); +struct local* frame_try_get_local_by_id(struct frame* self, int id); SK state_top(struct state* self); struct value* state_try_get_value(struct state* self, SK value); @@ -127,6 +130,9 @@ SK state_eq(struct state* self); int state_add_global(struct state* self, struct value* value); +struct global* state_try_get_global(struct state* self, + int id); + void state_call(struct state* self, struct fun* fun); void state_ret(struct state* self); SK state_add_nfun(struct state* self, diff --git a/lib/include/sym.h b/lib/include/sym.h index 143a926..8ae2b97 100644 --- a/lib/include/sym.h +++ b/lib/include/sym.h @@ -4,6 +4,7 @@ #include "commons.h" #define SK_NO_CLOSURE (-1) #define SK_NO_NATIVE (-1) +#include "value.h" struct symbol { @@ -14,6 +15,8 @@ struct symbol bool is_const; bool is_global; struct env* env; + struct node* node; + struct fun* fun; }; struct env @@ -24,6 +27,7 @@ struct env struct sym { + struct sym* parent; int id_counter; int closure_counter; int native_counter; @@ -36,11 +40,13 @@ 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_find(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, char const* name, + struct node* node, struct env* env); void symbol_free(struct symbol* self); @@ -49,10 +55,14 @@ void sym_init(struct sym* self); struct sym* sym_new_clone(struct sym* self); void sym_free(struct sym* self); -int sym_decl_var(struct sym* self, char const* name); -int sym_decl_const(struct sym* self, char const* name); -int sym_decl_closure(struct sym* self, int id, char const* name); -int sym_decl_global(struct sym* self, int id, char const* name); +int sym_decl_var(struct sym* self, char const* name, + struct node* node); +int sym_decl_const(struct sym* self, char const* name, + struct node* node); +int sym_decl_closure(struct sym* self, int id, char const* name, + struct node* node, struct fun* fun); +int sym_decl_global(struct sym* self, int id, char const* name, + struct node* node); void sym_open_scope(struct sym* self); void sym_close_scope(struct sym* self); diff --git a/lib/include/token.h b/lib/include/token.h index 16e5c2a..67ec171 100644 --- a/lib/include/token.h +++ b/lib/include/token.h @@ -17,7 +17,7 @@ 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_MODULE), \ -G(TOKEN_MOD_ACCESS) +G(TOKEN_MOD_ACCESS), G(TOKEN_IMPORT) SK_ENUM_H(TokenKind, TOKEN_KIND); diff --git a/lib/src/compiler.c b/lib/src/compiler.c index fa1050f..29e05e1 100644 --- a/lib/src/compiler.c +++ b/lib/src/compiler.c @@ -1,4 +1,5 @@ #include "compiler.h" +#include "path.h" #include "token.h" #include "state.h" #include "natives.h" @@ -9,6 +10,7 @@ void compiler_init(struct compiler* self) assert(self); vec_init(&self->var_names); vec_init(&self->modules); + vec_init(&self->funs); } void mod_free(struct mod* self) @@ -22,6 +24,7 @@ void compiler_free(struct compiler* self) vec_free(&self->var_names); vec_free_elements(&self->modules, (void*) mod_free); vec_free(&self->modules); + vec_free(&self->funs); } void compiler_compile(struct compiler* self, @@ -44,6 +47,48 @@ void compiler_compile(struct compiler* self, } } break; + case NODE_IMPORT: { + struct node* name_node = node->children.data[0]; + struct path path; + path_init(&path, name_node->token->value); + + struct str name; + str_init(&name); + path_set_ext(&path, "sk"); + path_extract_name(&path, &name); + + struct module* module = malloc(sizeof(struct module)); + module_init(module, name.value); + module_load_source(module, path.str->value); + module_compile(module); + + struct value* value = malloc(sizeof(struct value)); + union val v; + v.mod = module; + value_init(value, TYPE_MODULE, v, node->token->line); + + struct str mod_name; + str_init(&mod_name); + path_set_ext(&path, ""); + path_extract_name(&path, &mod_name); + + int id = prog_add_constant(prog, value); + prog_add_instr(prog, OP_PUSH, id); + prog_add_instr(prog, OP_MAKE_REF, SK_NO_PARAM); + + int addr = sym_decl_const(sym, mod_name.value, node); + prog_add_instr(prog, OP_LOCAL_STORE, addr); + + struct mod* mymod = malloc(sizeof(struct mod)); + mymod->name = strdup(mod_name.value); + mymod->module = module; + vec_push(&self->modules, mymod); + + str_free(&mod_name); + str_free(&name); + path_free(&path); + } break; + case NODE_BLOCK: { sym_open_scope(sym); for (size_t i=0; ichildren.size; i++) @@ -118,7 +163,8 @@ void compiler_compile(struct compiler* self, struct node* expr = node->children.data[1]; compiler_compile(self, expr, prog, sym, state); - int id = sym_decl_var(sym, ident->token->value); + int id = sym_decl_var(sym, ident->token->value, + expr); prog_add_instr(prog, OP_LOCAL_STORE, id); char* name = vec_pop(&self->var_names); @@ -136,7 +182,8 @@ void compiler_compile(struct compiler* self, } struct node* expr = node->children.data[1]; compiler_compile(self, expr, prog, sym, state); - int id = sym_decl_const(sym, ident->token->value); + int id = sym_decl_const(sym, ident->token->value, + expr); prog_add_instr(prog, OP_LOCAL_STORE, id); char* name = vec_pop(&self->var_names); free(name); @@ -145,7 +192,12 @@ void compiler_compile(struct compiler* self, case NODE_ASSIGN: { struct node* ident = node->children.data[0]; struct node* expr = node->children.data[1]; - struct symbol* symbol = sym_try_get(sym, ident->token->value); + struct symbol* symbol = compiler_find( + self, + ident->token->value, + sym, + node + ); if (!symbol) { @@ -174,19 +226,26 @@ void compiler_compile(struct compiler* self, } break; case NODE_IDENT: { - struct symbol* symbol = sym_try_get(sym, - node->token->value); + char* name = node->token->value; + + struct symbol* symbol = compiler_find(self, + name, + sym, + node); + if (!symbol) { errors_push(node->token->line, "unknown identifier '%s'.", - node->token->value); + name); break; } struct env* itr = sym->env->parent; + int const max_depth = 1; + int i = 0; - while (itr) + while (i <= max_depth && itr) { struct symbol const* s = env_try_get(itr, symbol->name); @@ -196,6 +255,7 @@ void compiler_compile(struct compiler* self, } itr = itr->parent; + i++; } if (symbol->is_global) @@ -281,6 +341,7 @@ void compiler_compile(struct compiler* self, errors_push(node->token->line, "unknown module '%s'.", mod_name->token->value); + break; } struct symbol* symbol = sym_try_get( @@ -309,6 +370,8 @@ void compiler_compile(struct compiler* self, fun_init(fun, p); natives_populate(state, fun->sym); + // Self value + // ---------- struct node* params = node->children.data[0]; struct node* body = node->children.data[1]; @@ -317,43 +380,25 @@ void compiler_compile(struct compiler* self, self->var_names.data[self->var_names.size - 1] : NULL; + // Parameters + // ---------- for (size_t i=0; ichildren.size; i++) { struct node* child = params->children.data[i]; char* name = child->token->value; - sym_decl_var(fun->sym, name); + sym_decl_var(fun->sym, name, child); } if (var_name) { - sym_decl_var(fun->sym, var_name); + sym_decl_var(fun->sym, var_name, node); } - // Closure - { - for (size_t i=0; ienv->symbols.size; i++) - { - struct symbol* s = sym->env->symbols.data[i]; - sym_decl_closure(fun->sym, s->id, s->name); - } + fun->sym->parent = sym; - if (sym->env->parent) - { - for ( - size_t i=0; - ienv->parent->symbols.size; - i++ - ) - { - struct symbol* s = - sym->env->parent->symbols.data[i]; - - sym_decl_closure(fun->sym, s->id, s->name); - } - } - } - - compiler_compile(self, body, p, fun->sym, state); + vec_push(&self->funs, fun); + compiler_compile_fun(self, body, p, fun->sym, state); + vec_pop(&self->funs); union val val; val.fun = fun; @@ -361,6 +406,7 @@ void compiler_compile(struct compiler* self, val); prog_add_instr(prog, OP_MAKE_REF, SK_NO_PARAM); } break; + case NODE_BOOL: { union val val; val.boolean = @@ -619,3 +665,87 @@ void compiler_compile_if(struct compiler* self, } } } + +TypeKind compiler_node_type(struct compiler* self, + struct node* node) +{ + assert(self); + assert(node); + + switch (node->kind) + { + case NODE_INT: return TYPE_INT; + default: { + fprintf(stderr, "cannot find node type of '%s'", + NodeKindStr[node->kind]); + abort(); + }; + } +} + +struct symbol* compiler_find(struct compiler* self, + char* name, + struct sym* sym, + struct node* node) +{ + struct symbol* symbol = NULL; + struct sym* itr = sym; + + while (itr) + { + symbol = sym_try_get(itr, name); + if (symbol) + { + if (self->funs.size > 0) + { + struct fun* fun = + self->funs.data[ + self->funs.size - 1 + ]; + + sym_decl_closure( + fun->sym, + symbol->id, + symbol->name, + node, + fun + ); + + struct symbol* s = sym_try_get( + fun->sym, + symbol->name + ); + + if (s->closure_id != SK_NO_CLOSURE) + { + symbol = s; + } + } + } + + if (symbol) { break; } + itr = itr->parent; + } + + return symbol; +} + +void compiler_compile_fun(struct compiler* self, + struct node* node, + struct prog* prog, + struct sym* sym, + struct state* state) +{ + if (node->kind == NODE_BLOCK) + { + for (size_t i=0; ichildren.size; i++) + { + compiler_compile(self, node->children.data[i], + prog, sym, state); + } + } + else + { + compiler_compile(self, node, prog, sym, state); + } +} diff --git a/lib/src/exec.c b/lib/src/exec.c index e07490e..1d21f5e 100644 --- a/lib/src/exec.c +++ b/lib/src/exec.c @@ -17,6 +17,7 @@ void exec_free(struct exec* self) void exec_execute(struct exec* self, struct state* state, + struct sym* sym, struct prog* prog) { while (self->pc < prog->opcodes.size) @@ -118,6 +119,7 @@ void exec_execute(struct exec* self, struct value* f = value_new_clone(state_try_get_value(state, function)); + assert(f->type == TYPE_REF); struct value* val_fun = state_try_deref( state, f->val.ref @@ -136,6 +138,7 @@ void exec_execute(struct exec* self, } SK res = nfun_call(val_fun->val.nfun, state, + sym, &ordered); struct value* value = state_try_get_value(state, res); @@ -167,8 +170,10 @@ void exec_execute(struct exec* self, } struct fun* fun = val_fun->val.fun; - state_call(state, fun); + + // Params + // ------ for (size_t i=0; ival.ref); - exec_execute(&ex, state, fun_val->val.fun->prog); + exec_execute(&ex, state, sym, + fun_val->val.fun->prog); struct value* res = value_new_clone(state_try_get_value( state, @@ -211,15 +217,19 @@ void exec_execute(struct exec* self, self->pc++; } break; + case OP_POP: { + state_pop(state); + self->pc++; + } break; + case OP_PUSH: { struct value* constant = prog->constants.data[param]; switch (constant->type) { case TYPE_FUN: { - - struct fun* fun = fun_new_clone(constant->val.fun); - struct sym* s = fun->sym; - exec_capture_env(self, state, fun, s->env); + struct fun* fun = + fun_new_clone(constant->val.fun); + exec_capture_env(self, state, fun, sym->env); state_push_fun( state, @@ -235,7 +245,8 @@ void exec_execute(struct exec* self, struct exec exec; exec_init(&exec); - exec_execute(&exec, mod->state, mod->prog); + exec_execute(&exec, mod->state, + sym, mod->prog); exec_free(&exec); @@ -396,54 +407,137 @@ void exec_capture_env(struct exec* self, { (void) self; - if (env->parent) + struct env* itr = fun->sym->env; + + if (itr) { - for (size_t i=0; iparent->symbols.size; i++) + for (size_t i=0; isymbols.size; i++) { - struct symbol* symbol = env->parent->symbols.data[i]; - if (symbol->closure_id != SK_NO_CLOSURE) + struct symbol* symbol = itr->symbols.data[i]; + for (size_t j=0; jframes.size; j++) { - struct local* loc = - state_try_get_local_by_id( - state, - symbol->closure_id - ); + size_t k = state->frames.size - j - 1; + // HOW TO CHOOSE FRAME ? + struct frame* frame = state->frames.data[k]; - if(!loc) { continue; } + if (symbol->closure_id != SK_NO_CLOSURE) + { + struct local* loc = + frame_try_get_local_by_id( + frame, + symbol->closure_id + ); - struct value* val = - state_try_get_value( - state, - loc->addr - ); + if (loc) + { + struct value* val = frame_try_get_value( + frame, + loc->addr + ); - fun_capture(fun, symbol->id, val); - } - } - } - if (env) - { - for (size_t i=0; isymbols.size; i++) - { - struct symbol* symbol = env->symbols.data[i]; - if (symbol->closure_id != SK_NO_CLOSURE) - { - struct local* loc = - state_try_get_local_by_id( - state, - symbol->closure_id - ); - - if(!loc) { continue; } - - struct value* val = - state_try_get_value( - state, - loc->addr - ); - - fun_capture(fun, symbol->id, val); + printf("capture %d\n", symbol->closure_id); + fun_capture(fun, symbol->closure_id, val); + break; + } + + // struct local* loc = + // state_try_get_local_by_id( + // state, + // symbol->closure_id + // ); + // + // if(!loc) { continue; } + // + // struct value* val = + // state_try_get_value( + // state, + // loc->addr + // ); + // + // fun_capture(fun, symbol->id, val); + } } } + + itr = itr->parent; } + // struct env* itr = env; + // + // if (itr) + // { + // for (size_t i=0; isymbols.size; i++) + // { + // struct symbol* symbol = itr->symbols.data[i]; + // if (symbol->closure_id != SK_NO_CLOSURE) + // { + // struct local* loc = + // state_try_get_local_by_id( + // state, + // symbol->closure_id + // ); + // + // if(!loc) { continue; } + // + // struct value* val = + // state_try_get_value( + // state, + // loc->addr + // ); + // + // fun_capture(fun, symbol->id, val); + // } + // } + // + // itr = itr->parent; + // } + // if (env->parent) + // { + // for (size_t i=0; iparent->symbols.size; i++) + // { + // struct symbol* symbol = env->parent->symbols.data[i]; + // if (symbol->closure_id != SK_NO_CLOSURE) + // { + // struct local* loc = + // state_try_get_local_by_id( + // state, + // symbol->closure_id + // ); + // + // if(!loc) { continue; } + // + // struct value* val = + // state_try_get_value( + // state, + // loc->addr + // ); + // + // fun_capture(fun, symbol->id, val); + // } + // } + // } + // if (env) + // { + // for (size_t i=0; isymbols.size; i++) + // { + // struct symbol* symbol = env->symbols.data[i]; + // if (symbol->closure_id != SK_NO_CLOSURE) + // { + // struct local* loc = + // state_try_get_local_by_id( + // state, + // symbol->closure_id + // ); + // + // if(!loc) { continue; } + // + // struct value* val = + // state_try_get_value( + // state, + // loc->addr + // ); + // + // fun_capture(fun, symbol->id, val); + // } + // } + // } } diff --git a/lib/src/fun.c b/lib/src/fun.c index 6648cf8..2baaea3 100644 --- a/lib/src/fun.c +++ b/lib/src/fun.c @@ -1,6 +1,7 @@ #include "fun.h" #include "prog.h" #include "sym.h" +int FunId = 0; void closure_init(struct closure* self, int id, struct value* value) { @@ -29,6 +30,8 @@ void closure_free(struct closure* self) void fun_init(struct fun* self, struct prog* new_prog) { assert(self); + self->id = FunId; + FunId++; self->prog = new_prog; self->sym = malloc(sizeof(struct sym)); sym_init(self->sym); @@ -56,6 +59,8 @@ struct fun* fun_new_clone(struct fun* self) free(clone->sym); clone->sym = sym_new_clone(self->sym); + clone->id = self->id; + for (size_t i=0; iclosures.size; i++) { struct closure* closure = self->closures.data[i]; diff --git a/lib/src/lexer.c b/lib/src/lexer.c index d759323..1a87b41 100644 --- a/lib/src/lexer.c +++ b/lib/src/lexer.c @@ -198,6 +198,7 @@ struct token* lexer_try_new_next(struct lexer* self) SK_SCAN_TEXT("=", TOKEN_ASSIGN); SK_SCAN_TEXT(",", TOKEN_COMMA); SK_SCAN_KEYWORD("fun", TOKEN_FUN, NULL); + SK_SCAN_KEYWORD("import", TOKEN_IMPORT, NULL); SK_SCAN_KEYWORD("return", TOKEN_RETURN, NULL); SK_SCAN_KEYWORD("if", TOKEN_IF, NULL); SK_SCAN_KEYWORD("else", TOKEN_ELSE, NULL); diff --git a/lib/src/module.c b/lib/src/module.c index 527d395..4b83306 100644 --- a/lib/src/module.c +++ b/lib/src/module.c @@ -104,7 +104,7 @@ int module_compile(struct module* self) struct exec exec; exec_init(&exec); - exec_execute(&exec, self->state, self->prog); + exec_execute(&exec, self->state, self->sym, self->prog); if (!errors_ok()) { diff --git a/lib/src/natives.c b/lib/src/natives.c index d5101ec..5dc89e0 100644 --- a/lib/src/natives.c +++ b/lib/src/natives.c @@ -1,4 +1,6 @@ #include "natives.h" +#include "path.h" +#include "module.h" void natives_populate(struct state* state, struct sym* sym) { @@ -6,6 +8,7 @@ void natives_populate(struct state* state, struct sym* sym) assert(sym); natives_decl(state, sym, "println", native_println, -1); + natives_decl(state, sym, "import", native_import, 1); } void natives_decl(struct state* state, @@ -16,12 +19,16 @@ void natives_decl(struct state* state, { assert(state); assert(sym); - sym_decl_global(sym, state->global_id, name); + sym_decl_global(sym, state->global_id, name, NULL); state_add_nfun(state, fun, arity); } -SK native_println(struct state* state, struct vec* args) +SK native_println(struct state* state, + struct sym* sym, + struct vec* args) { + (void) sym; + for (size_t i=0; isize; i++) { struct value* arg @@ -37,3 +44,38 @@ SK native_println(struct state* state, struct vec* args) printf("\n"); return state_push_bool(state, true, 0); } + +SK native_import(struct state* state, + struct sym* sym, + struct vec* args) +{ + struct value* filename_val = + state_try_get_value(state, (SK) args->data[0]); + + assert(filename_val); + char* filename_str = filename_val->val.str; + struct path path; + path_init(&path, filename_str); + + struct str filename; + str_init(&filename); + path_extract_name(&path, &filename); + + struct module* module = malloc(sizeof(struct module)); + path_set_ext(&path, ""); + module_init(module, path.str->value); + module_load_source(module, filename.value); + module_compile(module); + + struct value* value = malloc(sizeof(struct value)); + union val v; + v.mod = module; + value_init(value, TYPE_MODULE, v, 0); + + int id = state_add_global(state, value); + + sym_decl_global(sym, id, "po", NULL); + + str_free(&filename); + return state_push_ref(state, id, 0); +} diff --git a/lib/src/nfun.c b/lib/src/nfun.c index 9c3ed33..48f973d 100644 --- a/lib/src/nfun.c +++ b/lib/src/nfun.c @@ -14,6 +14,7 @@ void nfun_free(struct nfun* self) SK nfun_call(struct nfun* self, struct state* state, + struct sym* sym, struct vec* args) { assert(self); @@ -33,7 +34,7 @@ SK nfun_call(struct nfun* self, return state_push_bool(state, false, line); } - SK result = (*self->body)(state, args); + SK result = (*self->body)(state, sym, args); return result; } diff --git a/lib/src/parser.c b/lib/src/parser.c index e537554..98b1a16 100644 --- a/lib/src/parser.c +++ b/lib/src/parser.c @@ -143,9 +143,42 @@ struct node* parser_try_expr(struct parser* self) return SK_TRY(parser_try_fun_decl); } + if (lexer_next_is(&self->lexer, TOKEN_IMPORT)) + { + return SK_TRY(parser_try_import); + } + return SK_TRY(parser_try_or); } +struct node* parser_try_import(struct parser* self) +{ + assert(self); + + if (!lexer_next_is(&self->lexer, TOKEN_IMPORT)) + { + return NULL; + } + + struct token* tok = lexer_try_new_next(&self->lexer); + + if (!lexer_next_is(&self->lexer, TOKEN_STRING)) + { + token_free(tok); + free(tok); + return NULL; + } + + struct node* string = malloc(sizeof(struct node)); + node_init(string, NODE_STRING, + lexer_try_new_next(&self->lexer)); + + struct node* node = malloc(sizeof(struct node)); + node_init(node, NODE_IMPORT, tok); + node_push_new_child(node, string); + return node; +} + struct node* parser_try_fun_decl(struct parser* self) { if (!lexer_next_is(&self->lexer, TOKEN_FUN)) diff --git a/lib/src/path.c b/lib/src/path.c new file mode 100644 index 0000000..63f1873 --- /dev/null +++ b/lib/src/path.c @@ -0,0 +1,95 @@ +#include "path.h" + +void path_init(struct path* self, char const* path_text) +{ + assert(self); + self->str = malloc(sizeof(struct str)); + str_init(self->str); + str_extend(self->str, (char*) path_text); +} + +void path_free(struct path* self) +{ + assert(self); + str_free(self->str); + free(self->str); +} + +bool path_is_relative(struct path* self) +{ + assert(self); + + return self->str->size > 0 && self->str->value[0] == '.'; + + return false; +} + +void path_set_ext(struct path* self, char const* ext) +{ + assert(self); + assert(ext); + + ssize_t idx = path_try_find_ext(self); + + if (idx < 0) + { + if (strlen(ext) > 0) + { + str_push(self->str, '.'); + } + str_extend(self->str, (char*) ext); + } + else + { + struct str* str = malloc(sizeof(struct str)); + str_init(str); + + for (ssize_t i=0; istr->value[i]); + } + + if (strlen(ext) > 0) + { + str_push(str, '.'); + str_extend(str, (char*) ext); + } + + str_free(self->str); + free(self->str); + self->str = str; + } +} + +ssize_t path_try_find_ext(struct path* self) +{ + assert(self); + + for (size_t i=0; istr->size; i++) + { + size_t k = self->str->size - i - 1; + + if (k > 0 && self->str->value[k] == '.' + && isalnum(self->str->value[k - 1])) + { + return k; + } + } + + return -1; +} + +void path_extract_name(struct path* self, struct str* dest) +{ + assert(self); + assert(dest); + + if (path_is_relative(self)) + { + str_extend(dest, self->str->value + 2); + } + else + { + str_extend(dest, self->str->value); + } +} diff --git a/lib/src/state.c b/lib/src/state.c index d8745da..c378211 100644 --- a/lib/src/state.c +++ b/lib/src/state.c @@ -26,13 +26,14 @@ void frame_init(struct frame* self) vec_init(&self->locals); vec_init(&self->stack); self->fun = NULL; + self->parent = 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++) { @@ -61,7 +62,7 @@ struct frame* frame_new_clone(struct frame* self) // struct fun* fun; clone->fun = self->fun; - + clone->parent = self->parent; return clone; } @@ -107,9 +108,10 @@ struct state* state_new_clone(struct state* self) struct global const* glob = self->globals.data[i]; struct global* global = malloc(sizeof(struct global)); global->id = glob->id; - global->addr = glob->id; + global->addr = glob->addr; vec_push(&clone->globals, global); } + // struct vec global_values; for (size_t i=0; iglobal_values.size; i++) { @@ -179,7 +181,10 @@ void state_push_frame(struct state* self) assert(self); struct frame* frame = malloc(sizeof(struct frame)); frame_init(frame); - + if (self->frames.size > 1) + { + frame->parent = self->frames.data[self->frames.size - 1]; + } vec_push(&self->frames, frame); } @@ -191,6 +196,38 @@ void state_pop_frame(struct state* self) free(frame); } +struct value* frame_try_get_value(struct frame* self, SK value) +{ + assert(self); + + for (size_t i=0; istack_values.size; i++) + { + struct stack_value* stack_value = self->stack_values.data[i]; + + if (stack_value->addr == value) + { + return stack_value->value; + } + } + + return NULL; +} + +struct local* frame_try_get_local_by_id(struct frame* self, int id) +{ + for (size_t i=0; ilocals.size; i++) + { + struct local* loc = self->locals.data[i]; + + if (loc->id == id) + { + return loc; + } + } + + return NULL; +} + SK state_top(struct state* self) { assert(self); @@ -455,11 +492,20 @@ void state_module_load(struct state* self, id ); - struct value* value - = value_new_clone(state_try_get_value(module->state, symbol->id)); + struct local* loca = state_try_get_local_by_id(module->state, symbol->id); + struct value* value + = state_try_get_value(module->state, loca->addr); - - if (value->type == TYPE_FUN) + if (value->type == TYPE_REF) + { + struct value* v = state_try_deref(module->state, + value->val.ref); + v = value_new_clone(v); + state_push_ref(self, + state_add_global(self, v), + value->line); + } + else if (value->type == TYPE_FUN) { state_push_ref(self, state_add_global(self, value), @@ -468,7 +514,6 @@ void state_module_load(struct state* self, else { state_push(self, value->type, value->val, value->line); - free(value); } } @@ -886,6 +931,22 @@ int state_add_global(struct state* self, return addr; } +struct global* state_try_get_global(struct state* self, + int id) +{ + for (size_t i=0; iglobals.size; i++) + { + struct global* glob = self->globals.data[i]; + + if (glob->id == id) + { + return glob; + } + } + + return NULL; +} + void state_call(struct state* self, struct fun* fun) { assert(self); diff --git a/lib/src/sym.c b/lib/src/sym.c index 252db01..be1da7c 100644 --- a/lib/src/sym.c +++ b/lib/src/sym.c @@ -23,11 +23,13 @@ struct env* env_new_clone(struct env* self) new_symbol->closure_id = symbol->closure_id; new_symbol->native_id = symbol->native_id; new_symbol->env = clone; + new_symbol->node = symbol->node; + new_symbol->fun = symbol->fun; vec_push(&clone->symbols, new_symbol); } - clone->parent = self->parent ? env_new_clone(self->parent) : NULL; + clone->parent = self->parent ? self->parent : NULL; return clone; } @@ -62,6 +64,11 @@ struct symbol* env_try_get(struct env* self, char const* name) return NULL; } +struct symbol* env_try_find(struct env* self, char const* name) +{ + return NULL; +} + struct symbol* env_try_get_by_id(struct env* self, int id) { assert(self); @@ -87,6 +94,7 @@ struct symbol* env_try_get_by_id(struct env* self, int id) void symbol_init(struct symbol* self, int id, char const* name, + struct node* node, struct env* env) { assert(self); @@ -97,6 +105,8 @@ void symbol_init(struct symbol* self, self->closure_id = SK_NO_CLOSURE; self->native_id = SK_NO_NATIVE; self->env = env; + self->node = node; + self->fun = NULL; } void symbol_free(struct symbol* self) @@ -108,6 +118,7 @@ void symbol_free(struct symbol* self) void sym_init(struct sym* self) { assert(self); + self->parent = NULL; self->id_counter = 1; self->closure_counter = 1; self->native_counter = 1; @@ -121,11 +132,12 @@ struct sym* sym_new_clone(struct sym* self) assert(self); struct sym* clone = malloc(sizeof(struct sym)); sym_init(clone); + env_free(clone->env); + free(clone->env); clone->id_counter = self->id_counter; clone->closure_counter = self->closure_counter; - env_free(clone->env); - free(clone->env); + clone->parent = self->parent; clone->env = self->env ? env_new_clone(self->env) : NULL; return clone; @@ -139,12 +151,13 @@ void sym_free(struct sym* self) self->env = NULL; } -int sym_decl_var(struct sym* self, char const* name) +int sym_decl_var(struct sym* self, char const* name, + struct node* node) { assert(self); assert(name); struct symbol* symbol = malloc(sizeof(struct symbol)); - symbol_init(symbol, self->id_counter, name, self->env); + symbol_init(symbol, self->id_counter, name, node, self->env); vec_push(&self->env->symbols, symbol); @@ -152,12 +165,13 @@ int sym_decl_var(struct sym* self, char const* name) return self->id_counter - 1; } -int sym_decl_const(struct sym* self, char const* name) +int sym_decl_const(struct sym* self, char const* name, + struct node* node) { assert(self); assert(name); struct symbol* symbol = malloc(sizeof(struct symbol)); - symbol_init(symbol, self->id_counter, name, self->env); + symbol_init(symbol, self->id_counter, name, node, self->env); symbol->is_const = true; vec_push(&self->env->symbols, symbol); @@ -165,27 +179,33 @@ int sym_decl_const(struct sym* self, char const* name) return self->id_counter - 1; } -int sym_decl_closure(struct sym* self, int id, char const* name) +int sym_decl_closure(struct sym* self, int id, char const* name, + struct node* node, struct fun* fun) { assert(self); assert(name); struct symbol* symbol = malloc(sizeof(struct symbol)); - symbol_init(symbol, self->closure_counter, name, self->env); + symbol_init(symbol, self->closure_counter, name, node, + self->env); symbol->is_const = false; symbol->closure_id = id; + symbol->fun = fun; vec_push(&self->env->symbols, symbol); self->closure_counter++; return self->closure_counter - 1; } -int sym_decl_global(struct sym* self, int id, char const* name) +int sym_decl_global(struct sym* self, + int id, + char const* name, + struct node* node) { assert(self); assert(name); struct symbol* symbol = malloc(sizeof(struct symbol)); - symbol_init(symbol, id, name, self->env); + symbol_init(symbol, id, name, node, self->env); symbol->is_global = true; vec_push(&self->env->symbols, symbol); return id; diff --git a/tests/lexer.h b/tests/lexer.h index e42f1c4..968e302 100644 --- a/tests/lexer.h +++ b/tests/lexer.h @@ -146,9 +146,10 @@ static void test_lexer_function() static void test_lexer_module() { - test_lexer("module :: ", 2, + test_lexer("module :: import", 3, "MODULE", - "MOD_ACCESS" + "MOD_ACCESS", + "IMPORT" ); } void register_lexer() diff --git a/tests/main.c b/tests/main.c index 3e58ae5..e0eae0c 100644 --- a/tests/main.c +++ b/tests/main.c @@ -2,6 +2,7 @@ #include #include "lexer.h" #include "parser.h" +#include "path.h" int main() { @@ -10,6 +11,7 @@ int main() register_lexer(); register_parser(); + register_path(); CU_basic_set_mode(CU_BRM_VERBOSE); CU_basic_run_tests(); diff --git a/tests/parser.h b/tests/parser.h index 04e2c11..a0d9639 100644 --- a/tests/parser.h +++ b/tests/parser.h @@ -165,6 +165,12 @@ static void test_parser_module() "x::hello()"); } +static void test_parser_import() +{ + test_parser("ROOT(IMPORT(STRING[./hello]))", + "import \"./hello\""); +} + void register_parser() { CU_pSuite suite = CU_add_suite("Parser", 0, 0); @@ -179,6 +185,7 @@ void register_parser() CU_add_test(suite, "IfExpression", test_parser_if); CU_add_test(suite, "Functions", test_parser_function); CU_add_test(suite, "Modules", test_parser_module); + CU_add_test(suite, "Imports", test_parser_import); } #endif diff --git a/tests/path.h b/tests/path.h new file mode 100644 index 0000000..2f88ff4 --- /dev/null +++ b/tests/path.h @@ -0,0 +1,94 @@ +#ifndef SK_TEST_PATH_H +#define SK_TEST_PATH_H + +#include +#include + +static void test_is_relative(bool oracle, char const* text) +{ + struct path path; + path_init(&path, text); + CU_ASSERT_FATAL(path_is_relative(&path) == oracle); + path_free(&path); +} + +static void test_path_relative() +{ + test_is_relative(true, "./module.sk"); + test_is_relative(false, "module.sk"); + test_is_relative(false, "/home/module.sk"); + test_is_relative(false, ""); +} + +static void test_path_set_ext(char const* oracle, + char const* text, + char const* ext) +{ + struct path path; + path_init(&path, text); + path_set_ext(&path, ext); + if (strcmp(path.str->value, oracle) != 0) + { + fprintf(stderr, "\n%s + %s", text, ext); + fprintf(stderr, "\n%s <> %s\n", oracle, path.str->value); + } + CU_ASSERT_STRING_EQUAL_FATAL(path.str->value, oracle); + path_free(&path); +} + +static void test_path_ext() +{ + test_path_set_ext("./hello/world", + "./hello/world", ""); + + test_path_set_ext("./hello/world", + "./hello/world.sk", ""); + + test_path_set_ext("./hello/world.sk", + "./hello/world", "sk"); + + test_path_set_ext("./hello/world.sk", + "./hello/world.sk", "sk"); + + test_path_set_ext("./hello/world.sk", + "./hello/world.com", "sk"); +} + +static void test_path_extract_name(char const* text, + char const* oracle) +{ + struct path path; + path_init(&path, text); + + struct str s; + str_init(&s); + + path_extract_name(&path, &s); + + if (strcmp(s.value, oracle) != 0) + { + fprintf(stderr, "\n%s <> %s\n", oracle, s.value); + } + + CU_ASSERT_STRING_EQUAL_FATAL(s.value, oracle); + str_free(&s); + path_free(&path); +} + +static void test_path_extract() +{ + test_path_extract_name("world.sk", "world.sk"); + test_path_extract_name("./world.sk", "world.sk"); + test_path_extract_name("./../world.sk", "../world.sk"); + test_path_extract_name("./world", "world"); + test_path_extract_name("./hello/world", "hello/world"); +} +void register_path() +{ + CU_pSuite suite = CU_add_suite("Path", 0, 0); + CU_add_test(suite, "Relative paths", test_path_relative); + CU_add_test(suite, "Extensions", test_path_ext); + CU_add_test(suite, "Extract name", test_path_extract); +} + +#endif