🧑💻 add important symbol "globals"
This commit is contained in:
parent
eca6141408
commit
b4482792c8
1
makefile
1
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
|
||||
|
|
|
@ -334,15 +334,21 @@ 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) {
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -25,8 +25,8 @@ private:
|
|||
error& err;
|
||||
const std::string* file;
|
||||
std::stack<u32> in_iterloop;
|
||||
std::unordered_map<f64,u32> const_number_map;
|
||||
std::unordered_map<std::string,u32> const_string_map;
|
||||
std::unordered_map<f64, u32> const_number_map;
|
||||
std::unordered_map<std::string, u32> const_string_map;
|
||||
std::vector<f64> const_number_table;
|
||||
std::vector<std::string> const_string_table;
|
||||
std::vector<opcode> code;
|
||||
|
@ -35,10 +35,10 @@ private:
|
|||
|
||||
// symbol table
|
||||
// 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
|
||||
// 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*);
|
||||
|
||||
|
@ -97,6 +97,7 @@ public:
|
|||
const std::vector<std::string>& strs() const {return const_string_table;}
|
||||
const std::vector<f64>& nums() const {return const_number_table;}
|
||||
const std::vector<opcode>& codes() const {return code;}
|
||||
const std::unordered_map<std::string, i32>& globals() const {return global;}
|
||||
|
||||
public:
|
||||
codegen(error& e): fileindex(0), err(e), file(nullptr) {}
|
||||
|
|
|
@ -163,7 +163,12 @@ void dbg::run(
|
|||
const std::vector<std::string>& 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[]={
|
||||
|
|
|
@ -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 << "<coroutine>"; 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<var> 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_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<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() {
|
||||
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;
|
||||
|
|
|
@ -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<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 {
|
||||
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<var>&, nas_func&);
|
||||
void mark_upval(std::vector<var>&, nas_upval&);
|
||||
void mark_co(std::vector<var>&, nas_co&);
|
||||
void mark_map(std::vector<var>&, nas_map&);
|
||||
void sweep();
|
||||
|
||||
public:
|
||||
|
|
|
@ -4,6 +4,7 @@ void vm::init(
|
|||
const std::vector<std::string>& strs,
|
||||
const std::vector<f64>& nums,
|
||||
const std::vector<opcode>& code,
|
||||
const std::unordered_map<std::string, i32>& global,
|
||||
const std::vector<std::string>& filenames,
|
||||
const std::vector<std::string>& 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,
|
||||
|
|
470
src/nasal_vm.h
470
src/nasal_vm.h
|
@ -39,6 +39,7 @@ protected:
|
|||
const std::vector<std::string>&,
|
||||
const std::vector<f64>&,
|
||||
const std::vector<opcode>&,
|
||||
const std::unordered_map<std::string, i32>&,
|
||||
const std::vector<std::string>&,
|
||||
const std::vector<std::string>&);
|
||||
|
||||
|
@ -155,15 +156,14 @@ public:
|
|||
const codegen&,
|
||||
const linker&,
|
||||
const std::vector<std::string>&,
|
||||
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;i<imm[ctx.pc];++i) {
|
||||
vec[i]=ctx.top[i];
|
||||
ctx.top = ctx.top-imm[ctx.pc]+1;
|
||||
for(u32 i = 0; i<imm[ctx.pc]; ++i) {
|
||||
vec[i] = ctx.top[i];
|
||||
}
|
||||
ctx.top[0]=newv;
|
||||
ctx.top[0] = newv;
|
||||
}
|
||||
|
||||
inline void vm::o_newh() {
|
||||
(++ctx.top)[0]=ngc.alloc(vm_hash);
|
||||
(++ctx.top)[0] = ngc.alloc(vm_hash);
|
||||
}
|
||||
|
||||
inline void vm::o_newf() {
|
||||
(++ctx.top)[0]=ngc.alloc(vm_func);
|
||||
nas_func& func=ctx.top[0].func();
|
||||
func.entry=imm[ctx.pc];
|
||||
func.psize=1;
|
||||
(++ctx.top)[0] = ngc.alloc(vm_func);
|
||||
auto& func = ctx.top[0].func();
|
||||
func.entry = imm[ctx.pc];
|
||||
func.psize = 1;
|
||||
|
||||
/* this means you create a new function in local scope */
|
||||
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
|
||||
// so this size & stk setting has no problem
|
||||
var upval=(ctx.upvalr.type==vm_nil)?ngc.alloc(vm_upval):ctx.upvalr;
|
||||
upval.upval().size=ctx.funcr.func().lsize;
|
||||
upval.upval().stk=ctx.localr;
|
||||
var upval = (ctx.upvalr.type==vm_nil)? ngc.alloc(vm_upval):ctx.upvalr;
|
||||
upval.upval().size = ctx.funcr.func().lsize;
|
||||
upval.upval().stk = ctx.localr;
|
||||
func.upval.push_back(upval);
|
||||
ctx.upvalr=upval;
|
||||
ctx.upvalr = upval;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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.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<int32_t>(ctx.top[0].num()));
|
||||
ctx.top[0] = var::num(~static_cast<int32_t>(ctx.top[0].num()));
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#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<psize && func.local[argc+1].type==vm_none) {
|
||||
die("lack argument(s)");
|
||||
return;
|
||||
}
|
||||
|
||||
var dynamic=nil;
|
||||
var dynamic = nil;
|
||||
if (func.dpara>=0) { // load dynamic arguments
|
||||
dynamic=ngc.alloc(vm_vec);
|
||||
dynamic = ngc.alloc(vm_vec);
|
||||
for(u32 i=psize;i<argc;++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
|
||||
// are all outside the stack top and may be
|
||||
// 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
|
||||
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<func.lsize;++i) {
|
||||
local[i]=func.local[i];
|
||||
local[i] = func.local[i];
|
||||
}
|
||||
if (func.dpara>=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<func.lsize;++i) {
|
||||
local[i]=func.local[i];
|
||||
var* local = ctx.top;
|
||||
ctx.top += func.lsize;
|
||||
for(u32 i = 0; i<func.lsize; ++i) {
|
||||
local[i] = func.local[i];
|
||||
}
|
||||
|
||||
for(auto& i:func.keys) {
|
||||
auto& key=cstr[i.first];
|
||||
for(const auto& i : func.keys) {
|
||||
auto& key = cstr[i.first];
|
||||
if (hash.count(key)) {
|
||||
local[i.second]=hash[key];
|
||||
local[i.second] = hash[key];
|
||||
} else if (local[i.second].type==vm_none) {
|
||||
die("lack argument(s): \""+key+"\"");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ctx.top[0]=ctx.upvalr;
|
||||
(++ctx.top)[0]=var::addr(ctx.localr);
|
||||
(++ctx.top)[0]=var::ret(ctx.pc); // rewrite top with vm_ret
|
||||
ctx.top[0] = ctx.upvalr;
|
||||
(++ctx.top)[0] = var::addr(ctx.localr);
|
||||
(++ctx.top)[0] = var::ret(ctx.pc); // rewrite top with vm_ret
|
||||
ctx.pc=func.entry-1;
|
||||
ctx.localr=local;
|
||||
ctx.upvalr=nil;
|
||||
ctx.localr = local;
|
||||
ctx.upvalr = nil;
|
||||
}
|
||||
|
||||
inline void vm::o_callb() {
|
||||
// reserve place for builtin function return,
|
||||
// this code is written for coroutine
|
||||
(++ctx.top)[0]=nil;
|
||||
(++ctx.top)[0] = nil;
|
||||
|
||||
// if running a builtin function about coroutine
|
||||
// (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
|
||||
// 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 (ctx.top[0].type==vm_none) {
|
||||
|
@ -720,7 +743,7 @@ inline void vm::o_slcbeg() {
|
|||
// +--------------+
|
||||
// | 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) {
|
||||
die("must slice a vector");
|
||||
return;
|
||||
|
@ -728,13 +751,13 @@ inline void vm::o_slcbeg() {
|
|||
}
|
||||
|
||||
inline void vm::o_slcend() {
|
||||
ctx.top[-1]=ctx.top[0];
|
||||
ctx.top[-1] = ctx.top[0];
|
||||
--ctx.top;
|
||||
}
|
||||
|
||||
inline void vm::o_slc() {
|
||||
var val=(ctx.top--)[0];
|
||||
var res=ctx.top[-1].vec().get_val(val.tonum());
|
||||
var val = (ctx.top--)[0];
|
||||
var res = ctx.top[-1].vec().get_val(val.tonum());
|
||||
if (res.type==vm_none) {
|
||||
die("index "+std::to_string(val.tonum())+" out of range");
|
||||
return;
|
||||
|
@ -743,60 +766,63 @@ inline void vm::o_slc() {
|
|||
}
|
||||
|
||||
inline void vm::o_slc2() {
|
||||
var val2=(ctx.top--)[0];
|
||||
var val1=(ctx.top--)[0];
|
||||
auto& ref=ctx.top[-1].vec().elems;
|
||||
auto& aim=ctx.top[0].vec().elems;
|
||||
var val2 = (ctx.top--)[0];
|
||||
var val1 = (ctx.top--)[0];
|
||||
auto& ref = ctx.top[-1].vec().elems;
|
||||
auto& aim = ctx.top[0].vec().elems;
|
||||
|
||||
u8 type1=val1.type,type2=val2.type;
|
||||
i32 num1=val1.tonum();
|
||||
i32 num2=val2.tonum();
|
||||
i32 size=ref.size();
|
||||
u8 type1 = val1.type,type2=val2.type;
|
||||
i32 num1 = val1.tonum();
|
||||
i32 num2 = val2.tonum();
|
||||
i32 size = ref.size();
|
||||
if (type1==vm_nil && type2==vm_nil) {
|
||||
num1=0;
|
||||
num2=size-1;
|
||||
num1 = 0;
|
||||
num2 = size-1;
|
||||
} 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) {
|
||||
num2=num1<0? -1:size-1;
|
||||
num2 = num1<0? -1:size-1;
|
||||
}
|
||||
|
||||
if (num1<-size || num1>=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<size;++i) {
|
||||
upval.elems[i]=local[i];
|
||||
for(u32 i = 0; i<size; ++i) {
|
||||
upval.elems[i] = local[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
|
@ -1,5 +1,6 @@
|
|||
# hexdump.nas by ValKmjolnir
|
||||
# 2021/8/13
|
||||
import.std.file;
|
||||
|
||||
# init
|
||||
var hex=func(){
|
||||
|
@ -20,22 +21,7 @@ var hex=func(){
|
|||
|
||||
# read file
|
||||
var s=func(){
|
||||
var filename=[
|
||||
"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"
|
||||
];
|
||||
var filename = find_all_files_with_extension("./src","cpp","h");
|
||||
if(size(runtime.argv())!=0){
|
||||
var argv=runtime.argv();
|
||||
if(argv[0]=="-h" or argv[0]=="--h"){
|
||||
|
|
Loading…
Reference in New Issue