🧑‍💻 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 -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

View File

@ -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;
}

View File

@ -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

View File

@ -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) {}

View File

@ -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[]={

View File

@ -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;

View File

@ -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:

View File

@ -2,8 +2,9 @@
void vm::init(
const std::vector<std::string>& strs,
const std::vector<f64>& nums,
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,

View File

@ -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];
}
}

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
# 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"){