✨ anonymous modules.
parent
b5f0713fee
commit
4d0edad298
|
@ -8,7 +8,7 @@ int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
errors_init();
|
errors_init();
|
||||||
struct module module;
|
struct module module;
|
||||||
module_init(&module);
|
module_init(&module, argv[1]);
|
||||||
|
|
||||||
module_load_source(&module, argv[1]);
|
module_load_source(&module, argv[1]);
|
||||||
int status = module_compile(&module);
|
int status = module_compile(&module);
|
||||||
|
|
|
@ -9,6 +9,8 @@ EXPR ::=
|
||||||
| IF
|
| IF
|
||||||
| return EXPR
|
| return EXPR
|
||||||
| FUN_DECL
|
| FUN_DECL
|
||||||
|
| MOD_ACCESS
|
||||||
|
MOD_ACCESS ::= EXPR mod_access ident
|
||||||
FUN_DECL ::=
|
FUN_DECL ::=
|
||||||
| fun ident opar PARAMS cpar EXPR* end
|
| fun ident opar PARAMS cpar EXPR* end
|
||||||
IF ::= if EXPR BLOCK (else (BLOCK | IF))?
|
IF ::= if EXPR BLOCK (else (BLOCK | IF))?
|
||||||
|
@ -32,7 +34,10 @@ LITERAL ::=
|
||||||
| ident
|
| ident
|
||||||
| FUN
|
| FUN
|
||||||
| CALL
|
| CALL
|
||||||
CALL ::= ident opar ARGS cpar
|
| MODULE
|
||||||
|
MODULE ::= module EXPR* end
|
||||||
|
CALL ::=
|
||||||
|
| (ident|MOD_ACCESS) opar ARGS cpar
|
||||||
ARGS ::= (EXPR (comma EXPR)*)?
|
ARGS ::= (EXPR (comma EXPR)*)?
|
||||||
FUN ::= fun opar PARAMS cpar EXPR* end
|
FUN ::= fun opar PARAMS cpar EXPR* end
|
||||||
PARAMS ::= (EXPR (comma EXPR)*)?
|
PARAMS ::= (EXPR (comma EXPR)*)?
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
var m = module
|
||||||
|
var x = 32
|
||||||
|
var y = "bim"
|
||||||
|
|
||||||
|
fun add(x, y)
|
||||||
|
return x + y
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assert m::x eq 32
|
||||||
|
assert m::y eq "bim"
|
||||||
|
assert m::add(7, 2) eq 9
|
|
@ -7,11 +7,18 @@
|
||||||
|
|
||||||
struct state;
|
struct state;
|
||||||
|
|
||||||
|
struct mod
|
||||||
|
{
|
||||||
|
char* name;
|
||||||
|
struct module* module;
|
||||||
|
};
|
||||||
|
|
||||||
struct compiler
|
struct compiler
|
||||||
{
|
{
|
||||||
struct vec var_names;
|
struct vec var_names;
|
||||||
|
struct vec modules;
|
||||||
};
|
};
|
||||||
|
void mod_free(struct mod* self);
|
||||||
void compiler_init(struct compiler* self);
|
void compiler_init(struct compiler* self);
|
||||||
void compiler_free(struct compiler* self);
|
void compiler_free(struct compiler* self);
|
||||||
|
|
||||||
|
|
|
@ -8,13 +8,15 @@
|
||||||
|
|
||||||
struct module
|
struct module
|
||||||
{
|
{
|
||||||
|
char* name;
|
||||||
struct str source;
|
struct str source;
|
||||||
struct prog prog;
|
struct prog* prog;
|
||||||
struct sym sym;
|
struct sym* sym;
|
||||||
struct state state;
|
struct state* state;
|
||||||
};
|
};
|
||||||
|
|
||||||
void module_init(struct module* self);
|
void module_init(struct module* self, char const* name);
|
||||||
|
struct module* module_new_clone(struct module* self);
|
||||||
void module_free(struct module* self);
|
void module_free(struct module* self);
|
||||||
|
|
||||||
void module_load_source(struct module* self,
|
void module_load_source(struct module* self,
|
||||||
|
|
|
@ -15,7 +15,8 @@ G(NODE_LT), G(NODE_LE), G(NODE_GT), G(NODE_GE), \
|
||||||
G(NODE_EQUAL), G(NODE_NOT_EQUAL), G(NODE_VAR_DECL), \
|
G(NODE_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_RETURN), G(NODE_CALL), G(NODE_ARGS), G(NODE_MODULE), \
|
||||||
|
G(NODE_MOD_ACCESS)
|
||||||
|
|
||||||
SK_ENUM_H(NodeKind, NODE_KIND);
|
SK_ENUM_H(NodeKind, NODE_KIND);
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,8 @@ struct node* parser_try_usub(struct parser* self);
|
||||||
struct node* parser_try_not(struct parser* self);
|
struct node* parser_try_not(struct parser* self);
|
||||||
struct node* parser_try_pow(struct parser* self);
|
struct node* parser_try_pow(struct parser* self);
|
||||||
struct node* parser_try_literal(struct parser* self);
|
struct node* parser_try_literal(struct parser* self);
|
||||||
|
struct node* parser_try_mod_access(struct parser* self);
|
||||||
|
struct node* parser_try_module(struct parser* self);
|
||||||
struct node* parser_try_call(struct parser* self);
|
struct node* parser_try_call(struct parser* self);
|
||||||
struct node* parser_try_args(struct parser* self);
|
struct node* parser_try_args(struct parser* self);
|
||||||
struct node* parser_try_fun(struct parser* self);
|
struct node* parser_try_fun(struct parser* self);
|
||||||
|
|
|
@ -15,7 +15,7 @@ G(OP_BR), G(OP_BRF), G(OP_LT), G(OP_GT), \
|
||||||
G(OP_EQUAL), G(OP_LOCAL_STORE), G(OP_LOCAL_LOAD), \
|
G(OP_EQUAL), G(OP_LOCAL_STORE), G(OP_LOCAL_LOAD), \
|
||||||
G(OP_CALL), G(OP_RET), G(OP_MAKE_REF), \
|
G(OP_CALL), G(OP_RET), G(OP_MAKE_REF), \
|
||||||
G(OP_CLOSURE_LOAD), G(OP_CLOSURE_STORE), \
|
G(OP_CLOSURE_LOAD), G(OP_CLOSURE_STORE), \
|
||||||
G(OP_GLOBAL_LOAD)
|
G(OP_GLOBAL_LOAD), G(OP_MODULE_LOAD)
|
||||||
|
|
||||||
SK_ENUM_H(Opcode, OPCODE);
|
SK_ENUM_H(Opcode, OPCODE);
|
||||||
|
|
||||||
|
|
|
@ -50,9 +50,11 @@ void stack_value_init(struct stack_value* self,
|
||||||
void stack_value_free(struct stack_value* self);
|
void stack_value_free(struct stack_value* self);
|
||||||
|
|
||||||
void frame_init(struct frame* self);
|
void frame_init(struct frame* self);
|
||||||
|
struct frame* frame_new_clone(struct frame* self);
|
||||||
void frame_free(struct frame* self);
|
void frame_free(struct frame* self);
|
||||||
|
|
||||||
void state_init(struct state* self);
|
void state_init(struct state* self);
|
||||||
|
struct state* state_new_clone(struct state* self);
|
||||||
void state_free(struct state* self);
|
void state_free(struct state* self);
|
||||||
|
|
||||||
SK state_make_ref(struct state* self);
|
SK state_make_ref(struct state* self);
|
||||||
|
@ -79,6 +81,7 @@ SK state_push_float(struct state* self, double real, int line);
|
||||||
SK state_push_string(struct state* self, char const* str, int line);
|
SK state_push_string(struct state* self, char const* str, int line);
|
||||||
SK state_push_fun(struct state* self, struct fun* fun, int line);
|
SK state_push_fun(struct state* self, struct fun* fun, int line);
|
||||||
SK state_push_ref(struct state* self, size_t ref, int line);
|
SK state_push_ref(struct state* self, size_t ref, int line);
|
||||||
|
SK state_push_mod(struct state* self, struct module* mod, int line);
|
||||||
|
|
||||||
struct local* state_try_get_local(struct state* self, int id);
|
struct local* state_try_get_local(struct state* self, int id);
|
||||||
|
|
||||||
|
@ -97,6 +100,9 @@ void state_global_load(struct state* self,
|
||||||
void state_closure_load(struct state* self,
|
void state_closure_load(struct state* self,
|
||||||
int id);
|
int id);
|
||||||
|
|
||||||
|
void state_module_load(struct state* self,
|
||||||
|
int id);
|
||||||
|
|
||||||
TypeKind state_common_num_type(struct state* self, SK lhs, SK rhs);
|
TypeKind state_common_num_type(struct state* self, SK lhs, SK rhs);
|
||||||
TypeKind state_type(struct state* self, SK value);
|
TypeKind state_type(struct state* self, SK value);
|
||||||
double state_as_real(struct state* self, SK lhs);
|
double state_as_real(struct state* self, SK lhs);
|
||||||
|
|
|
@ -36,6 +36,7 @@ struct env* env_new_clone(struct env* self);
|
||||||
void env_free(struct env* self);
|
void env_free(struct env* self);
|
||||||
|
|
||||||
struct symbol* env_try_get(struct env* self, char const* name);
|
struct symbol* env_try_get(struct env* self, char const* name);
|
||||||
|
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,
|
||||||
|
@ -57,5 +58,6 @@ void sym_open_scope(struct sym* self);
|
||||||
void sym_close_scope(struct sym* self);
|
void sym_close_scope(struct sym* self);
|
||||||
|
|
||||||
struct symbol* sym_try_get(struct sym* self, char const* name);
|
struct symbol* sym_try_get(struct sym* self, char const* name);
|
||||||
|
struct symbol* sym_try_get_by_id(struct sym* self, int id);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -16,7 +16,8 @@ G(TOKEN_LT), G(TOKEN_LE), G(TOKEN_GT), G(TOKEN_GE), \
|
||||||
G(TOKEN_EQUAL), G(TOKEN_NOT_EQUAL), G(TOKEN_VAR), \
|
G(TOKEN_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_FUN), G(TOKEN_RETURN), G(TOKEN_COMMA), G(TOKEN_MODULE), \
|
||||||
|
G(TOKEN_MOD_ACCESS)
|
||||||
|
|
||||||
SK_ENUM_H(TokenKind, TOKEN_KIND);
|
SK_ENUM_H(TokenKind, TOKEN_KIND);
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
#define TYPE_KIND(G) \
|
#define TYPE_KIND(G) \
|
||||||
G(TYPE_INT), G(TYPE_BOOL), G(TYPE_FLOAT), \
|
G(TYPE_INT), G(TYPE_BOOL), G(TYPE_FLOAT), \
|
||||||
G(TYPE_STRING), G(TYPE_FUN), G(TYPE_REF), \
|
G(TYPE_STRING), G(TYPE_FUN), G(TYPE_REF), \
|
||||||
G(TYPE_NATIVE_FUN)
|
G(TYPE_NATIVE_FUN), G(TYPE_MODULE)
|
||||||
|
|
||||||
SK_ENUM_H(TypeKind, TYPE_KIND);
|
SK_ENUM_H(TypeKind, TYPE_KIND);
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ union val
|
||||||
struct fun* fun;
|
struct fun* fun;
|
||||||
struct nfun* nfun;
|
struct nfun* nfun;
|
||||||
size_t ref;
|
size_t ref;
|
||||||
|
struct module* mod;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct value
|
struct value
|
||||||
|
|
|
@ -2,17 +2,26 @@
|
||||||
#include "token.h"
|
#include "token.h"
|
||||||
#include "state.h"
|
#include "state.h"
|
||||||
#include "natives.h"
|
#include "natives.h"
|
||||||
|
#include "module.h"
|
||||||
|
|
||||||
void compiler_init(struct compiler* self)
|
void compiler_init(struct compiler* self)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
vec_init(&self->var_names);
|
vec_init(&self->var_names);
|
||||||
|
vec_init(&self->modules);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mod_free(struct mod* self)
|
||||||
|
{
|
||||||
|
free(self->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void compiler_free(struct compiler* self)
|
void compiler_free(struct compiler* self)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
vec_free(&self->var_names);
|
vec_free(&self->var_names);
|
||||||
|
vec_free_elements(&self->modules, (void*) mod_free);
|
||||||
|
vec_free(&self->modules);
|
||||||
}
|
}
|
||||||
|
|
||||||
void compiler_compile(struct compiler* self,
|
void compiler_compile(struct compiler* self,
|
||||||
|
@ -209,6 +218,89 @@ void compiler_compile(struct compiler* self,
|
||||||
prog_add_instr(prog, OP_RET, SK_NO_PARAM);
|
prog_add_instr(prog, OP_RET, SK_NO_PARAM);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case NODE_MODULE: {
|
||||||
|
char* name = "";
|
||||||
|
|
||||||
|
if (self->var_names.size > 0)
|
||||||
|
{
|
||||||
|
name = self->var_names.data[
|
||||||
|
self->var_names.size - 1
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
struct module* mod = malloc(sizeof(struct module));
|
||||||
|
module_init(mod, name);
|
||||||
|
|
||||||
|
for (size_t i=0; i<node->children.size; i++)
|
||||||
|
{
|
||||||
|
struct node* child = node->children.data[i];
|
||||||
|
|
||||||
|
compiler_compile(
|
||||||
|
self,
|
||||||
|
child,
|
||||||
|
mod->prog,
|
||||||
|
mod->sym,
|
||||||
|
mod->state
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct value* val = malloc(sizeof(struct value));
|
||||||
|
union val v;
|
||||||
|
v.mod = mod;
|
||||||
|
value_init(val, TYPE_MODULE, v, node->token->line);
|
||||||
|
int id = prog_add_constant(prog, val);
|
||||||
|
prog_add_instr(prog, OP_PUSH, id);
|
||||||
|
prog_add_instr(prog, OP_MAKE_REF, SK_NO_PARAM);
|
||||||
|
|
||||||
|
struct mod* mymod = malloc(sizeof(struct mod));
|
||||||
|
mymod->name = strdup(name);
|
||||||
|
mymod->module = mod;
|
||||||
|
vec_push(&self->modules, mymod);
|
||||||
|
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case NODE_MOD_ACCESS: {
|
||||||
|
struct node* mod_name = node->children.data[0];
|
||||||
|
struct node* target = node->children.data[1];
|
||||||
|
|
||||||
|
struct mod* mod = NULL;
|
||||||
|
|
||||||
|
for (size_t i=0; i<self->modules.size; i++)
|
||||||
|
{
|
||||||
|
struct mod* m = self->modules.data[i];
|
||||||
|
|
||||||
|
if (strcmp(m->name, mod_name->token->value) == 0)
|
||||||
|
{
|
||||||
|
mod = m;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mod)
|
||||||
|
{
|
||||||
|
errors_push(node->token->line,
|
||||||
|
"unknown module '%s'.",
|
||||||
|
mod_name->token->value);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct symbol* symbol = sym_try_get(
|
||||||
|
mod->module->sym,
|
||||||
|
target->token->value
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(symbol);
|
||||||
|
|
||||||
|
compiler_compile(
|
||||||
|
self,
|
||||||
|
mod_name,
|
||||||
|
prog,
|
||||||
|
sym,
|
||||||
|
state
|
||||||
|
);
|
||||||
|
|
||||||
|
prog_add_instr(prog, OP_MODULE_LOAD, symbol->id);
|
||||||
|
} break;
|
||||||
|
|
||||||
case NODE_FUN: {
|
case NODE_FUN: {
|
||||||
struct fun* fun = malloc(sizeof(struct fun));
|
struct fun* fun = malloc(sizeof(struct fun));
|
||||||
struct prog* p = malloc(sizeof(struct prog));
|
struct prog* p = malloc(sizeof(struct prog));
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include "sym.h"
|
#include "sym.h"
|
||||||
#include "fun.h"
|
#include "fun.h"
|
||||||
#include "nfun.h"
|
#include "nfun.h"
|
||||||
|
#include "module.h"
|
||||||
|
|
||||||
void exec_init(struct exec* self)
|
void exec_init(struct exec* self)
|
||||||
{
|
{
|
||||||
|
@ -55,6 +56,10 @@ void exec_execute(struct exec* self,
|
||||||
self->pc++;
|
self->pc++;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case OP_MODULE_LOAD: {
|
||||||
|
state_module_load(state, param);
|
||||||
|
self->pc++;
|
||||||
|
} break;
|
||||||
case OP_ASSERT_EQ: {
|
case OP_ASSERT_EQ: {
|
||||||
SK rhs = state_pop(state);
|
SK rhs = state_pop(state);
|
||||||
SK lhs = state_pop(state);
|
SK lhs = state_pop(state);
|
||||||
|
@ -117,7 +122,6 @@ void exec_execute(struct exec* self,
|
||||||
state,
|
state,
|
||||||
f->val.ref
|
f->val.ref
|
||||||
);
|
);
|
||||||
|
|
||||||
assert(val_fun);
|
assert(val_fun);
|
||||||
|
|
||||||
if (val_fun->type == TYPE_NATIVE_FUN)
|
if (val_fun->type == TYPE_NATIVE_FUN)
|
||||||
|
@ -224,6 +228,24 @@ void exec_execute(struct exec* self,
|
||||||
);
|
);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case TYPE_MODULE: {
|
||||||
|
struct module* mod =
|
||||||
|
constant->val.mod;
|
||||||
|
|
||||||
|
struct exec exec;
|
||||||
|
exec_init(&exec);
|
||||||
|
|
||||||
|
exec_execute(&exec, mod->state, mod->prog);
|
||||||
|
|
||||||
|
exec_free(&exec);
|
||||||
|
|
||||||
|
state_push_mod(
|
||||||
|
state,
|
||||||
|
mod,
|
||||||
|
constant->line
|
||||||
|
);
|
||||||
|
} break;
|
||||||
|
|
||||||
case TYPE_INT: {
|
case TYPE_INT: {
|
||||||
state_push_int(
|
state_push_int(
|
||||||
state,
|
state,
|
||||||
|
|
|
@ -90,7 +90,8 @@ bool lexer_is_sep(struct lexer* self, size_t index)
|
||||||
|| c == '<'
|
|| c == '<'
|
||||||
|| c == '>'
|
|| c == '>'
|
||||||
|| c == ','
|
|| c == ','
|
||||||
|| c == '=';
|
|| c == '='
|
||||||
|
|| c == ':';
|
||||||
}
|
}
|
||||||
|
|
||||||
bool lexer_next_nth_is(struct lexer* self, TokenKind kind, int nth)
|
bool lexer_next_nth_is(struct lexer* self, TokenKind kind, int nth)
|
||||||
|
@ -179,6 +180,7 @@ struct token* lexer_try_new_next(struct lexer* self)
|
||||||
{
|
{
|
||||||
return tok;
|
return tok;
|
||||||
}
|
}
|
||||||
|
SK_SCAN_TEXT("::", TOKEN_MOD_ACCESS);
|
||||||
SK_SCAN_TEXT("<=", TOKEN_LE);
|
SK_SCAN_TEXT("<=", TOKEN_LE);
|
||||||
SK_SCAN_TEXT(">=", TOKEN_GE);
|
SK_SCAN_TEXT(">=", TOKEN_GE);
|
||||||
SK_SCAN_TEXT("==", TOKEN_EQUAL);
|
SK_SCAN_TEXT("==", TOKEN_EQUAL);
|
||||||
|
@ -199,6 +201,7 @@ struct token* lexer_try_new_next(struct lexer* self)
|
||||||
SK_SCAN_KEYWORD("return", TOKEN_RETURN, NULL);
|
SK_SCAN_KEYWORD("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);
|
||||||
|
SK_SCAN_KEYWORD("module", TOKEN_MODULE, NULL);
|
||||||
SK_SCAN_KEYWORD("begin", TOKEN_BEGIN, NULL);
|
SK_SCAN_KEYWORD("begin", TOKEN_BEGIN, NULL);
|
||||||
SK_SCAN_KEYWORD("end", TOKEN_END, NULL);
|
SK_SCAN_KEYWORD("end", TOKEN_END, NULL);
|
||||||
SK_SCAN_KEYWORD("var", TOKEN_VAR, NULL);
|
SK_SCAN_KEYWORD("var", TOKEN_VAR, NULL);
|
||||||
|
|
|
@ -5,24 +5,63 @@
|
||||||
#include "exec.h"
|
#include "exec.h"
|
||||||
#include "natives.h"
|
#include "natives.h"
|
||||||
|
|
||||||
void module_init(struct module* self)
|
void module_init(struct module* self, char const* name)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
|
self->name = strdup(name);
|
||||||
str_init(&self->source);
|
str_init(&self->source);
|
||||||
prog_init(&self->prog);
|
|
||||||
state_init(&self->state);
|
|
||||||
sym_init(&self->sym);
|
|
||||||
|
|
||||||
natives_populate(&self->state, &self->sym);
|
self->prog = malloc(sizeof(struct prog));
|
||||||
|
prog_init(self->prog);
|
||||||
|
|
||||||
|
self->state = malloc(sizeof(struct state));
|
||||||
|
state_init(self->state);
|
||||||
|
|
||||||
|
self->sym = malloc(sizeof(struct sym));
|
||||||
|
sym_init(self->sym);
|
||||||
|
|
||||||
|
natives_populate(self->state, self->sym);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct module* module_new_clone(struct module* self)
|
||||||
|
{
|
||||||
|
assert(self);
|
||||||
|
struct module* clone = malloc(sizeof(struct module));
|
||||||
|
module_init(clone, self->name);
|
||||||
|
|
||||||
|
prog_free(clone->prog);
|
||||||
|
free(clone->prog);
|
||||||
|
state_free(clone->state);
|
||||||
|
free(clone->state);
|
||||||
|
sym_free(clone->sym);
|
||||||
|
free(clone->sym);
|
||||||
|
|
||||||
|
// struct str source;
|
||||||
|
if (self->source.value)
|
||||||
|
{
|
||||||
|
str_extend(&clone->source, self->source.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// struct prog prog;
|
||||||
|
clone->prog = prog_new_clone(self->prog);
|
||||||
|
// struct sym sym;
|
||||||
|
clone->sym = sym_new_clone(self->sym);
|
||||||
|
// struct state state;
|
||||||
|
clone->state = state_new_clone(self->state);
|
||||||
|
return clone;
|
||||||
}
|
}
|
||||||
|
|
||||||
void module_free(struct module* self)
|
void module_free(struct module* self)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
str_free(&self->source);
|
str_free(&self->source);
|
||||||
prog_free(&self->prog);
|
prog_free(self->prog);
|
||||||
sym_free(&self->sym);
|
free(self->prog);
|
||||||
state_free(&self->state);
|
sym_free(self->sym);
|
||||||
|
free(self->sym);
|
||||||
|
state_free(self->state);
|
||||||
|
free(self->state);
|
||||||
|
free(self->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void module_load_source(struct module* self,
|
void module_load_source(struct module* self,
|
||||||
|
@ -59,13 +98,13 @@ int module_compile(struct module* self)
|
||||||
struct compiler compiler;
|
struct compiler compiler;
|
||||||
compiler_init(&compiler);
|
compiler_init(&compiler);
|
||||||
|
|
||||||
compiler_compile(&compiler, root, &self->prog, &self->sym,
|
compiler_compile(&compiler, root, self->prog, self->sym,
|
||||||
&self->state);
|
self->state);
|
||||||
|
|
||||||
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->prog);
|
||||||
|
|
||||||
if (!errors_ok())
|
if (!errors_ok())
|
||||||
{
|
{
|
||||||
|
@ -82,6 +121,5 @@ free_node:
|
||||||
free(root);
|
free(root);
|
||||||
parser_free(&parser);
|
parser_free(&parser);
|
||||||
|
|
||||||
|
|
||||||
return errors_ok() ? EXIT_SUCCESS : EXIT_FAILURE;
|
return errors_ok() ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
137
lib/src/parser.c
137
lib/src/parser.c
|
@ -116,10 +116,10 @@ struct node* parser_try_expr(struct parser* self)
|
||||||
return SK_TRY(parser_try_const_decl);
|
return SK_TRY(parser_try_const_decl);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lexer_next_is(&self->lexer, TOKEN_IDENT)
|
// ASSIGN
|
||||||
&& lexer_next_nth_is(&self->lexer, TOKEN_ASSIGN, 1))
|
|
||||||
{
|
{
|
||||||
return SK_TRY(parser_try_assign);
|
struct node* n = SK_TRY(parser_try_assign);
|
||||||
|
if (n) { return n; }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lexer_next_is(&self->lexer, TOKEN_VAR))
|
if (lexer_next_is(&self->lexer, TOKEN_VAR))
|
||||||
|
@ -356,15 +356,11 @@ struct node* parser_try_if(struct parser* self)
|
||||||
struct node* parser_try_assign(struct parser* self)
|
struct node* parser_try_assign(struct parser* self)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
|
struct node* ident = SK_TRY(parser_try_or);
|
||||||
if (!lexer_next_is(&self->lexer, TOKEN_IDENT))
|
if (!ident)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct node* ident = malloc(sizeof(struct node));
|
|
||||||
node_init(ident, NODE_IDENT, lexer_try_new_next(&self->lexer));
|
|
||||||
|
|
||||||
if (!lexer_next_is(&self->lexer, TOKEN_ASSIGN))
|
if (!lexer_next_is(&self->lexer, TOKEN_ASSIGN))
|
||||||
{
|
{
|
||||||
node_free(ident); free(ident);
|
node_free(ident); free(ident);
|
||||||
|
@ -886,6 +882,11 @@ struct node* parser_try_literal(struct parser* self)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
|
|
||||||
|
{
|
||||||
|
struct node* node = SK_TRY(parser_try_call);
|
||||||
|
if (node) { return node; }
|
||||||
|
}
|
||||||
|
|
||||||
if (lexer_next_is(&self->lexer, TOKEN_OPAR))
|
if (lexer_next_is(&self->lexer, TOKEN_OPAR))
|
||||||
{
|
{
|
||||||
lexer_consume_next(&self->lexer);
|
lexer_consume_next(&self->lexer);
|
||||||
|
@ -908,10 +909,10 @@ struct node* parser_try_literal(struct parser* self)
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lexer_next_is(&self->lexer, TOKEN_IDENT)
|
|
||||||
&& lexer_next_nth_is(&self->lexer, TOKEN_OPAR, 1))
|
if (lexer_next_nth_is(&self->lexer, TOKEN_MOD_ACCESS, 1))
|
||||||
{
|
{
|
||||||
return SK_TRY(parser_try_call);
|
return SK_TRY(parser_try_mod_access);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lexer_next_is(&self->lexer, TOKEN_IDENT))
|
if (lexer_next_is(&self->lexer, TOKEN_IDENT))
|
||||||
|
@ -930,10 +931,15 @@ struct node* parser_try_literal(struct parser* self)
|
||||||
return SK_TRY(parser_try_fun);
|
return SK_TRY(parser_try_fun);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (lexer_next_is(&self->lexer, TOKEN_MODULE))
|
||||||
|
{
|
||||||
|
return SK_TRY(parser_try_module);
|
||||||
|
}
|
||||||
|
|
||||||
return SK_TRY(parser_try_builtin);
|
return SK_TRY(parser_try_builtin);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct node* parser_try_call(struct parser* self)
|
struct node* parser_try_mod_access(struct parser* self)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
|
|
||||||
|
@ -942,8 +948,109 @@ struct node* parser_try_call(struct parser* self)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct token* lhs_tok = lexer_try_new_next(&self->lexer);
|
||||||
|
struct node* lhs = malloc(sizeof(struct node));
|
||||||
|
node_init(lhs, NODE_IDENT, lhs_tok);
|
||||||
|
|
||||||
|
if (!lhs)
|
||||||
|
{
|
||||||
|
token_free(lhs_tok);
|
||||||
|
free(lhs_tok);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!lexer_next_is(&self->lexer, TOKEN_MOD_ACCESS))
|
||||||
|
{
|
||||||
|
node_free(lhs);
|
||||||
|
free(lhs);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
struct token* access_tok = lexer_try_new_next(&self->lexer);
|
||||||
|
|
||||||
|
if (!lexer_next_is(&self->lexer, TOKEN_IDENT))
|
||||||
|
{
|
||||||
|
node_free(lhs);
|
||||||
|
free(lhs);
|
||||||
|
token_free(access_tok);
|
||||||
|
free(access_tok);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct token* rhs_tok = lexer_try_new_next(&self->lexer);
|
||||||
|
struct node* rhs = malloc(sizeof(struct node));
|
||||||
|
node_init(rhs, NODE_IDENT, rhs_tok);
|
||||||
|
|
||||||
|
struct node* node = malloc(sizeof(struct node));
|
||||||
|
node_init(node, NODE_MOD_ACCESS, access_tok);
|
||||||
|
|
||||||
|
node_push_new_child(node, lhs);
|
||||||
|
node_push_new_child(node, rhs);
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct node* parser_try_module(struct parser* self)
|
||||||
|
{
|
||||||
|
assert(self);
|
||||||
|
|
||||||
|
if (!lexer_next_is(&self->lexer, TOKEN_MODULE))
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct node* node = malloc(sizeof(struct node));
|
||||||
|
node_init(node, NODE_MODULE, lexer_try_new_next(&self->lexer));
|
||||||
|
|
||||||
|
struct node* expr = NULL;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
expr = SK_TRY(parser_try_expr);
|
||||||
|
|
||||||
|
if (expr)
|
||||||
|
{
|
||||||
|
node_push_new_child(node, expr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (expr);
|
||||||
|
|
||||||
|
if (!lexer_next_is(&self->lexer, TOKEN_END))
|
||||||
|
{
|
||||||
|
node_free(node);
|
||||||
|
free(node);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
lexer_consume_next(&self->lexer);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct node* parser_try_call(struct parser* self)
|
||||||
|
{
|
||||||
|
assert(self);
|
||||||
|
|
||||||
|
struct node* lhs = NULL;
|
||||||
|
|
||||||
|
if (lexer_next_is(&self->lexer, TOKEN_IDENT)
|
||||||
|
&& !lexer_next_nth_is(&self->lexer, TOKEN_MOD_ACCESS, 1))
|
||||||
|
{
|
||||||
struct node* ident = malloc(sizeof(struct node));
|
struct node* ident = malloc(sizeof(struct node));
|
||||||
node_init(ident, NODE_IDENT, lexer_try_new_next(&self->lexer));
|
node_init(ident, NODE_IDENT,
|
||||||
|
lexer_try_new_next(&self->lexer));
|
||||||
|
if (!ident)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
lhs = ident;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lhs = SK_TRY(parser_try_mod_access);
|
||||||
|
if (!lhs)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct token* tok = malloc(sizeof(struct token));
|
struct token* tok = malloc(sizeof(struct token));
|
||||||
token_init(tok, TOKEN_BEGIN, "", self->lexer.context.line);
|
token_init(tok, TOKEN_BEGIN, "", self->lexer.context.line);
|
||||||
|
@ -951,7 +1058,7 @@ struct node* parser_try_call(struct parser* self)
|
||||||
struct node* node = malloc(sizeof(struct node));
|
struct node* node = malloc(sizeof(struct node));
|
||||||
node_init(node, NODE_CALL, tok);
|
node_init(node, NODE_CALL, tok);
|
||||||
|
|
||||||
node_push_new_child(node, ident);
|
node_push_new_child(node, lhs);
|
||||||
|
|
||||||
if (!lexer_next_is(&self->lexer, TOKEN_OPAR))
|
if (!lexer_next_is(&self->lexer, TOKEN_OPAR))
|
||||||
{
|
{
|
||||||
|
|
115
lib/src/state.c
115
lib/src/state.c
|
@ -1,4 +1,5 @@
|
||||||
#include "state.h"
|
#include "state.h"
|
||||||
|
#include "module.h"
|
||||||
#include "nfun.h"
|
#include "nfun.h"
|
||||||
|
|
||||||
void stack_value_init(struct stack_value* self,
|
void stack_value_init(struct stack_value* self,
|
||||||
|
@ -27,6 +28,43 @@ void frame_init(struct frame* self)
|
||||||
self->fun = NULL;
|
self->fun = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct frame* frame_new_clone(struct frame* self)
|
||||||
|
{
|
||||||
|
struct frame* clone = malloc(sizeof(struct frame));
|
||||||
|
frame_init(clone);
|
||||||
|
|
||||||
|
// struct vec stack_values;
|
||||||
|
for (size_t i=0; i<self->stack_values.size; i++)
|
||||||
|
{
|
||||||
|
struct stack_value* sv = self->stack_values.data[i];
|
||||||
|
struct stack_value* val = malloc(sizeof(struct stack_value));
|
||||||
|
stack_value_init(val, sv->addr,
|
||||||
|
value_new_clone(sv->value));
|
||||||
|
vec_push(&clone->stack_values, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
// struct vec locals;
|
||||||
|
for (size_t i=0; i<self->locals.size; i++)
|
||||||
|
{
|
||||||
|
struct local const* loc = self->locals.data[i];
|
||||||
|
struct local* local = malloc(sizeof(struct local));
|
||||||
|
local->id = loc->id;
|
||||||
|
local->addr = loc->addr;
|
||||||
|
vec_push(&clone->locals, local);
|
||||||
|
}
|
||||||
|
|
||||||
|
// struct vec stack;
|
||||||
|
for (size_t i=0; i<self->stack.size; i++)
|
||||||
|
{
|
||||||
|
vec_push(&clone->stack, self->stack.data[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// struct fun* fun;
|
||||||
|
clone->fun = self->fun;
|
||||||
|
|
||||||
|
return clone;
|
||||||
|
}
|
||||||
|
|
||||||
void frame_free(struct frame* self)
|
void frame_free(struct frame* self)
|
||||||
{
|
{
|
||||||
vec_free_elements(&self->stack_values, (void*) stack_value_free);
|
vec_free_elements(&self->stack_values, (void*) stack_value_free);
|
||||||
|
@ -47,6 +85,42 @@ void state_init(struct state* self)
|
||||||
vec_init(&self->globals);
|
vec_init(&self->globals);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct state* state_new_clone(struct state* self)
|
||||||
|
{
|
||||||
|
assert(self);
|
||||||
|
struct state* clone = malloc(sizeof(struct state));
|
||||||
|
state_init(clone);
|
||||||
|
|
||||||
|
for (size_t i=0; i<self->frames.size; i++)
|
||||||
|
{
|
||||||
|
struct frame* frame = self->frames.data[i];
|
||||||
|
vec_push(&clone->frames, frame_new_clone(frame));
|
||||||
|
}
|
||||||
|
|
||||||
|
// size_t addr;
|
||||||
|
clone->addr = self->addr;
|
||||||
|
// int global_id;
|
||||||
|
clone->global_id = self->global_id;
|
||||||
|
// struct vec globals;
|
||||||
|
for (size_t i=0; i<self->globals.size; i++)
|
||||||
|
{
|
||||||
|
struct global const* glob = self->globals.data[i];
|
||||||
|
struct global* global = malloc(sizeof(struct global));
|
||||||
|
global->id = glob->id;
|
||||||
|
global->addr = glob->id;
|
||||||
|
vec_push(&clone->globals, global);
|
||||||
|
}
|
||||||
|
// struct vec global_values;
|
||||||
|
for (size_t i=0; i<self->global_values.size; i++)
|
||||||
|
{
|
||||||
|
struct value* val = self->global_values.data[i];
|
||||||
|
struct value* value = value_new_clone(val);
|
||||||
|
vec_push(&clone->global_values, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return clone;
|
||||||
|
}
|
||||||
|
|
||||||
void state_free(struct state* self)
|
void state_free(struct state* self)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
|
@ -243,6 +317,14 @@ SK state_push_ref(struct state* self,size_t ref, int line)
|
||||||
return state_push(self, TYPE_REF, val, line);
|
return state_push(self, TYPE_REF, val, line);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SK state_push_mod(struct state* self, struct module* mod, int line)
|
||||||
|
{
|
||||||
|
assert(self);
|
||||||
|
union val val;
|
||||||
|
val.mod = module_new_clone(mod);
|
||||||
|
return state_push(self, TYPE_MODULE, val, line);
|
||||||
|
}
|
||||||
|
|
||||||
struct local* state_try_get_local(struct state* self, int id)
|
struct local* state_try_get_local(struct state* self, int id)
|
||||||
{
|
{
|
||||||
struct frame* frame = state_frame(self);
|
struct frame* frame = state_frame(self);
|
||||||
|
@ -357,6 +439,39 @@ void state_closure_load(struct state* self,
|
||||||
fprintf(stderr, "cannot load closure %d\n", id);
|
fprintf(stderr, "cannot load closure %d\n", id);
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void state_module_load(struct state* self,
|
||||||
|
int id)
|
||||||
|
{
|
||||||
|
assert(self);
|
||||||
|
SK mod = state_pop(self);
|
||||||
|
struct value* ref_val = state_try_get_value(self, mod);
|
||||||
|
|
||||||
|
struct value* mod_value = state_try_deref(self, ref_val->val.ref);
|
||||||
|
struct module* module = mod_value->val.mod;
|
||||||
|
|
||||||
|
struct symbol* symbol = sym_try_get_by_id(
|
||||||
|
module->sym,
|
||||||
|
id
|
||||||
|
);
|
||||||
|
|
||||||
|
struct value* value
|
||||||
|
= value_new_clone(state_try_get_value(module->state, symbol->id));
|
||||||
|
|
||||||
|
|
||||||
|
if (value->type == TYPE_FUN)
|
||||||
|
{
|
||||||
|
state_push_ref(self,
|
||||||
|
state_add_global(self, value),
|
||||||
|
value->line);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
state_push(self, value->type, value->val, value->line);
|
||||||
|
free(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TypeKind state_common_num_type(struct state* self, SK lhs, SK rhs)
|
TypeKind state_common_num_type(struct state* self, SK lhs, SK rhs)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
|
|
|
@ -62,6 +62,28 @@ struct symbol* env_try_get(struct env* self, char const* name)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct symbol* env_try_get_by_id(struct env* self, int id)
|
||||||
|
{
|
||||||
|
assert(self);
|
||||||
|
|
||||||
|
for (size_t i=0; i<self->symbols.size; i++)
|
||||||
|
{
|
||||||
|
struct symbol* symbol = self->symbols.data[i];
|
||||||
|
|
||||||
|
if (symbol->id == id)
|
||||||
|
{
|
||||||
|
return symbol;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self->parent)
|
||||||
|
{
|
||||||
|
return env_try_get_by_id(self->parent, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
void symbol_init(struct symbol* self,
|
void symbol_init(struct symbol* self,
|
||||||
int id,
|
int id,
|
||||||
char const* name,
|
char const* name,
|
||||||
|
@ -191,3 +213,8 @@ struct symbol* sym_try_get(struct sym* self, char const* name)
|
||||||
{
|
{
|
||||||
return env_try_get(self->env, name);
|
return env_try_get(self->env, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct symbol* sym_try_get_by_id(struct sym* self, int id)
|
||||||
|
{
|
||||||
|
return env_try_get_by_id(self->env, id);
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "value.h"
|
#include "value.h"
|
||||||
#include "nfun.h"
|
#include "nfun.h"
|
||||||
|
#include "module.h"
|
||||||
|
|
||||||
SK_ENUM_C(TypeKind, TYPE_KIND);
|
SK_ENUM_C(TypeKind, TYPE_KIND);
|
||||||
|
|
||||||
|
@ -34,6 +35,12 @@ void value_free(struct value* self)
|
||||||
nfun_free(self->val.nfun);
|
nfun_free(self->val.nfun);
|
||||||
free(self->val.nfun);
|
free(self->val.nfun);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (self->type == TYPE_MODULE)
|
||||||
|
{
|
||||||
|
module_free(self->val.mod);
|
||||||
|
free(self->val.mod);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct value* value_new_clone(struct value* self)
|
struct value* value_new_clone(struct value* self)
|
||||||
|
@ -81,6 +88,12 @@ struct value* value_new_clone(struct value* self)
|
||||||
return clone;
|
return clone;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case TYPE_MODULE: {
|
||||||
|
val.mod = module_new_clone(self->val.mod);
|
||||||
|
value_init(clone, TYPE_MODULE, val, self->line);
|
||||||
|
|
||||||
|
return clone;
|
||||||
|
} break;
|
||||||
case TYPE_NATIVE_FUN: {
|
case TYPE_NATIVE_FUN: {
|
||||||
val.nfun = malloc(sizeof(struct nfun));
|
val.nfun = malloc(sizeof(struct nfun));
|
||||||
val.nfun->body = self->val.nfun->body;
|
val.nfun->body = self->val.nfun->body;
|
||||||
|
@ -122,6 +135,10 @@ void value_str(struct value* self, struct str* dest)
|
||||||
|
|
||||||
switch (self->type)
|
switch (self->type)
|
||||||
{
|
{
|
||||||
|
case TYPE_MODULE: {
|
||||||
|
str_format(dest, "<mod:%p>", self->val.mod);
|
||||||
|
} break;
|
||||||
|
|
||||||
case TYPE_FUN: {
|
case TYPE_FUN: {
|
||||||
str_format(dest, "<fun:%p>", self->val.fun);
|
str_format(dest, "<fun:%p>", self->val.fun);
|
||||||
} break;
|
} break;
|
||||||
|
|
|
@ -144,6 +144,13 @@ static void test_lexer_function()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_lexer_module()
|
||||||
|
{
|
||||||
|
test_lexer("module :: ", 2,
|
||||||
|
"MODULE",
|
||||||
|
"MOD_ACCESS"
|
||||||
|
);
|
||||||
|
}
|
||||||
void register_lexer()
|
void register_lexer()
|
||||||
{
|
{
|
||||||
CU_pSuite suite = CU_add_suite("Lexer", 0, 0);
|
CU_pSuite suite = CU_add_suite("Lexer", 0, 0);
|
||||||
|
@ -157,6 +164,7 @@ void register_lexer()
|
||||||
CU_add_test(suite, "Blocks", test_lexer_block);
|
CU_add_test(suite, "Blocks", test_lexer_block);
|
||||||
CU_add_test(suite, "Conditionnals", test_lexer_cond);
|
CU_add_test(suite, "Conditionnals", test_lexer_cond);
|
||||||
CU_add_test(suite, "Functions", test_lexer_function);
|
CU_add_test(suite, "Functions", test_lexer_function);
|
||||||
|
CU_add_test(suite, "Modules", test_lexer_module);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -152,6 +152,19 @@ static void test_parser_function()
|
||||||
"hello(x, 2)");
|
"hello(x, 2)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_parser_module()
|
||||||
|
{
|
||||||
|
test_parser("ROOT(MODULE(INT[4],STRING[5],BOOL[true]))",
|
||||||
|
"module 4 \"5\" true end");
|
||||||
|
|
||||||
|
test_parser("ROOT(ASSIGN(MOD_ACCESS(IDENT[x],IDENT[hello])"
|
||||||
|
",INT[3]))",
|
||||||
|
"x::hello = 3");
|
||||||
|
|
||||||
|
test_parser("ROOT(CALL(MOD_ACCESS(IDENT[x],IDENT[hello]),ARGS))",
|
||||||
|
"x::hello()");
|
||||||
|
}
|
||||||
|
|
||||||
void register_parser()
|
void register_parser()
|
||||||
{
|
{
|
||||||
CU_pSuite suite = CU_add_suite("Parser", 0, 0);
|
CU_pSuite suite = CU_add_suite("Parser", 0, 0);
|
||||||
|
@ -165,6 +178,7 @@ void register_parser()
|
||||||
CU_add_test(suite, "Blocks", test_parser_block);
|
CU_add_test(suite, "Blocks", test_parser_block);
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue