🎨 change code format

This commit is contained in:
ValKmjolnir 2022-11-26 22:49:22 +08:00
parent 54969681fc
commit 4c5ffb0240
20 changed files with 1965 additions and 2088 deletions

View File

@ -21,10 +21,8 @@ const u32 VM_TIME =0x04;
const u32 VM_EXEC =0x08; const u32 VM_EXEC =0x08;
const u32 VM_DETAIL=0x10; const u32 VM_DETAIL=0x10;
const u32 VM_DEBUG =0x20; const u32 VM_DEBUG =0x20;
const u32 VM_OPT =0x40;
std::ostream& help(std::ostream& out) std::ostream& help(std::ostream& out) {
{
out out
<<" ,--#-,\n" <<" ,--#-,\n"
<<"<3 / \\____\\ <3\n" <<"<3 / \\____\\ <3\n"
@ -44,8 +42,6 @@ std::ostream& help(std::ostream& out)
<<" -d, --detail | get detail crash info.\n" <<" -d, --detail | get detail crash info.\n"
<<" | get detail path-not-found info.\n" <<" | get detail path-not-found info.\n"
<<" | get detail gc 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" <<" -dbg, --debug | debug mode (ignore -t -d).\n"
<<"file:\n" <<"file:\n"
<<" <filename> | execute file.\n" <<" <filename> | execute file.\n"
@ -54,8 +50,7 @@ std::ostream& help(std::ostream& out)
return out; return out;
} }
std::ostream& logo(std::ostream& out) std::ostream& logo(std::ostream& out) {
{
out out
<<" __ _\n" <<" __ _\n"
<<" /\\ \\ \\__ _ ___ __ _| |\n" <<" /\\ \\ \\__ _ ___ __ _| |\n"
@ -72,16 +67,14 @@ std::ostream& logo(std::ostream& out)
} }
[[noreturn]] [[noreturn]]
void err() void err() {
{
std::cerr std::cerr
<<"invalid argument(s).\n" <<"invalid argument(s).\n"
<<"use <nasal -h> to get help.\n"; <<"use <nasal -h> to get help.\n";
std::exit(1); std::exit(1);
} }
void execute(const string& file,const std::vector<string>& argv,const u32 cmd) void execute(const string& file,const std::vector<string>& argv,const u32 cmd) {
{
error err; error err;
lexer lex(err); lexer lex(err);
parse parse(err); parse parse(err);
@ -96,46 +89,44 @@ void execute(const string& file,const std::vector<string>& argv,const u32 cmd)
// linker gets parser's ast and load import files to this ast // linker gets parser's ast and load import files to this ast
ld.link(parse,file,cmd&VM_DETAIL).chkerr(); ld.link(parse,file,cmd&VM_DETAIL).chkerr();
// optimizer does simple optimization on ast // optimizer does simple optimization on ast
if(cmd&VM_OPT) optimize(parse.tree());
optimize(parse.tree()); if (cmd&VM_AST) {
if(cmd&VM_AST)
parse.tree().dump(); parse.tree().dump();
}
// code generator gets parser's ast and linker's import file list to generate code // code generator gets parser's ast and linker's import file list to generate code
gen.compile(parse,ld).chkerr(); gen.compile(parse,ld).chkerr();
if(cmd&VM_CODE) if (cmd&VM_CODE) {
gen.print(); gen.print();
}
// run // run
if(cmd&VM_DEBUG) if (cmd&VM_DEBUG) {
debugger(err).run(gen,ld,argv); debugger(err).run(gen,ld,argv);
else if(cmd&VM_TIME) } else if (cmd&VM_TIME) {
{
auto start=ch_clk::now(); auto start=ch_clk::now();
ctx.run(gen,ld,argv,cmd&VM_DETAIL); ctx.run(gen,ld,argv,cmd&VM_DETAIL);
auto end=ch_clk::now(); auto end=ch_clk::now();
std::clog<<"process exited after "<<(end-start).count()*1.0/ch_clk::duration::period::den<<"s.\n"; 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); ctx.run(gen,ld,argv,cmd&VM_DETAIL);
}
} }
i32 main(i32 argc,const char* argv[]) i32 main(i32 argc,const char* argv[]) {
{ if (argc<=1) {
if(argc<=1)
{
std::clog<<logo; std::clog<<logo;
return 0; return 0;
} }
if(argc==2) if (argc==2) {
{
string s(argv[1]); string s(argv[1]);
if(s=="-h" || s=="--help") if (s=="-h" || s=="--help") {
std::clog<<help; std::clog<<help;
else if(s[0]!='-') } else if (s[0]!='-') {
execute(s,{},VM_EXEC); execute(s,{},VM_EXEC);
else } else {
err(); err();
}
return 0; return 0;
} }
std::unordered_map<string,u32> cmdlst={ std::unordered_map<string,u32> cmdlst={
@ -144,23 +135,23 @@ i32 main(i32 argc,const char* argv[])
{"--exec",VM_EXEC},{"-e",VM_EXEC}, {"--exec",VM_EXEC},{"-e",VM_EXEC},
{"--time",VM_TIME|VM_EXEC},{"-t",VM_TIME|VM_EXEC}, {"--time",VM_TIME|VM_EXEC},{"-t",VM_TIME|VM_EXEC},
{"--detail",VM_DETAIL|VM_EXEC},{"-d",VM_DETAIL|VM_EXEC}, {"--detail",VM_DETAIL|VM_EXEC},{"-d",VM_DETAIL|VM_EXEC},
{"--optimize",VM_OPT},{"-o",VM_OPT},
{"--debug",VM_DEBUG},{"-dbg",VM_DEBUG} {"--debug",VM_DEBUG},{"-dbg",VM_DEBUG}
}; };
u32 cmd=0; u32 cmd=0;
string filename=""; string filename="";
std::vector<string> vm_argv; std::vector<string> vm_argv;
for(i32 i=1;i<argc;++i) for(i32 i=1;i<argc;++i) {
{ if (cmdlst.count(argv[i])) {
if(cmdlst.count(argv[i]))
cmd|=cmdlst[argv[i]]; cmd|=cmdlst[argv[i]];
else if(!filename.length()) } else if (!filename.length()) {
filename=argv[i]; filename=argv[i];
else } else {
vm_argv.push_back(argv[i]); vm_argv.push_back(argv[i]);
}
} }
if(!filename.length()) if (!filename.length()) {
err(); err();
}
execute(filename,vm_argv,cmd?cmd:VM_EXEC); execute(filename,vm_argv,cmd?cmd:VM_EXEC);
return 0; return 0;
} }

View File

@ -32,46 +32,46 @@ clean:
-@ rm ./nasal.exe -@ rm ./nasal.exe
test:nasal test:nasal
@ ./nasal -o -e test/ascii-art.nas @ ./nasal -e test/ascii-art.nas
@ ./nasal -o -c test/auto_crash.nas @ ./nasal -c test/auto_crash.nas
@ ./nasal -o -a -c test/bf.nas @ ./nasal -a -c test/bf.nas
@ ./nasal -o -a -c test/bfconvertor.nas @ ./nasal -a -c test/bfconvertor.nas
@ ./nasal -o -d test/bfs.nas @ ./nasal -d test/bfs.nas
@ ./nasal -o -t test/bigloop.nas @ ./nasal -t test/bigloop.nas
@ ./nasal -o -e test/bp.nas @ ./nasal -e test/bp.nas
@ ./nasal -o -d test/calc.nas @ ./nasal -d test/calc.nas
@ ./nasal -o -e test/choice.nas @ ./nasal -e test/choice.nas
@ ./nasal -o -e test/class.nas @ ./nasal -e test/class.nas
@ ./nasal -o -t -d test/console3D.nas @ ./nasal -t -d test/console3D.nas
@ ./nasal -o -e test/coroutine.nas @ ./nasal -e test/coroutine.nas
@ ./nasal -o -e test/diff.nas @ ./nasal -e test/diff.nas
@ ./nasal -o -e test/donuts.nas @ ./nasal -e test/donuts.nas
-@ ./nasal -o -d test/exception.nas -@ ./nasal -d test/exception.nas
@ ./nasal -o -t -d test/fib.nas @ ./nasal -t -d test/fib.nas
@ ./nasal -o -e test/filesystem.nas @ ./nasal -e test/filesystem.nas
@ ./nasal -o -d test/hexdump.nas @ ./nasal -d test/hexdump.nas
@ ./nasal -o -c test/httptest.nas @ ./nasal -c test/httptest.nas
@ ./nasal -o -e test/json.nas @ ./nasal -e test/json.nas
@ ./nasal -o -e test/leetcode1319.nas @ ./nasal -e test/leetcode1319.nas
@ ./nasal -o -d test/lexer.nas @ ./nasal -d test/lexer.nas
@ ./nasal -o -d test/life.nas @ ./nasal -d test/life.nas
@ ./nasal -o -t test/loop.nas @ ./nasal -t test/loop.nas
@ ./nasal -o -t -d test/mandel.nas @ ./nasal -t -d test/mandel.nas
@ ./nasal -o -t -d test/mandelbrot.nas @ ./nasal -t -d test/mandelbrot.nas
@ ./nasal -o -t -d test/md5.nas @ ./nasal -t -d test/md5.nas
@ ./nasal -o -t -d test/md5compare.nas @ ./nasal -t -d test/md5compare.nas
-@ ./nasal -o -d test/module_test.nas -@ ./nasal -d test/module_test.nas
@ ./nasal -o -e test/nasal_test.nas @ ./nasal -e test/nasal_test.nas
@ ./nasal -o -c test/occupation.nas @ ./nasal -c test/occupation.nas
@ ./nasal -o -t -d test/pi.nas @ ./nasal -t -d test/pi.nas
@ ./nasal -o -c test/ppmgen.nas @ ./nasal -c test/ppmgen.nas
@ ./nasal -o -t -d test/prime.nas @ ./nasal -t -d test/prime.nas
@ ./nasal -o -e test/qrcode.nas @ ./nasal -e test/qrcode.nas
@ ./nasal -o -t -d test/quick_sort.nas @ ./nasal -t -d test/quick_sort.nas
@ ./nasal -o -e test/scalar.nas hello world @ ./nasal -e test/scalar.nas hello world
-@ ./nasal -o -c -t test/snake.nas -@ ./nasal -c -t test/snake.nas
@ ./nasal -o -c -e test/trait.nas @ ./nasal -c -e test/trait.nas
-@ ./nasal -o -c -t test/tetris.nas -@ ./nasal -c -t test/tetris.nas
@ ./nasal -o -c -t -d test/turingmachine.nas @ ./nasal -c -t -d test/turingmachine.nas
@ ./nasal -o -c -t -d test/ycombinator.nas @ ./nasal -c -t -d test/ycombinator.nas
@ ./nasal -o -d test/wavecollapse.nas @ ./nasal -d test/wavecollapse.nas

View File

@ -1,27 +1,31 @@
#include <iostream> #include <iostream>
#include "../nasal.h" #include "../nasal.h"
double fibonaci(double x){ double fibonaci(double x) {
if(x<=2) if (x<=2) {
return x; return x;
}
return fibonaci(x-1)+fibonaci(x-2); return fibonaci(x-1)+fibonaci(x-2);
} }
var fib(var* args,usize size,gc* ngc){ var fib(var* args,usize size,gc* ngc) {
if(!size) if (!size) {
return nas_err("fib","lack arguments"); return nas_err("fib","lack arguments");
}
var num=args[0]; var num=args[0];
return {vm_num,fibonaci(num.tonum())}; return {vm_num,fibonaci(num.tonum())};
} }
var quick_fib(var* args,usize size,gc* ngc){ var quick_fib(var* args,usize size,gc* ngc) {
if(!size) if (!size) {
return nas_err("quick_fib","lack arguments"); return nas_err("quick_fib","lack arguments");
}
double num=args[0].tonum(); double num=args[0].tonum();
if(num<2) if (num<2) {
return {vm_num,num}; return {vm_num,num};
}
double a=1,b=1,res=0; double a=1,b=1,res=0;
for(double i=1;i<num;i+=1){ for(double i=1;i<num;i+=1) {
res=a+b; res=a+b;
a=b; a=b;
b=res; b=res;
@ -35,6 +39,6 @@ mod_func func_tbl[]={
{nullptr, nullptr}, {nullptr, nullptr},
}; };
extern "C" mod_func* get(){ extern "C" mod_func* get() {
return func_tbl; return func_tbl;
} }

View File

@ -8,7 +8,7 @@
#include <termios.h> #include <termios.h>
#endif #endif
class noecho_input{ class noecho_input {
private: private:
#ifndef _WIN32 #ifndef _WIN32
struct termios init_termios; struct termios init_termios;
@ -16,7 +16,7 @@ private:
int peek_char=-1; int peek_char=-1;
#endif #endif
public: public:
noecho_input(){ noecho_input() {
#ifndef _WIN32 #ifndef _WIN32
tcflush(0,TCIOFLUSH); tcflush(0,TCIOFLUSH);
tcgetattr(0,&init_termios); tcgetattr(0,&init_termios);
@ -29,23 +29,24 @@ public:
tcsetattr(0,TCSANOW,&new_termios); tcsetattr(0,TCSANOW,&new_termios);
#endif #endif
} }
~noecho_input(){ ~noecho_input() {
#ifndef _WIN32 #ifndef _WIN32
tcflush(0,TCIOFLUSH); tcflush(0,TCIOFLUSH);
tcsetattr(0,TCSANOW,&init_termios); tcsetattr(0,TCSANOW,&init_termios);
#endif #endif
} }
int noecho_kbhit(){ int noecho_kbhit() {
#ifndef _WIN32 #ifndef _WIN32
unsigned char ch=0; unsigned char ch=0;
int nread=0; int nread=0;
if(peek_char!=-1) if (peek_char!=-1) {
return 1; return 1;
}
int flag=fcntl(0,F_GETFL); int flag=fcntl(0,F_GETFL);
fcntl(0,F_SETFL,flag|O_NONBLOCK); fcntl(0,F_SETFL,flag|O_NONBLOCK);
nread=read(0,&ch,1); nread=read(0,&ch,1);
fcntl(0,F_SETFL,flag); fcntl(0,F_SETFL,flag);
if(nread==1){ if (nread==1) {
peek_char=ch; peek_char=ch;
return 1; return 1;
} }
@ -54,10 +55,10 @@ public:
return kbhit(); return kbhit();
#endif #endif
} }
int noecho_getch(){ int noecho_getch() {
#ifndef _WIN32 #ifndef _WIN32
int ch=0; int ch=0;
if(peek_char!=-1){ if (peek_char!=-1) {
ch=peek_char; ch=peek_char;
peek_char=-1; peek_char=-1;
return ch; return ch;
@ -71,15 +72,16 @@ public:
}; };
noecho_input this_window; 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()}; 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()}; return {vm_num,(double)this_window.noecho_kbhit()};
} }
var nas_noblock(var* args,usize size,gc* ngc){ var nas_noblock(var* args,usize size,gc* ngc) {
if(this_window.noecho_kbhit()) if (this_window.noecho_kbhit()) {
return {vm_num,(double)this_window.noecho_getch()}; return {vm_num,(double)this_window.noecho_getch()};
}
return nil; return nil;
} }
@ -90,6 +92,6 @@ mod_func func_tbl[]={
{nullptr,nullptr} {nullptr,nullptr}
}; };
extern "C" mod_func* get(){ extern "C" mod_func* get() {
return func_tbl; return func_tbl;
} }

View File

@ -1,14 +1,14 @@
#include "../nasal.h" #include "../nasal.h"
#include <cmath> #include <cmath>
var nas_vec2(var* args,usize size,gc* ngc){ var nas_vec2(var* args,usize size,gc* ngc) {
var res=ngc->alloc(vm_vec); var res=ngc->alloc(vm_vec);
res.vec().elems.push_back(args[0]); res.vec().elems.push_back(args[0]);
res.vec().elems.push_back(args[1]); res.vec().elems.push_back(args[1]);
return res; 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); var res=ngc->alloc(vm_vec);
res.vec().elems.push_back(args[0]); res.vec().elems.push_back(args[0]);
res.vec().elems.push_back(args[1]); res.vec().elems.push_back(args[1]);
@ -16,12 +16,12 @@ var nas_vec3(var* args,usize size,gc* ngc){
return res; return res;
} }
var nas_vec2_add(var* args,usize size,gc* ngc){ var nas_vec2_add(var* args,usize size,gc* ngc) {
if(args[0].type!=vm_vec || args[1].type!=vm_vec) if (args[0].type!=vm_vec || args[1].type!=vm_vec)
return nil; return nil;
auto& v0=args[0].vec().elems; auto& v0=args[0].vec().elems;
auto& v1=args[1].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 nil;
var res=ngc->alloc(vm_vec); var res=ngc->alloc(vm_vec);
res.vec().elems.push_back({vm_num,v0[0].num()+v1[0].num()}); 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; return res;
} }
var nas_vec2_sub(var* args,usize size,gc* ngc){ var nas_vec2_sub(var* args,usize size,gc* ngc) {
if(args[0].type!=vm_vec || args[1].type!=vm_vec) if (args[0].type!=vm_vec || args[1].type!=vm_vec)
return nil; return nil;
auto& v0=args[0].vec().elems; auto& v0=args[0].vec().elems;
auto& v1=args[1].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 nil;
var res=ngc->alloc(vm_vec); var res=ngc->alloc(vm_vec);
res.vec().elems.push_back({vm_num,v0[0].num()-v1[0].num()}); 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; return res;
} }
var nas_vec2_mult(var* args,usize size,gc* ngc){ var nas_vec2_mult(var* args,usize size,gc* ngc) {
if(args[0].type!=vm_vec || args[1].type!=vm_vec) if (args[0].type!=vm_vec || args[1].type!=vm_vec)
return nil; return nil;
auto& v0=args[0].vec().elems; auto& v0=args[0].vec().elems;
auto& v1=args[1].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 nil;
var res=ngc->alloc(vm_vec); var res=ngc->alloc(vm_vec);
res.vec().elems.push_back({vm_num,v0[0].num()*v1[0].num()}); 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; return res;
} }
var nas_vec2_div(var* args,usize size,gc* ngc){ var nas_vec2_div(var* args,usize size,gc* ngc) {
if(args[0].type!=vm_vec || args[1].type!=vm_vec) if (args[0].type!=vm_vec || args[1].type!=vm_vec)
return nil; return nil;
auto& v0=args[0].vec().elems; auto& v0=args[0].vec().elems;
auto& v1=args[1].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 nil;
var res=ngc->alloc(vm_vec); var res=ngc->alloc(vm_vec);
res.vec().elems.push_back({vm_num,v0[0].num()/v1[0].num()}); 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; return res;
} }
var nas_vec2_neg(var* args,usize size,gc* ngc){ var nas_vec2_neg(var* args,usize size,gc* ngc) {
if(args[0].type!=vm_vec) if (args[0].type!=vm_vec)
return nil; return nil;
auto& v0=args[0].vec().elems; auto& v0=args[0].vec().elems;
if(v0.size()!=2) if (v0.size()!=2)
return nil; return nil;
var res=ngc->alloc(vm_vec); var res=ngc->alloc(vm_vec);
res.vec().elems.push_back({vm_num,-v0[0].num()}); 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; return res;
} }
var nas_vec2_norm(var* args,usize size,gc* ngc){ var nas_vec2_norm(var* args,usize size,gc* ngc) {
if(args[0].type!=vm_vec) if (args[0].type!=vm_vec)
return nil; return nil;
auto& v0=args[0].vec().elems; auto& v0=args[0].vec().elems;
if(v0.size()!=2) if (v0.size()!=2)
return nil; return nil;
auto x=v0[0].num(); auto x=v0[0].num();
auto y=v0[1].num(); auto y=v0[1].num();
@ -95,33 +95,33 @@ var nas_vec2_norm(var* args,usize size,gc* ngc){
return res; return res;
} }
var nas_vec2_len(var* args,usize size,gc* ngc){ var nas_vec2_len(var* args,usize size,gc* ngc) {
if(args[0].type!=vm_vec) if (args[0].type!=vm_vec)
return nil; return nil;
auto& v0=args[0].vec().elems; auto& v0=args[0].vec().elems;
if(v0.size()!=2) if (v0.size()!=2)
return nil; return nil;
auto x=v0[0].num(); auto x=v0[0].num();
auto y=v0[1].num(); auto y=v0[1].num();
return {vm_num,std::sqrt(x*x+y*y)}; return {vm_num,std::sqrt(x*x+y*y)};
} }
var nas_vec2_dot(var* args,usize size,gc* ngc){ var nas_vec2_dot(var* args,usize size,gc* ngc) {
if(args[0].type!=vm_vec || args[1].type!=vm_vec) if (args[0].type!=vm_vec || args[1].type!=vm_vec)
return nil; return nil;
auto& v0=args[0].vec().elems; auto& v0=args[0].vec().elems;
auto& v1=args[1].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 nil;
return {vm_num,v0[0].num()*v1[0].num()+v0[1].num()*v1[1].num()}; 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){ var nas_vec3_add(var* args,usize size,gc* ngc) {
if(args[0].type!=vm_vec || args[1].type!=vm_vec) if (args[0].type!=vm_vec || args[1].type!=vm_vec)
return nil; return nil;
auto& v0=args[0].vec().elems; auto& v0=args[0].vec().elems;
auto& v1=args[1].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 nil;
var res=ngc->alloc(vm_vec); var res=ngc->alloc(vm_vec);
res.vec().elems.push_back({vm_num,v0[0].num()+v1[0].num()}); 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; return res;
} }
var nas_vec3_sub(var* args,usize size,gc* ngc){ var nas_vec3_sub(var* args,usize size,gc* ngc) {
if(args[0].type!=vm_vec || args[1].type!=vm_vec) if (args[0].type!=vm_vec || args[1].type!=vm_vec)
return nil; return nil;
auto& v0=args[0].vec().elems; auto& v0=args[0].vec().elems;
auto& v1=args[1].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 nil;
var res=ngc->alloc(vm_vec); var res=ngc->alloc(vm_vec);
res.vec().elems.push_back({vm_num,v0[0].num()-v1[0].num()}); 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; return res;
} }
var nas_vec3_mult(var* args,usize size,gc* ngc){ var nas_vec3_mult(var* args,usize size,gc* ngc) {
if(args[0].type!=vm_vec || args[1].type!=vm_vec) if (args[0].type!=vm_vec || args[1].type!=vm_vec)
return nil; return nil;
auto& v0=args[0].vec().elems; auto& v0=args[0].vec().elems;
auto& v1=args[1].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 nil;
var res=ngc->alloc(vm_vec); var res=ngc->alloc(vm_vec);
res.vec().elems.push_back({vm_num,v0[0].num()*v1[0].num()}); 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; return res;
} }
var nas_vec3_div(var* args,usize size,gc* ngc){ var nas_vec3_div(var* args,usize size,gc* ngc) {
if(args[0].type!=vm_vec || args[1].type!=vm_vec) if (args[0].type!=vm_vec || args[1].type!=vm_vec)
return nil; return nil;
auto& v0=args[0].vec().elems; auto& v0=args[0].vec().elems;
auto& v1=args[1].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 nil;
var res=ngc->alloc(vm_vec); var res=ngc->alloc(vm_vec);
res.vec().elems.push_back({vm_num,v0[0].num()/v1[0].num()}); 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; return res;
} }
var nas_vec3_neg(var* args,usize size,gc* ngc){ var nas_vec3_neg(var* args,usize size,gc* ngc) {
if(args[0].type!=vm_vec) if (args[0].type!=vm_vec)
return nil; return nil;
auto& v0=args[0].vec().elems; auto& v0=args[0].vec().elems;
if(v0.size()!=3) if (v0.size()!=3)
return nil; return nil;
var res=ngc->alloc(vm_vec); var res=ngc->alloc(vm_vec);
res.vec().elems.push_back({vm_num,-v0[0].num()}); 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; return res;
} }
var nas_vec3_norm(var* args,usize size,gc* ngc){ var nas_vec3_norm(var* args,usize size,gc* ngc) {
if(args[0].type!=vm_vec) if (args[0].type!=vm_vec)
return nil; return nil;
auto& v0=args[0].vec().elems; auto& v0=args[0].vec().elems;
if(v0.size()!=3) if (v0.size()!=3)
return nil; return nil;
auto x=v0[0].num(); auto x=v0[0].num();
auto y=v0[1].num(); auto y=v0[1].num();
@ -202,11 +202,11 @@ var nas_vec3_norm(var* args,usize size,gc* ngc){
return res; return res;
} }
var nas_vec3_len(var* args,usize size,gc* ngc){ var nas_vec3_len(var* args,usize size,gc* ngc) {
if(args[0].type!=vm_vec) if (args[0].type!=vm_vec)
return nil; return nil;
auto& v0=args[0].vec().elems; auto& v0=args[0].vec().elems;
if(v0.size()!=3) if (v0.size()!=3)
return nil; return nil;
auto x=v0[0].num(); auto x=v0[0].num();
auto y=v0[1].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)}; return {vm_num,std::sqrt(x*x+y*y+z*z)};
} }
var nas_rotate_x(var* args,usize size,gc* ngc){ var nas_rotate_x(var* args,usize size,gc* ngc) {
if(args[0].type!=vm_vec) if (args[0].type!=vm_vec)
return nil; return nil;
auto& v0=args[0].vec().elems; auto& v0=args[0].vec().elems;
if(v0.size()!=3) if (v0.size()!=3)
return nil; return nil;
auto angle=args[1].num(); auto angle=args[1].num();
var res=ngc->alloc(vm_vec); var res=ngc->alloc(vm_vec);
@ -228,11 +228,11 @@ var nas_rotate_x(var* args,usize size,gc* ngc){
return res; return res;
} }
var nas_rotate_y(var* args,usize size,gc* ngc){ var nas_rotate_y(var* args,usize size,gc* ngc) {
if(args[0].type!=vm_vec) if (args[0].type!=vm_vec)
return nil; return nil;
auto& v0=args[0].vec().elems; auto& v0=args[0].vec().elems;
if(v0.size()!=3) if (v0.size()!=3)
return nil; return nil;
auto angle=args[1].num(); auto angle=args[1].num();
var res=ngc->alloc(vm_vec); var res=ngc->alloc(vm_vec);
@ -242,11 +242,11 @@ var nas_rotate_y(var* args,usize size,gc* ngc){
return res; return res;
} }
var nas_rotate_z(var* args,usize size,gc* ngc){ var nas_rotate_z(var* args,usize size,gc* ngc) {
if(args[0].type!=vm_vec) if (args[0].type!=vm_vec)
return nil; return nil;
auto& v0=args[0].vec().elems; auto& v0=args[0].vec().elems;
if(v0.size()!=3) if (v0.size()!=3)
return nil; return nil;
auto angle=args[1].num(); auto angle=args[1].num();
var res=ngc->alloc(vm_vec); var res=ngc->alloc(vm_vec);
@ -256,12 +256,12 @@ var nas_rotate_z(var* args,usize size,gc* ngc){
return res; return res;
} }
var nas_vec3_dot(var* args,usize size,gc* ngc){ var nas_vec3_dot(var* args,usize size,gc* ngc) {
if(args[0].type!=vm_vec || args[1].type!=vm_vec) if (args[0].type!=vm_vec || args[1].type!=vm_vec)
return nil; return nil;
auto& v0=args[0].vec().elems; auto& v0=args[0].vec().elems;
auto& v1=args[1].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 nil;
return {vm_num,v0[0].num()*v1[0].num()+v0[1].num()*v1[1].num()+v0[2].num()*v1[2].num()}; 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} {nullptr,nullptr}
}; };
extern "C" mod_func* get(){ extern "C" mod_func* get() {
return func_tbl; return func_tbl;
} }

View File

@ -9,10 +9,10 @@ class WSAmanager{
private: private:
WSAData data; WSAData data;
public: public:
WSAmanager(){ WSAmanager() {
WSAStartup(0x1010,&data); WSAStartup(0x1010,&data);
} }
~WSAmanager(){ ~WSAmanager() {
WSACleanup(); WSACleanup();
} }
}; };
@ -25,15 +25,15 @@ static WSAmanager win;
#include <netinet/in.h> #include <netinet/in.h>
#endif #endif
var nas_socket(var* args,usize size,gc* ngc){ 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) 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"); return nas_err("socket","\"af\", \"type\", \"protocol\" should be number");
int sd=socket(args[0].num(),args[1].num(),args[2].num()); int sd=socket(args[0].num(),args[1].num(),args[2].num());
return {vm_num,(double)sd}; return {vm_num,(double)sd};
} }
var nas_closesocket(var* args,usize size,gc* ngc){ var nas_closesocket(var* args,usize size,gc* ngc) {
if(args[0].type!=vm_num) if (args[0].type!=vm_num)
return nas_err("closesocket","\"\" should be number"); return nas_err("closesocket","\"\" should be number");
#ifdef _WIN32 #ifdef _WIN32
return {vm_num,(double)closesocket(args[0].num())}; return {vm_num,(double)closesocket(args[0].num())};
@ -42,20 +42,20 @@ var nas_closesocket(var* args,usize size,gc* ngc){
#endif #endif
} }
var nas_shutdown(var* args,usize size,gc* ngc){ var nas_shutdown(var* args,usize size,gc* ngc) {
if(args[0].type!=vm_num) if (args[0].type!=vm_num)
return nas_err("shutdown","\"sd\" must be a number"); 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 nas_err("shutdown","\"how\" must be a number");
return {vm_num,(double)shutdown(args[0].num(),args[1].num())}; return {vm_num,(double)shutdown(args[0].num(),args[1].num())};
} }
var nas_bind(var* args,usize size,gc* ngc){ var nas_bind(var* args,usize size,gc* ngc) {
if(args[0].type!=vm_num) if (args[0].type!=vm_num)
return nas_err("bind","\"sd\" muse be a number"); 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"); 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"); return nas_err("bind","\"port\" must be a number");
sockaddr_in server; sockaddr_in server;
memset(&server,0,sizeof(sockaddr_in)); 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))}; return {vm_num,(double)bind(args[0].num(),(sockaddr*)&server,sizeof(server))};
} }
var nas_listen(var* args,usize size,gc* ngc){ var nas_listen(var* args,usize size,gc* ngc) {
if(args[0].type!=vm_num) if (args[0].type!=vm_num)
return nas_err("listen","\"sd\" must be a number"); 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 nas_err("listen","\"backlog\" must be a number");
return{vm_num,(double)listen(args[0].num(),args[1].num())}; return{vm_num,(double)listen(args[0].num(),args[1].num())};
} }
var nas_connect(var* args,usize size,gc* ngc){ var nas_connect(var* args,usize size,gc* ngc) {
if(args[0].type!=vm_num) if (args[0].type!=vm_num)
return nas_err("connect","\"sd\" must be a number"); 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"); 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"); return nas_err("connect","\"port\" must be a number");
sockaddr_in addr; sockaddr_in addr;
memset(&addr,0,sizeof(sockaddr_in)); 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))}; return {vm_num,(double)connect(args[0].num(),(sockaddr*)&addr,sizeof(sockaddr_in))};
} }
var nas_accept(var* args,usize size,gc* ngc){ var nas_accept(var* args,usize size,gc* ngc) {
if(args[0].type!=vm_num) if (args[0].type!=vm_num)
return nas_err("accept","\"sd\" must be a number"); return nas_err("accept","\"sd\" must be a number");
sockaddr_in client; sockaddr_in client;
int socklen=sizeof(sockaddr_in); int socklen=sizeof(sockaddr_in);
@ -107,26 +107,26 @@ var nas_accept(var* args,usize size,gc* ngc){
return res; return res;
} }
var nas_send(var* args,usize size,gc* ngc){ var nas_send(var* args,usize size,gc* ngc) {
if(args[0].type!=vm_num) if (args[0].type!=vm_num)
return nas_err("send","\"sd\" must be a number"); 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"); 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 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())}; 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){ var nas_sendto(var* args,usize size,gc* ngc) {
if(args[0].type!=vm_num) if (args[0].type!=vm_num)
return nas_err("sendto","\"sd\" must be a number"); 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"); 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"); 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"); 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"); return nas_err("sendto","\"flags\" must be a number");
sockaddr_in addr; sockaddr_in addr;
memset(&addr,0,sizeof(sockaddr_in)); 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))}; 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){ var nas_recv(var* args,usize size,gc* ngc) {
if(args[0].type!=vm_num) if (args[0].type!=vm_num)
return nas_err("recv","\"sd\" must be a number"); 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"); 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"); 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"); return nas_err("recv","\"flags\" muse be a number");
var res=ngc->temp=ngc->alloc(vm_hash); var res=ngc->temp=ngc->alloc(vm_hash);
auto& hash=res.hash().elems; auto& hash=res.hash().elems;
@ -156,14 +156,14 @@ var nas_recv(var* args,usize size,gc* ngc){
return res; return res;
} }
var nas_recvfrom(var* args,usize size,gc* ngc){ var nas_recvfrom(var* args,usize size,gc* ngc) {
if(args[0].type!=vm_num) if (args[0].type!=vm_num)
return nas_err("recvfrom","\"sd\" must be a number"); 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"); 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"); 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"); return nas_err("recvfrom","\"flags\" muse be a number");
sockaddr_in addr; sockaddr_in addr;
int socklen=sizeof(sockaddr_in); int socklen=sizeof(sockaddr_in);
@ -183,7 +183,7 @@ var nas_recvfrom(var* args,usize size,gc* ngc){
return res; 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)); return ngc->newstr(strerror(errno));
} }
@ -203,6 +203,6 @@ mod_func func_tbl[]={
{nullptr,nullptr} {nullptr,nullptr}
}; };
extern "C" mod_func* get(){ extern "C" mod_func* get() {
return func_tbl; return func_tbl;
} }

119
nasal.h
View File

@ -23,115 +23,131 @@ using std::string;
const u32 STACK_DEPTH=1024; const u32 STACK_DEPTH=1024;
inline f64 hex2f(const char* str) inline f64 hex2f(const char* str) {
{
f64 ret=0; f64 ret=0;
for(;*str;++str) for(;*str;++str) {
{ if ('0'<=*str && *str<='9') {
if('0'<=*str && *str<='9')
ret=ret*16+(*str-'0'); ret=ret*16+(*str-'0');
else if('a'<=*str && *str<='f') } else if ('a'<=*str && *str<='f') {
ret=ret*16+(*str-'a'+10); ret=ret*16+(*str-'a'+10);
else if('A'<=*str && *str<='F') } else if ('A'<=*str && *str<='F') {
ret=ret*16+(*str-'A'+10); ret=ret*16+(*str-'A'+10);
else } else {
return nan(""); return nan("");
}
} }
return ret; return ret;
} }
inline f64 oct2f(const char* str)
{ inline f64 oct2f(const char* str) {
f64 ret=0; f64 ret=0;
while('0'<=*str && *str<'8') while('0'<=*str && *str<'8') {
ret=ret*8+(*str++-'0'); ret=ret*8+(*str++-'0');
if(*str) return nan(""); }
if (*str) {
return nan("");
}
return ret; return ret;
} }
// we have the same reason not using atof here just as andy's interpreter does. // 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. // it is not platform independent, and may have strange output.
// so we write a new function here to convert str to number manually. // 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. // 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; f64 ret=0,negative=1,num_pow=0;
while('0'<=*str && *str<='9') while('0'<=*str && *str<='9') {
ret=ret*10+(*str++-'0'); ret=ret*10+(*str++-'0');
if(!*str) return ret; }
if(*str=='.') if (!*str) {
{ return ret;
if(!*++str) return nan(""); }
if (*str=='.') {
if (!*++str) {
return nan("");
}
num_pow=0.1; num_pow=0.1;
while('0'<=*str && *str<='9') while('0'<=*str && *str<='9') {
{
ret+=num_pow*(*str++-'0'); ret+=num_pow*(*str++-'0');
num_pow*=0.1; num_pow*=0.1;
} }
if(!*str) return ret; if (!*str) {
return ret;
}
} }
if(*str!='e' && *str!='E') if (*str!='e' && *str!='E') {
return nan(""); return nan("");
if(!*++str) return nan(""); }
if(*str=='-' || *str=='+') if (!*++str) {
return nan("");
}
if (*str=='-' || *str=='+') {
negative=(*str++=='-'? -1:1); negative=(*str++=='-'? -1:1);
if(!*str) return nan(""); }
if (!*str) {
return nan("");
}
num_pow=0; num_pow=0;
while('0'<=*str && *str<='9') while('0'<=*str && *str<='9') {
num_pow=num_pow*10+(*str++-'0'); num_pow=num_pow*10+(*str++-'0');
if(*str) return nan(""); }
if (*str) {
return nan("");
}
return ret*std::pow(10,negative*num_pow); return ret*std::pow(10,negative*num_pow);
} }
f64 str2num(const char* str)
{ f64 str2num(const char* str) {
bool negative=false; bool negative=false;
f64 res=0; f64 res=0;
if(*str=='-' || *str=='+') if (*str=='-' || *str=='+') {
negative=(*str++=='-'); negative=(*str++=='-');
if(!*str) }
if (!*str) {
return nan(""); return nan("");
if(str[0]=='0' && str[1]=='x') }
if (str[0]=='0' && str[1]=='x') {
res=hex2f(str+2); res=hex2f(str+2);
else if(str[0]=='0' && str[1]=='o') } else if (str[0]=='0' && str[1]=='o') {
res=oct2f(str+2); res=oct2f(str+2);
else } else {
res=dec2f(str); res=dec2f(str);
}
return negative?-res:res; 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 // RFC-2279 but now we use RFC-3629 so nbytes is less than 4
const u8 c=(u8)head; 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; return 1;
if((c>>4)==0x0e) // 1110 xxxx (10xx xxxx)^2 }
if ((c>>4)==0x0e) { // 1110 xxxx (10xx xxxx)^2
return 2; return 2;
if((c>>3)==0x1e) // 1111 0xxx (10xx xxxx)^3 }
if ((c>>3)==0x1e) { // 1111 0xxx (10xx xxxx)^3
return 3; return 3;
}
return 0; return 0;
} }
string chrhex(const char c) string chrhex(const char c) {
{
const char hextbl[]="0123456789abcdef"; const char hextbl[]="0123456789abcdef";
return {hextbl[(c&0xf0)>>4],hextbl[c&0x0f]}; 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(""); string ret("");
for(auto i:str) for(auto i:str) {
{
#ifdef _WIN32 #ifdef _WIN32
// windows ps or cmd doesn't output unicode normally // windows ps or cmd doesn't output unicode normally
// if 'chcp65001' is not enabled, we output the hex // if 'chcp65001' is not enabled, we output the hex
if(i<=0) if (i<=0) {
{
ret+="\\x"+chrhex(i); ret+="\\x"+chrhex(i);
continue; continue;
} }
#endif #endif
switch(i) switch(i) {
{
case '\0': ret+="\\0"; break; case '\0': ret+="\\0"; break;
case '\a': ret+="\\a"; break; case '\a': ret+="\\a"; break;
case '\b': ret+="\\b"; break; case '\b': ret+="\\b"; break;
@ -147,8 +163,9 @@ string rawstr(const string& str,const usize maxlen=0)
default: ret+=i; break; default: ret+=i; break;
} }
} }
if(maxlen && ret.length()>maxlen) if (maxlen && ret.length()>maxlen) {
ret=ret.substr(0,maxlen)+"..."; ret=ret.substr(0,maxlen)+"...";
}
return ret; return ret;
} }

View File

@ -3,7 +3,7 @@
#include <vector> #include <vector>
#include <cstring> #include <cstring>
enum ast_node:u32{ enum ast_node:u32 {
ast_null=0, // null node ast_null=0, // null node
ast_root, // mark the root node of ast ast_root, // mark the root node of ast
ast_block, // expression block ast_block, // expression block
@ -125,8 +125,7 @@ const char* ast_name[]={
"ReturnExpression" "ReturnExpression"
}; };
class ast class ast {
{
private: private:
u32 nd_line; u32 nd_line;
u32 nd_col; u32 nd_col;
@ -135,8 +134,8 @@ private:
string nd_str; string nd_str;
std::vector<ast> nd_child; std::vector<ast> nd_child;
public: public:
ast(const u32 l,const u32 c,const u32 t): ast(const u32 l,const u32 c,const u32 t)
nd_line(l),nd_col(c),nd_type(t),nd_num(0){} : nd_line(l),nd_col(c),nd_type(t),nd_num(0) {}
ast(const ast&); ast(const ast&);
ast(ast&&); ast(ast&&);
void dump() const; void dump() const;
@ -145,16 +144,16 @@ public:
ast& operator=(const ast&); ast& operator=(const ast&);
ast& operator=(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];} const ast& operator[](usize n) const {return nd_child[n];}
usize size() const {return nd_child.size();} usize size() const {return nd_child.size();}
void add(ast&& node){nd_child.push_back(std::move(node));} void add(ast&& node) {nd_child.push_back(std::move(node));}
void add(const ast& node){nd_child.push_back(node);} void add(const ast& node) {nd_child.push_back(node);}
void set_line(const u32 l){nd_line=l;} void set_line(const u32 l) {nd_line=l;}
void set_type(const u32 t){nd_type=t;} void set_type(const u32 t) {nd_type=t;}
void set_str(const string& s){nd_str=s;} void set_str(const string& s) {nd_str=s;}
void set_num(const f64 n){nd_num=n;} void set_num(const f64 n) {nd_num=n;}
inline u32 line() const {return nd_line;} inline u32 line() const {return nd_line;}
inline u32 col() const {return nd_col;} inline u32 col() const {return nd_col;}
@ -162,20 +161,18 @@ public:
inline f64 num() const {return nd_num;} inline f64 num() const {return nd_num;}
inline const string& str() const {return nd_str;} inline const string& str() const {return nd_str;}
inline const std::vector<ast>& child() const {return nd_child;} inline const std::vector<ast>& child() const {return nd_child;}
inline std::vector<ast>& child(){return nd_child;} inline std::vector<ast>& child() {return nd_child;}
}; };
ast::ast(const ast& tmp): 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_line=tmp.nd_line;
nd_col=tmp.nd_col; nd_col=tmp.nd_col;
nd_type=tmp.nd_type; nd_type=tmp.nd_type;
nd_num =tmp.nd_num; nd_num =tmp.nd_num;
} }
ast::ast(ast&& tmp) ast::ast(ast&& tmp) {
{
nd_line=tmp.nd_line; nd_line=tmp.nd_line;
nd_col=tmp.nd_col; nd_col=tmp.nd_col;
nd_type=tmp.nd_type; nd_type=tmp.nd_type;
@ -184,8 +181,7 @@ ast::ast(ast&& tmp)
nd_child.swap(tmp.nd_child); nd_child.swap(tmp.nd_child);
} }
ast& ast::operator=(const ast& tmp) ast& ast::operator=(const ast& tmp) {
{
nd_line=tmp.nd_line; nd_line=tmp.nd_line;
nd_col=tmp.nd_col; nd_col=tmp.nd_col;
nd_type=tmp.nd_type; nd_type=tmp.nd_type;
@ -195,8 +191,7 @@ ast& ast::operator=(const ast& tmp)
return *this; return *this;
} }
ast& ast::operator=(ast&& tmp) ast& ast::operator=(ast&& tmp) {
{
nd_line=tmp.nd_line; nd_line=tmp.nd_line;
nd_col=tmp.nd_col; nd_col=tmp.nd_col;
nd_type=tmp.nd_type; nd_type=tmp.nd_type;
@ -206,8 +201,7 @@ ast& ast::operator=(ast&& tmp)
return *this; return *this;
} }
void ast::clear() void ast::clear() {
{
nd_line=nd_col=0; nd_line=nd_col=0;
nd_num=0; nd_num=0;
nd_str.clear(); nd_str.clear();
@ -215,34 +209,36 @@ void ast::clear()
nd_child.clear(); nd_child.clear();
} }
void ast::dump() const void ast::dump() const{
{
std::vector<string> tmp; std::vector<string> tmp;
print(0,false,tmp); print(0,false,tmp);
} }
void ast::print(u32 depth,bool last,std::vector<string>& indent) const void ast::print(u32 depth,bool last,std::vector<string>& indent) const{
{ for(auto& i:indent) {
for(auto& i:indent)
std::cout<<i; std::cout<<i;
}
std::cout<<ast_name[nd_type]; std::cout<<ast_name[nd_type];
if(nd_type==ast_str || nd_type==ast_id || if (nd_type==ast_str ||
nd_type==ast_default || nd_type==ast_dynamic || nd_type==ast_id ||
nd_type==ast_callh) nd_type==ast_default ||
nd_type==ast_dynamic ||
nd_type==ast_callh) {
std::cout<<":"<<rawstr(nd_str); std::cout<<":"<<rawstr(nd_str);
else if(nd_type==ast_num || nd_type==ast_file) } else if (nd_type==ast_num || nd_type==ast_file) {
std::cout<<":"<<nd_num; std::cout<<":"<<nd_num;
}
std::cout<<" -> "<<nd_line<<":"<<nd_col<<"\n"; std::cout<<" -> "<<nd_line<<":"<<nd_col<<"\n";
if(last && depth) if (last && depth) {
indent.back()=" "; indent.back()=" ";
else if(!last && depth) } else if (!last && depth) {
#ifdef _WIN32 #ifdef _WIN32
indent.back()="| "; indent.back()="| ";
#else #else
indent.back()=""; indent.back()="";
#endif #endif
for(u32 i=0;i<nd_child.size();++i) }
{ for(u32 i=0;i<nd_child.size();++i) {
#ifdef _WIN32 #ifdef _WIN32
indent.push_back(i==nd_child.size()-1?"+-":"|-"); indent.push_back(i==nd_child.size()-1?"+-":"|-");
#else #else

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -4,8 +4,7 @@
#include "nasal_vm.h" #include "nasal_vm.h"
#include <algorithm> #include <algorithm>
class debugger:public vm class debugger:public vm {
{
private: private:
bool next; bool next;
usize fsize; usize fsize;
@ -24,7 +23,7 @@ public:
debugger(error& err): debugger(error& err):
next(false),fsize(0), next(false),fsize(0),
bk_fidx(0),bk_line(0), bk_fidx(0),bk_line(0),
src(err){} src(err) {}
void run( void run(
const codegen&, const codegen&,
const linker&, const linker&,
@ -32,39 +31,38 @@ public:
); );
}; };
std::vector<string> debugger::parse(const string& cmd) std::vector<string> debugger::parse(const string& cmd) {
{
std::vector<string> res; std::vector<string> res;
usize last=0,pos=cmd.find(" ",0); usize last=0,pos=cmd.find(" ",0);
while(pos!=string::npos) while(pos!=string::npos) {
{ if (pos>last) {
if(pos>last)
res.push_back(cmd.substr(last,pos-last)); res.push_back(cmd.substr(last,pos-last));
}
last=pos+1; last=pos+1;
pos=cmd.find(" ",last); pos=cmd.find(" ",last);
} }
if(last<cmd.length()) if (last<cmd.length()) {
res.push_back(cmd.substr(last)); res.push_back(cmd.substr(last));
}
return res; return res;
} }
u16 debugger::fileindex(const string& filename) u16 debugger::fileindex(const string& filename) {
{ for(u16 i=0;i<fsize;++i) {
for(u16 i=0;i<fsize;++i) if (filename==files[i]) {
if(filename==files[i])
return i; return i;
}
}
return 65535; return 65535;
} }
void debugger::err() void debugger::err() {
{
std::cerr std::cerr
<<"incorrect command\n" <<"incorrect command\n"
<<"input \'h\' to get help\n"; <<"input \'h\' to get help\n";
} }
void debugger::help() void debugger::help() {
{
std::cout std::cout
<<"<option>\n" <<"<option>\n"
<<"\th, help | get help\n" <<"\th, help | get help\n"
@ -82,123 +80,118 @@ void debugger::help()
<<"\tbk, break | set break point\n"; <<"\tbk, break | set break point\n";
} }
void debugger::callsort(const u64* arr) void debugger::callsort(const u64* arr) {
{
typedef std::pair<u32,u64> op; typedef std::pair<u32,u64> op;
std::vector<op> opcall; std::vector<op> opcall;
u64 total=0; u64 total=0;
for(u32 i=0;i<op_ret+1;++i) for(u32 i=0;i<op_ret+1;++i) {
{
total+=arr[i]; total+=arr[i];
opcall.push_back({i,arr[i]}); opcall.push_back({i,arr[i]});
} }
std::sort(opcall.begin(),opcall.end(), std::sort(opcall.begin(),opcall.end(),
[](const op& a,const op& b){return a.second>b.second;} [](const op& a,const op& b) {return a.second>b.second;}
); );
std::clog<<"\noperands call info (<1% ignored)\n"; std::clog<<"\noperands call info (<1% ignored)\n";
for(auto& i:opcall) for(auto& i:opcall) {
{
u64 rate=i.second*100/total; u64 rate=i.second*100/total;
if(!rate) if (!rate) {
break; break;
}
std::clog<<" "<<opname[i.first]<<" : "<<i.second<<" ("<<rate<<"%)\n"; std::clog<<" "<<opname[i.first]<<" : "<<i.second<<" ("<<rate<<"%)\n";
} }
std::clog<<" total : "<<total<<'\n'; std::clog<<" total : "<<total<<'\n';
} }
void debugger::stepinfo() void debugger::stepinfo() {
{
u32 line=bytecode[pc].line==0?0:bytecode[pc].line-1; u32 line=bytecode[pc].line==0?0:bytecode[pc].line-1;
u32 begin=(line>>3)==0?0:((line>>3)<<3); u32 begin=(line>>3)==0?0:((line>>3)<<3);
u32 end=(1+(line>>3))<<3; u32 end=(1+(line>>3))<<3;
src.load(files[bytecode[pc].fidx]); src.load(files[bytecode[pc].fidx]);
std::cout<<"\nsource code:\n"; std::cout<<"\nsource code:\n";
for(u32 i=begin;i<end && i<src.size();++i) for(u32 i=begin;i<end && i<src.size();++i) {
std::cout<<(i==line?back_white:reset)<<(i==line?"--> ":" ")<<src[i]<<reset<<"\n"; std::cout<<(i==line?back_white:reset)<<(i==line?"--> ":" ")<<src[i]<<reset<<"\n";
}
std::cout<<"next bytecode:\n"; std::cout<<"next bytecode:\n";
begin=(pc>>3)==0?0:((pc>>3)<<3); begin=(pc>>3)==0?0:((pc>>3)<<3);
end=(1+(pc>>3))<<3; end=(1+(pc>>3))<<3;
for(u32 i=begin;i<end && bytecode[i].op!=op_exit;++i) for(u32 i=begin;i<end && bytecode[i].op!=op_exit;++i) {
std::cout std::cout
<<(i==pc?back_white:reset)<<(i==pc?"--> ":" ") <<(i==pc?back_white:reset)<<(i==pc?"--> ":" ")
<<codestream(bytecode[i],i,cnum,cstr,files) <<codestream(bytecode[i],i,cnum,cstr,files)
<<reset<<"\n"; <<reset<<"\n";
}
stackinfo(10); stackinfo(10);
} }
void debugger::interact() void debugger::interact() {
{
// special operand // special operand
if(bytecode[pc].op==op_intg) if (bytecode[pc].op==op_intg) {
{
std::cout std::cout
<<cyan<<"[debug] "<<reset <<cyan<<"[debug] "<<reset
<<"nasal debug mode\n" <<"nasal debug mode\n"
<<"input \'h\' to get help\n"; <<"input \'h\' to get help\n";
} } else if (bytecode[pc].op==op_exit) {
else if(bytecode[pc].op==op_exit)
return; return;
}
if( if (
(bytecode[pc].fidx!=bk_fidx || bytecode[pc].line!=bk_line) && // break point (bytecode[pc].fidx!=bk_fidx || bytecode[pc].line!=bk_line) && // break point
!next // next step !next // next step
)return; ) {
return;
}
next=false; next=false;
string cmd; string cmd;
stepinfo(); stepinfo();
while(1) while(1) {
{
std::cout<<">> "; std::cout<<">> ";
std::getline(std::cin,cmd); std::getline(std::cin,cmd);
auto res=parse(cmd); auto res=parse(cmd);
if(res.size()==1) if (res.size()==1) {
{ if (res[0]=="h" || res[0]=="help") {
if(res[0]=="h" || res[0]=="help")
help(); help();
else if(res[0]=="bt" || res[0]=="backtrace") } else if (res[0]=="bt" || res[0]=="backtrace") {
traceback(); traceback();
else if(res[0]=="c" || res[0]=="continue") } else if (res[0]=="c" || res[0]=="continue") {
return; return;
else if(res[0]=="f" || res[0]=="file") } else if (res[0]=="f" || res[0]=="file") {
for(usize i=0;i<fsize;++i) for(usize i=0;i<fsize;++i) {
std::cout<<"["<<i<<"] "<<files[i]<<"\n"; std::cout<<"["<<i<<"] "<<files[i]<<"\n";
else if(res[0]=="g" || res[0]=="global") }
} else if (res[0]=="g" || res[0]=="global") {
gstate(); gstate();
else if(res[0]=="l" || res[0]=="local") } else if (res[0]=="l" || res[0]=="local") {
lstate(); lstate();
else if(res[0]=="u" || res[0]=="upval") } else if (res[0]=="u" || res[0]=="upval") {
ustate(); ustate();
else if(res[0]=="r" || res[0]=="register") } else if (res[0]=="r" || res[0]=="register") {
reginfo(); reginfo();
else if(res[0]=="a" || res[0]=="all") } else if (res[0]=="a" || res[0]=="all") {
detail(); detail();
else if(res[0]=="n" || res[0]=="next") } else if (res[0]=="n" || res[0]=="next") {
{
next=true; next=true;
return; return;
} } else if (res[0]=="q" || res[0]=="exit")
else if(res[0]=="q" || res[0]=="exit")
std::exit(0); std::exit(0);
else else {
err(); err();
} }
else if(res.size()==3 && (res[0]=="bk" || res[0]=="break")) } else if (res.size()==3 && (res[0]=="bk" || res[0]=="break")) {
{
bk_fidx=fileindex(res[1]); bk_fidx=fileindex(res[1]);
if(bk_fidx==65535) if (bk_fidx==65535) {
{
std::cout<<"cannot find file named `"<<res[1]<<"`\n"; std::cout<<"cannot find file named `"<<res[1]<<"`\n";
bk_fidx=0; bk_fidx=0;
} }
i32 tmp=atoi(res[2].c_str()); i32 tmp=atoi(res[2].c_str());
if(tmp<=0) if (tmp<=0) {
std::cout<<"incorrect line number `"<<res[2]<<"`\n"; std::cout<<"incorrect line number `"<<res[2]<<"`\n";
else } else {
bk_line=tmp; bk_line=tmp;
} }
else } else {
err(); err();
}
} }
} }
@ -212,8 +205,7 @@ void debugger::run(
init(gen.strs(),gen.nums(),gen.codes(),linker.filelist(),argv); init(gen.strs(),gen.nums(),gen.codes(),linker.filelist(),argv);
u64 count[op_ret+1]={0}; u64 count[op_ret+1]={0};
#ifndef _MSC_VER #ifndef _MSC_VER
const void* oprs[]= const void* oprs[]={
{
&&vmexit, &&intg, &&intl, &&loadg, &&vmexit, &&intg, &&intl, &&loadg,
&&loadl, &&loadu, &&pnum, &&pnil, &&loadl, &&loadu, &&pnum, &&pnil,
&&pstr, &&newv, &&newh, &&newf, &&pstr, &&newv, &&newh, &&newf,
@ -235,8 +227,7 @@ void debugger::run(
&&mcallv, &&mcallh, &&ret &&mcallv, &&mcallh, &&ret
}; };
std::vector<const void*> code; std::vector<const void*> code;
for(auto& i:gen.codes()) for(auto& i:gen.codes()) {
{
code.push_back(oprs[i.op]); code.push_back(oprs[i.op]);
imm.push_back(i.num); imm.push_back(i.num);
} }
@ -244,8 +235,7 @@ void debugger::run(
goto *code[pc]; goto *code[pc];
#else #else
typedef void (debugger::*nafunc)(); typedef void (debugger::*nafunc)();
const nafunc oprs[]= const nafunc oprs[]={
{
nullptr, &debugger::o_intg, nullptr, &debugger::o_intg,
&debugger::o_intl, &debugger::o_loadg, &debugger::o_intl, &debugger::o_loadg,
&debugger::o_loadl, &debugger::o_loadu, &debugger::o_loadl, &debugger::o_loadu,
@ -286,17 +276,17 @@ void debugger::run(
&debugger::o_ret &debugger::o_ret
}; };
std::vector<u32> code; std::vector<u32> code;
for(auto& i:gen.codes()) for(auto& i:gen.codes()) {
{
code.push_back(i.op); code.push_back(i.op);
imm.push_back(i.num); imm.push_back(i.num);
} }
while(oprs[code[pc]]){ while(oprs[code[pc]]) {
interact(); interact();
++count[code[pc]]; ++count[code[pc]];
(this->*oprs[code[pc]])(); (this->*oprs[code[pc]])();
if(top>=canary) if (top>=canary) {
die("stack overflow"); die("stack overflow");
}
++pc; ++pc;
} }
#endif #endif
@ -312,8 +302,9 @@ vmexit:
interact();\ interact();\
op();\ op();\
++count[num];\ ++count[num];\
if(top<canary)\ if (top<canary) {\
goto *code[++pc];\ goto *code[++pc];\
}\
die("stack overflow");\ die("stack overflow");\
goto *code[++pc];\ goto *code[++pc];\
} }

View File

@ -7,17 +7,15 @@
#ifdef _WIN32 #ifdef _WIN32
#include <windows.h> // use SetConsoleTextAttribute #include <windows.h> // use SetConsoleTextAttribute
struct for_reset struct for_reset {
{
CONSOLE_SCREEN_BUFFER_INFO scr; CONSOLE_SCREEN_BUFFER_INFO scr;
for_reset(){ for_reset() {
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE),&scr); GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE),&scr);
} }
}reset_ter_color; } reset_ter_color;
#endif #endif
std::ostream& back_white(std::ostream& s) std::ostream& back_white(std::ostream& s) {
{
#ifdef _WIN32 #ifdef _WIN32
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0xf0); SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0xf0);
#else #else
@ -25,8 +23,8 @@ std::ostream& back_white(std::ostream& s)
#endif #endif
return s; return s;
} }
std::ostream& red(std::ostream& s)
{ std::ostream& red(std::ostream& s) {
#ifdef _WIN32 #ifdef _WIN32
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0x0c); SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0x0c);
#else #else
@ -34,8 +32,8 @@ std::ostream& red(std::ostream& s)
#endif #endif
return s; return s;
} }
std::ostream& cyan(std::ostream& s)
{ std::ostream& cyan(std::ostream& s) {
#ifdef _WIN32 #ifdef _WIN32
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0x03); SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0x03);
#else #else
@ -43,8 +41,8 @@ std::ostream& cyan(std::ostream& s)
#endif #endif
return s; return s;
} }
std::ostream& orange(std::ostream& s)
{ std::ostream& orange(std::ostream& s) {
#ifdef _WIN32 #ifdef _WIN32
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0x0e); SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0x0e);
#else #else
@ -52,8 +50,8 @@ std::ostream& orange(std::ostream& s)
#endif #endif
return s; return s;
} }
std::ostream& white(std::ostream& s)
{ std::ostream& white(std::ostream& s) {
#ifdef _WIN32 #ifdef _WIN32
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0x0f); SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0x0f);
#else #else
@ -61,8 +59,8 @@ std::ostream& white(std::ostream& s)
#endif #endif
return s; return s;
} }
std::ostream& reset(std::ostream& s)
{ std::ostream& reset(std::ostream& s) {
#ifdef _WIN32 #ifdef _WIN32
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),reset_ter_color.scr.wAttributes); SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),reset_ter_color.scr.wAttributes);
#else #else
@ -71,29 +69,27 @@ std::ostream& reset(std::ostream& s)
return s; return s;
} }
class flstream class flstream {
{
protected: protected:
string file; string file;
std::vector<string> res; std::vector<string> res;
public: public:
flstream():file("<error-file-path>"){} flstream():file("") {}
void load(const string& f) void load(const string& f) {
{ if (file==f) { // don't need to load a loaded file
if(file==f){ // don't need to load a loaded file
return; return;
}else{ } else {
file=f; file=f;
} }
res.clear(); res.clear();
std::ifstream in(f,std::ios::binary); std::ifstream in(f,std::ios::binary);
if(in.fail()){ if (in.fail()) {
std::cerr<<red<<"src: "<<reset<<"cannot open <"<<f<<">\n"; std::cerr<<red<<"src: "<<reset<<"cannot open <"<<f<<">\n";
std::exit(1); std::exit(1);
} }
while(!in.eof()){ while(!in.eof()) {
string line; string line;
std::getline(in,line); std::getline(in,line);
res.push_back(line); res.push_back(line);
@ -104,34 +100,35 @@ public:
usize size() const {return res.size();} usize size() const {return res.size();}
}; };
class error:public flstream class error:public flstream {
{
private: private:
u32 cnt; u32 cnt;
string identation(usize len) string identation(usize len) {
{
string tmp=""; string tmp="";
tmp.resize(len,' '); tmp.resize(len,' ');
return tmp; return tmp;
} }
public: public:
error():cnt(0){} error():cnt(0) {}
void fatal(const string& stage,const string& info) void fatal(const string& stage,const string& info) {
{ std::cerr<<red<<stage<<": "<<white<<info<<reset<<"\n";
std::cerr if (file.length()) {
<<red<<stage<<": "<<white<<info<<reset<<"\n" std::cerr<<cyan<<" --> "<<red<<file<<"\n\n";
<<cyan<<" --> "<<red<<file<<"\n\n"; } else {
std::cerr<<"\n";
}
std::exit(1); std::exit(1);
} }
void err(const string& stage,const string& info) void err(const string& stage,const string& info) {
{
++cnt; ++cnt;
std::cerr std::cerr<<red<<stage<<": "<<white<<info<<reset<<"\n";
<<red<<stage<<": "<<white<<info<<reset<<"\n" if (file.length()) {
<<cyan<<" --> "<<red<<file<<reset<<"\n\n"; std::cerr<<cyan<<" --> "<<red<<file<<"\n\n";
} else {
std::cerr<<"\n";
}
} }
void err(const string& stage,u32 line,u32 col,u32 len,const string& info) void err(const string& stage,u32 line,u32 col,u32 len,const string& info) {
{
++cnt; ++cnt;
col=col?col:1; col=col?col:1;
len=len?len:1; len=len?len:1;
@ -152,5 +149,9 @@ public:
std::cerr<<red<<"^"; std::cerr<<red<<"^";
std::cerr<<red<<" "<<info<<reset<<"\n\n"; std::cerr<<red<<" "<<info<<reset<<"\n\n";
} }
void chkerr() const {if(cnt)std::exit(1);} void chkerr() const {
if (cnt) {
std::exit(1);
}
}
}; };

View File

@ -22,7 +22,7 @@
#include "nasal_err.h" #include "nasal_err.h"
enum vm_type:u8{ enum vm_type:u8 {
/* none-gc object */ /* none-gc object */
vm_none=0, vm_none=0,
vm_cnt, vm_cnt,
@ -42,8 +42,7 @@ enum vm_type:u8{
const u32 gc_tsize=vm_co-vm_str+1; const u32 gc_tsize=vm_co-vm_str+1;
// change parameters here to make your own efficient gc // change parameters here to make your own efficient gc
// better set bigger number on vm_vec // better set bigger number on vm_vec
const u32 ini[gc_tsize]= const u32 ini[gc_tsize]={
{
128, // vm_str 128, // vm_str
128, // vm_vec 128, // vm_vec
32, // vm_hash 32, // vm_hash
@ -52,15 +51,14 @@ const u32 ini[gc_tsize]=
0, // vm_obj 0, // vm_obj
0 // vm_co 0 // vm_co
}; };
const u32 incr[gc_tsize]= const u32 incr[gc_tsize]={
{
1024,// vm_str 1024,// vm_str
512, // vm_vec 512, // vm_vec
512, // vm_hash 512, // vm_hash
512, // vm_func 512, // vm_func
512, // vm_upval 512, // vm_upval
128, // vm_obj 128, // vm_obj
32 // vm_co 128 // vm_co
}; };
struct nas_vec; // vector struct nas_vec; // vector
@ -71,11 +69,9 @@ struct nas_obj; // special objects
struct nas_co; // coroutine struct nas_co; // coroutine
struct nas_val; // nas_val includes gc-managed types struct nas_val; // nas_val includes gc-managed types
struct var struct var {
{
u8 type; u8 type;
union union {
{
u32 ret; u32 ret;
i64 cnt; i64 cnt;
f64 num; f64 num;
@ -84,21 +80,21 @@ struct var
} val; } val;
// vm_none/vm_nil // vm_none/vm_nil
var(const u8 t=vm_none):type(t){} var(const u8 t=vm_none):type(t) {}
// vm_ret // vm_ret
var(const u8 t,const u32 n):type(t){val.ret=n;} var(const u8 t,const u32 n):type(t) {val.ret=n;}
// vm_cnt // vm_cnt
var(const u8 t,const i64 n):type(t){val.cnt=n;} var(const u8 t,const i64 n):type(t) {val.cnt=n;}
// vm_num // vm_num
var(const u8 t,const f64 n):type(t){val.num=n;} var(const u8 t,const f64 n):type(t) {val.num=n;}
// nas_val // nas_val
var(const u8 t,nas_val* n):type(t){val.gcobj=n;} var(const u8 t,nas_val* n):type(t) {val.gcobj=n;}
// vm_addr // vm_addr
var(const u8 t,var* n):type(t){val.addr=n;} var(const u8 t,var* n):type(t) {val.addr=n;}
// copy // copy
var(const var& nr):type(nr.type),val(nr.val){} var(const var& nr):type(nr.type),val(nr.val) {}
bool operator==(const var& nr){return type==nr.type && val.gcobj==nr.val.gcobj;} bool operator==(const var& nr) {return type==nr.type && val.gcobj==nr.val.gcobj;}
bool operator!=(const var& nr){return type!=nr.type || val.gcobj!=nr.val.gcobj;} bool operator!=(const var& nr) {return type!=nr.type || val.gcobj!=nr.val.gcobj;}
// number and string can be translated to each other // number and string can be translated to each other
f64 tonum(); f64 tonum();
string tostr(); string tostr();
@ -117,32 +113,29 @@ struct var
inline nas_co& co (); inline nas_co& co ();
}; };
struct nas_vec struct nas_vec {
{
bool printed; bool printed;
std::vector<var> elems; std::vector<var> elems;
nas_vec():printed(false){} nas_vec():printed(false) {}
friend std::ostream& operator<<(std::ostream&,nas_vec&); 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_val(const i32);
var* get_mem(const i32); var* get_mem(const i32);
}; };
struct nas_hash struct nas_hash {
{
bool printed; bool printed;
std::unordered_map<string,var> elems; std::unordered_map<string,var> elems;
nas_hash():printed(false){} nas_hash():printed(false) {}
friend std::ostream& operator<<(std::ostream&,nas_hash&); 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_val(const string&);
var* get_mem(const string&); var* get_mem(const string&);
}; };
struct nas_func struct nas_func {
{
i32 dpara; // dynamic parameter name index in hash. i32 dpara; // dynamic parameter name index in hash.
u32 entry; // pc will set to entry-1 to call this function u32 entry; // pc will set to entry-1 to call this function
u32 psize; // used to load default parameters to a new function u32 psize; // used to load default parameters to a new function
@ -151,50 +144,45 @@ struct nas_func
std::vector<var> upval; // closure std::vector<var> upval; // closure
std::unordered_map<u32,u32> keys; // parameter table, u32 begins from 1 std::unordered_map<u32,u32> 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(); void clear();
}; };
struct nas_upval struct nas_upval {
{
bool onstk; bool onstk;
u32 size; u32 size;
var* stk; var* stk;
std::vector<var> elems; std::vector<var> elems;
nas_upval(){onstk=true;stk=nullptr;size=0;} nas_upval() {onstk=true;stk=nullptr;size=0;}
var& operator[](usize n){return onstk?stk[n]:elems[n];} var& operator[](usize n) {return onstk?stk[n]:elems[n];}
void clear(){onstk=true;elems.clear();size=0;} void clear() {onstk=true;elems.clear();size=0;}
}; };
struct nas_obj struct nas_obj {
{ enum obj:u32 {
enum obj_t:u32
{
file=1, file=1,
dir, dir,
dylib, dylib,
faddr faddr,
unsafe
}; };
/* RAII constructor */ /* RAII constructor */
/* new object is initialized when creating */ /* new object is initialized when creating */
u32 type; u32 type;
void* ptr; void* ptr;
private: private:
void obj_file_dtor() void file_dtor() {
{
fclose((FILE*)ptr); fclose((FILE*)ptr);
} }
void obj_dir_dtor() void dir_dtor() {
{
#ifndef _MSC_VER #ifndef _MSC_VER
closedir((DIR*)ptr); closedir((DIR*)ptr);
#else #else
FindClose(ptr); FindClose(ptr);
#endif #endif
} }
void dylib_dtor() void dylib_dtor() {
{
#ifdef _WIN32 #ifdef _WIN32
FreeLibrary((HMODULE)ptr); FreeLibrary((HMODULE)ptr);
#else #else
@ -202,32 +190,28 @@ private:
#endif #endif
} }
public: public:
nas_obj():type(0),ptr(nullptr){} nas_obj():type(0),ptr(nullptr) {}
~nas_obj(){clear();} ~nas_obj() {clear();}
void set(u32 t=0,void* p=nullptr) void set(u32 t=0,void* p=nullptr) {
{
type=t; type=t;
ptr=p; ptr=p;
} }
void clear() void clear() {
{ if (!ptr) {
if(!ptr)
return; return;
switch(type) }
{ switch(type) {
case obj_t::file: obj_file_dtor();break; case obj::file: file_dtor(); break;
case obj_t::dir: obj_dir_dtor(); break; case obj::dir: dir_dtor(); break;
case obj_t::dylib: dylib_dtor(); break; case obj::dylib: dylib_dtor();break;
default: break; default: break;
} }
ptr=nullptr; ptr=nullptr;
} }
}; };
struct nas_co struct nas_co {
{ enum costat:u32{
enum costat:u32
{
suspended, suspended,
running, running,
dead dead
@ -250,13 +234,11 @@ struct nas_co
memr(nullptr), memr(nullptr),
funcr({vm_nil,(f64)0}), funcr({vm_nil,(f64)0}),
upvalr({vm_nil,(f64)0}), upvalr({vm_nil,(f64)0}),
status(nas_co::suspended) status(nas_co::suspended) {
{
for(u32 i=0;i<STACK_DEPTH;++i) for(u32 i=0;i<STACK_DEPTH;++i)
stack[i]={vm_nil,(f64)0}; stack[i]={vm_nil,(f64)0};
} }
void clear() void clear() {
{
for(u32 i=0;i<STACK_DEPTH;++i) for(u32 i=0;i<STACK_DEPTH;++i)
stack[i]={vm_nil,(f64)0}; stack[i]={vm_nil,(f64)0};
pc=0; pc=0;
@ -271,13 +253,11 @@ struct nas_co
const u8 GC_UNCOLLECTED=0; const u8 GC_UNCOLLECTED=0;
const u8 GC_COLLECTED =1; const u8 GC_COLLECTED =1;
const u8 GC_FOUND =2; const u8 GC_FOUND =2;
struct nas_val struct nas_val {
{
u8 mark; u8 mark;
u8 type; u8 type;
u8 unmut; // used to mark if a string is unmutable u8 unmut; // used to mark if a string is unmutable
union union {
{
string* str; string* str;
nas_vec* vec; nas_vec* vec;
nas_hash* hash; nas_hash* hash;
@ -292,105 +272,104 @@ struct nas_val
void clear(); void clear();
}; };
var nas_vec::get_val(const i32 n) var nas_vec::get_val(const i32 n) {
{
i32 size=elems.size(); i32 size=elems.size();
if(n<-size || n>=size) if (n<-size || n>=size) {
return {vm_none}; return {vm_none};
}
return elems[n>=0?n:n+size]; 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(); i32 size=elems.size();
if(n<-size || n>=size) if (n<-size || n>=size) {
return nullptr; return nullptr;
}
return &elems[n>=0?n:n+size]; return &elems[n>=0?n:n+size];
} }
std::ostream& operator<<(std::ostream& out,nas_vec& vec)
{ std::ostream& operator<<(std::ostream& out,nas_vec& vec) {
if(!vec.elems.size() || vec.printed) if (!vec.elems.size() || vec.printed) {
{
out<<(vec.elems.size()?"[..]":"[]"); out<<(vec.elems.size()?"[..]":"[]");
return out; return out;
} }
vec.printed=true; vec.printed=true;
usize iter=0,size=vec.elems.size(); usize iter=0,size=vec.elems.size();
out<<'['; out<<'[';
for(auto& i:vec.elems) for(auto& i:vec.elems) {
out<<i<<",]"[(++iter)==size]; out<<i<<",]"[(++iter)==size];
}
vec.printed=false; vec.printed=false;
return out; return out;
} }
var nas_hash::get_val(const string& key) var nas_hash::get_val(const string& key) {
{ if (elems.count(key)) {
if(elems.count(key))
return elems[key]; return elems[key];
else if(elems.count("parents")) } else if (elems.count("parents")) {
{
var ret(vm_none); var ret(vm_none);
var val=elems["parents"]; var val=elems["parents"];
if(val.type==vm_vec) if (val.type==vm_vec) {
for(auto& i:val.vec().elems) for(auto& i:val.vec().elems) {
{ if (i.type==vm_hash) {
if(i.type==vm_hash)
ret=i.hash().get_val(key); ret=i.hash().get_val(key);
if(ret.type!=vm_none) }
if (ret.type!=vm_none) {
return ret; return ret;
}
} }
}
} }
return {vm_none}; return {vm_none};
} }
var* nas_hash::get_mem(const string& key)
{ var* nas_hash::get_mem(const string& key) {
if(elems.count(key)) if (elems.count(key)) {
return &elems[key]; return &elems[key];
else if(elems.count("parents")) } else if (elems.count("parents")) {
{
var* addr=nullptr; var* addr=nullptr;
var val=elems["parents"]; var val=elems["parents"];
if(val.type==vm_vec) if (val.type==vm_vec) {
for(auto& i:val.vec().elems) for(auto& i:val.vec().elems) {
{ if (i.type==vm_hash) {
if(i.type==vm_hash)
addr=i.hash().get_mem(key); addr=i.hash().get_mem(key);
if(addr) }
if (addr) {
return addr; return addr;
}
} }
}
} }
return nullptr; return nullptr;
} }
std::ostream& operator<<(std::ostream& out,nas_hash& hash)
{ std::ostream& operator<<(std::ostream& out,nas_hash& hash) {
if(!hash.elems.size() || hash.printed) if (!hash.elems.size() || hash.printed) {
{
out<<(hash.elems.size()?"{..}":"{}"); out<<(hash.elems.size()?"{..}":"{}");
return out; return out;
} }
hash.printed=true; hash.printed=true;
usize iter=0,size=hash.elems.size(); usize iter=0,size=hash.elems.size();
out<<'{'; out<<'{';
for(auto& i:hash.elems) for(auto& i:hash.elems) {
out<<i.first<<':'<<i.second<<",}"[(++iter)==size]; out<<i.first<<':'<<i.second<<",}"[(++iter)==size];
}
hash.printed=false; hash.printed=false;
return out; return out;
} }
void nas_func::clear() void nas_func::clear() {
{
dpara=-1; dpara=-1;
local.clear(); local.clear();
upval.clear(); upval.clear();
keys.clear(); keys.clear();
} }
nas_val::nas_val(u8 val_type) nas_val::nas_val(u8 val_type) {
{
mark=GC_COLLECTED; mark=GC_COLLECTED;
type=val_type; type=val_type;
unmut=0; unmut=0;
switch(val_type) switch(val_type) {
{
case vm_str: ptr.str=new string; break; case vm_str: ptr.str=new string; break;
case vm_vec: ptr.vec=new nas_vec; break; case vm_vec: ptr.vec=new nas_vec; break;
case vm_hash: ptr.hash=new nas_hash; break; case vm_hash: ptr.hash=new nas_hash; break;
@ -400,10 +379,9 @@ nas_val::nas_val(u8 val_type)
case vm_co: ptr.co=new nas_co; break; case vm_co: ptr.co=new nas_co; break;
} }
} }
nas_val::~nas_val()
{ nas_val::~nas_val() {
switch(type) switch(type) {
{
case vm_str: delete ptr.str; break; case vm_str: delete ptr.str; break;
case vm_vec: delete ptr.vec; break; case vm_vec: delete ptr.vec; break;
case vm_hash: delete ptr.hash; break; case vm_hash: delete ptr.hash; break;
@ -414,10 +392,9 @@ nas_val::~nas_val()
} }
type=vm_nil; type=vm_nil;
} }
void nas_val::clear()
{ void nas_val::clear() {
switch(type) switch(type) {
{
case vm_str: ptr.str->clear(); break; case vm_str: ptr.str->clear(); break;
case vm_vec: ptr.vec->elems.clear(); break; case vm_vec: ptr.vec->elems.clear(); break;
case vm_hash: ptr.hash->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; case vm_co: ptr.co->clear(); break;
} }
} }
f64 var::tonum()
{ f64 var::tonum() {
return type!=vm_str?val.num:str2num(str().c_str()); return type!=vm_str?val.num:str2num(str().c_str());
} }
string var::tostr()
{ string var::tostr() {
if(type==vm_str) if (type==vm_str) {
return str(); return str();
else if(type==vm_num) } else if (type==vm_num) {
{
string tmp=std::to_string(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('0')+1,string::npos);
tmp.erase(tmp.find_last_not_of('.')+1,string::npos); tmp.erase(tmp.find_last_not_of('.')+1,string::npos);
@ -444,47 +420,45 @@ string var::tostr()
} }
return ""; return "";
} }
std::ostream& operator<<(std::ostream& out,var& ref)
{ std::ostream& operator<<(std::ostream& out,var& ref) {
switch(ref.type) switch(ref.type) {
{
case vm_none: out<<"undefined"; break; case vm_none: out<<"undefined"; break;
case vm_nil: out<<"nil"; break; case vm_nil: out<<"nil"; break;
case vm_num: out<<ref.val.num; break; case vm_num: out<<ref.val.num; break;
case vm_str: out<<ref.str(); break; case vm_str: out<<ref.str(); break;
case vm_vec: out<<ref.vec(); break; case vm_vec: out<<ref.vec(); break;
case vm_hash: out<<ref.hash(); break; case vm_hash: out<<ref.hash(); break;
case vm_func: out<<"func(..){..}";break; case vm_func: out<<"func(..) {..}";break;
case vm_obj: out<<"<object>"; break; case vm_obj: out<<"<object>"; break;
case vm_co: out<<"<coroutine>"; break; case vm_co: out<<"<coroutine>"; break;
} }
return out; return out;
} }
bool var::objchk(u32 objtype)
{ bool var::objchk(u32 objtype) {
return type==vm_obj && obj().type==objtype && obj().ptr; return type==vm_obj && obj().type==objtype && obj().ptr;
} }
inline var* var::addr (){return val.addr; }
inline u32 var::ret (){return val.ret; } inline var* var::addr () {return val.addr; }
inline i64& var::cnt (){return val.cnt; } inline u32 var::ret () {return val.ret; }
inline f64 var::num (){return val.num; } inline i64& var::cnt () {return val.cnt; }
inline string& var::str (){return *val.gcobj->ptr.str; } inline f64 var::num () {return val.num; }
inline nas_vec& var::vec (){return *val.gcobj->ptr.vec; } inline string& var::str () {return *val.gcobj->ptr.str; }
inline nas_hash& var::hash (){return *val.gcobj->ptr.hash; } inline nas_vec& var::vec () {return *val.gcobj->ptr.vec; }
inline nas_func& var::func (){return *val.gcobj->ptr.func; } inline nas_hash& var::hash () {return *val.gcobj->ptr.hash; }
inline nas_upval& var::upval(){return *val.gcobj->ptr.upval;} inline nas_func& var::func () {return *val.gcobj->ptr.func; }
inline nas_obj& var::obj (){return *val.gcobj->ptr.obj; } inline nas_upval& var::upval() {return *val.gcobj->ptr.upval;}
inline nas_co& var::co (){return *val.gcobj->ptr.co; } 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 zero={vm_num,(f64)0};
const var one ={vm_num,(f64)1}; const var one ={vm_num,(f64)1};
const var nil ={vm_nil,(f64)0}; const var nil ={vm_nil,(f64)0};
struct gc struct gc {
{
/* main context */ /* main context */
struct struct {
{
u32 pc; u32 pc;
var* top; var* top;
var* localr; var* localr;
@ -525,7 +499,7 @@ struct gc
var& _upvalr, var*& _canary, var*& _top, var* _stk): var& _upvalr, var*& _canary, var*& _top, var* _stk):
pc(_pc),localr(_localr),memr(_memr),funcr(_funcr),upvalr(_upvalr), pc(_pc),localr(_localr),memr(_memr),funcr(_funcr),upvalr(_upvalr),
canary(_canary),top(_top),stack(_stk),cort(nullptr),temp(nil), canary(_canary),top(_top),stack(_stk),cort(nullptr),temp(nil),
worktime(0){} worktime(0) {}
void mark(); void mark();
void sweep(); void sweep();
void init(const std::vector<string>&,const std::vector<string>&); void init(const std::vector<string>&,const std::vector<string>&);
@ -540,128 +514,135 @@ struct gc
}; };
/* gc functions */ /* gc functions */
void gc::mark() void gc::mark() {
{
std::queue<var> bfs; std::queue<var> bfs;
// scan coroutine process stack when coroutine ptr is not null // scan coroutine process stack when coroutine ptr is not null
// scan main process stack when coroutine ptr is null // scan main process stack when coroutine ptr is null
// this scan process must execute because when running coroutine, // 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. // 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(*i);
}
bfs.push(funcr); bfs.push(funcr);
bfs.push(upvalr); bfs.push(upvalr);
bfs.push(temp); bfs.push(temp);
if(cort) // scan main process stack if (cort) { // scan main process stack
{ for(var* i=mctx.stack;i<=mctx.top;++i) {
for(var* i=mctx.stack;i<=mctx.top;++i)
bfs.push(*i); bfs.push(*i);
}
bfs.push(mctx.funcr); bfs.push(mctx.funcr);
bfs.push(mctx.upvalr); bfs.push(mctx.upvalr);
} }
while(!bfs.empty()) while(!bfs.empty()) {
{
var tmp=bfs.front(); var tmp=bfs.front();
bfs.pop(); 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; tmp.val.gcobj->mark=GC_FOUND;
switch(tmp.type) switch(tmp.type) {
{
case vm_vec: case vm_vec:
for(auto& i:tmp.vec().elems) for(auto& i:tmp.vec().elems) {
bfs.push(i); bfs.push(i);
}
break; break;
case vm_hash: case vm_hash:
for(auto& i:tmp.hash().elems) for(auto& i:tmp.hash().elems) {
bfs.push(i.second); bfs.push(i.second);
}
break; break;
case vm_func: case vm_func:
for(auto& i:tmp.func().local) for(auto& i:tmp.func().local) {
bfs.push(i); bfs.push(i);
for(auto& i:tmp.func().upval) }
for(auto& i:tmp.func().upval) {
bfs.push(i); bfs.push(i);
}
break; break;
case vm_upval: case vm_upval:
for(auto& i:tmp.upval().elems) for(auto& i:tmp.upval().elems) {
bfs.push(i); bfs.push(i);
}
break; break;
case vm_co: case vm_co:
bfs.push(tmp.co().funcr); bfs.push(tmp.co().funcr);
bfs.push(tmp.co().upvalr); 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); bfs.push(*i);
}
break; break;
} }
} }
} }
void gc::sweep() void gc::sweep()
{ {
for(auto i:memory) for(auto i:memory) {
{ if (i->mark==GC_UNCOLLECTED) {
if(i->mark==GC_UNCOLLECTED)
{
i->clear(); i->clear();
unused[i->type-vm_str].push(i); unused[i->type-vm_str].push(i);
i->mark=GC_COLLECTED; i->mark=GC_COLLECTED;
} } else if (i->mark==GC_FOUND) {
else if(i->mark==GC_FOUND)
i->mark=GC_UNCOLLECTED; i->mark=GC_UNCOLLECTED;
}
} }
} }
void gc::init(const std::vector<string>& s,const std::vector<string>& argv)
{ void gc::init(const std::vector<string>& s,const std::vector<string>& argv) {
// initiaize function register // initiaize function register
funcr=nil; funcr=nil;
worktime=0; worktime=0;
for(u8 i=0;i<gc_tsize;++i) for(u8 i=0;i<gc_tsize;++i) {
size[i]=gcnt[i]=acnt[i]=0; size[i]=gcnt[i]=acnt[i]=0;
for(u8 i=0;i<gc_tsize;++i) }
for(u32 j=0;j<ini[i];++j) for(u8 i=0;i<gc_tsize;++i) {
{ for(u32 j=0;j<ini[i];++j) {
nas_val* tmp=new nas_val(i+vm_str); nas_val* tmp=new nas_val(i+vm_str);
memory.push_back(tmp); memory.push_back(tmp);
unused[i].push(tmp); unused[i].push(tmp);
} }
}
cort=nullptr; cort=nullptr;
// init constant strings // init constant strings
strs.resize(s.size()); strs.resize(s.size());
for(u32 i=0;i<strs.size();++i) for(u32 i=0;i<strs.size();++i) {
{
strs[i]={vm_str,new nas_val(vm_str)}; strs[i]={vm_str,new nas_val(vm_str)};
strs[i].val.gcobj->unmut=1; strs[i].val.gcobj->unmut=1;
strs[i].str()=s[i]; strs[i].str()=s[i];
} }
// record arguments // record arguments
env_argv.resize(argv.size()); env_argv.resize(argv.size());
for(usize i=0;i<argv.size();++i) for(usize i=0;i<argv.size();++i) {
{
env_argv[i]={vm_str,new nas_val(vm_str)}; env_argv[i]={vm_str,new nas_val(vm_str)};
env_argv[i].val.gcobj->unmut=1; env_argv[i].val.gcobj->unmut=1;
env_argv[i].str()=argv[i]; env_argv[i].str()=argv[i];
} }
} }
void gc::clear()
{ void gc::clear() {
for(auto i:memory) for(auto i:memory) {
delete i; delete i;
}
memory.clear(); memory.clear();
for(u8 i=0;i<gc_tsize;++i) for(u8 i=0;i<gc_tsize;++i) {
while(!unused[i].empty()) while(!unused[i].empty()) {
unused[i].pop(); unused[i].pop();
for(auto& i:strs) }
}
for(auto& i:strs) {
delete i.val.gcobj; delete i.val.gcobj;
}
strs.clear(); strs.clear();
env_argv.clear(); env_argv.clear();
} }
void gc::info()
{ void gc::info() {
const char* name[]={"str ","vec ","hash ","func ","upval","obj ","co "}; const char* name[]={"str ","vec ","hash ","func ","upval","obj ","co "};
std::cout<<"\ngarbage collector info (gc count|alloc count|memory size)\n"; std::cout<<"\ngarbage collector info (gc count|alloc count|memory size)\n";
u32 maxlen=0; u32 maxlen=0;
for(u8 i=0;i<gc_tsize;++i) for(u8 i=0;i<gc_tsize;++i) {
{
u32 len=std::to_string(gcnt[i]).length(); u32 len=std::to_string(gcnt[i]).length();
maxlen=maxlen<len?len:maxlen; maxlen=maxlen<len?len:maxlen;
len=std::to_string(acnt[i]).length(); len=std::to_string(acnt[i]).length();
@ -670,36 +651,34 @@ void gc::info()
maxlen=maxlen<len?len:maxlen; maxlen=maxlen<len?len:maxlen;
} }
double total=0; double total=0;
for(u8 i=0;i<gc_tsize;++i) for(u8 i=0;i<gc_tsize;++i) {
if(gcnt[i] || acnt[i] || ini[i] || size[i]) if (gcnt[i] || acnt[i] || ini[i] || size[i]) {
{
total+=gcnt[i]; total+=gcnt[i];
std::cout<<" "<<name[i]<<" | "<<std::left<<std::setw(maxlen)<<std::setfill(' ')<<gcnt[i]; std::cout<<" "<<name[i]<<" | "<<std::left<<std::setw(maxlen)<<std::setfill(' ')<<gcnt[i];
std::cout<<" | "<<std::left<<std::setw(maxlen)<<std::setfill(' ')<<acnt[i]; std::cout<<" | "<<std::left<<std::setw(maxlen)<<std::setfill(' ')<<acnt[i];
std::cout<<" | "<<std::left<<std::setw(maxlen)<<std::setfill(' ')<<ini[i]+size[i]*incr[i]<<" (+"<<size[i]<<")\n"; std::cout<<" | "<<std::left<<std::setw(maxlen)<<std::setfill(' ')<<ini[i]+size[i]*incr[i]<<" (+"<<size[i]<<")\n";
} }
}
double t=worktime*1.0/1000000000; // seconds double t=worktime*1.0/1000000000; // seconds
std::cout<<" time | "<<(t<0.1? t*1000:t)<<(t<0.1? "ms\n":"s\n"); std::cout<<" time | "<<(t<0.1? t*1000:t)<<(t<0.1? "ms\n":"s\n");
if(total) if (total) {
std::cout<<" avg | "<<t/total*1000<<" ms\n"; std::cout<<" avg | "<<t/total*1000<<" ms\n";
}
} }
var gc::alloc(u8 type)
{ var gc::alloc(u8 type) {
const u8 index=type-vm_str; const u8 index=type-vm_str;
++acnt[index]; ++acnt[index];
if(unused[index].empty()) if (unused[index].empty()) {
{
++gcnt[index]; ++gcnt[index];
auto begin=std::chrono::high_resolution_clock::now(); auto begin=std::chrono::high_resolution_clock::now();
mark(); mark();
sweep(); sweep();
worktime+=(std::chrono::high_resolution_clock::now()-begin).count(); worktime+=(std::chrono::high_resolution_clock::now()-begin).count();
} }
if(unused[index].empty()) if (unused[index].empty()) {
{
++size[index]; ++size[index];
for(u32 i=0;i<incr[index];++i) for(u32 i=0;i<incr[index];++i) {
{
nas_val* tmp=new nas_val(type); nas_val* tmp=new nas_val(type);
memory.push_back(tmp); memory.push_back(tmp);
unused[index].push(tmp); unused[index].push(tmp);
@ -710,26 +689,26 @@ var gc::alloc(u8 type)
unused[index].pop(); unused[index].pop();
return ret; return ret;
} }
var gc::newstr(char c)
{ var gc::newstr(char c) {
var s=alloc(vm_str); var s=alloc(vm_str);
s.str()=c; s.str()=c;
return s; return s;
} }
var gc::newstr(const char* buff)
{ var gc::newstr(const char* buff) {
var s=alloc(vm_str); var s=alloc(vm_str);
s.str()=buff; s.str()=buff;
return s; return s;
} }
var gc::newstr(const string& buff)
{ var gc::newstr(const string& buff) {
var s=alloc(vm_str); var s=alloc(vm_str);
s.str()=buff; s.str()=buff;
return s; return s;
} }
void gc::ctxchg(nas_co& ctx)
{ void gc::ctxchg(nas_co& ctx) {
mctx.pc=pc; mctx.pc=pc;
mctx.top=top; mctx.top=top;
mctx.localr=localr; mctx.localr=localr;
@ -751,8 +730,8 @@ void gc::ctxchg(nas_co& ctx)
cort->status=nas_co::running; cort->status=nas_co::running;
} }
void gc::ctxreserve()
{ void gc::ctxreserve() {
// pc=0 means this coroutine is finished // pc=0 means this coroutine is finished
cort->status=pc?nas_co::suspended:nas_co::dead; cort->status=pc?nas_co::suspended:nas_co::dead;
cort->pc=pc; cort->pc=pc;
@ -775,8 +754,7 @@ void gc::ctxreserve()
} }
// use to print error log and return error value // 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] "<<err_f<<": "<<info<<"\n"; std::cerr<<"[vm] "<<err_f<<": "<<info<<"\n";
return {vm_none}; return {vm_none};
} }

View File

@ -12,14 +12,14 @@
#define F_OK 0 #define F_OK 0
#endif #endif
class linker class linker{
{
private: private:
bool show_path; bool show_path;
bool lib_loaded; bool lib_loaded;
error& err; error& err;
std::vector<string> files; std::vector<string> files;
std::vector<string> envpath; std::vector<string> envpath;
bool imptchk(const ast&); bool imptchk(const ast&);
bool exist(const string&); bool exist(const string&);
void link(ast&,ast&&); void link(ast&,ast&&);
@ -34,7 +34,7 @@ public:
const std::vector<string>& filelist() const {return files;} const std::vector<string>& 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 #ifdef _WIN32
char sep=';'; char sep=';';
#else #else
@ -42,66 +42,68 @@ linker::linker(error& e):show_path(false),lib_loaded(false),err(e){
#endif #endif
string PATH=getenv("PATH"); string PATH=getenv("PATH");
usize last=0,pos=PATH.find(sep,0); usize last=0,pos=PATH.find(sep,0);
while(pos!=string::npos) while(pos!=string::npos) {
{
string dirpath=PATH.substr(last,pos-last); string dirpath=PATH.substr(last,pos-last);
if(dirpath.length()) if (dirpath.length()) {
envpath.push_back(dirpath); envpath.push_back(dirpath);
}
last=pos+1; last=pos+1;
pos=PATH.find(sep,last); pos=PATH.find(sep,last);
} }
if(last!=PATH.length()) if (last!=PATH.length()) {
envpath.push_back(PATH.substr(last)); envpath.push_back(PATH.substr(last));
}
} }
string linker::path(const ast& node) string linker::path(const ast& node) {
{ if (node[1].type()==ast_callf) {
if(node[1].type()==ast_callf)
return node[1][0].str(); return node[1][0].str();
}
string fpath="."; string fpath=".";
for(usize i=1;i<node.size();++i) for(usize i=1;i<node.size();++i) {
#ifndef _WIN32 #ifndef _WIN32
fpath+="/"+node[i].str(); fpath+="/"+node[i].str();
#else #else
fpath+="\\"+node[i].str(); fpath+="\\"+node[i].str();
#endif #endif
}
return fpath+".nas"; return fpath+".nas";
} }
string linker::findf(const string& fname) string linker::findf(const string& fname) {
{
std::vector<string> fpath={fname}; std::vector<string> fpath={fname};
for(auto&p:envpath) for(auto&p:envpath) {
{
#ifdef _WIN32 #ifdef _WIN32
fpath.push_back(p+"\\"+fname); fpath.push_back(p+"\\"+fname);
#else #else
fpath.push_back(p+"/"+fname); fpath.push_back(p+"/"+fname);
#endif #endif
} }
for(auto& i:fpath) for(auto& i:fpath) {
if(access(i.c_str(),F_OK)!=-1) if (access(i.c_str(),F_OK)!=-1) {
return i; return i;
if(fname=="lib.nas") }
}
if (fname=="lib.nas") {
#ifdef _WIN32 #ifdef _WIN32
return findf("stl\\lib.nas"); return findf("stl\\lib.nas");
#else #else
return findf("stl/lib.nas"); return findf("stl/lib.nas");
#endif #endif
if(!show_path) }
{ if (!show_path) {
err.err("link","cannot find file <"+fname+">"); err.err("link","cannot find file <"+fname+">");
return ""; return "";
} }
string paths=""; string paths="";
for(auto& i:fpath) for(auto& i:fpath) {
paths+=" "+i+"\n"; paths+=" "+i+"\n";
}
err.err("link","cannot find file <"+fname+"> in these paths:\n"+paths); err.err("link","cannot find file <"+fname+"> in these paths:\n"+paths);
return ""; return "";
} }
bool linker::imptchk(const ast& node) bool linker::imptchk(const ast& node) {
{
// only these two kinds of node can be recognized as 'import': // only these two kinds of node can be recognized as 'import':
/* /*
call call
@ -109,11 +111,12 @@ bool linker::imptchk(const ast& node)
|_callh:stl |_callh:stl
|_callh:file |_callh:file
*/ */
if(node.type()==ast_call && node[0].str()=="import" && node.size()>=2 && node[1].type()==ast_callh) if (node.type()==ast_call && node[0].str()=="import" && node.size()>=2 && node[1].type()==ast_callh) {
{ for(usize i=1;i<node.size();++i) {
for(usize i=1;i<node.size();++i) if (node[i].type()!=ast_callh) {
if(node[i].type()!=ast_callh)
return false; return false;
}
}
return true; return true;
} }
/* /*
@ -132,25 +135,25 @@ bool linker::imptchk(const ast& node)
); );
} }
bool linker::exist(const string& file) bool linker::exist(const string& file) {
{
// avoid importing the same file // avoid importing the same file
for(auto& fname:files) for(auto& fname:files) {
if(file==fname) if (file==fname) {
return true; return true;
}
}
files.push_back(file); files.push_back(file);
return false; return false;
} }
void linker::link(ast& root,ast&& add_root) void linker::link(ast& root,ast&& add_root) {
{
// add children of add_root to the back of root // add children of add_root to the back of root
for(auto& i:add_root.child()) for(auto& i:add_root.child()) {
root.add(std::move(i)); root.add(std::move(i));
}
} }
ast linker::fimpt(ast& node) ast linker::fimpt(ast& node) {
{
lexer lex(err); lexer lex(err);
parse par(err); parse par(err);
// get filename and set node to ast_null // get filename and set node to ast_null
@ -159,8 +162,9 @@ ast linker::fimpt(ast& node)
// avoid infinite loading loop // avoid infinite loading loop
filename=findf(filename); filename=findf(filename);
if(!filename.length() || exist(filename)) if (!filename.length() || exist(filename)) {
return {0,0,ast_root}; return {0,0,ast_root};
}
// start importing... // start importing...
lex.scan(filename); lex.scan(filename);
@ -170,17 +174,18 @@ ast linker::fimpt(ast& node)
return load(tmp,files.size()-1); return load(tmp,files.size()-1);
} }
ast linker::libimpt() ast linker::libimpt() {
{
lexer lex(err); lexer lex(err);
parse par(err); parse par(err);
string filename=findf("lib.nas"); string filename=findf("lib.nas");
if(!filename.length()) if (!filename.length()) {
return {0,0,ast_root}; return {0,0,ast_root};
}
// avoid infinite loading loop // avoid infinite loading loop
if(exist(filename)) if (exist(filename)) {
return {0,0,ast_root}; return {0,0,ast_root};
}
// start importing... // start importing...
lex.scan(filename); lex.scan(filename);
@ -190,20 +195,18 @@ ast linker::libimpt()
return load(tmp,files.size()-1); return load(tmp,files.size()-1);
} }
ast linker::load(ast& root,u16 fileindex) ast linker::load(ast& root,u16 fileindex) {
{
ast tree(0,0,ast_root); ast tree(0,0,ast_root);
if(!lib_loaded) if (!lib_loaded) {
{
link(tree,libimpt()); link(tree,libimpt());
lib_loaded=true; lib_loaded=true;
} }
for(auto& i:root.child()) for(auto& i:root.child()) {
{ if (imptchk(i)) {
if(imptchk(i))
link(tree,fimpt(i)); link(tree,fimpt(i));
else } else {
break; break;
}
} }
// add root to the back of tree // add root to the back of tree
ast file_head(0,0,ast_file); ast file_head(0,0,ast_file);
@ -213,8 +216,7 @@ ast linker::load(ast& root,u16 fileindex)
return tree; return tree;
} }
const error& linker::link(parse& parse,const string& self,bool spath=false) const error& linker::link(parse& parse,const string& self,bool spath=false) {
{
show_path=spath; show_path=spath;
// initializing // initializing
files={self}; files={self};

View File

@ -8,7 +8,7 @@
#define S_ISREG(m) (((m)&0xF000)==0x8000) #define S_ISREG(m) (((m)&0xF000)==0x8000)
#endif #endif
enum tok:u32{ enum tok:u32 {
tok_null=0, // null token (default token type) tok_null=0, // null token (default token type)
tok_num, // number literal tok_num, // number literal
tok_str, // string literal tok_str, // string literal
@ -61,18 +61,16 @@ enum tok:u32{
tok_eof // <eof> end of token list tok_eof // <eof> end of token list
}; };
struct token struct token {
{
u32 line; u32 line;
u32 col; u32 col;
u32 type; u32 type;
string str; string str;
token(u32 l=0,u32 c=0,u32 t=tok_null,const string& s="") 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: private:
u32 line; u32 line;
u32 column; u32 column;
@ -143,43 +141,36 @@ private:
string num_gen(); string num_gen();
string str_gen(); string str_gen();
public: 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 error& scan(const string&);
const std::vector<token>& result() const {return toks;} const std::vector<token>& result() const {return toks;}
}; };
bool lexer::skip(char c) bool lexer::skip(char c) {
{
return c==' '||c=='\n'||c=='\t'||c=='\r'||c==0; 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); 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'); 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'; return '0'<=c&&c<='7';
} }
bool lexer::is_dec(char c) bool lexer::is_dec(char c) {
{
return '0'<=c&&c<='9'; return '0'<=c&&c<='9';
} }
bool lexer::is_str(char c) bool lexer::is_str(char c) {
{
return c=='\''||c=='\"'||c=='`'; return c=='\''||c=='\"'||c=='`';
} }
bool lexer::is_single_opr(char c) bool lexer::is_single_opr(char c) {
{
return ( return (
c=='('||c==')'||c=='['||c==']'|| c=='('||c==')'||c=='['||c==']'||
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 ( return (
c=='='||c=='+'||c=='-'||c=='*'|| c=='='||c=='+'||c=='-'||c=='*'||
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) void lexer::open(const string& file) {
// {
// err.err("lexer",line,column,1,info);
// }
void lexer::open(const string& file)
{
struct stat buffer; 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.err("lexer","<"+file+"> is not a regular file");
err.chkerr(); err.chkerr();
} }
std::ifstream in(file,std::ios::binary); std::ifstream in(file,std::ios::binary);
if(in.fail()) if (in.fail()) {
err.err("lexer","failed to open <"+file+">"); err.err("lexer","failed to open <"+file+">");
else } else {
err.load(file); err.load(file);
}
std::stringstream ss; std::stringstream ss;
ss<<in.rdbuf(); ss<<in.rdbuf();
res=ss.str(); res=ss.str();
} }
u32 lexer::get_type(const string& str) u32 lexer::get_type(const string& str) {
{
return typetbl.count(str)?typetbl.at(str):tok_null; return typetbl.count(str)?typetbl.at(str):tok_null;
} }
string lexer::utf8_gen() string lexer::utf8_gen() {
{
string str=""; string str="";
while(ptr<res.size() && res[ptr]<0) while(ptr<res.size() && res[ptr]<0) {
{
string tmp=""; string tmp="";
u32 nbytes=utf8_hdchk(res[ptr]); u32 nbytes=utf8_hdchk(res[ptr]);
if(nbytes) if (nbytes) {
{
tmp+=res[ptr++]; tmp+=res[ptr++];
for(u32 i=0;i<nbytes;++i,++ptr) for(u32 i=0;i<nbytes;++i,++ptr) {
if(ptr<res.size() && (res[ptr]&0xc0)==0x80) if (ptr<res.size() && (res[ptr]&0xc0)==0x80) {
tmp+=res[ptr]; tmp+=res[ptr];
if(tmp.length()!=1+nbytes) }
{ }
if (tmp.length()!=1+nbytes) {
++column; ++column;
string utf_info="0x"+chrhex(tmp[0]); string utf_info="0x"+chrhex(tmp[0]);
for(u32 i=1;i<tmp.size();++i) for(u32 i=1;i<tmp.size();++i) {
utf_info+=" 0x"+chrhex(tmp[i]); utf_info+=" 0x"+chrhex(tmp[i]);
}
err.err("lexer",line,column,1,"invalid utf-8 <"+utf_info+">"); err.err("lexer",line,column,1,"invalid utf-8 <"+utf_info+">");
err.fatal("lexer","fatal error occurred, stop"); err.fatal("lexer","fatal error occurred, stop");
} }
str+=tmp; str+=tmp;
column+=2; // may have some problems because not all the unicode takes 2 space column+=2; // may have some problems because not all the unicode takes 2 space
} } else {
else
{
++ptr; ++ptr;
++column; ++column;
} }
@ -260,15 +240,12 @@ string lexer::utf8_gen()
return str; return str;
} }
string lexer::id_gen() string lexer::id_gen() {
{
string str=""; string str="";
while(ptr<res.size() && (is_id(res[ptr])||is_dec(res[ptr]))) while(ptr<res.size() && (is_id(res[ptr])||is_dec(res[ptr]))) {
{ if (res[ptr]<0) { // utf-8
if(res[ptr]<0) // utf-8
str+=utf8_gen(); str+=utf8_gen();
else // ascii } else { // ascii
{
str+=res[ptr++]; str+=res[ptr++];
++column; ++column;
} }
@ -276,66 +253,64 @@ string lexer::id_gen()
return str; return str;
} }
string lexer::num_gen() string lexer::num_gen() {
{
// generate hex number // generate hex number
if(ptr+1<res.size() && res[ptr]=='0' && res[ptr+1]=='x') if (ptr+1<res.size() && res[ptr]=='0' && res[ptr+1]=='x') {
{
string str="0x"; string str="0x";
ptr+=2; ptr+=2;
while(ptr<res.size() && is_hex(res[ptr])) while(ptr<res.size() && is_hex(res[ptr])) {
str+=res[ptr++]; str+=res[ptr++];
}
column+=str.length(); column+=str.length();
if(str.length()<3)// "0x" if (str.length()<3) { // "0x"
err.err("lexer",line,column,str.length(),"invalid number `"+str+"`"); err.err("lexer",line,column,str.length(),"invalid number `"+str+"`");
}
return str; return str;
} } else if (ptr+1<res.size() && res[ptr]=='0' && res[ptr+1]=='o') { // generate oct number
// generate oct number
else if(ptr+1<res.size() && res[ptr]=='0' && res[ptr+1]=='o')
{
string str="0o"; string str="0o";
ptr+=2; ptr+=2;
while(ptr<res.size() && is_oct(res[ptr])) while(ptr<res.size() && is_oct(res[ptr])) {
str+=res[ptr++]; str+=res[ptr++];
}
bool erfmt=false; bool erfmt=false;
while(ptr<res.size() && (is_dec(res[ptr]) || is_hex(res[ptr]))) while(ptr<res.size() && (is_dec(res[ptr]) || is_hex(res[ptr]))) {
{
erfmt=true; erfmt=true;
str+=res[ptr++]; str+=res[ptr++];
} }
column+=str.length(); column+=str.length();
if(str.length()==2 || erfmt) if (str.length()==2 || erfmt) {
err.err("lexer",line,column,str.length(),"invalid number `"+str+"`"); err.err("lexer",line,column,str.length(),"invalid number `"+str+"`");
}
return str; return str;
} }
// generate dec number // generate dec number
// dec number -> [0~9][0~9]*(.[0~9]*)(e|E(+|-)0|[1~9][0~9]*) // dec number -> [0~9][0~9]*(.[0~9]*)(e|E(+|-)0|[1~9][0~9]*)
string str=""; string str="";
while(ptr<res.size() && is_dec(res[ptr])) while(ptr<res.size() && is_dec(res[ptr])) {
str+=res[ptr++]; str+=res[ptr++];
if(ptr<res.size() && res[ptr]=='.') }
{ if (ptr<res.size() && res[ptr]=='.') {
str+=res[ptr++]; str+=res[ptr++];
while(ptr<res.size() && is_dec(res[ptr])) while(ptr<res.size() && is_dec(res[ptr])) {
str+=res[ptr++]; str+=res[ptr++];
}
// "xxxx." is not a correct number // "xxxx." is not a correct number
if(str.back()=='.') if (str.back()=='.') {
{
column+=str.length(); column+=str.length();
err.err("lexer",line,column,str.length(),"invalid number `"+str+"`"); err.err("lexer",line,column,str.length(),"invalid number `"+str+"`");
return "0"; return "0";
} }
} }
if(ptr<res.size() && (res[ptr]=='e' || res[ptr]=='E')) if (ptr<res.size() && (res[ptr]=='e' || res[ptr]=='E')) {
{
str+=res[ptr++]; str+=res[ptr++];
if(ptr<res.size() && (res[ptr]=='-' || res[ptr]=='+')) if (ptr<res.size() && (res[ptr]=='-' || res[ptr]=='+')) {
str+=res[ptr++]; str+=res[ptr++];
while(ptr<res.size() && is_dec(res[ptr])) }
while(ptr<res.size() && is_dec(res[ptr])) {
str+=res[ptr++]; str+=res[ptr++];
}
// "xxxe(-|+)" is not a correct number // "xxxe(-|+)" is not a correct number
if(str.back()=='e' || str.back()=='E' || str.back()=='-' || str.back()=='+') if (str.back()=='e' || str.back()=='E' || str.back()=='-' || str.back()=='+') {
{
column+=str.length(); column+=str.length();
err.err("lexer",line,column,str.length(),"invalid number `"+str+"`"); err.err("lexer",line,column,str.length(),"invalid number `"+str+"`");
return "0"; return "0";
@ -345,25 +320,20 @@ string lexer::num_gen()
return str; return str;
} }
string lexer::str_gen() string lexer::str_gen() {
{
string str=""; string str="";
const char begin=res[ptr]; const char begin=res[ptr];
++column; ++column;
while(++ptr<res.size() && res[ptr]!=begin) while(++ptr<res.size() && res[ptr]!=begin) {
{
++column; ++column;
if(res[ptr]=='\n') if (res[ptr]=='\n') {
{
column=0; column=0;
++line; ++line;
} }
if(res[ptr]=='\\' && ptr+1<res.size()) if (res[ptr]=='\\' && ptr+1<res.size()) {
{
++column; ++column;
++ptr; ++ptr;
switch(res[ptr]) switch(res[ptr]) {
{
case '0': str+='\0'; break; case '0': str+='\0'; break;
case 'a': str+='\a'; break; case 'a': str+='\a'; break;
case 'b': str+='\b'; break; case 'b': str+='\b'; break;
@ -384,86 +354,74 @@ string lexer::str_gen()
str+=res[ptr]; str+=res[ptr];
} }
// check if this string ends with a " or ' // check if this string ends with a " or '
if(ptr++>=res.size()) if (ptr++>=res.size()) {
{
err.err("lexer",line,column,1,"get EOF when generating string"); err.err("lexer",line,column,1,"get EOF when generating string");
return str; return str;
} }
++column; ++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"); err.err("lexer",line,column,1,"\'`\' is used for string that includes one character");
}
return str; return str;
} }
const error& lexer::scan(const string& file) const error& lexer::scan(const string& file) {
{
line=1; line=1;
column=0; column=0;
ptr=0; ptr=0;
open(file); open(file);
string str; string str;
while(ptr<res.size()) while(ptr<res.size()) {
{ while(ptr<res.size() && skip(res[ptr])) {
while(ptr<res.size() && skip(res[ptr]))
{
// these characters will be ignored, and '\n' will cause ++line // these characters will be ignored, and '\n' will cause ++line
++column; ++column;
if(res[ptr++]=='\n') if (res[ptr++]=='\n') {
{
++line; ++line;
column=0; column=0;
} }
} }
if(ptr>=res.size()) break; if (ptr>=res.size()) {
if(is_id(res[ptr])) break;
{ }
if (is_id(res[ptr])) {
str=id_gen(); str=id_gen();
u32 type=get_type(str); u32 type=get_type(str);
toks.push_back({line,column,type?type:tok_id,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 str=num_gen(); // make sure column is correct
toks.push_back({line,column,tok_num,str}); 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 str=str_gen(); // make sure column is correct
toks.push_back({line,column,tok_str,str}); 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]; str=res[ptr];
++column; ++column;
u32 type=get_type(str); u32 type=get_type(str);
if(!type) if (!type) {
err.err("lexer",line,column,str.length(),"invalid operator `"+str+"`"); err.err("lexer",line,column,str.length(),"invalid operator `"+str+"`");
}
toks.push_back({line,column,type,str}); toks.push_back({line,column,type,str});
++ptr; ++ptr;
} } else if (res[ptr]=='.') {
else if(res[ptr]=='.')
{
str="."; str=".";
if(ptr+2<res.size() && res[ptr+1]=='.' && res[ptr+2]=='.') if (ptr+2<res.size() && res[ptr+1]=='.' && res[ptr+2]=='.') {
str+=".."; str+="..";
}
ptr+=str.length(); ptr+=str.length();
column+=str.length(); column+=str.length();
toks.push_back({line,column,get_type(str),str}); toks.push_back({line,column,get_type(str),str});
} } else if (is_calc_opr(res[ptr])) {
else if(is_calc_opr(res[ptr]))
{
// get calculation operator // get calculation operator
str=res[ptr++]; str=res[ptr++];
if(ptr<res.size() && res[ptr]=='=') if (ptr<res.size() && res[ptr]=='=') {
str+=res[ptr++]; str+=res[ptr++];
}
column+=str.length(); column+=str.length();
toks.push_back({line,column,get_type(str),str}); toks.push_back({line,column,get_type(str),str});
} } else if (res[ptr]=='#') { // avoid note, after this process ptr will point to a '\n', so next loop line counter+1
else if(res[ptr]=='#')// avoid note, after this process ptr will point to a '\n', so next loop line counter+1 while(++ptr<res.size() && res[ptr]!='\n') {}
while(++ptr<res.size() && res[ptr]!='\n'); } else {
else
{
++column; ++column;
char c=res[ptr++]; char c=res[ptr++];
err.err("lexer",line,column,1,"invalid character 0x"+chrhex(c)); err.err("lexer",line,column,1,"invalid character 0x"+chrhex(c));

View File

@ -2,20 +2,17 @@
#include <cmath> #include <cmath>
void const_str(ast& root) void const_str(ast& root) {
{
auto& vec=root.child(); auto& vec=root.child();
root.set_str(vec[0].str()+vec[1].str()); root.set_str(vec[0].str()+vec[1].str());
root.child().clear(); root.child().clear();
root.set_type(ast_str); root.set_type(ast_str);
} }
void const_num(ast& root) void const_num(ast& root) {
{
auto& vec=root.child(); auto& vec=root.child();
f64 res=0; f64 res=0;
switch(root.type()) switch(root.type()) {
{
case ast_add: res=vec[0].num()+vec[1].num(); break; case ast_add: res=vec[0].num()+vec[1].num(); break;
case ast_sub: 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; 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; case ast_geq: res=vec[0].num()>=vec[1].num();break;
} }
// inf and nan will cause number hashmap error in codegen // 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; return;
}
root.set_num(res); root.set_num(res);
root.child().clear(); root.child().clear();
root.set_type(ast_num); root.set_type(ast_num);
} }
void calc_const(ast& root) void calc_const(ast& root) {
{
auto& vec=root.child(); auto& vec=root.child();
for(auto& i:vec) for(auto& i:vec) {
calc_const(i); 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(); f64 res=-vec[0].num();
root.set_num(res); root.set_num(res);
root.child().clear(); root.child().clear();
root.set_type(ast_num); root.set_type(ast_num);
return; return;
} }
if(vec.size()!=2) if (vec.size()!=2) {
return; 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_mult && root.type()!=ast_div &&
root.type()!=ast_link && root.type()!=ast_less && root.type()!=ast_link && root.type()!=ast_less &&
root.type()!=ast_leq && root.type()!=ast_grt && root.type()!=ast_leq && root.type()!=ast_grt &&
root.type()!=ast_geq) root.type()!=ast_geq) {
return; 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); const_str(root);
else if(root.type()!=ast_link && } else if (root.type()!=ast_link &&
vec[0].type()==ast_num && vec[1].type()==ast_num) vec[0].type()==ast_num && vec[1].type()==ast_num) {
const_num(root); const_num(root);
}
} }
void optimize(ast& root) void optimize(ast& root) {
{ for(auto& i:root.child()) {
for(auto& i:root.child())
calc_const(i); calc_const(i);
}
} }

View File

@ -37,8 +37,7 @@
`"` `"` `"` `"`
*/ */
class parse class parse {
{
#define thisline (toks[ptr].line) #define thisline (toks[ptr].line)
#define thiscol (toks[ptr].col) #define thiscol (toks[ptr].col)
#define thislen (toks[ptr].str.length()) #define thislen (toks[ptr].str.length())
@ -98,7 +97,7 @@ private:
}; };
void die(u32,u32,u32,string,bool); void die(u32,u32,u32,string,bool);
void next(){++ptr;}; void next() {++ptr;};
void match(u32 type,const char* info=nullptr); void match(u32 type,const char* info=nullptr);
bool lookahead(u32); bool lookahead(u32);
bool is_call(u32); bool is_call(u32);
@ -152,37 +151,37 @@ public:
parse(error& e): parse(error& e):
ptr(0),in_func(0),in_loop(0), ptr(0),in_func(0),in_loop(0),
toks(nullptr),root(0,0,ast_root), toks(nullptr),root(0,0,ast_root),
err(e){} err(e) {}
const error& compile(const lexer&); const error& compile(const lexer&);
ast& tree(){return root;} ast& tree() {return root;}
const ast& tree() const {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(); toks=lexer.result().data();
ptr=in_func=in_loop=0; ptr=in_func=in_loop=0;
root={0,0,ast_root}; root={0,0,ast_root};
while(!lookahead(tok_eof)){ while(!lookahead(tok_eof)) {
root.add(expr()); root.add(expr());
if(lookahead(tok_semi)){ if (lookahead(tok_semi)) {
match(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 // the last expression can be recognized without semi
die(thisline,thiscol,thislen,"expected \";\"",true); die(thisline,thiscol,thislen,"expected \";\"",true);
} }
} }
return err; 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 \" // tok_str's str has no \"
if(lookahead(tok_str)){ if (lookahead(tok_str)) {
col-=2; col-=2;
len+=2; len+=2;
} }
// used to report lack of ',' ';' // used to report lack of ',' ';'
if(prev && ptr){ if (prev && ptr) {
line=toks[ptr-1].line; line=toks[ptr-1].line;
col=toks[ptr-1].col; col=toks[ptr-1].col;
len=toks[ptr-1].str.length(); 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); err.err("parse",line,col,lookahead(tok_eof)?1:len,info);
} }
void parse::match(u32 type,const char* info)
{ void parse::match(u32 type,const char* info) {
if(!lookahead(type)){ if (!lookahead(type)) {
if(info){ if (info) {
die(thisline,thiscol,thislen,info); die(thisline,thiscol,thislen,info);
return; return;
} }
switch(type){ switch(type) {
case tok_num:die(thisline,thiscol,thislen,"expected number"); break; case tok_num:die(thisline,thiscol,thislen,"expected number"); break;
case tok_str:die(thisline,thiscol,thislen,"expected string"); break; case tok_str:die(thisline,thiscol,thislen,"expected string"); break;
case tok_id: die(thisline,thiscol,thislen,"expected identifier");break; case tok_id: die(thisline,thiscol,thislen,"expected identifier");break;
@ -205,34 +204,34 @@ void parse::match(u32 type,const char* info)
} }
return; return;
} }
if(lookahead(tok_eof)){ if (lookahead(tok_eof)) {
return; return;
} }
next(); next();
} }
bool parse::lookahead(u32 type)
{ bool parse::lookahead(u32 type) {
return toks[ptr].type==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; return type==tok_lcurve || type==tok_lbracket || type==tok_dot;
} }
bool parse::check_comma(const u32* panic_set)
{ bool parse::check_comma(const u32* panic_set) {
for(u32 i=0;panic_set[i];++i){ for(u32 i=0;panic_set[i];++i) {
if(lookahead(panic_set[i])){ if (lookahead(panic_set[i])) {
die(thisline,thiscol,thislen,"expected ',' between scalars",true); die(thisline,thiscol,thislen,"expected ',' between scalars",true);
return true; return true;
} }
} }
return false; return false;
} }
bool parse::check_tuple()
{ bool parse::check_tuple() {
u32 check_ptr=ptr,curve=1,bracket=0,brace=0; u32 check_ptr=ptr,curve=1,bracket=0,brace=0;
while(toks[++check_ptr].type!=tok_eof && curve){ while(toks[++check_ptr].type!=tok_eof && curve) {
switch(toks[check_ptr].type){ switch(toks[check_ptr].type) {
case tok_lcurve: ++curve; break; case tok_lcurve: ++curve; break;
case tok_lbracket: ++bracket; break; case tok_lbracket: ++bracket; break;
case tok_lbrace: ++brace; break; case tok_lbrace: ++brace; break;
@ -240,21 +239,21 @@ bool parse::check_tuple()
case tok_rbracket: --bracket; break; case tok_rbracket: --bracket; break;
case tok_rbrace: --brace; 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 true;
} }
} }
return false; return false;
} }
bool parse::check_func_end(const ast& node)
{ bool parse::check_func_end(const ast& node) {
u32 type=node.type(); u32 type=node.type();
if(type==ast_func){ if (type==ast_func) {
return true; 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; return false;
} }
if(node.child().empty() || ( if (node.child().empty() || (
type!=ast_def && type!=ast_def &&
type!=ast_equal && type!=ast_equal &&
type!=ast_addeq && type!=ast_addeq &&
@ -263,19 +262,19 @@ bool parse::check_func_end(const ast& node)
type!=ast_diveq && type!=ast_diveq &&
type!=ast_lnkeq type!=ast_lnkeq
) )
){ ) {
return false; return false;
}else{ } else {
return check_func_end(node.child().back()); return check_func_end(node.child().back());
} }
return false; 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); // special call means like this: function_name(a:1,b:2,c:3);
u32 check_ptr=ptr,curve=1,bracket=0,brace=0; u32 check_ptr=ptr,curve=1,bracket=0,brace=0;
while(toks[++check_ptr].type!=tok_eof && curve){ while(toks[++check_ptr].type!=tok_eof && curve) {
switch(toks[check_ptr].type){ switch(toks[check_ptr].type) {
case tok_lcurve: ++curve; break; case tok_lcurve: ++curve; break;
case tok_lbracket: ++bracket;break; case tok_lbracket: ++bracket;break;
case tok_lbrace: ++brace; break; case tok_lbrace: ++brace; break;
@ -284,54 +283,54 @@ bool parse::check_special_call()
case tok_rbrace: --brace; break; case tok_rbrace: --brace; break;
} }
// m?1:0 will be recognized as normal parameter // 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; 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 true;
} }
} }
return false; return false;
} }
bool parse::need_semi_check(const ast& node)
{ bool parse::need_semi_check(const ast& node) {
u32 type=node.type(); 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 false;
} }
return !check_func_end(node); return !check_func_end(node);
} }
ast parse::null()
{ ast parse::null() {
return {toks[ptr].line,toks[ptr].col,ast_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}; 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); ast node(toks[ptr].line,toks[ptr].col,ast_num);
node.set_num(str2num(toks[ptr].str.c_str())); node.set_num(str2num(toks[ptr].str.c_str()));
match(tok_num); match(tok_num);
return node; return node;
} }
ast parse::str()
{ ast parse::str() {
ast node(toks[ptr].line,toks[ptr].col,ast_str); ast node(toks[ptr].line,toks[ptr].col,ast_str);
node.set_str(toks[ptr].str); node.set_str(toks[ptr].str);
match(tok_str); match(tok_str);
return node; return node;
} }
ast parse::id()
{ ast parse::id() {
ast node(toks[ptr].line,toks[ptr].col,ast_id); ast node(toks[ptr].line,toks[ptr].col,ast_id);
node.set_str(toks[ptr].str); node.set_str(toks[ptr].str);
match(tok_id); match(tok_id);
return node; return node;
} }
ast parse::vec()
{ ast parse::vec() {
// panic set for this token is not ',' // panic set for this token is not ','
// this is the FIRST set of calculation // this is the FIRST set of calculation
// array end with tok_null=0 // array end with tok_null=0
@ -343,113 +342,113 @@ ast parse::vec()
}; };
ast node(toks[ptr].line,toks[ptr].col,ast_vec); ast node(toks[ptr].line,toks[ptr].col,ast_vec);
match(tok_lbracket); match(tok_lbracket);
while(!lookahead(tok_rbracket)){ while(!lookahead(tok_rbracket)) {
node.add(calc()); node.add(calc());
if(lookahead(tok_comma)){ if (lookahead(tok_comma)) {
match(tok_comma); match(tok_comma);
}else if(lookahead(tok_eof)){ } else if (lookahead(tok_eof)) {
break; break;
}else if(!lookahead(tok_rbracket) && !check_comma(panic_set)){ } else if (!lookahead(tok_rbracket) && !check_comma(panic_set)) {
break; break;
} }
} }
match(tok_rbracket,"expected ']' when generating vector"); match(tok_rbracket,"expected ']' when generating vector");
return node; return node;
} }
ast parse::hash()
{ ast parse::hash() {
ast node(toks[ptr].line,toks[ptr].col,ast_hash); ast node(toks[ptr].line,toks[ptr].col,ast_hash);
match(tok_lbrace); match(tok_lbrace);
while(!lookahead(tok_rbrace)){ while(!lookahead(tok_rbrace)) {
node.add(pair()); node.add(pair());
if(lookahead(tok_comma)){ if (lookahead(tok_comma)) {
match(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); die(thisline,thiscol,thislen,"expected ',' between hash members",true);
}else{ } else {
break; break;
} }
} }
match(tok_rbrace,"expected '}' when generating hash"); match(tok_rbrace,"expected '}' when generating hash");
return node; return node;
} }
ast parse::pair()
{ ast parse::pair() {
ast node(toks[ptr].line,toks[ptr].col,ast_pair); ast node(toks[ptr].line,toks[ptr].col,ast_pair);
if(lookahead(tok_id)){ if (lookahead(tok_id)) {
node.add(id()); node.add(id());
}else if(lookahead(tok_str)){ } else if (lookahead(tok_str)) {
node.add(str()); node.add(str());
}else{ } else {
match(tok_id,"expected hashmap key"); match(tok_id,"expected hashmap key");
} }
match(tok_colon); match(tok_colon);
node.add(calc()); node.add(calc());
return node; return node;
} }
ast parse::func()
{ ast parse::func() {
++in_func; ++in_func;
ast node(toks[ptr].line,toks[ptr].col,ast_func); ast node(toks[ptr].line,toks[ptr].col,ast_func);
match(tok_func); match(tok_func);
if(lookahead(tok_lcurve)){ if (lookahead(tok_lcurve)) {
node.add(params()); node.add(params());
}else{ } else {
node.add(null()); node.add(null());
} }
node.add(exprs()); node.add(exprs());
--in_func; --in_func;
return node; return node;
} }
ast parse::params()
{ ast parse::params() {
ast node(toks[ptr].line,toks[ptr].col,ast_params); ast node(toks[ptr].line,toks[ptr].col,ast_params);
match(tok_lcurve); match(tok_lcurve);
while(!lookahead(tok_rcurve)){ while(!lookahead(tok_rcurve)) {
ast tmp=id(); 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); ast special_arg(toks[ptr].line,toks[ptr].col,ast_null);
if(lookahead(tok_eq)){ if (lookahead(tok_eq)) {
match(tok_eq); match(tok_eq);
special_arg=std::move(tmp); special_arg=std::move(tmp);
special_arg.set_type(ast_default); special_arg.set_type(ast_default);
special_arg.add(calc()); special_arg.add(calc());
}else{ } else {
match(tok_ellipsis); match(tok_ellipsis);
special_arg=std::move(tmp); special_arg=std::move(tmp);
special_arg.set_type(ast_dynamic); special_arg.set_type(ast_dynamic);
} }
node.add(std::move(special_arg)); node.add(std::move(special_arg));
}else{ } else {
node.add(std::move(tmp)); node.add(std::move(tmp));
} }
if(lookahead(tok_comma)){ if (lookahead(tok_comma)) {
match(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); die(thisline,thiscol,thislen,"expected ',' between identifiers",true);
}else{ } else {
break; break;
} }
} }
match(tok_rcurve,"expected ')' after parameter list"); match(tok_rcurve,"expected ')' after parameter list");
return node; return node;
} }
ast parse::lcurve_expr()
{ ast parse::lcurve_expr() {
if(toks[ptr+1].type==tok_var) if (toks[ptr+1].type==tok_var)
return definition(); return definition();
return check_tuple()?multi_assgin():calc(); return check_tuple()?multi_assgin():calc();
} }
ast parse::expr() ast parse::expr()
{ {
u32 type=toks[ptr].type; 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"); 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"); die(thisline,thiscol,thislen,"must use return in functions");
} }
switch(type){ switch(type) {
case tok_nil: case tok_nil:
case tok_num: case tok_num:
case tok_str: case tok_str:
@ -477,36 +476,36 @@ ast parse::expr()
} }
return {toks[ptr].line,toks[ptr].col,ast_null}; return {toks[ptr].line,toks[ptr].col,ast_null};
} }
ast parse::exprs()
{ ast parse::exprs() {
if(lookahead(tok_eof)){ if (lookahead(tok_eof)) {
die(thisline,thiscol,thislen,"expected expression block"); die(thisline,thiscol,thislen,"expected expression block");
return null(); return null();
} }
ast node(toks[ptr].line,toks[ptr].col,ast_block); ast node(toks[ptr].line,toks[ptr].col,ast_block);
if(lookahead(tok_lbrace)){ if (lookahead(tok_lbrace)) {
match(tok_lbrace); match(tok_lbrace);
while(!lookahead(tok_rbrace) && !lookahead(tok_eof)){ while(!lookahead(tok_rbrace) && !lookahead(tok_eof)) {
node.add(expr()); node.add(expr());
if(lookahead(tok_semi)){ if (lookahead(tok_semi)) {
match(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 // the last expression can be recognized without semi
die(thisline,thiscol,thislen,"expected ';'",true); die(thisline,thiscol,thislen,"expected ';'",true);
} }
} }
match(tok_rbrace,"expected '}' when generating expressions"); match(tok_rbrace,"expected '}' when generating expressions");
}else{ } else {
node.add(expr()); node.add(expr());
if(lookahead(tok_semi)) if (lookahead(tok_semi))
match(tok_semi); match(tok_semi);
} }
return node; return node;
} }
ast parse::calc()
{ ast parse::calc() {
ast node=or_expr(); ast node=or_expr();
if(lookahead(tok_quesmark)){ if (lookahead(tok_quesmark)) {
// trinocular calculation // trinocular calculation
ast tmp(toks[ptr].line,toks[ptr].col,ast_trino); ast tmp(toks[ptr].line,toks[ptr].col,ast_trino);
match(tok_quesmark); match(tok_quesmark);
@ -515,7 +514,7 @@ ast parse::calc()
match(tok_colon); match(tok_colon);
tmp.add(calc()); tmp.add(calc());
node=std::move(tmp); 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 // 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); ast tmp(toks[ptr].line,toks[ptr].col,toks[ptr].type-tok_eq+ast_equal);
tmp.add(std::move(node)); tmp.add(std::move(node));
@ -525,10 +524,10 @@ ast parse::calc()
} }
return node; return node;
} }
ast parse::or_expr()
{ ast parse::or_expr() {
ast node=and_expr(); ast node=and_expr();
while(lookahead(tok_or)){ while(lookahead(tok_or)) {
ast tmp(toks[ptr].line,toks[ptr].col,ast_or); ast tmp(toks[ptr].line,toks[ptr].col,ast_or);
tmp.add(std::move(node)); tmp.add(std::move(node));
match(tok_or); match(tok_or);
@ -537,10 +536,10 @@ ast parse::or_expr()
} }
return node; return node;
} }
ast parse::and_expr()
{ ast parse::and_expr() {
ast node=cmp_expr(); ast node=cmp_expr();
while(lookahead(tok_and)){ while(lookahead(tok_and)) {
ast tmp(toks[ptr].line,toks[ptr].col,ast_and); ast tmp(toks[ptr].line,toks[ptr].col,ast_and);
tmp.add(std::move(node)); tmp.add(std::move(node));
match(tok_and); match(tok_and);
@ -549,10 +548,10 @@ ast parse::and_expr()
} }
return node; return node;
} }
ast parse::cmp_expr()
{ ast parse::cmp_expr() {
ast node=additive_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 // 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); ast tmp(toks[ptr].line,toks[ptr].col,toks[ptr].type-tok_cmpeq+ast_cmpeq);
tmp.add(std::move(node)); tmp.add(std::move(node));
@ -562,12 +561,12 @@ ast parse::cmp_expr()
} }
return node; return node;
} }
ast parse::additive_expr()
{ ast parse::additive_expr() {
ast node=multive_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); 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_add: tmp.set_type(ast_add); break;
case tok_sub: tmp.set_type(ast_sub); break; case tok_sub: tmp.set_type(ast_sub); break;
case tok_link: tmp.set_type(ast_link); break; case tok_link: tmp.set_type(ast_link); break;
@ -579,10 +578,10 @@ ast parse::additive_expr()
} }
return node; return node;
} }
ast parse::multive_expr()
{ ast parse::multive_expr() {
ast node=(lookahead(tok_sub) || lookahead(tok_not))?unary():scalar(); 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); ast tmp(toks[ptr].line,toks[ptr].col,toks[ptr].type-tok_mult+ast_mult);
tmp.add(std::move(node)); tmp.add(std::move(node));
match(toks[ptr].type); match(toks[ptr].type);
@ -591,62 +590,62 @@ ast parse::multive_expr()
} }
return node; return node;
} }
ast parse::unary()
{ ast parse::unary() {
ast node(toks[ptr].line,toks[ptr].col,ast_null); 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_sub:node.set_type(ast_neg);match(tok_sub);break;
case tok_not:node.set_type(ast_not);match(tok_not);break; case tok_not:node.set_type(ast_not);match(tok_not);break;
} }
node.add((lookahead(tok_sub) || lookahead(tok_not))?unary():scalar()); node.add((lookahead(tok_sub) || lookahead(tok_not))?unary():scalar());
return node; return node;
} }
ast parse::scalar()
{ ast parse::scalar() {
ast node(toks[ptr].line,toks[ptr].col,ast_null); ast node(toks[ptr].line,toks[ptr].col,ast_null);
if(lookahead(tok_nil)){ if (lookahead(tok_nil)) {
node=nil(); node=nil();
match(tok_nil); match(tok_nil);
}else if(lookahead(tok_num)){ } else if (lookahead(tok_num)) {
node=num(); node=num();
}else if(lookahead(tok_str)){ } else if (lookahead(tok_str)) {
node=str(); node=str();
}else if(lookahead(tok_id)){ } else if (lookahead(tok_id)) {
node=id(); node=id();
}else if(lookahead(tok_func)){ } else if (lookahead(tok_func)) {
node=func(); node=func();
}else if(lookahead(tok_lbracket)){ } else if (lookahead(tok_lbracket)) {
node=vec(); node=vec();
}else if(lookahead(tok_lbrace)){ } else if (lookahead(tok_lbrace)) {
node=hash(); node=hash();
}else if(lookahead(tok_lcurve)){ } else if (lookahead(tok_lcurve)) {
match(tok_lcurve); match(tok_lcurve);
node=calc(); node=calc();
match(tok_rcurve); match(tok_rcurve);
}else if(lookahead(tok_var)){ } else if (lookahead(tok_var)) {
match(tok_var); match(tok_var);
node.set_type(ast_def); node.set_type(ast_def);
node.add(id()); node.add(id());
match(tok_eq); match(tok_eq);
node.add(calc()); node.add(calc());
}else{ } else {
die(thisline,thiscol,thislen,"expected scalar"); die(thisline,thiscol,thislen,"expected scalar");
return node; return node;
} }
// check call and avoid ambiguous syntax // 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); ast tmp=std::move(node);
node={toks[ptr].line,toks[ptr].col,ast_call}; node={toks[ptr].line,toks[ptr].col,ast_call};
node.add(std::move(tmp)); node.add(std::move(tmp));
while(is_call(toks[ptr].type)){ while(is_call(toks[ptr].type)) {
node.add(call_scalar()); node.add(call_scalar());
} }
} }
return node; return node;
} }
ast parse::call_scalar()
{ ast parse::call_scalar() {
switch(toks[ptr].type){ switch(toks[ptr].type) {
case tok_lcurve: return callf(); break; case tok_lcurve: return callf(); break;
case tok_lbracket: return callv(); break; case tok_lbracket: return callv(); break;
case tok_dot: return callh(); break; case tok_dot: return callh(); break;
@ -654,16 +653,16 @@ ast parse::call_scalar()
// should never run this expression // should never run this expression
return {toks[ptr].line,toks[ptr].col,ast_nil}; 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); ast node(toks[ptr].line,toks[ptr].col,ast_callh);
match(tok_dot); match(tok_dot);
node.set_str(toks[ptr].str); node.set_str(toks[ptr].str);
match(tok_id,"expected hashmap key"); // get key match(tok_id,"expected hashmap key"); // get key
return node; return node;
} }
ast parse::callv()
{ ast parse::callv() {
// panic set for this token is not ',' // panic set for this token is not ','
// this is the FIRST set of subvec // this is the FIRST set of subvec
// array end with tok_null=0 // array end with tok_null=0
@ -676,24 +675,24 @@ ast parse::callv()
}; };
ast node(toks[ptr].line,toks[ptr].col,ast_callv); ast node(toks[ptr].line,toks[ptr].col,ast_callv);
match(tok_lbracket); match(tok_lbracket);
while(!lookahead(tok_rbracket)){ while(!lookahead(tok_rbracket)) {
node.add(subvec()); node.add(subvec());
if(lookahead(tok_comma)){ if (lookahead(tok_comma)) {
match(tok_comma); match(tok_comma);
}else if(lookahead(tok_eof)){ } else if (lookahead(tok_eof)) {
break; break;
}else if(!lookahead(tok_rbracket) && !check_comma(panic_set)){ } else if (!lookahead(tok_rbracket) && !check_comma(panic_set)) {
break; break;
} }
} }
if(node.size()==0){ if (node.size()==0) {
die(node.line(),node.col(),1,"expected index value"); die(node.line(),node.col(),1,"expected index value");
} }
match(tok_rbracket,"expected ']' when calling vector"); match(tok_rbracket,"expected ']' when calling vector");
return node; return node;
} }
ast parse::callf()
{ ast parse::callf() {
// panic set for this token is not ',' // panic set for this token is not ','
// this is the FIRST set of calculation/hashmember // this is the FIRST set of calculation/hashmember
// array end with tok_null=0 // array end with tok_null=0
@ -706,22 +705,22 @@ ast parse::callf()
ast node(toks[ptr].line,toks[ptr].col,ast_callf); ast node(toks[ptr].line,toks[ptr].col,ast_callf);
bool special_call=check_special_call(); bool special_call=check_special_call();
match(tok_lcurve); match(tok_lcurve);
while(!lookahead(tok_rcurve)){ while(!lookahead(tok_rcurve)) {
node.add(special_call?pair():calc()); node.add(special_call?pair():calc());
if(lookahead(tok_comma)) if (lookahead(tok_comma))
match(tok_comma); match(tok_comma);
else if(lookahead(tok_eof)) else if (lookahead(tok_eof))
break; break;
else if(!lookahead(tok_rcurve) && !check_comma(panic_set)) else if (!lookahead(tok_rcurve) && !check_comma(panic_set))
break; break;
} }
match(tok_rcurve,"expected ')' when calling function"); match(tok_rcurve,"expected ')' when calling function");
return node; return node;
} }
ast parse::subvec()
{ ast parse::subvec() {
ast node=lookahead(tok_colon)?nil():calc(); ast node=lookahead(tok_colon)?nil():calc();
if(lookahead(tok_colon)){ if (lookahead(tok_colon)) {
ast tmp(node.line(),node.col(),ast_subvec); ast tmp(node.line(),node.col(),ast_subvec);
match(tok_colon); match(tok_colon);
tmp.add(std::move(node)); tmp.add(std::move(node));
@ -730,63 +729,63 @@ ast parse::subvec()
} }
return node; return node;
} }
ast parse::definition()
{ ast parse::definition() {
ast node(toks[ptr].line,toks[ptr].col,ast_def); ast node(toks[ptr].line,toks[ptr].col,ast_def);
if(lookahead(tok_var)){ if (lookahead(tok_var)) {
match(tok_var); match(tok_var);
switch(toks[ptr].type){ switch(toks[ptr].type) {
case tok_id: node.add(id());break; case tok_id: node.add(id());break;
case tok_lcurve: node.add(outcurve_def());break; case tok_lcurve: node.add(outcurve_def());break;
default: die(thisline,thiscol,thislen,"expected identifier");break; default: die(thisline,thiscol,thislen,"expected identifier");break;
} }
}else if(lookahead(tok_lcurve)){ } else if (lookahead(tok_lcurve)) {
node.add(incurve_def()); node.add(incurve_def());
} }
match(tok_eq); match(tok_eq);
if(lookahead(tok_lcurve)){ if (lookahead(tok_lcurve)) {
node.add(check_tuple()?multi_scalar():calc()); node.add(check_tuple()?multi_scalar():calc());
}else{ } else {
node.add(calc()); node.add(calc());
} }
return node; return node;
} }
ast parse::incurve_def()
{ ast parse::incurve_def() {
match(tok_lcurve); match(tok_lcurve);
match(tok_var); match(tok_var);
ast node=multi_id(); ast node=multi_id();
match(tok_rcurve); match(tok_rcurve);
return node; return node;
} }
ast parse::outcurve_def()
{ ast parse::outcurve_def() {
match(tok_lcurve); match(tok_lcurve);
ast node=multi_id(); ast node=multi_id();
match(tok_rcurve); match(tok_rcurve);
return node; return node;
} }
ast parse::multi_id()
{ ast parse::multi_id() {
ast node(toks[ptr].line,toks[ptr].col,ast_multi_id); ast node(toks[ptr].line,toks[ptr].col,ast_multi_id);
while(!lookahead(tok_eof)){ while(!lookahead(tok_eof)) {
node.add(id()); 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 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"); die(tmp.line(),tmp.col(),1,"cannot call identifier in multi-definition");
} }
if(lookahead(tok_comma)){ if (lookahead(tok_comma)) {
match(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); die(thisline,thiscol,thislen,"expected ',' between identifiers",true);
}else{ } else {
break; break;
} }
} }
return node; 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 // if check_call_memory is true,we will check if value called here can reach a memory space
const u32 panic_set[]={ const u32 panic_set[]={
tok_id,tok_str,tok_num, tok_id,tok_str,tok_num,
@ -796,40 +795,40 @@ ast parse::multi_scalar()
}; };
ast node(toks[ptr].line,toks[ptr].col,ast_tuple); ast node(toks[ptr].line,toks[ptr].col,ast_tuple);
match(tok_lcurve); match(tok_lcurve);
while(!lookahead(tok_rcurve)){ while(!lookahead(tok_rcurve)) {
node.add(calc()); node.add(calc());
if(lookahead(tok_comma)){ if (lookahead(tok_comma)) {
match(tok_comma); match(tok_comma);
}else if(lookahead(tok_eof)){ } else if (lookahead(tok_eof)) {
break; break;
}else if(!lookahead(tok_rcurve) && !check_comma(panic_set)){ } else if (!lookahead(tok_rcurve) && !check_comma(panic_set)) {
break; break;
} }
} }
match(tok_rcurve,"expected ')' after multi-scalar"); match(tok_rcurve,"expected ')' after multi-scalar");
return node; return node;
} }
ast parse::multi_assgin()
{ ast parse::multi_assgin() {
ast node(toks[ptr].line,toks[ptr].col,ast_multi_assign); ast node(toks[ptr].line,toks[ptr].col,ast_multi_assign);
node.add(multi_scalar()); node.add(multi_scalar());
match(tok_eq); match(tok_eq);
if(lookahead(tok_eof)){ if (lookahead(tok_eof)) {
die(thisline,thiscol,thislen,"expected value list"); die(thisline,thiscol,thislen,"expected value list");
return node; return node;
} }
if(lookahead(tok_lcurve)){ if (lookahead(tok_lcurve)) {
node.add(check_tuple()?multi_scalar():calc()); node.add(check_tuple()?multi_scalar():calc());
}else{ } else {
node.add(calc()); node.add(calc());
} }
return node; return node;
} }
ast parse::loop()
{ ast parse::loop() {
++in_loop; ++in_loop;
ast node(0,0,ast_null); ast node(0,0,ast_null);
switch(toks[ptr].type){ switch(toks[ptr].type) {
case tok_while: node=while_loop(); break; case tok_while: node=while_loop(); break;
case tok_for: node=for_loop(); break; case tok_for: node=for_loop(); break;
case tok_forindex: case tok_forindex:
@ -838,8 +837,8 @@ ast parse::loop()
--in_loop; --in_loop;
return node; return node;
} }
ast parse::while_loop()
{ ast parse::while_loop() {
ast node(toks[ptr].line,toks[ptr].col,ast_while); ast node(toks[ptr].line,toks[ptr].col,ast_while);
match(tok_while); match(tok_while);
match(tok_lcurve); match(tok_lcurve);
@ -848,64 +847,64 @@ ast parse::while_loop()
node.add(exprs()); node.add(exprs());
return node; return node;
} }
ast parse::for_loop()
{ ast parse::for_loop() {
ast node(toks[ptr].line,toks[ptr].col,ast_for); ast node(toks[ptr].line,toks[ptr].col,ast_for);
match(tok_for); match(tok_for);
match(tok_lcurve); match(tok_lcurve);
// first expression // first expression
if(lookahead(tok_eof)){ if (lookahead(tok_eof)) {
die(thisline,thiscol,thislen,"expected definition"); die(thisline,thiscol,thislen,"expected definition");
} }
if(lookahead(tok_semi)){ if (lookahead(tok_semi)) {
node.add(null()); node.add(null());
}else if(lookahead(tok_var)){ } else if (lookahead(tok_var)) {
node.add(definition()); node.add(definition());
}else if(lookahead(tok_lcurve)){ } else if (lookahead(tok_lcurve)) {
node.add(lcurve_expr()); node.add(lcurve_expr());
}else{ } else {
node.add(calc()); node.add(calc());
} }
match(tok_semi,"expected ';' in for(;;)"); match(tok_semi,"expected ';' in for(;;)");
// conditional expression // conditional expression
if(lookahead(tok_eof)){ if (lookahead(tok_eof)) {
die(thisline,thiscol,thislen,"expected conditional expr"); die(thisline,thiscol,thislen,"expected conditional expr");
} }
if(lookahead(tok_semi)){ if (lookahead(tok_semi)) {
node.add(null()); node.add(null());
}else{ } else {
node.add(calc()); node.add(calc());
} }
match(tok_semi,"expected ';' in for(;;)"); match(tok_semi,"expected ';' in for(;;)");
//after loop expression //after loop expression
if(lookahead(tok_eof)){ if (lookahead(tok_eof)) {
die(thisline,thiscol,thislen,"expected calculation"); die(thisline,thiscol,thislen,"expected calculation");
} }
if(lookahead(tok_rcurve)){ if (lookahead(tok_rcurve)) {
node.add(null()); node.add(null());
}else{ } else {
node.add(calc()); node.add(calc());
} }
match(tok_rcurve); match(tok_rcurve);
node.add(exprs()); node.add(exprs());
return node; return node;
} }
ast parse::forei_loop()
{ ast parse::forei_loop() {
ast node(toks[ptr].line,toks[ptr].col,ast_null); 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_forindex:node.set_type(ast_forindex);match(tok_forindex);break;
case tok_foreach: node.set_type(ast_foreach); match(tok_foreach); break; case tok_foreach: node.set_type(ast_foreach); match(tok_foreach); break;
} }
match(tok_lcurve); match(tok_lcurve);
// first expression // first expression
// foreach/forindex must have an iterator to loop through // 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"); die(thisline,thiscol,thislen,"expected iterator");
} }
node.add(iter_gen()); node.add(iter_gen());
match(tok_semi,"expected ';' in foreach/forindex(iter;vector)"); match(tok_semi,"expected ';' in foreach/forindex(iter;vector)");
if(lookahead(tok_eof)){ if (lookahead(tok_eof)) {
die(thisline,thiscol,thislen,"expected vector"); die(thisline,thiscol,thislen,"expected vector");
} }
node.add(calc()); node.add(calc());
@ -913,24 +912,24 @@ ast parse::forei_loop()
node.add(exprs()); node.add(exprs());
return node; return node;
} }
ast parse::iter_gen()
{ ast parse::iter_gen() {
ast node(toks[ptr].line,toks[ptr].col,ast_null); ast node(toks[ptr].line,toks[ptr].col,ast_null);
if(lookahead(tok_var)){ if (lookahead(tok_var)) {
match(tok_var); match(tok_var);
node.set_type(ast_iter); node.set_type(ast_iter);
node.add(id()); node.add(id());
}else{ } else {
node.set_type(ast_call); node.set_type(ast_call);
node.add(id()); node.add(id());
while(is_call(toks[ptr].type)){ while(is_call(toks[ptr].type)) {
node.add(call_scalar()); node.add(call_scalar());
} }
} }
return node; return node;
} }
ast parse::cond()
{ ast parse::cond() {
ast node(toks[ptr].line,toks[ptr].col,ast_cond); ast node(toks[ptr].line,toks[ptr].col,ast_cond);
ast ifnode(toks[ptr].line,toks[ptr].col,ast_if); ast ifnode(toks[ptr].line,toks[ptr].col,ast_if);
match(tok_if); match(tok_if);
@ -939,7 +938,7 @@ ast parse::cond()
match(tok_rcurve); match(tok_rcurve);
ifnode.add(exprs()); ifnode.add(exprs());
node.add(std::move(ifnode)); node.add(std::move(ifnode));
while(lookahead(tok_elsif)){ while(lookahead(tok_elsif)) {
ast elsifnode(toks[ptr].line,toks[ptr].col,ast_elsif); ast elsifnode(toks[ptr].line,toks[ptr].col,ast_elsif);
match(tok_elsif); match(tok_elsif);
match(tok_lcurve); match(tok_lcurve);
@ -948,7 +947,7 @@ ast parse::cond()
elsifnode.add(exprs()); elsifnode.add(exprs());
node.add(std::move(elsifnode)); node.add(std::move(elsifnode));
} }
if(lookahead(tok_else)){ if (lookahead(tok_else)) {
ast elsenode(toks[ptr].line,toks[ptr].col,ast_else); ast elsenode(toks[ptr].line,toks[ptr].col,ast_else);
match(tok_else); match(tok_else);
elsenode.add(exprs()); elsenode.add(exprs());
@ -956,27 +955,27 @@ ast parse::cond()
} }
return node; return node;
} }
ast parse::continue_expr()
{ ast parse::continue_expr() {
ast node(toks[ptr].line,toks[ptr].col,ast_continue); ast node(toks[ptr].line,toks[ptr].col,ast_continue);
match(tok_continue); match(tok_continue);
return node; return node;
} }
ast parse::break_expr()
{ ast parse::break_expr() {
ast node(toks[ptr].line,toks[ptr].col,ast_break); ast node(toks[ptr].line,toks[ptr].col,ast_break);
match(tok_break); match(tok_break);
return node; return node;
} }
ast parse::ret_expr()
{ ast parse::ret_expr() {
ast node(toks[ptr].line,toks[ptr].col,ast_ret); ast node(toks[ptr].line,toks[ptr].col,ast_ret);
match(tok_ret); match(tok_ret);
u32 type=toks[ptr].type; 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_func || type==tok_sub || type==tok_not || type==tok_lcurve ||
type==tok_lbracket || type==tok_lbrace type==tok_lbracket || type==tok_lbrace
){ ) {
node.add(calc()); node.add(calc());
} }
return node; return node;

File diff suppressed because it is too large Load Diff

View File

@ -24,7 +24,7 @@ var compare=func(){
if(cmp(res,_md5(s))){ if(cmp(res,_md5(s))){
die("error: "~str(i)); die("error: "~str(i));
} }
print(" ",bar.bar((i-begin+1)/total)," (",i-begin+1,"/",total,")\t",res," byte: ",byte," time: ",timestamp.elapsedMSec()," \r"); print(" ",bar.bar((i-begin+1)/total)," (",i-begin+1,"/",total,")\t",res," byte: ",int(byte/1024),"k time: ",timestamp.elapsedMSec()," \r");
} }
print("\n"); print("\n");
}; };
@ -87,7 +87,7 @@ var filechecksum=func(){
if(cmp(res,_md5(f))){ if(cmp(res,_md5(f))){
die("error: "~files[i]); die("error: "~files[i]);
} }
print(" ",bar.bar((i+1)/total)," (",i+1,"/",total,")\t",res," byte: ",byte," time: ",timestamp.elapsedMSec()," \r"); print(" ",bar.bar((i+1)/total)," (",i+1,"/",total,")\t",res," byte: ",int(byte/1024),"k time: ",timestamp.elapsedMSec()," \r");
} }
print("\n"); print("\n");
} }

View File

@ -13,8 +13,8 @@ var ppm=func(filename,width,height,RGB){
io.close(fd); io.close(fd);
} }
var width=1280; var width=1920;
var height=720; var height=1080;
var bar=(os.platform()=="windows")? var bar=(os.platform()=="windows")?
process_bar.bar(front:"sharp",back:"point",sep:"line",length:50): process_bar.bar(front:"sharp",back:"point",sep:"line",length:50):
process_bar.high_resolution_bar(50); process_bar.high_resolution_bar(50);
@ -23,7 +23,7 @@ var f=func(i,j){
var (yDel,xDel)=(yMax-yMin,xMax-xMin); var (yDel,xDel)=(yMax-yMin,xMax-xMin);
var (y,x)=((i/height)*yDel+yMin,(j/width)*xDel+xMin); var (y,x)=((i/height)*yDel+yMin,(j/width)*xDel+xMin);
var (x0,y0)=(x,y); var (x0,y0)=(x,y);
for(var iter=0;iter<25;iter+=1){ for(var iter=0;iter<64;iter+=1){
var (x1,y1)=((x0*x0)-(y0*y0)+x,2*x0*y0+y); var (x1,y1)=((x0*x0)-(y0*y0)+x,2*x0*y0+y);
(x0,y0)=(x1,y1); (x0,y0)=(x1,y1);
if((x0*x0)+(y0*y0)>4){ if((x0*x0)+(y0*y0)>4){
@ -31,9 +31,11 @@ var f=func(i,j){
} }
} }
var progress=(i*width+j+1)/(width*height); 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); iter=iter==25?255:int(iter/25*255);
return iter~" "~iter~" "~iter~" "; return iter~" "~iter~" "~iter~" ";
} }
ppm("a.ppm",width,height,f); ppm("a.ppm",width,height,f);
println("\nfinished."); println();