🎨 change code format
This commit is contained in:
parent
54969681fc
commit
4c5ffb0240
61
main.cpp
61
main.cpp
|
@ -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;
|
||||||
}
|
}
|
86
makefile
86
makefile
|
@ -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
|
|
@ -2,24 +2,28 @@
|
||||||
#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;
|
||||||
|
|
|
@ -39,8 +39,9 @@ public:
|
||||||
#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);
|
||||||
|
@ -78,8 +79,9 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
127
nasal.h
127
nasal.h
|
@ -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 ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline f64 oct2f(const char* str) {
|
||||||
|
f64 ret=0;
|
||||||
|
while('0'<=*str && *str<'8') {
|
||||||
|
ret=ret*8+(*str++-'0');
|
||||||
|
}
|
||||||
|
if (*str) {
|
||||||
return nan("");
|
return nan("");
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
inline f64 oct2f(const char* str)
|
|
||||||
{
|
|
||||||
f64 ret=0;
|
|
||||||
while('0'<=*str && *str<'8')
|
|
||||||
ret=ret*8+(*str++-'0');
|
|
||||||
if(*str) return nan("");
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
50
nasal_ast.h
50
nasal_ast.h
|
@ -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;
|
||||||
|
@ -166,16 +165,14 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
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
|
||||||
|
|
690
nasal_builtin.h
690
nasal_builtin.h
File diff suppressed because it is too large
Load Diff
647
nasal_codegen.h
647
nasal_codegen.h
File diff suppressed because it is too large
Load Diff
131
nasal_dbg.h
131
nasal_dbg.h
|
@ -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;
|
||||||
|
@ -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,13 +80,11 @@ 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]});
|
||||||
}
|
}
|
||||||
|
@ -96,111 +92,108 @@ void debugger::callsort(const u64* arr)
|
||||||
[](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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void debugger::run(
|
void debugger::run(
|
||||||
const codegen& gen,
|
const codegen& gen,
|
||||||
|
@ -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,8 +276,7 @@ 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);
|
||||||
}
|
}
|
||||||
|
@ -295,8 +284,9 @@ void debugger::run(
|
||||||
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];\
|
||||||
}
|
}
|
||||||
|
|
73
nasal_err.h
73
nasal_err.h
|
@ -7,8 +7,7 @@
|
||||||
|
|
||||||
#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);
|
||||||
|
@ -16,8 +15,7 @@ struct for_reset
|
||||||
} 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,15 +69,13 @@ 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 {
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
346
nasal_gc.h
346
nasal_gc.h
|
@ -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;
|
||||||
|
@ -117,8 +113,7 @@ 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;
|
||||||
|
|
||||||
|
@ -129,8 +124,7 @@ struct nas_vec
|
||||||
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;
|
||||||
|
|
||||||
|
@ -141,8 +135,7 @@ struct nas_hash
|
||||||
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
|
||||||
|
@ -155,8 +148,7 @@ struct nas_func
|
||||||
void clear();
|
void clear();
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nas_upval
|
struct nas_upval {
|
||||||
{
|
|
||||||
bool onstk;
|
bool onstk;
|
||||||
u32 size;
|
u32 size;
|
||||||
var* stk;
|
var* stk;
|
||||||
|
@ -167,34 +159,30 @@ struct nas_upval
|
||||||
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
|
||||||
|
@ -204,30 +192,26 @@ private:
|
||||||
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,10 +420,9 @@ 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;
|
||||||
|
@ -460,10 +435,11 @@ std::ostream& operator<<(std::ostream& out,var& ref)
|
||||||
}
|
}
|
||||||
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 var* var::addr () {return val.addr; }
|
||||||
inline u32 var::ret () {return val.ret; }
|
inline u32 var::ret () {return val.ret; }
|
||||||
inline i64& var::cnt () {return val.cnt; }
|
inline i64& var::cnt () {return val.cnt; }
|
||||||
|
@ -480,11 +456,9 @@ 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;
|
||||||
|
@ -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};
|
||||||
}
|
}
|
||||||
|
|
102
nasal_import.h
102
nasal_import.h
|
@ -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&&);
|
||||||
|
@ -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,21 +195,19 @@ 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);
|
||||||
file_head.set_num(fileindex);
|
file_head.set_num(fileindex);
|
||||||
|
@ -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};
|
||||||
|
|
216
nasal_lexer.h
216
nasal_lexer.h
|
@ -61,8 +61,7 @@ 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;
|
||||||
|
@ -71,8 +70,7 @@ struct token
|
||||||
: 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;
|
||||||
|
@ -148,38 +146,31 @@ public:
|
||||||
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();
|
|
||||||
if(str.length()<3)// "0x"
|
|
||||||
err.err("lexer",line,column,str.length(),"invalid number `"+str+"`");
|
|
||||||
return str;
|
|
||||||
}
|
}
|
||||||
// generate oct number
|
column+=str.length();
|
||||||
else if(ptr+1<res.size() && res[ptr]=='0' && res[ptr+1]=='o')
|
if (str.length()<3) { // "0x"
|
||||||
{
|
err.err("lexer",line,column,str.length(),"invalid number `"+str+"`");
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
} else if (ptr+1<res.size() && res[ptr]=='0' && res[ptr+1]=='o') { // generate oct number
|
||||||
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));
|
||||||
|
|
40
nasal_opt.h
40
nasal_opt.h
|
@ -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 &&
|
if (root.type()==ast_link &&
|
||||||
vec[0].type()==ast_str && vec[1].type()==ast_str)
|
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);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
203
nasal_parse.h
203
nasal_parse.h
|
@ -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())
|
||||||
|
@ -157,8 +156,8 @@ public:
|
||||||
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;
|
||||||
|
|
||||||
|
@ -174,8 +173,8 @@ const error& parse::compile(const lexer& lexer)
|
||||||
}
|
}
|
||||||
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;
|
||||||
|
@ -190,8 +189,8 @@ 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);
|
||||||
|
@ -210,16 +209,16 @@ void parse::match(u32 type,const char* info)
|
||||||
}
|
}
|
||||||
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);
|
||||||
|
@ -228,8 +227,8 @@ bool parse::check_comma(const u32* panic_set)
|
||||||
}
|
}
|
||||||
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) {
|
||||||
|
@ -246,8 +245,8 @@ bool parse::check_tuple()
|
||||||
}
|
}
|
||||||
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;
|
||||||
|
@ -270,8 +269,8 @@ bool parse::check_func_end(const ast& node)
|
||||||
}
|
}
|
||||||
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) {
|
||||||
|
@ -293,45 +292,45 @@ bool parse::check_special_call()
|
||||||
}
|
}
|
||||||
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
|
||||||
|
@ -356,8 +355,8 @@ ast parse::vec()
|
||||||
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)) {
|
||||||
|
@ -373,8 +372,8 @@ ast parse::hash()
|
||||||
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());
|
||||||
|
@ -387,8 +386,8 @@ ast parse::pair()
|
||||||
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);
|
||||||
|
@ -401,8 +400,8 @@ ast parse::func()
|
||||||
--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)) {
|
||||||
|
@ -434,8 +433,8 @@ ast parse::params()
|
||||||
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();
|
||||||
|
@ -477,8 +476,8 @@ 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();
|
||||||
|
@ -503,8 +502,8 @@ ast parse::exprs()
|
||||||
}
|
}
|
||||||
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
|
||||||
|
@ -525,8 +524,8 @@ 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);
|
||||||
|
@ -537,8 +536,8 @@ 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);
|
||||||
|
@ -549,8 +548,8 @@ 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
|
||||||
|
@ -562,8 +561,8 @@ 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);
|
||||||
|
@ -579,8 +578,8 @@ 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);
|
||||||
|
@ -591,8 +590,8 @@ 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;
|
||||||
|
@ -601,8 +600,8 @@ ast parse::unary()
|
||||||
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();
|
||||||
|
@ -644,8 +643,8 @@ ast parse::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;
|
||||||
|
@ -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
|
||||||
|
@ -692,8 +691,8 @@ ast parse::callv()
|
||||||
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
|
||||||
|
@ -718,8 +717,8 @@ ast parse::callf()
|
||||||
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);
|
||||||
|
@ -730,8 +729,8 @@ 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);
|
||||||
|
@ -751,23 +750,23 @@ ast parse::definition()
|
||||||
}
|
}
|
||||||
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());
|
||||||
|
@ -785,8 +784,8 @@ ast parse::multi_id()
|
||||||
}
|
}
|
||||||
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,
|
||||||
|
@ -809,8 +808,8 @@ ast parse::multi_scalar()
|
||||||
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);
|
||||||
|
@ -825,8 +824,8 @@ ast parse::multi_assgin()
|
||||||
}
|
}
|
||||||
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) {
|
||||||
|
@ -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,8 +847,8 @@ 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);
|
||||||
|
@ -890,8 +889,8 @@ ast parse::for_loop()
|
||||||
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;
|
||||||
|
@ -913,8 +912,8 @@ 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);
|
||||||
|
@ -929,8 +928,8 @@ ast parse::iter_gen()
|
||||||
}
|
}
|
||||||
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);
|
||||||
|
@ -956,20 +955,20 @@ 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;
|
||||||
|
|
503
nasal_vm.h
503
nasal_vm.h
|
@ -4,8 +4,7 @@
|
||||||
#include <stack>
|
#include <stack>
|
||||||
#include "nasal_codegen.h"
|
#include "nasal_codegen.h"
|
||||||
|
|
||||||
class vm
|
class vm {
|
||||||
{
|
|
||||||
protected:
|
protected:
|
||||||
/* registers and constants of vm */
|
/* registers and constants of vm */
|
||||||
u32 pc; // program counter
|
u32 pc; // program counter
|
||||||
|
@ -144,8 +143,7 @@ void vm::init(
|
||||||
const std::vector<f64>& nums,
|
const std::vector<f64>& nums,
|
||||||
const std::vector<opcode>& code,
|
const std::vector<opcode>& code,
|
||||||
const std::vector<string>& filenames,
|
const std::vector<string>& filenames,
|
||||||
const std::vector<string>& argv)
|
const std::vector<string>& argv) {
|
||||||
{
|
|
||||||
ngc.init(strs,argv);
|
ngc.init(strs,argv);
|
||||||
cnum=nums.data();
|
cnum=nums.data();
|
||||||
cstr=strs.data();
|
cstr=strs.data();
|
||||||
|
@ -160,15 +158,15 @@ void vm::init(
|
||||||
top=stack;
|
top=stack;
|
||||||
|
|
||||||
/* clear main stack */
|
/* clear main stack */
|
||||||
for(u32 i=0;i<STACK_DEPTH;++i)
|
for(u32 i=0;i<STACK_DEPTH;++i) {
|
||||||
stack[i]=nil;
|
stack[i]=nil;
|
||||||
}
|
}
|
||||||
void vm::valinfo(var& val)
|
}
|
||||||
{
|
|
||||||
|
void vm::valinfo(var& val) {
|
||||||
const nas_val* p=val.val.gcobj;
|
const nas_val* p=val.val.gcobj;
|
||||||
std::cout<<"\t";
|
std::cout<<"\t";
|
||||||
switch(val.type)
|
switch(val.type) {
|
||||||
{
|
|
||||||
case vm_none: std::cout<<"| null |";break;
|
case vm_none: std::cout<<"| null |";break;
|
||||||
case vm_ret: std::cout<<"| pc | 0x"<<std::hex
|
case vm_ret: std::cout<<"| pc | 0x"<<std::hex
|
||||||
<<val.ret()<<std::dec;break;
|
<<val.ret()<<std::dec;break;
|
||||||
|
@ -201,35 +199,36 @@ void vm::valinfo(var& val)
|
||||||
}
|
}
|
||||||
std::cout<<"\n";
|
std::cout<<"\n";
|
||||||
}
|
}
|
||||||
void vm::traceback()
|
|
||||||
{
|
void vm::traceback() {
|
||||||
/* bytecode[0].num is the global size */
|
/* bytecode[0].num is the global size */
|
||||||
var* bottom=ngc.stack==stack?stack+bytecode[0].num:ngc.stack;
|
var* bottom=ngc.stack==stack?stack+bytecode[0].num:ngc.stack;
|
||||||
var* ctx_top=ngc.stack==stack?top:ngc.top;
|
var* ctx_top=ngc.stack==stack?top:ngc.top;
|
||||||
std::stack<u32> ret;
|
std::stack<u32> ret;
|
||||||
for(var* i=bottom;i<=ctx_top;++i)
|
for(var* i=bottom;i<=ctx_top;++i) {
|
||||||
if(i->type==vm_ret && i->ret()!=0)
|
if (i->type==vm_ret && i->ret()!=0) {
|
||||||
ret.push(i->ret());
|
ret.push(i->ret());
|
||||||
|
}
|
||||||
|
}
|
||||||
ret.push(pc); // store the position program crashed
|
ret.push(pc); // store the position program crashed
|
||||||
std::cout<<"trace back ("<<(ngc.stack==stack?"main":"coroutine")<<")\n";
|
std::cout<<"trace back ("<<(ngc.stack==stack?"main":"coroutine")<<")\n";
|
||||||
for(u32 p=0,same=0,prev=0xffffffff;!ret.empty();prev=p,ret.pop())
|
for(u32 p=0,same=0,prev=0xffffffff;!ret.empty();prev=p,ret.pop()) {
|
||||||
{
|
if ((p=ret.top())==prev) {
|
||||||
if((p=ret.top())==prev)
|
|
||||||
{
|
|
||||||
++same;
|
++same;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if(same)
|
if (same) {
|
||||||
std::cout
|
std::cout
|
||||||
<<" 0x"<<std::hex<<std::setw(8)<<std::setfill('0')
|
<<" 0x"<<std::hex<<std::setw(8)<<std::setfill('0')
|
||||||
<<prev<<std::dec<<" "<<same<<" same call(s)\n";
|
<<prev<<std::dec<<" "<<same<<" same call(s)\n";
|
||||||
|
}
|
||||||
same=0;
|
same=0;
|
||||||
std::cout<<" "<<codestream(bytecode[p],p,cnum,cstr,files)<<"\n";
|
std::cout<<" "<<codestream(bytecode[p],p,cnum,cstr,files)<<"\n";
|
||||||
}
|
}
|
||||||
// the first called place has no same calls
|
// the first called place has no same calls
|
||||||
}
|
}
|
||||||
void vm::stackinfo(const u32 limit=10)
|
|
||||||
{
|
void vm::stackinfo(const u32 limit=10) {
|
||||||
/* bytecode[0].num is the global size */
|
/* bytecode[0].num is the global size */
|
||||||
const u32 gsize=ngc.stack==stack?bytecode[0].num:0;
|
const u32 gsize=ngc.stack==stack?bytecode[0].num:0;
|
||||||
var* t=top;
|
var* t=top;
|
||||||
|
@ -237,16 +236,15 @@ void vm::stackinfo(const u32 limit=10)
|
||||||
std::cout<<"vm stack (0x"<<std::hex<<(u64)bottom<<std::dec
|
std::cout<<"vm stack (0x"<<std::hex<<(u64)bottom<<std::dec
|
||||||
<<" <sp+"<<gsize<<">, limit "<<limit<<", total "
|
<<" <sp+"<<gsize<<">, limit "<<limit<<", total "
|
||||||
<<(t<bottom? 0:(i64)(t-bottom+1))<<")\n";
|
<<(t<bottom? 0:(i64)(t-bottom+1))<<")\n";
|
||||||
for(u32 i=0;i<limit && t>=bottom;++i,--t)
|
for(u32 i=0;i<limit && t>=bottom;++i,--t) {
|
||||||
{
|
|
||||||
std::cout<<" 0x"<<std::hex
|
std::cout<<" 0x"<<std::hex
|
||||||
<<std::setw(8)<<std::setfill('0')
|
<<std::setw(8)<<std::setfill('0')
|
||||||
<<(u64)(t-ngc.stack)<<std::dec;
|
<<(u64)(t-ngc.stack)<<std::dec;
|
||||||
valinfo(t[0]);
|
valinfo(t[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void vm::reginfo()
|
|
||||||
{
|
void vm::reginfo() {
|
||||||
std::cout<<"registers ("<<(ngc.cort?"coroutine":"main")<<")\n"<<std::hex
|
std::cout<<"registers ("<<(ngc.cort?"coroutine":"main")<<")\n"<<std::hex
|
||||||
<<" [ pc ] | pc | 0x"<<pc<<"\n"
|
<<" [ pc ] | pc | 0x"<<pc<<"\n"
|
||||||
<<" [ global ] | addr | 0x"<<(u64)stack<<"\n"
|
<<" [ global ] | addr | 0x"<<(u64)stack<<"\n"
|
||||||
|
@ -258,64 +256,64 @@ void vm::reginfo()
|
||||||
std::cout<<" [ funcr ]";valinfo(funcr);
|
std::cout<<" [ funcr ]";valinfo(funcr);
|
||||||
std::cout<<" [ upvalr ]";valinfo(upvalr);
|
std::cout<<" [ upvalr ]";valinfo(upvalr);
|
||||||
}
|
}
|
||||||
void vm::gstate()
|
|
||||||
{
|
void vm::gstate() {
|
||||||
if(!bytecode[0].num || stack[0].type==vm_none) // bytecode[0].op is op_intg
|
if (!bytecode[0].num || stack[0].type==vm_none) { // bytecode[0].op is op_intg
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
std::cout<<"global (0x"<<std::hex<<(u64)stack<<" <sp+0>)\n"<<std::dec;
|
std::cout<<"global (0x"<<std::hex<<(u64)stack<<" <sp+0>)\n"<<std::dec;
|
||||||
for(u32 i=0;i<bytecode[0].num;++i)
|
for(u32 i=0;i<bytecode[0].num;++i) {
|
||||||
{
|
|
||||||
std::cout<<" 0x"<<std::hex<<std::setw(8)
|
std::cout<<" 0x"<<std::hex<<std::setw(8)
|
||||||
<<std::setfill('0')<<i<<std::dec;
|
<<std::setfill('0')<<i<<std::dec;
|
||||||
valinfo(stack[i]);
|
valinfo(stack[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void vm::lstate()
|
|
||||||
{
|
void vm::lstate() {
|
||||||
if(!localr || !funcr.func().lsize)
|
if (!localr || !funcr.func().lsize) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
const u32 lsize=funcr.func().lsize;
|
const u32 lsize=funcr.func().lsize;
|
||||||
std::cout<<"local (0x"<<std::hex<<(u64)localr
|
std::cout<<"local (0x"<<std::hex<<(u64)localr
|
||||||
<<" <sp+"<<(u64)(localr-ngc.stack)<<">)\n"<<std::dec;
|
<<" <sp+"<<(u64)(localr-ngc.stack)<<">)\n"<<std::dec;
|
||||||
for(u32 i=0;i<lsize;++i)
|
for(u32 i=0;i<lsize;++i) {
|
||||||
{
|
|
||||||
std::cout<<" 0x"<<std::hex<<std::setw(8)
|
std::cout<<" 0x"<<std::hex<<std::setw(8)
|
||||||
<<std::setfill('0')<<i<<std::dec;
|
<<std::setfill('0')<<i<<std::dec;
|
||||||
valinfo(localr[i]);
|
valinfo(localr[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void vm::ustate()
|
|
||||||
{
|
void vm::ustate() {
|
||||||
if(funcr.type==vm_nil || funcr.func().upval.empty())
|
if (funcr.type==vm_nil || funcr.func().upval.empty()) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
std::cout<<"upvalue\n";
|
std::cout<<"upvalue\n";
|
||||||
auto& upval=funcr.func().upval;
|
auto& upval=funcr.func().upval;
|
||||||
for(u32 i=0;i<upval.size();++i)
|
for(u32 i=0;i<upval.size();++i) {
|
||||||
{
|
|
||||||
std::cout<<" -> upval["<<i<<"]:\n";
|
std::cout<<" -> upval["<<i<<"]:\n";
|
||||||
auto& uv=upval[i].upval();
|
auto& uv=upval[i].upval();
|
||||||
for(u32 j=0;j<uv.size;++j)
|
for(u32 j=0;j<uv.size;++j) {
|
||||||
{
|
|
||||||
std::cout<<" 0x"<<std::hex<<std::setw(8)
|
std::cout<<" 0x"<<std::hex<<std::setw(8)
|
||||||
<<std::setfill('0')<<j<<std::dec;
|
<<std::setfill('0')<<j<<std::dec;
|
||||||
valinfo(uv[j]);
|
valinfo(uv[j]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void vm::detail()
|
|
||||||
{
|
void vm::detail() {
|
||||||
reginfo();
|
reginfo();
|
||||||
gstate();
|
gstate();
|
||||||
lstate();
|
lstate();
|
||||||
ustate();
|
ustate();
|
||||||
}
|
}
|
||||||
void vm::die(const string& str)
|
|
||||||
{
|
void vm::die(const string& str) {
|
||||||
std::cout<<"[vm] error: "<<str<<"\n";
|
std::cout<<"[vm] error: "<<str<<"\n";
|
||||||
traceback();
|
traceback();
|
||||||
stackinfo();
|
stackinfo();
|
||||||
if(verbose)
|
if (verbose) {
|
||||||
detail();
|
detail();
|
||||||
|
}
|
||||||
if (ngc.stack==stack) {
|
if (ngc.stack==stack) {
|
||||||
std::exit(1);
|
std::exit(1);
|
||||||
} else {
|
} else {
|
||||||
|
@ -324,78 +322,77 @@ void vm::die(const string& str)
|
||||||
top[0]=nil;
|
top[0]=nil;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inline bool vm::cond(var& val)
|
|
||||||
{
|
inline bool vm::cond(var& val) {
|
||||||
if(val.type==vm_num)
|
if (val.type==vm_num) {
|
||||||
return val.num();
|
return val.num();
|
||||||
else if(val.type==vm_str)
|
} else if (val.type==vm_str) {
|
||||||
{
|
|
||||||
const f64 num=str2num(val.str().c_str());
|
const f64 num=str2num(val.str().c_str());
|
||||||
return std::isnan(num)?!val.str().empty():num;
|
return std::isnan(num)?!val.str().empty():num;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
inline void vm::o_intg()
|
|
||||||
{
|
inline void vm::o_intg() {
|
||||||
// global values store on stack
|
// global values store on stack
|
||||||
top+=imm[pc];
|
top+=imm[pc];
|
||||||
--top;// point to the top
|
--top;// point to the top
|
||||||
}
|
}
|
||||||
inline void vm::o_intl()
|
|
||||||
{
|
inline void vm::o_intl() {
|
||||||
top[0].func().local.resize(imm[pc],nil);
|
top[0].func().local.resize(imm[pc],nil);
|
||||||
top[0].func().lsize=imm[pc];
|
top[0].func().lsize=imm[pc];
|
||||||
}
|
}
|
||||||
inline void vm::o_loadg()
|
|
||||||
{
|
inline void vm::o_loadg() {
|
||||||
stack[imm[pc]]=(top--)[0];
|
stack[imm[pc]]=(top--)[0];
|
||||||
}
|
}
|
||||||
inline void vm::o_loadl()
|
|
||||||
{
|
inline void vm::o_loadl() {
|
||||||
localr[imm[pc]]=(top--)[0];
|
localr[imm[pc]]=(top--)[0];
|
||||||
}
|
}
|
||||||
inline void vm::o_loadu()
|
|
||||||
{
|
inline void vm::o_loadu() {
|
||||||
funcr.func().upval[(imm[pc]>>16)&0xffff]
|
funcr.func().upval[(imm[pc]>>16)&0xffff]
|
||||||
.upval()[imm[pc]&0xffff]=(top--)[0];
|
.upval()[imm[pc]&0xffff]=(top--)[0];
|
||||||
}
|
}
|
||||||
inline void vm::o_pnum()
|
|
||||||
{
|
inline void vm::o_pnum() {
|
||||||
(++top)[0]={vm_num,cnum[imm[pc]]};
|
(++top)[0]={vm_num,cnum[imm[pc]]};
|
||||||
}
|
}
|
||||||
inline void vm::o_pnil()
|
|
||||||
{
|
inline void vm::o_pnil() {
|
||||||
(++top)[0]=nil;
|
(++top)[0]=nil;
|
||||||
}
|
}
|
||||||
inline void vm::o_pstr()
|
|
||||||
{
|
inline void vm::o_pstr() {
|
||||||
(++top)[0]=ngc.strs[imm[pc]];
|
(++top)[0]=ngc.strs[imm[pc]];
|
||||||
}
|
}
|
||||||
inline void vm::o_newv()
|
|
||||||
{
|
inline void vm::o_newv() {
|
||||||
var newv=ngc.alloc(vm_vec);
|
var newv=ngc.alloc(vm_vec);
|
||||||
auto& vec=newv.vec().elems;
|
auto& vec=newv.vec().elems;
|
||||||
vec.resize(imm[pc]);
|
vec.resize(imm[pc]);
|
||||||
// use top-=imm[pc]-1 here will cause error if imm[pc] is 0
|
// use top-=imm[pc]-1 here will cause error if imm[pc] is 0
|
||||||
top=top-imm[pc]+1;
|
top=top-imm[pc]+1;
|
||||||
for(u32 i=0;i<imm[pc];++i)
|
for(u32 i=0;i<imm[pc];++i) {
|
||||||
vec[i]=top[i];
|
vec[i]=top[i];
|
||||||
|
}
|
||||||
top[0]=newv;
|
top[0]=newv;
|
||||||
}
|
}
|
||||||
inline void vm::o_newh()
|
|
||||||
{
|
inline void vm::o_newh() {
|
||||||
(++top)[0]=ngc.alloc(vm_hash);
|
(++top)[0]=ngc.alloc(vm_hash);
|
||||||
}
|
}
|
||||||
inline void vm::o_newf()
|
|
||||||
{
|
inline void vm::o_newf() {
|
||||||
(++top)[0]=ngc.alloc(vm_func);
|
(++top)[0]=ngc.alloc(vm_func);
|
||||||
nas_func& func=top[0].func();
|
nas_func& func=top[0].func();
|
||||||
func.entry=imm[pc];
|
func.entry=imm[pc];
|
||||||
func.psize=1;
|
func.psize=1;
|
||||||
|
|
||||||
/* this means you create a new function in local scope */
|
/* this means you create a new function in local scope */
|
||||||
if(localr)
|
if (localr) {
|
||||||
{
|
|
||||||
func.upval=funcr.func().upval;
|
func.upval=funcr.func().upval;
|
||||||
// function created in the same local scope shares one closure
|
// function created in the same local scope shares one closure
|
||||||
// so this size & stk setting has no problem
|
// so this size & stk setting has no problem
|
||||||
|
@ -406,50 +403,49 @@ inline void vm::o_newf()
|
||||||
upvalr=upval;
|
upvalr=upval;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inline void vm::o_happ()
|
|
||||||
{
|
inline void vm::o_happ() {
|
||||||
top[-1].hash().elems[cstr[imm[pc]]]=top[0];
|
top[-1].hash().elems[cstr[imm[pc]]]=top[0];
|
||||||
--top;
|
--top;
|
||||||
}
|
}
|
||||||
inline void vm::o_para()
|
|
||||||
{
|
inline void vm::o_para() {
|
||||||
nas_func& func=top[0].func();
|
nas_func& func=top[0].func();
|
||||||
// func->size has 1 place reserved for "me"
|
// func->size has 1 place reserved for "me"
|
||||||
func.keys[imm[pc]]=func.psize;
|
func.keys[imm[pc]]=func.psize;
|
||||||
func.local[func.psize++]={vm_none};
|
func.local[func.psize++]={vm_none};
|
||||||
}
|
}
|
||||||
inline void vm::o_deft()
|
|
||||||
{
|
inline void vm::o_deft() {
|
||||||
var val=top[0];
|
var val=top[0];
|
||||||
nas_func& func=(--top)[0].func();
|
nas_func& func=(--top)[0].func();
|
||||||
// func->size has 1 place reserved for "me"
|
// func->size has 1 place reserved for "me"
|
||||||
func.keys[imm[pc]]=func.psize;
|
func.keys[imm[pc]]=func.psize;
|
||||||
func.local[func.psize++]=val;
|
func.local[func.psize++]=val;
|
||||||
}
|
}
|
||||||
inline void vm::o_dyn()
|
|
||||||
{
|
inline void vm::o_dyn() {
|
||||||
top[0].func().dpara=imm[pc];
|
top[0].func().dpara=imm[pc];
|
||||||
}
|
}
|
||||||
inline void vm::o_unot()
|
|
||||||
{
|
inline void vm::o_unot() {
|
||||||
var val=top[0];
|
var val=top[0];
|
||||||
switch(val.type)
|
switch(val.type) {
|
||||||
{
|
|
||||||
case vm_nil:top[0]=one;break;
|
case vm_nil:top[0]=one;break;
|
||||||
case vm_num:top[0]=val.num()?zero:one;break;
|
case vm_num:top[0]=val.num()?zero:one;break;
|
||||||
case vm_str:
|
case vm_str:{
|
||||||
{
|
|
||||||
const f64 num=str2num(val.str().c_str());
|
const f64 num=str2num(val.str().c_str());
|
||||||
if(std::isnan(num))
|
if (std::isnan(num)) {
|
||||||
top[0]={vm_num,(f64)val.str().empty()};
|
top[0]={vm_num,(f64)val.str().empty()};
|
||||||
else
|
} else {
|
||||||
top[0]=num?zero:one;
|
top[0]=num?zero:one;
|
||||||
|
}
|
||||||
} break;
|
} break;
|
||||||
default:vm_error("incorrect value type");break;
|
default:vm_error("incorrect value type");break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inline void vm::o_usub()
|
|
||||||
{
|
inline void vm::o_usub() {
|
||||||
top[0]={vm_num,-top[0].tonum()};
|
top[0]={vm_num,-top[0].tonum()};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -461,8 +457,7 @@ inline void vm::o_add(){op_calc(+);}
|
||||||
inline void vm::o_sub() {op_calc(-);}
|
inline void vm::o_sub() {op_calc(-);}
|
||||||
inline void vm::o_mul() {op_calc(*);}
|
inline void vm::o_mul() {op_calc(*);}
|
||||||
inline void vm::o_div() {op_calc(/);}
|
inline void vm::o_div() {op_calc(/);}
|
||||||
inline void vm::o_lnk()
|
inline void vm::o_lnk() {
|
||||||
{
|
|
||||||
top[-1]=ngc.newstr(top[-1].tostr()+top[0].tostr());
|
top[-1]=ngc.newstr(top[-1].tostr()+top[0].tostr());
|
||||||
--top;
|
--top;
|
||||||
}
|
}
|
||||||
|
@ -474,8 +469,7 @@ inline void vm::o_addc(){op_calc_const(+);}
|
||||||
inline void vm::o_subc() {op_calc_const(-);}
|
inline void vm::o_subc() {op_calc_const(-);}
|
||||||
inline void vm::o_mulc() {op_calc_const(*);}
|
inline void vm::o_mulc() {op_calc_const(*);}
|
||||||
inline void vm::o_divc() {op_calc_const(/);}
|
inline void vm::o_divc() {op_calc_const(/);}
|
||||||
inline void vm::o_lnkc()
|
inline void vm::o_lnkc() {
|
||||||
{
|
|
||||||
top[0]=ngc.newstr(top[0].tostr()+cstr[imm[pc]]);
|
top[0]=ngc.newstr(top[0].tostr()+cstr[imm[pc]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -488,8 +482,7 @@ inline void vm::o_addeq(){op_calc_eq(+);}
|
||||||
inline void vm::o_subeq() {op_calc_eq(-);}
|
inline void vm::o_subeq() {op_calc_eq(-);}
|
||||||
inline void vm::o_muleq() {op_calc_eq(*);}
|
inline void vm::o_muleq() {op_calc_eq(*);}
|
||||||
inline void vm::o_diveq() {op_calc_eq(/);}
|
inline void vm::o_diveq() {op_calc_eq(/);}
|
||||||
inline void vm::o_lnkeq()
|
inline void vm::o_lnkeq() {
|
||||||
{
|
|
||||||
top[-1]=memr[0]=ngc.newstr(memr[0].tostr()+top[-1].tostr());
|
top[-1]=memr[0]=ngc.newstr(memr[0].tostr()+top[-1].tostr());
|
||||||
memr=nullptr;
|
memr=nullptr;
|
||||||
top-=imm[pc]+1;
|
top-=imm[pc]+1;
|
||||||
|
@ -504,15 +497,13 @@ inline void vm::o_addeqc(){op_calc_eq_const(+);}
|
||||||
inline void vm::o_subeqc() {op_calc_eq_const(-);}
|
inline void vm::o_subeqc() {op_calc_eq_const(-);}
|
||||||
inline void vm::o_muleqc() {op_calc_eq_const(*);}
|
inline void vm::o_muleqc() {op_calc_eq_const(*);}
|
||||||
inline void vm::o_diveqc() {op_calc_eq_const(/);}
|
inline void vm::o_diveqc() {op_calc_eq_const(/);}
|
||||||
inline void vm::o_lnkeqc()
|
inline void vm::o_lnkeqc() {
|
||||||
{
|
|
||||||
top[0]=memr[0]=ngc.newstr(memr[0].tostr()+cstr[imm[pc]&0x7fffffff]);
|
top[0]=memr[0]=ngc.newstr(memr[0].tostr()+cstr[imm[pc]&0x7fffffff]);
|
||||||
memr=nullptr;
|
memr=nullptr;
|
||||||
top-=(imm[pc]>>31);
|
top-=(imm[pc]>>31);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void vm::o_meq()
|
inline void vm::o_meq() {
|
||||||
{
|
|
||||||
// pop old memr[0] and replace it
|
// pop old memr[0] and replace it
|
||||||
// the reason why we should get memr and push the old value on stack
|
// the reason why we should get memr and push the old value on stack
|
||||||
// is that when lnkeq/lnkeqc is called, there will be
|
// is that when lnkeq/lnkeqc is called, there will be
|
||||||
|
@ -522,34 +513,36 @@ inline void vm::o_meq()
|
||||||
memr=nullptr;
|
memr=nullptr;
|
||||||
top-=imm[pc]+1;
|
top-=imm[pc]+1;
|
||||||
}
|
}
|
||||||
inline void vm::o_eq()
|
|
||||||
{
|
inline void vm::o_eq() {
|
||||||
var val2=top[0];
|
var val2=top[0];
|
||||||
var val1=(--top)[0];
|
var val1=(--top)[0];
|
||||||
if(val1.type==vm_nil && val2.type==vm_nil)
|
if (val1.type==vm_nil && val2.type==vm_nil) {
|
||||||
top[0]=one;
|
top[0]=one;
|
||||||
else if(val1.type==vm_str && val2.type==vm_str)
|
} else if (val1.type==vm_str && val2.type==vm_str) {
|
||||||
top[0]=(val1.str()==val2.str())?one:zero;
|
top[0]=(val1.str()==val2.str())?one:zero;
|
||||||
else if((val1.type==vm_num || val2.type==vm_num)
|
} else if ((val1.type==vm_num || val2.type==vm_num)
|
||||||
&& val1.type!=vm_nil && val2.type!=vm_nil)
|
&& val1.type!=vm_nil && val2.type!=vm_nil) {
|
||||||
top[0]=(val1.tonum()==val2.tonum())?one:zero;
|
top[0]=(val1.tonum()==val2.tonum())?one:zero;
|
||||||
else
|
} else {
|
||||||
top[0]=(val1==val2)?one:zero;
|
top[0]=(val1==val2)?one:zero;
|
||||||
}
|
}
|
||||||
inline void vm::o_neq()
|
}
|
||||||
{
|
|
||||||
|
inline void vm::o_neq() {
|
||||||
var val2=top[0];
|
var val2=top[0];
|
||||||
var val1=(--top)[0];
|
var val1=(--top)[0];
|
||||||
if(val1.type==vm_nil && val2.type==vm_nil)
|
if (val1.type==vm_nil && val2.type==vm_nil) {
|
||||||
top[0]=zero;
|
top[0]=zero;
|
||||||
else if(val1.type==vm_str && val2.type==vm_str)
|
} else if (val1.type==vm_str && val2.type==vm_str) {
|
||||||
top[0]=(val1.str()!=val2.str())?one:zero;
|
top[0]=(val1.str()!=val2.str())?one:zero;
|
||||||
else if((val1.type==vm_num || val2.type==vm_num)
|
} else if ((val1.type==vm_num || val2.type==vm_num)
|
||||||
&& val1.type!=vm_nil && val2.type!=vm_nil)
|
&& val1.type!=vm_nil && val2.type!=vm_nil) {
|
||||||
top[0]=(val1.tonum()!=val2.tonum())?one:zero;
|
top[0]=(val1.tonum()!=val2.tonum())?one:zero;
|
||||||
else
|
} else {
|
||||||
top[0]=(val1!=val2)?one:zero;
|
top[0]=(val1!=val2)?one:zero;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#define op_cmp(type)\
|
#define op_cmp(type)\
|
||||||
--top;\
|
--top;\
|
||||||
|
@ -568,154 +561,166 @@ inline void vm::o_leqc(){op_cmp_const(<=);}
|
||||||
inline void vm::o_grtc() {op_cmp_const(>);}
|
inline void vm::o_grtc() {op_cmp_const(>);}
|
||||||
inline void vm::o_geqc() {op_cmp_const(>=);}
|
inline void vm::o_geqc() {op_cmp_const(>=);}
|
||||||
|
|
||||||
inline void vm::o_pop()
|
inline void vm::o_pop() {
|
||||||
{
|
|
||||||
--top;
|
--top;
|
||||||
}
|
}
|
||||||
inline void vm::o_jmp()
|
|
||||||
{
|
inline void vm::o_jmp() {
|
||||||
pc=imm[pc]-1;
|
pc=imm[pc]-1;
|
||||||
}
|
}
|
||||||
inline void vm::o_jt()
|
|
||||||
{
|
inline void vm::o_jt() {
|
||||||
if(cond(top[0]))
|
// jump true needs to reserve the result on stack
|
||||||
|
// because conditional expression in nasal has return value
|
||||||
|
if (cond(top[0])) {
|
||||||
pc=imm[pc]-1;
|
pc=imm[pc]-1;
|
||||||
}
|
}
|
||||||
inline void vm::o_jf()
|
}
|
||||||
{
|
|
||||||
if(!cond(top[0]))
|
inline void vm::o_jf() {
|
||||||
|
// jump false doesn't need to reserve result
|
||||||
|
if (!cond(top[0])) {
|
||||||
pc=imm[pc]-1;
|
pc=imm[pc]-1;
|
||||||
|
}
|
||||||
--top;
|
--top;
|
||||||
}
|
}
|
||||||
inline void vm::o_cnt()
|
|
||||||
{
|
inline void vm::o_cnt() {
|
||||||
if(top[0].type!=vm_vec)
|
if (top[0].type!=vm_vec) {
|
||||||
vm_error("must use vector in forindex/foreach");
|
vm_error("must use vector in forindex/foreach");
|
||||||
|
}
|
||||||
(++top)[0]={vm_cnt,(i64)-1};
|
(++top)[0]={vm_cnt,(i64)-1};
|
||||||
}
|
}
|
||||||
inline void vm::o_findex()
|
|
||||||
{
|
inline void vm::o_findex() {
|
||||||
if((usize)(++top[0].cnt())>=top[-1].vec().size())
|
if ((usize)(++top[0].cnt())>=top[-1].vec().size()) {
|
||||||
{
|
|
||||||
pc=imm[pc]-1;
|
pc=imm[pc]-1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
top[1]={vm_num,(f64)top[0].cnt()};
|
top[1]={vm_num,(f64)top[0].cnt()};
|
||||||
++top;
|
++top;
|
||||||
}
|
}
|
||||||
inline void vm::o_feach()
|
|
||||||
{
|
inline void vm::o_feach() {
|
||||||
auto& ref=top[-1].vec().elems;
|
auto& ref=top[-1].vec().elems;
|
||||||
if((usize)(++top[0].cnt())>=ref.size())
|
if ((usize)(++top[0].cnt())>=ref.size()) {
|
||||||
{
|
|
||||||
pc=imm[pc]-1;
|
pc=imm[pc]-1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
top[1]=ref[top[0].cnt()];
|
top[1]=ref[top[0].cnt()];
|
||||||
++top;
|
++top;
|
||||||
}
|
}
|
||||||
inline void vm::o_callg()
|
|
||||||
{
|
inline void vm::o_callg() {
|
||||||
(++top)[0]=stack[imm[pc]];
|
(++top)[0]=stack[imm[pc]];
|
||||||
}
|
}
|
||||||
inline void vm::o_calll()
|
|
||||||
{
|
inline void vm::o_calll() {
|
||||||
(++top)[0]=localr[imm[pc]];
|
(++top)[0]=localr[imm[pc]];
|
||||||
}
|
}
|
||||||
inline void vm::o_upval()
|
|
||||||
{
|
inline void vm::o_upval() {
|
||||||
(++top)[0]=funcr.func().upval[(imm[pc]>>16)&0xffff]
|
(++top)[0]=funcr.func().upval[(imm[pc]>>16)&0xffff]
|
||||||
.upval()[imm[pc]&0xffff];
|
.upval()[imm[pc]&0xffff];
|
||||||
}
|
}
|
||||||
inline void vm::o_callv()
|
|
||||||
{
|
inline void vm::o_callv() {
|
||||||
var val=top[0];
|
var val=top[0];
|
||||||
var vec=(--top)[0];
|
var vec=(--top)[0];
|
||||||
if(vec.type==vm_vec)
|
if (vec.type==vm_vec) {
|
||||||
{
|
|
||||||
top[0]=vec.vec().get_val(val.tonum());
|
top[0]=vec.vec().get_val(val.tonum());
|
||||||
if(top[0].type==vm_none)
|
if (top[0].type==vm_none) {
|
||||||
vm_error("out of range:"+std::to_string(val.tonum()));
|
vm_error("out of range:"+std::to_string(val.tonum()));
|
||||||
}
|
}
|
||||||
else if(vec.type==vm_hash)
|
} else if (vec.type==vm_hash) {
|
||||||
{
|
if (val.type!=vm_str) {
|
||||||
if(val.type!=vm_str)
|
|
||||||
vm_error("must use string as the key");
|
vm_error("must use string as the key");
|
||||||
|
}
|
||||||
top[0]=vec.hash().get_val(val.str());
|
top[0]=vec.hash().get_val(val.str());
|
||||||
if(top[0].type==vm_none)
|
if (top[0].type==vm_none) {
|
||||||
vm_error("cannot find member \""+val.str()+"\"");
|
vm_error("cannot find member \""+val.str()+"\"");
|
||||||
if(top[0].type==vm_func)
|
} else if (top[0].type==vm_func) {
|
||||||
top[0].func().local[0]=val; // 'me'
|
top[0].func().local[0]=val; // 'me'
|
||||||
}
|
}
|
||||||
else if(vec.type==vm_str)
|
} else if (vec.type==vm_str) {
|
||||||
{
|
|
||||||
string& str=vec.str();
|
string& str=vec.str();
|
||||||
i32 num=val.tonum();
|
i32 num=val.tonum();
|
||||||
i32 len=str.length();
|
i32 len=str.length();
|
||||||
if(num<-len || num>=len)
|
if (num<-len || num>=len) {
|
||||||
vm_error("out of range:"+std::to_string(val.tonum()));
|
vm_error("out of range:"+std::to_string(val.tonum()));
|
||||||
top[0]={vm_num,f64((u8)str[num>=0? num:num+len])};
|
|
||||||
}
|
}
|
||||||
else
|
top[0]={vm_num,f64((u8)str[num>=0? num:num+len])};
|
||||||
|
} else {
|
||||||
vm_error("must call a vector/hash/string");
|
vm_error("must call a vector/hash/string");
|
||||||
}
|
}
|
||||||
inline void vm::o_callvi()
|
}
|
||||||
{
|
|
||||||
|
inline void vm::o_callvi() {
|
||||||
var val=top[0];
|
var val=top[0];
|
||||||
if(val.type!=vm_vec)
|
if (val.type!=vm_vec) {
|
||||||
vm_error("must use a vector");
|
vm_error("must use a vector");
|
||||||
|
}
|
||||||
// cannot use operator[],because this may cause overflow
|
// cannot use operator[],because this may cause overflow
|
||||||
(++top)[0]=val.vec().get_val(imm[pc]);
|
(++top)[0]=val.vec().get_val(imm[pc]);
|
||||||
if(top[0].type==vm_none)
|
if (top[0].type==vm_none) {
|
||||||
vm_error("out of range:"+std::to_string(imm[pc]));
|
vm_error("out of range:"+std::to_string(imm[pc]));
|
||||||
}
|
}
|
||||||
inline void vm::o_callh()
|
}
|
||||||
{
|
|
||||||
|
inline void vm::o_callh() {
|
||||||
var val=top[0];
|
var val=top[0];
|
||||||
if(val.type!=vm_hash)
|
if (val.type!=vm_hash) {
|
||||||
vm_error("must call a hash");
|
vm_error("must call a hash");
|
||||||
|
}
|
||||||
top[0]=val.hash().get_val(cstr[imm[pc]]);
|
top[0]=val.hash().get_val(cstr[imm[pc]]);
|
||||||
if(top[0].type==vm_none)
|
if (top[0].type==vm_none) {
|
||||||
vm_error("member \""+cstr[imm[pc]]+"\" does not exist");
|
vm_error("member \""+cstr[imm[pc]]+"\" does not exist");
|
||||||
if(top[0].type==vm_func)
|
} else if (top[0].type==vm_func) {
|
||||||
top[0].func().local[0]=val; // 'me'
|
top[0].func().local[0]=val; // 'me'
|
||||||
}
|
}
|
||||||
inline void vm::o_callfv()
|
}
|
||||||
{
|
|
||||||
|
inline void vm::o_callfv() {
|
||||||
u32 argc=imm[pc]; // arguments counter
|
u32 argc=imm[pc]; // arguments counter
|
||||||
var* local=top-argc+1; // arguments begin address
|
var* local=top-argc+1; // arguments begin address
|
||||||
if(local[-1].type!=vm_func)
|
if (local[-1].type!=vm_func) {
|
||||||
vm_error("must call a function");
|
vm_error("must call a function");
|
||||||
|
}
|
||||||
auto& func=local[-1].func();
|
auto& func=local[-1].func();
|
||||||
var tmp=local[-1];
|
var tmp=local[-1];
|
||||||
local[-1]=funcr;
|
local[-1]=funcr;
|
||||||
funcr=tmp;
|
funcr=tmp;
|
||||||
// top-argc+lsize(local) +1(old pc) +1(old localr) +1(old upvalr)
|
// top-argc+lsize(local) +1(old pc) +1(old localr) +1(old upvalr)
|
||||||
if(top-argc+func.lsize+3>=canary)
|
if (top-argc+func.lsize+3>=canary) {
|
||||||
vm_error("stack overflow");
|
vm_error("stack overflow");
|
||||||
|
}
|
||||||
// parameter size is func->psize-1, 1 is reserved for "me"
|
// parameter size is func->psize-1, 1 is reserved for "me"
|
||||||
u32 psize=func.psize-1;
|
u32 psize=func.psize-1;
|
||||||
if(argc<psize && func.local[argc+1].type==vm_none)
|
if (argc<psize && func.local[argc+1].type==vm_none) {
|
||||||
vm_error("lack argument(s)");
|
vm_error("lack argument(s)");
|
||||||
|
}
|
||||||
|
|
||||||
var dynamic=nil;
|
var dynamic=nil;
|
||||||
top=local+func.lsize;
|
top=local+func.lsize;
|
||||||
if(func.dpara>=0)// load dynamic arguments
|
if (func.dpara>=0) { // load dynamic arguments
|
||||||
{
|
|
||||||
dynamic=ngc.alloc(vm_vec);
|
dynamic=ngc.alloc(vm_vec);
|
||||||
for(u32 i=psize;i<argc;++i)
|
for(u32 i=psize;i<argc;++i) {
|
||||||
dynamic.vec().elems.push_back(local[i]);
|
dynamic.vec().elems.push_back(local[i]);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
u32 min_size=(std::min)(psize,argc); // avoid error in MSVC
|
u32 min_size=(std::min)(psize,argc); // avoid error in MSVC
|
||||||
for(u32 i=min_size;i>=1;--i)// load arguments
|
for(u32 i=min_size;i>=1;--i) { // load arguments
|
||||||
local[i]=local[i-1];
|
local[i]=local[i-1];
|
||||||
|
}
|
||||||
local[0]=func.local[0];// load "me"
|
local[0]=func.local[0];// load "me"
|
||||||
// load local scope & default arguments
|
// load local scope & default arguments
|
||||||
for(u32 i=min_size+1;i<func.lsize;++i)
|
for(u32 i=min_size+1;i<func.lsize;++i) {
|
||||||
local[i]=func.local[i];
|
local[i]=func.local[i];
|
||||||
if(func.dpara>=0)
|
}
|
||||||
|
if (func.dpara>=0) {
|
||||||
local[psize+1]=dynamic;
|
local[psize+1]=dynamic;
|
||||||
|
}
|
||||||
|
|
||||||
top[0]=upvalr;
|
top[0]=upvalr;
|
||||||
(++top)[0]={vm_addr,localr};
|
(++top)[0]={vm_addr,localr};
|
||||||
|
@ -724,34 +729,38 @@ inline void vm::o_callfv()
|
||||||
localr=local;
|
localr=local;
|
||||||
upvalr=nil;
|
upvalr=nil;
|
||||||
}
|
}
|
||||||
inline void vm::o_callfh()
|
|
||||||
{
|
inline void vm::o_callfh() {
|
||||||
auto& hash=top[0].hash().elems;
|
auto& hash=top[0].hash().elems;
|
||||||
if(top[-1].type!=vm_func)
|
if (top[-1].type!=vm_func) {
|
||||||
vm_error("must call a function");
|
vm_error("must call a function");
|
||||||
|
}
|
||||||
auto& func=top[-1].func();
|
auto& func=top[-1].func();
|
||||||
var tmp=top[-1];
|
var tmp=top[-1];
|
||||||
top[-1]=funcr;
|
top[-1]=funcr;
|
||||||
funcr=tmp;
|
funcr=tmp;
|
||||||
// top -1(hash) +lsize(local) +1(old pc) +1(old localr) +1(old upvalr)
|
// top -1(hash) +lsize(local) +1(old pc) +1(old localr) +1(old upvalr)
|
||||||
if(top+func.lsize+2>=canary)
|
if (top+func.lsize+2>=canary) {
|
||||||
vm_error("stack overflow");
|
vm_error("stack overflow");
|
||||||
if(func.dpara>=0)
|
}
|
||||||
|
if (func.dpara>=0) {
|
||||||
vm_error("special call cannot use dynamic argument");
|
vm_error("special call cannot use dynamic argument");
|
||||||
|
}
|
||||||
|
|
||||||
var* local=top;
|
var* local=top;
|
||||||
top+=func.lsize;
|
top+=func.lsize;
|
||||||
for(u32 i=0;i<func.lsize;++i)
|
for(u32 i=0;i<func.lsize;++i) {
|
||||||
local[i]=func.local[i];
|
local[i]=func.local[i];
|
||||||
|
}
|
||||||
|
|
||||||
for(auto& i:func.keys)
|
for(auto& i:func.keys) {
|
||||||
{
|
|
||||||
auto& key=cstr[i.first];
|
auto& key=cstr[i.first];
|
||||||
if(hash.count(key))
|
if (hash.count(key)) {
|
||||||
local[i.second]=hash[key];
|
local[i.second]=hash[key];
|
||||||
else if(local[i.second].type==vm_none)
|
} else if (local[i.second].type==vm_none) {
|
||||||
vm_error("lack argument(s): \""+key+"\"");
|
vm_error("lack argument(s): \""+key+"\"");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
top[0]=upvalr;
|
top[0]=upvalr;
|
||||||
(++top)[0]={vm_addr,localr};
|
(++top)[0]={vm_addr,localr};
|
||||||
|
@ -760,8 +769,8 @@ inline void vm::o_callfh()
|
||||||
localr=local;
|
localr=local;
|
||||||
upvalr=nil;
|
upvalr=nil;
|
||||||
}
|
}
|
||||||
inline void vm::o_callb()
|
|
||||||
{
|
inline void vm::o_callb() {
|
||||||
// reserve place for builtin function return,
|
// reserve place for builtin function return,
|
||||||
// in fact this code is changed because of coroutine
|
// in fact this code is changed because of coroutine
|
||||||
(++top)[0]=nil;
|
(++top)[0]=nil;
|
||||||
|
@ -769,35 +778,38 @@ inline void vm::o_callb()
|
||||||
// because if running a builtin function about coroutine
|
// because if running a builtin function about coroutine
|
||||||
// (top) will be set to another context.top, instead of main_context.top
|
// (top) will be set to another context.top, instead of main_context.top
|
||||||
top[0]=(*builtin[imm[pc]].func)(localr,ngc);
|
top[0]=(*builtin[imm[pc]].func)(localr,ngc);
|
||||||
if(top[0].type==vm_none)
|
if (top[0].type==vm_none) {
|
||||||
vm_error("native function error");
|
vm_error("native function error");
|
||||||
}
|
}
|
||||||
inline void vm::o_slcbeg()
|
}
|
||||||
{
|
|
||||||
|
inline void vm::o_slcbeg() {
|
||||||
// +--------------+
|
// +--------------+
|
||||||
// | slice_vector | <-- top[0]
|
// | slice_vector | <-- top[0]
|
||||||
// +--------------+
|
// +--------------+
|
||||||
// | resource_vec | <-- top[-1]
|
// | resource_vec | <-- top[-1]
|
||||||
// +--------------+
|
// +--------------+
|
||||||
(++top)[0]=ngc.alloc(vm_vec);
|
(++top)[0]=ngc.alloc(vm_vec);
|
||||||
if(top[-1].type!=vm_vec)
|
if (top[-1].type!=vm_vec) {
|
||||||
vm_error("must slice a vector");
|
vm_error("must slice a vector");
|
||||||
}
|
}
|
||||||
inline void vm::o_slcend()
|
}
|
||||||
{
|
|
||||||
|
inline void vm::o_slcend() {
|
||||||
top[-1]=top[0];
|
top[-1]=top[0];
|
||||||
--top;
|
--top;
|
||||||
}
|
}
|
||||||
inline void vm::o_slc()
|
|
||||||
{
|
inline void vm::o_slc() {
|
||||||
var val=(top--)[0];
|
var val=(top--)[0];
|
||||||
var res=top[-1].vec().get_val(val.tonum());
|
var res=top[-1].vec().get_val(val.tonum());
|
||||||
if(res.type==vm_none)
|
if (res.type==vm_none) {
|
||||||
vm_error("out of range:"+std::to_string(val.tonum()));
|
vm_error("out of range:"+std::to_string(val.tonum()));
|
||||||
|
}
|
||||||
top[0].vec().elems.push_back(res);
|
top[0].vec().elems.push_back(res);
|
||||||
}
|
}
|
||||||
inline void vm::o_slc2()
|
|
||||||
{
|
inline void vm::o_slc2() {
|
||||||
var val2=(top--)[0];
|
var val2=(top--)[0];
|
||||||
var val1=(top--)[0];
|
var val1=(top--)[0];
|
||||||
auto& ref=top[-1].vec().elems;
|
auto& ref=top[-1].vec().elems;
|
||||||
|
@ -807,15 +819,14 @@ inline void vm::o_slc2()
|
||||||
i32 num1=val1.tonum();
|
i32 num1=val1.tonum();
|
||||||
i32 num2=val2.tonum();
|
i32 num2=val2.tonum();
|
||||||
i32 size=ref.size();
|
i32 size=ref.size();
|
||||||
if(type1==vm_nil && type2==vm_nil)
|
if (type1==vm_nil && type2==vm_nil) {
|
||||||
{
|
|
||||||
num1=0;
|
num1=0;
|
||||||
num2=size-1;
|
num2=size-1;
|
||||||
}
|
} else if (type1==vm_nil && type2!=vm_nil) {
|
||||||
else if(type1==vm_nil && type2!=vm_nil)
|
|
||||||
num1=num2<0? -size:0;
|
num1=num2<0? -size:0;
|
||||||
else if(type1!=vm_nil && type2==vm_nil)
|
} else if (type1!=vm_nil && type2==vm_nil) {
|
||||||
num2=num1<0? -1:size-1;
|
num2=num1<0? -1:size-1;
|
||||||
|
}
|
||||||
|
|
||||||
if (num1<-size || num1>=size || num2<-size || num2>=size) {
|
if (num1<-size || num1>=size || num2<-size || num2>=size) {
|
||||||
vm_error("index "+std::to_string(num1)+":"+std::to_string(num2)+" out of range.");
|
vm_error("index "+std::to_string(num1)+":"+std::to_string(num2)+" out of range.");
|
||||||
|
@ -824,67 +835,67 @@ inline void vm::o_slc2()
|
||||||
aim.push_back(i>=0?ref[i]:ref[i+size]);
|
aim.push_back(i>=0?ref[i]:ref[i+size]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inline void vm::o_mcallg()
|
|
||||||
{
|
inline void vm::o_mcallg() {
|
||||||
memr=stack+imm[pc];
|
memr=stack+imm[pc];
|
||||||
(++top)[0]=memr[0];
|
(++top)[0]=memr[0];
|
||||||
// push value in this memory space on stack
|
// push value in this memory space on stack
|
||||||
// to avoid being garbage collected
|
// to avoid being garbage collected
|
||||||
}
|
}
|
||||||
inline void vm::o_mcalll()
|
|
||||||
{
|
inline void vm::o_mcalll() {
|
||||||
memr=localr+imm[pc];
|
memr=localr+imm[pc];
|
||||||
(++top)[0]=memr[0];
|
(++top)[0]=memr[0];
|
||||||
// push value in this memory space on stack
|
// push value in this memory space on stack
|
||||||
// to avoid being garbage collected
|
// to avoid being garbage collected
|
||||||
}
|
}
|
||||||
inline void vm::o_mupval()
|
|
||||||
{
|
inline void vm::o_mupval() {
|
||||||
memr=&(funcr.func().upval[(imm[pc]>>16)&0xffff].upval()[imm[pc]&0xffff]);
|
memr=&(funcr.func().upval[(imm[pc]>>16)&0xffff].upval()[imm[pc]&0xffff]);
|
||||||
(++top)[0]=memr[0];
|
(++top)[0]=memr[0];
|
||||||
// push value in this memory space on stack
|
// push value in this memory space on stack
|
||||||
// to avoid being garbage collected
|
// to avoid being garbage collected
|
||||||
}
|
}
|
||||||
inline void vm::o_mcallv()
|
|
||||||
{
|
inline void vm::o_mcallv() {
|
||||||
var val=top[0]; // index
|
var val=top[0]; // index
|
||||||
var vec=(--top)[0]; // mcall vector, reserved on stack to avoid gc
|
var vec=(--top)[0]; // mcall vector, reserved on stack to avoid gc
|
||||||
if(vec.type==vm_vec)
|
if (vec.type==vm_vec) {
|
||||||
{
|
|
||||||
memr=vec.vec().get_mem(val.tonum());
|
memr=vec.vec().get_mem(val.tonum());
|
||||||
if(!memr)
|
if (!memr) {
|
||||||
vm_error("out of range:"+std::to_string(val.tonum()));
|
vm_error("out of range:"+std::to_string(val.tonum()));
|
||||||
}else if(vec.type==vm_hash) // do mcallh but use the mcallv way
|
}
|
||||||
{
|
} else if (vec.type==vm_hash) { // do mcallh but use the mcallv way
|
||||||
if(val.type!=vm_str)
|
if (val.type!=vm_str) {
|
||||||
vm_error("must use string as the key");
|
vm_error("must use string as the key");
|
||||||
|
}
|
||||||
nas_hash& ref=vec.hash();
|
nas_hash& ref=vec.hash();
|
||||||
string& str=val.str();
|
string& str=val.str();
|
||||||
memr=ref.get_mem(str);
|
memr=ref.get_mem(str);
|
||||||
if(!memr)
|
if (!memr) {
|
||||||
{
|
|
||||||
ref.elems[str]=nil;
|
ref.elems[str]=nil;
|
||||||
memr=ref.get_mem(str);
|
memr=ref.get_mem(str);
|
||||||
}
|
}
|
||||||
}else
|
} else {
|
||||||
vm_error("cannot get memory space in this type");
|
vm_error("cannot get memory space in this type");
|
||||||
}
|
}
|
||||||
inline void vm::o_mcallh()
|
}
|
||||||
{
|
|
||||||
|
inline void vm::o_mcallh() {
|
||||||
var hash=top[0]; // mcall hash, reserved on stack to avoid gc
|
var hash=top[0]; // mcall hash, reserved on stack to avoid gc
|
||||||
if(hash.type!=vm_hash)
|
if (hash.type!=vm_hash) {
|
||||||
vm_error("must call a hash");
|
vm_error("must call a hash");
|
||||||
|
}
|
||||||
auto& ref=hash.hash();
|
auto& ref=hash.hash();
|
||||||
auto& str=cstr[imm[pc]];
|
auto& str=cstr[imm[pc]];
|
||||||
memr=ref.get_mem(str);
|
memr=ref.get_mem(str);
|
||||||
if(!memr) // create a new key
|
if (!memr) { // create a new key
|
||||||
{
|
|
||||||
ref.elems[str]=nil;
|
ref.elems[str]=nil;
|
||||||
memr=ref.get_mem(str);
|
memr=ref.get_mem(str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inline void vm::o_ret()
|
|
||||||
{
|
inline void vm::o_ret() {
|
||||||
/* +-------------+
|
/* +-------------+
|
||||||
* | return value| <- top[0]
|
* | return value| <- top[0]
|
||||||
* +-------------+
|
* +-------------+
|
||||||
|
@ -895,7 +906,6 @@ inline void vm::o_ret()
|
||||||
* | old upvalr | <- top[-3]
|
* | old upvalr | <- top[-3]
|
||||||
* +-------------+
|
* +-------------+
|
||||||
* | local scope |
|
* | local scope |
|
||||||
* | ... |
|
|
||||||
* +-------------+ <- local pointer stored in localr
|
* +-------------+ <- local pointer stored in localr
|
||||||
* | old funcr | <- old function stored in funcr
|
* | old funcr | <- old function stored in funcr
|
||||||
* +-------------+
|
* +-------------+
|
||||||
|
@ -913,8 +923,7 @@ inline void vm::o_ret()
|
||||||
funcr=top[0];
|
funcr=top[0];
|
||||||
top[0]=ret; // rewrite func with returned value
|
top[0]=ret; // rewrite func with returned value
|
||||||
|
|
||||||
if(up.type==vm_upval) // synchronize upvalue
|
if (up.type==vm_upval) { // synchronize upvalue
|
||||||
{
|
|
||||||
auto& upval=up.upval();
|
auto& upval=up.upval();
|
||||||
auto size=func.func().lsize;
|
auto size=func.func().lsize;
|
||||||
upval.onstk=false;
|
upval.onstk=false;
|
||||||
|
@ -923,20 +932,19 @@ inline void vm::o_ret()
|
||||||
}
|
}
|
||||||
// cannot use gc.cort to judge,
|
// cannot use gc.cort to judge,
|
||||||
// because there maybe another function call inside
|
// because there maybe another function call inside
|
||||||
if(!pc)
|
if (!pc) {
|
||||||
ngc.ctxreserve();
|
ngc.ctxreserve();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
void vm::run(
|
void vm::run(
|
||||||
const codegen& gen,
|
const codegen& gen,
|
||||||
const linker& linker,
|
const linker& linker,
|
||||||
const std::vector<string>& argv,
|
const std::vector<string>& argv,
|
||||||
const bool detail)
|
const bool detail) {
|
||||||
{
|
|
||||||
verbose=detail;
|
verbose=detail;
|
||||||
init(gen.strs(),gen.nums(),gen.codes(),linker.filelist(),argv);
|
init(gen.strs(),gen.nums(),gen.codes(),linker.filelist(),argv);
|
||||||
#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,
|
||||||
|
@ -958,8 +966,7 @@ void vm::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);
|
||||||
}
|
}
|
||||||
|
@ -967,8 +974,7 @@ void vm::run(
|
||||||
goto *code[pc];
|
goto *code[pc];
|
||||||
#else
|
#else
|
||||||
typedef void (vm::*nafunc)();
|
typedef void (vm::*nafunc)();
|
||||||
const nafunc oprs[]=
|
const nafunc oprs[]={
|
||||||
{
|
|
||||||
nullptr, &vm::o_intg,
|
nullptr, &vm::o_intg,
|
||||||
&vm::o_intl, &vm::o_loadg,
|
&vm::o_intl, &vm::o_loadg,
|
||||||
&vm::o_loadl, &vm::o_loadu,
|
&vm::o_loadl, &vm::o_loadu,
|
||||||
|
@ -1009,22 +1015,23 @@ void vm::run(
|
||||||
&vm::o_ret
|
&vm::o_ret
|
||||||
};
|
};
|
||||||
std::vector<nafunc> code;
|
std::vector<nafunc> 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);
|
||||||
}
|
}
|
||||||
while(code[pc]) {
|
while(code[pc]) {
|
||||||
(this->*code[pc])();
|
(this->*code[pc])();
|
||||||
if(top>=canary)
|
if (top>=canary) {
|
||||||
die("stack overflow");
|
die("stack overflow");
|
||||||
|
}
|
||||||
++pc;
|
++pc;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
vmexit:
|
vmexit:
|
||||||
if(detail)
|
if (detail) {
|
||||||
ngc.info();
|
ngc.info();
|
||||||
|
}
|
||||||
ngc.clear();
|
ngc.clear();
|
||||||
imm.clear();
|
imm.clear();
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -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");
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
if(progress*100-int(progress*100)==0){
|
||||||
print(bar.bar(progress)," ",progress*100,"% \r");
|
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();
|
||||||
|
|
Loading…
Reference in New Issue