change way of calling native functions

This commit is contained in:
ValKmjolnir 2023-10-21 00:31:39 +08:00
parent 7f8a0b6445
commit 820c05c986
17 changed files with 448 additions and 410 deletions

View File

@ -2,45 +2,52 @@
namespace nasal { namespace nasal {
var builtin_u32xor(var* local, gc& ngc) { var builtin_u32xor(context* ctx, gc* ngc) {
auto local = ctx->localr;
return var::num(static_cast<f64>( return var::num(static_cast<f64>(
static_cast<u32>(local[1].num()) ^ static_cast<u32>(local[1].num()) ^
static_cast<u32>(local[2].num()) static_cast<u32>(local[2].num())
)); ));
} }
var builtin_u32and(var* local, gc& ngc) { var builtin_u32and(context* ctx, gc* ngc) {
auto local = ctx->localr;
return var::num(static_cast<f64>( return var::num(static_cast<f64>(
static_cast<u32>(local[1].num()) & static_cast<u32>(local[1].num()) &
static_cast<u32>(local[2].num()) static_cast<u32>(local[2].num())
)); ));
} }
var builtin_u32or(var* local, gc& ngc) { var builtin_u32or(context* ctx, gc* ngc) {
auto local = ctx->localr;
return var::num(static_cast<f64>( return var::num(static_cast<f64>(
static_cast<u32>(local[1].num()) | static_cast<u32>(local[1].num()) |
static_cast<u32>(local[2].num()) static_cast<u32>(local[2].num())
)); ));
} }
var builtin_u32nand(var* local, gc& ngc) { var builtin_u32nand(context* ctx, gc* ngc) {
auto local = ctx->localr;
return var::num(static_cast<f64>(~( return var::num(static_cast<f64>(~(
static_cast<u32>(local[1].num()) & static_cast<u32>(local[1].num()) &
static_cast<u32>(local[2].num()) static_cast<u32>(local[2].num())
))); )));
} }
var builtin_u32not(var* local, gc& ngc) { var builtin_u32not(context* ctx, gc* ngc) {
return var::num(static_cast<f64>(~static_cast<u32>(local[1].num()))); return var::num(static_cast<f64>(
~static_cast<u32>(ctx->localr[1].num())
));
} }
var builtin_fld(var* local, gc& ngc) { var builtin_fld(context* ctx, gc* ngc) {
// bits.fld(s,0,3); // bits.fld(s,0,3);
// if s stores 10100010(162) // if s stores 10100010(162)
// will get 101(5) // will get 101(5)
var str = local[1]; auto local = ctx->localr;
var startbit = local[2]; auto str = local[1];
var length = local[3]; auto startbit = local[2];
auto length = local[3];
if (str.type!=vm_str || str.val.gcobj->unmutable) { if (str.type!=vm_str || str.val.gcobj->unmutable) {
return nas_err("fld", "\"str\" must be mutable string"); return nas_err("fld", "\"str\" must be mutable string");
} }
@ -62,14 +69,15 @@ var builtin_fld(var* local, gc& ngc) {
return var::num(static_cast<f64>(res)); return var::num(static_cast<f64>(res));
} }
var builtin_sfld(var* local, gc& ngc) { var builtin_sfld(context* ctx, gc* ngc) {
// bits.sfld(s,0,3); // bits.sfld(s,0,3);
// if s stores 10100010(162) // if s stores 10100010(162)
// will get 101(5) then this will be signed extended to // will get 101(5) then this will be signed extended to
// 11111101(-3) // 11111101(-3)
var str = local[1]; auto local = ctx->localr;
var startbit = local[2]; auto str = local[1];
var length = local[3]; auto startbit = local[2];
auto length = local[3];
if (str.type!=vm_str || str.val.gcobj->unmutable) { if (str.type!=vm_str || str.val.gcobj->unmutable) {
return nas_err("sfld", "\"str\" must be mutable string"); return nas_err("sfld", "\"str\" must be mutable string");
} }
@ -94,15 +102,16 @@ var builtin_sfld(var* local, gc& ngc) {
return var::num(static_cast<f64>(static_cast<i32>(res))); return var::num(static_cast<f64>(static_cast<i32>(res)));
} }
var builtin_setfld(var* local, gc& ngc) { var builtin_setfld(context* ctx, gc* ngc) {
// bits.setfld(s,0,8,69); // bits.setfld(s,0,8,69);
// set 01000101(69) to string will get this: // set 01000101(69) to string will get this:
// 10100010(162) // 10100010(162)
// so s[0]=162 // so s[0]=162
var str = local[1]; auto local = ctx->localr;
var startbit = local[2]; auto str = local[1];
var length = local[3]; auto startbit = local[2];
var value = local[4]; auto length = local[3];
auto value = local[4];
if (str.type!=vm_str || str.val.gcobj->unmutable) { if (str.type!=vm_str || str.val.gcobj->unmutable) {
return nas_err("setfld", "\"str\" must be mutable string"); return nas_err("setfld", "\"str\" must be mutable string");
} }
@ -126,12 +135,12 @@ var builtin_setfld(var* local, gc& ngc) {
return nil; return nil;
} }
var builtin_buf(var* local, gc& ngc) { var builtin_buf(context* ctx, gc* ngc) {
var length = local[1]; var length = ctx->localr[1];
if (length.type!=vm_num || length.num()<=0) { if (length.type!=vm_num || length.num()<=0) {
return nas_err("buf", "\"len\" must be number greater than 0"); return nas_err("buf", "\"len\" must be number greater than 0");
} }
var str = ngc.alloc(vm_str); var str = ngc->alloc(vm_str);
auto& s = str.str(); auto& s = str.str();
s.resize(length.num(), '\0'); s.resize(length.num(), '\0');
return str; return str;

View File

@ -6,15 +6,15 @@
namespace nasal { namespace nasal {
var builtin_u32xor(var*, gc&); var builtin_u32xor(context*, gc*);
var builtin_u32and(var*, gc&); var builtin_u32and(context*, gc*);
var builtin_u32or(var*, gc&); var builtin_u32or(context*, gc*);
var builtin_u32nand(var*, gc&); var builtin_u32nand(context*, gc*);
var builtin_u32not(var*, gc&); var builtin_u32not(context*, gc*);
var builtin_fld(var*, gc&); var builtin_fld(context*, gc*);
var builtin_sfld(var*, gc&); var builtin_sfld(context*, gc*);
var builtin_setfld(var*, gc&); var builtin_setfld(context*, gc*);
var builtin_buf(var*, gc&); var builtin_buf(context*, gc*);
extern nasal_builtin_table bits_native[]; extern nasal_builtin_table bits_native[];

View File

@ -2,7 +2,8 @@
namespace nasal { namespace nasal {
var builtin_cocreate(var* local, gc& ngc) { var builtin_cocreate(context* ctx, gc* ngc) {
// ```
// +-------------+ // +-------------+
// | old pc | <- top[0] // | old pc | <- top[0]
// +-------------+ // +-------------+
@ -15,69 +16,73 @@ var builtin_cocreate(var* local, gc& ngc) {
// +-------------+ <- local pointer stored in localr // +-------------+ <- local pointer stored in localr
// | old funcr | <- old function stored in funcr // | old funcr | <- old function stored in funcr
// +-------------+ // +-------------+
var func = local[1]; // ```
if (func.type!=vm_func) { auto coroutine_function = ctx->localr[1];
if (coroutine_function.type!=vm_func) {
return nas_err( return nas_err(
"coroutine::create", "coroutine::create",
"must use a function to create coroutine" "must use a function to create coroutine"
); );
} }
if (ngc.cort) { if (ngc->cort) {
return nas_err( return nas_err(
"coroutine::create", "coroutine::create",
"cannot create another coroutine in a coroutine" "cannot create another coroutine in a coroutine"
); );
} }
var co = ngc.alloc(vm_co); auto coroutine_object = ngc->alloc(vm_co);
nas_co& cort = co.co(); auto& coroutine = coroutine_object.co();
cort.ctx.pc = func.func().entry-1; coroutine.ctx.pc = coroutine_function.func().entry-1;
coroutine.ctx.top[0] = nil;
coroutine.ctx.localr = coroutine.ctx.top+1;
coroutine.ctx.top = coroutine.ctx.localr +
coroutine_function.func().local_size;
coroutine.ctx.localr[0] = coroutine_function.func().local[0];
cort.ctx.top[0] = nil;
cort.ctx.localr = cort.ctx.top+1;
cort.ctx.top = cort.ctx.localr+func.func().local_size;
cort.ctx.localr[0] = func.func().local[0];
// store old upvalr on stack // store old upvalr on stack
cort.ctx.top[0] = nil; coroutine.ctx.top[0] = nil;
cort.ctx.top++; coroutine.ctx.top++;
// store old localr on stack // store old localr on stack
cort.ctx.top[0] = var::addr((var*)nullptr); coroutine.ctx.top[0] = var::addr((var*)nullptr);
cort.ctx.top++; coroutine.ctx.top++;
// store old pc on stack // store old pc on stack
// set to zero to make op_ret recognizing this as coroutine function // set to zero to make op_ret recognizing this as coroutine function
cort.ctx.top[0] = var::ret(0); coroutine.ctx.top[0] = var::ret(0);
// make sure the coroutine function can use correct upvalues // make sure the coroutine function can use correct upvalues
cort.ctx.funcr = func; coroutine.ctx.funcr = coroutine_function;
cort.status = nas_co::status::suspended; coroutine.status = nas_co::status::suspended;
return co; return coroutine_object;
} }
var builtin_coresume(var* local, gc& ngc) { var builtin_coresume(context* ctx, gc* ngc) {
if (ngc.cort) { if (ngc->cort) {
return nas_err( return nas_err(
"coroutine::resume", "coroutine::resume",
"cannot start another coroutine when one is running" "cannot start another coroutine when one is running"
); );
} }
var co = local[1]; auto main_local_frame = ctx->localr;
// return nil if is not a coroutine object auto coroutine_object = main_local_frame[1];
if (co.type!=vm_co) { // return nil if is not a coroutine object or coroutine exited
return nil; if (coroutine_object.type!=vm_co ||
} coroutine_object.co().status==nas_co::status::dead) {
// cannot resume a dead coroutine
if (co.co().status==nas_co::status::dead) {
return nil; return nil;
} }
// change to coroutine context // change to coroutine context
ngc.ctxchg(co.co()); ngc->ctxchg(coroutine_object.co());
// fetch coroutine's stack top and return // fetch coroutine's stack top and return
// then coroutine's stack top will catch this return value
// so the coroutine's stack top in fact is not changed // so the coroutine's stack top in fact is not changed
if (ngc.running_context->top[0].type==vm_ret) { if (ngc->running_context->top[0].type==vm_ret) {
// when first calling this coroutine, the stack top must be vm_ret // when first calling this coroutine, the stack top must be vm_ret
return ngc.running_context->top[0]; return ngc->running_context->top[0];
} }
// after first calling the coroutine, each time coroutine.yield triggered // after first calling the coroutine, each time coroutine.yield triggered
@ -87,39 +92,41 @@ var builtin_coresume(var* local, gc& ngc) {
// the coroutine seems like coroutine.yield returns the value // the coroutine seems like coroutine.yield returns the value
// but in fact coroutine.yield stop the coroutine // but in fact coroutine.yield stop the coroutine
// until main context calls the coroutine.resume // until main context calls the coroutine.resume
return local[2]; return main_local_frame[2];
} }
var builtin_coyield(var* local, gc& ngc) { var builtin_coyield(context* ctx, gc* ngc) {
if (!ngc.cort) { if (!ngc->cort) {
return nas_err("coroutine::yield", "no coroutine is running"); return nas_err("coroutine::yield", "no coroutine is running");
} }
// get coroutine local frame
auto coroutine_local_frame = ctx->localr;
// vm context will set to main context
ngc->ctxreserve();
// this will set to main stack top
ngc.ctxreserve();
// then this will return value to main's stack top[0] // then this will return value to main's stack top[0]
// the procedure seems like coroutine.resume returns the value // the procedure seems like coroutine.resume returns the value
// but in fact coroutine.resume stop the main context // but in fact coroutine.resume stop the main context
// until coroutine calls the coroutine.yield // until coroutine calls the coroutine.yield
return local[1]; return coroutine_local_frame[1];
} }
var builtin_costatus(var* local, gc& ngc) { var builtin_costatus(context* ctx, gc* ngc) {
var co = local[1]; auto coroutine_object = ctx->localr[1];
if (co.type!=vm_co) { if (coroutine_object.type!=vm_co) {
return ngc.newstr("error"); return ngc->newstr("error");
} }
switch(co.co().status) { switch(coroutine_object.co().status) {
case nas_co::status::suspended: return ngc.newstr("suspended"); case nas_co::status::suspended: return ngc->newstr("suspended");
case nas_co::status::running: return ngc.newstr("running"); case nas_co::status::running: return ngc->newstr("running");
case nas_co::status::dead: return ngc.newstr("dead"); case nas_co::status::dead: return ngc->newstr("dead");
} }
return nil; return nil;
} }
var builtin_corun(var* local, gc& ngc) { var builtin_corun(context* ctx, gc* ngc) {
return ngc.cort? one:zero; return ngc->cort? one:zero;
} }
nasal_builtin_table coroutine_native[] = { nasal_builtin_table coroutine_native[] = {

View File

@ -6,11 +6,11 @@
namespace nasal { namespace nasal {
var builtin_cocreate(var*, gc&); var builtin_cocreate(context*, gc*);
var builtin_coresume(var*, gc&); var builtin_coresume(context*, gc*);
var builtin_coyield(var*, gc&); var builtin_coyield(context*, gc*);
var builtin_costatus(var*, gc&); var builtin_costatus(context*, gc*);
var builtin_corun(var*, gc&); var builtin_corun(context*, gc*);
extern nasal_builtin_table coroutine_native[]; extern nasal_builtin_table coroutine_native[];

View File

@ -15,8 +15,8 @@ void dylib_destructor(void* ptr) {
void func_addr_destructor(void* ptr) {} void func_addr_destructor(void* ptr) {}
var builtin_dlopen(var* local, gc& ngc) { var builtin_dlopen(context* ctx, gc* ngc) {
var dlname = local[1]; auto dlname = ctx->localr[1];
if (dlname.type!=vm_str) { if (dlname.type!=vm_str) {
return nas_err("dlopen", "\"libname\" must be string"); return nas_err("dlopen", "\"libname\" must be string");
} }
@ -35,8 +35,8 @@ var builtin_dlopen(var* local, gc& ngc) {
if (!ptr) { if (!ptr) {
return nas_err("dlopen", "cannot open dynamic lib <"+dlname.str()+">"); return nas_err("dlopen", "cannot open dynamic lib <"+dlname.str()+">");
} }
var ret = ngc.temp = ngc.alloc(vm_hash); auto ret = ngc->temp = ngc->alloc(vm_hash);
var lib = ngc.alloc(vm_obj); auto lib = ngc->alloc(vm_obj);
lib.obj().set(dylib_type_name, dylib_destructor, ptr); lib.obj().set(dylib_type_name, dylib_destructor, ptr);
ret.hash().elems["lib"] = lib; ret.hash().elems["lib"] = lib;
@ -52,23 +52,23 @@ var builtin_dlopen(var* local, gc& ngc) {
return nas_err("dlopen", "cannot find <get> function"); return nas_err("dlopen", "cannot find <get> function");
} }
// get function pointer by name // get function pointer by name
module_func_info* tbl = reinterpret_cast<get_func_ptr>(func)(); auto tbl = reinterpret_cast<get_func_ptr>(func)();
if (!tbl) { if (!tbl) {
return nas_err("dlopen", "failed to get module functions"); return nas_err("dlopen", "failed to get module functions");
} }
for(u32 i = 0; tbl[i].name; ++i) { for(u32 i = 0; tbl[i].name; ++i) {
void* p = (void*)tbl[i].fd; void* p = (void*)tbl[i].fd;
var tmp = ngc.alloc(vm_obj); var tmp = ngc->alloc(vm_obj);
tmp.obj().set(func_addr_type_name, func_addr_destructor, p); tmp.obj().set(func_addr_type_name, func_addr_destructor, p);
ret.hash().elems[tbl[i].name] = tmp; ret.hash().elems[tbl[i].name] = tmp;
} }
ngc.temp = nil; ngc->temp = nil;
return ret; return ret;
} }
var builtin_dlclose(var* local, gc& ngc) { var builtin_dlclose(context* ctx, gc* ngc) {
var libptr = local[1]; auto libptr = ctx->localr[1];
if (!libptr.object_check(dylib_type_name)) { if (!libptr.object_check(dylib_type_name)) {
return nas_err("dlclose", "\"lib\" is not a valid dynamic lib"); return nas_err("dlclose", "\"lib\" is not a valid dynamic lib");
} }
@ -76,9 +76,10 @@ var builtin_dlclose(var* local, gc& ngc) {
return nil; return nil;
} }
var builtin_dlcallv(var* local, gc& ngc) { var builtin_dlcallv(context* ctx, gc* ngc) {
var fp = local[1]; auto local = ctx->localr;
var args = local[2]; auto fp = local[1];
auto args = local[2];
if (!fp.object_check(func_addr_type_name)) { if (!fp.object_check(func_addr_type_name)) {
return nas_err("dlcall", "\"ptr\" is not a valid function pointer"); return nas_err("dlcall", "\"ptr\" is not a valid function pointer");
} }
@ -86,23 +87,24 @@ var builtin_dlcallv(var* local, gc& ngc) {
return reinterpret_cast<module_func>(fp.obj().pointer)( return reinterpret_cast<module_func>(fp.obj().pointer)(
vec.data(), vec.data(),
vec.size(), vec.size(),
&ngc ngc
); );
} }
var builtin_dlcall(var* local, gc& ngc) { var builtin_dlcall(context* ctx, gc* ngc) {
auto local = ctx->localr;
var fp = local[1]; var fp = local[1];
if (!fp.object_check(func_addr_type_name)) { if (!fp.object_check(func_addr_type_name)) {
return nas_err("dlcall", "\"ptr\" is not a valid function pointer"); return nas_err("dlcall", "\"ptr\" is not a valid function pointer");
} }
var* local_frame_start = local+2; var* local_frame_start = local+2;
usize local_frame_size = ngc.running_context->top-local_frame_start; usize local_frame_size = ngc->running_context->top-local_frame_start;
// arguments' stored place begins at local +2 // arguments' stored place begins at local +2
return reinterpret_cast<module_func>(fp.obj().pointer)( return reinterpret_cast<module_func>(fp.obj().pointer)(
local_frame_start, local_frame_start,
local_frame_size, local_frame_size,
&ngc ngc
); );
} }

View File

@ -16,10 +16,10 @@ namespace nasal {
void dylib_destructor(void*); void dylib_destructor(void*);
void func_addr_destructor(void*); void func_addr_destructor(void*);
var builtin_dlopen(var*, gc&); var builtin_dlopen(context*, gc*);
var builtin_dlclose(var*, gc&); var builtin_dlclose(context*, gc*);
var builtin_dlcallv(var*, gc&); var builtin_dlcallv(context*, gc*);
var builtin_dlcall(var*, gc&); var builtin_dlcall(context*, gc*);
extern nasal_builtin_table dylib_lib_native[]; extern nasal_builtin_table dylib_lib_native[];

View File

@ -4,9 +4,10 @@
namespace nasal { namespace nasal {
var builtin_logprint(var* local, gc& ngc) { var builtin_logprint(context* ctx, gc* ngc) {
var level = local[1]; auto local = ctx->localr;
var elems = local[2]; auto level = local[1];
auto elems = local[2];
if (elems.type!=vm_vec) { if (elems.type!=vm_vec) {
return nas_err("logprint", "received argument is not vector."); return nas_err("logprint", "received argument is not vector.");
} }

View File

@ -15,7 +15,7 @@ namespace nasal {
#define SG_DEV_ALERT 8 #define SG_DEV_ALERT 8
#define SG_MANDATORY_INFO 9 #define SG_MANDATORY_INFO 9
var builtin_logprint(var*, gc&); var builtin_logprint(context*, gc*);
extern nasal_builtin_table flight_gear_native[]; extern nasal_builtin_table flight_gear_native[];

View File

@ -11,8 +11,8 @@ void filehandle_destructor(void* ptr) {
fclose(static_cast<FILE*>(ptr)); fclose(static_cast<FILE*>(ptr));
} }
var builtin_readfile(var* local, gc& ngc) { var builtin_readfile(context* ctx, gc* ngc) {
var val = local[1]; auto val = ctx->localr[1];
if (val.type!=vm_str) { if (val.type!=vm_str) {
return nas_err("io::readfile", "\"filename\" must be string"); return nas_err("io::readfile", "\"filename\" must be string");
} }
@ -21,12 +21,13 @@ var builtin_readfile(var* local, gc& ngc) {
if (!in.fail()) { if (!in.fail()) {
rd << in.rdbuf(); rd << in.rdbuf();
} }
return ngc.newstr(rd.str()); return ngc->newstr(rd.str());
} }
var builtin_fout(var* local, gc& ngc) { var builtin_fout(context* ctx, gc* ngc) {
var val = local[1]; auto local = ctx->localr;
var str = local[2]; auto val = local[1];
auto str = local[2];
if (val.type!=vm_str) { if (val.type!=vm_str) {
return nas_err("io::fout", "\"filename\" must be string"); return nas_err("io::fout", "\"filename\" must be string");
} }
@ -38,16 +39,18 @@ var builtin_fout(var* local, gc& ngc) {
return nil; return nil;
} }
var builtin_exists(var* local, gc& ngc) { var builtin_exists(context* ctx, gc* ngc) {
auto local = ctx->localr;
if (local[1].type!=vm_str) { if (local[1].type!=vm_str) {
return zero; return zero;
} }
return access(local[1].str().c_str(), F_OK)!=-1? one:zero; return access(local[1].str().c_str(), F_OK)!=-1? one:zero;
} }
var builtin_open(var* local, gc& ngc) { var builtin_open(context* ctx, gc* ngc) {
var name = local[1]; auto local = ctx->localr;
var mode = local[2]; auto name = local[1];
auto mode = local[2];
if (name.type!=vm_str) { if (name.type!=vm_str) {
return nas_err("open", "\"filename\" must be string"); return nas_err("open", "\"filename\" must be string");
} }
@ -58,13 +61,13 @@ var builtin_open(var* local, gc& ngc) {
if (!res) { if (!res) {
return nas_err("open", "failed to open file <"+name.str()+">"); return nas_err("open", "failed to open file <"+name.str()+">");
} }
var ret = ngc.alloc(vm_obj); var ret = ngc->alloc(vm_obj);
ret.obj().set(file_type_name, filehandle_destructor, res); ret.obj().set(file_type_name, filehandle_destructor, res);
return ret; return ret;
} }
var builtin_close(var* local, gc& ngc) { var builtin_close(context* ctx, gc* ngc) {
var fd = local[1]; var fd = ctx->localr[1];
if (!fd.object_check(file_type_name)) { if (!fd.object_check(file_type_name)) {
return nas_err("close", "not a valid filehandle"); return nas_err("close", "not a valid filehandle");
} }
@ -72,10 +75,11 @@ var builtin_close(var* local, gc& ngc) {
return nil; return nil;
} }
var builtin_read(var* local, gc& ngc) { var builtin_read(context* ctx, gc* ngc) {
var fd = local[1]; auto local = ctx->localr;
var buf = local[2]; auto fd = local[1];
var len = local[3]; auto buf = local[2];
auto len = local[3];
if (!fd.object_check(file_type_name)) { if (!fd.object_check(file_type_name)) {
return nas_err("read", "not a valid filehandle"); return nas_err("read", "not a valid filehandle");
} }
@ -99,9 +103,10 @@ var builtin_read(var* local, gc& ngc) {
return var::num(res); return var::num(res);
} }
var builtin_write(var* local, gc& ngc) { var builtin_write(context* ctx, gc* ngc) {
var fd = local[1]; auto local = ctx->localr;
var str = local[2]; auto fd = local[1];
auto str = local[2];
if (!fd.object_check(file_type_name)) { if (!fd.object_check(file_type_name)) {
return nas_err("write", "not a valid filehandle"); return nas_err("write", "not a valid filehandle");
} }
@ -116,10 +121,11 @@ var builtin_write(var* local, gc& ngc) {
))); )));
} }
var builtin_seek(var* local, gc& ngc) { var builtin_seek(context* ctx, gc* ngc) {
var fd = local[1]; auto local = ctx->localr;
var pos = local[2]; auto fd = local[1];
var whence = local[3]; auto pos = local[2];
auto whence = local[3];
if (!fd.object_check(file_type_name)) { if (!fd.object_check(file_type_name)) {
return nas_err("seek", "not a valid filehandle"); return nas_err("seek", "not a valid filehandle");
} }
@ -130,8 +136,8 @@ var builtin_seek(var* local, gc& ngc) {
))); )));
} }
var builtin_tell(var* local, gc& ngc) { var builtin_tell(context* ctx, gc* ngc) {
var fd = local[1]; auto fd = ctx->localr[1];
if (!fd.object_check(file_type_name)) { if (!fd.object_check(file_type_name)) {
return nas_err("tell", "not a valid filehandle"); return nas_err("tell", "not a valid filehandle");
} }
@ -140,12 +146,12 @@ var builtin_tell(var* local, gc& ngc) {
)); ));
} }
var builtin_readln(var* local, gc& ngc) { var builtin_readln(context* ctx, gc* ngc) {
var fd = local[1]; auto fd = ctx->localr[1];
if (!fd.object_check(file_type_name)) { if (!fd.object_check(file_type_name)) {
return nas_err("readln", "not a valid filehandle"); return nas_err("readln", "not a valid filehandle");
} }
var str = ngc.alloc(vm_str); auto str = ngc->alloc(vm_str);
char c; char c;
while((c = fgetc(static_cast<FILE*>(fd.obj().pointer)))!=EOF) { while((c = fgetc(static_cast<FILE*>(fd.obj().pointer)))!=EOF) {
if (c=='\r') { if (c=='\r') {
@ -162,16 +168,16 @@ var builtin_readln(var* local, gc& ngc) {
return nil; return nil;
} }
var builtin_stat(var* local, gc& ngc) { var builtin_stat(context* ctx, gc* ngc) {
var name = local[1]; auto name = ctx->localr[1];
if (name.type!=vm_str) { if (name.type!=vm_str) {
return nas_err("stat", "\"filename\" must be string"); return nas_err("stat", "\"filename\" must be string");
} }
struct stat buf; struct stat buf;
if (stat(name.str().c_str(),&buf)<0) { if (stat(name.str().c_str(), &buf)<0) {
return nas_err("stat", "failed to open file <"+name.str()+">"); return nas_err("stat", "failed to open file <"+name.str()+">");
} }
var ret = ngc.alloc(vm_vec); auto ret = ngc->alloc(vm_vec);
ret.vec().elems = { ret.vec().elems = {
var::num(static_cast<f64>(buf.st_dev)), var::num(static_cast<f64>(buf.st_dev)),
var::num(static_cast<f64>(buf.st_ino)), var::num(static_cast<f64>(buf.st_ino)),
@ -188,8 +194,8 @@ var builtin_stat(var* local, gc& ngc) {
return ret; return ret;
} }
var builtin_eof(var* local, gc& ngc) { var builtin_eof(context* ctx, gc* ngc) {
var fd = local[1]; auto fd = ctx->localr[1];
if (!fd.object_check(file_type_name)) { if (!fd.object_check(file_type_name)) {
return nas_err("readln", "not a valid filehandle"); return nas_err("readln", "not a valid filehandle");
} }

View File

@ -20,18 +20,18 @@ namespace nasal {
void filehandle_destructor(void*); void filehandle_destructor(void*);
var builtin_readfile(var*, gc&); var builtin_readfile(context*, gc*);
var builtin_fout(var*, gc&); var builtin_fout(context*, gc*);
var builtin_exists(var*, gc&); var builtin_exists(context*, gc*);
var builtin_open(var*, gc&); var builtin_open(context*, gc*);
var builtin_close(var*, gc&); var builtin_close(context*, gc*);
var builtin_read(var*, gc&); var builtin_read(context*, gc*);
var builtin_write(var*, gc&); var builtin_write(context*, gc*);
var builtin_seek(var*, gc&); var builtin_seek(context*, gc*);
var builtin_tell(var*, gc&); var builtin_tell(context*, gc*);
var builtin_readln(var*, gc&); var builtin_readln(context*, gc*);
var builtin_stat(var*, gc&); var builtin_stat(context*, gc*);
var builtin_eof(var*, gc&); var builtin_eof(context*, gc*);
extern nasal_builtin_table io_lib_native[]; extern nasal_builtin_table io_lib_native[];

View File

@ -2,61 +2,61 @@
namespace nasal { namespace nasal {
var builtin_pow(var* local, gc& ngc) { var builtin_pow(context* ctx, gc* ngc) {
var x = local[1]; auto x = ctx->localr[1];
var y = local[2]; auto y = ctx->localr[2];
if (x.type!=vm_num || y.type!=vm_num) { if (x.type!=vm_num || y.type!=vm_num) {
return var::num(std::nan("")); return var::num(std::nan(""));
} }
return var::num(std::pow(x.num(), y.num())); return var::num(std::pow(x.num(), y.num()));
} }
var builtin_sin(var* local, gc& ngc) { var builtin_sin(context* ctx, gc* ngc) {
var val = local[1]; auto val = ctx->localr[1];
return var::num(val.type==vm_num? sin(val.num()):std::nan("")); return var::num(val.type==vm_num? sin(val.num()):std::nan(""));
} }
var builtin_cos(var* local, gc& ngc) { var builtin_cos(context* ctx, gc* ngc) {
var val = local[1]; auto val = ctx->localr[1];
return var::num(val.type==vm_num? cos(val.num()):std::nan("")); return var::num(val.type==vm_num? cos(val.num()):std::nan(""));
} }
var builtin_tan(var* local, gc& ngc) { var builtin_tan(context* ctx, gc* ngc) {
var val = local[1]; auto val = ctx->localr[1];
return var::num(val.type==vm_num? tan(val.num()):std::nan("")); return var::num(val.type==vm_num? tan(val.num()):std::nan(""));
} }
var builtin_exp(var* local, gc& ngc) { var builtin_exp(context* ctx, gc* ngc) {
var val = local[1]; auto val = ctx->localr[1];
return var::num(val.type==vm_num? exp(val.num()):std::nan("")); return var::num(val.type==vm_num? exp(val.num()):std::nan(""));
} }
var builtin_lg(var* local, gc& ngc) { var builtin_lg(context* ctx, gc* ngc) {
var val = local[1]; auto val = ctx->localr[1];
return var::num(val.type==vm_num? log(val.num())/log(10.0):std::nan("")); return var::num(val.type==vm_num? log(val.num())/log(10.0):std::nan(""));
} }
var builtin_ln(var* local, gc& ngc) { var builtin_ln(context* ctx, gc* ngc) {
var val = local[1]; auto val = ctx->localr[1];
return var::num(val.type==vm_num? log(val.num()):std::nan("")); return var::num(val.type==vm_num? log(val.num()):std::nan(""));
} }
var builtin_sqrt(var* local, gc& ngc) { var builtin_sqrt(context* ctx, gc* ngc) {
var val = local[1]; auto val = ctx->localr[1];
return var::num(val.type==vm_num? sqrt(val.num()):std::nan("")); return var::num(val.type==vm_num? sqrt(val.num()):std::nan(""));
} }
var builtin_atan2(var* local, gc& ngc) { var builtin_atan2(context* ctx, gc* ngc) {
var x = local[1]; auto x = ctx->localr[1];
var y = local[2]; auto y = ctx->localr[2];
if (x.type!=vm_num || y.type!=vm_num) { if (x.type!=vm_num || y.type!=vm_num) {
return var::num(std::nan("")); return var::num(std::nan(""));
} }
return var::num(atan2(y.num(), x.num())); return var::num(atan2(y.num(), x.num()));
} }
var builtin_isnan(var* local, gc& ngc) { var builtin_isnan(context* ctx, gc* ngc) {
var x = local[1]; auto x = ctx->localr[1];
return (x.type==vm_num && std::isnan(x.num()))? one:zero; return (x.type==vm_num && std::isnan(x.num()))? one:zero;
} }

View File

@ -6,16 +6,16 @@
namespace nasal { namespace nasal {
var builtin_pow(var*, gc&); var builtin_pow(context*, gc*);
var builtin_sin(var*, gc&); var builtin_sin(context*, gc*);
var builtin_cos(var*, gc&); var builtin_cos(context*, gc*);
var builtin_tan(var*, gc&); var builtin_tan(context*, gc*);
var builtin_exp(var*, gc&); var builtin_exp(context*, gc*);
var builtin_lg(var*, gc&); var builtin_lg(context*, gc*);
var builtin_ln(var*, gc&); var builtin_ln(context*, gc*);
var builtin_sqrt(var*, gc&); var builtin_sqrt(context*, gc*);
var builtin_atan2(var*, gc&); var builtin_atan2(context*, gc*);
var builtin_isnan(var*, gc&); var builtin_isnan(context*, gc*);
extern nasal_builtin_table math_lib_native[]; extern nasal_builtin_table math_lib_native[];

View File

@ -3,33 +3,34 @@
namespace nasal { namespace nasal {
var builtin_print(var* local, gc& ngc) { var builtin_print(context* ctx, gc* ngc) {
for(auto& i : local[1].vec().elems) { for(auto& i : ctx->localr[1].vec().elems) {
std::cout << i; std::cout << i;
} }
std::cout << std::flush; std::cout << std::flush;
return nil; return nil;
} }
var builtin_println(var* local, gc& ngc) { var builtin_println(context* ctx, gc* ngc) {
for(auto& i : local[1].vec().elems) { for(auto& i : ctx->localr[1].vec().elems) {
std::cout << i; std::cout << i;
} }
std::cout << std::endl; std::cout << std::endl;
return nil; return nil;
} }
var builtin_exit(var* local, gc& ngc) { var builtin_exit(context* ctx, gc* ngc) {
std::exit(local[1].num()); std::exit(ctx->localr[1].num());
return nil; return nil;
} }
var builtin_abort(var* local, gc& ngc) { var builtin_abort(context* ctx, gc* ngc) {
std::abort(); std::abort();
return nil; return nil;
} }
var builtin_append(var* local, gc& ngc) { var builtin_append(context* ctx, gc* ngc) {
auto local = ctx->localr;
var vec = local[1]; var vec = local[1];
var elem = local[2]; var elem = local[2];
if (vec.type!=vm_vec) { if (vec.type!=vm_vec) {
@ -42,7 +43,8 @@ var builtin_append(var* local, gc& ngc) {
return nil; return nil;
} }
var builtin_setsize(var* local, gc& ngc) { var builtin_setsize(context* ctx, gc* ngc) {
auto local = ctx->localr;
var vec = local[1]; var vec = local[1];
var size = local[2]; var size = local[2];
if (vec.type!=vm_vec) { if (vec.type!=vm_vec) {
@ -55,17 +57,18 @@ var builtin_setsize(var* local, gc& ngc) {
return nil; return nil;
} }
var builtin_system(var* local, gc& ngc) { var builtin_system(context* ctx, gc* ngc) {
var str = local[1]; auto str = ctx->localr[1];
if (str.type!=vm_str) { if (str.type!=vm_str) {
return var::num(-1); return var::num(-1);
} }
return var::num(static_cast<f64>(system(str.str().c_str()))); return var::num(static_cast<f64>(system(str.str().c_str())));
} }
var builtin_input(var* local, gc& ngc) { var builtin_input(context* ctx, gc* ngc) {
auto local = ctx->localr;
var end = local[1]; var end = local[1];
var ret = ngc.alloc(vm_str); var ret = ngc->alloc(vm_str);
if (end.type!=vm_str || end.str().length()>1 || !end.str().length()) { if (end.type!=vm_str || end.str().length()>1 || !end.str().length()) {
std::cin >> ret.str(); std::cin >> ret.str();
} else { } else {
@ -74,7 +77,8 @@ var builtin_input(var* local, gc& ngc) {
return ret; return ret;
} }
var builtin_split(var* local, gc& ngc) { var builtin_split(context* ctx, gc* ngc) {
auto local = ctx->localr;
var delimeter = local[1]; var delimeter = local[1];
var str = local[2]; var str = local[2];
if (delimeter.type!=vm_str) { if (delimeter.type!=vm_str) {
@ -87,34 +91,34 @@ var builtin_split(var* local, gc& ngc) {
const auto& s = str.str(); const auto& s = str.str();
// avoid being sweeped // avoid being sweeped
var res = ngc.temp = ngc.alloc(vm_vec); auto res = ngc->temp = ngc->alloc(vm_vec);
auto& vec = res.vec().elems; auto& vec = res.vec().elems;
if (!deli.length()) { if (!deli.length()) {
for(auto i : s) { for(auto i : s) {
vec.push_back(ngc.newstr(i)); vec.push_back(ngc->newstr(i));
} }
ngc.temp = nil; ngc->temp = nil;
return res; return res;
} }
usize last = 0; usize last = 0;
usize pos = s.find(deli, 0); usize pos = s.find(deli, 0);
while(pos!=std::string::npos) { while(pos!=std::string::npos) {
if (pos>last) { if (pos>last) {
vec.push_back(ngc.newstr(s.substr(last, pos-last))); vec.push_back(ngc->newstr(s.substr(last, pos-last)));
} }
last = pos+deli.length(); last = pos+deli.length();
pos = s.find(deli, last); pos = s.find(deli, last);
} }
if (last!=s.length()) { if (last!=s.length()) {
vec.push_back(ngc.newstr(s.substr(last))); vec.push_back(ngc->newstr(s.substr(last)));
} }
ngc.temp = nil; ngc->temp = nil;
return res; return res;
} }
var builtin_rand(var* local, gc& ngc) { var builtin_rand(context* ctx, gc* ngc) {
var val = local[1]; auto val = ctx->localr[1];
if (val.type!=vm_num && val.type!=vm_nil) { if (val.type!=vm_num && val.type!=vm_nil) {
return nas_err("rand", "\"seed\" must be nil or number"); return nas_err("rand", "\"seed\" must be nil or number");
} }
@ -129,65 +133,65 @@ var builtin_rand(var* local, gc& ngc) {
return var::num(num); return var::num(num);
} }
var builtin_id(var* local, gc& ngc) { var builtin_id(context* ctx, gc* ngc) {
var val = local[1]; auto val = ctx->localr[1];
std::stringstream ss; std::stringstream ss;
ss << "0"; ss << "0";
if (val.type>vm_num) { if (val.type>vm_num) {
ss << "x" << std::hex; ss << "x" << std::hex;
ss << reinterpret_cast<u64>(val.val.gcobj) << std::dec; ss << reinterpret_cast<u64>(val.val.gcobj) << std::dec;
} }
return ngc.newstr(ss.str()); return ngc->newstr(ss.str());
} }
var builtin_int(var* local, gc& ngc) { var builtin_int(context* ctx, gc* ngc) {
var val = local[1]; auto val = ctx->localr[1];
if (val.type!=vm_num && val.type!=vm_str) { if (val.type!=vm_num && val.type!=vm_str) {
return nil; return nil;
} }
return var::num(static_cast<f64>(static_cast<i32>(val.to_num()))); return var::num(static_cast<f64>(static_cast<i32>(val.to_num())));
} }
var builtin_floor(var* local, gc& ngc) { var builtin_floor(context* ctx, gc* ngc) {
var val = local[1]; auto value = ctx->localr[1];
return var::num(std::floor(val.num())); return var::num(std::floor(value.num()));
} }
var builtin_num(var* local, gc& ngc) { var builtin_num(context* ctx, gc* ngc) {
var val = local[1]; auto val = ctx->localr[1];
if (val.type==vm_num) { if (val.type==vm_num) {
return val; return val;
} }
if (val.type!=vm_str) { if (val.type!=vm_str) {
return nil; return nil;
} }
f64 res = val.to_num(); auto res = val.to_num();
if (std::isnan(res)) { if (std::isnan(res)) {
return nil; return nil;
} }
return var::num(res); return var::num(res);
} }
var builtin_pop(var* local, gc& ngc) { var builtin_pop(context* ctx, gc* ngc) {
var val = local[1]; auto val = ctx->localr[1];
if (val.type!=vm_vec) { if (val.type!=vm_vec) {
return nas_err("pop", "\"vec\" must be vector"); return nas_err("pop", "\"vec\" must be vector");
} }
auto& vec = val.vec().elems; auto& vec = val.vec().elems;
if (vec.size()) { if (vec.size()) {
var tmp = vec.back(); auto tmp = vec.back();
vec.pop_back(); vec.pop_back();
return tmp; return tmp;
} }
return nil; return nil;
} }
var builtin_str(var* local, gc& ngc) { var builtin_str(context* ctx, gc* ngc) {
return ngc.newstr(local[1].to_str()); return ngc->newstr(ctx->localr[1].to_str());
} }
var builtin_size(var* local, gc& ngc) { var builtin_size(context* ctx, gc* ngc) {
var val = local[1]; auto val = ctx->localr[1];
f64 num = 0; f64 num = 0;
switch(val.type) { switch(val.type) {
case vm_num: num = val.num(); break; case vm_num: num = val.num(); break;
@ -199,16 +203,17 @@ var builtin_size(var* local, gc& ngc) {
return var::num(num); return var::num(num);
} }
var builtin_time(var* local, gc& ngc) { var builtin_time(context* ctx, gc* ngc) {
var val = local[1]; auto val = ctx->localr[1];
if (val.type!=vm_num) { if (val.type!=vm_num) {
return nas_err("time", "\"begin\" must be number"); return nas_err("time", "\"begin\" must be number");
} }
time_t begin = (time_t)val.num(); auto begin = static_cast<time_t>(val.num());
return var::num(static_cast<f64>(time(&begin))); return var::num(static_cast<f64>(time(&begin)));
} }
var builtin_contains(var* local, gc& ngc) { var builtin_contains(context* ctx, gc* ngc) {
auto local = ctx->localr;
var hash = local[1]; var hash = local[1];
var key = local[2]; var key = local[2];
if (hash.type!=vm_hash || key.type!=vm_str) { if (hash.type!=vm_hash || key.type!=vm_str) {
@ -217,7 +222,8 @@ var builtin_contains(var* local, gc& ngc) {
return hash.hash().elems.count(key.str())? one:zero; return hash.hash().elems.count(key.str())? one:zero;
} }
var builtin_delete(var* local, gc& ngc) { var builtin_delete(context* ctx, gc* ngc) {
auto local = ctx->localr;
var hash = local[1]; var hash = local[1];
var key = local[2]; var key = local[2];
if (hash.type!=vm_hash) { if (hash.type!=vm_hash) {
@ -232,32 +238,33 @@ var builtin_delete(var* local, gc& ngc) {
return nil; return nil;
} }
var builtin_keys(var* local, gc& ngc) { var builtin_keys(context* ctx, gc* ngc) {
var hash = local[1]; auto hash = ctx->localr[1];
if (hash.type!=vm_hash && hash.type!=vm_map) { if (hash.type!=vm_hash && hash.type!=vm_map) {
return nas_err("keys", "\"hash\" must be hash"); return nas_err("keys", "\"hash\" must be hash");
} }
// avoid being sweeped // avoid being sweeped
var res = ngc.temp = ngc.alloc(vm_vec); auto res = ngc->temp = ngc->alloc(vm_vec);
auto& vec = res.vec().elems; auto& vec = res.vec().elems;
if (hash.type==vm_hash) { if (hash.type==vm_hash) {
for(const auto& iter : hash.hash().elems) { for(const auto& iter : hash.hash().elems) {
vec.push_back(ngc.newstr(iter.first)); vec.push_back(ngc->newstr(iter.first));
} }
} else { } else {
for(const auto& iter : hash.map().mapper) { for(const auto& iter : hash.map().mapper) {
vec.push_back(ngc.newstr(iter.first)); vec.push_back(ngc->newstr(iter.first));
} }
} }
ngc.temp=nil; ngc->temp=nil;
return res; return res;
} }
var builtin_die(var* local, gc& ngc) { var builtin_die(context* ctx, gc* ngc) {
return nas_err("error", local[1].to_str()); return nas_err("error", ctx->localr[1].to_str());
} }
var builtin_find(var* local, gc& ngc) { var builtin_find(context* ctx, gc* ngc) {
auto local = ctx->localr;
var needle = local[1]; var needle = local[1];
var haystack = local[2]; var haystack = local[2];
usize pos = haystack.to_str().find(needle.to_str()); usize pos = haystack.to_str().find(needle.to_str());
@ -267,23 +274,24 @@ var builtin_find(var* local, gc& ngc) {
return var::num(static_cast<f64>(pos)); return var::num(static_cast<f64>(pos));
} }
var builtin_type(var* local, gc& ngc) { var builtin_type(context* ctx, gc* ngc) {
switch(local[1].type) { switch(ctx->localr[1].type) {
case vm_none: return ngc.newstr("undefined"); case vm_none: return ngc->newstr("undefined");
case vm_nil: return ngc.newstr("nil"); case vm_nil: return ngc->newstr("nil");
case vm_num: return ngc.newstr("num"); case vm_num: return ngc->newstr("num");
case vm_str: return ngc.newstr("str"); case vm_str: return ngc->newstr("str");
case vm_vec: return ngc.newstr("vec"); case vm_vec: return ngc->newstr("vec");
case vm_hash: return ngc.newstr("hash"); case vm_hash: return ngc->newstr("hash");
case vm_func: return ngc.newstr("func"); case vm_func: return ngc->newstr("func");
case vm_obj: return ngc.newstr("obj"); case vm_obj: return ngc->newstr("obj");
case vm_co: return ngc.newstr("coroutine"); case vm_co: return ngc->newstr("coroutine");
case vm_map: return ngc.newstr("namespace"); case vm_map: return ngc->newstr("namespace");
} }
return nil; return nil;
} }
var builtin_substr(var* local, gc& ngc) { var builtin_substr(context* ctx, gc* ngc) {
auto local = ctx->localr;
var str = local[1]; var str = local[1];
var beg = local[2]; var beg = local[2];
var len = local[3]; var len = local[3];
@ -301,10 +309,11 @@ var builtin_substr(var* local, gc& ngc) {
if (begin>=str.str().length()) { if (begin>=str.str().length()) {
return nas_err("susbtr", "begin index out of range: "+std::to_string(begin)); return nas_err("susbtr", "begin index out of range: "+std::to_string(begin));
} }
return ngc.newstr(str.str().substr(begin,length)); return ngc->newstr(str.str().substr(begin,length));
} }
var builtin_streq(var* local, gc& ngc) { var builtin_streq(context* ctx, gc* ngc) {
auto local = ctx->localr;
var a = local[1]; var a = local[1];
var b = local[2]; var b = local[2];
return var::num(static_cast<f64>( return var::num(static_cast<f64>(
@ -312,7 +321,8 @@ var builtin_streq(var* local, gc& ngc) {
)); ));
} }
var builtin_left(var* local, gc& ngc) { var builtin_left(context* ctx, gc* ngc) {
auto local = ctx->localr;
var str = local[1]; var str = local[1];
var len = local[2]; var len = local[2];
if (str.type!=vm_str) { if (str.type!=vm_str) {
@ -322,12 +332,13 @@ var builtin_left(var* local, gc& ngc) {
return nas_err("left", "\"length\" must be number"); return nas_err("left", "\"length\" must be number");
} }
if (len.num()<0) { if (len.num()<0) {
return ngc.newstr(""); return ngc->newstr("");
} }
return ngc.newstr(str.str().substr(0, len.num())); return ngc->newstr(str.str().substr(0, len.num()));
} }
var builtin_right(var* local, gc& ngc) { var builtin_right(context* ctx, gc* ngc) {
auto local = ctx->localr;
var str = local[1]; var str = local[1];
var len = local[2]; var len = local[2];
if (str.type!=vm_str) { if (str.type!=vm_str) {
@ -344,10 +355,11 @@ var builtin_right(var* local, gc& ngc) {
if (length<0) { if (length<0) {
length = 0; length = 0;
} }
return ngc.newstr(str.str().substr(srclen-length, srclen)); return ngc->newstr(str.str().substr(srclen-length, srclen));
} }
var builtin_cmp(var* local, gc& ngc) { var builtin_cmp(context* ctx, gc* ngc) {
auto local = ctx->localr;
var a = local[1]; var a = local[1];
var b = local[2]; var b = local[2];
if (a.type!=vm_str || b.type!=vm_str) { if (a.type!=vm_str || b.type!=vm_str) {
@ -359,7 +371,7 @@ var builtin_cmp(var* local, gc& ngc) {
))); )));
} }
var builtin_chr(var* local, gc& ngc) { var builtin_chr(context* ctx, gc* ngc) {
const char* extend[] = { const char* extend[] = {
""," ","","ƒ","","","","", ""," ","","ƒ","","","","",
"ˆ","","Š","","Œ"," ","Ž"," ", "ˆ","","Š","","Œ"," ","Ž"," ",
@ -378,25 +390,25 @@ var builtin_chr(var* local, gc& ngc) {
"ð","ñ","ò","ó","ô","õ","ö","÷", "ð","ñ","ò","ó","ô","õ","ö","÷",
"ø","ù","ú","û","ü","ý","þ","ÿ" "ø","ù","ú","û","ü","ý","þ","ÿ"
}; };
i32 num = local[1].num(); auto num = static_cast<i32>(ctx->localr[1].num());
if (0<=num && num<128) { if (0<=num && num<128) {
return ngc.newstr((char)num); return ngc->newstr((char)num);
} else if (128<=num && num<256) { } else if (128<=num && num<256) {
return ngc.newstr(extend[num-128]); return ngc->newstr(extend[num-128]);
} }
return ngc.newstr(" "); return ngc->newstr(" ");
} }
var builtin_char(var* local, gc& ngc) { var builtin_char(context* ctx, gc* ngc) {
return ngc.newstr((unsigned char)local[1].num()); return ngc->newstr(static_cast<unsigned char>(ctx->localr[1].num()));
} }
var builtin_values(var* local, gc& ngc) { var builtin_values(context* ctx, gc* ngc) {
var hash = local[1]; auto hash = ctx->localr[1];
if (hash.type!=vm_hash) { if (hash.type!=vm_hash) {
return nas_err("values", "\"hash\" must be hash"); return nas_err("values", "\"hash\" must be hash");
} }
var vec = ngc.alloc(vm_vec); var vec = ngc->alloc(vm_vec);
auto& v = vec.vec().elems; auto& v = vec.vec().elems;
for(auto& i : hash.hash().elems) { for(auto& i : hash.hash().elems) {
v.push_back(i.second); v.push_back(i.second);
@ -404,8 +416,8 @@ var builtin_values(var* local, gc& ngc) {
return vec; return vec;
} }
var builtin_sleep(var* local, gc& ngc) { var builtin_sleep(context* ctx, gc* ngc) {
var val = local[1]; auto val = ctx->localr[1];
if (val.type!=vm_num) { if (val.type!=vm_num) {
return nil; return nil;
} }
@ -421,36 +433,36 @@ var builtin_sleep(var* local, gc& ngc) {
return nil; return nil;
} }
var builtin_platform(var* local, gc& ngc) { var builtin_platform(context* ctx, gc* ngc) {
if (is_windows()) { if (is_windows()) {
return ngc.newstr("windows"); return ngc->newstr("windows");
} else if (is_linux()) { } else if (is_linux()) {
return ngc.newstr("linux"); return ngc->newstr("linux");
} else if (is_macos()) { } else if (is_macos()) {
return ngc.newstr("macOS"); return ngc->newstr("macOS");
} }
return ngc.newstr("unknown"); return ngc->newstr("unknown");
} }
var builtin_arch(var* local, gc& ngc) { var builtin_arch(context* ctx, gc* ngc) {
if (is_x86()) { if (is_x86()) {
return ngc.newstr("x86"); return ngc->newstr("x86");
} else if (is_x86_64()) { } else if (is_x86_64()) {
return ngc.newstr("x86-64"); return ngc->newstr("x86-64");
} else if (is_amd64()) { } else if (is_amd64()) {
return ngc.newstr("amd64"); return ngc->newstr("amd64");
} else if (is_arm()) { } else if (is_arm()) {
return ngc.newstr("arm"); return ngc->newstr("arm");
} else if (is_aarch64()) { } else if (is_aarch64()) {
return ngc.newstr("aarch64"); return ngc->newstr("aarch64");
} else if (is_ia64()) { } else if (is_ia64()) {
return ngc.newstr("ia64"); return ngc->newstr("ia64");
} else if (is_powerpc()) { } else if (is_powerpc()) {
return ngc.newstr("powerpc"); return ngc->newstr("powerpc");
} else if (is_superh()) { } else if (is_superh()) {
return ngc.newstr("superh"); return ngc->newstr("superh");
} }
return ngc.newstr("unknown"); return ngc->newstr("unknown");
} }
// md5 related functions // md5 related functions
@ -536,64 +548,64 @@ std::string md5(const std::string& src) {
return tohex(atmp)+tohex(btmp)+tohex(ctmp)+tohex(dtmp); return tohex(atmp)+tohex(btmp)+tohex(ctmp)+tohex(dtmp);
} }
var builtin_md5(var* local, gc& ngc) { var builtin_md5(context* ctx, gc* ngc) {
var str = local[1]; auto str = ctx->localr[1];
if (str.type!=vm_str) { if (str.type!=vm_str) {
return nas_err("md5", "\"str\" must be string"); return nas_err("md5", "\"str\" must be string");
} }
return ngc.newstr(md5(str.str())); return ngc->newstr(md5(str.str()));
} }
var builtin_millisec(var* local, gc& ngc) { var builtin_millisec(context* ctx, gc* ngc) {
f64 res = std::chrono::duration_cast<std::chrono::milliseconds> f64 res = std::chrono::duration_cast<std::chrono::milliseconds>
(std::chrono::high_resolution_clock::now().time_since_epoch()) (std::chrono::high_resolution_clock::now().time_since_epoch())
.count(); .count();
return var::num(res); return var::num(res);
} }
var builtin_gcextend(var* local, gc& ngc) { var builtin_gcextend(context* ctx, gc* ngc) {
var type = local[1]; auto type = ctx->localr[1];
if (type.type!=vm_str) { if (type.type!=vm_str) {
return nil; return nil;
} }
auto& s = type.str(); const auto& s = type.str();
if (s=="str") { if (s=="str") {
ngc.extend(vm_str); ngc->extend(vm_str);
} else if (s=="vec") { } else if (s=="vec") {
ngc.extend(vm_vec); ngc->extend(vm_vec);
} else if (s=="hash") { } else if (s=="hash") {
ngc.extend(vm_hash); ngc->extend(vm_hash);
} else if (s=="func") { } else if (s=="func") {
ngc.extend(vm_func); ngc->extend(vm_func);
} else if (s=="upval") { } else if (s=="upval") {
ngc.extend(vm_upval); ngc->extend(vm_upval);
} else if (s=="obj") { } else if (s=="obj") {
ngc.extend(vm_obj); ngc->extend(vm_obj);
} else if (s=="co") { } else if (s=="co") {
ngc.extend(vm_co); ngc->extend(vm_co);
} }
return nil; return nil;
} }
var builtin_gcinfo(var* local, gc& ngc) { var builtin_gcinfo(context* ctx, gc* ngc) {
auto den = std::chrono::high_resolution_clock::duration::period::den; auto den = std::chrono::high_resolution_clock::duration::period::den;
var res = ngc.alloc(vm_hash); var res = ngc->alloc(vm_hash);
double total = 0; double total = 0;
for(u32 i = 0; i<gc_type_size; ++i) { for(u32 i = 0; i<gc_type_size; ++i) {
total += ngc.gcnt[i]; total += ngc->gcnt[i];
} }
// using ms // using ms
auto& map = res.hash().elems; auto& map = res.hash().elems;
map["total"] = var::num(ngc.worktime*1.0/den*1000); map["total"] = var::num(ngc->worktime*1.0/den*1000);
map["average"] = var::num(ngc.worktime*1.0/den*1000/total); map["average"] = var::num(ngc->worktime*1.0/den*1000/total);
map["max_gc"] = var::num(ngc.max_time*1.0/den*1000); map["max_gc"] = var::num(ngc->max_time*1.0/den*1000);
map["max_mark"] = var::num(ngc.max_mark_time*1.0/den*1000); map["max_mark"] = var::num(ngc->max_mark_time*1.0/den*1000);
map["max_sweep"] = var::num(ngc.max_sweep_time*1.0/den*1000); map["max_sweep"] = var::num(ngc->max_sweep_time*1.0/den*1000);
return res; return res;
} }
var builtin_logtime(var* local, gc& ngc) { var builtin_logtime(context* ctx, gc* ngc) {
time_t t = time(nullptr); time_t t = time(nullptr);
tm* tm_t = localtime(&t); tm* tm_t = localtime(&t);
char s[64]; char s[64];
@ -606,11 +618,11 @@ var builtin_logtime(var* local, gc& ngc) {
tm_t->tm_min, tm_t->tm_min,
tm_t->tm_sec tm_t->tm_sec
); );
return ngc.newstr(s); return ngc->newstr(s);
} }
var builtin_ghosttype(var* local, gc& ngc) { var builtin_ghosttype(context* ctx, gc* ngc) {
var arg = local[1]; auto arg = ctx->localr[1];
if (arg.type!=vm_obj) { if (arg.type!=vm_obj) {
return nas_err("ghosttype", "this is not a ghost object."); return nas_err("ghosttype", "this is not a ghost object.");
} }
@ -618,7 +630,7 @@ var builtin_ghosttype(var* local, gc& ngc) {
if (!name.length()) { if (!name.length()) {
return var::num(reinterpret_cast<u64>(arg.obj().pointer)); return var::num(reinterpret_cast<u64>(arg.obj().pointer));
} }
return ngc.newstr(name); return ngc->newstr(name);
} }
nasal_builtin_table builtin[] = { nasal_builtin_table builtin[] = {

View File

@ -29,56 +29,56 @@
namespace nasal { namespace nasal {
var builtin_print(var*, gc&); var builtin_print(context*, gc*);
var builtin_println(var*, gc&); var builtin_println(context*, gc*);
var builtin_exit(var*, gc&); var builtin_exit(context*, gc*);
var builtin_abort(var*, gc&); var builtin_abort(context*, gc*);
var builtin_append(var*, gc&); var builtin_append(context*, gc*);
var builtin_setsize(var*, gc&); var builtin_setsize(context*, gc*);
var builtin_system(var*, gc&); var builtin_system(context*, gc*);
var builtin_input(var*, gc&); var builtin_input(context*, gc*);
var builtin_split(var*, gc&); var builtin_split(context*, gc*);
var builtin_rand(var*, gc&); var builtin_rand(context*, gc*);
var builtin_id(var*, gc&); var builtin_id(context*, gc*);
var builtin_int(var*, gc&); var builtin_int(context*, gc*);
var builtin_floor(var*, gc&); var builtin_floor(context*, gc*);
var builtin_num(var*, gc&); var builtin_num(context*, gc*);
var builtin_pop(var*, gc&); var builtin_pop(context*, gc*);
var builtin_str(var*, gc&); var builtin_str(context*, gc*);
var builtin_size(var*, gc&); var builtin_size(context*, gc*);
var builtin_time(var*, gc&); var builtin_time(context*, gc*);
var builtin_contains(var*, gc&); var builtin_contains(context*, gc*);
var builtin_delete(var*, gc&); var builtin_delete(context*, gc*);
var builtin_keys(var*, gc&); var builtin_keys(context*, gc*);
var builtin_die(var*, gc&); var builtin_die(context*, gc*);
var builtin_find(var*, gc&); var builtin_find(context*, gc*);
var builtin_type(var*, gc&); var builtin_type(context*, gc*);
var builtin_substr(var*, gc&); var builtin_substr(context*, gc*);
var builtin_streq(var*, gc&); var builtin_streq(context*, gc*);
var builtin_left(var*, gc&); var builtin_left(context*, gc*);
var builtin_right(var*, gc&); var builtin_right(context*, gc*);
var builtin_cmp(var*, gc&); var builtin_cmp(context*, gc*);
var builtin_chr(var*, gc&); var builtin_chr(context*, gc*);
var builtin_char(var*, gc&); var builtin_char(context*, gc*);
var builtin_values(var*, gc&); var builtin_values(context*, gc*);
var builtin_sleep(var*, gc&); var builtin_sleep(context*, gc*);
var builtin_platform(var*, gc&); var builtin_platform(context*, gc*);
var builtin_arch(var*, gc&); var builtin_arch(context*, gc*);
// md5 related functions // md5 related functions
std::string tohex(u32); std::string tohex(u32);
std::string md5(const std::string&); std::string md5(const std::string&);
var builtin_md5(var*, gc&); var builtin_md5(context*, gc*);
var builtin_millisec(var*, gc&); var builtin_millisec(context*, gc*);
var builtin_gcextend(var*, gc&); var builtin_gcextend(context*, gc*);
var builtin_gcinfo(var*, gc&); var builtin_gcinfo(context*, gc*);
var builtin_logtime(var*, gc&); var builtin_logtime(context*, gc*);
var builtin_ghosttype(var*, gc&); var builtin_ghosttype(context*, gc*);
// register builtin function's name and it's address here in this table below // register builtin function's name and it's address here in this table below
// this table must end with {nullptr,nullptr} // this table must end with {nullptr,nullptr}
struct nasal_builtin_table { struct nasal_builtin_table {
const char* name; const char* name;
var (*func)(var*, gc&); var (*func)(context*, gc*);
}; };
extern nasal_builtin_table builtin[]; extern nasal_builtin_table builtin[];

View File

@ -821,11 +821,12 @@ inline void vm::o_callb() {
// if running a native function about coroutine // if running a native function about coroutine
// (top) will be set to another context.top, instead of main_context.top // (top) will be set to another context.top, instead of main_context.top
var tmp = (*native_function[imm[ctx.pc]].func)(ctx.localr, ngc); auto function_pointer = native_function[imm[ctx.pc]].func;
var result = (*function_pointer)(&ctx, &ngc);
// so we use tmp variable to store this return value // so we use tmp variable to store this return value
// and set it to top[0] later // and set it to top[0] later
ctx.top[0] = tmp; ctx.top[0] = result;
// if get none, this means errors occurred when calling this native function // if get none, this means errors occurred when calling this native function
if (ctx.top[0].type==vm_none) { if (ctx.top[0].type==vm_none) {

View File

@ -12,130 +12,130 @@ void dir_entry_destructor(void* ptr) {
#endif #endif
} }
var builtin_pipe(var* local, gc& ngc) { var builtin_pipe(context* ctx, gc* ngc) {
#ifndef _WIN32 #ifndef _WIN32
i32 fd[2]; i32 fd[2];
var res = ngc.alloc(vm_vec); var res = ngc->alloc(vm_vec);
if (pipe(fd)==-1) { if (pipe(fd)==-1) {
return nas_err("pipe", "failed to create pipe"); return nas_err("unix::pipe", "failed to create pipe");
} }
res.vec().elems.push_back(var::num(static_cast<f64>(fd[0]))); res.vec().elems.push_back(var::num(static_cast<f64>(fd[0])));
res.vec().elems.push_back(var::num(static_cast<f64>(fd[1]))); res.vec().elems.push_back(var::num(static_cast<f64>(fd[1])));
return res; return res;
#endif #endif
return nas_err("pipe", "not supported on windows"); return nas_err("unix::pipe", "not supported on windows");
} }
var builtin_fork(var* local, gc& ngc) { var builtin_fork(context* ctx, gc* ngc) {
#ifndef _WIN32 #ifndef _WIN32
f64 res=fork(); f64 res=fork();
if (res<0) { if (res<0) {
return nas_err("fork", "failed to fork a process"); return nas_err("unix::fork", "failed to fork a process");
} }
return var::num(static_cast<f64>(res)); return var::num(static_cast<f64>(res));
#endif #endif
return nas_err("fork", "not supported on windows"); return nas_err("unix::fork", "not supported on windows");
} }
var builtin_waitpid(var* local, gc& ngc) { var builtin_waitpid(context* ctx, gc* ngc) {
var pid = local[1]; auto pid = ctx->localr[1];
var nohang = local[2]; auto nohang = ctx->localr[2];
if (pid.type!=vm_num || nohang.type!=vm_num) { if (pid.type!=vm_num || nohang.type!=vm_num) {
return nas_err("waitpid", "pid and nohang must be number"); return nas_err("unix::waitpid", "pid and nohang must be number");
} }
#ifndef _WIN32 #ifndef _WIN32
i32 ret_pid, status; i32 ret_pid, status;
ret_pid = waitpid(pid.num(), &status, nohang.num()==0? 0:WNOHANG); ret_pid = waitpid(pid.num(), &status, nohang.num()==0? 0:WNOHANG);
var vec = ngc.alloc(vm_vec); var vec = ngc->alloc(vm_vec);
vec.vec().elems.push_back(var::num(static_cast<f64>(ret_pid))); vec.vec().elems.push_back(var::num(static_cast<f64>(ret_pid)));
vec.vec().elems.push_back(var::num(static_cast<f64>(status))); vec.vec().elems.push_back(var::num(static_cast<f64>(status)));
return vec; return vec;
#endif #endif
return nas_err("waitpid", "not supported on windows"); return nas_err("unix::waitpid", "not supported on windows");
} }
var builtin_opendir(var* local, gc& ngc) { var builtin_opendir(context* ctx, gc* ngc) {
var path = local[1]; auto path = ctx->localr[1];
if (path.type!=vm_str) { if (path.type!=vm_str) {
return nas_err("opendir", "\"path\" must be string"); return nas_err("unix::opendir", "\"path\" must be string");
} }
#ifdef _MSC_VER #ifdef _MSC_VER
WIN32_FIND_DATAA data; WIN32_FIND_DATAA data;
HANDLE p; HANDLE p;
p = FindFirstFileA((path.str()+"\\*.*").c_str(), &data); p = FindFirstFileA((path.str()+"\\*.*").c_str(), &data);
if (p==INVALID_HANDLE_VALUE) { if (p==INVALID_HANDLE_VALUE) {
return nas_err("opendir", "cannot open dir <"+path.str()+">"); return nas_err("unix::opendir", "cannot open dir <"+path.str()+">");
} }
#else #else
DIR* p = opendir(path.str().c_str()); DIR* p = opendir(path.str().c_str());
if (!p) { if (!p) {
return nas_err("opendir", "cannot open dir <"+path.str()+">"); return nas_err("unix::opendir", "cannot open dir <"+path.str()+">");
} }
#endif #endif
var ret = ngc.alloc(vm_obj); var ret = ngc->alloc(vm_obj);
ret.obj().set(dir_type_name, dir_entry_destructor, p); ret.obj().set(dir_type_name, dir_entry_destructor, p);
return ret; return ret;
} }
var builtin_readdir(var* local, gc& ngc) { var builtin_readdir(context* ctx, gc* ngc) {
var handle = local[1]; auto handle = ctx->localr[1];
if (!handle.object_check(dir_type_name)) { if (!handle.object_check(dir_type_name)) {
return nas_err("readdir", "not a valid dir handle"); return nas_err("unix::readdir", "not a valid dir handle");
} }
#ifdef _MSC_VER #ifdef _MSC_VER
WIN32_FIND_DATAA data; WIN32_FIND_DATAA data;
if (!FindNextFileA(handle.obj().pointer, &data)) { if (!FindNextFileA(handle.obj().pointer, &data)) {
return nil; return nil;
} }
return ngc.newstr(data.cFileName); return ngc->newstr(data.cFileName);
#else #else
dirent* p = readdir(static_cast<DIR*>(handle.obj().pointer)); dirent* p = readdir(static_cast<DIR*>(handle.obj().pointer));
return p? ngc.newstr(p->d_name):nil; return p? ngc->newstr(p->d_name):nil;
#endif #endif
} }
var builtin_closedir(var* local, gc& ngc) { var builtin_closedir(context* ctx, gc* ngc) {
var handle = local[1]; auto handle = ctx->localr[1];
if (!handle.object_check(dir_type_name)) { if (!handle.object_check(dir_type_name)) {
return nas_err("closedir", "not a valid dir handle"); return nas_err("unix::closedir", "not a valid dir handle");
} }
handle.obj().clear(); handle.obj().clear();
return nil; return nil;
} }
var builtin_chdir(var* local, gc& ngc) { var builtin_chdir(context* ctx, gc* ngc) {
var path = local[1]; auto path = ctx->localr[1];
if (path.type!=vm_str) { if (path.type!=vm_str) {
return var::num(-1.0); return var::num(-1.0);
} }
return var::num(static_cast<f64>(chdir(path.str().c_str()))); return var::num(static_cast<f64>(chdir(path.str().c_str())));
} }
var builtin_environ(var* local, gc& ngc) { var builtin_environ(context* ctx, gc* ngc) {
var res = ngc.temp = ngc.alloc(vm_vec); var res = ngc->temp = ngc->alloc(vm_vec);
auto& vec = res.vec().elems; auto& vec = res.vec().elems;
for(char** env = environ; *env; ++env) { for(char** env = environ; *env; ++env) {
vec.push_back(ngc.newstr(*env)); vec.push_back(ngc->newstr(*env));
} }
ngc.temp = nil; ngc->temp = nil;
return res; return res;
} }
var builtin_getcwd(var* local, gc& ngc) { var builtin_getcwd(context* ctx, gc* ngc) {
char buf[1024]; char buf[1024];
if (!getcwd(buf, sizeof(buf))) { if (!getcwd(buf, sizeof(buf))) {
return nil; return nil;
} }
return ngc.newstr(buf); return ngc->newstr(buf);
} }
var builtin_getenv(var* local, gc& ngc) { var builtin_getenv(context* ctx, gc* ngc) {
var envvar = local[1]; auto envvar = ctx->localr[1];
if (envvar.type!=vm_str) { if (envvar.type!=vm_str) {
return nas_err("getenv", "\"envvar\" must be string"); return nas_err("unix::getenv", "\"envvar\" must be string");
} }
char* res = getenv(envvar.str().c_str()); char* res = getenv(envvar.str().c_str());
return res? ngc.newstr(res):nil; return res? ngc->newstr(res):nil;
} }
nasal_builtin_table unix_lib_native[] = { nasal_builtin_table unix_lib_native[] = {

View File

@ -24,16 +24,16 @@ namespace nasal {
void dir_entry_destructor(void*); void dir_entry_destructor(void*);
var builtin_pipe(var*, gc&); var builtin_pipe(context*, gc*);
var builtin_fork(var*, gc&); var builtin_fork(context*, gc*);
var builtin_waitpid(var*, gc&); var builtin_waitpid(context*, gc*);
var builtin_opendir(var*, gc&); var builtin_opendir(context*, gc*);
var builtin_readdir(var*, gc&); var builtin_readdir(context*, gc*);
var builtin_closedir(var*, gc&); var builtin_closedir(context*, gc*);
var builtin_chdir(var*, gc&); var builtin_chdir(context*, gc*);
var builtin_environ(var*, gc&); var builtin_environ(context*, gc*);
var builtin_getcwd(var*, gc&); var builtin_getcwd(context*, gc*);
var builtin_getenv(var*, gc&); var builtin_getenv(context*, gc*);
extern nasal_builtin_table unix_lib_native[]; extern nasal_builtin_table unix_lib_native[];