diff --git a/main.cpp b/main.cpp index 834bd88..9c97571 100644 --- a/main.cpp +++ b/main.cpp @@ -21,10 +21,8 @@ const u32 VM_TIME =0x04; const u32 VM_EXEC =0x08; const u32 VM_DETAIL=0x10; const u32 VM_DEBUG =0x20; -const u32 VM_OPT =0x40; -std::ostream& help(std::ostream& out) -{ +std::ostream& help(std::ostream& out) { out <<" ,--#-,\n" <<"<3 / \\____\\ <3\n" @@ -44,8 +42,6 @@ std::ostream& help(std::ostream& out) <<" -d, --detail | get detail crash info.\n" <<" | get detail path-not-found info.\n" <<" | get detail gc info.\n" - <<" -o, --optimize | use optimizer (beta).\n" - <<" | use <-o -e> to run optimized code.\n" <<" -dbg, --debug | debug mode (ignore -t -d).\n" <<"file:\n" <<" | execute file.\n" @@ -54,8 +50,7 @@ std::ostream& help(std::ostream& out) return out; } -std::ostream& logo(std::ostream& out) -{ +std::ostream& logo(std::ostream& out) { out <<" __ _\n" <<" /\\ \\ \\__ _ ___ __ _| |\n" @@ -72,16 +67,14 @@ std::ostream& logo(std::ostream& out) } [[noreturn]] -void err() -{ +void err() { std::cerr <<"invalid argument(s).\n" <<"use to get help.\n"; std::exit(1); } -void execute(const string& file,const std::vector& argv,const u32 cmd) -{ +void execute(const string& file,const std::vector& argv,const u32 cmd) { error err; lexer lex(err); parse parse(err); @@ -96,46 +89,44 @@ void execute(const string& file,const std::vector& argv,const u32 cmd) // linker gets parser's ast and load import files to this ast ld.link(parse,file,cmd&VM_DETAIL).chkerr(); // optimizer does simple optimization on ast - if(cmd&VM_OPT) - optimize(parse.tree()); - if(cmd&VM_AST) + optimize(parse.tree()); + if (cmd&VM_AST) { parse.tree().dump(); + } // code generator gets parser's ast and linker's import file list to generate code gen.compile(parse,ld).chkerr(); - if(cmd&VM_CODE) + if (cmd&VM_CODE) { gen.print(); + } // run - if(cmd&VM_DEBUG) + if (cmd&VM_DEBUG) { debugger(err).run(gen,ld,argv); - else if(cmd&VM_TIME) - { + } else if (cmd&VM_TIME) { auto start=ch_clk::now(); ctx.run(gen,ld,argv,cmd&VM_DETAIL); auto end=ch_clk::now(); std::clog<<"process exited after "<<(end-start).count()*1.0/ch_clk::duration::period::den<<"s.\n"; - } - else if(cmd&VM_EXEC) + } else if (cmd&VM_EXEC) { ctx.run(gen,ld,argv,cmd&VM_DETAIL); + } } -i32 main(i32 argc,const char* argv[]) -{ - if(argc<=1) - { +i32 main(i32 argc,const char* argv[]) { + if (argc<=1) { std::clog< cmdlst={ @@ -144,23 +135,23 @@ i32 main(i32 argc,const char* argv[]) {"--exec",VM_EXEC},{"-e",VM_EXEC}, {"--time",VM_TIME|VM_EXEC},{"-t",VM_TIME|VM_EXEC}, {"--detail",VM_DETAIL|VM_EXEC},{"-d",VM_DETAIL|VM_EXEC}, - {"--optimize",VM_OPT},{"-o",VM_OPT}, {"--debug",VM_DEBUG},{"-dbg",VM_DEBUG} }; u32 cmd=0; string filename=""; std::vector vm_argv; - for(i32 i=1;i #include "../nasal.h" -double fibonaci(double x){ - if(x<=2) +double fibonaci(double x) { + if (x<=2) { return x; + } return fibonaci(x-1)+fibonaci(x-2); } -var fib(var* args,usize size,gc* ngc){ - if(!size) +var fib(var* args,usize size,gc* ngc) { + if (!size) { return nas_err("fib","lack arguments"); + } var num=args[0]; return {vm_num,fibonaci(num.tonum())}; } -var quick_fib(var* args,usize size,gc* ngc){ - if(!size) +var quick_fib(var* args,usize size,gc* ngc) { + if (!size) { return nas_err("quick_fib","lack arguments"); + } double num=args[0].tonum(); - if(num<2) + if (num<2) { return {vm_num,num}; + } double a=1,b=1,res=0; - for(double i=1;i #endif -class noecho_input{ +class noecho_input { private: #ifndef _WIN32 struct termios init_termios; @@ -16,7 +16,7 @@ private: int peek_char=-1; #endif public: - noecho_input(){ + noecho_input() { #ifndef _WIN32 tcflush(0,TCIOFLUSH); tcgetattr(0,&init_termios); @@ -29,23 +29,24 @@ public: tcsetattr(0,TCSANOW,&new_termios); #endif } - ~noecho_input(){ + ~noecho_input() { #ifndef _WIN32 tcflush(0,TCIOFLUSH); tcsetattr(0,TCSANOW,&init_termios); #endif } - int noecho_kbhit(){ + int noecho_kbhit() { #ifndef _WIN32 unsigned char ch=0; int nread=0; - if(peek_char!=-1) + if (peek_char!=-1) { return 1; + } int flag=fcntl(0,F_GETFL); fcntl(0,F_SETFL,flag|O_NONBLOCK); nread=read(0,&ch,1); fcntl(0,F_SETFL,flag); - if(nread==1){ + if (nread==1) { peek_char=ch; return 1; } @@ -54,10 +55,10 @@ public: return kbhit(); #endif } - int noecho_getch(){ + int noecho_getch() { #ifndef _WIN32 int ch=0; - if(peek_char!=-1){ + if (peek_char!=-1) { ch=peek_char; peek_char=-1; return ch; @@ -71,15 +72,16 @@ public: }; noecho_input this_window; -var nas_getch(var* args,usize size,gc* ngc){ +var nas_getch(var* args,usize size,gc* ngc) { return {vm_num,(double)this_window.noecho_getch()}; } -var nas_kbhit(var* args,usize size,gc* ngc){ +var nas_kbhit(var* args,usize size,gc* ngc) { return {vm_num,(double)this_window.noecho_kbhit()}; } -var nas_noblock(var* args,usize size,gc* ngc){ - if(this_window.noecho_kbhit()) +var nas_noblock(var* args,usize size,gc* ngc) { + if (this_window.noecho_kbhit()) { return {vm_num,(double)this_window.noecho_getch()}; + } return nil; } @@ -90,6 +92,6 @@ mod_func func_tbl[]={ {nullptr,nullptr} }; -extern "C" mod_func* get(){ +extern "C" mod_func* get() { return func_tbl; } \ No newline at end of file diff --git a/module/matrix.cpp b/module/matrix.cpp index a0bcdc1..7f9a1a1 100644 --- a/module/matrix.cpp +++ b/module/matrix.cpp @@ -1,14 +1,14 @@ #include "../nasal.h" #include -var nas_vec2(var* args,usize size,gc* ngc){ +var nas_vec2(var* args,usize size,gc* ngc) { var res=ngc->alloc(vm_vec); res.vec().elems.push_back(args[0]); res.vec().elems.push_back(args[1]); return res; } -var nas_vec3(var* args,usize size,gc* ngc){ +var nas_vec3(var* args,usize size,gc* ngc) { var res=ngc->alloc(vm_vec); res.vec().elems.push_back(args[0]); res.vec().elems.push_back(args[1]); @@ -16,12 +16,12 @@ var nas_vec3(var* args,usize size,gc* ngc){ return res; } -var nas_vec2_add(var* args,usize size,gc* ngc){ - if(args[0].type!=vm_vec || args[1].type!=vm_vec) +var nas_vec2_add(var* args,usize size,gc* ngc) { + if (args[0].type!=vm_vec || args[1].type!=vm_vec) return nil; auto& v0=args[0].vec().elems; auto& v1=args[1].vec().elems; - if(v0.size()!=2 || v1.size()!=2) + if (v0.size()!=2 || v1.size()!=2) return nil; var res=ngc->alloc(vm_vec); res.vec().elems.push_back({vm_num,v0[0].num()+v1[0].num()}); @@ -29,12 +29,12 @@ var nas_vec2_add(var* args,usize size,gc* ngc){ return res; } -var nas_vec2_sub(var* args,usize size,gc* ngc){ - if(args[0].type!=vm_vec || args[1].type!=vm_vec) +var nas_vec2_sub(var* args,usize size,gc* ngc) { + if (args[0].type!=vm_vec || args[1].type!=vm_vec) return nil; auto& v0=args[0].vec().elems; auto& v1=args[1].vec().elems; - if(v0.size()!=2 || v1.size()!=2) + if (v0.size()!=2 || v1.size()!=2) return nil; var res=ngc->alloc(vm_vec); res.vec().elems.push_back({vm_num,v0[0].num()-v1[0].num()}); @@ -42,12 +42,12 @@ var nas_vec2_sub(var* args,usize size,gc* ngc){ return res; } -var nas_vec2_mult(var* args,usize size,gc* ngc){ - if(args[0].type!=vm_vec || args[1].type!=vm_vec) +var nas_vec2_mult(var* args,usize size,gc* ngc) { + if (args[0].type!=vm_vec || args[1].type!=vm_vec) return nil; auto& v0=args[0].vec().elems; auto& v1=args[1].vec().elems; - if(v0.size()!=2 || v1.size()!=2) + if (v0.size()!=2 || v1.size()!=2) return nil; var res=ngc->alloc(vm_vec); res.vec().elems.push_back({vm_num,v0[0].num()*v1[0].num()}); @@ -55,12 +55,12 @@ var nas_vec2_mult(var* args,usize size,gc* ngc){ return res; } -var nas_vec2_div(var* args,usize size,gc* ngc){ - if(args[0].type!=vm_vec || args[1].type!=vm_vec) +var nas_vec2_div(var* args,usize size,gc* ngc) { + if (args[0].type!=vm_vec || args[1].type!=vm_vec) return nil; auto& v0=args[0].vec().elems; auto& v1=args[1].vec().elems; - if(v0.size()!=2 || v1.size()!=2) + if (v0.size()!=2 || v1.size()!=2) return nil; var res=ngc->alloc(vm_vec); res.vec().elems.push_back({vm_num,v0[0].num()/v1[0].num()}); @@ -68,11 +68,11 @@ var nas_vec2_div(var* args,usize size,gc* ngc){ return res; } -var nas_vec2_neg(var* args,usize size,gc* ngc){ - if(args[0].type!=vm_vec) +var nas_vec2_neg(var* args,usize size,gc* ngc) { + if (args[0].type!=vm_vec) return nil; auto& v0=args[0].vec().elems; - if(v0.size()!=2) + if (v0.size()!=2) return nil; var res=ngc->alloc(vm_vec); res.vec().elems.push_back({vm_num,-v0[0].num()}); @@ -80,11 +80,11 @@ var nas_vec2_neg(var* args,usize size,gc* ngc){ return res; } -var nas_vec2_norm(var* args,usize size,gc* ngc){ - if(args[0].type!=vm_vec) +var nas_vec2_norm(var* args,usize size,gc* ngc) { + if (args[0].type!=vm_vec) return nil; auto& v0=args[0].vec().elems; - if(v0.size()!=2) + if (v0.size()!=2) return nil; auto x=v0[0].num(); auto y=v0[1].num(); @@ -95,33 +95,33 @@ var nas_vec2_norm(var* args,usize size,gc* ngc){ return res; } -var nas_vec2_len(var* args,usize size,gc* ngc){ - if(args[0].type!=vm_vec) +var nas_vec2_len(var* args,usize size,gc* ngc) { + if (args[0].type!=vm_vec) return nil; auto& v0=args[0].vec().elems; - if(v0.size()!=2) + if (v0.size()!=2) return nil; auto x=v0[0].num(); auto y=v0[1].num(); return {vm_num,std::sqrt(x*x+y*y)}; } -var nas_vec2_dot(var* args,usize size,gc* ngc){ - if(args[0].type!=vm_vec || args[1].type!=vm_vec) +var nas_vec2_dot(var* args,usize size,gc* ngc) { + if (args[0].type!=vm_vec || args[1].type!=vm_vec) return nil; auto& v0=args[0].vec().elems; auto& v1=args[1].vec().elems; - if(v0.size()!=2 || v1.size()!=2) + if (v0.size()!=2 || v1.size()!=2) return nil; return {vm_num,v0[0].num()*v1[0].num()+v0[1].num()*v1[1].num()}; } -var nas_vec3_add(var* args,usize size,gc* ngc){ - if(args[0].type!=vm_vec || args[1].type!=vm_vec) +var nas_vec3_add(var* args,usize size,gc* ngc) { + if (args[0].type!=vm_vec || args[1].type!=vm_vec) return nil; auto& v0=args[0].vec().elems; auto& v1=args[1].vec().elems; - if(v0.size()!=3 || v1.size()!=3) + if (v0.size()!=3 || v1.size()!=3) return nil; var res=ngc->alloc(vm_vec); res.vec().elems.push_back({vm_num,v0[0].num()+v1[0].num()}); @@ -130,12 +130,12 @@ var nas_vec3_add(var* args,usize size,gc* ngc){ return res; } -var nas_vec3_sub(var* args,usize size,gc* ngc){ - if(args[0].type!=vm_vec || args[1].type!=vm_vec) +var nas_vec3_sub(var* args,usize size,gc* ngc) { + if (args[0].type!=vm_vec || args[1].type!=vm_vec) return nil; auto& v0=args[0].vec().elems; auto& v1=args[1].vec().elems; - if(v0.size()!=3 || v1.size()!=3) + if (v0.size()!=3 || v1.size()!=3) return nil; var res=ngc->alloc(vm_vec); res.vec().elems.push_back({vm_num,v0[0].num()-v1[0].num()}); @@ -144,12 +144,12 @@ var nas_vec3_sub(var* args,usize size,gc* ngc){ return res; } -var nas_vec3_mult(var* args,usize size,gc* ngc){ - if(args[0].type!=vm_vec || args[1].type!=vm_vec) +var nas_vec3_mult(var* args,usize size,gc* ngc) { + if (args[0].type!=vm_vec || args[1].type!=vm_vec) return nil; auto& v0=args[0].vec().elems; auto& v1=args[1].vec().elems; - if(v0.size()!=3 || v1.size()!=3) + if (v0.size()!=3 || v1.size()!=3) return nil; var res=ngc->alloc(vm_vec); res.vec().elems.push_back({vm_num,v0[0].num()*v1[0].num()}); @@ -158,12 +158,12 @@ var nas_vec3_mult(var* args,usize size,gc* ngc){ return res; } -var nas_vec3_div(var* args,usize size,gc* ngc){ - if(args[0].type!=vm_vec || args[1].type!=vm_vec) +var nas_vec3_div(var* args,usize size,gc* ngc) { + if (args[0].type!=vm_vec || args[1].type!=vm_vec) return nil; auto& v0=args[0].vec().elems; auto& v1=args[1].vec().elems; - if(v0.size()!=3 || v1.size()!=3) + if (v0.size()!=3 || v1.size()!=3) return nil; var res=ngc->alloc(vm_vec); res.vec().elems.push_back({vm_num,v0[0].num()/v1[0].num()}); @@ -172,11 +172,11 @@ var nas_vec3_div(var* args,usize size,gc* ngc){ return res; } -var nas_vec3_neg(var* args,usize size,gc* ngc){ - if(args[0].type!=vm_vec) +var nas_vec3_neg(var* args,usize size,gc* ngc) { + if (args[0].type!=vm_vec) return nil; auto& v0=args[0].vec().elems; - if(v0.size()!=3) + if (v0.size()!=3) return nil; var res=ngc->alloc(vm_vec); res.vec().elems.push_back({vm_num,-v0[0].num()}); @@ -185,11 +185,11 @@ var nas_vec3_neg(var* args,usize size,gc* ngc){ return res; } -var nas_vec3_norm(var* args,usize size,gc* ngc){ - if(args[0].type!=vm_vec) +var nas_vec3_norm(var* args,usize size,gc* ngc) { + if (args[0].type!=vm_vec) return nil; auto& v0=args[0].vec().elems; - if(v0.size()!=3) + if (v0.size()!=3) return nil; auto x=v0[0].num(); auto y=v0[1].num(); @@ -202,11 +202,11 @@ var nas_vec3_norm(var* args,usize size,gc* ngc){ return res; } -var nas_vec3_len(var* args,usize size,gc* ngc){ - if(args[0].type!=vm_vec) +var nas_vec3_len(var* args,usize size,gc* ngc) { + if (args[0].type!=vm_vec) return nil; auto& v0=args[0].vec().elems; - if(v0.size()!=3) + if (v0.size()!=3) return nil; auto x=v0[0].num(); auto y=v0[1].num(); @@ -214,11 +214,11 @@ var nas_vec3_len(var* args,usize size,gc* ngc){ return {vm_num,std::sqrt(x*x+y*y+z*z)}; } -var nas_rotate_x(var* args,usize size,gc* ngc){ - if(args[0].type!=vm_vec) +var nas_rotate_x(var* args,usize size,gc* ngc) { + if (args[0].type!=vm_vec) return nil; auto& v0=args[0].vec().elems; - if(v0.size()!=3) + if (v0.size()!=3) return nil; auto angle=args[1].num(); var res=ngc->alloc(vm_vec); @@ -228,11 +228,11 @@ var nas_rotate_x(var* args,usize size,gc* ngc){ return res; } -var nas_rotate_y(var* args,usize size,gc* ngc){ - if(args[0].type!=vm_vec) +var nas_rotate_y(var* args,usize size,gc* ngc) { + if (args[0].type!=vm_vec) return nil; auto& v0=args[0].vec().elems; - if(v0.size()!=3) + if (v0.size()!=3) return nil; auto angle=args[1].num(); var res=ngc->alloc(vm_vec); @@ -242,11 +242,11 @@ var nas_rotate_y(var* args,usize size,gc* ngc){ return res; } -var nas_rotate_z(var* args,usize size,gc* ngc){ - if(args[0].type!=vm_vec) +var nas_rotate_z(var* args,usize size,gc* ngc) { + if (args[0].type!=vm_vec) return nil; auto& v0=args[0].vec().elems; - if(v0.size()!=3) + if (v0.size()!=3) return nil; auto angle=args[1].num(); var res=ngc->alloc(vm_vec); @@ -256,12 +256,12 @@ var nas_rotate_z(var* args,usize size,gc* ngc){ return res; } -var nas_vec3_dot(var* args,usize size,gc* ngc){ - if(args[0].type!=vm_vec || args[1].type!=vm_vec) +var nas_vec3_dot(var* args,usize size,gc* ngc) { + if (args[0].type!=vm_vec || args[1].type!=vm_vec) return nil; auto& v0=args[0].vec().elems; auto& v1=args[1].vec().elems; - if(v0.size()!=3 || v1.size()!=3) + if (v0.size()!=3 || v1.size()!=3) return nil; return {vm_num,v0[0].num()*v1[0].num()+v0[1].num()*v1[1].num()+v0[2].num()*v1[2].num()}; } @@ -291,6 +291,6 @@ mod_func func_tbl[]={ {nullptr,nullptr} }; -extern "C" mod_func* get(){ +extern "C" mod_func* get() { return func_tbl; } \ No newline at end of file diff --git a/module/nasocket.cpp b/module/nasocket.cpp index 82bbc7a..6abd935 100644 --- a/module/nasocket.cpp +++ b/module/nasocket.cpp @@ -9,10 +9,10 @@ class WSAmanager{ private: WSAData data; public: - WSAmanager(){ + WSAmanager() { WSAStartup(0x1010,&data); } - ~WSAmanager(){ + ~WSAmanager() { WSACleanup(); } }; @@ -25,15 +25,15 @@ static WSAmanager win; #include #endif -var nas_socket(var* args,usize size,gc* ngc){ - if(args[0].type!=vm_num || args[1].type!=vm_num || args[2].type!=vm_num) +var nas_socket(var* args,usize size,gc* ngc) { + if (args[0].type!=vm_num || args[1].type!=vm_num || args[2].type!=vm_num) return nas_err("socket","\"af\", \"type\", \"protocol\" should be number"); int sd=socket(args[0].num(),args[1].num(),args[2].num()); return {vm_num,(double)sd}; } -var nas_closesocket(var* args,usize size,gc* ngc){ - if(args[0].type!=vm_num) +var nas_closesocket(var* args,usize size,gc* ngc) { + if (args[0].type!=vm_num) return nas_err("closesocket","\"\" should be number"); #ifdef _WIN32 return {vm_num,(double)closesocket(args[0].num())}; @@ -42,20 +42,20 @@ var nas_closesocket(var* args,usize size,gc* ngc){ #endif } -var nas_shutdown(var* args,usize size,gc* ngc){ - if(args[0].type!=vm_num) +var nas_shutdown(var* args,usize size,gc* ngc) { + if (args[0].type!=vm_num) return nas_err("shutdown","\"sd\" must be a number"); - if(args[1].type!=vm_num) + if (args[1].type!=vm_num) return nas_err("shutdown","\"how\" must be a number"); return {vm_num,(double)shutdown(args[0].num(),args[1].num())}; } -var nas_bind(var* args,usize size,gc* ngc){ - if(args[0].type!=vm_num) +var nas_bind(var* args,usize size,gc* ngc) { + if (args[0].type!=vm_num) return nas_err("bind","\"sd\" muse be a number"); - if(args[1].type!=vm_str) + if (args[1].type!=vm_str) return nas_err("bind","\"ip\" should be a string including an ip with correct format"); - if(args[2].type!=vm_num) + if (args[2].type!=vm_num) return nas_err("bind","\"port\" must be a number"); sockaddr_in server; memset(&server,0,sizeof(sockaddr_in)); @@ -65,20 +65,20 @@ var nas_bind(var* args,usize size,gc* ngc){ return {vm_num,(double)bind(args[0].num(),(sockaddr*)&server,sizeof(server))}; } -var nas_listen(var* args,usize size,gc* ngc){ - if(args[0].type!=vm_num) +var nas_listen(var* args,usize size,gc* ngc) { + if (args[0].type!=vm_num) return nas_err("listen","\"sd\" must be a number"); - if(args[1].type!=vm_num) + if (args[1].type!=vm_num) return nas_err("listen","\"backlog\" must be a number"); return{vm_num,(double)listen(args[0].num(),args[1].num())}; } -var nas_connect(var* args,usize size,gc* ngc){ - if(args[0].type!=vm_num) +var nas_connect(var* args,usize size,gc* ngc) { + if (args[0].type!=vm_num) return nas_err("connect","\"sd\" must be a number"); - if(args[1].type!=vm_str) + if (args[1].type!=vm_str) return nas_err("connect","\"hostname\" must be a string"); - if(args[2].type!=vm_num) + if (args[2].type!=vm_num) return nas_err("connect","\"port\" must be a number"); sockaddr_in addr; memset(&addr,0,sizeof(sockaddr_in)); @@ -89,8 +89,8 @@ var nas_connect(var* args,usize size,gc* ngc){ return {vm_num,(double)connect(args[0].num(),(sockaddr*)&addr,sizeof(sockaddr_in))}; } -var nas_accept(var* args,usize size,gc* ngc){ - if(args[0].type!=vm_num) +var nas_accept(var* args,usize size,gc* ngc) { + if (args[0].type!=vm_num) return nas_err("accept","\"sd\" must be a number"); sockaddr_in client; int socklen=sizeof(sockaddr_in); @@ -107,26 +107,26 @@ var nas_accept(var* args,usize size,gc* ngc){ return res; } -var nas_send(var* args,usize size,gc* ngc){ - if(args[0].type!=vm_num) +var nas_send(var* args,usize size,gc* ngc) { + if (args[0].type!=vm_num) return nas_err("send","\"sd\" must be a number"); - if(args[1].type!=vm_str) + if (args[1].type!=vm_str) return nas_err("send","\"buff\" must be a string"); - if(args[2].type!=vm_num) + if (args[2].type!=vm_num) return nas_err("send","\"flags\" muse be a number"); return {vm_num,(double)send(args[0].num(),args[1].str().c_str(),args[1].str().length(),args[2].num())}; } -var nas_sendto(var* args,usize size,gc* ngc){ - if(args[0].type!=vm_num) +var nas_sendto(var* args,usize size,gc* ngc) { + if (args[0].type!=vm_num) return nas_err("sendto","\"sd\" must be a number"); - if(args[1].type!=vm_str) + if (args[1].type!=vm_str) return nas_err("sendto","\"hostname\" must be a string"); - if(args[2].type!=vm_num) + if (args[2].type!=vm_num) return nas_err("sendto","\"port\" must be a number"); - if(args[3].type!=vm_str) + if (args[3].type!=vm_str) return nas_err("sendto","\"buff\" must be a string"); - if(args[4].type!=vm_num) + if (args[4].type!=vm_num) return nas_err("sendto","\"flags\" must be a number"); sockaddr_in addr; memset(&addr,0,sizeof(sockaddr_in)); @@ -137,14 +137,14 @@ var nas_sendto(var* args,usize size,gc* ngc){ return {vm_num,(double)sendto(args[0].num(),args[3].str().c_str(),args[3].str().length(),args[4].num(),(sockaddr*)&addr,sizeof(sockaddr_in))}; } -var nas_recv(var* args,usize size,gc* ngc){ - if(args[0].type!=vm_num) +var nas_recv(var* args,usize size,gc* ngc) { + if (args[0].type!=vm_num) return nas_err("recv","\"sd\" must be a number"); - if(args[1].type!=vm_num) + if (args[1].type!=vm_num) return nas_err("recv","\"len\" must be a number"); - if(args[1].num()<=0 || args[1].num()>16*1024*1024) + if (args[1].num()<=0 || args[1].num()>16*1024*1024) return nas_err("recv","\"len\" out of range"); - if(args[2].type!=vm_num) + if (args[2].type!=vm_num) return nas_err("recv","\"flags\" muse be a number"); var res=ngc->temp=ngc->alloc(vm_hash); auto& hash=res.hash().elems; @@ -156,14 +156,14 @@ var nas_recv(var* args,usize size,gc* ngc){ return res; } -var nas_recvfrom(var* args,usize size,gc* ngc){ - if(args[0].type!=vm_num) +var nas_recvfrom(var* args,usize size,gc* ngc) { + if (args[0].type!=vm_num) return nas_err("recvfrom","\"sd\" must be a number"); - if(args[1].type!=vm_num) + if (args[1].type!=vm_num) return nas_err("recvfrom","\"len\" must be a number"); - if(args[1].num()<=0 || args[1].num()>16*1024*1024) + if (args[1].num()<=0 || args[1].num()>16*1024*1024) return nas_err("recvfrom","\"len\" out of range"); - if(args[2].type!=vm_num) + if (args[2].type!=vm_num) return nas_err("recvfrom","\"flags\" muse be a number"); sockaddr_in addr; int socklen=sizeof(sockaddr_in); @@ -183,7 +183,7 @@ var nas_recvfrom(var* args,usize size,gc* ngc){ return res; } -var nas_errno(var* args,usize size,gc* ngc){ +var nas_errno(var* args,usize size,gc* ngc) { return ngc->newstr(strerror(errno)); } @@ -203,6 +203,6 @@ mod_func func_tbl[]={ {nullptr,nullptr} }; -extern "C" mod_func* get(){ +extern "C" mod_func* get() { return func_tbl; } \ No newline at end of file diff --git a/nasal.h b/nasal.h index 90d2103..5d57cbe 100644 --- a/nasal.h +++ b/nasal.h @@ -23,115 +23,131 @@ using std::string; const u32 STACK_DEPTH=1024; -inline f64 hex2f(const char* str) -{ +inline f64 hex2f(const char* str) { f64 ret=0; - for(;*str;++str) - { - if('0'<=*str && *str<='9') + for(;*str;++str) { + if ('0'<=*str && *str<='9') { ret=ret*16+(*str-'0'); - else if('a'<=*str && *str<='f') + } else if ('a'<=*str && *str<='f') { ret=ret*16+(*str-'a'+10); - else if('A'<=*str && *str<='F') + } else if ('A'<=*str && *str<='F') { ret=ret*16+(*str-'A'+10); - else + } else { return nan(""); + } } return ret; } -inline f64 oct2f(const char* str) -{ + +inline f64 oct2f(const char* str) { f64 ret=0; - while('0'<=*str && *str<'8') + while('0'<=*str && *str<'8') { ret=ret*8+(*str++-'0'); - if(*str) return nan(""); + } + if (*str) { + return nan(""); + } return ret; } + // we have the same reason not using atof here just as andy's interpreter does. // 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) -{ +inline f64 dec2f(const char* str) { f64 ret=0,negative=1,num_pow=0; - while('0'<=*str && *str<='9') + while('0'<=*str && *str<='9') { ret=ret*10+(*str++-'0'); - if(!*str) return ret; - if(*str=='.') - { - if(!*++str) return nan(""); + } + if (!*str) { + return ret; + } + if (*str=='.') { + if (!*++str) { + return nan(""); + } num_pow=0.1; - while('0'<=*str && *str<='9') - { + while('0'<=*str && *str<='9') { ret+=num_pow*(*str++-'0'); num_pow*=0.1; } - if(!*str) return ret; + if (!*str) { + return ret; + } } - if(*str!='e' && *str!='E') + if (*str!='e' && *str!='E') { return nan(""); - if(!*++str) return nan(""); - if(*str=='-' || *str=='+') + } + if (!*++str) { + return nan(""); + } + if (*str=='-' || *str=='+') { negative=(*str++=='-'? -1:1); - if(!*str) return nan(""); + } + if (!*str) { + return nan(""); + } num_pow=0; - while('0'<=*str && *str<='9') + while('0'<=*str && *str<='9') { num_pow=num_pow*10+(*str++-'0'); - if(*str) return nan(""); + } + if (*str) { + return nan(""); + } return ret*std::pow(10,negative*num_pow); } -f64 str2num(const char* str) -{ + +f64 str2num(const char* str) { bool negative=false; f64 res=0; - if(*str=='-' || *str=='+') + if (*str=='-' || *str=='+') { negative=(*str++=='-'); - if(!*str) + } + if (!*str) { return nan(""); - if(str[0]=='0' && str[1]=='x') + } + if (str[0]=='0' && str[1]=='x') { res=hex2f(str+2); - else if(str[0]=='0' && str[1]=='o') + } else if (str[0]=='0' && str[1]=='o') { res=oct2f(str+2); - else + } else { res=dec2f(str); + } return negative?-res:res; } -i32 utf8_hdchk(const char head) -{ +i32 utf8_hdchk(const char head) { // RFC-2279 but now we use RFC-3629 so nbytes is less than 4 const u8 c=(u8)head; - if((c>>5)==0x06) // 110x xxxx (10xx xxxx)^1 + if ((c>>5)==0x06) { // 110x xxxx (10xx xxxx)^1 return 1; - if((c>>4)==0x0e) // 1110 xxxx (10xx xxxx)^2 + } + if ((c>>4)==0x0e) { // 1110 xxxx (10xx xxxx)^2 return 2; - if((c>>3)==0x1e) // 1111 0xxx (10xx xxxx)^3 + } + if ((c>>3)==0x1e) { // 1111 0xxx (10xx xxxx)^3 return 3; + } return 0; } -string chrhex(const char c) -{ +string chrhex(const char c) { const char hextbl[]="0123456789abcdef"; return {hextbl[(c&0xf0)>>4],hextbl[c&0x0f]}; } -string rawstr(const string& str,const usize maxlen=0) -{ +string rawstr(const string& str,const usize maxlen=0) { string ret(""); - for(auto i:str) - { + for(auto i:str) { #ifdef _WIN32 // windows ps or cmd doesn't output unicode normally // if 'chcp65001' is not enabled, we output the hex - if(i<=0) - { + if (i<=0) { ret+="\\x"+chrhex(i); continue; } #endif - switch(i) - { + switch(i) { case '\0': ret+="\\0"; break; case '\a': ret+="\\a"; break; case '\b': ret+="\\b"; break; @@ -147,8 +163,9 @@ string rawstr(const string& str,const usize maxlen=0) default: ret+=i; break; } } - if(maxlen && ret.length()>maxlen) + if (maxlen && ret.length()>maxlen) { ret=ret.substr(0,maxlen)+"..."; + } return ret; } diff --git a/nasal_ast.h b/nasal_ast.h index 5523b9e..593a982 100644 --- a/nasal_ast.h +++ b/nasal_ast.h @@ -3,7 +3,7 @@ #include #include -enum ast_node:u32{ +enum ast_node:u32 { ast_null=0, // null node ast_root, // mark the root node of ast ast_block, // expression block @@ -125,8 +125,7 @@ const char* ast_name[]={ "ReturnExpression" }; -class ast -{ +class ast { private: u32 nd_line; u32 nd_col; @@ -135,8 +134,8 @@ private: string nd_str; std::vector nd_child; public: - ast(const u32 l,const u32 c,const u32 t): - nd_line(l),nd_col(c),nd_type(t),nd_num(0){} + ast(const u32 l,const u32 c,const u32 t) + : nd_line(l),nd_col(c),nd_type(t),nd_num(0) {} ast(const ast&); ast(ast&&); void dump() const; @@ -145,16 +144,16 @@ public: ast& operator=(const ast&); ast& operator=(ast&&); - ast& operator[](usize n){return nd_child[n];} + ast& operator[](usize n) {return nd_child[n];} const ast& operator[](usize n) const {return nd_child[n];} usize size() const {return nd_child.size();} - void add(ast&& node){nd_child.push_back(std::move(node));} - void add(const ast& node){nd_child.push_back(node);} - void set_line(const u32 l){nd_line=l;} - void set_type(const u32 t){nd_type=t;} - void set_str(const string& s){nd_str=s;} - void set_num(const f64 n){nd_num=n;} + void add(ast&& node) {nd_child.push_back(std::move(node));} + void add(const ast& node) {nd_child.push_back(node);} + void set_line(const u32 l) {nd_line=l;} + void set_type(const u32 t) {nd_type=t;} + 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;} @@ -162,20 +161,18 @@ public: 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;} + inline std::vector& child() {return nd_child;} }; ast::ast(const ast& tmp): - nd_str(tmp.nd_str),nd_child(tmp.nd_child) -{ + nd_str(tmp.nd_str),nd_child(tmp.nd_child) { nd_line=tmp.nd_line; nd_col=tmp.nd_col; nd_type=tmp.nd_type; nd_num =tmp.nd_num; } -ast::ast(ast&& tmp) -{ +ast::ast(ast&& tmp) { nd_line=tmp.nd_line; nd_col=tmp.nd_col; nd_type=tmp.nd_type; @@ -184,8 +181,7 @@ ast::ast(ast&& tmp) nd_child.swap(tmp.nd_child); } -ast& ast::operator=(const ast& tmp) -{ +ast& ast::operator=(const ast& tmp) { nd_line=tmp.nd_line; nd_col=tmp.nd_col; nd_type=tmp.nd_type; @@ -195,8 +191,7 @@ ast& ast::operator=(const ast& tmp) return *this; } -ast& ast::operator=(ast&& tmp) -{ +ast& ast::operator=(ast&& tmp) { nd_line=tmp.nd_line; nd_col=tmp.nd_col; nd_type=tmp.nd_type; @@ -206,8 +201,7 @@ ast& ast::operator=(ast&& tmp) return *this; } -void ast::clear() -{ +void ast::clear() { nd_line=nd_col=0; nd_num=0; nd_str.clear(); @@ -215,34 +209,36 @@ void ast::clear() nd_child.clear(); } -void ast::dump() const -{ +void ast::dump() const{ std::vector tmp; print(0,false,tmp); } -void ast::print(u32 depth,bool last,std::vector& indent) const -{ - for(auto& i:indent) +void ast::print(u32 depth,bool last,std::vector& indent) const{ + for(auto& i:indent) { std::cout< "<1 || !end.str().length()) + if (end.type!=vm_str || end.str().length()>1 || !end.str().length()) { std::cin>>ret.str(); - else + } else { std::getline(std::cin,ret.str(),end.str()[0]); + } return ret; } -var builtin_fin(var* local,gc& ngc) -{ +var builtin_fin(var* local,gc& ngc) { var val=local[1]; - if(val.type!=vm_str) + if (val.type!=vm_str) { return nas_err("io::fin","\"filename\" must be string"); + } std::ifstream in(val.str(),std::ios::binary); std::stringstream rd; - if(!in.fail()) + if (!in.fail()) { rd<"); + } out<last) + while(pos!=string::npos) { + if (pos>last) { vec.push_back(ngc.newstr(s.substr(last,pos-last))); + } last=pos+deli.length(); pos=s.find(deli,last); } - if(last!=s.length()) + if (last!=s.length()) { vec.push_back(ngc.newstr(s.substr(last))); + } ngc.temp=nil; return res; } -var builtin_rand(var* local,gc& ngc) -{ +var builtin_rand(var* local,gc& ngc) { var val=local[1]; - if(val.type!=vm_num && val.type!=vm_nil) + if (val.type!=vm_num && val.type!=vm_nil) { return nas_err("rand","\"seed\" must be nil or number"); - if(val.type==vm_num) - { + } + if (val.type==vm_num) { srand((u32)val.num()); return nil; } f64 num=0; - for(u32 i=0;i<5;++i) + for(u32 i=0;i<5;++i) { num=(num+rand())*(1.0/(RAND_MAX+1.0)); + } return {vm_num,num}; } -var builtin_id(var* local,gc& ngc) -{ +var builtin_id(var* local,gc& ngc) { var val=local[1]; std::stringstream ss; ss<<"0"; - if(val.type>vm_num) + if (val.type>vm_num) { ss<<"x"<= 0"); - if(len.type!=vm_num || len.num()<0) + } + if (len.type!=vm_num || len.num()<0) { return nas_err("substr","\"length\" should be number >= 0"); + } usize begin=(usize)beg.num(); usize length=(usize)len.num(); - if(begin>=str.str().length() || begin+length>str.str().length()) + if (begin>=str.str().length() || begin+length>str.str().length()) { return nas_err("susbtr","index out of range"); + } return ngc.newstr(str.str().substr(begin,length)); } -var builtin_streq(var* local,gc& ngc) -{ +var builtin_streq(var* local,gc& ngc) { var a=local[1]; var b=local[2]; return {vm_num,f64((a.type!=vm_str || b.type!=vm_str)?0:(a.str()==b.str()))}; } -var builtin_left(var* local,gc& ngc) -{ +var builtin_left(var* local,gc& ngc) { var str=local[1]; var len=local[2]; - if(str.type!=vm_str) + if (str.type!=vm_str) { return nas_err("left","\"string\" must be string"); - if(len.type!=vm_num) + } + if (len.type!=vm_num) { return nas_err("left","\"length\" must be number"); - if(len.num()<0) + } + if (len.num()<0) { return ngc.newstr(""); + } return ngc.newstr(str.str().substr(0,len.num())); } -var builtin_right(var* local,gc& ngc) -{ +var builtin_right(var* local,gc& ngc) { var str=local[1]; var len=local[2]; - if(str.type!=vm_str) + if (str.type!=vm_str) { return nas_err("right","\"string\" must be string"); - if(len.type!=vm_num) + } + if (len.type!=vm_num) { return nas_err("right","\"length\" must be number"); + } i32 length=(i32)len.num(); i32 srclen=str.str().length(); - if(length>srclen) + if (length>srclen) { length=srclen; - if(length<0) + } + if (length<0) { length=0; + } return ngc.newstr(str.str().substr(srclen-length,srclen)); } -var builtin_cmp(var* local,gc& ngc) -{ +var builtin_cmp(var* local,gc& ngc) { var a=local[1]; var b=local[2]; - if(a.type!=vm_str || b.type!=vm_str) + if (a.type!=vm_str || b.type!=vm_str) { return nas_err("cmp","\"a\" and \"b\" must be string"); + } return {vm_num,(f64)strcmp(a.str().c_str(),b.str().c_str())}; } -var builtin_chr(var* local,gc& ngc) -{ +var builtin_chr(var* local,gc& ngc) { const char* extend[]={ "€"," ","‚","ƒ","„","…","†","‡", "ˆ","‰","Š","‹","Œ"," ","Ž"," ", @@ -527,78 +516,85 @@ var builtin_chr(var* local,gc& ngc) "ø","ù","ú","û","ü","ý","þ","ÿ" }; i32 num=local[1].num(); - if(0<=num && num<128) + if (0<=num && num<128) { return ngc.newstr((char)num); - else if(128<=num && num<256) + } else if (128<=num && num<256) { return ngc.newstr(extend[num-128]); + } return ngc.newstr(" "); } -var builtin_char(var* local,gc& ngc) -{ +var builtin_char(var* local,gc& ngc) { return ngc.newstr((char)local[1].num()); } -var builtin_values(var* local,gc& ngc) -{ +var builtin_values(var* local,gc& ngc) { var hash=local[1]; - if(hash.type!=vm_hash) + if (hash.type!=vm_hash) { return nas_err("values","\"hash\" must be hash"); + } var vec=ngc.alloc(vm_vec); auto& v=vec.vec().elems; - for(auto& i:hash.hash().elems) + for(auto& i:hash.hash().elems) { v.push_back(i.second); + } return vec; } -var builtin_exists(var* local,gc& ngc) -{ - if(local[1].type!=vm_str) +var builtin_exists(var* local,gc& ngc) { + if (local[1].type!=vm_str) { return zero; + } return access(local[1].str().c_str(),F_OK)!=-1?one:zero; } -var builtin_open(var* local,gc& ngc) -{ +var builtin_open(var* local,gc& ngc) { var name=local[1]; var mode=local[2]; - if(name.type!=vm_str) + if (name.type!=vm_str) { return nas_err("open","\"filename\" must be string"); - if(mode.type!=vm_str) + } + if (mode.type!=vm_str) { return nas_err("open","\"mode\" must be string"); + } FILE* res=fopen(name.str().c_str(),mode.str().c_str()); - if(!res) + if (!res) { return nas_err("open","failed to open file <"+name.str()+">"); + } var ret=ngc.alloc(vm_obj); ret.obj().set(nas_obj::file,res); return ret; } -var builtin_close(var* local,gc& ngc) -{ +var builtin_close(var* local,gc& ngc) { var fd=local[1]; - if(!fd.objchk(nas_obj::file)) + if (!fd.objchk(nas_obj::file)) { return nas_err("close","not a valid filehandle"); + } fd.obj().clear(); return nil; } -var builtin_read(var* local,gc& ngc) -{ +var builtin_read(var* local,gc& ngc) { var fd=local[1]; var buf=local[2]; var len=local[3]; - if(!fd.objchk(nas_obj::file)) + if (!fd.objchk(nas_obj::file)) { return nas_err("read","not a valid filehandle"); - if(buf.type!=vm_str || buf.val.gcobj->unmut) + } + if (buf.type!=vm_str || buf.val.gcobj->unmut) { return nas_err("read","\"buf\" must be mutable string"); - if(len.type!=vm_num) + } + if (len.type!=vm_num) { return nas_err("read","\"len\" must be number"); - if(len.num()<=0 || len.num()>=(1<<30)) + } + if (len.num()<=0 || len.num()>=(1<<30)) { return nas_err("read","\"len\" less than 1 or too large"); + } char* buff=new char[(usize)len.num()+1]; - if(!buff) + if (!buff) { return nas_err("read","malloc failed"); + } f64 res=fread(buff,1,len.num(),(FILE*)fd.obj().ptr); buf.str()=buff; buf.val.gcobj->unmut=true; @@ -606,63 +602,67 @@ var builtin_read(var* local,gc& ngc) return {vm_num,res}; } -var builtin_write(var* local,gc& ngc) -{ +var builtin_write(var* local,gc& ngc) { var fd=local[1]; var str=local[2]; - if(!fd.objchk(nas_obj::file)) + if (!fd.objchk(nas_obj::file)) { return nas_err("write","not a valid filehandle"); - if(str.type!=vm_str) + } + if (str.type!=vm_str) { return nas_err("write","\"str\" must be string"); + } return {vm_num,(f64)fwrite(str.str().c_str(),1,str.str().length(),(FILE*)fd.obj().ptr)}; } -var builtin_seek(var* local,gc& ngc) -{ +var builtin_seek(var* local,gc& ngc) { var fd=local[1]; var pos=local[2]; var whence=local[3]; - if(!fd.objchk(nas_obj::file)) + if (!fd.objchk(nas_obj::file)) { return nas_err("seek","not a valid filehandle"); + } return {vm_num,(f64)fseek((FILE*)fd.obj().ptr,pos.num(),whence.num())}; } -var builtin_tell(var* local,gc& ngc) -{ +var builtin_tell(var* local,gc& ngc) { var fd=local[1]; - if(!fd.objchk(nas_obj::file)) + if (!fd.objchk(nas_obj::file)) { return nas_err("tell","not a valid filehandle"); + } return {vm_num,(f64)ftell((FILE*)fd.obj().ptr)}; } -var builtin_readln(var* local,gc& ngc) -{ +var builtin_readln(var* local,gc& ngc) { var fd=local[1]; - if(!fd.objchk(nas_obj::file)) + if (!fd.objchk(nas_obj::file)) { return nas_err("readln","not a valid filehandle"); + } var str=ngc.alloc(vm_str); char c; - while((c=fgetc((FILE*)fd.obj().ptr))!=EOF) - { - if(c=='\r') + while((c=fgetc((FILE*)fd.obj().ptr))!=EOF) { + if (c=='\r') { continue; - if(c=='\n') + } + if (c=='\n') { return str; + } str.str()+=c; } - if(str.str().length()) + if (str.str().length()) { return str; + } return nil; } -var builtin_stat(var* local,gc& ngc) -{ +var builtin_stat(var* local,gc& ngc) { var name=local[1]; - if(name.type!=vm_str) + if (name.type!=vm_str) { return nas_err("stat","\"filename\" must be string"); + } struct stat buf; - if(stat(name.str().c_str(),&buf)<0) + if (stat(name.str().c_str(),&buf)<0) { return nas_err("stat","failed to open file <"+name.str()+">"); + } var ret=ngc.alloc(vm_vec); ret.vec().elems={ {vm_num,(f64)buf.st_dev}, @@ -680,40 +680,43 @@ var builtin_stat(var* local,gc& ngc) return ret; } -var builtin_eof(var* local,gc& ngc) -{ +var builtin_eof(var* local,gc& ngc) { var fd=local[1]; - if(!fd.objchk(nas_obj::file)) + if (!fd.objchk(nas_obj::file)) { return nas_err("readln","not a valid filehandle"); + } return {vm_num,(f64)feof((FILE*)fd.obj().ptr)}; } -var builtin_fld(var* local,gc& ngc) -{ +var builtin_fld(var* local,gc& ngc) { // bits.fld(s,0,3); // if s stores 10100010(162) // will get 101(5) var str=local[1]; var startbit=local[2]; var length=local[3]; - if(str.type!=vm_str || str.val.gcobj->unmut) + if (str.type!=vm_str || str.val.gcobj->unmut) { return nas_err("fld","\"str\" must be mutable string"); - if(startbit.type!=vm_num || length.type!=vm_num) + } + if (startbit.type!=vm_num || length.type!=vm_num) { return nas_err("fld","\"startbit\",\"len\" must be number"); + } u32 bit=(u32)startbit.num(); u32 len=(u32)length.num(); - if(bit+len>8*str.str().length()) + if (bit+len>8*str.str().length()) { return nas_err("fld","bitfield out of bounds"); + } u32 res=0; auto& s=str.str(); - for(u32 i=bit;i>3]&(1<<(7-(i&7)))) + for(u32 i=bit;i>3]&(1<<(7-(i&7)))) { res|=1<<(bit+len-i-1); + } + } return {vm_num,(f64)res}; } -var builtin_sfld(var* local,gc& ngc) -{ +var builtin_sfld(var* local,gc& ngc) { // bits.sfld(s,0,3); // if s stores 10100010(162) // will get 101(5) then this will be signed extended to @@ -721,26 +724,31 @@ var builtin_sfld(var* local,gc& ngc) var str=local[1]; var startbit=local[2]; var length=local[3]; - if(str.type!=vm_str || str.val.gcobj->unmut) + if (str.type!=vm_str || str.val.gcobj->unmut) { return nas_err("sfld","\"str\" must be mutable string"); - if(startbit.type!=vm_num || length.type!=vm_num) + } + if (startbit.type!=vm_num || length.type!=vm_num) { return nas_err("sfld","\"startbit\",\"len\" must be number"); + } u32 bit=(u32)startbit.num(); u32 len=(u32)length.num(); - if(bit+len>8*str.str().length()) + if (bit+len>8*str.str().length()) { return nas_err("sfld","bitfield out of bounds"); + } u32 res=0; auto& s=str.str(); - for(u32 i=bit;i>3]&(1<<(7-(i&7)))) + for(u32 i=bit;i>3]&(1<<(7-(i&7)))) { res|=1<<(bit+len-i-1); - if(res&(1<<(len-1))) + } + } + if (res&(1<<(len-1))) { res|=~((1<unmut) + if (str.type!=vm_str || str.val.gcobj->unmut) { return nas_err("setfld","\"str\" must be mutable string"); - if(startbit.type!=vm_num || length.type!=vm_num || value.type!=vm_num) + } + if (startbit.type!=vm_num || length.type!=vm_num || value.type!=vm_num) { return nas_err("setfld","\"startbit\",\"len\",\"val\" must be number"); + } u32 bit=(u32)startbit.num(); u32 len=(u32)length.num(); u64 val=(u64)value.num(); - if(bit+len>8*str.str().length()) + if (bit+len>8*str.str().length()) { return nas_err("setfld","bitfield out of bounds"); + } auto& s=str.str(); - for(u32 i=bit;i>3]|=(1<<(7-(i&7))); - else + } else { s[i>>3]&=~(1<<(7-(i&7))); + } } return nil; } -var builtin_buf(var* local,gc& ngc) -{ +var builtin_buf(var* local,gc& ngc) { var length=local[1]; - if(length.type!=vm_num || length.num()<=0) + if (length.type!=vm_num || length.num()<=0) { return nas_err("buf","\"len\" must be number greater than 0"); + } var str=ngc.alloc(vm_str); auto& s=str.str(); s.resize(length.num(),'\0'); return str; } -var builtin_sleep(var* local,gc& ngc) -{ +var builtin_sleep(var* local,gc& ngc) { var val=local[1]; - if(val.type!=vm_num) + if (val.type!=vm_num) { return nil; + } std::this_thread::sleep_for(std::chrono::microseconds(i64(val.num()*1e6))); return nil; } -var builtin_pipe(var* local,gc& ngc) -{ +var builtin_pipe(var* local,gc& ngc) { #ifndef _WIN32 i32 fd[2]; var res=ngc.alloc(vm_vec); - if(pipe(fd)==-1) + if (pipe(fd)==-1) { return nas_err("pipe","failed to create pipe"); + } res.vec().elems.push_back({vm_num,(f64)fd[0]}); res.vec().elems.push_back({vm_num,(f64)fd[1]}); return res; @@ -803,23 +814,23 @@ var builtin_pipe(var* local,gc& ngc) return nas_err("pipe","not supported"); } -var builtin_fork(var* local,gc& ngc) -{ +var builtin_fork(var* local,gc& ngc) { #ifndef _WIN32 f64 res=fork(); - if(res<0) + if (res<0) { return nas_err("fork","failed to fork a process"); + } return {vm_num,(f64)res}; #endif return nas_err("fork","not supported"); } -var builtin_waitpid(var* local,gc& ngc) -{ +var builtin_waitpid(var* local,gc& ngc) { var pid=local[1]; var nohang=local[2]; - if(pid.type!=vm_num || nohang.type!=vm_num) + if (pid.type!=vm_num || nohang.type!=vm_num) { return nas_err("waitpid","pid and nohang must be number"); + } #ifndef _WIN32 i32 ret_pid,status; ret_pid=waitpid(pid.num(),&status,nohang.num()==0?0:WNOHANG); @@ -831,36 +842,39 @@ var builtin_waitpid(var* local,gc& ngc) return nas_err("waitpid","not supported"); } -var builtin_opendir(var* local,gc& ngc) -{ +var builtin_opendir(var* local,gc& ngc) { var path=local[1]; - if(path.type!=vm_str) + if (path.type!=vm_str) { return nas_err("opendir","\"path\" must be string"); + } #ifdef _MSC_VER WIN32_FIND_DATAA data; HANDLE p; p=FindFirstFileA((path.str()+"\\*.*").c_str(),&data); - if(p==INVALID_HANDLE_VALUE) + if (p==INVALID_HANDLE_VALUE) { return nas_err("opendir","cannot open dir <"+path.str()+">"); + } #else DIR* p=opendir(path.str().c_str()); - if(!p) + if (!p) { return nas_err("opendir","cannot open dir <"+path.str()+">"); + } #endif var ret=ngc.alloc(vm_obj); ret.obj().set(nas_obj::dir,p); return ret; } -var builtin_readdir(var* local,gc& ngc) -{ +var builtin_readdir(var* local,gc& ngc) { var handle=local[1]; - if(!handle.objchk(nas_obj::dir)) + if (!handle.objchk(nas_obj::dir)) { return nas_err("readdir","not a valid dir handle"); + } #ifdef _MSC_VER WIN32_FIND_DATAA data; - if(!FindNextFileA(handle.obj().ptr,&data)) + if (!FindNextFileA(handle.obj().ptr,&data)) { return nil; + } return ngc.newstr(data.cFileName); #else dirent* p=readdir((DIR*)handle.obj().ptr); @@ -868,59 +882,60 @@ var builtin_readdir(var* local,gc& ngc) #endif } -var builtin_closedir(var* local,gc& ngc) -{ +var builtin_closedir(var* local,gc& ngc) { var handle=local[1]; - if(!handle.objchk(nas_obj::dir)) + if (!handle.objchk(nas_obj::dir)) { return nas_err("closedir","not a valid dir handle"); + } handle.obj().clear(); return nil; } -var builtin_chdir(var* local,gc& ngc) -{ +var builtin_chdir(var* local,gc& ngc) { var path=local[1]; - if(path.type!=vm_str) + if (path.type!=vm_str) { return {vm_num,(f64)-1}; + } return {vm_num,(f64)chdir(path.str().c_str())}; } -var builtin_environ(var* local,gc& ngc) -{ +var builtin_environ(var* local,gc& ngc) { var res=ngc.temp=ngc.alloc(vm_vec); auto& vec=res.vec().elems; - for(char** env=environ;*env;++env) + for(char** env=environ;*env;++env) { vec.push_back(ngc.newstr(*env)); + } ngc.temp=nil; return res; } -var builtin_getcwd(var* local,gc& ngc) -{ +var builtin_getcwd(var* local,gc& ngc) { char buf[1024]; - if(!getcwd(buf,sizeof(buf))) + if (!getcwd(buf,sizeof(buf))) { return nil; + } return ngc.newstr(buf); } -var builtin_getenv(var* local,gc& ngc) -{ +var builtin_getenv(var* local,gc& ngc) { var envvar=local[1]; - if(envvar.type!=vm_str) + if (envvar.type!=vm_str) { return nas_err("getenv","\"envvar\" must be string"); + } char* res=getenv(envvar.str().c_str()); return res?ngc.newstr(res):nil; } -var builtin_dlopen(var* local,gc& ngc) -{ +var builtin_dlopen(var* local,gc& ngc) { var dlname=local[1]; - if(dlname.type!=vm_str) + if (dlname.type!=vm_str) { return nas_err("dlopen","\"libname\" must be string"); + } #ifdef _WIN32 wchar_t* str=new wchar_t[dlname.str().size()+1]; - if(!str) + if (!str) { return nas_err("dlopen","malloc failed"); + } memset(str,0,sizeof(wchar_t)*dlname.str().size()+1); mbstowcs(str,dlname.str().c_str(),dlname.str().size()+1); void* ptr=LoadLibraryA(dlname.str().c_str()); @@ -928,8 +943,9 @@ var builtin_dlopen(var* local,gc& ngc) #else void* ptr=dlopen(dlname.str().c_str(),RTLD_LOCAL|RTLD_LAZY); #endif - if(!ptr) + if (!ptr) { return nas_err("dlopen","cannot open dynamic lib <"+dlname.str()+">"); + } var ret=ngc.temp=ngc.alloc(vm_hash); var lib=ngc.alloc(vm_obj); lib.obj().set(nas_obj::dylib,ptr); @@ -940,13 +956,15 @@ var builtin_dlopen(var* local,gc& ngc) #else void* func=dlsym(lib.obj().ptr,"get"); #endif - if(!func) + if (!func) { return nas_err("dlopen","cannot find function"); + } // get function pointer by name mod_func* tbl=(mod_func*)((getptr)func)(); - if(!tbl) + if (!tbl) { return nas_err("dlopen","failed to get module functions"); - for(u32 i=0;tbl[i].name;++i){ + } + for(u32 i=0;tbl[i].name;++i) { void* p=(void*)tbl[i].fd; var tmp=ngc.alloc(vm_obj); tmp.obj().set(nas_obj::faddr,p); @@ -957,36 +975,35 @@ var builtin_dlopen(var* local,gc& ngc) return ret; } -var builtin_dlclose(var* local,gc& ngc) -{ +var builtin_dlclose(var* local,gc& ngc) { var libptr=local[1]; - if(!libptr.objchk(nas_obj::dylib)) + if (!libptr.objchk(nas_obj::dylib)) { return nas_err("dlclose","\"lib\" is not a valid dynamic lib"); + } libptr.obj().clear(); return nil; } -var builtin_dlcallv(var* local,gc& ngc) -{ +var builtin_dlcallv(var* local,gc& ngc) { var fp=local[1]; var args=local[2]; - if(!fp.objchk(nas_obj::faddr)) + if (!fp.objchk(nas_obj::faddr)) { return nas_err("dlcall","\"ptr\" is not a valid function pointer"); + } auto& vec=args.vec().elems; return ((mod)fp.obj().ptr)(vec.data(),vec.size(),&ngc); } -var builtin_dlcall(var* local,gc& ngc) -{ +var builtin_dlcall(var* local,gc& ngc) { var fp=local[1]; - if(!fp.objchk(nas_obj::faddr)) + if (!fp.objchk(nas_obj::faddr)) { return nas_err("dlcall","\"ptr\" is not a valid function pointer"); + } // arguments' stored place begins at local +2 return ((mod)fp.obj().ptr)(local+2,ngc.top-local-2,&ngc); } -var builtin_platform(var* local,gc& ngc) -{ +var builtin_platform(var* local,gc& ngc) { #if defined _WIN32 || defined _WIN64 return ngc.newstr("windows"); #elif defined __linux__ @@ -998,28 +1015,27 @@ var builtin_platform(var* local,gc& ngc) } // md5 related functions -string tohex(u32 num) -{ +string tohex(u32 num) { const char str16[]="0123456789abcdef"; string str=""; - for(u32 i=0;i<4;i++,num>>=8) - { + for(u32 i=0;i<4;i++,num>>=8) { string tmp=""; - for(u32 j=0,b=num&0xff;j<2;j++,b>>=4) + for(u32 j=0,b=num&0xff;j<2;j++,b>>=4) { tmp.insert(0,1,str16[b&0xf]); + } str+=tmp; } return str; } -string md5(const string& src) -{ +string md5(const string& src) { std::vector buff; usize num=((src.length()+8)>>6)+1; usize buffsize=num<<4; buff.resize(buffsize,0); - for(usize i=0;i>2]|=((u8)src[i])<<((i&0x3)<<3); + } buff[src.length()>>2]|=0x80<<(((src.length()%4))<<3); buff[buffsize-2]=(src.length()<<3)&0xffffffff; buff[buffsize-1]=((src.length()<<3)>>32)&0xffffffff; @@ -1060,14 +1076,12 @@ string md5(const string& src) u32 atmp=0x67452301,btmp=0xefcdab89; u32 ctmp=0x98badcfe,dtmp=0x10325476; - for(u32 i=0;i (std::chrono::high_resolution_clock::now().time_since_epoch()) .count(); return {vm_num,res}; } -var builtin_sysargv(var* local,gc& ngc) -{ +var builtin_sysargv(var* local,gc& ngc) { var res=ngc.alloc(vm_vec); res.vec().elems=ngc.env_argv; return res; } -var builtin_logtime(var* local,gc& ngc) -{ +var builtin_logtime(var* local,gc& ngc) { time_t t=time(nullptr); tm* tm_t=localtime(&t); char s[128]; @@ -1206,12 +1218,10 @@ var builtin_logtime(var* local,gc& ngc) // register builtin function's name and it's address here in this table below // this table must end with {nullptr,nullptr} -struct -{ +struct { const char* name; var (*func)(var*,gc&); -} builtin[]= -{ +} builtin[]= { {"__print", builtin_print }, {"__println", builtin_println }, {"__exit", builtin_exit }, diff --git a/nasal_codegen.h b/nasal_codegen.h index 16d68e0..d0316a8 100644 --- a/nasal_codegen.h +++ b/nasal_codegen.h @@ -6,8 +6,7 @@ #include #include -enum op_code_type:u8 -{ +enum op_code_type:u8 { op_exit, // stop the virtual machine op_intg, // global scope size op_intl, // local scope size @@ -85,8 +84,7 @@ enum op_code_type:u8 op_ret // return }; -const char* opname[]= -{ +const char* opname[]={ "exit ","intg ","intl ","loadg ", "loadl ","loadu ","pnum ","pnil ", "pstr ","newv ","newh ","newf ", @@ -108,16 +106,14 @@ const char* opname[]= "mcallv","mcallh","ret " }; -struct opcode -{ +struct opcode { u8 op; // opcode u16 fidx;// source code file index u32 num; // imm num u32 line;// line of source code opcode(u8 o=op_exit,u16 f=0,u32 n=0,u32 l=0): - op(o),fidx(f),num(n),line(l){} - opcode& operator=(const opcode& tmp) - { + op(o),fidx(f),num(n),line(l) {} + opcode& operator=(const opcode& tmp) { op=tmp.op; fidx=tmp.fidx; num=tmp.num; @@ -126,8 +122,7 @@ struct opcode } }; -class codestream -{ +class codestream { private: opcode code; const u32 index; @@ -136,9 +131,8 @@ private: const string* files; public: codestream(const opcode& c,const u32 i,const f64* n,const string* s,const string* f=nullptr): - code(c.op,c.fidx,c.num,c.line),index(i),nums(n),strs(s),files(f){} - friend std::ostream& operator<<(std::ostream& out,const codestream& ins) - { + code(c.op,c.fidx,c.num,c.line),index(i),nums(n),strs(s),files(f) {} + friend std::ostream& operator<<(std::ostream& out,const codestream& ins) { u8 op=ins.code.op; u32 num=ins.code.num; out<>8)&0xff)<<" " <& strs() const {return str_res;} @@ -274,148 +268,136 @@ public: const std::vector& codes() const {return code;} }; -bool codegen::check_memory_reachable(const ast& node) -{ - if(node.type()==ast_call){ +bool codegen::check_memory_reachable(const ast& node) { + if (node.type()==ast_call) { const ast& tmp=node.child().back(); - if(tmp.type()==ast_callf){ + if (tmp.type()==ast_callf) { die("bad left-value",tmp.line(),tmp.col(),1); return false; } - if(tmp.type()==ast_callv && (tmp.size()==0 || tmp.size()>1 || tmp[0].type()==ast_subvec)){ + if (tmp.type()==ast_callv && (tmp.size()==0 || tmp.size()>1 || tmp[0].type()==ast_subvec)) { die("bad left-value",tmp.line(),tmp.col(),1); return false; } - }else if(node.type()!=ast_id){ + } else if (node.type()!=ast_id) { die("bad left-value",node.line(),node.col(),1); return false; } return true; } -void codegen::die(const string& info,const u32 line,const u32 col,const u32 len=1) -{ +void codegen::die(const string& info,const u32 line,const u32 col,const u32 len=1) { err.load(file[fileindex]); err.err("code",line,col,len,info); } -void codegen::regist_num(const f64 num) -{ - if(!num_table.count(num)) - { +void codegen::regist_num(const f64 num) { + if (!num_table.count(num)) { u32 size=num_table.size(); num_table[num]=size; num_res.push_back(num); } } -void codegen::regist_str(const string& str) -{ - if(!str_table.count(str)) - { +void codegen::regist_str(const string& str) { + if (!str_table.count(str)) { u32 size=str_table.size(); str_table[str]=size; str_res.push_back(str); } } -void codegen::find_symbol(const ast& node) -{ +void codegen::find_symbol(const ast& node) { // symbol definition checked here // if find a function, return - if(node.type()==ast_func) + if (node.type()==ast_func) { return; - // find definition, check - else if(node.type()==ast_def) - { - if(node[0].type()==ast_multi_id) - for(auto& i:node[0].child()) + } else if (node.type()==ast_def) { // find definition, check + if (node[0].type()==ast_multi_id) { + for(auto& i:node[0].child()) { add_sym(i.str()); - else + } + } else { add_sym(node[0].str()); + } find_symbol(node[1]); - } - // find iterator(foreach, forindex), check - else if(node.type()==ast_iter) + } else if (node.type()==ast_iter) { // find iterator(foreach, forindex), check add_sym(node[0].str()); - // check children - else - for(auto& i:node.child()) + } else { // check children + for(auto& i:node.child()) { find_symbol(i); + } + } } -void codegen::add_sym(const string& name) -{ - if(local.empty()) - { - if(global.count(name)) +void codegen::add_sym(const string& name) { + if (local.empty()) { + if (global.count(name)) { return; + } i32 index=global.size(); global[name]=index; return; } - if(local.back().count(name)) + if (local.back().count(name)) { return; + } i32 index=local.back().size(); local.back()[name]=index; } -i32 codegen::local_find(const string& name) -{ - if(local.empty()) +i32 codegen::local_find(const string& name) { + if (local.empty()) { return -1; + } return local.back().count(name)?local.back()[name]:-1; } -i32 codegen::global_find(const string& name) -{ +i32 codegen::global_find(const string& name) { return global.count(name)?global[name]:-1; } -i32 codegen::upvalue_find(const string& name) -{ +i32 codegen::upvalue_find(const string& name) { // 32768 level 65536 upvalues i32 index=-1; usize size=local.size(); - if(size<=1) + if (size<=1) { return -1; + } auto iter=local.begin(); - for(u32 i=0;icount(name)) + for(u32 i=0;icount(name)) { index=((i<<16)|(*iter)[name]); + } + } return index; } -void codegen::gen(u8 op,u32 num,u32 line) -{ +void codegen::gen(u8 op,u32 num,u32 line) { code.push_back({op,fileindex,num,line}); } -void codegen::num_gen(const ast& node) -{ +void codegen::num_gen(const ast& node) { f64 num=node.num(); regist_num(num); gen(op_pnum,num_table[num],node.line()); } -void codegen::str_gen(const ast& node) -{ +void codegen::str_gen(const ast& node) { regist_str(node.str()); gen(op_pstr,str_table[node.str()],node.line()); } -void codegen::vec_gen(const ast& node) -{ - for(auto& child:node.child()) +void codegen::vec_gen(const ast& node) { + for(auto& child:node.child()) { calc_gen(child); + } gen(op_newv,node.size(),node.line()); } -void codegen::hash_gen(const ast& node) -{ +void codegen::hash_gen(const ast& node) { gen(op_newh,0,node.line()); - for(auto& child:node.child()) - { + for(auto& child:node.child()) { calc_gen(child[1]); const string& str=child[0].str(); regist_str(str); @@ -423,30 +405,29 @@ void codegen::hash_gen(const ast& node) } } -void codegen::func_gen(const ast& node) -{ +void codegen::func_gen(const ast& node) { // parameter list format check bool checked_default=false; bool checked_dynamic=false; std::unordered_map argname; - for(auto& tmp:node[0].child()){ - if(tmp.type()==ast_default){ + for(auto& tmp:node[0].child()) { + if (tmp.type()==ast_default) { checked_default=true; - }else if(tmp.type()==ast_dynamic){ + } else if (tmp.type()==ast_dynamic) { checked_dynamic=true; } // check default parameter and dynamic parameter - if(checked_default && tmp.type()!=ast_default){ + if (checked_default && tmp.type()!=ast_default) { die("must use default parameters here",tmp.line(),tmp.col(),tmp.str().length()); } - if(checked_dynamic && &tmp!=&node[0].child().back()){ + if (checked_dynamic && &tmp!=&node[0].child().back()) { die("dynamic parameter must be the last one",tmp.line(),tmp.col(),tmp.str().length()); } // check redefinition string name=tmp.str(); - if(argname.count(name)){ + if (argname.count(name)) { die("redefinition of parameter: "+name,tmp.line(),tmp.col(),name.length()); - }else{ + } else { argname[name]=true; } } @@ -464,14 +445,13 @@ void codegen::func_gen(const ast& node) local.push_back({{"me",0}}); // generate parameter list - for(auto& tmp:node[0].child()) - { + for(auto& tmp:node[0].child()) { const string& str=tmp.str(); - if(str=="me") + if (str=="me") { die("\"me\" should not be a parameter",tmp.line(),tmp.col(),tmp.str().length()); + } regist_str(str); - switch(tmp.type()) - { + switch(tmp.type()) { case ast_id:gen(op_para,str_table[str],tmp.line());break; case ast_default: calc_gen(tmp[0]); @@ -494,28 +474,26 @@ void codegen::func_gen(const ast& node) block_gen(block); in_iterloop.pop(); code[lsize].num=local.back().size(); - if(local.back().size()>=STACK_DEPTH) + if (local.back().size()>=STACK_DEPTH) { die("too many local variants: "+std::to_string(local.back().size()),block.line(),0); + } local.pop_back(); - if(!block.size() || block.child().back().type()!=ast_ret) - { + if (!block.size() || block.child().back().type()!=ast_ret) { gen(op_pnil,0,block.line()); gen(op_ret,0,block.line()); } code[jmp_ptr].num=code.size(); } -void codegen::call_gen(const ast& node) -{ +void codegen::call_gen(const ast& node) { calc_gen(node[0]); - if(code.back().op==op_callb) + if (code.back().op==op_callb) { return; - for(usize i=1;i=0) - { + if ((index=local_find(str))>=0) { gen(op_calll,index,node.line()); return; } - if((index=upvalue_find(str))>=0) - { + if ((index=upvalue_find(str))>=0) { gen(op_upval,index,node.line()); return; } - if((index=global_find(str))>=0) - { + if ((index=global_find(str))>=0) { gen(op_callg,index,node.line()); return; } die("undefined symbol \""+str+"\"",node.line(),node.col(),node.str().length()); } -void codegen::call_hash(const ast& node) -{ +void codegen::call_hash(const ast& node) { regist_str(node.str()); gen(op_callh,str_table[node.str()],node.line()); } -void codegen::call_vec(const ast& node) -{ +void codegen::call_vec(const ast& node) { // maybe this place can use callv-const if ast's first child is ast_num - if(node.size()==1 && node[0].type()!=ast_subvec) - { + if (node.size()==1 && node[0].type()!=ast_subvec) { calc_gen(node[0]); gen(op_callv,0,node[0].line()); return; } gen(op_slcbeg,0,node.line()); - for(auto& tmp:node.child()) - { - if(tmp.type()!=ast_subvec) - { + for(auto& tmp:node.child()) { + if (tmp.type()!=ast_subvec) { calc_gen(tmp); gen(op_slc,0,tmp.line()); - } - else - { + } else { calc_gen(tmp[0]); calc_gen(tmp[1]); gen(op_slc2,0,tmp.line()); @@ -586,19 +554,16 @@ void codegen::call_vec(const ast& node) gen(op_slcend,0,node.line()); } -void codegen::call_func(const ast& node) -{ - if(!node.size()) +void codegen::call_func(const ast& node) { + if (!node.size()) { gen(op_callfv,0,node.line()); - else if(node[0].type()==ast_pair) - { + } else if (node[0].type()==ast_pair) { hash_gen(node); gen(op_callfh,0,node.line()); - } - else - { - for(auto& child:node.child()) + } else { + for(auto& child:node.child()) { calc_gen(child); + } gen(op_callfv,node.size(),node.line()); } } @@ -611,108 +576,91 @@ void codegen::call_func(const ast& node) * so we use another way to avoid gc-caused SIGSEGV: reserve m-called value on stack. * you could see the notes in `vm::opr_mcallv()`. */ -void codegen::mcall(const ast& node) -{ - if(!check_memory_reachable(node)){ +void codegen::mcall(const ast& node) { + if (!check_memory_reachable(node)) { return; } - if(node.type()==ast_id) - { + if (node.type()==ast_id) { mcall_id(node); return; } - if(node.size()==1) // foreach and forindex use call-id ast to get mcall - { + if (node.size()==1) { // foreach and forindex use call-id ast to get mcall mcall_id(node[0]); return; } calc_gen(node[0]); - for(usize i=1;i=0) - { + if ((index=local_find(str))>=0) { gen(op_mcalll,index,node.line()); return; } - if((index=upvalue_find(str))>=0) - { + if ((index=upvalue_find(str))>=0) { gen(op_mupval,index,node.line()); return; } - if((index=global_find(str))>=0) - { + if ((index=global_find(str))>=0) { gen(op_mcallg,index,node.line()); return; } die("undefined symbol \""+str+"\"",node.line(),node.col(),node.str().length()); } -void codegen::mcall_vec(const ast& node) -{ +void codegen::mcall_vec(const ast& node) { calc_gen(node[0]); gen(op_mcallv,0,node.line()); } -void codegen::mcall_hash(const ast& node) -{ +void codegen::mcall_hash(const ast& node) { regist_str(node.str()); gen(op_mcallh,str_table[node.str()],node.line()); } -void codegen::single_def(const ast& node) -{ +void codegen::single_def(const ast& node) { const string& str=node[0].str(); calc_gen(node[1]); local.empty()? gen(op_loadg,global_find(str),node.line()): gen(op_loadl,local_find(str),node.line()); } -void codegen::multi_def(const ast& node) -{ +void codegen::multi_def(const ast& node) { auto& ids=node[0].child(); usize size=ids.size(); - if(node[1].type()==ast_tuple) // (var a,b,c)=(c,b,a); - { + if (node[1].type()==ast_tuple) { // (var a,b,c)=(c,b,a); auto& vals=node[1].child(); - for(usize i=0;inode[1].size()){ + } else if (node[0].type()==ast_multi_id && node[1].type()==ast_tuple && node[0].size()>node[1].size()) { die("too many values in multi-definition",node[1].line(),node[1].col(),1); } node[0].type()==ast_id?single_def(node):multi_def(node); } -void codegen::multi_assign_gen(const ast& node) -{ - if(node[1].type()==ast_tuple && node[0].size()node[1].size()){ + } else if (node[1].type()==ast_tuple && node[0].size()>node[1].size()) { die("too many values in multi-assignment",node[1].line(),node[1].col(),1); } i32 size=node[0].size(); - if(node[1].type()==ast_tuple) - { - for(i32 i=size-1;i>=0;--i) + if (node[1].type()==ast_tuple) { + for(i32 i=size-1;i>=0;--i) { calc_gen(node[1][i]); - for(i32 i=0;i jmp_label; - for(auto& tmp:node.child()) - { - if(tmp.type()==ast_if || tmp.type()==ast_elsif) - { + for(auto& tmp:node.child()) { + if (tmp.type()==ast_if || tmp.type()==ast_elsif) { calc_gen(tmp[0]); usize ptr=code.size(); gen(op_jf,0,tmp.line()); block_gen(tmp[1]); // without 'else' the last condition doesn't need to jmp - if(&tmp!=&node.child().back()) - { + if (&tmp!=&node.child().back()) { jmp_label.push_back(code.size()); gen(op_jmp,0,tmp.line()); } code[ptr].num=code.size(); - } - else - { + } else { block_gen(tmp[0]); break; } } - for(auto i:jmp_label) + for(auto i:jmp_label) { code[i].num=code.size(); + } } -void codegen::loop_gen(const ast& node) -{ +void codegen::loop_gen(const ast& node) { continue_ptr.push_front(std::vector()); break_ptr.push_front(std::vector()); - switch(node.type()) - { + switch(node.type()) { case ast_while: while_gen(node); break; case ast_for: for_gen(node); break; case ast_forindex:forindex_gen(node);break; @@ -826,18 +763,18 @@ void codegen::loop_gen(const ast& node) } } -void codegen::load_continue_break(i32 continue_place,i32 break_place) -{ - for(auto i:continue_ptr.front()) +void codegen::load_continue_break(i32 continue_place,i32 break_place) { + for(auto i:continue_ptr.front()) { code[i].num=continue_place; - for(auto i:break_ptr.front()) + } + for(auto i:break_ptr.front()) { code[i].num=break_place; + } continue_ptr.pop_front(); break_ptr.pop_front(); } -void codegen::while_gen(const ast& node) -{ +void codegen::while_gen(const ast& node) { usize loop_ptr=code.size(); calc_gen(node[0]); usize condition_ptr=code.size(); @@ -849,22 +786,21 @@ void codegen::while_gen(const ast& node) load_continue_break(code.size()-1,code.size()); } -void codegen::for_gen(const ast& node) -{ - switch(node[0].type()) - { +void codegen::for_gen(const ast& node) { + switch(node[0].type()) { case ast_null:break; case ast_def:def_gen(node[0]);break; case ast_multi_assign:multi_assign_gen(node[0]);break; case ast_addeq:case ast_subeq: case ast_multeq:case ast_diveq:case ast_lnkeq: calc_gen(node[0]); - if(op_addeq<=code.back().op && code.back().op<=op_lnkeq) + if (op_addeq<=code.back().op && code.back().op<=op_lnkeq) { code.back().num=1; - else if(op_addeqc<=code.back().op && code.back().op<=op_lnkeqc) + } else if (op_addeqc<=code.back().op && code.back().op<=op_lnkeqc) { code.back().num|=0x80000000; - else + } else { gen(op_pop,0,node[0].line()); + } break; case ast_nil:case ast_num:case ast_str:break; case ast_vec:case ast_hash:case ast_func: @@ -878,58 +814,59 @@ void codegen::for_gen(const ast& node) case ast_geq:case ast_grt: case ast_trino: calc_gen(node[0]); - if(code.back().op==op_meq) + if (code.back().op==op_meq) { code.back().num=1; - else + } else { gen(op_pop,0,node[0].line()); + } break; case ast_equal: - if(node[0][0].type()==ast_id) - { + if (node[0][0].type()==ast_id) { calc_gen(node[0][1]); mcall_id(node[0][0]); // only the first mcall_id can use load - if(code.back().op==op_mcalll) + if (code.back().op==op_mcalll) { code.back().op=op_loadl; - else if(code.back().op==op_mupval) + } else if (code.back().op==op_mupval) { code.back().op=op_loadu; - else + } else { code.back().op=op_loadg; - } - else - { + } + } else { calc_gen(node[0]); - if(code.back().op==op_meq) + if (code.back().op==op_meq) { code.back().num=1; - else + } else { gen(op_pop,0,node[0].line()); + } } break; } usize jmp_place=code.size(); - if(node[1].type()==ast_null) + if (node[1].type()==ast_null) { gen(op_pnum,num_table[1],node[1].line()); - else + } else { calc_gen(node[1]); + } usize label_exit=code.size(); gen(op_jf,0,node[1].line()); block_gen(node[3]); usize continue_place=code.size(); - switch(node[2].type()) - { + switch(node[2].type()) { case ast_null:break; case ast_def:def_gen(node[2]);break; case ast_multi_assign:multi_assign_gen(node[2]);break; case ast_addeq:case ast_subeq: case ast_multeq:case ast_diveq:case ast_lnkeq: calc_gen(node[2]); - if(op_addeq<=code.back().op && code.back().op<=op_lnkeq) + if (op_addeq<=code.back().op && code.back().op<=op_lnkeq) { code.back().num=1; - else if(op_addeqc<=code.back().op && code.back().op<=op_lnkeqc) + } else if (op_addeqc<=code.back().op && code.back().op<=op_lnkeqc) { code.back().num|=0x80000000; - else + } else { gen(op_pop,0,node[2].line()); + } break; case ast_nil:case ast_num:case ast_str:break; case ast_vec:case ast_hash:case ast_func: @@ -941,31 +878,31 @@ void codegen::for_gen(const ast& node) case ast_less:case ast_geq:case ast_grt: case ast_trino: calc_gen(node[2]); - if(code.back().op==op_meq) + if (code.back().op==op_meq) { code.back().num=1; - else + } else { gen(op_pop,0,node[2].line()); + } break; case ast_equal: - if(node[2][0].type()==ast_id) - { + if (node[2][0].type()==ast_id) { calc_gen(node[2][1]); mcall_id(node[2][0]); // only the first mcall_id can use load - if(code.back().op==op_mcalll) + if (code.back().op==op_mcalll) { code.back().op=op_loadl; - else if(code.back().op==op_mupval) + } else if (code.back().op==op_mupval) { code.back().op=op_loadu; - else + } else { code.back().op=op_loadg; - } - else - { + } + } else { calc_gen(node[2]); - if(code.back().op==op_meq) + if (code.back().op==op_meq) { code.back().num=1; - else + } else { gen(op_pop,0,node[2].line()); + } } break; } @@ -974,64 +911,28 @@ void codegen::for_gen(const ast& node) load_continue_break(continue_place,code.size()); } -void codegen::forindex_gen(const ast& node) -{ + +void codegen::forindex_gen(const ast& node) { calc_gen(node[1]); gen(op_cnt,0,node[1].line()); usize ptr=code.size(); gen(op_findex,0,node.line()); - if(node[0].type()==ast_iter) // define a new iterator - { + if (node[0].type()==ast_iter) { // define a new iterator const string& str=node[0][0].str(); local.empty()? gen(op_loadg,global_find(str),node[0][0].line()): gen(op_loadl,local_find(str),node[0][0].line()); - } - else // use exist variable as the iterator - { + } else { // use exist variable as the iterator mcall(node[0]); - if(code.back().op==op_mcallg) + if (code.back().op==op_mcallg) { code.back().op=op_loadg; - else if(code.back().op==op_mcalll) + } else if (code.back().op==op_mcalll) { code.back().op=op_loadl; - else if(code.back().op==op_mupval) + } else if (code.back().op==op_mupval) { code.back().op=op_loadu; - else - gen(op_meq,1,node[0].line()); - } - ++in_iterloop.top(); - block_gen(node[2]); - --in_iterloop.top(); - gen(op_jmp,ptr,node.line()); - code[ptr].num=code.size(); - load_continue_break(code.size()-1,code.size()); - gen(op_pop,0,node[1].line());// pop vector - gen(op_pop,0,node.line());// pop iterator -} -void codegen::foreach_gen(const ast& node) -{ - calc_gen(node[1]); - gen(op_cnt,0,node.line()); - usize ptr=code.size(); - gen(op_feach,0,node.line()); - if(node[0].type()==ast_iter) // define a new iterator - { - const string& str=node[0][0].str(); - local.empty()? - gen(op_loadg,global_find(str),node[0][0].line()): - gen(op_loadl,local_find(str),node[0][0].line()); - } - else // use exist variable as the iterator - { - mcall(node[0]); - if(code.back().op==op_mcallg) - code.back().op=op_loadg; - else if(code.back().op==op_mcalll) - code.back().op=op_loadl; - else if(code.back().op==op_mupval) - code.back().op=op_loadu; - else + } else { gen(op_meq,1,node[0].line()); + } } ++in_iterloop.top(); block_gen(node[2]); @@ -1043,8 +944,39 @@ void codegen::foreach_gen(const ast& node) gen(op_pop,0,node.line());// pop iterator } -void codegen::or_gen(const ast& node) -{ +void codegen::foreach_gen(const ast& node) { + calc_gen(node[1]); + gen(op_cnt,0,node.line()); + usize ptr=code.size(); + gen(op_feach,0,node.line()); + if (node[0].type()==ast_iter) { // define a new iterator + const string& str=node[0][0].str(); + local.empty()? + gen(op_loadg,global_find(str),node[0][0].line()): + gen(op_loadl,local_find(str),node[0][0].line()); + } else { // use exist variable as the iterator + mcall(node[0]); + if (code.back().op==op_mcallg) { + code.back().op=op_loadg; + } else if (code.back().op==op_mcalll) { + code.back().op=op_loadl; + } else if (code.back().op==op_mupval) { + code.back().op=op_loadu; + } else { + gen(op_meq,1,node[0].line()); + } + } + ++in_iterloop.top(); + block_gen(node[2]); + --in_iterloop.top(); + gen(op_jmp,ptr,node.line()); + code[ptr].num=code.size(); + load_continue_break(code.size()-1,code.size()); + gen(op_pop,0,node[1].line());// pop vector + gen(op_pop,0,node.line());// pop iterator +} + +void codegen::or_gen(const ast& node) { calc_gen(node[0]); usize l1=code.size(); gen(op_jt,0,node[0].line()); @@ -1060,8 +992,7 @@ void codegen::or_gen(const ast& node) code[l1].num=code[l2].num=code.size(); } -void codegen::and_gen(const ast& node) -{ +void codegen::and_gen(const ast& node) { calc_gen(node[0]); gen(op_jt,code.size()+2,node[0].line()); @@ -1078,8 +1009,7 @@ void codegen::and_gen(const ast& node) //jt jumps here } -void codegen::trino_gen(const ast& node) -{ +void codegen::trino_gen(const ast& node) { calc_gen(node[0]); usize lfalse=code.size(); gen(op_jf,0,node[0].line()); @@ -1091,10 +1021,8 @@ void codegen::trino_gen(const ast& node) code[lexit].num=code.size(); } -void codegen::calc_gen(const ast& node) -{ - switch(node.type()) - { +void codegen::calc_gen(const ast& node) { + switch(node.type()) { case ast_nil: gen(op_pnil,0,node.line());break; case ast_num: num_gen(node); break; case ast_str: str_gen(node); break; @@ -1110,53 +1038,49 @@ void codegen::calc_gen(const ast& node) break; // ast_addeq(22)~ast_lnkeq(26) op_addeq(23)~op_lnkeq(27) case ast_addeq:case ast_subeq:case ast_multeq:case ast_diveq: - if(node[1].type()!=ast_num) + if (node[1].type()!=ast_num) { calc_gen(node[1]); + } mcall(node[0]); - if(node[1].type()!=ast_num) + if (node[1].type()!=ast_num) { gen(node.type()-ast_addeq+op_addeq,0,node.line()); - else - { + } else { regist_num(node[1].num()); gen(node.type()-ast_addeq+op_addeqc,num_table[node[1].num()],node.line()); } break; case ast_lnkeq: - if(node[1].type()!=ast_str) + if (node[1].type()!=ast_str) { calc_gen(node[1]); - else + } else { regist_str(node[1].str()); + } mcall(node[0]); - if(node[1].type()!=ast_str) + if (node[1].type()!=ast_str) { gen(op_lnkeq,0,node.line()); - else + } else { gen(op_lnkeqc,str_table[node[1].str()],node.line()); + } break; case ast_or:or_gen(node);break; case ast_and:and_gen(node);break; // ast_add(33)~ast_link(37) op_add(18)~op_lnk(22) case ast_add:case ast_sub:case ast_mult:case ast_div: calc_gen(node[0]); - if(node[1].type()!=ast_num) - { + if (node[1].type()!=ast_num) { calc_gen(node[1]); gen(node.type()-ast_add+op_add,0,node.line()); - } - else - { + } else { regist_num(node[1].num()); gen(node.type()-ast_add+op_addc,num_table[node[1].num()],node.line()); } break; case ast_link: calc_gen(node[0]); - if(node[1].type()!=ast_str) - { + if (node[1].type()!=ast_str) { calc_gen(node[1]); gen(op_lnk,0,node.line()); - } - else - { + } else { regist_str(node[1].str()); gen(op_lnkc,str_table[node[1].str()],node.line()); } @@ -1169,13 +1093,10 @@ void codegen::calc_gen(const ast& node) break; case ast_less:case ast_leq:case ast_grt:case ast_geq: calc_gen(node[0]); - if(node[1].type()!=ast_num) - { + if (node[1].type()!=ast_num) { calc_gen(node[1]); gen(node.type()-ast_less+op_less,0,node.line()); - } - else - { + } else { regist_num(node[1].num()); gen(node.type()-ast_less+op_lessc,num_table[node[1].num()],node.line()); } @@ -1196,11 +1117,9 @@ void codegen::calc_gen(const ast& node) } } -void codegen::block_gen(const ast& node) -{ - for(auto& tmp:node.child()) - switch(tmp.type()) - { +void codegen::block_gen(const ast& node) { + for(auto& tmp:node.child()) { + switch(tmp.type()) { case ast_null:case ast_nil:case ast_num:case ast_str:break; case ast_file:fileindex=tmp.num();break; // special node type in main block case ast_def:def_gen(tmp);break; @@ -1219,36 +1138,36 @@ void codegen::block_gen(const ast& node) case ast_forindex: case ast_foreach:loop_gen(tmp);break; case ast_equal: - if(tmp[0].type()==ast_id) - { + if (tmp[0].type()==ast_id) { calc_gen(tmp[1]); mcall_id(tmp[0]); // only the first mcall_id can use load - if(code.back().op==op_mcalll) + if (code.back().op==op_mcalll) { code.back().op=op_loadl; - else if(code.back().op==op_mupval) + } else if (code.back().op==op_mupval) { code.back().op=op_loadu; - else + } else { code.back().op=op_loadg; - } - else - { + } + } else { calc_gen(tmp); - if(code.back().op==op_meq) + if (code.back().op==op_meq) { code.back().num=1; - else + } else { gen(op_pop,0,tmp.line()); + } } break; case ast_addeq:case ast_subeq: case ast_multeq:case ast_diveq:case ast_lnkeq: calc_gen(tmp); - if(op_addeq<=code.back().op && code.back().op<=op_lnkeq) + if (op_addeq<=code.back().op && code.back().op<=op_lnkeq) { code.back().num=1; - else if(op_addeqc<=code.back().op && code.back().op<=op_lnkeqc) + } else if (op_addeqc<=code.back().op && code.back().op<=op_lnkeqc) { code.back().num|=0x80000000; - else + } else { gen(op_pop,0,tmp.line()); + } break; case ast_id: case ast_vec: @@ -1272,31 +1191,31 @@ void codegen::block_gen(const ast& node) case ast_and: case ast_trino: calc_gen(tmp); - if(code.back().op==op_meq) + if (code.back().op==op_meq) { code.back().num=1; - else + } else { gen(op_pop,0,tmp.line()); + } break; case ast_ret:ret_gen(tmp);break; } + } } -void codegen::ret_gen(const ast& node) -{ - for(u32 i=0;i=STACK_DEPTH){ + if (global.size()>=STACK_DEPTH) { err.load(file[fileindex]); err.err("code","too many global variants: "+std::to_string(global.size())); } - if(code.size()>0xffffffff){ + if (code.size()>0xffffffff) { err.load(file[fileindex]); err.err("code","too large generated bytecode file: "+std::to_string(code.size())); } return err; } -void codegen::singleop(const u32 index) -{ +void codegen::singleop(const u32 index) { // print opcode index,opcode name,opcode immediate number const opcode& c=code[index]; - if(!festk.empty() && index==festk.top()) - { + if (!festk.empty() && index==festk.top()) { std::cout<;\n"; - if(code[index].op!=op_newf) // avoid two empty lines + if (code[index].op!=op_newf) { // avoid two empty lines std::cout<<"\n"; + } fbstk.pop(); festk.pop(); } - if(c.op==op_newf) - { + if (c.op==op_newf) { std::cout<:\n"; - for(u32 i=index;i -class debugger:public vm -{ +class debugger:public vm { private: bool next; usize fsize; @@ -24,7 +23,7 @@ public: debugger(error& err): next(false),fsize(0), bk_fidx(0),bk_line(0), - src(err){} + src(err) {} void run( const codegen&, const linker&, @@ -32,39 +31,38 @@ public: ); }; -std::vector debugger::parse(const string& cmd) -{ +std::vector debugger::parse(const string& cmd) { std::vector res; usize last=0,pos=cmd.find(" ",0); - while(pos!=string::npos) - { - if(pos>last) + while(pos!=string::npos) { + if (pos>last) { res.push_back(cmd.substr(last,pos-last)); + } last=pos+1; pos=cmd.find(" ",last); } - if(last\n" <<"\th, help | get help\n" @@ -82,123 +80,118 @@ void debugger::help() <<"\tbk, break | set break point\n"; } -void debugger::callsort(const u64* arr) -{ +void debugger::callsort(const u64* arr) { typedef std::pair op; std::vector opcall; u64 total=0; - for(u32 i=0;ib.second;} + [](const op& a,const op& b) {return a.second>b.second;} ); std::clog<<"\noperands call info (<1% ignored)\n"; - for(auto& i:opcall) - { + for(auto& i:opcall) { u64 rate=i.second*100/total; - if(!rate) + if (!rate) { break; + } std::clog<<" "<>3)==0?0:((line>>3)<<3); u32 end=(1+(line>>3))<<3; src.load(files[bytecode[pc].fidx]); std::cout<<"\nsource code:\n"; - for(u32 i=begin;i ":" ")<>3)==0?0:((pc>>3)<<3); end=(1+(pc>>3))<<3; - for(u32 i=begin;i ":" ") <> "; std::getline(std::cin,cmd); auto res=parse(cmd); - if(res.size()==1) - { - if(res[0]=="h" || res[0]=="help") + if (res.size()==1) { + if (res[0]=="h" || res[0]=="help") { help(); - else if(res[0]=="bt" || res[0]=="backtrace") + } else if (res[0]=="bt" || res[0]=="backtrace") { traceback(); - else if(res[0]=="c" || res[0]=="continue") + } else if (res[0]=="c" || res[0]=="continue") { return; - else if(res[0]=="f" || res[0]=="file") - for(usize i=0;i code; - for(auto& i:gen.codes()) - { + for(auto& i:gen.codes()) { code.push_back(oprs[i.op]); imm.push_back(i.num); } @@ -244,8 +235,7 @@ void debugger::run( goto *code[pc]; #else typedef void (debugger::*nafunc)(); - const nafunc oprs[]= - { + const nafunc oprs[]={ nullptr, &debugger::o_intg, &debugger::o_intl, &debugger::o_loadg, &debugger::o_loadl, &debugger::o_loadu, @@ -286,17 +276,17 @@ void debugger::run( &debugger::o_ret }; std::vector code; - for(auto& i:gen.codes()) - { + for(auto& i:gen.codes()) { code.push_back(i.op); imm.push_back(i.num); } - while(oprs[code[pc]]){ + while(oprs[code[pc]]) { interact(); ++count[code[pc]]; (this->*oprs[code[pc]])(); - if(top>=canary) + if (top>=canary) { die("stack overflow"); + } ++pc; } #endif @@ -312,8 +302,9 @@ vmexit: interact();\ op();\ ++count[num];\ - if(top // use SetConsoleTextAttribute -struct for_reset -{ +struct for_reset { CONSOLE_SCREEN_BUFFER_INFO scr; - for_reset(){ + for_reset() { GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE),&scr); } -}reset_ter_color; +} reset_ter_color; #endif -std::ostream& back_white(std::ostream& s) -{ +std::ostream& back_white(std::ostream& s) { #ifdef _WIN32 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0xf0); #else @@ -25,8 +23,8 @@ std::ostream& back_white(std::ostream& s) #endif return s; } -std::ostream& red(std::ostream& s) -{ + +std::ostream& red(std::ostream& s) { #ifdef _WIN32 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0x0c); #else @@ -34,8 +32,8 @@ std::ostream& red(std::ostream& s) #endif return s; } -std::ostream& cyan(std::ostream& s) -{ + +std::ostream& cyan(std::ostream& s) { #ifdef _WIN32 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0x03); #else @@ -43,8 +41,8 @@ std::ostream& cyan(std::ostream& s) #endif return s; } -std::ostream& orange(std::ostream& s) -{ + +std::ostream& orange(std::ostream& s) { #ifdef _WIN32 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0x0e); #else @@ -52,8 +50,8 @@ std::ostream& orange(std::ostream& s) #endif return s; } -std::ostream& white(std::ostream& s) -{ + +std::ostream& white(std::ostream& s) { #ifdef _WIN32 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0x0f); #else @@ -61,8 +59,8 @@ std::ostream& white(std::ostream& s) #endif return s; } -std::ostream& reset(std::ostream& s) -{ + +std::ostream& reset(std::ostream& s) { #ifdef _WIN32 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),reset_ter_color.scr.wAttributes); #else @@ -71,29 +69,27 @@ std::ostream& reset(std::ostream& s) return s; } -class flstream -{ +class flstream { protected: string file; std::vector res; public: - flstream():file(""){} - void load(const string& f) - { - if(file==f){ // don't need to load a loaded file + flstream():file("") {} + void load(const string& f) { + if (file==f) { // don't need to load a loaded file return; - }else{ + } else { file=f; } res.clear(); std::ifstream in(f,std::ios::binary); - if(in.fail()){ + if (in.fail()) { std::cerr<\n"; std::exit(1); } - while(!in.eof()){ + while(!in.eof()) { string line; std::getline(in,line); res.push_back(line); @@ -104,34 +100,35 @@ public: usize size() const {return res.size();} }; -class error:public flstream -{ +class error:public flstream { private: u32 cnt; - string identation(usize len) - { + string identation(usize len) { string tmp=""; tmp.resize(len,' '); return tmp; } public: - error():cnt(0){} - void fatal(const string& stage,const string& info) - { - std::cerr - < "< "< "< "< elems; - nas_vec():printed(false){} + nas_vec():printed(false) {} friend std::ostream& operator<<(std::ostream&,nas_vec&); - usize size(){return elems.size();} + usize size() {return elems.size();} var get_val(const i32); var* get_mem(const i32); }; -struct nas_hash -{ +struct nas_hash { bool printed; std::unordered_map elems; - nas_hash():printed(false){} + nas_hash():printed(false) {} friend std::ostream& operator<<(std::ostream&,nas_hash&); - usize size(){return elems.size();} + usize size() {return elems.size();} var get_val(const string&); var* get_mem(const string&); }; -struct nas_func -{ +struct nas_func { i32 dpara; // dynamic parameter name index in hash. u32 entry; // pc will set to entry-1 to call this function u32 psize; // used to load default parameters to a new function @@ -151,50 +144,45 @@ struct nas_func std::vector upval; // closure std::unordered_map keys; // parameter table, u32 begins from 1 - nas_func():dpara(-1),entry(0),psize(0),lsize(0){} + nas_func():dpara(-1),entry(0),psize(0),lsize(0) {} void clear(); }; -struct nas_upval -{ +struct nas_upval { bool onstk; u32 size; var* stk; std::vector elems; - nas_upval(){onstk=true;stk=nullptr;size=0;} - var& operator[](usize n){return onstk?stk[n]:elems[n];} - void clear(){onstk=true;elems.clear();size=0;} + nas_upval() {onstk=true;stk=nullptr;size=0;} + var& operator[](usize n) {return onstk?stk[n]:elems[n];} + void clear() {onstk=true;elems.clear();size=0;} }; -struct nas_obj -{ - enum obj_t:u32 - { +struct nas_obj { + enum obj:u32 { file=1, dir, dylib, - faddr + faddr, + unsafe }; /* RAII constructor */ /* new object is initialized when creating */ u32 type; void* ptr; private: - void obj_file_dtor() - { + void file_dtor() { fclose((FILE*)ptr); } - void obj_dir_dtor() - { + void dir_dtor() { #ifndef _MSC_VER closedir((DIR*)ptr); #else FindClose(ptr); #endif } - void dylib_dtor() - { + void dylib_dtor() { #ifdef _WIN32 FreeLibrary((HMODULE)ptr); #else @@ -202,32 +190,28 @@ private: #endif } public: - nas_obj():type(0),ptr(nullptr){} - ~nas_obj(){clear();} - void set(u32 t=0,void* p=nullptr) - { + nas_obj():type(0),ptr(nullptr) {} + ~nas_obj() {clear();} + void set(u32 t=0,void* p=nullptr) { type=t; ptr=p; } - void clear() - { - if(!ptr) + void clear() { + if (!ptr) { return; - switch(type) - { - case obj_t::file: obj_file_dtor();break; - case obj_t::dir: obj_dir_dtor(); break; - case obj_t::dylib: dylib_dtor(); break; + } + switch(type) { + case obj::file: file_dtor(); break; + case obj::dir: dir_dtor(); break; + case obj::dylib: dylib_dtor();break; default: break; } ptr=nullptr; } }; -struct nas_co -{ - enum costat:u32 - { +struct nas_co { + enum costat:u32{ suspended, running, dead @@ -250,13 +234,11 @@ struct nas_co memr(nullptr), funcr({vm_nil,(f64)0}), upvalr({vm_nil,(f64)0}), - status(nas_co::suspended) - { + status(nas_co::suspended) { for(u32 i=0;i=size) + if (n<-size || n>=size) { return {vm_none}; + } return elems[n>=0?n:n+size]; } -var* nas_vec::get_mem(const i32 n) -{ + +var* nas_vec::get_mem(const i32 n) { i32 size=elems.size(); - if(n<-size || n>=size) + if (n<-size || n>=size) { return nullptr; + } return &elems[n>=0?n:n+size]; } -std::ostream& operator<<(std::ostream& out,nas_vec& vec) -{ - if(!vec.elems.size() || vec.printed) - { + +std::ostream& operator<<(std::ostream& out,nas_vec& vec) { + if (!vec.elems.size() || vec.printed) { out<<(vec.elems.size()?"[..]":"[]"); return out; } vec.printed=true; usize iter=0,size=vec.elems.size(); out<<'['; - for(auto& i:vec.elems) + for(auto& i:vec.elems) { out<clear(); break; case vm_vec: ptr.vec->elems.clear(); break; case vm_hash: ptr.hash->elems.clear();break; @@ -427,16 +404,15 @@ void nas_val::clear() case vm_co: ptr.co->clear(); break; } } -f64 var::tonum() -{ + +f64 var::tonum() { return type!=vm_str?val.num:str2num(str().c_str()); } -string var::tostr() -{ - if(type==vm_str) + +string var::tostr() { + if (type==vm_str) { return str(); - else if(type==vm_num) - { + } else if (type==vm_num) { string tmp=std::to_string(num()); tmp.erase(tmp.find_last_not_of('0')+1,string::npos); tmp.erase(tmp.find_last_not_of('.')+1,string::npos); @@ -444,47 +420,45 @@ string var::tostr() } return ""; } -std::ostream& operator<<(std::ostream& out,var& ref) -{ - switch(ref.type) - { + +std::ostream& operator<<(std::ostream& out,var& ref) { + switch(ref.type) { case vm_none: out<<"undefined"; break; case vm_nil: out<<"nil"; break; case vm_num: out<"; break; case vm_co: out<<""; break; } return out; } -bool var::objchk(u32 objtype) -{ + +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; } + +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; } const var zero={vm_num,(f64)0}; const var one ={vm_num,(f64)1}; const var nil ={vm_nil,(f64)0}; -struct gc -{ +struct gc { /* main context */ - struct - { + struct { u32 pc; var* top; var* localr; @@ -525,7 +499,7 @@ struct gc var& _upvalr, var*& _canary, var*& _top, var* _stk): pc(_pc),localr(_localr),memr(_memr),funcr(_funcr),upvalr(_upvalr), canary(_canary),top(_top),stack(_stk),cort(nullptr),temp(nil), - worktime(0){} + worktime(0) {} void mark(); void sweep(); void init(const std::vector&,const std::vector&); @@ -540,128 +514,135 @@ struct gc }; /* gc functions */ -void gc::mark() -{ +void gc::mark() { std::queue bfs; // scan coroutine process stack when coroutine ptr is not null // scan main process stack when coroutine ptr is null // this scan process must execute because when running coroutine, // the nas_co related to it will not update it's context(like `top`) until the coroutine suspends or exits. - for(var* i=stack;i<=top;++i) + for(var* i=stack;i<=top;++i) { bfs.push(*i); + } bfs.push(funcr); bfs.push(upvalr); bfs.push(temp); - if(cort) // scan main process stack - { - for(var* i=mctx.stack;i<=mctx.top;++i) + if (cort) { // scan main process stack + for(var* i=mctx.stack;i<=mctx.top;++i) { bfs.push(*i); + } bfs.push(mctx.funcr); bfs.push(mctx.upvalr); } - while(!bfs.empty()) - { + while(!bfs.empty()) { var tmp=bfs.front(); bfs.pop(); - if(tmp.type<=vm_num || tmp.val.gcobj->mark) continue; + if (tmp.type<=vm_num || tmp.val.gcobj->mark) { + continue; + } tmp.val.gcobj->mark=GC_FOUND; - switch(tmp.type) - { + switch(tmp.type) { case vm_vec: - for(auto& i:tmp.vec().elems) + for(auto& i:tmp.vec().elems) { bfs.push(i); + } break; case vm_hash: - for(auto& i:tmp.hash().elems) + for(auto& i:tmp.hash().elems) { bfs.push(i.second); + } break; case vm_func: - for(auto& i:tmp.func().local) + for(auto& i:tmp.func().local) { bfs.push(i); - for(auto& i:tmp.func().upval) + } + for(auto& i:tmp.func().upval) { bfs.push(i); + } break; case vm_upval: - for(auto& i:tmp.upval().elems) + for(auto& i:tmp.upval().elems) { bfs.push(i); + } break; case vm_co: bfs.push(tmp.co().funcr); bfs.push(tmp.co().upvalr); - for(var* i=tmp.co().stack;i<=tmp.co().top;++i) + for(var* i=tmp.co().stack;i<=tmp.co().top;++i) { bfs.push(*i); + } break; } } } + void gc::sweep() { - for(auto i:memory) - { - if(i->mark==GC_UNCOLLECTED) - { + for(auto i:memory) { + if (i->mark==GC_UNCOLLECTED) { i->clear(); unused[i->type-vm_str].push(i); i->mark=GC_COLLECTED; - } - else if(i->mark==GC_FOUND) + } else if (i->mark==GC_FOUND) { i->mark=GC_UNCOLLECTED; + } } } -void gc::init(const std::vector& s,const std::vector& argv) -{ + +void gc::init(const std::vector& s,const std::vector& argv) { // initiaize function register funcr=nil; worktime=0; - for(u8 i=0;iunmut=1; strs[i].str()=s[i]; } // record arguments env_argv.resize(argv.size()); - for(usize i=0;iunmut=1; env_argv[i].str()=argv[i]; } } -void gc::clear() -{ - for(auto i:memory) + +void gc::clear() { + for(auto i:memory) { delete i; + } memory.clear(); - for(u8 i=0;istatus=nas_co::running; } -void gc::ctxreserve() -{ + +void gc::ctxreserve() { // pc=0 means this coroutine is finished cort->status=pc?nas_co::suspended:nas_co::dead; cort->pc=pc; @@ -775,8 +754,7 @@ void gc::ctxreserve() } // use to print error log and return error value -var nas_err(const string& err_f,const string& info) -{ +var nas_err(const string& err_f,const string& info) { std::cerr<<"[vm] "< files; std::vector envpath; + bool imptchk(const ast&); bool exist(const string&); void link(ast&,ast&&); @@ -34,7 +34,7 @@ public: const std::vector& filelist() const {return files;} }; -linker::linker(error& e):show_path(false),lib_loaded(false),err(e){ +linker::linker(error& e):show_path(false),lib_loaded(false),err(e) { #ifdef _WIN32 char sep=';'; #else @@ -42,66 +42,68 @@ linker::linker(error& e):show_path(false),lib_loaded(false),err(e){ #endif string PATH=getenv("PATH"); usize last=0,pos=PATH.find(sep,0); - while(pos!=string::npos) - { + while(pos!=string::npos) { string dirpath=PATH.substr(last,pos-last); - if(dirpath.length()) + if (dirpath.length()) { envpath.push_back(dirpath); + } last=pos+1; pos=PATH.find(sep,last); } - if(last!=PATH.length()) + if (last!=PATH.length()) { envpath.push_back(PATH.substr(last)); + } } -string linker::path(const ast& node) -{ - if(node[1].type()==ast_callf) +string linker::path(const ast& node) { + if (node[1].type()==ast_callf) { return node[1][0].str(); + } string fpath="."; - for(usize i=1;i fpath={fname}; - for(auto&p:envpath) - { + for(auto&p:envpath) { #ifdef _WIN32 fpath.push_back(p+"\\"+fname); #else fpath.push_back(p+"/"+fname); #endif } - for(auto& i:fpath) - if(access(i.c_str(),F_OK)!=-1) + for(auto& i:fpath) { + if (access(i.c_str(),F_OK)!=-1) { return i; - if(fname=="lib.nas") + } + } + if (fname=="lib.nas") { #ifdef _WIN32 return findf("stl\\lib.nas"); #else return findf("stl/lib.nas"); #endif - if(!show_path) - { + } + if (!show_path) { err.err("link","cannot find file <"+fname+">"); return ""; } string paths=""; - for(auto& i:fpath) + for(auto& i:fpath) { paths+=" "+i+"\n"; + } err.err("link","cannot find file <"+fname+"> in these paths:\n"+paths); return ""; } -bool linker::imptchk(const ast& node) -{ +bool linker::imptchk(const ast& node) { // only these two kinds of node can be recognized as 'import': /* call @@ -109,11 +111,12 @@ bool linker::imptchk(const ast& node) |_callh:stl |_callh:file */ - if(node.type()==ast_call && node[0].str()=="import" && node.size()>=2 && node[1].type()==ast_callh) - { - for(usize i=1;i=2 && node[1].type()==ast_callh) { + for(usize i=1;i end of token list }; -struct token -{ +struct token { u32 line; u32 col; u32 type; string str; token(u32 l=0,u32 c=0,u32 t=tok_null,const string& s="") - :line(l),col(c),type(t),str(s){} + : line(l),col(c),type(t),str(s) {} }; -class lexer -{ +class lexer { private: u32 line; u32 column; @@ -143,43 +141,36 @@ private: string num_gen(); string str_gen(); public: - lexer(error& e):line(1),column(0),ptr(0),res(""),err(e){} + lexer(error& e): line(1),column(0),ptr(0),res(""),err(e) {} const error& scan(const string&); const std::vector& result() const {return toks;} }; -bool lexer::skip(char c) -{ +bool lexer::skip(char c) { return c==' '||c=='\n'||c=='\t'||c=='\r'||c==0; } -bool lexer::is_id(char c) -{ +bool lexer::is_id(char c) { return (c=='_')||('a'<=c && c<='z')||('A'<=c&&c<='Z')||(c<0); } -bool lexer::is_hex(char c) -{ +bool lexer::is_hex(char c) { return ('0'<=c&&c<='9')||('a'<=c&&c<='f')||('A'<=c && c<='F'); } -bool lexer::is_oct(char c) -{ +bool lexer::is_oct(char c) { return '0'<=c&&c<='7'; } -bool lexer::is_dec(char c) -{ +bool lexer::is_dec(char c) { return '0'<=c&&c<='9'; } -bool lexer::is_str(char c) -{ +bool lexer::is_str(char c) { return c=='\''||c=='\"'||c=='`'; } -bool lexer::is_single_opr(char c) -{ +bool lexer::is_single_opr(char c) { return ( c=='('||c==')'||c=='['||c==']'|| c=='{'||c=='}'||c==','||c==';'|| @@ -189,8 +180,7 @@ bool lexer::is_single_opr(char c) ); } -bool lexer::is_calc_opr(char c) -{ +bool lexer::is_calc_opr(char c) { return ( c=='='||c=='+'||c=='-'||c=='*'|| c=='!'||c=='/'||c=='<'||c=='>'|| @@ -198,61 +188,51 @@ bool lexer::is_calc_opr(char c) ); } -// void lexer::die(const string& info) -// { -// err.err("lexer",line,column,1,info); -// } - -void lexer::open(const string& file) -{ +void lexer::open(const string& file) { struct stat buffer; - if(stat(file.c_str(),&buffer)==0 && !S_ISREG(buffer.st_mode)) - { + if (stat(file.c_str(),&buffer)==0 && !S_ISREG(buffer.st_mode)) { err.err("lexer","<"+file+"> is not a regular file"); err.chkerr(); } std::ifstream in(file,std::ios::binary); - if(in.fail()) + if (in.fail()) { err.err("lexer","failed to open <"+file+">"); - else + } else { err.load(file); + } std::stringstream ss; ss<"); err.fatal("lexer","fatal error occurred, stop"); } str+=tmp; column+=2; // may have some problems because not all the unicode takes 2 space - } - else - { + } else { ++ptr; ++column; } @@ -260,15 +240,12 @@ string lexer::utf8_gen() return str; } -string lexer::id_gen() -{ +string lexer::id_gen() { string str=""; - while(ptr [0~9][0~9]*(.[0~9]*)(e|E(+|-)0|[1~9][0~9]*) string str=""; - while(ptr=res.size()) - { + if (ptr++>=res.size()) { err.err("lexer",line,column,1,"get EOF when generating string"); return str; } ++column; - if(begin=='`' && str.length()!=1) + if (begin=='`' && str.length()!=1) { err.err("lexer",line,column,1,"\'`\' is used for string that includes one character"); + } return str; } -const error& lexer::scan(const string& file) -{ +const error& lexer::scan(const string& file) { line=1; column=0; ptr=0; open(file); string str; - while(ptr=res.size()) break; - if(is_id(res[ptr])) - { + if (ptr>=res.size()) { + break; + } + if (is_id(res[ptr])) { str=id_gen(); u32 type=get_type(str); toks.push_back({line,column,type?type:tok_id,str}); - } - else if(is_dec(res[ptr])) - { + } else if (is_dec(res[ptr])) { str=num_gen(); // make sure column is correct toks.push_back({line,column,tok_num,str}); - } - else if(is_str(res[ptr])) - { + } else if (is_str(res[ptr])) { str=str_gen(); // make sure column is correct toks.push_back({line,column,tok_str,str}); - } - else if(is_single_opr(res[ptr])) - { + } else if (is_single_opr(res[ptr])) { str=res[ptr]; ++column; u32 type=get_type(str); - if(!type) + if (!type) { err.err("lexer",line,column,str.length(),"invalid operator `"+str+"`"); + } toks.push_back({line,column,type,str}); ++ptr; - } - else if(res[ptr]=='.') - { + } else if (res[ptr]=='.') { str="."; - if(ptr+2 -void const_str(ast& root) -{ +void const_str(ast& root) { auto& vec=root.child(); root.set_str(vec[0].str()+vec[1].str()); root.child().clear(); root.set_type(ast_str); } -void const_num(ast& root) -{ +void const_num(ast& root) { auto& vec=root.child(); f64 res=0; - switch(root.type()) - { + switch(root.type()) { case ast_add: res=vec[0].num()+vec[1].num(); break; case ast_sub: res=vec[0].num()-vec[1].num(); break; case ast_mult:res=vec[0].num()*vec[1].num(); break; @@ -26,43 +23,46 @@ void const_num(ast& root) case ast_geq: res=vec[0].num()>=vec[1].num();break; } // inf and nan will cause number hashmap error in codegen - if(std::isinf(res) || std::isnan(res)) + if (std::isinf(res) || std::isnan(res)) { return; + } root.set_num(res); root.child().clear(); root.set_type(ast_num); } -void calc_const(ast& root) -{ +void calc_const(ast& root) { auto& vec=root.child(); - for(auto& i:vec) + for(auto& i:vec) { calc_const(i); - if(vec.size()==1 && root.type()==ast_neg && vec[0].type()==ast_num) - { + } + if (vec.size()==1 && root.type()==ast_neg && vec[0].type()==ast_num) { f64 res=-vec[0].num(); root.set_num(res); root.child().clear(); root.set_type(ast_num); return; } - if(vec.size()!=2) + if (vec.size()!=2) { return; - if(root.type()!=ast_add && root.type()!=ast_sub && + } + if (root.type()!=ast_add && root.type()!=ast_sub && root.type()!=ast_mult && root.type()!=ast_div && root.type()!=ast_link && root.type()!=ast_less && root.type()!=ast_leq && root.type()!=ast_grt && - root.type()!=ast_geq) + root.type()!=ast_geq) { return; - if(root.type()==ast_link && - vec[0].type()==ast_str && vec[1].type()==ast_str) + } + if (root.type()==ast_link && + vec[0].type()==ast_str && vec[1].type()==ast_str) { const_str(root); - else if(root.type()!=ast_link && - vec[0].type()==ast_num && vec[1].type()==ast_num) + } else if (root.type()!=ast_link && + vec[0].type()==ast_num && vec[1].type()==ast_num) { const_num(root); + } } -void optimize(ast& root) -{ - for(auto& i:root.child()) +void optimize(ast& root) { + for(auto& i:root.child()) { calc_const(i); + } } diff --git a/nasal_parse.h b/nasal_parse.h index 400ba51..0a135a3 100644 --- a/nasal_parse.h +++ b/nasal_parse.h @@ -37,8 +37,7 @@ `"` `"` */ -class parse -{ +class parse { #define thisline (toks[ptr].line) #define thiscol (toks[ptr].col) #define thislen (toks[ptr].str.length()) @@ -98,7 +97,7 @@ private: }; void die(u32,u32,u32,string,bool); - void next(){++ptr;}; + void next() {++ptr;}; void match(u32 type,const char* info=nullptr); bool lookahead(u32); bool is_call(u32); @@ -152,37 +151,37 @@ public: parse(error& e): ptr(0),in_func(0),in_loop(0), toks(nullptr),root(0,0,ast_root), - err(e){} + err(e) {} const error& compile(const lexer&); - ast& tree(){return root;} + ast& tree() {return root;} const ast& tree() const {return root;} }; -const error& parse::compile(const lexer& lexer) -{ + +const error& parse::compile(const lexer& lexer) { toks=lexer.result().data(); ptr=in_func=in_loop=0; root={0,0,ast_root}; - while(!lookahead(tok_eof)){ + while(!lookahead(tok_eof)) { root.add(expr()); - if(lookahead(tok_semi)){ + if (lookahead(tok_semi)) { match(tok_semi); - }else if(need_semi_check(root.child().back()) && !lookahead(tok_eof)){ + } else if (need_semi_check(root.child().back()) && !lookahead(tok_eof)) { // the last expression can be recognized without semi die(thisline,thiscol,thislen,"expected \";\"",true); } } return err; } -void parse::die(u32 line,u32 col,u32 len,string info,bool prev=false) -{ + +void parse::die(u32 line,u32 col,u32 len,string info,bool prev=false) { // tok_str's str has no \" - if(lookahead(tok_str)){ + if (lookahead(tok_str)) { col-=2; len+=2; } // used to report lack of ',' ';' - if(prev && ptr){ + if (prev && ptr) { line=toks[ptr-1].line; col=toks[ptr-1].col; len=toks[ptr-1].str.length(); @@ -190,14 +189,14 @@ void parse::die(u32 line,u32 col,u32 len,string info,bool prev=false) } err.err("parse",line,col,lookahead(tok_eof)?1:len,info); } -void parse::match(u32 type,const char* info) -{ - if(!lookahead(type)){ - if(info){ + +void parse::match(u32 type,const char* info) { + if (!lookahead(type)) { + if (info) { die(thisline,thiscol,thislen,info); return; } - switch(type){ + switch(type) { case tok_num:die(thisline,thiscol,thislen,"expected number"); break; case tok_str:die(thisline,thiscol,thislen,"expected string"); break; case tok_id: die(thisline,thiscol,thislen,"expected identifier");break; @@ -205,34 +204,34 @@ void parse::match(u32 type,const char* info) } return; } - if(lookahead(tok_eof)){ + if (lookahead(tok_eof)) { return; } next(); } -bool parse::lookahead(u32 type) -{ + +bool parse::lookahead(u32 type) { return toks[ptr].type==type; } -bool parse::is_call(u32 type) -{ + +bool parse::is_call(u32 type) { return type==tok_lcurve || type==tok_lbracket || type==tok_dot; } -bool parse::check_comma(const u32* panic_set) -{ - for(u32 i=0;panic_set[i];++i){ - if(lookahead(panic_set[i])){ + +bool parse::check_comma(const u32* panic_set) { + for(u32 i=0;panic_set[i];++i) { + if (lookahead(panic_set[i])) { die(thisline,thiscol,thislen,"expected ',' between scalars",true); return true; } } return false; } -bool parse::check_tuple() -{ + +bool parse::check_tuple() { u32 check_ptr=ptr,curve=1,bracket=0,brace=0; - while(toks[++check_ptr].type!=tok_eof && curve){ - switch(toks[check_ptr].type){ + while(toks[++check_ptr].type!=tok_eof && curve) { + switch(toks[check_ptr].type) { case tok_lcurve: ++curve; break; case tok_lbracket: ++bracket; break; case tok_lbrace: ++brace; break; @@ -240,21 +239,21 @@ bool parse::check_tuple() case tok_rbracket: --bracket; break; case tok_rbrace: --brace; break; } - if(curve==1 && !bracket && !brace && toks[check_ptr].type==tok_comma){ + if (curve==1 && !bracket && !brace && toks[check_ptr].type==tok_comma) { return true; } } return false; } -bool parse::check_func_end(const ast& node) -{ + +bool parse::check_func_end(const ast& node) { u32 type=node.type(); - if(type==ast_func){ + if (type==ast_func) { return true; - }else if(type==ast_num || type==ast_id || type==ast_str || type==ast_nil || type==ast_vec || type==ast_hash){ + } else if (type==ast_num || type==ast_id || type==ast_str || type==ast_nil || type==ast_vec || type==ast_hash) { return false; } - if(node.child().empty() || ( + if (node.child().empty() || ( type!=ast_def && type!=ast_equal && type!=ast_addeq && @@ -263,19 +262,19 @@ bool parse::check_func_end(const ast& node) type!=ast_diveq && type!=ast_lnkeq ) - ){ + ) { return false; - }else{ + } else { return check_func_end(node.child().back()); } return false; } -bool parse::check_special_call() -{ + +bool parse::check_special_call() { // special call means like this: function_name(a:1,b:2,c:3); u32 check_ptr=ptr,curve=1,bracket=0,brace=0; - while(toks[++check_ptr].type!=tok_eof && curve){ - switch(toks[check_ptr].type){ + while(toks[++check_ptr].type!=tok_eof && curve) { + switch(toks[check_ptr].type) { case tok_lcurve: ++curve; break; case tok_lbracket: ++bracket;break; case tok_lbrace: ++brace; break; @@ -284,54 +283,54 @@ bool parse::check_special_call() case tok_rbrace: --brace; break; } // m?1:0 will be recognized as normal parameter - if(curve==1 && !bracket && !brace && toks[check_ptr].type==tok_quesmark){ + if (curve==1 && !bracket && !brace && toks[check_ptr].type==tok_quesmark) { return false; } - if(curve==1 && !bracket && !brace && toks[check_ptr].type==tok_colon){ + if (curve==1 && !bracket && !brace && toks[check_ptr].type==tok_colon) { return true; } } return false; } -bool parse::need_semi_check(const ast& node) -{ + +bool parse::need_semi_check(const ast& node) { u32 type=node.type(); - if(type==ast_for || type==ast_foreach || type==ast_forindex || type==ast_while || type==ast_cond){ + if (type==ast_for || type==ast_foreach || type==ast_forindex || type==ast_while || type==ast_cond) { return false; } return !check_func_end(node); } -ast parse::null() -{ + +ast parse::null() { return {toks[ptr].line,toks[ptr].col,ast_null}; } -ast parse::nil() -{ + +ast parse::nil() { return {toks[ptr].line,toks[ptr].col,ast_nil}; } -ast parse::num() -{ + +ast parse::num() { ast node(toks[ptr].line,toks[ptr].col,ast_num); node.set_num(str2num(toks[ptr].str.c_str())); match(tok_num); return node; } -ast parse::str() -{ + +ast parse::str() { ast node(toks[ptr].line,toks[ptr].col,ast_str); node.set_str(toks[ptr].str); match(tok_str); return node; } -ast parse::id() -{ + +ast parse::id() { ast node(toks[ptr].line,toks[ptr].col,ast_id); node.set_str(toks[ptr].str); match(tok_id); return node; } -ast parse::vec() -{ + +ast parse::vec() { // panic set for this token is not ',' // this is the FIRST set of calculation // array end with tok_null=0 @@ -343,113 +342,113 @@ ast parse::vec() }; ast node(toks[ptr].line,toks[ptr].col,ast_vec); match(tok_lbracket); - while(!lookahead(tok_rbracket)){ + while(!lookahead(tok_rbracket)) { node.add(calc()); - if(lookahead(tok_comma)){ + if (lookahead(tok_comma)) { match(tok_comma); - }else if(lookahead(tok_eof)){ + } else if (lookahead(tok_eof)) { break; - }else if(!lookahead(tok_rbracket) && !check_comma(panic_set)){ + } else if (!lookahead(tok_rbracket) && !check_comma(panic_set)) { break; } } match(tok_rbracket,"expected ']' when generating vector"); return node; } -ast parse::hash() -{ + +ast parse::hash() { ast node(toks[ptr].line,toks[ptr].col,ast_hash); match(tok_lbrace); - while(!lookahead(tok_rbrace)){ + while(!lookahead(tok_rbrace)) { node.add(pair()); - if(lookahead(tok_comma)){ + if (lookahead(tok_comma)) { match(tok_comma); - }else if(lookahead(tok_id) || lookahead(tok_str)){ // first set of hashmember + } else if (lookahead(tok_id) || lookahead(tok_str)) { // first set of hashmember die(thisline,thiscol,thislen,"expected ',' between hash members",true); - }else{ + } else { break; } } match(tok_rbrace,"expected '}' when generating hash"); return node; } -ast parse::pair() -{ + +ast parse::pair() { ast node(toks[ptr].line,toks[ptr].col,ast_pair); - if(lookahead(tok_id)){ + if (lookahead(tok_id)) { node.add(id()); - }else if(lookahead(tok_str)){ + } else if (lookahead(tok_str)) { node.add(str()); - }else{ + } else { match(tok_id,"expected hashmap key"); } match(tok_colon); node.add(calc()); return node; } -ast parse::func() -{ + +ast parse::func() { ++in_func; ast node(toks[ptr].line,toks[ptr].col,ast_func); match(tok_func); - if(lookahead(tok_lcurve)){ + if (lookahead(tok_lcurve)) { node.add(params()); - }else{ + } else { node.add(null()); } node.add(exprs()); --in_func; return node; } -ast parse::params() -{ + +ast parse::params() { ast node(toks[ptr].line,toks[ptr].col,ast_params); match(tok_lcurve); - while(!lookahead(tok_rcurve)){ + while(!lookahead(tok_rcurve)) { ast tmp=id(); - if(lookahead(tok_eq) || lookahead(tok_ellipsis)){ + if (lookahead(tok_eq) || lookahead(tok_ellipsis)) { ast special_arg(toks[ptr].line,toks[ptr].col,ast_null); - if(lookahead(tok_eq)){ + if (lookahead(tok_eq)) { match(tok_eq); special_arg=std::move(tmp); special_arg.set_type(ast_default); special_arg.add(calc()); - }else{ + } else { match(tok_ellipsis); special_arg=std::move(tmp); special_arg.set_type(ast_dynamic); } node.add(std::move(special_arg)); - }else{ + } else { node.add(std::move(tmp)); } - if(lookahead(tok_comma)){ + if (lookahead(tok_comma)) { match(tok_comma); - }else if(lookahead(tok_id)){ // first set of identifier + } else if (lookahead(tok_id)) { // first set of identifier die(thisline,thiscol,thislen,"expected ',' between identifiers",true); - }else{ + } else { break; } } match(tok_rcurve,"expected ')' after parameter list"); return node; } -ast parse::lcurve_expr() -{ - if(toks[ptr+1].type==tok_var) + +ast parse::lcurve_expr() { + if (toks[ptr+1].type==tok_var) return definition(); return check_tuple()?multi_assgin():calc(); } ast parse::expr() { u32 type=toks[ptr].type; - if((type==tok_break || type==tok_continue) && !in_loop){ + if ((type==tok_break || type==tok_continue) && !in_loop) { die(thisline,thiscol,thislen,"must use break/continue in loops"); } - if(type==tok_ret && !in_func){ + if (type==tok_ret && !in_func) { die(thisline,thiscol,thislen,"must use return in functions"); } - switch(type){ + switch(type) { case tok_nil: case tok_num: case tok_str: @@ -477,36 +476,36 @@ ast parse::expr() } return {toks[ptr].line,toks[ptr].col,ast_null}; } -ast parse::exprs() -{ - if(lookahead(tok_eof)){ + +ast parse::exprs() { + if (lookahead(tok_eof)) { die(thisline,thiscol,thislen,"expected expression block"); return null(); } ast node(toks[ptr].line,toks[ptr].col,ast_block); - if(lookahead(tok_lbrace)){ + if (lookahead(tok_lbrace)) { match(tok_lbrace); - while(!lookahead(tok_rbrace) && !lookahead(tok_eof)){ + while(!lookahead(tok_rbrace) && !lookahead(tok_eof)) { node.add(expr()); - if(lookahead(tok_semi)){ + if (lookahead(tok_semi)) { match(tok_semi); - }else if(need_semi_check(node.child().back()) && !lookahead(tok_rbrace)){ + } else if (need_semi_check(node.child().back()) && !lookahead(tok_rbrace)) { // the last expression can be recognized without semi die(thisline,thiscol,thislen,"expected ';'",true); } } match(tok_rbrace,"expected '}' when generating expressions"); - }else{ + } else { node.add(expr()); - if(lookahead(tok_semi)) + if (lookahead(tok_semi)) match(tok_semi); } return node; } -ast parse::calc() -{ + +ast parse::calc() { ast node=or_expr(); - if(lookahead(tok_quesmark)){ + if (lookahead(tok_quesmark)) { // trinocular calculation ast tmp(toks[ptr].line,toks[ptr].col,ast_trino); match(tok_quesmark); @@ -515,7 +514,7 @@ ast parse::calc() match(tok_colon); tmp.add(calc()); node=std::move(tmp); - }else if(tok_eq<=toks[ptr].type && toks[ptr].type<=tok_lnkeq){ + } else if (tok_eq<=toks[ptr].type && toks[ptr].type<=tok_lnkeq) { // tok_eq~tok_lnkeq is 37 to 42,ast_equal~ast_lnkeq is 21~26 ast tmp(toks[ptr].line,toks[ptr].col,toks[ptr].type-tok_eq+ast_equal); tmp.add(std::move(node)); @@ -525,10 +524,10 @@ ast parse::calc() } return node; } -ast parse::or_expr() -{ + +ast parse::or_expr() { ast node=and_expr(); - while(lookahead(tok_or)){ + while(lookahead(tok_or)) { ast tmp(toks[ptr].line,toks[ptr].col,ast_or); tmp.add(std::move(node)); match(tok_or); @@ -537,10 +536,10 @@ ast parse::or_expr() } return node; } -ast parse::and_expr() -{ + +ast parse::and_expr() { ast node=cmp_expr(); - while(lookahead(tok_and)){ + while(lookahead(tok_and)) { ast tmp(toks[ptr].line,toks[ptr].col,ast_and); tmp.add(std::move(node)); match(tok_and); @@ -549,10 +548,10 @@ ast parse::and_expr() } return node; } -ast parse::cmp_expr() -{ + +ast parse::cmp_expr() { ast node=additive_expr(); - while(tok_cmpeq<=toks[ptr].type && toks[ptr].type<=tok_geq){ + while(tok_cmpeq<=toks[ptr].type && toks[ptr].type<=tok_geq) { // tok_cmpeq~tok_geq is 43~48,ast_cmpeq~ast_geq is 27~32 ast tmp(toks[ptr].line,toks[ptr].col,toks[ptr].type-tok_cmpeq+ast_cmpeq); tmp.add(std::move(node)); @@ -562,12 +561,12 @@ ast parse::cmp_expr() } return node; } -ast parse::additive_expr() -{ + +ast parse::additive_expr() { ast node=multive_expr(); - while(lookahead(tok_add) || lookahead(tok_sub) || lookahead(tok_link)){ + while(lookahead(tok_add) || lookahead(tok_sub) || lookahead(tok_link)) { ast tmp(toks[ptr].line,toks[ptr].col,ast_null); - switch(toks[ptr].type){ + switch(toks[ptr].type) { case tok_add: tmp.set_type(ast_add); break; case tok_sub: tmp.set_type(ast_sub); break; case tok_link: tmp.set_type(ast_link); break; @@ -579,10 +578,10 @@ ast parse::additive_expr() } return node; } -ast parse::multive_expr() -{ + +ast parse::multive_expr() { ast node=(lookahead(tok_sub) || lookahead(tok_not))?unary():scalar(); - while(lookahead(tok_mult) || lookahead(tok_div)){ + while(lookahead(tok_mult) || lookahead(tok_div)) { ast tmp(toks[ptr].line,toks[ptr].col,toks[ptr].type-tok_mult+ast_mult); tmp.add(std::move(node)); match(toks[ptr].type); @@ -591,62 +590,62 @@ ast parse::multive_expr() } return node; } -ast parse::unary() -{ + +ast parse::unary() { ast node(toks[ptr].line,toks[ptr].col,ast_null); - switch(toks[ptr].type){ + switch(toks[ptr].type) { case tok_sub:node.set_type(ast_neg);match(tok_sub);break; case tok_not:node.set_type(ast_not);match(tok_not);break; } node.add((lookahead(tok_sub) || lookahead(tok_not))?unary():scalar()); return node; } -ast parse::scalar() -{ + +ast parse::scalar() { ast node(toks[ptr].line,toks[ptr].col,ast_null); - if(lookahead(tok_nil)){ + if (lookahead(tok_nil)) { node=nil(); match(tok_nil); - }else if(lookahead(tok_num)){ + } else if (lookahead(tok_num)) { node=num(); - }else if(lookahead(tok_str)){ + } else if (lookahead(tok_str)) { node=str(); - }else if(lookahead(tok_id)){ + } else if (lookahead(tok_id)) { node=id(); - }else if(lookahead(tok_func)){ + } else if (lookahead(tok_func)) { node=func(); - }else if(lookahead(tok_lbracket)){ + } else if (lookahead(tok_lbracket)) { node=vec(); - }else if(lookahead(tok_lbrace)){ + } else if (lookahead(tok_lbrace)) { node=hash(); - }else if(lookahead(tok_lcurve)){ + } else if (lookahead(tok_lcurve)) { match(tok_lcurve); node=calc(); match(tok_rcurve); - }else if(lookahead(tok_var)){ + } else if (lookahead(tok_var)) { match(tok_var); node.set_type(ast_def); node.add(id()); match(tok_eq); node.add(calc()); - }else{ + } else { die(thisline,thiscol,thislen,"expected scalar"); return node; } // check call and avoid ambiguous syntax - if(is_call(toks[ptr].type) && !(lookahead(tok_lcurve) && toks[ptr+1].type==tok_var)){ + if (is_call(toks[ptr].type) && !(lookahead(tok_lcurve) && toks[ptr+1].type==tok_var)) { ast tmp=std::move(node); node={toks[ptr].line,toks[ptr].col,ast_call}; node.add(std::move(tmp)); - while(is_call(toks[ptr].type)){ + while(is_call(toks[ptr].type)) { node.add(call_scalar()); } } return node; } -ast parse::call_scalar() -{ - switch(toks[ptr].type){ + +ast parse::call_scalar() { + switch(toks[ptr].type) { case tok_lcurve: return callf(); break; case tok_lbracket: return callv(); break; case tok_dot: return callh(); break; @@ -654,16 +653,16 @@ ast parse::call_scalar() // should never run this expression return {toks[ptr].line,toks[ptr].col,ast_nil}; } -ast parse::callh() -{ + +ast parse::callh() { ast node(toks[ptr].line,toks[ptr].col,ast_callh); match(tok_dot); node.set_str(toks[ptr].str); match(tok_id,"expected hashmap key"); // get key return node; } -ast parse::callv() -{ + +ast parse::callv() { // panic set for this token is not ',' // this is the FIRST set of subvec // array end with tok_null=0 @@ -676,24 +675,24 @@ ast parse::callv() }; ast node(toks[ptr].line,toks[ptr].col,ast_callv); match(tok_lbracket); - while(!lookahead(tok_rbracket)){ + while(!lookahead(tok_rbracket)) { node.add(subvec()); - if(lookahead(tok_comma)){ + if (lookahead(tok_comma)) { match(tok_comma); - }else if(lookahead(tok_eof)){ + } else if (lookahead(tok_eof)) { break; - }else if(!lookahead(tok_rbracket) && !check_comma(panic_set)){ + } else if (!lookahead(tok_rbracket) && !check_comma(panic_set)) { break; } } - if(node.size()==0){ + if (node.size()==0) { die(node.line(),node.col(),1,"expected index value"); } match(tok_rbracket,"expected ']' when calling vector"); return node; } -ast parse::callf() -{ + +ast parse::callf() { // panic set for this token is not ',' // this is the FIRST set of calculation/hashmember // array end with tok_null=0 @@ -706,22 +705,22 @@ ast parse::callf() ast node(toks[ptr].line,toks[ptr].col,ast_callf); bool special_call=check_special_call(); match(tok_lcurve); - while(!lookahead(tok_rcurve)){ + while(!lookahead(tok_rcurve)) { node.add(special_call?pair():calc()); - if(lookahead(tok_comma)) + if (lookahead(tok_comma)) match(tok_comma); - else if(lookahead(tok_eof)) + else if (lookahead(tok_eof)) break; - else if(!lookahead(tok_rcurve) && !check_comma(panic_set)) + else if (!lookahead(tok_rcurve) && !check_comma(panic_set)) break; } match(tok_rcurve,"expected ')' when calling function"); return node; } -ast parse::subvec() -{ + +ast parse::subvec() { ast node=lookahead(tok_colon)?nil():calc(); - if(lookahead(tok_colon)){ + if (lookahead(tok_colon)) { ast tmp(node.line(),node.col(),ast_subvec); match(tok_colon); tmp.add(std::move(node)); @@ -730,63 +729,63 @@ ast parse::subvec() } return node; } -ast parse::definition() -{ + +ast parse::definition() { ast node(toks[ptr].line,toks[ptr].col,ast_def); - if(lookahead(tok_var)){ + if (lookahead(tok_var)) { match(tok_var); - switch(toks[ptr].type){ + switch(toks[ptr].type) { case tok_id: node.add(id());break; case tok_lcurve: node.add(outcurve_def());break; default: die(thisline,thiscol,thislen,"expected identifier");break; } - }else if(lookahead(tok_lcurve)){ + } else if (lookahead(tok_lcurve)) { node.add(incurve_def()); } match(tok_eq); - if(lookahead(tok_lcurve)){ + if (lookahead(tok_lcurve)) { node.add(check_tuple()?multi_scalar():calc()); - }else{ + } else { node.add(calc()); } return node; } -ast parse::incurve_def() -{ + +ast parse::incurve_def() { match(tok_lcurve); match(tok_var); ast node=multi_id(); match(tok_rcurve); return node; } -ast parse::outcurve_def() -{ + +ast parse::outcurve_def() { match(tok_lcurve); ast node=multi_id(); match(tok_rcurve); return node; } -ast parse::multi_id() -{ + +ast parse::multi_id() { ast node(toks[ptr].line,toks[ptr].col,ast_multi_id); - while(!lookahead(tok_eof)){ + while(!lookahead(tok_eof)) { node.add(id()); - if(is_call(toks[ptr].type)){ + if (is_call(toks[ptr].type)) { ast tmp=call_scalar();// recognize calls but this is still a syntax error die(tmp.line(),tmp.col(),1,"cannot call identifier in multi-definition"); } - if(lookahead(tok_comma)){ + if (lookahead(tok_comma)) { match(tok_comma); - }else if(lookahead(tok_id)){ // first set of identifier + } else if (lookahead(tok_id)) { // first set of identifier die(thisline,thiscol,thislen,"expected ',' between identifiers",true); - }else{ + } else { break; } } return node; } -ast parse::multi_scalar() -{ + +ast parse::multi_scalar() { // if check_call_memory is true,we will check if value called here can reach a memory space const u32 panic_set[]={ tok_id,tok_str,tok_num, @@ -796,40 +795,40 @@ ast parse::multi_scalar() }; ast node(toks[ptr].line,toks[ptr].col,ast_tuple); match(tok_lcurve); - while(!lookahead(tok_rcurve)){ + while(!lookahead(tok_rcurve)) { node.add(calc()); - if(lookahead(tok_comma)){ + if (lookahead(tok_comma)) { match(tok_comma); - }else if(lookahead(tok_eof)){ + } else if (lookahead(tok_eof)) { break; - }else if(!lookahead(tok_rcurve) && !check_comma(panic_set)){ + } else if (!lookahead(tok_rcurve) && !check_comma(panic_set)) { break; } } match(tok_rcurve,"expected ')' after multi-scalar"); return node; } -ast parse::multi_assgin() -{ + +ast parse::multi_assgin() { ast node(toks[ptr].line,toks[ptr].col,ast_multi_assign); node.add(multi_scalar()); match(tok_eq); - if(lookahead(tok_eof)){ + if (lookahead(tok_eof)) { die(thisline,thiscol,thislen,"expected value list"); return node; } - if(lookahead(tok_lcurve)){ + if (lookahead(tok_lcurve)) { node.add(check_tuple()?multi_scalar():calc()); - }else{ + } else { node.add(calc()); } return node; } -ast parse::loop() -{ + +ast parse::loop() { ++in_loop; ast node(0,0,ast_null); - switch(toks[ptr].type){ + switch(toks[ptr].type) { case tok_while: node=while_loop(); break; case tok_for: node=for_loop(); break; case tok_forindex: @@ -838,8 +837,8 @@ ast parse::loop() --in_loop; return node; } -ast parse::while_loop() -{ + +ast parse::while_loop() { ast node(toks[ptr].line,toks[ptr].col,ast_while); match(tok_while); match(tok_lcurve); @@ -848,64 +847,64 @@ ast parse::while_loop() node.add(exprs()); return node; } -ast parse::for_loop() -{ + +ast parse::for_loop() { ast node(toks[ptr].line,toks[ptr].col,ast_for); match(tok_for); match(tok_lcurve); // first expression - if(lookahead(tok_eof)){ + if (lookahead(tok_eof)) { die(thisline,thiscol,thislen,"expected definition"); } - if(lookahead(tok_semi)){ + if (lookahead(tok_semi)) { node.add(null()); - }else if(lookahead(tok_var)){ + } else if (lookahead(tok_var)) { node.add(definition()); - }else if(lookahead(tok_lcurve)){ + } else if (lookahead(tok_lcurve)) { node.add(lcurve_expr()); - }else{ + } else { node.add(calc()); } match(tok_semi,"expected ';' in for(;;)"); // conditional expression - if(lookahead(tok_eof)){ + if (lookahead(tok_eof)) { die(thisline,thiscol,thislen,"expected conditional expr"); } - if(lookahead(tok_semi)){ + if (lookahead(tok_semi)) { node.add(null()); - }else{ + } else { node.add(calc()); } match(tok_semi,"expected ';' in for(;;)"); //after loop expression - if(lookahead(tok_eof)){ + if (lookahead(tok_eof)) { die(thisline,thiscol,thislen,"expected calculation"); } - if(lookahead(tok_rcurve)){ + if (lookahead(tok_rcurve)) { node.add(null()); - }else{ + } else { node.add(calc()); } match(tok_rcurve); node.add(exprs()); return node; } -ast parse::forei_loop() -{ + +ast parse::forei_loop() { ast node(toks[ptr].line,toks[ptr].col,ast_null); - switch(toks[ptr].type){ + switch(toks[ptr].type) { case tok_forindex:node.set_type(ast_forindex);match(tok_forindex);break; case tok_foreach: node.set_type(ast_foreach); match(tok_foreach); break; } match(tok_lcurve); // first expression // foreach/forindex must have an iterator to loop through - if(!lookahead(tok_var) && !lookahead(tok_id)){ + if (!lookahead(tok_var) && !lookahead(tok_id)) { die(thisline,thiscol,thislen,"expected iterator"); } node.add(iter_gen()); match(tok_semi,"expected ';' in foreach/forindex(iter;vector)"); - if(lookahead(tok_eof)){ + if (lookahead(tok_eof)) { die(thisline,thiscol,thislen,"expected vector"); } node.add(calc()); @@ -913,24 +912,24 @@ ast parse::forei_loop() node.add(exprs()); return node; } -ast parse::iter_gen() -{ + +ast parse::iter_gen() { ast node(toks[ptr].line,toks[ptr].col,ast_null); - if(lookahead(tok_var)){ + if (lookahead(tok_var)) { match(tok_var); node.set_type(ast_iter); node.add(id()); - }else{ + } else { node.set_type(ast_call); node.add(id()); - while(is_call(toks[ptr].type)){ + while(is_call(toks[ptr].type)) { node.add(call_scalar()); } } return node; } -ast parse::cond() -{ + +ast parse::cond() { ast node(toks[ptr].line,toks[ptr].col,ast_cond); ast ifnode(toks[ptr].line,toks[ptr].col,ast_if); match(tok_if); @@ -939,7 +938,7 @@ ast parse::cond() match(tok_rcurve); ifnode.add(exprs()); node.add(std::move(ifnode)); - while(lookahead(tok_elsif)){ + while(lookahead(tok_elsif)) { ast elsifnode(toks[ptr].line,toks[ptr].col,ast_elsif); match(tok_elsif); match(tok_lcurve); @@ -948,7 +947,7 @@ ast parse::cond() elsifnode.add(exprs()); node.add(std::move(elsifnode)); } - if(lookahead(tok_else)){ + if (lookahead(tok_else)) { ast elsenode(toks[ptr].line,toks[ptr].col,ast_else); match(tok_else); elsenode.add(exprs()); @@ -956,27 +955,27 @@ ast parse::cond() } return node; } -ast parse::continue_expr() -{ + +ast parse::continue_expr() { ast node(toks[ptr].line,toks[ptr].col,ast_continue); match(tok_continue); return node; } -ast parse::break_expr() -{ + +ast parse::break_expr() { ast node(toks[ptr].line,toks[ptr].col,ast_break); match(tok_break); return node; } -ast parse::ret_expr() -{ + +ast parse::ret_expr() { ast node(toks[ptr].line,toks[ptr].col,ast_ret); match(tok_ret); u32 type=toks[ptr].type; - if(type==tok_nil || type==tok_num || type==tok_str || type==tok_id || + if (type==tok_nil || type==tok_num || type==tok_str || type==tok_id || type==tok_func || type==tok_sub || type==tok_not || type==tok_lcurve || type==tok_lbracket || type==tok_lbrace - ){ + ) { node.add(calc()); } return node; diff --git a/nasal_vm.h b/nasal_vm.h index ce0c387..74db975 100644 --- a/nasal_vm.h +++ b/nasal_vm.h @@ -4,8 +4,7 @@ #include #include "nasal_codegen.h" -class vm -{ +class vm { protected: /* registers and constants of vm */ u32 pc; // program counter @@ -131,7 +130,7 @@ public: upvalr(nil),canary(nullptr),top(stack), cnum(nullptr),cstr(nullptr), ngc(pc,localr,memr,funcr,upvalr,canary,top,stack), - files(nullptr),bytecode(nullptr),verbose(false){} + files(nullptr),bytecode(nullptr),verbose(false) {} void run( const codegen&, const linker&, @@ -144,8 +143,7 @@ void vm::init( const std::vector& nums, const std::vector& code, const std::vector& filenames, - const std::vector& argv) -{ + const std::vector& argv) { ngc.init(strs,argv); cnum=nums.data(); cstr=strs.data(); @@ -160,15 +158,15 @@ void vm::init( top=stack; /* clear main stack */ - for(u32 i=0;i ret; - for(var* i=bottom;i<=ctx_top;++i) - if(i->type==vm_ret && i->ret()!=0) + for(var* i=bottom;i<=ctx_top;++i) { + if (i->type==vm_ret && i->ret()!=0) { ret.push(i->ret()); + } + } ret.push(pc); // store the position program crashed std::cout<<"trace back ("<<(ngc.stack==stack?"main":"coroutine")<<")\n"; - for(u32 p=0,same=0,prev=0xffffffff;!ret.empty();prev=p,ret.pop()) - { - if((p=ret.top())==prev) - { + for(u32 p=0,same=0,prev=0xffffffff;!ret.empty();prev=p,ret.pop()) { + if ((p=ret.top())==prev) { ++same; continue; } - if(same) + if (same) { std::cout <<" 0x"<, limit "<=bottom;++i,--t) - { + for(u32 i=0;i=bottom;++i,--t) { std::cout<<" 0x"<)\n"<)\n"< upval["<>16)&0xffff] .upval()[imm[pc]&0xffff]=(top--)[0]; } -inline void vm::o_pnum() -{ + +inline void vm::o_pnum() { (++top)[0]={vm_num,cnum[imm[pc]]}; } -inline void vm::o_pnil() -{ + +inline void vm::o_pnil() { (++top)[0]=nil; } -inline void vm::o_pstr() -{ + +inline void vm::o_pstr() { (++top)[0]=ngc.strs[imm[pc]]; } -inline void vm::o_newv() -{ + +inline void vm::o_newv() { var newv=ngc.alloc(vm_vec); auto& vec=newv.vec().elems; vec.resize(imm[pc]); // use top-=imm[pc]-1 here will cause error if imm[pc] is 0 top=top-imm[pc]+1; - for(u32 i=0;isize has 1 place reserved for "me" func.keys[imm[pc]]=func.psize; func.local[func.psize++]={vm_none}; } -inline void vm::o_deft() -{ + +inline void vm::o_deft() { var val=top[0]; nas_func& func=(--top)[0].func(); // func->size has 1 place reserved for "me" func.keys[imm[pc]]=func.psize; func.local[func.psize++]=val; } -inline void vm::o_dyn() -{ + +inline void vm::o_dyn() { top[0].func().dpara=imm[pc]; } -inline void vm::o_unot() -{ + +inline void vm::o_unot() { var val=top[0]; - switch(val.type) - { + switch(val.type) { case vm_nil:top[0]=one;break; case vm_num:top[0]=val.num()?zero:one;break; - case vm_str: - { + case vm_str:{ const f64 num=str2num(val.str().c_str()); - if(std::isnan(num)) + if (std::isnan(num)) { top[0]={vm_num,(f64)val.str().empty()}; - else + } else { top[0]=num?zero:one; - }break; + } + } break; default:vm_error("incorrect value type");break; } } -inline void vm::o_usub() -{ + +inline void vm::o_usub() { top[0]={vm_num,-top[0].tonum()}; } @@ -457,12 +453,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() -{ +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() { top[-1]=ngc.newstr(top[-1].tostr()+top[0].tostr()); --top; } @@ -470,12 +465,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() -{ +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() { top[0]=ngc.newstr(top[0].tostr()+cstr[imm[pc]]); } @@ -484,12 +478,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() -{ +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() { top[-1]=memr[0]=ngc.newstr(memr[0].tostr()+top[-1].tostr()); memr=nullptr; top-=imm[pc]+1; @@ -500,19 +493,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() -{ +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() { top[0]=memr[0]=ngc.newstr(memr[0].tostr()+cstr[imm[pc]&0x7fffffff]); memr=nullptr; top-=(imm[pc]>>31); } -inline void vm::o_meq() -{ +inline 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 @@ -522,200 +513,214 @@ inline void vm::o_meq() memr=nullptr; top-=imm[pc]+1; } -inline void vm::o_eq() -{ + +inline void vm::o_eq() { var val2=top[0]; var val1=(--top)[0]; - if(val1.type==vm_nil && val2.type==vm_nil) + if (val1.type==vm_nil && val2.type==vm_nil) { top[0]=one; - else if(val1.type==vm_str && val2.type==vm_str) + } else if (val1.type==vm_str && val2.type==vm_str) { 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) + } else if ((val1.type==vm_num || val2.type==vm_num) + && val1.type!=vm_nil && val2.type!=vm_nil) { top[0]=(val1.tonum()==val2.tonum())?one:zero; - else + } else { top[0]=(val1==val2)?one:zero; + } } -inline void vm::o_neq() -{ + +inline void vm::o_neq() { var val2=top[0]; var val1=(--top)[0]; - if(val1.type==vm_nil && val2.type==vm_nil) + if (val1.type==vm_nil && val2.type==vm_nil) { top[0]=zero; - else if(val1.type==vm_str && val2.type==vm_str) + } else if (val1.type==vm_str && val2.type==vm_str) { 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) + } else if ((val1.type==vm_num || val2.type==vm_num) + && val1.type!=vm_nil && val2.type!=vm_nil) { top[0]=(val1.tonum()!=val2.tonum())?one:zero; - else + } else { top[0]=(val1!=val2)?one:zero; + } } #define op_cmp(type)\ --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(>=);} +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(>=);} #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(>=);} +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(>=);} -inline void vm::o_pop() -{ +inline void vm::o_pop() { --top; } -inline void vm::o_jmp() -{ + +inline void vm::o_jmp() { pc=imm[pc]-1; } -inline void vm::o_jt() -{ - if(cond(top[0])) + +inline 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])) { pc=imm[pc]-1; + } } -inline void vm::o_jf() -{ - if(!cond(top[0])) + +inline void vm::o_jf() { + // jump false doesn't need to reserve result + if (!cond(top[0])) { pc=imm[pc]-1; + } --top; } -inline void vm::o_cnt() -{ - if(top[0].type!=vm_vec) + +inline void vm::o_cnt() { + if (top[0].type!=vm_vec) { vm_error("must use vector in forindex/foreach"); + } (++top)[0]={vm_cnt,(i64)-1}; } -inline void vm::o_findex() -{ - if((usize)(++top[0].cnt())>=top[-1].vec().size()) - { + +inline void vm::o_findex() { + if ((usize)(++top[0].cnt())>=top[-1].vec().size()) { pc=imm[pc]-1; return; } top[1]={vm_num,(f64)top[0].cnt()}; ++top; } -inline void vm::o_feach() -{ + +inline void vm::o_feach() { auto& ref=top[-1].vec().elems; - if((usize)(++top[0].cnt())>=ref.size()) - { + if ((usize)(++top[0].cnt())>=ref.size()) { pc=imm[pc]-1; return; } top[1]=ref[top[0].cnt()]; ++top; } -inline void vm::o_callg() -{ + +inline void vm::o_callg() { (++top)[0]=stack[imm[pc]]; } -inline void vm::o_calll() -{ + +inline void vm::o_calll() { (++top)[0]=localr[imm[pc]]; } -inline void vm::o_upval() -{ + +inline void vm::o_upval() { (++top)[0]=funcr.func().upval[(imm[pc]>>16)&0xffff] .upval()[imm[pc]&0xffff]; } -inline void vm::o_callv() -{ + +inline void vm::o_callv() { var val=top[0]; var vec=(--top)[0]; - if(vec.type==vm_vec) - { + if (vec.type==vm_vec) { top[0]=vec.vec().get_val(val.tonum()); - if(top[0].type==vm_none) + if (top[0].type==vm_none) { vm_error("out of range:"+std::to_string(val.tonum())); - } - else if(vec.type==vm_hash) - { - if(val.type!=vm_str) + } + } else if (vec.type==vm_hash) { + if (val.type!=vm_str) { vm_error("must use string as the key"); + } top[0]=vec.hash().get_val(val.str()); - if(top[0].type==vm_none) + if (top[0].type==vm_none) { vm_error("cannot find member \""+val.str()+"\""); - if(top[0].type==vm_func) - top[0].func().local[0]=val;// 'me' - } - else if(vec.type==vm_str) - { + } else if (top[0].type==vm_func) { + top[0].func().local[0]=val; // 'me' + } + } else if (vec.type==vm_str) { string& str=vec.str(); i32 num=val.tonum(); i32 len=str.length(); - if(num<-len || num>=len) + if (num<-len || num>=len) { vm_error("out of range:"+std::to_string(val.tonum())); + } top[0]={vm_num,f64((u8)str[num>=0? num:num+len])}; - } - else + } else { vm_error("must call a vector/hash/string"); + } } -inline void vm::o_callvi() -{ + +inline void vm::o_callvi() { var val=top[0]; - if(val.type!=vm_vec) + if (val.type!=vm_vec) { vm_error("must use a vector"); + } // cannot use operator[],because this may cause overflow (++top)[0]=val.vec().get_val(imm[pc]); - if(top[0].type==vm_none) + if (top[0].type==vm_none) { vm_error("out of range:"+std::to_string(imm[pc])); + } } -inline void vm::o_callh() -{ + +inline void vm::o_callh() { var val=top[0]; - if(val.type!=vm_hash) + if (val.type!=vm_hash) { vm_error("must call a hash"); + } top[0]=val.hash().get_val(cstr[imm[pc]]); - if(top[0].type==vm_none) + if (top[0].type==vm_none) { vm_error("member \""+cstr[imm[pc]]+"\" does not exist"); - if(top[0].type==vm_func) - top[0].func().local[0]=val;// 'me' + } else if (top[0].type==vm_func) { + top[0].func().local[0]=val; // 'me' + } } -inline void vm::o_callfv() -{ + +inline void vm::o_callfv() { u32 argc=imm[pc]; // arguments counter var* local=top-argc+1; // arguments begin address - if(local[-1].type!=vm_func) + if (local[-1].type!=vm_func) { vm_error("must call a function"); + } auto& func=local[-1].func(); var tmp=local[-1]; local[-1]=funcr; funcr=tmp; // top-argc+lsize(local) +1(old pc) +1(old localr) +1(old upvalr) - if(top-argc+func.lsize+3>=canary) + if (top-argc+func.lsize+3>=canary) { vm_error("stack overflow"); + } // parameter size is func->psize-1, 1 is reserved for "me" u32 psize=func.psize-1; - if(argc=0)// load dynamic arguments - { + if (func.dpara>=0) { // load dynamic arguments dynamic=ngc.alloc(vm_vec); - for(u32 i=psize;i=1;--i)// load arguments + for(u32 i=min_size;i>=1;--i) { // load arguments local[i]=local[i-1]; + } local[0]=func.local[0];// load "me" // load local scope & default arguments - for(u32 i=min_size+1;i=0) + } + if (func.dpara>=0) { local[psize+1]=dynamic; + } top[0]=upvalr; (++top)[0]={vm_addr,localr}; @@ -724,33 +729,37 @@ inline void vm::o_callfv() localr=local; upvalr=nil; } -inline void vm::o_callfh() -{ + +inline void vm::o_callfh() { auto& hash=top[0].hash().elems; - if(top[-1].type!=vm_func) + if (top[-1].type!=vm_func) { vm_error("must call a function"); + } auto& func=top[-1].func(); var tmp=top[-1]; top[-1]=funcr; funcr=tmp; // top -1(hash) +lsize(local) +1(old pc) +1(old localr) +1(old upvalr) - if(top+func.lsize+2>=canary) + if (top+func.lsize+2>=canary) { vm_error("stack overflow"); - if(func.dpara>=0) + } + if (func.dpara>=0) { vm_error("special call cannot use dynamic argument"); + } var* local=top; top+=func.lsize; - for(u32 i=0;i=size || num2<-size || num2>=size){ + if (num1<-size || num1>=size || num2<-size || num2>=size) { vm_error("index "+std::to_string(num1)+":"+std::to_string(num2)+" out of range."); - }else if(num1<=num2){ + } else if (num1<=num2) { for(i32 i=num1;i<=num2;++i) aim.push_back(i>=0?ref[i]:ref[i+size]); } } -inline void vm::o_mcallg() -{ + +inline 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() -{ + +inline 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() -{ + +inline 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() -{ + +inline 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) - { + if (vec.type==vm_vec) { memr=vec.vec().get_mem(val.tonum()); - if(!memr) + if (!memr) { vm_error("out of range:"+std::to_string(val.tonum())); - }else if(vec.type==vm_hash) // do mcallh but use the mcallv way - { - if(val.type!=vm_str) + } + } else if (vec.type==vm_hash) { // do mcallh but use the mcallv way + if (val.type!=vm_str) { vm_error("must use string as the key"); + } nas_hash& ref=vec.hash(); string& str=val.str(); memr=ref.get_mem(str); - if(!memr) - { + if (!memr) { ref.elems[str]=nil; memr=ref.get_mem(str); } - }else + } else { vm_error("cannot get memory space in this type"); + } } -inline void vm::o_mcallh() -{ + +inline void vm::o_mcallh() { var hash=top[0]; // mcall hash, reserved on stack to avoid gc - if(hash.type!=vm_hash) + if (hash.type!=vm_hash) { vm_error("must call a hash"); + } auto& ref=hash.hash(); auto& str=cstr[imm[pc]]; memr=ref.get_mem(str); - if(!memr) // create a new key - { + if (!memr) { // create a new key ref.elems[str]=nil; memr=ref.get_mem(str); } } -inline void vm::o_ret() -{ + +inline void vm::o_ret() { /* +-------------+ * | return value| <- top[0] * +-------------+ @@ -895,7 +906,6 @@ inline void vm::o_ret() * | old upvalr | <- top[-3] * +-------------+ * | local scope | -* | ... | * +-------------+ <- local pointer stored in localr * | old funcr | <- old function stored in funcr * +-------------+ @@ -913,8 +923,7 @@ inline void vm::o_ret() funcr=top[0]; top[0]=ret; // rewrite func with returned value - if(up.type==vm_upval) // synchronize upvalue - { + if (up.type==vm_upval) { // synchronize upvalue auto& upval=up.upval(); auto size=func.func().lsize; upval.onstk=false; @@ -923,20 +932,19 @@ inline void vm::o_ret() } // cannot use gc.cort to judge, // because there maybe another function call inside - if(!pc) + if (!pc) { ngc.ctxreserve(); + } } void vm::run( const codegen& gen, const linker& linker, const std::vector& argv, - const bool detail) -{ + const bool detail) { verbose=detail; init(gen.strs(),gen.nums(),gen.codes(),linker.filelist(),argv); #ifndef _MSC_VER - const void* oprs[]= - { + const void* oprs[]={ &&vmexit, &&intg, &&intl, &&loadg, &&loadl, &&loadu, &&pnum, &&pnil, &&pstr, &&newv, &&newh, &&newf, @@ -958,8 +966,7 @@ void vm::run( &&mcallv, &&mcallh, &&ret }; std::vector code; - for(auto& i:gen.codes()) - { + for(auto& i:gen.codes()) { code.push_back(oprs[i.op]); imm.push_back(i.num); } @@ -967,8 +974,7 @@ void vm::run( goto *code[pc]; #else typedef void (vm::*nafunc)(); - const nafunc oprs[]= - { + const nafunc oprs[]={ nullptr, &vm::o_intg, &vm::o_intl, &vm::o_loadg, &vm::o_loadl, &vm::o_loadu, @@ -1009,22 +1015,23 @@ void vm::run( &vm::o_ret }; std::vector code; - for(auto& i:gen.codes()) - { + for(auto& i:gen.codes()) { code.push_back(oprs[i.op]); imm.push_back(i.num); } - while(code[pc]){ + while(code[pc]) { (this->*code[pc])(); - if(top>=canary) + if (top>=canary) { die("stack overflow"); + } ++pc; } #endif vmexit: - if(detail) + if (detail) { ngc.info(); + } ngc.clear(); imm.clear(); return; @@ -1033,7 +1040,7 @@ vmexit: // may cause stackoverflow #define exec_check(op) {\ op();\ - if(top4){ @@ -31,9 +31,11 @@ var f=func(i,j){ } } var progress=(i*width+j+1)/(width*height); - print(bar.bar(progress)," ",progress*100,"% \r"); + if(progress*100-int(progress*100)==0){ + print(bar.bar(progress)," ",progress*100,"% \r"); + } iter=iter==25?255:int(iter/25*255); return iter~" "~iter~" "~iter~" "; } ppm("a.ppm",width,height,f); -println("\nfinished."); +println();