diff --git a/nasal.h b/nasal.h index d4c76fe..dd8bb7e 100644 --- a/nasal.h +++ b/nasal.h @@ -23,7 +23,7 @@ using std::string; const u32 STACK_DEPTH=1024; -inline f64 hex2f(const char* str) { +f64 hex2f(const char* str) { f64 ret=0; for(;*str;++str) { if ('0'<=*str && *str<='9') { @@ -39,7 +39,7 @@ inline f64 hex2f(const char* str) { return ret; } -inline f64 oct2f(const char* str) { +f64 oct2f(const char* str) { f64 ret=0; while('0'<=*str && *str<'8') { ret=ret*8+(*str++-'0'); @@ -54,7 +54,7 @@ inline f64 oct2f(const char* str) { // it is not platform independent, and may have strange output. // so we write a new function here to convert str to number manually. // but this also makes 0.1+0.2==0.3, not another result that you may get in other languages. -inline f64 dec2f(const char* str) { +f64 dec2f(const char* str) { f64 ret=0,negative=1,num_pow=0; while('0'<=*str && *str<='9') { ret=ret*10+(*str++-'0'); diff --git a/nasal_ast.h b/nasal_ast.h index 518abea..8924745 100644 --- a/nasal_ast.h +++ b/nasal_ast.h @@ -157,13 +157,13 @@ public: void set_str(const string& s) {nd_str=s;} void set_num(const f64 n) {nd_num=n;} - inline u32 line() const {return nd_line;} - inline u32 col() const {return nd_col;} - inline u32 type() const {return nd_type;} - inline f64 num() const {return nd_num;} - inline const string& str() const {return nd_str;} - inline const std::vector& child() const {return nd_child;} - inline std::vector& child() {return nd_child;} + u32 line() const {return nd_line;} + u32 col() const {return nd_col;} + u32 type() const {return nd_type;} + f64 num() const {return nd_num;} + const string& str() const {return nd_str;} + const std::vector& child() const {return nd_child;} + std::vector& child() {return nd_child;} }; ast::ast(const ast& tmp): diff --git a/nasal_builtin.h b/nasal_builtin.h index 5f4350c..bc0bdcb 100644 --- a/nasal_builtin.h +++ b/nasal_builtin.h @@ -1151,13 +1151,20 @@ var builtin_coresume(var* local,gc& ngc) { return nas_err("coroutine::resume","cannot start another coroutine when one is running"); } var co=local[1]; + // return nil if is not a coroutine object if (co.type!=vm_co) { - return nas_err("coroutine::resume","must use a coroutine object"); + return nil; } + // cannot resume a dead coroutine if (co.co().status==nas_co::dead) { return nil; } + + // change to coroutine context ngc.ctxchg(co.co()); + + // fetch coroutine's stack top and return + // so the coroutine's stack top in fact is not changed return ngc.top[0]; } @@ -1165,16 +1172,21 @@ var builtin_coyield(var* local,gc& ngc) { if (!ngc.cort) { return nas_err("coroutine::yield","no coroutine is running"); } - ngc.ctxreserve(); + // this will set to main stack top - // then builtin_coresume will return it + ngc.ctxreserve(); + + // then this will return value to main's stack top[0] + // the procedure seems like coroutine.resume returns the value + // but in fact coroutine.resume stop the main context + // until coroutine calls the coroutine.yield return local[1]; } var builtin_costatus(var* local,gc& ngc) { var co=local[1]; if (co.type!=vm_co) { - return nas_err("coroutine::status","must use a coroutine object"); + return ngc.newstr("error"); } switch(co.co().status) { case nas_co::suspended: return ngc.newstr("suspended");break; diff --git a/nasal_gc.h b/nasal_gc.h index d36d8b7..823de2e 100644 --- a/nasal_gc.h +++ b/nasal_gc.h @@ -80,17 +80,17 @@ struct var { string tostr(); friend std::ostream& operator<<(std::ostream&,var&); bool objchk(u32); - inline var* addr(); - inline u32 ret (); - inline i64& cnt (); - inline f64 num (); - inline string& str (); - inline nas_vec& vec (); - inline nas_hash& hash(); - inline nas_func& func(); - inline nas_upval& upval(); - inline nas_obj& obj (); - inline nas_co& co (); + var* addr(); + u32 ret (); + i64& cnt (); + f64 num (); + string& str (); + nas_vec& vec (); + nas_hash& hash(); + nas_func& func(); + nas_upval& upval(); + nas_obj& obj (); + nas_co& co (); }; struct nas_vec { @@ -412,17 +412,17 @@ bool var::objchk(u32 objtype) { return type==vm_obj && obj().type==objtype && obj().ptr; } -inline var* var::addr () {return val.addr; } -inline u32 var::ret () {return val.ret; } -inline i64& var::cnt () {return val.cnt; } -inline f64 var::num () {return val.num; } -inline string& var::str () {return *val.gcobj->ptr.str; } -inline nas_vec& var::vec () {return *val.gcobj->ptr.vec; } -inline nas_hash& var::hash () {return *val.gcobj->ptr.hash; } -inline nas_func& var::func () {return *val.gcobj->ptr.func; } -inline nas_upval& var::upval() {return *val.gcobj->ptr.upval;} -inline nas_obj& var::obj () {return *val.gcobj->ptr.obj; } -inline nas_co& var::co () {return *val.gcobj->ptr.co; } +var* var::addr () {return val.addr; } +u32 var::ret () {return val.ret; } +i64& var::cnt () {return val.cnt; } +f64 var::num () {return val.num; } +string& var::str () {return *val.gcobj->ptr.str; } +nas_vec& var::vec () {return *val.gcobj->ptr.vec; } +nas_hash& var::hash () {return *val.gcobj->ptr.hash; } +nas_func& var::func () {return *val.gcobj->ptr.func; } +nas_upval& var::upval() {return *val.gcobj->ptr.upval;} +nas_obj& var::obj () {return *val.gcobj->ptr.obj; } +nas_co& var::co () {return *val.gcobj->ptr.co; } const var zero={vm_num,(f64)0}; const var one ={vm_num,(f64)1}; diff --git a/nasal_lexer.h b/nasal_lexer.h index d09481b..b75664c 100644 --- a/nasal_lexer.h +++ b/nasal_lexer.h @@ -238,28 +238,31 @@ string lexer::utf8_gen() { while(ptr"); - err.fatal("lexer","fatal error occurred, stop"); - } - str+=tmp; - column+=2; // may have some problems because not all the unicode takes 2 space - } else { + if (!nbytes) { ++ptr; ++column; + continue; } + + tmp+=res[ptr++]; + for(u32 i=0;i"); + err.fatal("lexer","fatal error occurred, stop"); + } + str+=tmp; + column+=2; // may have some problems because not all the unicode takes 2 space } return str; } diff --git a/nasal_vm.h b/nasal_vm.h index 2aeda98..2e59fb1 100644 --- a/nasal_vm.h +++ b/nasal_vm.h @@ -313,12 +313,18 @@ void vm::die(const string& str) { std::cout<<"[vm] error: "<>16)&0xffff] .upval()[imm[pc]&0xffff]=(top--)[0]; } -inline void vm::o_pnum() { +void vm::o_pnum() { (++top)[0]={vm_num,cnum[imm[pc]]}; } -inline void vm::o_pnil() { +void vm::o_pnil() { (++top)[0]=nil; } -inline void vm::o_pstr() { +void vm::o_pstr() { (++top)[0]=ngc.strs[imm[pc]]; } -inline void vm::o_newv() { +void vm::o_newv() { var newv=ngc.alloc(vm_vec); auto& vec=newv.vec().elems; vec.resize(imm[pc]); @@ -383,11 +389,11 @@ inline void vm::o_newv() { top[0]=newv; } -inline void vm::o_newh() { +void vm::o_newh() { (++top)[0]=ngc.alloc(vm_hash); } -inline void vm::o_newf() { +void vm::o_newf() { (++top)[0]=ngc.alloc(vm_func); nas_func& func=top[0].func(); func.entry=imm[pc]; @@ -406,19 +412,19 @@ inline void vm::o_newf() { } } -inline void vm::o_happ() { +void vm::o_happ() { top[-1].hash().elems[cstr[imm[pc]]]=top[0]; --top; } -inline void vm::o_para() { +void vm::o_para() { nas_func& func=top[0].func(); // func->size has 1 place reserved for "me" func.keys[imm[pc]]=func.psize; func.local[func.psize++]={vm_none}; } -inline void vm::o_deft() { +void vm::o_deft() { var val=top[0]; nas_func& func=(--top)[0].func(); // func->size has 1 place reserved for "me" @@ -426,11 +432,11 @@ inline void vm::o_deft() { func.local[func.psize++]=val; } -inline void vm::o_dyn() { +void vm::o_dyn() { top[0].func().dpara=imm[pc]; } -inline void vm::o_unot() { +void vm::o_unot() { var val=top[0]; switch(val.type) { case vm_nil:top[0]=one;break; @@ -450,7 +456,7 @@ inline void vm::o_unot() { } } -inline void vm::o_usub() { +void vm::o_usub() { top[0]={vm_num,-top[0].tonum()}; } @@ -458,11 +464,11 @@ inline void vm::o_usub() { top[-1]={vm_num,top[-1].tonum() type top[0].tonum()};\ --top; -inline void vm::o_add() {op_calc(+);} -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() { +void vm::o_add() {op_calc(+);} +void vm::o_sub() {op_calc(-);} +void vm::o_mul() {op_calc(*);} +void vm::o_div() {op_calc(/);} +void vm::o_lnk() { top[-1]=ngc.newstr(top[-1].tostr()+top[0].tostr()); --top; } @@ -470,11 +476,11 @@ inline void vm::o_lnk() { #define op_calc_const(type)\ top[0]={vm_num,top[0].tonum() type cnum[imm[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() { +void vm::o_addc() {op_calc_const(+);} +void vm::o_subc() {op_calc_const(-);} +void vm::o_mulc() {op_calc_const(*);} +void vm::o_divc() {op_calc_const(/);} +void vm::o_lnkc() { top[0]=ngc.newstr(top[0].tostr()+cstr[imm[pc]]); } @@ -483,11 +489,11 @@ inline void vm::o_lnkc() { memr=nullptr;\ top-=imm[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() { +void vm::o_addeq() {op_calc_eq(+);} +void vm::o_subeq() {op_calc_eq(-);} +void vm::o_muleq() {op_calc_eq(*);} +void vm::o_diveq() {op_calc_eq(/);} +void vm::o_lnkeq() { top[-1]=memr[0]=ngc.newstr(memr[0].tostr()+top[-1].tostr()); memr=nullptr; top-=imm[pc]+1; @@ -498,17 +504,17 @@ inline void vm::o_lnkeq() { memr=nullptr;\ top-=(imm[pc]>>31); -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() { +void vm::o_addeqc() {op_calc_eq_const(+);} +void vm::o_subeqc() {op_calc_eq_const(-);} +void vm::o_muleqc() {op_calc_eq_const(*);} +void vm::o_diveqc() {op_calc_eq_const(/);} +void vm::o_lnkeqc() { top[0]=memr[0]=ngc.newstr(memr[0].tostr()+cstr[imm[pc]&0x7fffffff]); memr=nullptr; top-=(imm[pc]>>31); } -inline void vm::o_meq() { +void vm::o_meq() { // pop old memr[0] and replace it // the reason why we should get memr and push the old value on stack // is that when lnkeq/lnkeqc is called, there will be @@ -519,7 +525,7 @@ inline void vm::o_meq() { top-=imm[pc]+1; } -inline void vm::o_eq() { +void vm::o_eq() { var val2=top[0]; var val1=(--top)[0]; if (val1.type==vm_nil && val2.type==vm_nil) { @@ -534,7 +540,7 @@ inline void vm::o_eq() { } } -inline void vm::o_neq() { +void vm::o_neq() { var val2=top[0]; var val1=(--top)[0]; if (val1.type==vm_nil && val2.type==vm_nil) { @@ -553,28 +559,28 @@ inline void vm::o_neq() { --top;\ top[0]=(top[0].tonum() type top[1].tonum())?one:zero; -inline void vm::o_less() {op_cmp(<);} -inline void vm::o_leq() {op_cmp(<=);} -inline void vm::o_grt() {op_cmp(>);} -inline void vm::o_geq() {op_cmp(>=);} +void vm::o_less() {op_cmp(<);} +void vm::o_leq() {op_cmp(<=);} +void vm::o_grt() {op_cmp(>);} +void vm::o_geq() {op_cmp(>=);} #define op_cmp_const(type)\ top[0]=(top[0].tonum() type cnum[imm[pc]])?one:zero; -inline void vm::o_lessc() {op_cmp_const(<);} -inline void vm::o_leqc() {op_cmp_const(<=);} -inline void vm::o_grtc() {op_cmp_const(>);} -inline void vm::o_geqc() {op_cmp_const(>=);} +void vm::o_lessc() {op_cmp_const(<);} +void vm::o_leqc() {op_cmp_const(<=);} +void vm::o_grtc() {op_cmp_const(>);} +void vm::o_geqc() {op_cmp_const(>=);} -inline void vm::o_pop() { +void vm::o_pop() { --top; } -inline void vm::o_jmp() { +void vm::o_jmp() { pc=imm[pc]-1; } -inline void vm::o_jt() { +void vm::o_jt() { // jump true needs to reserve the result on stack // because conditional expression in nasal has return value if (cond(top[0])) { @@ -582,7 +588,7 @@ inline void vm::o_jt() { } } -inline void vm::o_jf() { +void vm::o_jf() { // jump false doesn't need to reserve result if (!cond(top[0])) { pc=imm[pc]-1; @@ -590,7 +596,7 @@ inline void vm::o_jf() { --top; } -inline void vm::o_cnt() { +void vm::o_cnt() { if (top[0].type!=vm_vec) { die("must use vector in forindex/foreach"); return; @@ -598,7 +604,7 @@ inline void vm::o_cnt() { (++top)[0]={vm_cnt,(i64)-1}; } -inline void vm::o_findex() { +void vm::o_findex() { if ((usize)(++top[0].cnt())>=top[-1].vec().size()) { pc=imm[pc]-1; return; @@ -607,7 +613,7 @@ inline void vm::o_findex() { ++top; } -inline void vm::o_feach() { +void vm::o_feach() { auto& ref=top[-1].vec().elems; if ((usize)(++top[0].cnt())>=ref.size()) { pc=imm[pc]-1; @@ -617,20 +623,20 @@ inline void vm::o_feach() { ++top; } -inline void vm::o_callg() { +void vm::o_callg() { (++top)[0]=stack[imm[pc]]; } -inline void vm::o_calll() { +void vm::o_calll() { (++top)[0]=localr[imm[pc]]; } -inline void vm::o_upval() { +void vm::o_upval() { (++top)[0]=funcr.func().upval[(imm[pc]>>16)&0xffff] .upval()[imm[pc]&0xffff]; } -inline void vm::o_callv() { +void vm::o_callv() { var val=top[0]; var vec=(--top)[0]; if (vec.type==vm_vec) { @@ -666,7 +672,7 @@ inline void vm::o_callv() { } } -inline void vm::o_callvi() { +void vm::o_callvi() { var val=top[0]; if (val.type!=vm_vec) { die("must use a vector"); @@ -680,7 +686,7 @@ inline void vm::o_callvi() { } } -inline void vm::o_callh() { +void vm::o_callh() { var val=top[0]; if (val.type!=vm_hash) { die("must call a hash"); @@ -695,7 +701,7 @@ inline void vm::o_callh() { } } -inline void vm::o_callfv() { +void vm::o_callfv() { u32 argc=imm[pc]; // arguments counter var* local=top-argc+1; // arguments begin address if (local[-1].type!=vm_func) { @@ -753,7 +759,7 @@ inline void vm::o_callfv() { upvalr=nil; } -inline void vm::o_callfh() { +void vm::o_callfh() { auto& hash=top[0].hash().elems; if (top[-1].type!=vm_func) { die("must call a function"); @@ -797,7 +803,7 @@ inline void vm::o_callfh() { upvalr=nil; } -inline void vm::o_callb() { +void vm::o_callb() { // reserve place for builtin function return, // in fact this code is changed because of coroutine (++top)[0]=nil; @@ -811,7 +817,7 @@ inline void vm::o_callb() { } } -inline void vm::o_slcbeg() { +void vm::o_slcbeg() { // +--------------+ // | slice_vector | <-- top[0] // +--------------+ @@ -824,12 +830,12 @@ inline void vm::o_slcbeg() { } } -inline void vm::o_slcend() { +void vm::o_slcend() { top[-1]=top[0]; --top; } -inline void vm::o_slc() { +void vm::o_slc() { var val=(top--)[0]; var res=top[-1].vec().get_val(val.tonum()); if (res.type==vm_none) { @@ -839,7 +845,7 @@ inline void vm::o_slc() { top[0].vec().elems.push_back(res); } -inline void vm::o_slc2() { +void vm::o_slc2() { var val2=(top--)[0]; var val1=(top--)[0]; auto& ref=top[-1].vec().elems; @@ -868,28 +874,28 @@ inline void vm::o_slc2() { } } -inline void vm::o_mcallg() { +void vm::o_mcallg() { memr=stack+imm[pc]; (++top)[0]=memr[0]; // push value in this memory space on stack // to avoid being garbage collected } -inline void vm::o_mcalll() { +void vm::o_mcalll() { memr=localr+imm[pc]; (++top)[0]=memr[0]; // push value in this memory space on stack // to avoid being garbage collected } -inline void vm::o_mupval() { +void vm::o_mupval() { memr=&(funcr.func().upval[(imm[pc]>>16)&0xffff].upval()[imm[pc]&0xffff]); (++top)[0]=memr[0]; // push value in this memory space on stack // to avoid being garbage collected } -inline void vm::o_mcallv() { +void vm::o_mcallv() { var val=top[0]; // index var vec=(--top)[0]; // mcall vector, reserved on stack to avoid gc if (vec.type==vm_vec) { @@ -916,7 +922,7 @@ inline void vm::o_mcallv() { } } -inline void vm::o_mcallh() { +void vm::o_mcallh() { var hash=top[0]; // mcall hash, reserved on stack to avoid gc if (hash.type!=vm_hash) { die("must call a hash"); @@ -931,7 +937,7 @@ inline void vm::o_mcallh() { } } -inline void vm::o_ret() { +void vm::o_ret() { /* +-------------+ * | return value| <- top[0] * +-------------+ @@ -974,6 +980,7 @@ inline void vm::o_ret() { ngc.ctxreserve(); } } + void vm::run( const codegen& gen, const linker& linker, diff --git a/test/life.nas b/test/life.nas index d5d7c1d..e2cfa0e 100644 --- a/test/life.nas +++ b/test/life.nas @@ -28,6 +28,7 @@ var run=func(width,height){ if(_width>=width) _width=0; return map[_height][_width]=='O'; } + # enable ANSI escape sequence if(os.platform()=="windows") system("color"); @@ -55,43 +56,48 @@ var run=func(width,height){ }; var ppm_gen=func(width,height){ + var pixels=width*height; + + var new_map=func(){ + var tmp=[]; + setsize(tmp,pixels); + return tmp; + } # iteration counter and trigger for ppm/data generator var iter_to_print=0; var init=func(){ - var res=new_map(width,height); + var res=new_map(); if(io.exists(".life_data")) { var vec=split("\n",io.fin(".life_data")); if (num(vec[0])!=width or num(vec[1])!=height) { die("incorrect width or height: "~vec[0]~":"~str(width)~" / "~vec[1]~":"~str(height)) } iter_to_print=num(vec[2]); - var data=split("",vec[3]); - for(var i=0;i=height) _height=0; if(_width>=width) _width=0; - return map[_height][_width]==1; + return map[_height*width+_width]==1; } for(var r=0;r<1001;r+=1){ @@ -128,9 +131,9 @@ var ppm_gen=func(width,height){ for(var i=0;i