🧑‍💻 add important symbol "globals"

This commit is contained in:
ValKmjolnir 2023-07-06 22:10:07 +08:00
parent eca6141408
commit b4482792c8
11 changed files with 381 additions and 243 deletions

View File

@ -100,6 +100,7 @@ test:nasal
-@ ./nasal -d test/exception.nas -@ ./nasal -d test/exception.nas
@ ./nasal -t -d test/fib.nas @ ./nasal -t -d test/fib.nas
@ ./nasal -e test/filesystem.nas @ ./nasal -e test/filesystem.nas
@ ./nasal -t -d test/globals_test.nas
@ ./nasal -d test/hexdump.nas @ ./nasal -d test/hexdump.nas
@ ./nasal -e test/json.nas @ ./nasal -e test/json.nas
@ ./nasal -e test/leetcode1319.nas @ ./nasal -e test/leetcode1319.nas

View File

@ -334,15 +334,21 @@ var builtin_delete(var* local, gc& ngc) {
var builtin_keys(var* local, gc& ngc) { var builtin_keys(var* local, gc& ngc) {
var hash=local[1]; var hash=local[1];
if (hash.type!=vm_hash) { 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); var res=ngc.temp=ngc.alloc(vm_vec);
auto& vec=res.vec().elems; auto& vec=res.vec().elems;
for(auto& iter:hash.hash().elems) { if (hash.type==vm_hash) {
for(const auto& iter : hash.hash().elems) {
vec.push_back(ngc.newstr(iter.first)); vec.push_back(ngc.newstr(iter.first));
} }
} else {
for(const auto& iter : hash.map().mapper) {
vec.push_back(ngc.newstr(iter.first));
}
}
ngc.temp=nil; ngc.temp=nil;
return res; return res;
} }
@ -372,6 +378,7 @@ var builtin_type(var* local, gc& ngc) {
case vm_func: return ngc.newstr("func"); break; case vm_func: return ngc.newstr("func"); break;
case vm_obj: return ngc.newstr("obj"); break; case vm_obj: return ngc.newstr("obj"); break;
case vm_co: return ngc.newstr("coroutine");break; case vm_co: return ngc.newstr("coroutine");break;
case vm_map: return ngc.newstr("mapper"); break;
} }
return nil; return nil;
} }

View File

@ -1091,6 +1091,7 @@ const error& codegen::compile(parse& parse, linker& import) {
fileindex = 0; fileindex = 0;
file = import.filelist().data(); file = import.filelist().data();
in_iterloop.push(0); in_iterloop.push(0);
add_symbol("globals");
find_symbol(parse.tree()); // search symbols first find_symbol(parse.tree()); // search symbols first
gen(op_intg, global.size(), 0); gen(op_intg, global.size(), 0);
block_gen(parse.tree()); // generate main block block_gen(parse.tree()); // generate main block

View File

@ -25,8 +25,8 @@ private:
error& err; error& err;
const std::string* file; const std::string* file;
std::stack<u32> in_iterloop; std::stack<u32> in_iterloop;
std::unordered_map<f64,u32> const_number_map; std::unordered_map<f64, u32> const_number_map;
std::unordered_map<std::string,u32> const_string_map; std::unordered_map<std::string, u32> const_string_map;
std::vector<f64> const_number_table; std::vector<f64> const_number_table;
std::vector<std::string> const_string_table; std::vector<std::string> const_string_table;
std::vector<opcode> code; std::vector<opcode> code;
@ -35,10 +35,10 @@ private:
// symbol table // symbol table
// global : max STACK_DEPTH-1 values // global : max STACK_DEPTH-1 values
std::unordered_map<std::string,i32> global; std::unordered_map<std::string, i32> global;
// local : max 32768 upvalues 65536 values // local : max 32768 upvalues 65536 values
// but in fact local scope also has less than STACK_DEPTH value // but in fact local scope also has less than STACK_DEPTH value
std::list<std::unordered_map<std::string,i32>> local; std::list<std::unordered_map<std::string, i32>> local;
void check_id_exist(identifier*); void check_id_exist(identifier*);
@ -97,6 +97,7 @@ public:
const std::vector<std::string>& strs() const {return const_string_table;} const std::vector<std::string>& strs() const {return const_string_table;}
const std::vector<f64>& nums() const {return const_number_table;} const std::vector<f64>& nums() const {return const_number_table;}
const std::vector<opcode>& codes() const {return code;} const std::vector<opcode>& codes() const {return code;}
const std::unordered_map<std::string, i32>& globals() const {return global;}
public: public:
codegen(error& e): fileindex(0), err(e), file(nullptr) {} codegen(error& e): fileindex(0), err(e), file(nullptr) {}

View File

@ -163,7 +163,12 @@ void dbg::run(
const std::vector<std::string>& argv) { const std::vector<std::string>& argv) {
verbose=true; verbose=true;
fsize=linker.filelist().size(); fsize=linker.filelist().size();
init(gen.strs(), gen.nums(), gen.codes(), linker.filelist(), argv); init(gen.strs(),
gen.nums(),
gen.codes(),
gen.globals(),
linker.filelist(),
argv);
u64 count[op_ret+1]={0}; u64 count[op_ret+1]={0};
typedef void (dbg::*nafunc)(); typedef void (dbg::*nafunc)();
const nafunc oprs[]={ const nafunc oprs[]={

View File

@ -153,6 +153,35 @@ void nas_co::clear() {
status = coroutine_status::suspended; status = coroutine_status::suspended;
} }
var nas_map::get_val(const std::string& key) {
if (mapper.count(key)) {
return *mapper.at(key);
}
return var::none();
}
var* nas_map::get_mem(const std::string& key) {
if (mapper.count(key)) {
return mapper.at(key);
}
return nullptr;
}
std::ostream& operator<<(std::ostream& out, nas_map& mp) {
if (!mp.mapper.size() || mp.printed) {
out << (mp.mapper.size()? "{..}":"{}");
return out;
}
mp.printed = true;
usize iter = 0, size = mp.mapper.size();
out << "{";
for(auto& i : mp.mapper) {
out << i.first << ":" << *i.second << ",}"[(++iter)==size];
}
mp.printed = false;
return out;
}
nas_val::nas_val(u8 val_type) { nas_val::nas_val(u8 val_type) {
mark = gc_status::collected; mark = gc_status::collected;
type = val_type; type = val_type;
@ -165,6 +194,7 @@ nas_val::nas_val(u8 val_type) {
case vm_upval: ptr.upval = new nas_upval; break; case vm_upval: ptr.upval = new nas_upval; break;
case vm_obj: ptr.obj = new nas_ghost; break; case vm_obj: ptr.obj = new nas_ghost; break;
case vm_co: ptr.co = new nas_co; break; case vm_co: ptr.co = new nas_co; break;
case vm_map: ptr.map = new nas_map; break;
} }
} }
@ -177,6 +207,7 @@ nas_val::~nas_val() {
case vm_upval:delete ptr.upval;break; case vm_upval:delete ptr.upval;break;
case vm_obj: delete ptr.obj; break; case vm_obj: delete ptr.obj; break;
case vm_co: delete ptr.co; break; case vm_co: delete ptr.co; break;
case vm_map: delete ptr.map; break;
} }
type=vm_nil; type=vm_nil;
} }
@ -190,6 +221,7 @@ void nas_val::clear() {
case vm_upval:ptr.upval->clear(); break; case vm_upval:ptr.upval->clear(); break;
case vm_obj: ptr.obj->clear(); break; case vm_obj: ptr.obj->clear(); break;
case vm_co: ptr.co->clear(); break; case vm_co: ptr.co->clear(); break;
case vm_map: ptr.map->clear(); break;
} }
} }
@ -220,6 +252,7 @@ std::ostream& operator<<(std::ostream& out, var& ref) {
case vm_func: out << "func(..) {..}"; break; case vm_func: out << "func(..) {..}"; break;
case vm_obj: out << ref.obj(); break; case vm_obj: out << ref.obj(); break;
case vm_co: out << "<coroutine>"; break; case vm_co: out << "<coroutine>"; break;
case vm_map: out << ref.map(); break;
} }
return out; return out;
} }
@ -300,6 +333,10 @@ nas_co& var::co() {
return *val.gcobj->ptr.co; return *val.gcobj->ptr.co;
} }
nas_map& var::map() {
return *val.gcobj->ptr.map;
}
void gc::mark() { void gc::mark() {
std::vector<var> bfs; std::vector<var> bfs;
mark_context(bfs); mark_context(bfs);
@ -345,6 +382,7 @@ void gc::mark_var(std::vector<var>& bfs_queue, var& value) {
case vm_func: mark_func(bfs_queue, value.func()); break; case vm_func: mark_func(bfs_queue, value.func()); break;
case vm_upval: mark_upval(bfs_queue, value.upval()); break; case vm_upval: mark_upval(bfs_queue, value.upval()); break;
case vm_co: mark_co(bfs_queue, value.co()); break; case vm_co: mark_co(bfs_queue, value.co()); break;
case vm_map: mark_map(bfs_queue, value.map()); break;
default: break; default: break;
} }
} }
@ -384,6 +422,12 @@ void gc::mark_co(std::vector<var>& bfs_queue, nas_co& co) {
} }
} }
void gc::mark_map(std::vector<var>& bfs_queue, nas_map& mp) {
for(const auto& i : mp.mapper) {
bfs_queue.push_back(*i.second);
}
}
void gc::sweep() { void gc::sweep() {
for(auto i : memory) { for(auto i : memory) {
if (i->mark==gc_status::uncollected) { if (i->mark==gc_status::uncollected) {
@ -469,7 +513,8 @@ void gc::info() {
"function ", "function ",
"upvalue ", "upvalue ",
"object ", "object ",
"coroutine" "coroutine",
"mapper "
}; };
usize indent = 0; usize indent = 0;

View File

@ -47,10 +47,11 @@ enum vm_type:u8 {
vm_func, vm_func,
vm_upval, vm_upval,
vm_obj, vm_obj,
vm_co vm_co,
vm_map // for globals, arg
}; };
const u32 gc_type_size = vm_co-vm_str+1; const u32 gc_type_size = vm_map-vm_str+1;
enum class coroutine_status:u32 { enum class coroutine_status:u32 {
suspended, suspended,
@ -70,6 +71,7 @@ struct nas_func; // function(lambda)
struct nas_upval; // upvalue struct nas_upval; // upvalue
struct nas_ghost; // objects struct nas_ghost; // objects
struct nas_co; // coroutine struct nas_co; // coroutine
struct nas_map; // mapper
struct nas_val; // nas_val includes gc-managed types struct nas_val; // nas_val includes gc-managed types
struct var { struct var {
@ -127,6 +129,7 @@ public:
nas_upval& upval(); nas_upval& upval();
nas_ghost& obj(); nas_ghost& obj();
nas_co& co(); nas_co& co();
nas_map& map();
}; };
struct nas_vec { struct nas_vec {
@ -295,6 +298,19 @@ struct nas_co {
void clear(); void clear();
}; };
struct nas_map {
bool printed = false;
std::unordered_map<std::string, var*> mapper;
nas_map() {}
void clear() {
mapper.clear();
}
var get_val(const std::string&);
var* get_mem(const std::string&);
};
struct nas_val { struct nas_val {
gc_status mark; gc_status mark;
u8 type; // value type u8 type; // value type
@ -307,6 +323,7 @@ struct nas_val {
nas_upval* upval; nas_upval* upval;
nas_ghost* obj; nas_ghost* obj;
nas_co* co; nas_co* co;
nas_map* map;
} ptr; } ptr;
nas_val(u8); nas_val(u8);
@ -316,6 +333,7 @@ struct nas_val {
std::ostream& operator<<(std::ostream&, nas_vec&); std::ostream& operator<<(std::ostream&, nas_vec&);
std::ostream& operator<<(std::ostream&, nas_hash&); std::ostream& operator<<(std::ostream&, nas_hash&);
std::ostream& operator<<(std::ostream&, nas_map&);
std::ostream& operator<<(std::ostream&, var&); std::ostream& operator<<(std::ostream&, var&);
const var zero = var::num(0); const var zero = var::num(0);
@ -348,7 +366,8 @@ struct gc {
128, // vm_func 128, // vm_func
256, // vm_upval 256, // vm_upval
16, // vm_obj 16, // vm_obj
16 // vm_co 16, // vm_co
2, // vm_map
}; };
/* values for analysis */ /* values for analysis */
@ -372,6 +391,7 @@ private:
void mark_func(std::vector<var>&, nas_func&); void mark_func(std::vector<var>&, nas_func&);
void mark_upval(std::vector<var>&, nas_upval&); void mark_upval(std::vector<var>&, nas_upval&);
void mark_co(std::vector<var>&, nas_co&); void mark_co(std::vector<var>&, nas_co&);
void mark_map(std::vector<var>&, nas_map&);
void sweep(); void sweep();
public: public:

View File

@ -4,6 +4,7 @@ void vm::init(
const std::vector<std::string>& strs, const std::vector<std::string>& strs,
const std::vector<f64>& nums, const std::vector<f64>& nums,
const std::vector<opcode>& code, const std::vector<opcode>& code,
const std::unordered_map<std::string, i32>& global,
const std::vector<std::string>& filenames, const std::vector<std::string>& filenames,
const std::vector<std::string>& argv const std::vector<std::string>& argv
) { ) {
@ -27,6 +28,13 @@ void vm::init(
/* init gc */ /* init gc */
ngc.init(strs,argv); ngc.init(strs,argv);
/* init vm globals */
auto map_instance = ngc.alloc(vm_map);
stack[global.at("globals")] = map_instance;
for(const auto& i : global) {
map_instance.map().mapper[i.first] = stack+i.second;
}
} }
void vm::valinfo(var& val) { void vm::valinfo(var& val) {
@ -204,7 +212,12 @@ void vm::run(
const bool detail const bool detail
) { ) {
verbose=detail; verbose=detail;
init(gen.strs(), gen.nums(), gen.codes(), linker.filelist(), argv); init(gen.strs(),
gen.nums(),
gen.codes(),
gen.globals(),
linker.filelist(),
argv);
#ifndef _MSC_VER #ifndef _MSC_VER
const void* oprs[]={ const void* oprs[]={
&&vmexit, &&intg, &&intl, &&loadg, &&vmexit, &&intg, &&intl, &&loadg,

View File

@ -39,6 +39,7 @@ protected:
const std::vector<std::string>&, const std::vector<std::string>&,
const std::vector<f64>&, const std::vector<f64>&,
const std::vector<opcode>&, const std::vector<opcode>&,
const std::unordered_map<std::string, i32>&,
const std::vector<std::string>&, const std::vector<std::string>&,
const std::vector<std::string>&); const std::vector<std::string>&);
@ -155,15 +156,14 @@ public:
const codegen&, const codegen&,
const linker&, const linker&,
const std::vector<std::string>&, const std::vector<std::string>&,
const bool const bool);
);
}; };
inline bool vm::cond(var& val) { inline bool vm::cond(var& val) {
if (val.type==vm_num) { if (val.type==vm_num) {
return val.num(); return val.num();
} else if (val.type==vm_str) { } else if (val.type==vm_str) {
const f64 num=str2num(val.str().c_str()); const f64 num = str2num(val.str().c_str());
return std::isnan(num)? !val.str().empty():num; return std::isnan(num)? !val.str().empty():num;
} }
return false; return false;
@ -171,144 +171,150 @@ inline bool vm::cond(var& val) {
inline void vm::o_intg() { inline void vm::o_intg() {
// global values store on stack // global values store on stack
ctx.top+=imm[ctx.pc]; ctx.top += imm[ctx.pc];
--ctx.top;// point to the top // point to the top
--ctx.top;
} }
inline void vm::o_intl() { inline void vm::o_intl() {
ctx.top[0].func().local.resize(imm[ctx.pc], nil); ctx.top[0].func().local.resize(imm[ctx.pc], nil);
ctx.top[0].func().lsize=imm[ctx.pc]; ctx.top[0].func().lsize = imm[ctx.pc];
} }
inline void vm::o_loadg() { inline void vm::o_loadg() {
stack[imm[ctx.pc]]=(ctx.top--)[0]; stack[imm[ctx.pc]] = (ctx.top--)[0];
} }
inline void vm::o_loadl() { inline void vm::o_loadl() {
ctx.localr[imm[ctx.pc]]=(ctx.top--)[0]; ctx.localr[imm[ctx.pc]] = (ctx.top--)[0];
} }
inline void vm::o_loadu() { inline void vm::o_loadu() {
ctx.funcr.func().upval[(imm[ctx.pc]>>16)&0xffff] ctx.funcr.func().upval[(imm[ctx.pc]>>16)&0xffff]
.upval()[imm[ctx.pc]&0xffff]=(ctx.top--)[0]; .upval()[imm[ctx.pc]&0xffff] = (ctx.top--)[0];
} }
inline void vm::o_pnum() { inline void vm::o_pnum() {
(++ctx.top)[0]=var::num(cnum[imm[ctx.pc]]); (++ctx.top)[0] = var::num(cnum[imm[ctx.pc]]);
} }
inline void vm::o_pnil() { inline void vm::o_pnil() {
(++ctx.top)[0]=nil; (++ctx.top)[0] = nil;
} }
inline void vm::o_pstr() { inline void vm::o_pstr() {
(++ctx.top)[0]=ngc.strs[imm[ctx.pc]]; (++ctx.top)[0] = ngc.strs[imm[ctx.pc]];
} }
inline void vm::o_newv() { inline void vm::o_newv() {
var newv=ngc.alloc(vm_vec); var newv = ngc.alloc(vm_vec);
auto& vec=newv.vec().elems; auto& vec = newv.vec().elems;
vec.resize(imm[ctx.pc]); vec.resize(imm[ctx.pc]);
// use top-=imm[pc]-1 here will cause error if imm[pc] is 0 // use top-=imm[pc]-1 here will cause error if imm[pc] is 0
ctx.top=ctx.top-imm[ctx.pc]+1; ctx.top = ctx.top-imm[ctx.pc]+1;
for(u32 i=0;i<imm[ctx.pc];++i) { for(u32 i = 0; i<imm[ctx.pc]; ++i) {
vec[i]=ctx.top[i]; vec[i] = ctx.top[i];
} }
ctx.top[0]=newv; ctx.top[0] = newv;
} }
inline void vm::o_newh() { inline void vm::o_newh() {
(++ctx.top)[0]=ngc.alloc(vm_hash); (++ctx.top)[0] = ngc.alloc(vm_hash);
} }
inline void vm::o_newf() { inline void vm::o_newf() {
(++ctx.top)[0]=ngc.alloc(vm_func); (++ctx.top)[0] = ngc.alloc(vm_func);
nas_func& func=ctx.top[0].func(); auto& func = ctx.top[0].func();
func.entry=imm[ctx.pc]; func.entry = imm[ctx.pc];
func.psize=1; func.psize = 1;
/* this means you create a new function in local scope */ /* this means you create a new function in local scope */
if (ctx.localr) { if (ctx.localr) {
func.upval=ctx.funcr.func().upval; func.upval = ctx.funcr.func().upval;
// function created in the same local scope shares one closure // function created in the same local scope shares one closure
// so this size & stk setting has no problem // so this size & stk setting has no problem
var upval=(ctx.upvalr.type==vm_nil)?ngc.alloc(vm_upval):ctx.upvalr; var upval = (ctx.upvalr.type==vm_nil)? ngc.alloc(vm_upval):ctx.upvalr;
upval.upval().size=ctx.funcr.func().lsize; upval.upval().size = ctx.funcr.func().lsize;
upval.upval().stk=ctx.localr; upval.upval().stk = ctx.localr;
func.upval.push_back(upval); func.upval.push_back(upval);
ctx.upvalr=upval; ctx.upvalr = upval;
} }
} }
inline void vm::o_happ() { inline void vm::o_happ() {
ctx.top[-1].hash().elems[cstr[imm[ctx.pc]]]=ctx.top[0]; ctx.top[-1].hash().elems[cstr[imm[ctx.pc]]] = ctx.top[0];
--ctx.top; --ctx.top;
} }
inline void vm::o_para() { inline void vm::o_para() {
nas_func& func=ctx.top[0].func(); auto& func = ctx.top[0].func();
// func->size has 1 place reserved for "me" // func->size has 1 place reserved for "me"
func.keys[imm[ctx.pc]]=func.psize; func.keys[imm[ctx.pc]] = func.psize;
func.local[func.psize++]=var::none(); func.local[func.psize++] = var::none();
} }
inline void vm::o_deft() { inline void vm::o_deft() {
var val=ctx.top[0]; var val = ctx.top[0];
nas_func& func=(--ctx.top)[0].func(); auto& func = (--ctx.top)[0].func();
// func->size has 1 place reserved for "me" // func->size has 1 place reserved for "me"
func.keys[imm[ctx.pc]]=func.psize; func.keys[imm[ctx.pc]] = func.psize;
func.local[func.psize++]=val; func.local[func.psize++] = val;
} }
inline void vm::o_dyn() { inline void vm::o_dyn() {
ctx.top[0].func().dpara=imm[ctx.pc]; ctx.top[0].func().dpara = imm[ctx.pc];
} }
inline void vm::o_lnot() { inline void vm::o_lnot() {
var val=ctx.top[0]; var val = ctx.top[0];
switch(val.type) { switch(val.type) {
case vm_nil:ctx.top[0]=one;break; case vm_nil: ctx.top[0] = one; break;
case vm_num:ctx.top[0]=val.num()?zero:one;break; case vm_num: ctx.top[0] = val.num()? zero:one; break;
case vm_str:{ case vm_str: {
const f64 num=str2num(val.str().c_str()); const f64 num = str2num(val.str().c_str());
if (std::isnan(num)) { if (std::isnan(num)) {
ctx.top[0]=var::num((f64)val.str().empty()); ctx.top[0] = var::num((f64)val.str().empty());
} else { } else {
ctx.top[0]=num?zero:one; ctx.top[0] = num? zero:one;
} }
} break; } break;
default:{ default:
die("incorrect value type"); die("incorrect value type");
return; return;
} break;
} }
} }
inline void vm::o_usub() { inline void vm::o_usub() {
ctx.top[0]=var::num(-ctx.top[0].tonum()); ctx.top[0] = var::num(-ctx.top[0].tonum());
} }
inline void vm::o_bnot() { inline void vm::o_bnot() {
ctx.top[0]=var::num(~static_cast<int32_t>(ctx.top[0].num())); ctx.top[0] = var::num(~static_cast<int32_t>(ctx.top[0].num()));
} }
inline void vm::o_btor() { inline void vm::o_btor() {
ctx.top[-1]=var::num(static_cast<int32_t>(ctx.top[-1].tonum())|static_cast<int32_t>(ctx.top[0].tonum())); ctx.top[-1] = var::num(
static_cast<int32_t>(ctx.top[-1].tonum())|
static_cast<int32_t>(ctx.top[0].tonum()));
--ctx.top; --ctx.top;
} }
inline void vm::o_btxor() { inline void vm::o_btxor() {
ctx.top[-1]=var::num(static_cast<int32_t>(ctx.top[-1].tonum())^static_cast<int32_t>(ctx.top[0].tonum())); ctx.top[-1] = var::num(
static_cast<int32_t>(ctx.top[-1].tonum())^
static_cast<int32_t>(ctx.top[0].tonum()));
--ctx.top; --ctx.top;
} }
inline void vm::o_btand() { inline void vm::o_btand() {
ctx.top[-1]=var::num(static_cast<int32_t>(ctx.top[-1].tonum())&static_cast<int32_t>(ctx.top[0].tonum())); ctx.top[-1] = var::num(
static_cast<int32_t>(ctx.top[-1].tonum())&
static_cast<int32_t>(ctx.top[0].tonum()));
--ctx.top; --ctx.top;
} }
#define op_calc(type)\ #define op_calc(type)\
ctx.top[-1]=var::num(ctx.top[-1].tonum() type ctx.top[0].tonum());\ ctx.top[-1] = var::num(ctx.top[-1].tonum() type ctx.top[0].tonum());\
--ctx.top; --ctx.top;
inline void vm::o_add() {op_calc(+);} inline void vm::o_add() {op_calc(+);}
@ -316,57 +322,57 @@ inline void vm::o_sub() {op_calc(-);}
inline void vm::o_mul() {op_calc(*);} inline void vm::o_mul() {op_calc(*);}
inline void vm::o_div() {op_calc(/);} inline void vm::o_div() {op_calc(/);}
inline void vm::o_lnk() { inline void vm::o_lnk() {
ctx.top[-1]=ngc.newstr(ctx.top[-1].tostr()+ctx.top[0].tostr()); ctx.top[-1] = ngc.newstr(ctx.top[-1].tostr()+ctx.top[0].tostr());
--ctx.top; --ctx.top;
} }
#define op_calc_const(type)\ #define op_calc_const(type)\
ctx.top[0]=var::num(ctx.top[0].tonum() type cnum[imm[ctx.pc]]); ctx.top[0] = var::num(ctx.top[0].tonum() type cnum[imm[ctx.pc]]);
inline void vm::o_addc() {op_calc_const(+);} inline void vm::o_addc() {op_calc_const(+);}
inline void vm::o_subc() {op_calc_const(-);} inline void vm::o_subc() {op_calc_const(-);}
inline void vm::o_mulc() {op_calc_const(*);} inline void vm::o_mulc() {op_calc_const(*);}
inline void vm::o_divc() {op_calc_const(/);} inline void vm::o_divc() {op_calc_const(/);}
inline void vm::o_lnkc() { inline void vm::o_lnkc() {
ctx.top[0]=ngc.newstr(ctx.top[0].tostr()+cstr[imm[ctx.pc]]); ctx.top[0] = ngc.newstr(ctx.top[0].tostr()+cstr[imm[ctx.pc]]);
} }
// top[0] stores the value of memr[0], to avoid being garbage-collected // top[0] stores the value of memr[0], to avoid being garbage-collected
// so when the calculation ends, top-=1, then top-=imm[pc] // so when the calculation ends, top-=1, then top-=imm[pc]
// because this return value is meaningless if on stack when imm[pc]=1 // because this return value is meaningless if on stack when imm[pc] = 1
// like this: func{a+=c;}(); the result of 'a+c' will no be used later, imm[pc]=1 // like this: func{a+=c;}(); the result of 'a+c' will no be used later, imm[pc] = 1
// but if b+=a+=c; the result of 'a+c' will be used later, imm[pc]=0 // but if b+=a+=c; the result of 'a+c' will be used later, imm[pc] = 0
#define op_calc_eq(type)\ #define op_calc_eq(type)\
ctx.top[-1]=ctx.memr[0]=var::num(ctx.memr[0].tonum() type ctx.top[-1].tonum());\ ctx.top[-1] = ctx.memr[0] = var::num(ctx.memr[0].tonum() type ctx.top[-1].tonum());\
ctx.memr=nullptr;\ ctx.memr = nullptr;\
ctx.top-=imm[ctx.pc]+1; ctx.top -= imm[ctx.pc]+1;
inline void vm::o_addeq() {op_calc_eq(+);} inline void vm::o_addeq() {op_calc_eq(+);}
inline void vm::o_subeq() {op_calc_eq(-);} inline void vm::o_subeq() {op_calc_eq(-);}
inline void vm::o_muleq() {op_calc_eq(*);} inline void vm::o_muleq() {op_calc_eq(*);}
inline void vm::o_diveq() {op_calc_eq(/);} inline void vm::o_diveq() {op_calc_eq(/);}
inline void vm::o_lnkeq() { inline void vm::o_lnkeq() {
ctx.top[-1]=ctx.memr[0]=ngc.newstr(ctx.memr[0].tostr()+ctx.top[-1].tostr()); ctx.top[-1] = ctx.memr[0] = ngc.newstr(ctx.memr[0].tostr()+ctx.top[-1].tostr());
ctx.memr=nullptr; ctx.memr = nullptr;
ctx.top-=imm[ctx.pc]+1; ctx.top -= imm[ctx.pc]+1;
} }
inline void vm::o_bandeq() { inline void vm::o_bandeq() {
ctx.top[-1]=ctx.memr[0]=var::num(i32(ctx.memr[0].tonum())&i32(ctx.top[-1].tonum())); ctx.top[-1] = ctx.memr[0] = var::num(i32(ctx.memr[0].tonum())&i32(ctx.top[-1].tonum()));
ctx.memr=nullptr; ctx.memr = nullptr;
ctx.top-=imm[ctx.pc]+1; ctx.top -= imm[ctx.pc]+1;
} }
inline void vm::o_boreq() { inline void vm::o_boreq() {
ctx.top[-1]=ctx.memr[0]=var::num(i32(ctx.memr[0].tonum())|i32(ctx.top[-1].tonum())); ctx.top[-1] = ctx.memr[0] = var::num(i32(ctx.memr[0].tonum())|i32(ctx.top[-1].tonum()));
ctx.memr=nullptr; ctx.memr = nullptr;
ctx.top-=imm[ctx.pc]+1; ctx.top -= imm[ctx.pc]+1;
} }
inline void vm::o_bxoreq() { inline void vm::o_bxoreq() {
ctx.top[-1]=ctx.memr[0]=var::num(i32(ctx.memr[0].tonum())^i32(ctx.top[-1].tonum())); ctx.top[-1] = ctx.memr[0] = var::num(i32(ctx.memr[0].tonum())^i32(ctx.top[-1].tonum()));
ctx.memr=nullptr; ctx.memr = nullptr;
ctx.top-=imm[ctx.pc]+1; ctx.top -= imm[ctx.pc]+1;
} }
// top[0] stores the value of memr[0], to avoid being garbage-collected // top[0] stores the value of memr[0], to avoid being garbage-collected
@ -375,21 +381,21 @@ inline void vm::o_bxoreq() {
// like this: func{a+=1;}(); the result of 'a+1' will no be used later, imm[pc]>>31=1 // like this: func{a+=1;}(); the result of 'a+1' will no be used later, imm[pc]>>31=1
// but if b+=a+=1; the result of 'a+1' will be used later, imm[pc]>>31=0 // but if b+=a+=1; the result of 'a+1' will be used later, imm[pc]>>31=0
#define op_calc_eq_const(type)\ #define op_calc_eq_const(type)\
ctx.top[0]=ctx.memr[0]=var::num(ctx.memr[0].tonum() type cnum[imm[ctx.pc]]);\ ctx.top[0] = ctx.memr[0] = var::num(ctx.memr[0].tonum() type cnum[imm[ctx.pc]]);\
ctx.memr=nullptr; ctx.memr = nullptr;
inline void vm::o_addeqc() {op_calc_eq_const(+);} inline void vm::o_addeqc() {op_calc_eq_const(+);}
inline void vm::o_subeqc() {op_calc_eq_const(-);} inline void vm::o_subeqc() {op_calc_eq_const(-);}
inline void vm::o_muleqc() {op_calc_eq_const(*);} inline void vm::o_muleqc() {op_calc_eq_const(*);}
inline void vm::o_diveqc() {op_calc_eq_const(/);} inline void vm::o_diveqc() {op_calc_eq_const(/);}
inline void vm::o_lnkeqc() { inline void vm::o_lnkeqc() {
ctx.top[0]=ctx.memr[0]=ngc.newstr(ctx.memr[0].tostr()+cstr[imm[ctx.pc]]); ctx.top[0] = ctx.memr[0] = ngc.newstr(ctx.memr[0].tostr()+cstr[imm[ctx.pc]]);
ctx.memr=nullptr; ctx.memr = nullptr;
} }
#define op_calc_eq_const_and_pop(type)\ #define op_calc_eq_const_and_pop(type)\
ctx.top[0]=ctx.memr[0]=var::num(ctx.memr[0].tonum() type cnum[imm[ctx.pc]]);\ ctx.top[0] = ctx.memr[0] = var::num(ctx.memr[0].tonum() type cnum[imm[ctx.pc]]);\
ctx.memr=nullptr;\ ctx.memr = nullptr;\
--ctx.top; --ctx.top;
inline void vm::o_addecp() {op_calc_eq_const_and_pop(+);} inline void vm::o_addecp() {op_calc_eq_const_and_pop(+);}
@ -397,8 +403,8 @@ inline void vm::o_subecp() {op_calc_eq_const_and_pop(-);}
inline void vm::o_mulecp() {op_calc_eq_const_and_pop(*);} inline void vm::o_mulecp() {op_calc_eq_const_and_pop(*);}
inline void vm::o_divecp() {op_calc_eq_const_and_pop(/);} inline void vm::o_divecp() {op_calc_eq_const_and_pop(/);}
inline void vm::o_lnkecp() { inline void vm::o_lnkecp() {
ctx.top[0]=ctx.memr[0]=ngc.newstr(ctx.memr[0].tostr()+cstr[imm[ctx.pc]]); ctx.top[0] = ctx.memr[0] = ngc.newstr(ctx.memr[0].tostr()+cstr[imm[ctx.pc]]);
ctx.memr=nullptr; ctx.memr = nullptr;
--ctx.top; --ctx.top;
} }
@ -408,44 +414,44 @@ inline void vm::o_meq() {
// is that when lnkeq/lnkeqc is called, there will be // is that when lnkeq/lnkeqc is called, there will be
// a new gc object vm_str which is returned by gc::alloc // a new gc object vm_str which is returned by gc::alloc
// this may cause gc, so we should temporarily put it on stack // this may cause gc, so we should temporarily put it on stack
ctx.memr[0]=ctx.top[-1]; ctx.memr[0] = ctx.top[-1];
ctx.memr=nullptr; ctx.memr = nullptr;
ctx.top-=imm[ctx.pc]+1; ctx.top -= imm[ctx.pc]+1;
} }
inline void vm::o_eq() { inline void vm::o_eq() {
var val2=ctx.top[0]; var val2 = ctx.top[0];
var val1=(--ctx.top)[0]; var val1 = (--ctx.top)[0];
if (val1.type==vm_nil && val2.type==vm_nil) { if (val1.type==vm_nil && val2.type==vm_nil) {
ctx.top[0]=one; ctx.top[0] = one;
} else if (val1.type==vm_str && val2.type==vm_str) { } else if (val1.type==vm_str && val2.type==vm_str) {
ctx.top[0]=(val1.str()==val2.str())?one:zero; ctx.top[0] = (val1.str()==val2.str())?one:zero;
} else if ((val1.type==vm_num || val2.type==vm_num) } else if ((val1.type==vm_num || val2.type==vm_num)
&& val1.type!=vm_nil && val2.type!=vm_nil) { && val1.type!=vm_nil && val2.type!=vm_nil) {
ctx.top[0]=(val1.tonum()==val2.tonum())?one:zero; ctx.top[0] = (val1.tonum()==val2.tonum())?one:zero;
} else { } else {
ctx.top[0]=(val1==val2)?one:zero; ctx.top[0] = (val1==val2)?one:zero;
} }
} }
inline void vm::o_neq() { inline void vm::o_neq() {
var val2=ctx.top[0]; var val2 = ctx.top[0];
var val1=(--ctx.top)[0]; var val1 = (--ctx.top)[0];
if (val1.type==vm_nil && val2.type==vm_nil) { if (val1.type==vm_nil && val2.type==vm_nil) {
ctx.top[0]=zero; ctx.top[0] = zero;
} else if (val1.type==vm_str && val2.type==vm_str) { } else if (val1.type==vm_str && val2.type==vm_str) {
ctx.top[0]=(val1.str()!=val2.str())?one:zero; ctx.top[0] = (val1.str()!=val2.str())?one:zero;
} else if ((val1.type==vm_num || val2.type==vm_num) } else if ((val1.type==vm_num || val2.type==vm_num)
&& val1.type!=vm_nil && val2.type!=vm_nil) { && val1.type!=vm_nil && val2.type!=vm_nil) {
ctx.top[0]=(val1.tonum()!=val2.tonum())?one:zero; ctx.top[0] = (val1.tonum()!=val2.tonum())?one:zero;
} else { } else {
ctx.top[0]=(val1!=val2)?one:zero; ctx.top[0] = (val1!=val2)?one:zero;
} }
} }
#define op_cmp(type)\ #define op_cmp(type)\
--ctx.top;\ --ctx.top;\
ctx.top[0]=(ctx.top[0].tonum() type ctx.top[1].tonum())?one:zero; ctx.top[0] = (ctx.top[0].tonum() type ctx.top[1].tonum())?one:zero;
inline void vm::o_less() {op_cmp(<);} inline void vm::o_less() {op_cmp(<);}
inline void vm::o_leq() {op_cmp(<=);} inline void vm::o_leq() {op_cmp(<=);}
@ -453,7 +459,7 @@ inline void vm::o_grt() {op_cmp(>);}
inline void vm::o_geq() {op_cmp(>=);} inline void vm::o_geq() {op_cmp(>=);}
#define op_cmp_const(type)\ #define op_cmp_const(type)\
ctx.top[0]=(ctx.top[0].tonum() type cnum[imm[ctx.pc]])?one:zero; ctx.top[0] = (ctx.top[0].tonum() type cnum[imm[ctx.pc]])?one:zero;
inline void vm::o_lessc() {op_cmp_const(<);} inline void vm::o_lessc() {op_cmp_const(<);}
inline void vm::o_leqc() {op_cmp_const(<=);} inline void vm::o_leqc() {op_cmp_const(<=);}
@ -465,21 +471,21 @@ inline void vm::o_pop() {
} }
inline void vm::o_jmp() { inline void vm::o_jmp() {
ctx.pc=imm[ctx.pc]-1; ctx.pc = imm[ctx.pc]-1;
} }
inline void vm::o_jt() { inline void vm::o_jt() {
// jump true needs to reserve the result on stack // jump true needs to reserve the result on stack
// because conditional expression in nasal has return value // because conditional expression in nasal has return value
if (cond(ctx.top[0])) { if (cond(ctx.top[0])) {
ctx.pc=imm[ctx.pc]-1; ctx.pc = imm[ctx.pc]-1;
} }
} }
inline void vm::o_jf() { inline void vm::o_jf() {
// jump false doesn't need to reserve result // jump false doesn't need to reserve result
if (!cond(ctx.top[0])) { if (!cond(ctx.top[0])) {
ctx.pc=imm[ctx.pc]-1; ctx.pc = imm[ctx.pc]-1;
} }
--ctx.top; --ctx.top;
} }
@ -489,48 +495,48 @@ inline void vm::o_cnt() {
die("must use vector in forindex/foreach"); die("must use vector in forindex/foreach");
return; return;
} }
(++ctx.top)[0]=var::cnt(-1); (++ctx.top)[0] = var::cnt(-1);
} }
inline void vm::o_findex() { inline void vm::o_findex() {
if ((usize)(++ctx.top[0].cnt())>=ctx.top[-1].vec().size()) { if ((usize)(++ctx.top[0].cnt())>=ctx.top[-1].vec().size()) {
ctx.pc=imm[ctx.pc]-1; ctx.pc = imm[ctx.pc]-1;
return; return;
} }
ctx.top[1]=var::num(ctx.top[0].cnt()); ctx.top[1] = var::num(ctx.top[0].cnt());
++ctx.top; ++ctx.top;
} }
inline void vm::o_feach() { inline void vm::o_feach() {
auto& ref=ctx.top[-1].vec().elems; auto& ref = ctx.top[-1].vec().elems;
if ((usize)(++ctx.top[0].cnt())>=ref.size()) { if ((usize)(++ctx.top[0].cnt())>=ref.size()) {
ctx.pc=imm[ctx.pc]-1; ctx.pc = imm[ctx.pc]-1;
return; return;
} }
ctx.top[1]=ref[ctx.top[0].cnt()]; ctx.top[1] = ref[ctx.top[0].cnt()];
++ctx.top; ++ctx.top;
} }
inline void vm::o_callg() { inline void vm::o_callg() {
// get main stack directly // get main stack directly
(++ctx.top)[0]=stack[imm[ctx.pc]]; (++ctx.top)[0] = stack[imm[ctx.pc]];
} }
inline void vm::o_calll() { inline void vm::o_calll() {
(++ctx.top)[0]=ctx.localr[imm[ctx.pc]]; (++ctx.top)[0] = ctx.localr[imm[ctx.pc]];
} }
inline void vm::o_upval() { inline void vm::o_upval() {
(++ctx.top)[0]=ctx.funcr.func() (++ctx.top)[0] = ctx.funcr.func()
.upval[(imm[ctx.pc]>>16)&0xffff] .upval[(imm[ctx.pc]>>16)&0xffff]
.upval()[imm[ctx.pc]&0xffff]; .upval()[imm[ctx.pc]&0xffff];
} }
inline void vm::o_callv() { inline void vm::o_callv() {
var val=ctx.top[0]; var val = ctx.top[0];
var vec=(--ctx.top)[0]; var vec = (--ctx.top)[0];
if (vec.type==vm_vec) { if (vec.type==vm_vec) {
ctx.top[0]=vec.vec().get_val(val.tonum()); ctx.top[0] = vec.vec().get_val(val.tonum());
if (ctx.top[0].type==vm_none) { if (ctx.top[0].type==vm_none) {
die("out of range:"+std::to_string(val.tonum())); die("out of range:"+std::to_string(val.tonum()));
return; return;
@ -540,12 +546,12 @@ inline void vm::o_callv() {
die("must use string as the key"); die("must use string as the key");
return; return;
} }
ctx.top[0]=vec.hash().get_val(val.str()); ctx.top[0] = vec.hash().get_val(val.str());
if (ctx.top[0].type==vm_none) { if (ctx.top[0].type==vm_none) {
die("cannot find member \""+val.str()+"\""); die("cannot find member \""+val.str()+"\"");
return; return;
} else if (ctx.top[0].type==vm_func) { } else if (ctx.top[0].type==vm_func) {
ctx.top[0].func().local[0]=val; // 'me' ctx.top[0].func().local[0] = val; // 'me'
} }
} else if (vec.type==vm_str) { } else if (vec.type==vm_str) {
auto& str = vec.str(); auto& str = vec.str();
@ -555,7 +561,17 @@ inline void vm::o_callv() {
die("out of range:"+std::to_string(val.tonum())); die("out of range:"+std::to_string(val.tonum()));
return; return;
} }
ctx.top[0]=var::num(f64((u8)str[num>=0? num:num+len])); ctx.top[0] = var::num(f64((u8)str[num>=0? num:num+len]));
} else if (vec.type==vm_map) {
if (val.type!=vm_str) {
die("must use string as the key");
return;
}
ctx.top[0] = vec.map().get_val(val.str());
if (ctx.top[0].type==vm_none) {
die("cannot find symbol \""+val.str()+"\"");
return;
}
} else { } else {
die("must call a vector/hash/string"); die("must call a vector/hash/string");
return; return;
@ -563,13 +579,13 @@ inline void vm::o_callv() {
} }
inline void vm::o_callvi() { inline void vm::o_callvi() {
var val=ctx.top[0]; var val = ctx.top[0];
if (val.type!=vm_vec) { if (val.type!=vm_vec) {
die("must use a vector"); die("must use a vector");
return; return;
} }
// cannot use operator[],because this may cause overflow // cannot use operator[],because this may cause overflow
(++ctx.top)[0]=val.vec().get_val(imm[ctx.pc]); (++ctx.top)[0] = val.vec().get_val(imm[ctx.pc]);
if (ctx.top[0].type==vm_none) { if (ctx.top[0].type==vm_none) {
die("out of range:"+std::to_string(imm[ctx.pc])); die("out of range:"+std::to_string(imm[ctx.pc]));
return; return;
@ -577,30 +593,37 @@ inline void vm::o_callvi() {
} }
inline void vm::o_callh() { inline void vm::o_callh() {
var val=ctx.top[0]; var val = ctx.top[0];
if (val.type!=vm_hash) { if (val.type!=vm_hash && val.type!=vm_map) {
die("must call a hash"); die("must call a hash");
return; return;
} }
ctx.top[0]=val.hash().get_val(cstr[imm[ctx.pc]]); const auto& str = cstr[imm[ctx.pc]];
if (val.type==vm_hash) {
ctx.top[0] = val.hash().get_val(str);
} else {
ctx.top[0] = val.map().get_val(str);
}
if (ctx.top[0].type==vm_none) { if (ctx.top[0].type==vm_none) {
die("member \""+cstr[imm[ctx.pc]]+"\" does not exist"); val.type==vm_hash?
die("member \"" + str + "\" does not exist"):
die("cannot find symbol \"" + str + "\"");
return; return;
} else if (ctx.top[0].type==vm_func) { } else if (ctx.top[0].type==vm_func) {
ctx.top[0].func().local[0]=val; // 'me' ctx.top[0].func().local[0] = val; // 'me'
} }
} }
inline void vm::o_callfv() { inline void vm::o_callfv() {
u32 argc=imm[ctx.pc]; // arguments counter u32 argc = imm[ctx.pc]; // arguments counter
var* local=ctx.top-argc+1; // arguments begin address var* local = ctx.top-argc+1; // arguments begin address
if (local[-1].type!=vm_func) { if (local[-1].type!=vm_func) {
die("must call a function"); die("must call a function");
return; return;
} }
auto& func=local[-1].func(); auto& func = local[-1].func();
var tmp=local[-1]; var tmp = local[-1];
local[-1]=ctx.funcr; local[-1] = ctx.funcr;
ctx.funcr=tmp; ctx.funcr=tmp;
// top-argc+lsize(local) +1(old pc) +1(old localr) +1(old upvalr) // top-argc+lsize(local) +1(old pc) +1(old localr) +1(old upvalr)
if (ctx.top-argc+func.lsize+3>=ctx.canary) { if (ctx.top-argc+func.lsize+3>=ctx.canary) {
@ -608,15 +631,15 @@ inline void vm::o_callfv() {
return; return;
} }
// parameter size is func->psize-1, 1 is reserved for "me" // parameter size is func->psize-1, 1 is reserved for "me"
u32 psize=func.psize-1; u32 psize = func.psize-1;
if (argc<psize && func.local[argc+1].type==vm_none) { if (argc<psize && func.local[argc+1].type==vm_none) {
die("lack argument(s)"); die("lack argument(s)");
return; return;
} }
var dynamic=nil; var dynamic = nil;
if (func.dpara>=0) { // load dynamic arguments if (func.dpara>=0) { // load dynamic arguments
dynamic=ngc.alloc(vm_vec); dynamic = ngc.alloc(vm_vec);
for(u32 i=psize;i<argc;++i) { for(u32 i=psize;i<argc;++i) {
dynamic.vec().elems.push_back(local[i]); dynamic.vec().elems.push_back(local[i]);
} }
@ -626,42 +649,42 @@ inline void vm::o_callfv() {
// then all the available values the vector needs // then all the available values the vector needs
// are all outside the stack top and may be // are all outside the stack top and may be
// collected incorrectly // collected incorrectly
ctx.top=local+func.lsize; ctx.top = local+func.lsize;
u32 min_size=(std::min)(psize, argc); // avoid error in MSVC u32 min_size = (std::min)(psize, argc); // avoid error in MSVC
for(u32 i=min_size;i>=1;--i) { // load arguments for(u32 i=min_size;i>=1;--i) { // load arguments
local[i]=local[i-1]; local[i] = local[i-1];
} }
local[0]=func.local[0];// load "me" local[0] = func.local[0];// load "me"
// load local scope & default arguments // load local scope & default arguments
for(u32 i=min_size+1;i<func.lsize;++i) { for(u32 i=min_size+1;i<func.lsize;++i) {
local[i]=func.local[i]; local[i] = func.local[i];
} }
if (func.dpara>=0) { if (func.dpara>=0) {
local[psize+1]=dynamic; local[psize+1] = dynamic;
} }
ctx.top[0]=ctx.upvalr; ctx.top[0] = ctx.upvalr;
(++ctx.top)[0]=var::addr(ctx.localr); (++ctx.top)[0] = var::addr(ctx.localr);
(++ctx.top)[0]=var::ret(ctx.pc); (++ctx.top)[0] = var::ret(ctx.pc);
ctx.pc=func.entry-1; ctx.pc=func.entry-1;
ctx.localr=local; ctx.localr = local;
ctx.upvalr=nil; ctx.upvalr = nil;
} }
inline void vm::o_callfh() { inline void vm::o_callfh() {
auto& hash=ctx.top[0].hash().elems; auto& hash = ctx.top[0].hash().elems;
if (ctx.top[-1].type!=vm_func) { if (ctx.top[-1].type!=vm_func) {
die("must call a function"); die("must call a function");
return; return;
} }
auto& func=ctx.top[-1].func(); auto& func = ctx.top[-1].func();
var tmp=ctx.top[-1]; var tmp = ctx.top[-1];
ctx.top[-1]=ctx.funcr; ctx.top[-1] = ctx.funcr;
ctx.funcr=tmp; ctx.funcr = tmp;
// top -1(hash) +lsize(local) +1(old pc) +1(old localr) +1(old upvalr) // top -1(hash) +lsize(local) +1(old pc) +1(old localr) +1(old upvalr)
if (ctx.top+func.lsize+2>=ctx.canary) { if (ctx.top+func.lsize+2>= ctx.canary) {
die("stack overflow"); die("stack overflow");
return; return;
} }
@ -670,42 +693,42 @@ inline void vm::o_callfh() {
return; return;
} }
var* local=ctx.top; var* local = ctx.top;
ctx.top+=func.lsize; ctx.top += func.lsize;
for(u32 i=0;i<func.lsize;++i) { for(u32 i = 0; i<func.lsize; ++i) {
local[i]=func.local[i]; local[i] = func.local[i];
} }
for(auto& i:func.keys) { for(const auto& i : func.keys) {
auto& key=cstr[i.first]; auto& key = cstr[i.first];
if (hash.count(key)) { if (hash.count(key)) {
local[i.second]=hash[key]; local[i.second] = hash[key];
} else if (local[i.second].type==vm_none) { } else if (local[i.second].type==vm_none) {
die("lack argument(s): \""+key+"\""); die("lack argument(s): \""+key+"\"");
return; return;
} }
} }
ctx.top[0]=ctx.upvalr; ctx.top[0] = ctx.upvalr;
(++ctx.top)[0]=var::addr(ctx.localr); (++ctx.top)[0] = var::addr(ctx.localr);
(++ctx.top)[0]=var::ret(ctx.pc); // rewrite top with vm_ret (++ctx.top)[0] = var::ret(ctx.pc); // rewrite top with vm_ret
ctx.pc=func.entry-1; ctx.pc=func.entry-1;
ctx.localr=local; ctx.localr = local;
ctx.upvalr=nil; ctx.upvalr = nil;
} }
inline void vm::o_callb() { inline void vm::o_callb() {
// reserve place for builtin function return, // reserve place for builtin function return,
// this code is written for coroutine // this code is written for coroutine
(++ctx.top)[0]=nil; (++ctx.top)[0] = nil;
// if running a builtin function about coroutine // if running a builtin 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=(*builtin[imm[ctx.pc]].func)(ctx.localr, ngc); var tmp = (*builtin[imm[ctx.pc]].func)(ctx.localr, 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] = tmp;
// 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) {
@ -720,7 +743,7 @@ inline void vm::o_slcbeg() {
// +--------------+ // +--------------+
// | resource_vec | <-- top[-1] // | resource_vec | <-- top[-1]
// +--------------+ // +--------------+
(++ctx.top)[0]=ngc.alloc(vm_vec); (++ctx.top)[0] = ngc.alloc(vm_vec);
if (ctx.top[-1].type!=vm_vec) { if (ctx.top[-1].type!=vm_vec) {
die("must slice a vector"); die("must slice a vector");
return; return;
@ -728,13 +751,13 @@ inline void vm::o_slcbeg() {
} }
inline void vm::o_slcend() { inline void vm::o_slcend() {
ctx.top[-1]=ctx.top[0]; ctx.top[-1] = ctx.top[0];
--ctx.top; --ctx.top;
} }
inline void vm::o_slc() { inline void vm::o_slc() {
var val=(ctx.top--)[0]; var val = (ctx.top--)[0];
var res=ctx.top[-1].vec().get_val(val.tonum()); var res = ctx.top[-1].vec().get_val(val.tonum());
if (res.type==vm_none) { if (res.type==vm_none) {
die("index "+std::to_string(val.tonum())+" out of range"); die("index "+std::to_string(val.tonum())+" out of range");
return; return;
@ -743,60 +766,63 @@ inline void vm::o_slc() {
} }
inline void vm::o_slc2() { inline void vm::o_slc2() {
var val2=(ctx.top--)[0]; var val2 = (ctx.top--)[0];
var val1=(ctx.top--)[0]; var val1 = (ctx.top--)[0];
auto& ref=ctx.top[-1].vec().elems; auto& ref = ctx.top[-1].vec().elems;
auto& aim=ctx.top[0].vec().elems; auto& aim = ctx.top[0].vec().elems;
u8 type1=val1.type,type2=val2.type; u8 type1 = val1.type,type2=val2.type;
i32 num1=val1.tonum(); i32 num1 = val1.tonum();
i32 num2=val2.tonum(); i32 num2 = val2.tonum();
i32 size=ref.size(); i32 size = ref.size();
if (type1==vm_nil && type2==vm_nil) { if (type1==vm_nil && type2==vm_nil) {
num1=0; num1 = 0;
num2=size-1; num2 = size-1;
} else if (type1==vm_nil && type2!=vm_nil) { } else if (type1==vm_nil && type2!=vm_nil) {
num1=num2<0? -size:0; num1 = num2<0? -size:0;
} else if (type1!=vm_nil && type2==vm_nil) { } else if (type1!=vm_nil && type2==vm_nil) {
num2=num1<0? -1:size-1; num2 = num1<0? -1:size-1;
} }
if (num1<-size || num1>=size || num2<-size || num2>=size) { if (num1<-size || num1>=size || num2<-size || num2>=size) {
die("index "+std::to_string(num1)+":"+std::to_string(num2)+" out of range"); die("index "+std::to_string(num1)+":"+std::to_string(num2)+" out of range");
return; return;
} else if (num1<=num2) { } else if (num1<=num2) {
for(i32 i=num1;i<=num2;++i) { for(i32 i = num1; i<=num2; ++i) {
aim.push_back(i>=0?ref[i]:ref[i+size]); aim.push_back(i>=0? ref[i]:ref[i+size]);
} }
} }
} }
inline void vm::o_mcallg() { inline void vm::o_mcallg() {
ctx.memr=stack+imm[ctx.pc]; ctx.memr = stack+imm[ctx.pc];
(++ctx.top)[0]=ctx.memr[0]; (++ctx.top)[0] = ctx.memr[0];
// push value in this memory space on stack // push value in this memory space on stack
// to avoid being garbage collected // to avoid being garbage collected
} }
inline void vm::o_mcalll() { inline void vm::o_mcalll() {
ctx.memr=ctx.localr+imm[ctx.pc]; ctx.memr = ctx.localr+imm[ctx.pc];
(++ctx.top)[0]=ctx.memr[0]; (++ctx.top)[0] = ctx.memr[0];
// push value in this memory space on stack // push value in this memory space on stack
// to avoid being garbage collected // to avoid being garbage collected
} }
inline void vm::o_mupval() { inline void vm::o_mupval() {
ctx.memr=&(ctx.funcr.func().upval[(imm[ctx.pc]>>16)&0xffff].upval()[imm[ctx.pc]&0xffff]); ctx.memr = &(
(++ctx.top)[0]=ctx.memr[0]; ctx.funcr.func()
.upval[(imm[ctx.pc]>>16)&0xffff]
.upval()[imm[ctx.pc]&0xffff]);
(++ctx.top)[0] = ctx.memr[0];
// push value in this memory space on stack // push value in this memory space on stack
// to avoid being garbage collected // to avoid being garbage collected
} }
inline void vm::o_mcallv() { inline void vm::o_mcallv() {
var val=ctx.top[0]; // index var val = ctx.top[0]; // index
var vec=(--ctx.top)[0]; // mcall vector, reserved on stack to avoid gc var vec = (--ctx.top)[0]; // mcall vector, reserved on stack to avoid gc
if (vec.type==vm_vec) { if (vec.type==vm_vec) {
ctx.memr=vec.vec().get_mem(val.tonum()); ctx.memr = vec.vec().get_mem(val.tonum());
if (!ctx.memr) { if (!ctx.memr) {
die("index "+std::to_string(val.tonum())+" out of range"); die("index "+std::to_string(val.tonum())+" out of range");
return; return;
@ -810,8 +836,19 @@ inline void vm::o_mcallv() {
auto& str = val.str(); auto& str = val.str();
ctx.memr = ref.get_mem(str); ctx.memr = ref.get_mem(str);
if (!ctx.memr) { if (!ctx.memr) {
ref.elems[str]=nil; ref.elems[str] = nil;
ctx.memr=ref.get_mem(str); ctx.memr = ref.get_mem(str);
}
} else if (vec.type==vm_map) {
if (val.type!=vm_str) {
die("key must be string");
return;
}
auto& ref = vec.map();
auto& str = val.str();
ctx.memr = ref.get_mem(str);
if (!ctx.memr) {
die("cannot find symbol \"" + str + "\"");
} }
} else { } else {
die("cannot get memory space in this type"); die("cannot get memory space in this type");
@ -820,17 +857,24 @@ inline void vm::o_mcallv() {
} }
inline void vm::o_mcallh() { inline void vm::o_mcallh() {
var hash=ctx.top[0]; // mcall hash, reserved on stack to avoid gc var hash = ctx.top[0]; // mcall hash, reserved on stack to avoid gc
if (hash.type!=vm_hash) { if (hash.type!=vm_hash && hash.type!=vm_map) {
die("must call a hash"); die("must call a hash");
return; return;
} }
auto& ref=hash.hash(); auto& str = cstr[imm[ctx.pc]];
auto& str=cstr[imm[ctx.pc]]; if (hash.type==vm_map) {
ctx.memr=ref.get_mem(str); ctx.memr = hash.map().get_mem(str);
if (!ctx.memr) {
die("cannot find symbol \"" + str + "\"");
}
return;
}
auto& ref = hash.hash();
ctx.memr = ref.get_mem(str);
if (!ctx.memr) { // create a new key if (!ctx.memr) { // create a new key
ref.elems[str]=nil; ref.elems[str] = nil;
ctx.memr=ref.get_mem(str); ctx.memr = ref.get_mem(str);
} }
} }
@ -849,26 +893,26 @@ inline void vm::o_ret() {
* | old funcr | <- old function stored in funcr * | old funcr | <- old function stored in funcr
* +-------------+ * +-------------+
*/ */
var ret =ctx.top[0]; var ret = ctx.top[0];
var* local=ctx.localr; var* local = ctx.localr;
var func =ctx.funcr; var func = ctx.funcr;
var up =ctx.upvalr; var up = ctx.upvalr;
ctx.pc =ctx.top[-1].ret(); ctx.pc = ctx.top[-1].ret();
ctx.localr=ctx.top[-2].addr(); ctx.localr = ctx.top[-2].addr();
ctx.upvalr=ctx.top[-3]; ctx.upvalr = ctx.top[-3];
ctx.top=local-1; ctx.top=local-1;
ctx.funcr=ctx.top[0]; ctx.funcr = ctx.top[0];
ctx.top[0]=ret; // rewrite func with returned value ctx.top[0] = ret; // rewrite func with returned value
if (up.type==vm_upval) { // synchronize upvalue if (up.type==vm_upval) { // synchronize upvalue
auto& upval=up.upval(); auto& upval = up.upval();
auto size=func.func().lsize; auto size = func.func().lsize;
upval.onstk=false; upval.onstk = false;
upval.elems.resize(size); upval.elems.resize(size);
for(u32 i=0;i<size;++i) { for(u32 i = 0; i<size; ++i) {
upval.elems[i]=local[i]; upval.elems[i] = local[i];
} }
} }

15
test/globals_test.nas Normal file
View File

@ -0,0 +1,15 @@
# test if globals run correctly
println(globals);
println(keys(globals));
foreach(var i; keys(globals)) {
println("var ", i, " = ", typeof(globals[i]), ";");
}
var test_func = nil;
globals.test_func = func() {
println("succeed!");
}
println();
println(globals.test_func);
globals.test_func();

View File

@ -1,5 +1,6 @@
# hexdump.nas by ValKmjolnir # hexdump.nas by ValKmjolnir
# 2021/8/13 # 2021/8/13
import.std.file;
# init # init
var hex=func(){ var hex=func(){
@ -20,22 +21,7 @@ var hex=func(){
# read file # read file
var s=func(){ var s=func(){
var filename=[ var filename = find_all_files_with_extension("./src","cpp","h");
"main.cpp",
"nasal_ast.h",
"nasal_builtin.h",
"nasal_codegen.h",
"nasal_dbg.h",
"nasal_err.h",
"nasal_gc.h",
"nasal_import.h",
"nasal_lexer.h",
"nasal_opt.h",
"nasal_parse.h",
"nasal_vm.h",
"nasal.ebnf",
"nasal.h"
];
if(size(runtime.argv())!=0){ if(size(runtime.argv())!=0){
var argv=runtime.argv(); var argv=runtime.argv();
if(argv[0]=="-h" or argv[0]=="--h"){ if(argv[0]=="-h" or argv[0]=="--h"){