✨ native functions.
parent
06b379c99c
commit
88aad1ee75
|
@ -25,6 +25,9 @@ add_library(skopy-lib SHARED
|
||||||
|
|
||||||
src/sym.c
|
src/sym.c
|
||||||
src/fun.c
|
src/fun.c
|
||||||
|
|
||||||
|
src/nfun.c
|
||||||
|
src/natives.c
|
||||||
)
|
)
|
||||||
|
|
||||||
file(GLOB_RECURSE
|
file(GLOB_RECURSE
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "vec.h"
|
#include "vec.h"
|
||||||
#include "errors.h"
|
#include "errors.h"
|
||||||
|
|
||||||
|
|
||||||
#define SK_ENUM_ENUM(X) X
|
#define SK_ENUM_ENUM(X) X
|
||||||
#define SK_ENUM_STR(X) #X
|
#define SK_ENUM_STR(X) #X
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
#include "prog.h"
|
#include "prog.h"
|
||||||
#include "sym.h"
|
#include "sym.h"
|
||||||
|
|
||||||
|
struct state;
|
||||||
|
|
||||||
struct compiler
|
struct compiler
|
||||||
{
|
{
|
||||||
struct vec var_names;
|
struct vec var_names;
|
||||||
|
@ -16,12 +18,14 @@ void compiler_free(struct compiler* self);
|
||||||
void compiler_compile(struct compiler* self,
|
void compiler_compile(struct compiler* self,
|
||||||
struct node* node,
|
struct node* node,
|
||||||
struct prog* prog,
|
struct prog* prog,
|
||||||
struct sym* sym);
|
struct sym* sym,
|
||||||
|
struct state* state);
|
||||||
|
|
||||||
void compiler_compile_children(struct compiler* self,
|
void compiler_compile_children(struct compiler* self,
|
||||||
struct node* node,
|
struct node* node,
|
||||||
struct prog* prog,
|
struct prog* prog,
|
||||||
struct sym* sym);
|
struct sym* sym,
|
||||||
|
struct state* state);
|
||||||
|
|
||||||
void compiler_compile_value(struct compiler* self,
|
void compiler_compile_value(struct compiler* self,
|
||||||
struct node* node,
|
struct node* node,
|
||||||
|
@ -32,17 +36,20 @@ void compiler_compile_value(struct compiler* self,
|
||||||
void compiler_compile_and(struct compiler* self,
|
void compiler_compile_and(struct compiler* self,
|
||||||
struct node* node,
|
struct node* node,
|
||||||
struct prog* prog,
|
struct prog* prog,
|
||||||
struct sym* sym);
|
struct sym* sym,
|
||||||
|
struct state* state);
|
||||||
|
|
||||||
void compiler_compile_or(struct compiler* self,
|
void compiler_compile_or(struct compiler* self,
|
||||||
struct node* node,
|
struct node* node,
|
||||||
struct prog* prog,
|
struct prog* prog,
|
||||||
struct sym* sym);
|
struct sym* sym,
|
||||||
|
struct state* state);
|
||||||
|
|
||||||
void compiler_compile_if(struct compiler* self,
|
void compiler_compile_if(struct compiler* self,
|
||||||
struct node* node,
|
struct node* node,
|
||||||
struct prog* prog,
|
struct prog* prog,
|
||||||
struct sym* sym,
|
struct sym* sym,
|
||||||
|
struct state* state,
|
||||||
struct vec* to_end);
|
struct vec* to_end);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -4,12 +4,14 @@
|
||||||
#include "commons.h"
|
#include "commons.h"
|
||||||
#include "prog.h"
|
#include "prog.h"
|
||||||
#include "sym.h"
|
#include "sym.h"
|
||||||
|
#include "state.h"
|
||||||
|
|
||||||
struct module
|
struct module
|
||||||
{
|
{
|
||||||
struct str source;
|
struct str source;
|
||||||
struct prog prog;
|
struct prog prog;
|
||||||
struct sym sym;
|
struct sym sym;
|
||||||
|
struct state state;
|
||||||
};
|
};
|
||||||
|
|
||||||
void module_init(struct module* self);
|
void module_init(struct module* self);
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
#ifndef SK_NATIVES_H
|
||||||
|
#define SK_NATIVES_H
|
||||||
|
|
||||||
|
#include "commons.h"
|
||||||
|
#include "state.h"
|
||||||
|
#include "sym.h"
|
||||||
|
|
||||||
|
void natives_populate(struct state* state, struct sym* sym);
|
||||||
|
void natives_decl(struct state* state,
|
||||||
|
struct sym* sym,
|
||||||
|
char* name,
|
||||||
|
nfun_body fun,
|
||||||
|
size_t arity);
|
||||||
|
|
||||||
|
SK native_println(struct state* state, struct vec* args);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,21 @@
|
||||||
|
#ifndef SK_NFUN_H
|
||||||
|
#define SK_NFUN_H
|
||||||
|
|
||||||
|
#include "commons.h"
|
||||||
|
#include "state.h"
|
||||||
|
|
||||||
|
typedef SK (*nfun_body)(struct state*, struct vec*);
|
||||||
|
|
||||||
|
struct nfun
|
||||||
|
{
|
||||||
|
nfun_body body;
|
||||||
|
size_t arity;
|
||||||
|
};
|
||||||
|
|
||||||
|
void nfun_init(struct nfun* self, nfun_body body, size_t arity);
|
||||||
|
void nfun_free(struct nfun* self);
|
||||||
|
|
||||||
|
SK nfun_call(struct nfun* self,
|
||||||
|
struct state* state,
|
||||||
|
struct vec* args);
|
||||||
|
#endif
|
|
@ -1,7 +1,6 @@
|
||||||
#ifndef SK_STATE_H
|
#ifndef SK_STATE_H
|
||||||
#define SK_STATE_H
|
#define SK_STATE_H
|
||||||
|
|
||||||
#include "commons.h"
|
|
||||||
#include "value.h"
|
#include "value.h"
|
||||||
|
|
||||||
#define SK size_t
|
#define SK size_t
|
||||||
|
@ -34,6 +33,8 @@ struct state
|
||||||
struct vec globals;
|
struct vec globals;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef SK (*nfun_body)(struct state*, struct vec*);
|
||||||
|
|
||||||
void stack_value_init(struct stack_value* self,
|
void stack_value_init(struct stack_value* self,
|
||||||
size_t addr,
|
size_t addr,
|
||||||
struct value* new_value);
|
struct value* new_value);
|
||||||
|
@ -53,7 +54,6 @@ 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);
|
||||||
|
|
||||||
bool state_has_top(struct state* self);
|
|
||||||
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);
|
||||||
struct local* state_try_get_local_by_id(struct state* self, int id);
|
struct local* state_try_get_local_by_id(struct state* self, int id);
|
||||||
|
@ -109,4 +109,7 @@ SK state_eq(struct state* self);
|
||||||
|
|
||||||
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,
|
||||||
|
nfun_body body,
|
||||||
|
size_t arity);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -3,11 +3,13 @@
|
||||||
|
|
||||||
#include "commons.h"
|
#include "commons.h"
|
||||||
#define SK_NO_CLOSURE (-1)
|
#define SK_NO_CLOSURE (-1)
|
||||||
|
#define SK_NO_NATIVE (-1)
|
||||||
|
|
||||||
struct symbol
|
struct symbol
|
||||||
{
|
{
|
||||||
int id;
|
int id;
|
||||||
int closure_id;
|
int closure_id;
|
||||||
|
int native_id;
|
||||||
char* name;
|
char* name;
|
||||||
bool is_const;
|
bool is_const;
|
||||||
struct env* env;
|
struct env* env;
|
||||||
|
@ -23,6 +25,7 @@ struct sym
|
||||||
{
|
{
|
||||||
int id_counter;
|
int id_counter;
|
||||||
int closure_counter;
|
int closure_counter;
|
||||||
|
int native_counter;
|
||||||
struct env* env;
|
struct env* env;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -46,6 +49,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);
|
||||||
|
|
||||||
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);
|
||||||
|
|
|
@ -7,7 +7,8 @@
|
||||||
|
|
||||||
#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)
|
||||||
|
|
||||||
SK_ENUM_H(TypeKind, TYPE_KIND);
|
SK_ENUM_H(TypeKind, TYPE_KIND);
|
||||||
|
|
||||||
|
@ -18,6 +19,7 @@ union val
|
||||||
bool boolean;
|
bool boolean;
|
||||||
char* str;
|
char* str;
|
||||||
struct fun* fun;
|
struct fun* fun;
|
||||||
|
struct nfun* nfun;
|
||||||
size_t ref;
|
size_t ref;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "compiler.h"
|
#include "compiler.h"
|
||||||
#include "token.h"
|
#include "token.h"
|
||||||
|
#include "state.h"
|
||||||
|
#include "natives.h"
|
||||||
|
|
||||||
void compiler_init(struct compiler* self)
|
void compiler_init(struct compiler* self)
|
||||||
{
|
{
|
||||||
|
@ -16,7 +18,8 @@ void compiler_free(struct compiler* self)
|
||||||
void compiler_compile(struct compiler* self,
|
void compiler_compile(struct compiler* self,
|
||||||
struct node* node,
|
struct node* node,
|
||||||
struct prog* prog,
|
struct prog* prog,
|
||||||
struct sym* sym)
|
struct sym* sym,
|
||||||
|
struct state* state)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
assert(node);
|
assert(node);
|
||||||
|
@ -28,7 +31,7 @@ void compiler_compile(struct compiler* self,
|
||||||
for (size_t i=0; i<node->children.size; i++)
|
for (size_t i=0; i<node->children.size; i++)
|
||||||
{
|
{
|
||||||
compiler_compile(self, node->children.data[i],
|
compiler_compile(self, node->children.data[i],
|
||||||
prog, sym);
|
prog, sym, state);
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
@ -37,7 +40,7 @@ void compiler_compile(struct compiler* self,
|
||||||
for (size_t i=0; i<node->children.size; i++)
|
for (size_t i=0; i<node->children.size; i++)
|
||||||
{
|
{
|
||||||
compiler_compile(self, node->children.data[i],
|
compiler_compile(self, node->children.data[i],
|
||||||
prog, sym);
|
prog, sym, state);
|
||||||
}
|
}
|
||||||
sym_close_scope(sym);
|
sym_close_scope(sym);
|
||||||
} break;
|
} break;
|
||||||
|
@ -49,10 +52,10 @@ void compiler_compile(struct compiler* self,
|
||||||
for (size_t i=0; i<args->children.size; i++)
|
for (size_t i=0; i<args->children.size; i++)
|
||||||
{
|
{
|
||||||
compiler_compile(self, args->children.data[i],
|
compiler_compile(self, args->children.data[i],
|
||||||
prog, sym);
|
prog, sym, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
compiler_compile(self, target, prog, sym);
|
compiler_compile(self, target, prog, sym, state);
|
||||||
prog_add_instr(prog, OP_CALL, args->children.size);
|
prog_add_instr(prog, OP_CALL, args->children.size);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
@ -60,7 +63,8 @@ void compiler_compile(struct compiler* self,
|
||||||
struct vec to_end;
|
struct vec to_end;
|
||||||
vec_init(&to_end);
|
vec_init(&to_end);
|
||||||
|
|
||||||
compiler_compile_if(self, node, prog, sym, &to_end);
|
compiler_compile_if(self, node, prog, sym, state,
|
||||||
|
&to_end);
|
||||||
size_t end_point = prog->params.size;
|
size_t end_point = prog->params.size;
|
||||||
|
|
||||||
for (size_t i=0; i<to_end.size; i++)
|
for (size_t i=0; i<to_end.size; i++)
|
||||||
|
@ -73,20 +77,20 @@ void compiler_compile(struct compiler* self,
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_NOT: {
|
case NODE_NOT: {
|
||||||
compiler_compile_children(self, node, prog, sym);
|
compiler_compile_children(self, node, prog, sym, state);
|
||||||
prog_add_instr(prog, OP_NOT, SK_NO_PARAM);
|
prog_add_instr(prog, OP_NOT, SK_NO_PARAM);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_AND: {
|
case NODE_AND: {
|
||||||
compiler_compile_and(self, node, prog, sym);
|
compiler_compile_and(self, node, prog, sym, state);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_OR: {
|
case NODE_OR: {
|
||||||
compiler_compile_or(self, node, prog, sym);
|
compiler_compile_or(self, node, prog, sym, state);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_ASSERT_EQ: {
|
case NODE_ASSERT_EQ: {
|
||||||
compiler_compile_children(self, node, prog, sym);
|
compiler_compile_children(self, node, prog, sym, state);
|
||||||
prog_add_instr(prog, OP_ASSERT_EQ, SK_NO_PARAM);
|
prog_add_instr(prog, OP_ASSERT_EQ, SK_NO_PARAM);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
@ -103,7 +107,7 @@ 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);
|
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);
|
||||||
|
|
||||||
|
@ -122,7 +126,7 @@ void compiler_compile(struct compiler* self,
|
||||||
ident->token->value);
|
ident->token->value);
|
||||||
}
|
}
|
||||||
struct node* expr = node->children.data[1];
|
struct node* expr = node->children.data[1];
|
||||||
compiler_compile(self, expr, prog, sym);
|
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);
|
||||||
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);
|
||||||
|
@ -148,7 +152,7 @@ void compiler_compile(struct compiler* self,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
compiler_compile(self, expr, prog, sym);
|
compiler_compile(self, expr, prog, sym, state);
|
||||||
|
|
||||||
if (symbol->closure_id != SK_NO_CLOSURE)
|
if (symbol->closure_id != SK_NO_CLOSURE)
|
||||||
{
|
{
|
||||||
|
@ -165,28 +169,34 @@ void compiler_compile(struct compiler* self,
|
||||||
node->token->value);
|
node->token->value);
|
||||||
if (!symbol)
|
if (!symbol)
|
||||||
{
|
{
|
||||||
|
errors_push(node->token->line,
|
||||||
|
"unknown identifier '%s'.",
|
||||||
|
node->token->value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct env* itr = sym->env->parent;
|
struct env* itr = sym->env->parent;
|
||||||
struct symbol* context = NULL;
|
|
||||||
|
|
||||||
while (itr)
|
while (itr)
|
||||||
{
|
{
|
||||||
struct symbol* s = env_try_get(itr, symbol->name);
|
struct symbol const* s = env_try_get(itr, symbol->name);
|
||||||
|
|
||||||
if (s)
|
if (s)
|
||||||
{
|
{
|
||||||
context = s;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
itr = itr->parent;
|
itr = itr->parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (0 && context)
|
if (symbol->native_id != SK_NO_NATIVE)
|
||||||
{
|
{
|
||||||
prog_add_instr(prog, OP_LOCAL_LOAD, context->id);
|
struct value* value = malloc(sizeof(struct value));
|
||||||
|
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)
|
||||||
{
|
{
|
||||||
|
@ -200,7 +210,7 @@ void compiler_compile(struct compiler* self,
|
||||||
|
|
||||||
case NODE_RETURN: {
|
case NODE_RETURN: {
|
||||||
compiler_compile(self, node->children.data[0],
|
compiler_compile(self, node->children.data[0],
|
||||||
prog, sym);
|
prog, sym, state);
|
||||||
prog_add_instr(prog, OP_RET, SK_NO_PARAM);
|
prog_add_instr(prog, OP_RET, SK_NO_PARAM);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
@ -210,6 +220,8 @@ void compiler_compile(struct compiler* self,
|
||||||
prog_init(p);
|
prog_init(p);
|
||||||
|
|
||||||
fun_init(fun, p);
|
fun_init(fun, p);
|
||||||
|
natives_populate(state, fun->sym);
|
||||||
|
|
||||||
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];
|
||||||
|
|
||||||
|
@ -253,7 +265,7 @@ void compiler_compile(struct compiler* self,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
compiler_compile(self, body, p, fun->sym);
|
compiler_compile(self, body, p, fun->sym, state);
|
||||||
|
|
||||||
union val val;
|
union val val;
|
||||||
val.fun = fun;
|
val.fun = fun;
|
||||||
|
@ -291,70 +303,70 @@ void compiler_compile(struct compiler* self,
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_LT: {
|
case NODE_LT: {
|
||||||
compiler_compile_children(self, node, prog, sym);
|
compiler_compile_children(self, node, prog, sym, state);
|
||||||
prog_add_instr(prog, OP_LT, SK_NO_PARAM);
|
prog_add_instr(prog, OP_LT, SK_NO_PARAM);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_LE: {
|
case NODE_LE: {
|
||||||
compiler_compile_children(self, node, prog, sym);
|
compiler_compile_children(self, node, prog, sym, state);
|
||||||
prog_add_instr(prog, OP_GT, SK_NO_PARAM);
|
prog_add_instr(prog, OP_GT, SK_NO_PARAM);
|
||||||
prog_add_instr(prog, OP_NOT, SK_NO_PARAM);
|
prog_add_instr(prog, OP_NOT, SK_NO_PARAM);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_GT: {
|
case NODE_GT: {
|
||||||
compiler_compile_children(self, node, prog, sym);
|
compiler_compile_children(self, node, prog, sym, state);
|
||||||
prog_add_instr(prog, OP_GT, SK_NO_PARAM);
|
prog_add_instr(prog, OP_GT, SK_NO_PARAM);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_GE: {
|
case NODE_GE: {
|
||||||
compiler_compile_children(self, node, prog, sym);
|
compiler_compile_children(self, node, prog, sym, state);
|
||||||
prog_add_instr(prog, OP_LT, SK_NO_PARAM);
|
prog_add_instr(prog, OP_LT, SK_NO_PARAM);
|
||||||
prog_add_instr(prog, OP_NOT, SK_NO_PARAM);
|
prog_add_instr(prog, OP_NOT, SK_NO_PARAM);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_EQUAL: {
|
case NODE_EQUAL: {
|
||||||
compiler_compile_children(self, node, prog, sym);
|
compiler_compile_children(self, node, prog, sym, state);
|
||||||
prog_add_instr(prog, OP_EQUAL, SK_NO_PARAM);
|
prog_add_instr(prog, OP_EQUAL, SK_NO_PARAM);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_NOT_EQUAL: {
|
case NODE_NOT_EQUAL: {
|
||||||
compiler_compile_children(self, node, prog, sym);
|
compiler_compile_children(self, node, prog, sym, state);
|
||||||
prog_add_instr(prog, OP_EQUAL, SK_NO_PARAM);
|
prog_add_instr(prog, OP_EQUAL, SK_NO_PARAM);
|
||||||
prog_add_instr(prog, OP_NOT, SK_NO_PARAM);
|
prog_add_instr(prog, OP_NOT, SK_NO_PARAM);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_ADD: {
|
case NODE_ADD: {
|
||||||
compiler_compile_children(self, node, prog, sym);
|
compiler_compile_children(self, node, prog, sym, state);
|
||||||
prog_add_instr(prog, OP_ADD, SK_NO_PARAM);
|
prog_add_instr(prog, OP_ADD, SK_NO_PARAM);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_SUB: {
|
case NODE_SUB: {
|
||||||
compiler_compile_children(self, node, prog, sym);
|
compiler_compile_children(self, node, prog, sym, state);
|
||||||
prog_add_instr(prog, OP_SUB, SK_NO_PARAM);
|
prog_add_instr(prog, OP_SUB, SK_NO_PARAM);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_MUL: {
|
case NODE_MUL: {
|
||||||
compiler_compile_children(self, node, prog, sym);
|
compiler_compile_children(self, node, prog, sym, state);
|
||||||
prog_add_instr(prog, OP_MUL, SK_NO_PARAM);
|
prog_add_instr(prog, OP_MUL, SK_NO_PARAM);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_DIV: {
|
case NODE_DIV: {
|
||||||
compiler_compile_children(self, node, prog, sym);
|
compiler_compile_children(self, node, prog, sym, state);
|
||||||
prog_add_instr(prog, OP_DIV, SK_NO_PARAM);
|
prog_add_instr(prog, OP_DIV, SK_NO_PARAM);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_MOD: {
|
case NODE_MOD: {
|
||||||
compiler_compile_children(self, node, prog, sym);
|
compiler_compile_children(self, node, prog, sym, state);
|
||||||
prog_add_instr(prog, OP_MOD, SK_NO_PARAM);
|
prog_add_instr(prog, OP_MOD, SK_NO_PARAM);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_POW: {
|
case NODE_POW: {
|
||||||
compiler_compile_children(self, node, prog, sym);
|
compiler_compile_children(self, node, prog, sym, state);
|
||||||
prog_add_instr(prog, OP_POW, SK_NO_PARAM);
|
prog_add_instr(prog, OP_POW, SK_NO_PARAM);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_USUB: {
|
case NODE_USUB: {
|
||||||
compiler_compile_children(self, node, prog, sym);
|
compiler_compile_children(self, node, prog, sym, state);
|
||||||
prog_add_instr(prog, OP_USUB, SK_NO_PARAM);
|
prog_add_instr(prog, OP_USUB, SK_NO_PARAM);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
@ -369,7 +381,8 @@ void compiler_compile(struct compiler* self,
|
||||||
void compiler_compile_children(struct compiler* self,
|
void compiler_compile_children(struct compiler* self,
|
||||||
struct node* node,
|
struct node* node,
|
||||||
struct prog* prog,
|
struct prog* prog,
|
||||||
struct sym* sym)
|
struct sym* sym,
|
||||||
|
struct state* state)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
assert(node);
|
assert(node);
|
||||||
|
@ -378,7 +391,7 @@ void compiler_compile_children(struct compiler* self,
|
||||||
for (size_t i=0; i<node->children.size; i++)
|
for (size_t i=0; i<node->children.size; i++)
|
||||||
{
|
{
|
||||||
struct node* child = node->children.data[i];
|
struct node* child = node->children.data[i];
|
||||||
compiler_compile(self, child, prog, sym);
|
compiler_compile(self, child, prog, sym, state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -399,7 +412,8 @@ void compiler_compile_value(struct compiler* self,
|
||||||
void compiler_compile_and(struct compiler* self,
|
void compiler_compile_and(struct compiler* self,
|
||||||
struct node* node,
|
struct node* node,
|
||||||
struct prog* prog,
|
struct prog* prog,
|
||||||
struct sym* sym)
|
struct sym* sym,
|
||||||
|
struct state* state)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
assert(node);
|
assert(node);
|
||||||
|
@ -412,7 +426,7 @@ void compiler_compile_and(struct compiler* self,
|
||||||
for (size_t i =0; i<node->children.size; i++)
|
for (size_t i =0; i<node->children.size; i++)
|
||||||
{
|
{
|
||||||
struct node* child = node->children.data[i];
|
struct node* child = node->children.data[i];
|
||||||
compiler_compile(self, child, prog, sym);
|
compiler_compile(self, child, prog, sym, state);
|
||||||
size_t brf = prog_add_instr(prog, OP_BRF, 0); // to false
|
size_t brf = prog_add_instr(prog, OP_BRF, 0); // to false
|
||||||
vec_push(&to_false, (void*) brf);
|
vec_push(&to_false, (void*) brf);
|
||||||
}
|
}
|
||||||
|
@ -442,7 +456,8 @@ void compiler_compile_and(struct compiler* self,
|
||||||
void compiler_compile_or(struct compiler* self,
|
void compiler_compile_or(struct compiler* self,
|
||||||
struct node* node,
|
struct node* node,
|
||||||
struct prog* prog,
|
struct prog* prog,
|
||||||
struct sym* sym)
|
struct sym* sym,
|
||||||
|
struct state* state)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
assert(node);
|
assert(node);
|
||||||
|
@ -454,7 +469,7 @@ void compiler_compile_or(struct compiler* self,
|
||||||
for (size_t i =0; i<node->children.size; i++)
|
for (size_t i =0; i<node->children.size; i++)
|
||||||
{
|
{
|
||||||
struct node* child = node->children.data[i];
|
struct node* child = node->children.data[i];
|
||||||
compiler_compile(self, child, prog, sym);
|
compiler_compile(self, child, prog, sym, state);
|
||||||
prog_add_instr(prog, OP_NOT, 0);
|
prog_add_instr(prog, OP_NOT, 0);
|
||||||
size_t brf = prog_add_instr(prog, OP_BRF, 0); // to true
|
size_t brf = prog_add_instr(prog, OP_BRF, 0); // to true
|
||||||
vec_push(&to_true, (void*) brf);
|
vec_push(&to_true, (void*) brf);
|
||||||
|
@ -486,15 +501,16 @@ void compiler_compile_if(struct compiler* self,
|
||||||
struct node* node,
|
struct node* node,
|
||||||
struct prog* prog,
|
struct prog* prog,
|
||||||
struct sym* sym,
|
struct sym* sym,
|
||||||
|
struct state* state,
|
||||||
struct vec* to_end)
|
struct vec* to_end)
|
||||||
{
|
{
|
||||||
struct node* cond = node->children.data[0];
|
struct node* cond = node->children.data[0];
|
||||||
struct node* block = node->children.data[1];
|
struct node* block = node->children.data[1];
|
||||||
|
|
||||||
compiler_compile(self, cond, prog, sym);
|
compiler_compile(self, cond, prog, sym, state);
|
||||||
size_t brf = prog_add_instr(prog, OP_BRF, 40); // to next
|
size_t brf = prog_add_instr(prog, OP_BRF, 40); // to next
|
||||||
|
|
||||||
compiler_compile(self, block, prog, sym);
|
compiler_compile(self, block, prog, sym, state);
|
||||||
|
|
||||||
size_t br = prog_add_instr(prog, OP_BR, 0); // to end
|
size_t br = prog_add_instr(prog, OP_BR, 0); // to end
|
||||||
vec_push(to_end, (void*) br);
|
vec_push(to_end, (void*) br);
|
||||||
|
@ -507,11 +523,11 @@ void compiler_compile_if(struct compiler* self,
|
||||||
struct node* next = node->children.data[2];
|
struct node* next = node->children.data[2];
|
||||||
if (next->kind == NODE_IF)
|
if (next->kind == NODE_IF)
|
||||||
{
|
{
|
||||||
compiler_compile_if(self, next, prog, sym, to_end);
|
compiler_compile_if(self, next, prog, sym, state, to_end);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
compiler_compile(self, next, prog, sym);
|
compiler_compile(self, next, prog, sym, state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "exec.h"
|
#include "exec.h"
|
||||||
#include "sym.h"
|
#include "sym.h"
|
||||||
#include "fun.h"
|
#include "fun.h"
|
||||||
|
#include "nfun.h"
|
||||||
|
|
||||||
void exec_init(struct exec* self)
|
void exec_init(struct exec* self)
|
||||||
{
|
{
|
||||||
|
@ -93,19 +94,57 @@ void exec_execute(struct exec* self,
|
||||||
struct vec params;
|
struct vec params;
|
||||||
vec_init(¶ms);
|
vec_init(¶ms);
|
||||||
|
|
||||||
|
struct vec 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);
|
||||||
|
vec_push(&pvalues, (void*) arg);
|
||||||
vec_push(¶ms, (void*) value_new_clone(state_try_get_value(state, arg)));
|
vec_push(¶ms, (void*) value_new_clone(state_try_get_value(state, arg)));
|
||||||
}
|
}
|
||||||
|
|
||||||
struct value* f = value_new_clone(state_try_get_value(state, function));
|
struct value* f = value_new_clone(state_try_get_value(state, function));
|
||||||
|
|
||||||
struct fun* fun = state_try_deref(
|
struct value* val_fun = state_try_deref(
|
||||||
state,
|
state,
|
||||||
f->val.ref
|
f->val.ref
|
||||||
)->val.fun;
|
);
|
||||||
|
|
||||||
|
if (val_fun->type == TYPE_NATIVE_FUN)
|
||||||
|
{
|
||||||
|
SK res = nfun_call(val_fun->val.nfun,
|
||||||
|
state,
|
||||||
|
&pvalues);
|
||||||
|
struct value* value =
|
||||||
|
state_try_get_value(state, res);
|
||||||
|
state_push(
|
||||||
|
state,
|
||||||
|
value->type,
|
||||||
|
value->val,
|
||||||
|
value->line
|
||||||
|
);
|
||||||
|
|
||||||
|
vec_free(&pvalues);
|
||||||
|
vec_free_elements(¶ms, NULL);
|
||||||
|
vec_free(¶ms);
|
||||||
|
free(f);
|
||||||
|
self->pc++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec_free(&pvalues);
|
||||||
|
if (!val_fun)
|
||||||
|
{
|
||||||
|
vec_free_elements(¶ms, NULL);
|
||||||
|
vec_free(¶ms);
|
||||||
|
errors_push(f->line, "cannot deref nil ref");
|
||||||
|
free(f);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct fun* fun = val_fun->val.fun;
|
||||||
|
|
||||||
state_call(state, fun);
|
state_call(state, fun);
|
||||||
for (size_t i=0; i<params.size; i++)
|
for (size_t i=0; i<params.size; i++)
|
||||||
|
@ -191,6 +230,14 @@ void exec_execute(struct exec* self,
|
||||||
);
|
);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case TYPE_REF: {
|
||||||
|
state_push_ref(
|
||||||
|
state,
|
||||||
|
constant->val.ref,
|
||||||
|
constant->line
|
||||||
|
);
|
||||||
|
} break;
|
||||||
|
|
||||||
case TYPE_BOOL: {
|
case TYPE_BOOL: {
|
||||||
state_push_bool(
|
state_push_bool(
|
||||||
state,
|
state,
|
||||||
|
|
|
@ -3,13 +3,17 @@
|
||||||
#include "compiler.h"
|
#include "compiler.h"
|
||||||
#include "state.h"
|
#include "state.h"
|
||||||
#include "exec.h"
|
#include "exec.h"
|
||||||
|
#include "natives.h"
|
||||||
|
|
||||||
void module_init(struct module* self)
|
void module_init(struct module* self)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
str_init(&self->source);
|
str_init(&self->source);
|
||||||
prog_init(&self->prog);
|
prog_init(&self->prog);
|
||||||
|
state_init(&self->state);
|
||||||
sym_init(&self->sym);
|
sym_init(&self->sym);
|
||||||
|
|
||||||
|
natives_populate(&self->state, &self->sym);
|
||||||
}
|
}
|
||||||
|
|
||||||
void module_free(struct module* self)
|
void module_free(struct module* self)
|
||||||
|
@ -18,6 +22,7 @@ void module_free(struct module* self)
|
||||||
str_free(&self->source);
|
str_free(&self->source);
|
||||||
prog_free(&self->prog);
|
prog_free(&self->prog);
|
||||||
sym_free(&self->sym);
|
sym_free(&self->sym);
|
||||||
|
state_free(&self->state);
|
||||||
}
|
}
|
||||||
|
|
||||||
void module_load_source(struct module* self,
|
void module_load_source(struct module* self,
|
||||||
|
@ -54,14 +59,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);
|
||||||
|
|
||||||
struct exec exec;
|
struct exec exec;
|
||||||
exec_init(&exec);
|
exec_init(&exec);
|
||||||
|
|
||||||
struct state state;
|
exec_execute(&exec, &self->state, &self->prog);
|
||||||
state_init(&state);
|
|
||||||
exec_execute(&exec, &state, &self->prog);
|
|
||||||
|
|
||||||
if (!errors_ok())
|
if (!errors_ok())
|
||||||
{
|
{
|
||||||
|
@ -69,25 +73,8 @@ int module_compile(struct module* self)
|
||||||
goto free_state;
|
goto free_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state_has_top(&state))
|
|
||||||
{
|
|
||||||
struct value* value = state_try_get_value(
|
|
||||||
&state,
|
|
||||||
state_top(&state)
|
|
||||||
);
|
|
||||||
|
|
||||||
assert(value);
|
|
||||||
|
|
||||||
struct str str;
|
|
||||||
str_init(&str);
|
|
||||||
value_str(value, &str);
|
|
||||||
printf("%s\n", str.value);
|
|
||||||
str_free(&str);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Free
|
// Free
|
||||||
free_state:
|
free_state:
|
||||||
state_free(&state);
|
|
||||||
exec_free(&exec);
|
exec_free(&exec);
|
||||||
compiler_free(&compiler);
|
compiler_free(&compiler);
|
||||||
free_node:
|
free_node:
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
#include "natives.h"
|
||||||
|
|
||||||
|
void natives_populate(struct state* state, struct sym* sym)
|
||||||
|
{
|
||||||
|
assert(state);
|
||||||
|
assert(sym);
|
||||||
|
|
||||||
|
natives_decl(state, sym, "println", native_println, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void natives_decl(struct state* state,
|
||||||
|
struct sym* sym,
|
||||||
|
char* name,
|
||||||
|
nfun_body fun,
|
||||||
|
size_t arity)
|
||||||
|
{
|
||||||
|
assert(state);
|
||||||
|
assert(sym);
|
||||||
|
int addr = state_add_nfun(state, fun, arity);
|
||||||
|
sym_decl_native(sym, name, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
SK native_println(struct state* state, struct vec* args)
|
||||||
|
{
|
||||||
|
struct value* arg
|
||||||
|
= state_try_get_value(state, (SK) args->data[0]);
|
||||||
|
|
||||||
|
printf("%s\n", arg->val.str);
|
||||||
|
return state_push_bool(state, true, 0);
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
#include "nfun.h"
|
||||||
|
|
||||||
|
void nfun_init(struct nfun* self, nfun_body body, size_t arity)
|
||||||
|
{
|
||||||
|
assert(self);
|
||||||
|
self->body = body;
|
||||||
|
self->arity = arity;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfun_free(struct nfun* self)
|
||||||
|
{
|
||||||
|
assert(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
SK nfun_call(struct nfun* self,
|
||||||
|
struct state* state,
|
||||||
|
struct vec* args)
|
||||||
|
{
|
||||||
|
assert(self);
|
||||||
|
int line = 0;
|
||||||
|
|
||||||
|
if (args->size > 0)
|
||||||
|
{
|
||||||
|
line = state_line(state, (SK) args->data[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self->arity != args->size)
|
||||||
|
{
|
||||||
|
errors_push(line,
|
||||||
|
"wrong arity, expected %zu, got %zu.",
|
||||||
|
self->arity,
|
||||||
|
args->size);
|
||||||
|
return state_push_bool(state, false, line);
|
||||||
|
}
|
||||||
|
|
||||||
|
SK result = (*self->body)(state, args);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
#include "state.h"
|
#include "state.h"
|
||||||
|
#include "nfun.h"
|
||||||
|
|
||||||
void stack_value_init(struct stack_value* self,
|
void stack_value_init(struct stack_value* self,
|
||||||
size_t addr,
|
size_t addr,
|
||||||
|
@ -105,11 +106,6 @@ void state_pop_frame(struct state* self)
|
||||||
frame_free(frame);
|
frame_free(frame);
|
||||||
free(frame);
|
free(frame);
|
||||||
}
|
}
|
||||||
bool state_has_top(struct state* self)
|
|
||||||
{
|
|
||||||
struct frame* frame = state_frame(self);
|
|
||||||
return frame->stack.size > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
SK state_top(struct state* self)
|
SK state_top(struct state* self)
|
||||||
{
|
{
|
||||||
|
@ -743,3 +739,20 @@ void state_ret(struct state* self)
|
||||||
assert(self);
|
assert(self);
|
||||||
state_pop_frame(self);
|
state_pop_frame(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SK state_add_nfun(struct state* self,
|
||||||
|
nfun_body body,
|
||||||
|
size_t arity)
|
||||||
|
{
|
||||||
|
struct nfun* fun = malloc(sizeof(struct nfun));
|
||||||
|
nfun_init(fun, body, arity);
|
||||||
|
|
||||||
|
union val val;
|
||||||
|
val.nfun = fun;
|
||||||
|
|
||||||
|
struct value* value = malloc(sizeof(struct value));
|
||||||
|
value_init(value, TYPE_NATIVE_FUN, val, 0);
|
||||||
|
|
||||||
|
vec_push(&self->globals, value);
|
||||||
|
return self->globals.size - 1;
|
||||||
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ struct env* env_new_clone(struct env* self)
|
||||||
new_symbol->name = strdup(symbol->name);
|
new_symbol->name = strdup(symbol->name);
|
||||||
new_symbol->is_const = symbol->is_const;
|
new_symbol->is_const = symbol->is_const;
|
||||||
new_symbol->closure_id = symbol->closure_id;
|
new_symbol->closure_id = symbol->closure_id;
|
||||||
|
new_symbol->native_id = symbol->native_id;
|
||||||
new_symbol->env = clone;
|
new_symbol->env = clone;
|
||||||
|
|
||||||
vec_push(&clone->symbols, new_symbol);
|
vec_push(&clone->symbols, new_symbol);
|
||||||
|
@ -71,6 +72,7 @@ void symbol_init(struct symbol* self,
|
||||||
self->name = strdup(name);
|
self->name = strdup(name);
|
||||||
self->is_const = false;
|
self->is_const = false;
|
||||||
self->closure_id = SK_NO_CLOSURE;
|
self->closure_id = SK_NO_CLOSURE;
|
||||||
|
self->native_id = SK_NO_NATIVE;
|
||||||
self->env = env;
|
self->env = env;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,6 +87,7 @@ void sym_init(struct sym* self)
|
||||||
assert(self);
|
assert(self);
|
||||||
self->id_counter = 1;
|
self->id_counter = 1;
|
||||||
self->closure_counter = 1;
|
self->closure_counter = 1;
|
||||||
|
self->native_counter = 1;
|
||||||
self->env = malloc(sizeof(struct env));
|
self->env = malloc(sizeof(struct env));
|
||||||
env_init(self->env);
|
env_init(self->env);
|
||||||
}
|
}
|
||||||
|
@ -142,7 +145,7 @@ int sym_decl_closure(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->closure_counter, name, self->env);
|
symbol_init(symbol, self->closure_counter, name, self->env);
|
||||||
symbol->is_const = false;
|
symbol->is_const = false;
|
||||||
|
@ -153,6 +156,20 @@ 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)
|
||||||
|
{
|
||||||
|
assert(self);
|
||||||
|
assert(name);
|
||||||
|
struct symbol* symbol = malloc(sizeof(struct symbol));
|
||||||
|
symbol_init(symbol, self->native_counter, name, self->env);
|
||||||
|
symbol->is_const = false;
|
||||||
|
symbol->native_id = addr;
|
||||||
|
vec_push(&self->env->symbols, symbol);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "value.h"
|
#include "value.h"
|
||||||
|
#include "nfun.h"
|
||||||
|
|
||||||
SK_ENUM_C(TypeKind, TYPE_KIND);
|
SK_ENUM_C(TypeKind, TYPE_KIND);
|
||||||
|
|
||||||
|
@ -27,6 +28,12 @@ void value_free(struct value* self)
|
||||||
fun_free(self->val.fun);
|
fun_free(self->val.fun);
|
||||||
free(self->val.fun);
|
free(self->val.fun);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (self->type == TYPE_NATIVE_FUN)
|
||||||
|
{
|
||||||
|
nfun_free(self->val.nfun);
|
||||||
|
free(self->val.nfun);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct value* value_new_clone(struct value* self)
|
struct value* value_new_clone(struct value* self)
|
||||||
|
@ -74,6 +81,14 @@ struct value* value_new_clone(struct value* self)
|
||||||
return clone;
|
return clone;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case TYPE_NATIVE_FUN: {
|
||||||
|
val.nfun = malloc(sizeof(struct nfun));
|
||||||
|
val.nfun->body = self->val.nfun->body;
|
||||||
|
val.nfun->arity = self->val.nfun->arity;
|
||||||
|
value_init(clone, TYPE_NATIVE_FUN, val, self->line);
|
||||||
|
return clone;
|
||||||
|
} break;
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
fprintf(stderr, "cannot clone value '%s'\n",
|
fprintf(stderr, "cannot clone value '%s'\n",
|
||||||
TypeKindStr[self->type]);
|
TypeKindStr[self->type]);
|
||||||
|
@ -111,6 +126,10 @@ void value_str(struct value* self, struct str* dest)
|
||||||
str_format(dest, "<fun:%p>", self->val.fun);
|
str_format(dest, "<fun:%p>", self->val.fun);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case TYPE_NATIVE_FUN: {
|
||||||
|
str_format(dest, "<nfun:%p>", self->val.nfun);
|
||||||
|
} break;
|
||||||
|
|
||||||
case TYPE_REF: {
|
case TYPE_REF: {
|
||||||
str_format(dest, "<ref:%zu>", self->val.ref);
|
str_format(dest, "<ref:%zu>", self->val.ref);
|
||||||
} break;
|
} break;
|
||||||
|
|
Loading…
Reference in New Issue