✨ improved println 🎨 better global support 🐛 string duplication with clone.
parent
88aad1ee75
commit
b5f0713fee
|
@ -2,3 +2,4 @@
|
||||||
*\#*
|
*\#*
|
||||||
build
|
build
|
||||||
.cache
|
.cache
|
||||||
|
vgcore*
|
||||||
|
|
|
@ -10,7 +10,7 @@ void natives_decl(struct state* state,
|
||||||
struct sym* sym,
|
struct sym* sym,
|
||||||
char* name,
|
char* name,
|
||||||
nfun_body fun,
|
nfun_body fun,
|
||||||
size_t arity);
|
int arity);
|
||||||
|
|
||||||
SK native_println(struct state* state, struct vec* args);
|
SK native_println(struct state* state, struct vec* args);
|
||||||
|
|
||||||
|
|
|
@ -9,10 +9,10 @@ typedef SK (*nfun_body)(struct state*, struct vec*);
|
||||||
struct nfun
|
struct nfun
|
||||||
{
|
{
|
||||||
nfun_body body;
|
nfun_body body;
|
||||||
size_t arity;
|
int arity;
|
||||||
};
|
};
|
||||||
|
|
||||||
void nfun_init(struct nfun* self, nfun_body body, size_t arity);
|
void nfun_init(struct nfun* self, nfun_body body, int arity);
|
||||||
void nfun_free(struct nfun* self);
|
void nfun_free(struct nfun* self);
|
||||||
|
|
||||||
SK nfun_call(struct nfun* self,
|
SK nfun_call(struct nfun* self,
|
||||||
|
|
|
@ -14,7 +14,8 @@ G(OP_NOT), G(OP_AND), G(OP_OR), \
|
||||||
G(OP_BR), G(OP_BRF), G(OP_LT), G(OP_GT), \
|
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)
|
||||||
|
|
||||||
SK_ENUM_H(Opcode, OPCODE);
|
SK_ENUM_H(Opcode, OPCODE);
|
||||||
|
|
||||||
|
|
|
@ -26,11 +26,19 @@ struct frame
|
||||||
struct fun* fun;
|
struct fun* fun;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct global
|
||||||
|
{
|
||||||
|
int id;
|
||||||
|
size_t addr;
|
||||||
|
};
|
||||||
|
|
||||||
struct state
|
struct state
|
||||||
{
|
{
|
||||||
struct vec frames;
|
struct vec frames;
|
||||||
size_t addr;
|
size_t addr;
|
||||||
|
int global_id;
|
||||||
struct vec globals;
|
struct vec globals;
|
||||||
|
struct vec global_values;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef SK (*nfun_body)(struct state*, struct vec*);
|
typedef SK (*nfun_body)(struct state*, struct vec*);
|
||||||
|
@ -83,6 +91,9 @@ void state_closure_store(struct state* self,
|
||||||
void state_local_load(struct state* self,
|
void state_local_load(struct state* self,
|
||||||
int id);
|
int id);
|
||||||
|
|
||||||
|
void state_global_load(struct state* self,
|
||||||
|
int id);
|
||||||
|
|
||||||
void state_closure_load(struct state* self,
|
void state_closure_load(struct state* self,
|
||||||
int id);
|
int id);
|
||||||
|
|
||||||
|
@ -107,9 +118,12 @@ SK state_lt(struct state* self);
|
||||||
SK state_gt(struct state* self);
|
SK state_gt(struct state* self);
|
||||||
SK state_eq(struct state* self);
|
SK state_eq(struct state* self);
|
||||||
|
|
||||||
|
int state_add_global(struct state* self,
|
||||||
|
struct value* value);
|
||||||
|
|
||||||
void state_call(struct state* self, struct fun* fun);
|
void state_call(struct state* self, struct fun* fun);
|
||||||
void state_ret(struct state* self);
|
void state_ret(struct state* self);
|
||||||
SK state_add_nfun(struct state* self,
|
SK state_add_nfun(struct state* self,
|
||||||
nfun_body body,
|
nfun_body body,
|
||||||
size_t arity);
|
int arity);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -12,6 +12,7 @@ struct symbol
|
||||||
int native_id;
|
int native_id;
|
||||||
char* name;
|
char* name;
|
||||||
bool is_const;
|
bool is_const;
|
||||||
|
bool is_global;
|
||||||
struct env* env;
|
struct env* env;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -26,6 +27,7 @@ struct sym
|
||||||
int id_counter;
|
int id_counter;
|
||||||
int closure_counter;
|
int closure_counter;
|
||||||
int native_counter;
|
int native_counter;
|
||||||
|
int global_counter;
|
||||||
struct env* env;
|
struct env* env;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -49,7 +51,7 @@ 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);
|
int sym_decl_const(struct sym* self, char const* name);
|
||||||
int sym_decl_closure(struct sym* self, int id, char const* name);
|
int sym_decl_closure(struct sym* self, int id, char const* name);
|
||||||
int sym_decl_native(struct sym* self, char const* name, int addr);
|
int sym_decl_global(struct sym* self, int id, char const* name);
|
||||||
|
|
||||||
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);
|
||||||
|
|
|
@ -189,14 +189,9 @@ void compiler_compile(struct compiler* self,
|
||||||
itr = itr->parent;
|
itr = itr->parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (symbol->native_id != SK_NO_NATIVE)
|
if (symbol->is_global)
|
||||||
{
|
{
|
||||||
struct value* value = malloc(sizeof(struct value));
|
prog_add_instr(prog, OP_GLOBAL_LOAD, symbol->id);
|
||||||
union val val;
|
|
||||||
val.ref = symbol->native_id;
|
|
||||||
value_init(value, TYPE_REF, val, node->token->line);
|
|
||||||
size_t idx = prog_add_constant(prog, value);
|
|
||||||
prog_add_instr(prog, OP_PUSH, idx);
|
|
||||||
}
|
}
|
||||||
else if (symbol->closure_id != SK_NO_CLOSURE)
|
else if (symbol->closure_id != SK_NO_CLOSURE)
|
||||||
{
|
{
|
||||||
|
@ -265,6 +260,7 @@ void compiler_compile(struct compiler* self,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
compiler_compile(self, body, p, fun->sym, state);
|
compiler_compile(self, body, p, fun->sym, state);
|
||||||
|
|
||||||
union val val;
|
union val val;
|
||||||
|
|
|
@ -40,6 +40,11 @@ void exec_execute(struct exec* self,
|
||||||
self->pc++;
|
self->pc++;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case OP_GLOBAL_LOAD: {
|
||||||
|
state_global_load(state, param);
|
||||||
|
self->pc++;
|
||||||
|
} break;
|
||||||
|
|
||||||
case OP_LOCAL_LOAD: {
|
case OP_LOCAL_LOAD: {
|
||||||
state_local_load(state, param);
|
state_local_load(state, param);
|
||||||
self->pc++;
|
self->pc++;
|
||||||
|
@ -98,6 +103,7 @@ void exec_execute(struct exec* self,
|
||||||
vec_init(&pvalues);
|
vec_init(&pvalues);
|
||||||
|
|
||||||
SK function = state_pop(state);
|
SK function = state_pop(state);
|
||||||
|
|
||||||
for (size_t i=0; i<param; i++)
|
for (size_t i=0; i<param; i++)
|
||||||
{
|
{
|
||||||
SK arg = state_pop(state);
|
SK arg = state_pop(state);
|
||||||
|
@ -112,11 +118,21 @@ void exec_execute(struct exec* self,
|
||||||
f->val.ref
|
f->val.ref
|
||||||
);
|
);
|
||||||
|
|
||||||
|
assert(val_fun);
|
||||||
|
|
||||||
if (val_fun->type == TYPE_NATIVE_FUN)
|
if (val_fun->type == TYPE_NATIVE_FUN)
|
||||||
{
|
{
|
||||||
|
struct vec ordered;
|
||||||
|
vec_init(&ordered);
|
||||||
|
for (size_t i=0; i<pvalues.size; i++)
|
||||||
|
{
|
||||||
|
SK arg = (SK)
|
||||||
|
pvalues.data[pvalues.size - 1 - i];
|
||||||
|
vec_push(&ordered, (void*) arg);
|
||||||
|
}
|
||||||
SK res = nfun_call(val_fun->val.nfun,
|
SK res = nfun_call(val_fun->val.nfun,
|
||||||
state,
|
state,
|
||||||
&pvalues);
|
&ordered);
|
||||||
struct value* value =
|
struct value* value =
|
||||||
state_try_get_value(state, res);
|
state_try_get_value(state, res);
|
||||||
state_push(
|
state_push(
|
||||||
|
@ -127,8 +143,10 @@ void exec_execute(struct exec* self,
|
||||||
);
|
);
|
||||||
|
|
||||||
vec_free(&pvalues);
|
vec_free(&pvalues);
|
||||||
vec_free_elements(¶ms, NULL);
|
vec_free(&ordered);
|
||||||
|
vec_free_elements(¶ms, (void*) value_free);
|
||||||
vec_free(¶ms);
|
vec_free(¶ms);
|
||||||
|
value_free(f);
|
||||||
free(f);
|
free(f);
|
||||||
self->pc++;
|
self->pc++;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -5,26 +5,35 @@ void natives_populate(struct state* state, struct sym* sym)
|
||||||
assert(state);
|
assert(state);
|
||||||
assert(sym);
|
assert(sym);
|
||||||
|
|
||||||
natives_decl(state, sym, "println", native_println, 1);
|
natives_decl(state, sym, "println", native_println, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void natives_decl(struct state* state,
|
void natives_decl(struct state* state,
|
||||||
struct sym* sym,
|
struct sym* sym,
|
||||||
char* name,
|
char* name,
|
||||||
nfun_body fun,
|
nfun_body fun,
|
||||||
size_t arity)
|
int arity)
|
||||||
{
|
{
|
||||||
assert(state);
|
assert(state);
|
||||||
assert(sym);
|
assert(sym);
|
||||||
int addr = state_add_nfun(state, fun, arity);
|
sym_decl_global(sym, state->global_id, name);
|
||||||
sym_decl_native(sym, name, addr);
|
state_add_nfun(state, fun, arity);
|
||||||
}
|
}
|
||||||
|
|
||||||
SK native_println(struct state* state, struct vec* args)
|
SK native_println(struct state* state, struct vec* args)
|
||||||
{
|
{
|
||||||
struct value* arg
|
for (size_t i=0; i<args->size; i++)
|
||||||
= state_try_get_value(state, (SK) args->data[0]);
|
{
|
||||||
|
struct value* arg
|
||||||
|
= state_try_get_value(state, (SK) args->data[i]);
|
||||||
|
|
||||||
printf("%s\n", arg->val.str);
|
struct str str;
|
||||||
|
str_init(&str);
|
||||||
|
value_str(arg, &str);
|
||||||
|
if (i > 0) { printf(" "); }
|
||||||
|
printf("%s", str.value);
|
||||||
|
str_free(&str);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
return state_push_bool(state, true, 0);
|
return state_push_bool(state, true, 0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#include "nfun.h"
|
#include "nfun.h"
|
||||||
|
|
||||||
void nfun_init(struct nfun* self, nfun_body body, size_t arity)
|
void nfun_init(struct nfun* self, nfun_body body, int arity)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
self->body = body;
|
self->body = body;
|
||||||
|
@ -24,7 +24,7 @@ SK nfun_call(struct nfun* self,
|
||||||
line = state_line(state, (SK) args->data[0]);
|
line = state_line(state, (SK) args->data[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self->arity != args->size)
|
if (self->arity >= 0 && self->arity != (int) args->size)
|
||||||
{
|
{
|
||||||
errors_push(line,
|
errors_push(line,
|
||||||
"wrong arity, expected %zu, got %zu.",
|
"wrong arity, expected %zu, got %zu.",
|
||||||
|
|
|
@ -214,7 +214,6 @@ struct node* parser_try_block(struct parser* self)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct token* tok = lexer_try_new_next(&self->lexer);
|
struct token* tok = lexer_try_new_next(&self->lexer);
|
||||||
|
|
||||||
struct node* node = SK_TRY(parser_try_inner_block);
|
struct node* node = SK_TRY(parser_try_inner_block);
|
||||||
|
|
||||||
if (!node)
|
if (!node)
|
||||||
|
@ -226,9 +225,12 @@ struct node* parser_try_block(struct parser* self)
|
||||||
if (!lexer_next_is(&self->lexer, TOKEN_END))
|
if (!lexer_next_is(&self->lexer, TOKEN_END))
|
||||||
{
|
{
|
||||||
node_free(node); free(node);
|
node_free(node); free(node);
|
||||||
|
token_free(tok); free(tok);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
token_free(tok);
|
||||||
|
free(tok);
|
||||||
lexer_consume_next(&self->lexer);
|
lexer_consume_next(&self->lexer);
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,9 @@ void state_init(struct state* self)
|
||||||
assert(self);
|
assert(self);
|
||||||
vec_init(&self->frames);
|
vec_init(&self->frames);
|
||||||
self->addr = 1;
|
self->addr = 1;
|
||||||
|
self->global_id = 1456;
|
||||||
state_push_frame(self);
|
state_push_frame(self);
|
||||||
|
vec_init(&self->global_values);
|
||||||
vec_init(&self->globals);
|
vec_init(&self->globals);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,7 +53,10 @@ void state_free(struct state* self)
|
||||||
vec_free_elements(&self->frames, (void*) frame_free);
|
vec_free_elements(&self->frames, (void*) frame_free);
|
||||||
vec_free(&self->frames);
|
vec_free(&self->frames);
|
||||||
|
|
||||||
vec_free_elements(&self->globals, (void*) value_free);
|
vec_free_elements(&self->global_values, (void*) value_free);
|
||||||
|
vec_free(&self->global_values);
|
||||||
|
|
||||||
|
vec_free_elements(&self->globals, NULL);
|
||||||
vec_free(&self->globals);
|
vec_free(&self->globals);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,25 +66,30 @@ SK state_make_ref(struct state* self)
|
||||||
struct value* value = state_try_get_value(self, val);
|
struct value* value = state_try_get_value(self, val);
|
||||||
|
|
||||||
struct value* on_heap = value_new_clone(value);
|
struct value* on_heap = value_new_clone(value);
|
||||||
vec_push(&self->globals, on_heap);
|
|
||||||
|
|
||||||
return state_push_ref(
|
size_t addr = state_add_global(
|
||||||
self,
|
self,
|
||||||
self->globals.size - 1,
|
on_heap
|
||||||
on_heap->line
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return state_push_ref(self, addr, value->line);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct value* state_try_deref(struct state* self, size_t ref)
|
struct value* state_try_deref(struct state* self, size_t ref)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
|
|
||||||
if (ref >= self->globals.size)
|
for (size_t i=0; i<self->globals.size; i++)
|
||||||
{
|
{
|
||||||
return NULL;
|
struct global const* global = self->globals.data[i];
|
||||||
|
|
||||||
|
if (global->addr == ref)
|
||||||
|
{
|
||||||
|
return self->global_values.data[ref];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return self->globals.data[ref];
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct frame* state_frame(struct state* self)
|
struct frame* state_frame(struct state* self)
|
||||||
|
@ -302,7 +312,25 @@ void state_local_load(struct state* self,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(stderr, "cannot load %d\n", id);
|
fprintf(stderr, "cannot load local %d\n", id);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
void state_global_load(struct state* self,
|
||||||
|
int id)
|
||||||
|
{
|
||||||
|
for (size_t i=0; i<self->globals.size; i++)
|
||||||
|
{
|
||||||
|
struct global const* global = self->globals.data[i];
|
||||||
|
|
||||||
|
if (global->id == id)
|
||||||
|
{
|
||||||
|
state_push_ref(self, global->addr, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "cannot load global %d\n", id);
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -726,6 +754,23 @@ SK state_eq(struct state* self)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int state_add_global(struct state* self,
|
||||||
|
struct value* value)
|
||||||
|
{
|
||||||
|
assert(self);
|
||||||
|
|
||||||
|
vec_push(&self->global_values, value);
|
||||||
|
size_t addr = self->global_values.size - 1;
|
||||||
|
struct global* global = malloc(sizeof(struct global));
|
||||||
|
global->id = self->global_id;
|
||||||
|
self->global_id++;
|
||||||
|
global->addr = addr;
|
||||||
|
|
||||||
|
vec_push(&self->globals, global);
|
||||||
|
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
void state_call(struct state* self, struct fun* fun)
|
void state_call(struct state* self, struct fun* fun)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
|
@ -742,7 +787,7 @@ void state_ret(struct state* self)
|
||||||
|
|
||||||
SK state_add_nfun(struct state* self,
|
SK state_add_nfun(struct state* self,
|
||||||
nfun_body body,
|
nfun_body body,
|
||||||
size_t arity)
|
int arity)
|
||||||
{
|
{
|
||||||
struct nfun* fun = malloc(sizeof(struct nfun));
|
struct nfun* fun = malloc(sizeof(struct nfun));
|
||||||
nfun_init(fun, body, arity);
|
nfun_init(fun, body, arity);
|
||||||
|
@ -753,6 +798,5 @@ SK state_add_nfun(struct state* self,
|
||||||
struct value* value = malloc(sizeof(struct value));
|
struct value* value = malloc(sizeof(struct value));
|
||||||
value_init(value, TYPE_NATIVE_FUN, val, 0);
|
value_init(value, TYPE_NATIVE_FUN, val, 0);
|
||||||
|
|
||||||
vec_push(&self->globals, value);
|
return state_add_global(self, value);
|
||||||
return self->globals.size - 1;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,6 +71,7 @@ void symbol_init(struct symbol* self,
|
||||||
self->id = id;
|
self->id = id;
|
||||||
self->name = strdup(name);
|
self->name = strdup(name);
|
||||||
self->is_const = false;
|
self->is_const = false;
|
||||||
|
self->is_global = false;
|
||||||
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;
|
||||||
|
@ -88,6 +89,7 @@ void sym_init(struct sym* self)
|
||||||
self->id_counter = 1;
|
self->id_counter = 1;
|
||||||
self->closure_counter = 1;
|
self->closure_counter = 1;
|
||||||
self->native_counter = 1;
|
self->native_counter = 1;
|
||||||
|
self->global_counter = 1;
|
||||||
self->env = malloc(sizeof(struct env));
|
self->env = malloc(sizeof(struct env));
|
||||||
env_init(self->env);
|
env_init(self->env);
|
||||||
}
|
}
|
||||||
|
@ -156,20 +158,16 @@ int sym_decl_closure(struct sym* self, int id, char const* name)
|
||||||
return self->closure_counter - 1;
|
return self->closure_counter - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sym_decl_native(struct sym* self, char const* name, int addr)
|
int sym_decl_global(struct sym* self, int id, char const* name)
|
||||||
{
|
{
|
||||||
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->native_counter, name, self->env);
|
symbol_init(symbol, id, name, self->env);
|
||||||
symbol->is_const = false;
|
symbol->is_global = true;
|
||||||
symbol->native_id = addr;
|
|
||||||
vec_push(&self->env->symbols, symbol);
|
vec_push(&self->env->symbols, symbol);
|
||||||
|
return id;
|
||||||
self->native_counter++;
|
|
||||||
return self->native_counter - 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void sym_open_scope(struct sym* self)
|
void sym_open_scope(struct sym* self)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
|
|
|
@ -70,7 +70,7 @@ struct value* value_new_clone(struct value* self)
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case TYPE_STRING: {
|
case TYPE_STRING: {
|
||||||
val.str = self->val.str;
|
val.str = strdup(self->val.str);
|
||||||
value_init(clone, TYPE_STRING, val, self->line);
|
value_init(clone, TYPE_STRING, val, self->line);
|
||||||
return clone;
|
return clone;
|
||||||
} break;
|
} break;
|
||||||
|
|
Loading…
Reference in New Issue