Compare commits
2 Commits
4d0edad298
...
2f73e3a0ca
Author | SHA1 | Date |
---|---|---|
bog | 2f73e3a0ca | |
bog | 6e6534acbd |
|
@ -10,6 +10,8 @@ EXPR ::=
|
||||||
| return EXPR
|
| return EXPR
|
||||||
| FUN_DECL
|
| FUN_DECL
|
||||||
| MOD_ACCESS
|
| MOD_ACCESS
|
||||||
|
| IMPORT
|
||||||
|
IMPORT ::= import string
|
||||||
MOD_ACCESS ::= EXPR mod_access ident
|
MOD_ACCESS ::= EXPR mod_access ident
|
||||||
FUN_DECL ::=
|
FUN_DECL ::=
|
||||||
| fun ident opar PARAMS cpar EXPR* end
|
| fun ident opar PARAMS cpar EXPR* end
|
||||||
|
@ -45,4 +47,4 @@ BUILTIN ::=
|
||||||
| int
|
| int
|
||||||
| bool
|
| bool
|
||||||
| float
|
| float
|
||||||
| string
|
| stri
|
||||||
|
|
|
@ -10,3 +10,8 @@ end
|
||||||
assert m::x eq 32
|
assert m::x eq 32
|
||||||
assert m::y eq "bim"
|
assert m::y eq "bim"
|
||||||
assert m::add(7, 2) eq 9
|
assert m::add(7, 2) eq 9
|
||||||
|
|
||||||
|
import "./other_mod"
|
||||||
|
|
||||||
|
assert other_mod::my_value eq 42
|
||||||
|
assert other_mod::f(3) eq 21
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
var x = 37
|
|
@ -28,6 +28,8 @@ add_library(skopy-lib SHARED
|
||||||
|
|
||||||
src/nfun.c
|
src/nfun.c
|
||||||
src/natives.c
|
src/natives.c
|
||||||
|
|
||||||
|
src/path.c
|
||||||
)
|
)
|
||||||
|
|
||||||
file(GLOB_RECURSE
|
file(GLOB_RECURSE
|
||||||
|
|
|
@ -17,6 +17,7 @@ struct compiler
|
||||||
{
|
{
|
||||||
struct vec var_names;
|
struct vec var_names;
|
||||||
struct vec modules;
|
struct vec modules;
|
||||||
|
struct vec funs;
|
||||||
};
|
};
|
||||||
void mod_free(struct mod* self);
|
void mod_free(struct mod* self);
|
||||||
void compiler_init(struct compiler* self);
|
void compiler_init(struct compiler* self);
|
||||||
|
@ -58,5 +59,16 @@ void compiler_compile_if(struct compiler* self,
|
||||||
struct sym* sym,
|
struct sym* sym,
|
||||||
struct state* state,
|
struct state* state,
|
||||||
struct vec* to_end);
|
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
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -16,10 +16,10 @@ void exec_free(struct exec* self);
|
||||||
|
|
||||||
void exec_execute(struct exec* self,
|
void exec_execute(struct exec* self,
|
||||||
struct state* state,
|
struct state* state,
|
||||||
|
struct sym* sym,
|
||||||
struct prog* prog);
|
struct prog* prog);
|
||||||
|
|
||||||
void exec_capture_env(struct exec* self,
|
void exec_capture_env(struct exec* self,
|
||||||
struct state* state,
|
struct state* state,
|
||||||
struct fun* fun,
|
struct fun* fun);
|
||||||
struct env* env);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#include "commons.h"
|
#include "commons.h"
|
||||||
|
|
||||||
|
extern int FunId;
|
||||||
|
|
||||||
struct closure
|
struct closure
|
||||||
{
|
{
|
||||||
int id;
|
int id;
|
||||||
|
@ -11,6 +13,8 @@ struct closure
|
||||||
|
|
||||||
struct fun
|
struct fun
|
||||||
{
|
{
|
||||||
|
int id;
|
||||||
|
int base;
|
||||||
struct prog* prog;
|
struct prog* prog;
|
||||||
struct sym* sym;
|
struct sym* sym;
|
||||||
struct vec closures;
|
struct vec closures;
|
||||||
|
@ -20,7 +24,7 @@ void closure_init(struct closure* self, int id, struct value* value);
|
||||||
struct closure* closure_new_clone(struct closure* self);
|
struct closure* closure_new_clone(struct closure* self);
|
||||||
void closure_free(struct closure* self);
|
void closure_free(struct closure* self);
|
||||||
|
|
||||||
void fun_init(struct fun* self, struct prog* new_prog);
|
void fun_init(struct fun* self, struct prog* new_prog, int base);
|
||||||
void fun_free(struct fun* self);
|
void fun_free(struct fun* self);
|
||||||
struct fun* fun_new_clone(struct fun* self);
|
struct fun* fun_new_clone(struct fun* self);
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,9 @@ void natives_decl(struct state* state,
|
||||||
nfun_body fun,
|
nfun_body fun,
|
||||||
int arity);
|
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
|
#endif
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
#include "commons.h"
|
#include "commons.h"
|
||||||
#include "state.h"
|
#include "state.h"
|
||||||
|
|
||||||
typedef SK (*nfun_body)(struct state*, struct vec*);
|
typedef SK (*nfun_body)(struct state*, struct sym*, struct vec*);
|
||||||
|
|
||||||
struct nfun
|
struct nfun
|
||||||
{
|
{
|
||||||
|
@ -17,5 +17,6 @@ void nfun_free(struct nfun* self);
|
||||||
|
|
||||||
SK nfun_call(struct nfun* self,
|
SK nfun_call(struct nfun* self,
|
||||||
struct state* state,
|
struct state* state,
|
||||||
|
struct sym* sym,
|
||||||
struct vec* args);
|
struct vec* args);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -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_CONST_DECL), G(NODE_IDENT), G(NODE_ASSIGN), \
|
||||||
G(NODE_BLOCK), G(NODE_IF), G(NODE_FUN), G(NODE_PARAMS), \
|
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_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);
|
SK_ENUM_H(NodeKind, NODE_KIND);
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ struct node* parser_try(struct parser* self,
|
||||||
struct node* parser_try_parse(struct parser* self);
|
struct node* parser_try_parse(struct parser* self);
|
||||||
struct node* parser_try_root(struct parser* self);
|
struct node* parser_try_root(struct parser* self);
|
||||||
struct node* parser_try_expr(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_fun_decl(struct parser* self);
|
||||||
struct node* parser_try_block(struct parser* self);
|
struct node* parser_try_block(struct parser* self);
|
||||||
struct node* parser_try_inner_block(struct parser* self);
|
struct node* parser_try_inner_block(struct parser* self);
|
||||||
|
|
|
@ -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
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
#define SK_NO_PARAM (-1)
|
#define SK_NO_PARAM (-1)
|
||||||
#define OPCODE(G) \
|
#define OPCODE(G) \
|
||||||
G(OP_PUSH), \
|
G(OP_PUSH), G(OP_POP), \
|
||||||
G(OP_ADD), G(OP_SUB), G(OP_MUL), \
|
G(OP_ADD), G(OP_SUB), G(OP_MUL), \
|
||||||
G(OP_DIV), G(OP_MOD), G(OP_POW), \
|
G(OP_DIV), G(OP_MOD), G(OP_POW), \
|
||||||
G(OP_USUB), G(OP_ASSERT_EQ), \
|
G(OP_USUB), G(OP_ASSERT_EQ), \
|
||||||
|
|
|
@ -24,6 +24,7 @@ struct frame
|
||||||
struct vec locals;
|
struct vec locals;
|
||||||
struct vec stack;
|
struct vec stack;
|
||||||
struct fun* fun;
|
struct fun* fun;
|
||||||
|
struct frame* parent;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct global
|
struct global
|
||||||
|
@ -41,7 +42,7 @@ struct state
|
||||||
struct vec global_values;
|
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,
|
void stack_value_init(struct stack_value* self,
|
||||||
size_t addr,
|
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);
|
struct frame* state_frame(struct state* self);
|
||||||
void state_push_frame(struct state* self);
|
void state_push_frame(struct state* self);
|
||||||
void state_pop_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);
|
SK state_top(struct state* self);
|
||||||
struct value* state_try_get_value(struct state* self, SK value);
|
struct value* state_try_get_value(struct state* self, SK value);
|
||||||
|
|
|
@ -4,6 +4,10 @@
|
||||||
#include "commons.h"
|
#include "commons.h"
|
||||||
#define SK_NO_CLOSURE (-1)
|
#define SK_NO_CLOSURE (-1)
|
||||||
#define SK_NO_NATIVE (-1)
|
#define SK_NO_NATIVE (-1)
|
||||||
|
#include "value.h"
|
||||||
|
|
||||||
|
|
||||||
|
extern int IdCounter;
|
||||||
|
|
||||||
struct symbol
|
struct symbol
|
||||||
{
|
{
|
||||||
|
@ -14,6 +18,8 @@ struct symbol
|
||||||
bool is_const;
|
bool is_const;
|
||||||
bool is_global;
|
bool is_global;
|
||||||
struct env* env;
|
struct env* env;
|
||||||
|
struct node* node;
|
||||||
|
struct fun* fun;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct env
|
struct env
|
||||||
|
@ -24,8 +30,7 @@ struct env
|
||||||
|
|
||||||
struct sym
|
struct sym
|
||||||
{
|
{
|
||||||
int id_counter;
|
struct sym* parent;
|
||||||
int closure_counter;
|
|
||||||
int native_counter;
|
int native_counter;
|
||||||
int global_counter;
|
int global_counter;
|
||||||
struct env* env;
|
struct env* env;
|
||||||
|
@ -41,6 +46,7 @@ struct symbol* env_try_get_by_id(struct env* self, int id);
|
||||||
void symbol_init(struct symbol* self,
|
void symbol_init(struct symbol* self,
|
||||||
int id,
|
int id,
|
||||||
char const* name,
|
char const* name,
|
||||||
|
struct node* node,
|
||||||
struct env* env);
|
struct env* env);
|
||||||
|
|
||||||
void symbol_free(struct symbol* self);
|
void symbol_free(struct symbol* self);
|
||||||
|
@ -49,10 +55,14 @@ void sym_init(struct sym* self);
|
||||||
struct sym* sym_new_clone(struct sym* self);
|
struct sym* sym_new_clone(struct sym* self);
|
||||||
void sym_free(struct sym* self);
|
void sym_free(struct sym* self);
|
||||||
|
|
||||||
int sym_decl_var(struct sym* self, char const* name);
|
int sym_decl_var(struct sym* self, char const* name,
|
||||||
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);
|
int sym_decl_const(struct sym* self, char const* name,
|
||||||
int sym_decl_global(struct sym* self, int id, 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_open_scope(struct sym* self);
|
||||||
void sym_close_scope(struct sym* self);
|
void sym_close_scope(struct sym* self);
|
||||||
|
|
|
@ -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_CONST), G(TOKEN_ASSIGN), G(TOKEN_IDENT), \
|
||||||
G(TOKEN_BEGIN), G(TOKEN_END), G(TOKEN_IF), G(TOKEN_ELSE), \
|
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_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);
|
SK_ENUM_H(TokenKind, TOKEN_KIND);
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "compiler.h"
|
#include "compiler.h"
|
||||||
|
#include "path.h"
|
||||||
#include "token.h"
|
#include "token.h"
|
||||||
#include "state.h"
|
#include "state.h"
|
||||||
#include "natives.h"
|
#include "natives.h"
|
||||||
|
@ -9,6 +10,7 @@ void compiler_init(struct compiler* self)
|
||||||
assert(self);
|
assert(self);
|
||||||
vec_init(&self->var_names);
|
vec_init(&self->var_names);
|
||||||
vec_init(&self->modules);
|
vec_init(&self->modules);
|
||||||
|
vec_init(&self->funs);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mod_free(struct mod* self)
|
void mod_free(struct mod* self)
|
||||||
|
@ -22,6 +24,7 @@ void compiler_free(struct compiler* self)
|
||||||
vec_free(&self->var_names);
|
vec_free(&self->var_names);
|
||||||
vec_free_elements(&self->modules, (void*) mod_free);
|
vec_free_elements(&self->modules, (void*) mod_free);
|
||||||
vec_free(&self->modules);
|
vec_free(&self->modules);
|
||||||
|
vec_free(&self->funs);
|
||||||
}
|
}
|
||||||
|
|
||||||
void compiler_compile(struct compiler* self,
|
void compiler_compile(struct compiler* self,
|
||||||
|
@ -44,6 +47,48 @@ void compiler_compile(struct compiler* self,
|
||||||
}
|
}
|
||||||
} break;
|
} 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: {
|
case NODE_BLOCK: {
|
||||||
sym_open_scope(sym);
|
sym_open_scope(sym);
|
||||||
for (size_t i=0; i<node->children.size; i++)
|
for (size_t i=0; i<node->children.size; i++)
|
||||||
|
@ -118,7 +163,8 @@ void compiler_compile(struct compiler* self,
|
||||||
struct node* expr = node->children.data[1];
|
struct node* expr = node->children.data[1];
|
||||||
compiler_compile(self, expr, prog, sym, state);
|
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);
|
prog_add_instr(prog, OP_LOCAL_STORE, id);
|
||||||
char* name = vec_pop(&self->var_names);
|
char* name = vec_pop(&self->var_names);
|
||||||
|
@ -136,7 +182,8 @@ void compiler_compile(struct compiler* self,
|
||||||
}
|
}
|
||||||
struct node* expr = node->children.data[1];
|
struct node* expr = node->children.data[1];
|
||||||
compiler_compile(self, expr, prog, sym, state);
|
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);
|
prog_add_instr(prog, OP_LOCAL_STORE, id);
|
||||||
char* name = vec_pop(&self->var_names);
|
char* name = vec_pop(&self->var_names);
|
||||||
free(name);
|
free(name);
|
||||||
|
@ -145,7 +192,12 @@ void compiler_compile(struct compiler* self,
|
||||||
case NODE_ASSIGN: {
|
case NODE_ASSIGN: {
|
||||||
struct node* ident = node->children.data[0];
|
struct node* ident = node->children.data[0];
|
||||||
struct node* expr = node->children.data[1];
|
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)
|
if (!symbol)
|
||||||
{
|
{
|
||||||
|
@ -174,19 +226,26 @@ void compiler_compile(struct compiler* self,
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_IDENT: {
|
case NODE_IDENT: {
|
||||||
struct symbol* symbol = sym_try_get(sym,
|
char* name = node->token->value;
|
||||||
node->token->value);
|
|
||||||
|
struct symbol* symbol = compiler_find(self,
|
||||||
|
name,
|
||||||
|
sym,
|
||||||
|
node);
|
||||||
|
|
||||||
if (!symbol)
|
if (!symbol)
|
||||||
{
|
{
|
||||||
errors_push(node->token->line,
|
errors_push(node->token->line,
|
||||||
"unknown identifier '%s'.",
|
"unknown identifier '%s'.",
|
||||||
node->token->value);
|
name);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct env* itr = sym->env->parent;
|
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);
|
struct symbol const* s = env_try_get(itr, symbol->name);
|
||||||
|
|
||||||
|
@ -196,6 +255,7 @@ void compiler_compile(struct compiler* self,
|
||||||
}
|
}
|
||||||
|
|
||||||
itr = itr->parent;
|
itr = itr->parent;
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (symbol->is_global)
|
if (symbol->is_global)
|
||||||
|
@ -281,6 +341,7 @@ void compiler_compile(struct compiler* self,
|
||||||
errors_push(node->token->line,
|
errors_push(node->token->line,
|
||||||
"unknown module '%s'.",
|
"unknown module '%s'.",
|
||||||
mod_name->token->value);
|
mod_name->token->value);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct symbol* symbol = sym_try_get(
|
struct symbol* symbol = sym_try_get(
|
||||||
|
@ -306,9 +367,11 @@ void compiler_compile(struct compiler* self,
|
||||||
struct prog* p = malloc(sizeof(struct prog));
|
struct prog* p = malloc(sizeof(struct prog));
|
||||||
prog_init(p);
|
prog_init(p);
|
||||||
|
|
||||||
fun_init(fun, p);
|
fun_init(fun, p, IdCounter);
|
||||||
natives_populate(state, fun->sym);
|
natives_populate(state, fun->sym);
|
||||||
|
|
||||||
|
// Self value
|
||||||
|
// ----------
|
||||||
struct node* params = node->children.data[0];
|
struct node* params = node->children.data[0];
|
||||||
struct node* body = node->children.data[1];
|
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]
|
self->var_names.data[self->var_names.size - 1]
|
||||||
: NULL;
|
: NULL;
|
||||||
|
|
||||||
|
// Parameters
|
||||||
|
// ----------
|
||||||
for (size_t i=0; i<params->children.size; i++)
|
for (size_t i=0; i<params->children.size; i++)
|
||||||
{
|
{
|
||||||
struct node* child = params->children.data[i];
|
struct node* child = params->children.data[i];
|
||||||
char* name = child->token->value;
|
char* name = child->token->value;
|
||||||
sym_decl_var(fun->sym, name);
|
sym_decl_var(fun->sym, name, child);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (var_name)
|
if (var_name)
|
||||||
{
|
{
|
||||||
sym_decl_var(fun->sym, var_name);
|
sym_decl_var(fun->sym, var_name, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Closure
|
fun->sym->parent = sym;
|
||||||
{
|
|
||||||
for (size_t i=0; i<sym->env->symbols.size; i++)
|
|
||||||
{
|
|
||||||
struct symbol* s = sym->env->symbols.data[i];
|
|
||||||
sym_decl_closure(fun->sym, s->id, s->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sym->env->parent)
|
vec_push(&self->funs, fun);
|
||||||
{
|
compiler_compile_fun(self, body, p, fun->sym, state);
|
||||||
for (
|
vec_pop(&self->funs);
|
||||||
size_t i=0;
|
|
||||||
i<sym->env->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);
|
|
||||||
|
|
||||||
union val val;
|
union val val;
|
||||||
val.fun = fun;
|
val.fun = fun;
|
||||||
|
@ -361,6 +406,7 @@ void compiler_compile(struct compiler* self,
|
||||||
val);
|
val);
|
||||||
prog_add_instr(prog, OP_MAKE_REF, SK_NO_PARAM);
|
prog_add_instr(prog, OP_MAKE_REF, SK_NO_PARAM);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_BOOL: {
|
case NODE_BOOL: {
|
||||||
union val val;
|
union val val;
|
||||||
val.boolean =
|
val.boolean =
|
||||||
|
@ -619,3 +665,77 @@ void compiler_compile_if(struct compiler* self,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct symbol* compiler_find(struct compiler* self,
|
||||||
|
char* name,
|
||||||
|
struct sym* sym,
|
||||||
|
struct node* node)
|
||||||
|
{
|
||||||
|
struct symbol* symbol = NULL;
|
||||||
|
struct sym* itr = sym->parent;
|
||||||
|
|
||||||
|
symbol = sym_try_get(sym, name);
|
||||||
|
if (symbol)
|
||||||
|
{
|
||||||
|
return symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
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; i<node->children.size; i++)
|
||||||
|
{
|
||||||
|
compiler_compile(self, node->children.data[i],
|
||||||
|
prog, sym, state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
compiler_compile(self, node, prog, sym, state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
179
lib/src/exec.c
179
lib/src/exec.c
|
@ -17,6 +17,7 @@ void exec_free(struct exec* self)
|
||||||
|
|
||||||
void exec_execute(struct exec* self,
|
void exec_execute(struct exec* self,
|
||||||
struct state* state,
|
struct state* state,
|
||||||
|
struct sym* sym,
|
||||||
struct prog* prog)
|
struct prog* prog)
|
||||||
{
|
{
|
||||||
while (self->pc < prog->opcodes.size)
|
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));
|
struct value* f = value_new_clone(state_try_get_value(state, function));
|
||||||
|
|
||||||
|
assert(f->type == TYPE_REF);
|
||||||
struct value* val_fun = state_try_deref(
|
struct value* val_fun = state_try_deref(
|
||||||
state,
|
state,
|
||||||
f->val.ref
|
f->val.ref
|
||||||
|
@ -136,6 +138,7 @@ void exec_execute(struct exec* self,
|
||||||
}
|
}
|
||||||
SK res = nfun_call(val_fun->val.nfun,
|
SK res = nfun_call(val_fun->val.nfun,
|
||||||
state,
|
state,
|
||||||
|
sym,
|
||||||
&ordered);
|
&ordered);
|
||||||
struct value* value =
|
struct value* value =
|
||||||
state_try_get_value(state, res);
|
state_try_get_value(state, res);
|
||||||
|
@ -167,18 +170,20 @@ void exec_execute(struct exec* self,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct fun* fun = val_fun->val.fun;
|
struct fun* fun = val_fun->val.fun;
|
||||||
|
|
||||||
state_call(state, fun);
|
state_call(state, fun);
|
||||||
|
|
||||||
|
// Params
|
||||||
|
// ------
|
||||||
for (size_t i=0; i<params.size; i++)
|
for (size_t i=0; i<params.size; i++)
|
||||||
{
|
{
|
||||||
size_t k = params.size - 1 - i;
|
size_t k = params.size - 1 - i;
|
||||||
struct value* val = params.data[k];
|
struct value* val = params.data[k];
|
||||||
state_push(state, val->type, val->val, val->line);
|
state_push(state, val->type, val->val, val->line);
|
||||||
state_local_store(state, i+1);
|
state_local_store(state, fun->base + i);
|
||||||
}
|
}
|
||||||
|
|
||||||
state_push(state, f->type, f->val, f->line);
|
state_push(state, f->type, f->val, f->line);
|
||||||
state_local_store(state, params.size + 1);
|
state_local_store(state, fun->base + params.size);
|
||||||
|
|
||||||
vec_free_elements(¶ms, NULL);
|
vec_free_elements(¶ms, NULL);
|
||||||
vec_free(¶ms);
|
vec_free(¶ms);
|
||||||
|
@ -191,7 +196,8 @@ void exec_execute(struct exec* self,
|
||||||
struct value* fun_val =
|
struct value* fun_val =
|
||||||
state_try_deref(state, f->val.ref);
|
state_try_deref(state, f->val.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(
|
struct value* res = value_new_clone(state_try_get_value(
|
||||||
state,
|
state,
|
||||||
|
@ -211,15 +217,19 @@ void exec_execute(struct exec* self,
|
||||||
self->pc++;
|
self->pc++;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case OP_POP: {
|
||||||
|
state_pop(state);
|
||||||
|
self->pc++;
|
||||||
|
} break;
|
||||||
|
|
||||||
case OP_PUSH: {
|
case OP_PUSH: {
|
||||||
struct value* constant = prog->constants.data[param];
|
struct value* constant = prog->constants.data[param];
|
||||||
switch (constant->type)
|
switch (constant->type)
|
||||||
{
|
{
|
||||||
case TYPE_FUN: {
|
case TYPE_FUN: {
|
||||||
|
struct fun* fun =
|
||||||
struct fun* fun = fun_new_clone(constant->val.fun);
|
fun_new_clone(constant->val.fun);
|
||||||
struct sym* s = fun->sym;
|
exec_capture_env(self, state, fun);
|
||||||
exec_capture_env(self, state, fun, s->env);
|
|
||||||
|
|
||||||
state_push_fun(
|
state_push_fun(
|
||||||
state,
|
state,
|
||||||
|
@ -235,7 +245,8 @@ void exec_execute(struct exec* self,
|
||||||
struct exec exec;
|
struct exec exec;
|
||||||
exec_init(&exec);
|
exec_init(&exec);
|
||||||
|
|
||||||
exec_execute(&exec, mod->state, mod->prog);
|
exec_execute(&exec, mod->state,
|
||||||
|
sym, mod->prog);
|
||||||
|
|
||||||
exec_free(&exec);
|
exec_free(&exec);
|
||||||
|
|
||||||
|
@ -391,59 +402,123 @@ void exec_execute(struct exec* self,
|
||||||
|
|
||||||
void exec_capture_env(struct exec* self,
|
void exec_capture_env(struct exec* self,
|
||||||
struct state* state,
|
struct state* state,
|
||||||
struct fun* fun,
|
struct fun* fun)
|
||||||
struct env* env)
|
|
||||||
{
|
{
|
||||||
(void) self;
|
(void) self;
|
||||||
|
|
||||||
if (env->parent)
|
struct env* itr = fun->sym->env;
|
||||||
|
|
||||||
|
while (itr)
|
||||||
{
|
{
|
||||||
for (size_t i=0; i<env->parent->symbols.size; i++)
|
for (size_t i=0; i<itr->symbols.size; i++)
|
||||||
{
|
{
|
||||||
struct symbol* symbol = env->parent->symbols.data[i];
|
struct symbol* symbol = itr->symbols.data[i];
|
||||||
if (symbol->closure_id != SK_NO_CLOSURE)
|
for (size_t j=0; j<state->frames.size; j++)
|
||||||
{
|
{
|
||||||
struct local* loc =
|
size_t k = state->frames.size - j - 1;
|
||||||
state_try_get_local_by_id(
|
struct frame* frame = state->frames.data[k];
|
||||||
state,
|
|
||||||
symbol->closure_id
|
|
||||||
);
|
|
||||||
|
|
||||||
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 =
|
if (loc)
|
||||||
state_try_get_value(
|
{
|
||||||
state,
|
struct value* val = frame_try_get_value(
|
||||||
loc->addr
|
frame,
|
||||||
);
|
loc->addr
|
||||||
|
);
|
||||||
|
|
||||||
fun_capture(fun, symbol->id, val);
|
fun_capture(fun, symbol->id, val);
|
||||||
}
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (env)
|
|
||||||
{
|
|
||||||
for (size_t i=0; i<env->symbols.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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
itr = itr->parent;
|
||||||
}
|
}
|
||||||
|
// struct env* itr = env;
|
||||||
|
//
|
||||||
|
// if (itr)
|
||||||
|
// {
|
||||||
|
// for (size_t i=0; i<itr->symbols.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; i<env->parent->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; i<env->symbols.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);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "fun.h"
|
#include "fun.h"
|
||||||
#include "prog.h"
|
#include "prog.h"
|
||||||
#include "sym.h"
|
#include "sym.h"
|
||||||
|
int FunId = 0;
|
||||||
|
|
||||||
void closure_init(struct closure* self, int id, struct value* value)
|
void closure_init(struct closure* self, int id, struct value* value)
|
||||||
{
|
{
|
||||||
|
@ -26,9 +27,12 @@ void closure_free(struct closure* self)
|
||||||
free(self->value);
|
free(self->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void fun_init(struct fun* self, struct prog* new_prog)
|
void fun_init(struct fun* self, struct prog* new_prog, int base)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
|
self->id = FunId;
|
||||||
|
self->base = base;
|
||||||
|
FunId++;
|
||||||
self->prog = new_prog;
|
self->prog = new_prog;
|
||||||
self->sym = malloc(sizeof(struct sym));
|
self->sym = malloc(sizeof(struct sym));
|
||||||
sym_init(self->sym);
|
sym_init(self->sym);
|
||||||
|
@ -51,11 +55,13 @@ struct fun* fun_new_clone(struct fun* self)
|
||||||
{
|
{
|
||||||
(void) self;
|
(void) self;
|
||||||
struct fun* clone = malloc(sizeof(struct fun));
|
struct fun* clone = malloc(sizeof(struct fun));
|
||||||
fun_init(clone, prog_new_clone(self->prog));
|
fun_init(clone, prog_new_clone(self->prog), self->base);
|
||||||
sym_free(clone->sym);
|
sym_free(clone->sym);
|
||||||
free(clone->sym);
|
free(clone->sym);
|
||||||
clone->sym = sym_new_clone(self->sym);
|
clone->sym = sym_new_clone(self->sym);
|
||||||
|
|
||||||
|
clone->id = self->id;
|
||||||
|
|
||||||
for (size_t i=0; i<self->closures.size; i++)
|
for (size_t i=0; i<self->closures.size; i++)
|
||||||
{
|
{
|
||||||
struct closure* closure = self->closures.data[i];
|
struct closure* closure = self->closures.data[i];
|
||||||
|
|
|
@ -198,6 +198,7 @@ struct token* lexer_try_new_next(struct lexer* self)
|
||||||
SK_SCAN_TEXT("=", TOKEN_ASSIGN);
|
SK_SCAN_TEXT("=", TOKEN_ASSIGN);
|
||||||
SK_SCAN_TEXT(",", TOKEN_COMMA);
|
SK_SCAN_TEXT(",", TOKEN_COMMA);
|
||||||
SK_SCAN_KEYWORD("fun", TOKEN_FUN, NULL);
|
SK_SCAN_KEYWORD("fun", TOKEN_FUN, NULL);
|
||||||
|
SK_SCAN_KEYWORD("import", TOKEN_IMPORT, NULL);
|
||||||
SK_SCAN_KEYWORD("return", TOKEN_RETURN, NULL);
|
SK_SCAN_KEYWORD("return", TOKEN_RETURN, NULL);
|
||||||
SK_SCAN_KEYWORD("if", TOKEN_IF, NULL);
|
SK_SCAN_KEYWORD("if", TOKEN_IF, NULL);
|
||||||
SK_SCAN_KEYWORD("else", TOKEN_ELSE, NULL);
|
SK_SCAN_KEYWORD("else", TOKEN_ELSE, NULL);
|
||||||
|
|
|
@ -104,7 +104,7 @@ int module_compile(struct module* self)
|
||||||
struct exec exec;
|
struct exec exec;
|
||||||
exec_init(&exec);
|
exec_init(&exec);
|
||||||
|
|
||||||
exec_execute(&exec, self->state, self->prog);
|
exec_execute(&exec, self->state, self->sym, self->prog);
|
||||||
|
|
||||||
if (!errors_ok())
|
if (!errors_ok())
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
#include "natives.h"
|
#include "natives.h"
|
||||||
|
#include "path.h"
|
||||||
|
#include "module.h"
|
||||||
|
|
||||||
void natives_populate(struct state* state, struct sym* sym)
|
void natives_populate(struct state* state, struct sym* sym)
|
||||||
{
|
{
|
||||||
|
@ -6,6 +8,7 @@ void natives_populate(struct state* state, struct sym* sym)
|
||||||
assert(sym);
|
assert(sym);
|
||||||
|
|
||||||
natives_decl(state, sym, "println", native_println, -1);
|
natives_decl(state, sym, "println", native_println, -1);
|
||||||
|
natives_decl(state, sym, "import", native_import, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void natives_decl(struct state* state,
|
void natives_decl(struct state* state,
|
||||||
|
@ -16,12 +19,16 @@ void natives_decl(struct state* state,
|
||||||
{
|
{
|
||||||
assert(state);
|
assert(state);
|
||||||
assert(sym);
|
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);
|
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; i<args->size; i++)
|
for (size_t i=0; i<args->size; i++)
|
||||||
{
|
{
|
||||||
struct value* arg
|
struct value* arg
|
||||||
|
@ -37,3 +44,38 @@ SK native_println(struct state* state, struct vec* args)
|
||||||
printf("\n");
|
printf("\n");
|
||||||
return state_push_bool(state, true, 0);
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ void nfun_free(struct nfun* self)
|
||||||
|
|
||||||
SK nfun_call(struct nfun* self,
|
SK nfun_call(struct nfun* self,
|
||||||
struct state* state,
|
struct state* state,
|
||||||
|
struct sym* sym,
|
||||||
struct vec* args)
|
struct vec* args)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
|
@ -33,7 +34,7 @@ SK nfun_call(struct nfun* self,
|
||||||
return state_push_bool(state, false, line);
|
return state_push_bool(state, false, line);
|
||||||
}
|
}
|
||||||
|
|
||||||
SK result = (*self->body)(state, args);
|
SK result = (*self->body)(state, sym, args);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -143,9 +143,42 @@ struct node* parser_try_expr(struct parser* self)
|
||||||
return SK_TRY(parser_try_fun_decl);
|
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);
|
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)
|
struct node* parser_try_fun_decl(struct parser* self)
|
||||||
{
|
{
|
||||||
if (!lexer_next_is(&self->lexer, TOKEN_FUN))
|
if (!lexer_next_is(&self->lexer, TOKEN_FUN))
|
||||||
|
|
|
@ -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; i<idx; i++)
|
||||||
|
{
|
||||||
|
str_push(str, self->str->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; i<self->str->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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,13 +26,14 @@ void frame_init(struct frame* self)
|
||||||
vec_init(&self->locals);
|
vec_init(&self->locals);
|
||||||
vec_init(&self->stack);
|
vec_init(&self->stack);
|
||||||
self->fun = NULL;
|
self->fun = NULL;
|
||||||
|
self->parent = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct frame* frame_new_clone(struct frame* self)
|
struct frame* frame_new_clone(struct frame* self)
|
||||||
{
|
{
|
||||||
struct frame* clone = malloc(sizeof(struct frame));
|
struct frame* clone = malloc(sizeof(struct frame));
|
||||||
frame_init(clone);
|
frame_init(clone);
|
||||||
|
|
||||||
// struct vec stack_values;
|
// struct vec stack_values;
|
||||||
for (size_t i=0; i<self->stack_values.size; i++)
|
for (size_t i=0; i<self->stack_values.size; i++)
|
||||||
{
|
{
|
||||||
|
@ -61,7 +62,7 @@ struct frame* frame_new_clone(struct frame* self)
|
||||||
|
|
||||||
// struct fun* fun;
|
// struct fun* fun;
|
||||||
clone->fun = self->fun;
|
clone->fun = self->fun;
|
||||||
|
clone->parent = self->parent;
|
||||||
return clone;
|
return clone;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,9 +108,10 @@ struct state* state_new_clone(struct state* self)
|
||||||
struct global const* glob = self->globals.data[i];
|
struct global const* glob = self->globals.data[i];
|
||||||
struct global* global = malloc(sizeof(struct global));
|
struct global* global = malloc(sizeof(struct global));
|
||||||
global->id = glob->id;
|
global->id = glob->id;
|
||||||
global->addr = glob->id;
|
global->addr = glob->addr;
|
||||||
vec_push(&clone->globals, global);
|
vec_push(&clone->globals, global);
|
||||||
}
|
}
|
||||||
|
|
||||||
// struct vec global_values;
|
// struct vec global_values;
|
||||||
for (size_t i=0; i<self->global_values.size; i++)
|
for (size_t i=0; i<self->global_values.size; i++)
|
||||||
{
|
{
|
||||||
|
@ -179,7 +181,10 @@ void state_push_frame(struct state* self)
|
||||||
assert(self);
|
assert(self);
|
||||||
struct frame* frame = malloc(sizeof(struct frame));
|
struct frame* frame = malloc(sizeof(struct frame));
|
||||||
frame_init(frame);
|
frame_init(frame);
|
||||||
|
if (self->frames.size > 1)
|
||||||
|
{
|
||||||
|
frame->parent = self->frames.data[self->frames.size - 1];
|
||||||
|
}
|
||||||
vec_push(&self->frames, frame);
|
vec_push(&self->frames, frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,6 +196,38 @@ void state_pop_frame(struct state* self)
|
||||||
free(frame);
|
free(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct value* frame_try_get_value(struct frame* self, SK value)
|
||||||
|
{
|
||||||
|
assert(self);
|
||||||
|
|
||||||
|
for (size_t i=0; i<self->stack_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; i<self->locals.size; i++)
|
||||||
|
{
|
||||||
|
struct local* loc = self->locals.data[i];
|
||||||
|
|
||||||
|
if (loc->id == id)
|
||||||
|
{
|
||||||
|
return loc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
SK state_top(struct state* self)
|
SK state_top(struct state* self)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
|
@ -450,16 +487,25 @@ void state_module_load(struct state* self,
|
||||||
struct value* mod_value = state_try_deref(self, ref_val->val.ref);
|
struct value* mod_value = state_try_deref(self, ref_val->val.ref);
|
||||||
struct module* module = mod_value->val.mod;
|
struct module* module = mod_value->val.mod;
|
||||||
|
|
||||||
struct symbol* symbol = sym_try_get_by_id(
|
struct symbol const* symbol = sym_try_get_by_id(
|
||||||
module->sym,
|
module->sym,
|
||||||
id
|
id
|
||||||
);
|
);
|
||||||
|
|
||||||
struct value* value
|
struct local* loca = state_try_get_local_by_id(module->state, symbol->id);
|
||||||
= value_new_clone(state_try_get_value(module->state, symbol->id));
|
struct value* value
|
||||||
|
= state_try_get_value(module->state, loca->addr);
|
||||||
|
|
||||||
|
if (value->type == TYPE_REF)
|
||||||
if (value->type == TYPE_FUN)
|
{
|
||||||
|
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_push_ref(self,
|
||||||
state_add_global(self, value),
|
state_add_global(self, value),
|
||||||
|
@ -468,7 +514,6 @@ void state_module_load(struct state* self,
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
state_push(self, value->type, value->val, value->line);
|
state_push(self, value->type, value->val, value->line);
|
||||||
free(value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "sym.h"
|
#include "sym.h"
|
||||||
|
|
||||||
|
int IdCounter = 0;
|
||||||
|
|
||||||
void env_init(struct env* self)
|
void env_init(struct env* self)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
|
@ -23,11 +25,13 @@ struct env* env_new_clone(struct env* self)
|
||||||
new_symbol->closure_id = symbol->closure_id;
|
new_symbol->closure_id = symbol->closure_id;
|
||||||
new_symbol->native_id = symbol->native_id;
|
new_symbol->native_id = symbol->native_id;
|
||||||
new_symbol->env = clone;
|
new_symbol->env = clone;
|
||||||
|
new_symbol->node = symbol->node;
|
||||||
|
new_symbol->fun = symbol->fun;
|
||||||
|
|
||||||
vec_push(&clone->symbols, new_symbol);
|
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;
|
return clone;
|
||||||
}
|
}
|
||||||
|
@ -87,6 +91,7 @@ struct symbol* env_try_get_by_id(struct env* self, int id)
|
||||||
void symbol_init(struct symbol* self,
|
void symbol_init(struct symbol* self,
|
||||||
int id,
|
int id,
|
||||||
char const* name,
|
char const* name,
|
||||||
|
struct node* node,
|
||||||
struct env* env)
|
struct env* env)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
|
@ -97,6 +102,8 @@ void symbol_init(struct symbol* self,
|
||||||
self->closure_id = SK_NO_CLOSURE;
|
self->closure_id = SK_NO_CLOSURE;
|
||||||
self->native_id = SK_NO_NATIVE;
|
self->native_id = SK_NO_NATIVE;
|
||||||
self->env = env;
|
self->env = env;
|
||||||
|
self->node = node;
|
||||||
|
self->fun = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void symbol_free(struct symbol* self)
|
void symbol_free(struct symbol* self)
|
||||||
|
@ -108,8 +115,7 @@ void symbol_free(struct symbol* self)
|
||||||
void sym_init(struct sym* self)
|
void sym_init(struct sym* self)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
self->id_counter = 1;
|
self->parent = NULL;
|
||||||
self->closure_counter = 1;
|
|
||||||
self->native_counter = 1;
|
self->native_counter = 1;
|
||||||
self->global_counter = 1;
|
self->global_counter = 1;
|
||||||
self->env = malloc(sizeof(struct env));
|
self->env = malloc(sizeof(struct env));
|
||||||
|
@ -121,11 +127,10 @@ struct sym* sym_new_clone(struct sym* self)
|
||||||
assert(self);
|
assert(self);
|
||||||
struct sym* clone = malloc(sizeof(struct sym));
|
struct sym* clone = malloc(sizeof(struct sym));
|
||||||
sym_init(clone);
|
sym_init(clone);
|
||||||
|
|
||||||
clone->id_counter = self->id_counter;
|
|
||||||
clone->closure_counter = self->closure_counter;
|
|
||||||
env_free(clone->env);
|
env_free(clone->env);
|
||||||
free(clone->env);
|
free(clone->env);
|
||||||
|
|
||||||
|
clone->parent = self->parent;
|
||||||
clone->env = self->env ? env_new_clone(self->env) : NULL;
|
clone->env = self->env ? env_new_clone(self->env) : NULL;
|
||||||
|
|
||||||
return clone;
|
return clone;
|
||||||
|
@ -139,53 +144,60 @@ void sym_free(struct sym* self)
|
||||||
self->env = NULL;
|
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(self);
|
||||||
assert(name);
|
assert(name);
|
||||||
struct symbol* symbol = malloc(sizeof(struct symbol));
|
struct symbol* symbol = malloc(sizeof(struct symbol));
|
||||||
symbol_init(symbol, self->id_counter, name, self->env);
|
symbol_init(symbol, IdCounter, name, node, self->env);
|
||||||
|
IdCounter++;
|
||||||
vec_push(&self->env->symbols, symbol);
|
vec_push(&self->env->symbols, symbol);
|
||||||
|
|
||||||
self->id_counter++;
|
return symbol->id;
|
||||||
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(self);
|
||||||
assert(name);
|
assert(name);
|
||||||
struct symbol* symbol = malloc(sizeof(struct symbol));
|
struct symbol* symbol = malloc(sizeof(struct symbol));
|
||||||
symbol_init(symbol, self->id_counter, name, self->env);
|
symbol_init(symbol, IdCounter, name, node, self->env);
|
||||||
|
IdCounter++;
|
||||||
symbol->is_const = true;
|
symbol->is_const = true;
|
||||||
vec_push(&self->env->symbols, symbol);
|
vec_push(&self->env->symbols, symbol);
|
||||||
|
|
||||||
self->id_counter++;
|
return symbol->id;
|
||||||
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(self);
|
||||||
assert(name);
|
assert(name);
|
||||||
|
|
||||||
struct symbol* symbol = malloc(sizeof(struct symbol));
|
struct symbol* symbol = malloc(sizeof(struct symbol));
|
||||||
symbol_init(symbol, self->closure_counter, name, self->env);
|
symbol_init(symbol, IdCounter, name, node,
|
||||||
|
self->env);
|
||||||
|
IdCounter++;
|
||||||
symbol->is_const = false;
|
symbol->is_const = false;
|
||||||
symbol->closure_id = id;
|
symbol->closure_id = id;
|
||||||
|
symbol->fun = fun;
|
||||||
vec_push(&self->env->symbols, symbol);
|
vec_push(&self->env->symbols, symbol);
|
||||||
|
|
||||||
self->closure_counter++;
|
return symbol->id;
|
||||||
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(self);
|
||||||
assert(name);
|
assert(name);
|
||||||
struct symbol* symbol = malloc(sizeof(struct symbol));
|
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;
|
symbol->is_global = true;
|
||||||
vec_push(&self->env->symbols, symbol);
|
vec_push(&self->env->symbols, symbol);
|
||||||
return id;
|
return id;
|
||||||
|
|
|
@ -146,9 +146,10 @@ static void test_lexer_function()
|
||||||
|
|
||||||
static void test_lexer_module()
|
static void test_lexer_module()
|
||||||
{
|
{
|
||||||
test_lexer("module :: ", 2,
|
test_lexer("module :: import", 3,
|
||||||
"MODULE",
|
"MODULE",
|
||||||
"MOD_ACCESS"
|
"MOD_ACCESS",
|
||||||
|
"IMPORT"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
void register_lexer()
|
void register_lexer()
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include <CUnit/Basic.h>
|
#include <CUnit/Basic.h>
|
||||||
#include "lexer.h"
|
#include "lexer.h"
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
#include "path.h"
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
|
@ -10,6 +11,7 @@ int main()
|
||||||
|
|
||||||
register_lexer();
|
register_lexer();
|
||||||
register_parser();
|
register_parser();
|
||||||
|
register_path();
|
||||||
|
|
||||||
CU_basic_set_mode(CU_BRM_VERBOSE);
|
CU_basic_set_mode(CU_BRM_VERBOSE);
|
||||||
CU_basic_run_tests();
|
CU_basic_run_tests();
|
||||||
|
|
|
@ -165,6 +165,12 @@ static void test_parser_module()
|
||||||
"x::hello()");
|
"x::hello()");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_parser_import()
|
||||||
|
{
|
||||||
|
test_parser("ROOT(IMPORT(STRING[./hello]))",
|
||||||
|
"import \"./hello\"");
|
||||||
|
}
|
||||||
|
|
||||||
void register_parser()
|
void register_parser()
|
||||||
{
|
{
|
||||||
CU_pSuite suite = CU_add_suite("Parser", 0, 0);
|
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, "IfExpression", test_parser_if);
|
||||||
CU_add_test(suite, "Functions", test_parser_function);
|
CU_add_test(suite, "Functions", test_parser_function);
|
||||||
CU_add_test(suite, "Modules", test_parser_module);
|
CU_add_test(suite, "Modules", test_parser_module);
|
||||||
|
CU_add_test(suite, "Imports", test_parser_import);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
#ifndef SK_TEST_PATH_H
|
||||||
|
#define SK_TEST_PATH_H
|
||||||
|
|
||||||
|
#include <CUnit/CUnit.h>
|
||||||
|
#include <path.h>
|
||||||
|
|
||||||
|
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
|
Loading…
Reference in New Issue