From b4482792c8bef67b330fdf14faadb6d49df32177 Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Thu, 6 Jul 2023 22:10:07 +0800 Subject: [PATCH] :technologist: add important symbol "globals" --- makefile | 1 + src/nasal_builtin.cpp | 13 +- src/nasal_codegen.cpp | 1 + src/nasal_codegen.h | 9 +- src/nasal_dbg.cpp | 7 +- src/nasal_gc.cpp | 47 ++++- src/nasal_gc.h | 26 ++- src/nasal_vm.cpp | 17 +- src/nasal_vm.h | 470 +++++++++++++++++++++++------------------- test/globals_test.nas | 15 ++ test/hexdump.nas | 18 +- 11 files changed, 381 insertions(+), 243 deletions(-) create mode 100644 test/globals_test.nas diff --git a/makefile b/makefile index 55ec0db..6aeac4a 100644 --- a/makefile +++ b/makefile @@ -100,6 +100,7 @@ test:nasal -@ ./nasal -d test/exception.nas @ ./nasal -t -d test/fib.nas @ ./nasal -e test/filesystem.nas + @ ./nasal -t -d test/globals_test.nas @ ./nasal -d test/hexdump.nas @ ./nasal -e test/json.nas @ ./nasal -e test/leetcode1319.nas diff --git a/src/nasal_builtin.cpp b/src/nasal_builtin.cpp index 83ed4fa..73a90c7 100644 --- a/src/nasal_builtin.cpp +++ b/src/nasal_builtin.cpp @@ -334,14 +334,20 @@ var builtin_delete(var* local, gc& ngc) { var builtin_keys(var* local, gc& ngc) { 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"); } // avoid being sweeped var res=ngc.temp=ngc.alloc(vm_vec); auto& vec=res.vec().elems; - for(auto& iter:hash.hash().elems) { - vec.push_back(ngc.newstr(iter.first)); + if (hash.type==vm_hash) { + for(const auto& iter : hash.hash().elems) { + 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; return res; @@ -372,6 +378,7 @@ var builtin_type(var* local, gc& ngc) { case vm_func: return ngc.newstr("func"); break; case vm_obj: return ngc.newstr("obj"); break; case vm_co: return ngc.newstr("coroutine");break; + case vm_map: return ngc.newstr("mapper"); break; } return nil; } diff --git a/src/nasal_codegen.cpp b/src/nasal_codegen.cpp index 0312fec..fee4dbb 100644 --- a/src/nasal_codegen.cpp +++ b/src/nasal_codegen.cpp @@ -1091,6 +1091,7 @@ const error& codegen::compile(parse& parse, linker& import) { fileindex = 0; file = import.filelist().data(); in_iterloop.push(0); + add_symbol("globals"); find_symbol(parse.tree()); // search symbols first gen(op_intg, global.size(), 0); block_gen(parse.tree()); // generate main block diff --git a/src/nasal_codegen.h b/src/nasal_codegen.h index 9114c09..706d0c2 100644 --- a/src/nasal_codegen.h +++ b/src/nasal_codegen.h @@ -25,8 +25,8 @@ private: error& err; const std::string* file; std::stack in_iterloop; - std::unordered_map const_number_map; - std::unordered_map const_string_map; + std::unordered_map const_number_map; + std::unordered_map const_string_map; std::vector const_number_table; std::vector const_string_table; std::vector code; @@ -35,10 +35,10 @@ private: // symbol table // global : max STACK_DEPTH-1 values - std::unordered_map global; + std::unordered_map global; // local : max 32768 upvalues 65536 values // but in fact local scope also has less than STACK_DEPTH value - std::list> local; + std::list> local; void check_id_exist(identifier*); @@ -97,6 +97,7 @@ public: const std::vector& strs() const {return const_string_table;} const std::vector& nums() const {return const_number_table;} const std::vector& codes() const {return code;} + const std::unordered_map& globals() const {return global;} public: codegen(error& e): fileindex(0), err(e), file(nullptr) {} diff --git a/src/nasal_dbg.cpp b/src/nasal_dbg.cpp index eab3571..d88e181 100644 --- a/src/nasal_dbg.cpp +++ b/src/nasal_dbg.cpp @@ -163,7 +163,12 @@ void dbg::run( const std::vector& argv) { verbose=true; 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}; typedef void (dbg::*nafunc)(); const nafunc oprs[]={ diff --git a/src/nasal_gc.cpp b/src/nasal_gc.cpp index b1888f5..8cccc55 100644 --- a/src/nasal_gc.cpp +++ b/src/nasal_gc.cpp @@ -153,6 +153,35 @@ void nas_co::clear() { 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) { mark = gc_status::collected; 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_obj: ptr.obj = new nas_ghost; 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_obj: delete ptr.obj; break; case vm_co: delete ptr.co; break; + case vm_map: delete ptr.map; break; } type=vm_nil; } @@ -190,6 +221,7 @@ void nas_val::clear() { case vm_upval:ptr.upval->clear(); break; case vm_obj: ptr.obj->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_obj: out << ref.obj(); break; case vm_co: out << ""; break; + case vm_map: out << ref.map(); break; } return out; } @@ -300,6 +333,10 @@ nas_co& var::co() { return *val.gcobj->ptr.co; } +nas_map& var::map() { + return *val.gcobj->ptr.map; +} + void gc::mark() { std::vector bfs; mark_context(bfs); @@ -345,6 +382,7 @@ void gc::mark_var(std::vector& bfs_queue, var& value) { case vm_func: mark_func(bfs_queue, value.func()); break; case vm_upval: mark_upval(bfs_queue, value.upval()); break; case vm_co: mark_co(bfs_queue, value.co()); break; + case vm_map: mark_map(bfs_queue, value.map()); break; default: break; } } @@ -384,6 +422,12 @@ void gc::mark_co(std::vector& bfs_queue, nas_co& co) { } } +void gc::mark_map(std::vector& bfs_queue, nas_map& mp) { + for(const auto& i : mp.mapper) { + bfs_queue.push_back(*i.second); + } +} + void gc::sweep() { for(auto i : memory) { if (i->mark==gc_status::uncollected) { @@ -469,7 +513,8 @@ void gc::info() { "function ", "upvalue ", "object ", - "coroutine" + "coroutine", + "mapper " }; usize indent = 0; diff --git a/src/nasal_gc.h b/src/nasal_gc.h index d48d15b..9cde692 100644 --- a/src/nasal_gc.h +++ b/src/nasal_gc.h @@ -47,10 +47,11 @@ enum vm_type:u8 { vm_func, vm_upval, 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 { suspended, @@ -70,6 +71,7 @@ struct nas_func; // function(lambda) struct nas_upval; // upvalue struct nas_ghost; // objects struct nas_co; // coroutine +struct nas_map; // mapper struct nas_val; // nas_val includes gc-managed types struct var { @@ -127,6 +129,7 @@ public: nas_upval& upval(); nas_ghost& obj(); nas_co& co(); + nas_map& map(); }; struct nas_vec { @@ -295,6 +298,19 @@ struct nas_co { void clear(); }; +struct nas_map { + bool printed = false; + std::unordered_map mapper; + + nas_map() {} + void clear() { + mapper.clear(); + } + + var get_val(const std::string&); + var* get_mem(const std::string&); +}; + struct nas_val { gc_status mark; u8 type; // value type @@ -307,6 +323,7 @@ struct nas_val { nas_upval* upval; nas_ghost* obj; nas_co* co; + nas_map* map; } ptr; nas_val(u8); @@ -316,6 +333,7 @@ struct nas_val { std::ostream& operator<<(std::ostream&, nas_vec&); std::ostream& operator<<(std::ostream&, nas_hash&); +std::ostream& operator<<(std::ostream&, nas_map&); std::ostream& operator<<(std::ostream&, var&); const var zero = var::num(0); @@ -348,7 +366,8 @@ struct gc { 128, // vm_func 256, // vm_upval 16, // vm_obj - 16 // vm_co + 16, // vm_co + 2, // vm_map }; /* values for analysis */ @@ -372,6 +391,7 @@ private: void mark_func(std::vector&, nas_func&); void mark_upval(std::vector&, nas_upval&); void mark_co(std::vector&, nas_co&); + void mark_map(std::vector&, nas_map&); void sweep(); public: diff --git a/src/nasal_vm.cpp b/src/nasal_vm.cpp index 9f6f679..27e12e1 100644 --- a/src/nasal_vm.cpp +++ b/src/nasal_vm.cpp @@ -2,8 +2,9 @@ void vm::init( const std::vector& strs, - const std::vector& nums, + const std::vector& nums, const std::vector& code, + const std::unordered_map& global, const std::vector& filenames, const std::vector& argv ) { @@ -27,6 +28,13 @@ void vm::init( /* init gc */ 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) { @@ -204,7 +212,12 @@ void vm::run( const bool 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 const void* oprs[]={ &&vmexit, &&intg, &&intl, &&loadg, diff --git a/src/nasal_vm.h b/src/nasal_vm.h index caa9bfa..673d893 100644 --- a/src/nasal_vm.h +++ b/src/nasal_vm.h @@ -39,6 +39,7 @@ protected: const std::vector&, const std::vector&, const std::vector&, + const std::unordered_map&, const std::vector&, const std::vector&); @@ -155,15 +156,14 @@ public: const codegen&, const linker&, const std::vector&, - const bool - ); + const bool); }; inline bool vm::cond(var& val) { if (val.type==vm_num) { return val.num(); } 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 false; @@ -171,144 +171,150 @@ inline bool vm::cond(var& val) { inline void vm::o_intg() { // global values store on stack - ctx.top+=imm[ctx.pc]; - --ctx.top;// point to the top + ctx.top += imm[ctx.pc]; + // point to the top + --ctx.top; } inline void vm::o_intl() { 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() { - stack[imm[ctx.pc]]=(ctx.top--)[0]; + stack[imm[ctx.pc]] = (ctx.top--)[0]; } 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() { 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() { - (++ctx.top)[0]=var::num(cnum[imm[ctx.pc]]); + (++ctx.top)[0] = var::num(cnum[imm[ctx.pc]]); } inline void vm::o_pnil() { - (++ctx.top)[0]=nil; + (++ctx.top)[0] = nil; } 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() { - var newv=ngc.alloc(vm_vec); - auto& vec=newv.vec().elems; + var newv = ngc.alloc(vm_vec); + auto& vec = newv.vec().elems; vec.resize(imm[ctx.pc]); // use top-=imm[pc]-1 here will cause error if imm[pc] is 0 - ctx.top=ctx.top-imm[ctx.pc]+1; - for(u32 i=0;isize has 1 place reserved for "me" - func.keys[imm[ctx.pc]]=func.psize; - func.local[func.psize++]=var::none(); + func.keys[imm[ctx.pc]] = func.psize; + func.local[func.psize++] = var::none(); } inline void vm::o_deft() { - var val=ctx.top[0]; - nas_func& func=(--ctx.top)[0].func(); + var val = ctx.top[0]; + auto& func = (--ctx.top)[0].func(); // func->size has 1 place reserved for "me" - func.keys[imm[ctx.pc]]=func.psize; - func.local[func.psize++]=val; + func.keys[imm[ctx.pc]] = func.psize; + func.local[func.psize++] = val; } 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() { - var val=ctx.top[0]; + var val = ctx.top[0]; switch(val.type) { - case vm_nil:ctx.top[0]=one;break; - case vm_num:ctx.top[0]=val.num()?zero:one;break; - case vm_str:{ - const f64 num=str2num(val.str().c_str()); + case vm_nil: ctx.top[0] = one; break; + case vm_num: ctx.top[0] = val.num()? zero:one; break; + case vm_str: { + const f64 num = str2num(val.str().c_str()); if (std::isnan(num)) { - ctx.top[0]=var::num((f64)val.str().empty()); + ctx.top[0] = var::num((f64)val.str().empty()); } else { - ctx.top[0]=num?zero:one; + ctx.top[0] = num? zero:one; } } break; - default:{ + default: die("incorrect value type"); return; - } break; } } 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() { - ctx.top[0]=var::num(~static_cast(ctx.top[0].num())); + ctx.top[0] = var::num(~static_cast(ctx.top[0].num())); } inline void vm::o_btor() { - ctx.top[-1]=var::num(static_cast(ctx.top[-1].tonum())|static_cast(ctx.top[0].tonum())); + ctx.top[-1] = var::num( + static_cast(ctx.top[-1].tonum())| + static_cast(ctx.top[0].tonum())); --ctx.top; } inline void vm::o_btxor() { - ctx.top[-1]=var::num(static_cast(ctx.top[-1].tonum())^static_cast(ctx.top[0].tonum())); + ctx.top[-1] = var::num( + static_cast(ctx.top[-1].tonum())^ + static_cast(ctx.top[0].tonum())); --ctx.top; } inline void vm::o_btand() { - ctx.top[-1]=var::num(static_cast(ctx.top[-1].tonum())&static_cast(ctx.top[0].tonum())); + ctx.top[-1] = var::num( + static_cast(ctx.top[-1].tonum())& + static_cast(ctx.top[0].tonum())); --ctx.top; } #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; 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_div() {op_calc(/);} 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; } #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_subc() {op_calc_const(-);} inline void vm::o_mulc() {op_calc_const(*);} inline void vm::o_divc() {op_calc_const(/);} 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 // so when the calculation ends, top-=1, then top-=imm[pc] -// 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 -// but if b+=a+=c; the result of 'a+c' will be used later, imm[pc]=0 +// 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 +// but if b+=a+=c; the result of 'a+c' will be used later, imm[pc] = 0 #define op_calc_eq(type)\ - ctx.top[-1]=ctx.memr[0]=var::num(ctx.memr[0].tonum() type ctx.top[-1].tonum());\ - ctx.memr=nullptr;\ - ctx.top-=imm[ctx.pc]+1; + ctx.top[-1] = ctx.memr[0] = var::num(ctx.memr[0].tonum() type ctx.top[-1].tonum());\ + ctx.memr = nullptr;\ + ctx.top -= imm[ctx.pc]+1; inline void vm::o_addeq() {op_calc_eq(+);} inline void vm::o_subeq() {op_calc_eq(-);} inline void vm::o_muleq() {op_calc_eq(*);} inline void vm::o_diveq() {op_calc_eq(/);} inline void vm::o_lnkeq() { - ctx.top[-1]=ctx.memr[0]=ngc.newstr(ctx.memr[0].tostr()+ctx.top[-1].tostr()); - ctx.memr=nullptr; - ctx.top-=imm[ctx.pc]+1; + ctx.top[-1] = ctx.memr[0] = ngc.newstr(ctx.memr[0].tostr()+ctx.top[-1].tostr()); + ctx.memr = nullptr; + ctx.top -= imm[ctx.pc]+1; } inline void vm::o_bandeq() { - ctx.top[-1]=ctx.memr[0]=var::num(i32(ctx.memr[0].tonum())&i32(ctx.top[-1].tonum())); - ctx.memr=nullptr; - ctx.top-=imm[ctx.pc]+1; + ctx.top[-1] = ctx.memr[0] = var::num(i32(ctx.memr[0].tonum())&i32(ctx.top[-1].tonum())); + ctx.memr = nullptr; + ctx.top -= imm[ctx.pc]+1; } inline void vm::o_boreq() { - ctx.top[-1]=ctx.memr[0]=var::num(i32(ctx.memr[0].tonum())|i32(ctx.top[-1].tonum())); - ctx.memr=nullptr; - ctx.top-=imm[ctx.pc]+1; + ctx.top[-1] = ctx.memr[0] = var::num(i32(ctx.memr[0].tonum())|i32(ctx.top[-1].tonum())); + ctx.memr = nullptr; + ctx.top -= imm[ctx.pc]+1; } inline void vm::o_bxoreq() { - ctx.top[-1]=ctx.memr[0]=var::num(i32(ctx.memr[0].tonum())^i32(ctx.top[-1].tonum())); - ctx.memr=nullptr; - ctx.top-=imm[ctx.pc]+1; + ctx.top[-1] = ctx.memr[0] = var::num(i32(ctx.memr[0].tonum())^i32(ctx.top[-1].tonum())); + ctx.memr = nullptr; + ctx.top -= imm[ctx.pc]+1; } // 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 // but if b+=a+=1; the result of 'a+1' will be used later, imm[pc]>>31=0 #define op_calc_eq_const(type)\ - ctx.top[0]=ctx.memr[0]=var::num(ctx.memr[0].tonum() type cnum[imm[ctx.pc]]);\ - ctx.memr=nullptr; + ctx.top[0] = ctx.memr[0] = var::num(ctx.memr[0].tonum() type cnum[imm[ctx.pc]]);\ + ctx.memr = nullptr; inline void vm::o_addeqc() {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_diveqc() {op_calc_eq_const(/);} inline void vm::o_lnkeqc() { - ctx.top[0]=ctx.memr[0]=ngc.newstr(ctx.memr[0].tostr()+cstr[imm[ctx.pc]]); - ctx.memr=nullptr; + ctx.top[0] = ctx.memr[0] = ngc.newstr(ctx.memr[0].tostr()+cstr[imm[ctx.pc]]); + ctx.memr = nullptr; } #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.memr=nullptr;\ + ctx.top[0] = ctx.memr[0] = var::num(ctx.memr[0].tonum() type cnum[imm[ctx.pc]]);\ + ctx.memr = nullptr;\ --ctx.top; 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_divecp() {op_calc_eq_const_and_pop(/);} inline void vm::o_lnkecp() { - ctx.top[0]=ctx.memr[0]=ngc.newstr(ctx.memr[0].tostr()+cstr[imm[ctx.pc]]); - ctx.memr=nullptr; + ctx.top[0] = ctx.memr[0] = ngc.newstr(ctx.memr[0].tostr()+cstr[imm[ctx.pc]]); + ctx.memr = nullptr; --ctx.top; } @@ -408,44 +414,44 @@ inline void vm::o_meq() { // is that when lnkeq/lnkeqc is called, there will be // a new gc object vm_str which is returned by gc::alloc // this may cause gc, so we should temporarily put it on stack - ctx.memr[0]=ctx.top[-1]; - ctx.memr=nullptr; - ctx.top-=imm[ctx.pc]+1; + ctx.memr[0] = ctx.top[-1]; + ctx.memr = nullptr; + ctx.top -= imm[ctx.pc]+1; } inline void vm::o_eq() { - var val2=ctx.top[0]; - var val1=(--ctx.top)[0]; + var val2 = ctx.top[0]; + var val1 = (--ctx.top)[0]; 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) { - 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) && 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 { - ctx.top[0]=(val1==val2)?one:zero; + ctx.top[0] = (val1==val2)?one:zero; } } inline void vm::o_neq() { - var val2=ctx.top[0]; - var val1=(--ctx.top)[0]; + var val2 = ctx.top[0]; + var val1 = (--ctx.top)[0]; 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) { - 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) && 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 { - ctx.top[0]=(val1!=val2)?one:zero; + ctx.top[0] = (val1!=val2)?one:zero; } } #define op_cmp(type)\ --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_leq() {op_cmp(<=);} @@ -453,7 +459,7 @@ inline void vm::o_grt() {op_cmp(>);} inline void vm::o_geq() {op_cmp(>=);} #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_leqc() {op_cmp_const(<=);} @@ -465,21 +471,21 @@ inline void vm::o_pop() { } inline void vm::o_jmp() { - ctx.pc=imm[ctx.pc]-1; + ctx.pc = imm[ctx.pc]-1; } inline void vm::o_jt() { // jump true needs to reserve the result on stack // because conditional expression in nasal has return value if (cond(ctx.top[0])) { - ctx.pc=imm[ctx.pc]-1; + ctx.pc = imm[ctx.pc]-1; } } inline void vm::o_jf() { // jump false doesn't need to reserve result if (!cond(ctx.top[0])) { - ctx.pc=imm[ctx.pc]-1; + ctx.pc = imm[ctx.pc]-1; } --ctx.top; } @@ -489,48 +495,48 @@ inline void vm::o_cnt() { die("must use vector in forindex/foreach"); return; } - (++ctx.top)[0]=var::cnt(-1); + (++ctx.top)[0] = var::cnt(-1); } inline void vm::o_findex() { if ((usize)(++ctx.top[0].cnt())>=ctx.top[-1].vec().size()) { - ctx.pc=imm[ctx.pc]-1; + ctx.pc = imm[ctx.pc]-1; return; } - ctx.top[1]=var::num(ctx.top[0].cnt()); + ctx.top[1] = var::num(ctx.top[0].cnt()); ++ctx.top; } 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()) { - ctx.pc=imm[ctx.pc]-1; + ctx.pc = imm[ctx.pc]-1; return; } - ctx.top[1]=ref[ctx.top[0].cnt()]; + ctx.top[1] = ref[ctx.top[0].cnt()]; ++ctx.top; } inline void vm::o_callg() { // get main stack directly - (++ctx.top)[0]=stack[imm[ctx.pc]]; + (++ctx.top)[0] = stack[imm[ctx.pc]]; } 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() { - (++ctx.top)[0]=ctx.funcr.func() + (++ctx.top)[0] = ctx.funcr.func() .upval[(imm[ctx.pc]>>16)&0xffff] .upval()[imm[ctx.pc]&0xffff]; } inline void vm::o_callv() { - var val=ctx.top[0]; - var vec=(--ctx.top)[0]; + var val = ctx.top[0]; + var vec = (--ctx.top)[0]; 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) { die("out of range:"+std::to_string(val.tonum())); return; @@ -540,12 +546,12 @@ inline void vm::o_callv() { die("must use string as the key"); 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) { die("cannot find member \""+val.str()+"\""); return; } 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) { auto& str = vec.str(); @@ -555,7 +561,17 @@ inline void vm::o_callv() { die("out of range:"+std::to_string(val.tonum())); 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 { die("must call a vector/hash/string"); return; @@ -563,13 +579,13 @@ inline void vm::o_callv() { } inline void vm::o_callvi() { - var val=ctx.top[0]; + var val = ctx.top[0]; if (val.type!=vm_vec) { die("must use a vector"); return; } // 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) { die("out of range:"+std::to_string(imm[ctx.pc])); return; @@ -577,30 +593,37 @@ inline void vm::o_callvi() { } inline void vm::o_callh() { - var val=ctx.top[0]; - if (val.type!=vm_hash) { + var val = ctx.top[0]; + if (val.type!=vm_hash && val.type!=vm_map) { die("must call a hash"); 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) { - 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; } 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() { - u32 argc=imm[ctx.pc]; // arguments counter - var* local=ctx.top-argc+1; // arguments begin address + u32 argc = imm[ctx.pc]; // arguments counter + var* local = ctx.top-argc+1; // arguments begin address if (local[-1].type!=vm_func) { die("must call a function"); return; } - auto& func=local[-1].func(); - var tmp=local[-1]; - local[-1]=ctx.funcr; + auto& func = local[-1].func(); + var tmp = local[-1]; + local[-1] = ctx.funcr; ctx.funcr=tmp; // top-argc+lsize(local) +1(old pc) +1(old localr) +1(old upvalr) if (ctx.top-argc+func.lsize+3>=ctx.canary) { @@ -608,15 +631,15 @@ inline void vm::o_callfv() { return; } // parameter size is func->psize-1, 1 is reserved for "me" - u32 psize=func.psize-1; + u32 psize = func.psize-1; if (argc=0) { // load dynamic arguments - dynamic=ngc.alloc(vm_vec); + dynamic = ngc.alloc(vm_vec); for(u32 i=psize;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 for(u32 i=min_size+1;i=0) { - local[psize+1]=dynamic; + local[psize+1] = dynamic; } - ctx.top[0]=ctx.upvalr; - (++ctx.top)[0]=var::addr(ctx.localr); - (++ctx.top)[0]=var::ret(ctx.pc); + ctx.top[0] = ctx.upvalr; + (++ctx.top)[0] = var::addr(ctx.localr); + (++ctx.top)[0] = var::ret(ctx.pc); ctx.pc=func.entry-1; - ctx.localr=local; - ctx.upvalr=nil; + ctx.localr = local; + ctx.upvalr = nil; } 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) { die("must call a function"); return; } - auto& func=ctx.top[-1].func(); - var tmp=ctx.top[-1]; - ctx.top[-1]=ctx.funcr; - ctx.funcr=tmp; + auto& func = ctx.top[-1].func(); + var tmp = ctx.top[-1]; + ctx.top[-1] = ctx.funcr; + ctx.funcr = tmp; // 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"); return; } @@ -670,42 +693,42 @@ inline void vm::o_callfh() { return; } - var* local=ctx.top; - ctx.top+=func.lsize; - for(u32 i=0;i=size || num2<-size || num2>=size) { die("index "+std::to_string(num1)+":"+std::to_string(num2)+" out of range"); return; } else if (num1<=num2) { - for(i32 i=num1;i<=num2;++i) { - aim.push_back(i>=0?ref[i]:ref[i+size]); + for(i32 i = num1; i<=num2; ++i) { + aim.push_back(i>=0? ref[i]:ref[i+size]); } } } inline void vm::o_mcallg() { - ctx.memr=stack+imm[ctx.pc]; - (++ctx.top)[0]=ctx.memr[0]; + ctx.memr = stack+imm[ctx.pc]; + (++ctx.top)[0] = ctx.memr[0]; // push value in this memory space on stack // to avoid being garbage collected } inline void vm::o_mcalll() { - ctx.memr=ctx.localr+imm[ctx.pc]; - (++ctx.top)[0]=ctx.memr[0]; + ctx.memr = ctx.localr+imm[ctx.pc]; + (++ctx.top)[0] = ctx.memr[0]; // push value in this memory space on stack // to avoid being garbage collected } inline void vm::o_mupval() { - ctx.memr=&(ctx.funcr.func().upval[(imm[ctx.pc]>>16)&0xffff].upval()[imm[ctx.pc]&0xffff]); - (++ctx.top)[0]=ctx.memr[0]; + ctx.memr = &( + 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 // to avoid being garbage collected } inline void vm::o_mcallv() { - var val=ctx.top[0]; // index - var vec=(--ctx.top)[0]; // mcall vector, reserved on stack to avoid gc + var val = ctx.top[0]; // index + var vec = (--ctx.top)[0]; // mcall vector, reserved on stack to avoid gc if (vec.type==vm_vec) { - ctx.memr=vec.vec().get_mem(val.tonum()); + ctx.memr = vec.vec().get_mem(val.tonum()); if (!ctx.memr) { die("index "+std::to_string(val.tonum())+" out of range"); return; @@ -810,8 +836,19 @@ inline void vm::o_mcallv() { auto& str = val.str(); ctx.memr = ref.get_mem(str); if (!ctx.memr) { - ref.elems[str]=nil; - ctx.memr=ref.get_mem(str); + ref.elems[str] = nil; + 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 { die("cannot get memory space in this type"); @@ -820,17 +857,24 @@ inline void vm::o_mcallv() { } inline void vm::o_mcallh() { - var hash=ctx.top[0]; // mcall hash, reserved on stack to avoid gc - if (hash.type!=vm_hash) { + var hash = ctx.top[0]; // mcall hash, reserved on stack to avoid gc + if (hash.type!=vm_hash && hash.type!=vm_map) { die("must call a hash"); return; } - auto& ref=hash.hash(); - auto& str=cstr[imm[ctx.pc]]; - ctx.memr=ref.get_mem(str); + auto& str = cstr[imm[ctx.pc]]; + if (hash.type==vm_map) { + 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 - ref.elems[str]=nil; - ctx.memr=ref.get_mem(str); + ref.elems[str] = nil; + ctx.memr = ref.get_mem(str); } } @@ -849,26 +893,26 @@ inline void vm::o_ret() { * | old funcr | <- old function stored in funcr * +-------------+ */ - var ret =ctx.top[0]; - var* local=ctx.localr; - var func =ctx.funcr; - var up =ctx.upvalr; + var ret = ctx.top[0]; + var* local = ctx.localr; + var func = ctx.funcr; + var up = ctx.upvalr; - ctx.pc =ctx.top[-1].ret(); - ctx.localr=ctx.top[-2].addr(); - ctx.upvalr=ctx.top[-3]; + ctx.pc = ctx.top[-1].ret(); + ctx.localr = ctx.top[-2].addr(); + ctx.upvalr = ctx.top[-3]; ctx.top=local-1; - ctx.funcr=ctx.top[0]; - ctx.top[0]=ret; // rewrite func with returned value + ctx.funcr = ctx.top[0]; + ctx.top[0] = ret; // rewrite func with returned value if (up.type==vm_upval) { // synchronize upvalue - auto& upval=up.upval(); - auto size=func.func().lsize; - upval.onstk=false; + auto& upval = up.upval(); + auto size = func.func().lsize; + upval.onstk = false; upval.elems.resize(size); - for(u32 i=0;i