add stl/json.nas & fix bug

bug: may cause program crash if stack overflow occurs on main stack
This commit is contained in:
ValKmjolnir 2022-10-08 21:34:47 +08:00
parent 405175061a
commit 7a93527948
8 changed files with 314 additions and 298 deletions

View File

@ -301,14 +301,12 @@ void nasal_dbg::run(
++count[code[pc]];
(this->*oprs[code[pc]])();
if(top>=canary)
break;
die("stack overflow");
++pc;
}
#endif
vmexit:
if(top>=canary)
die("stack overflow");
callsort(count);
gc.clear();
imm.clear();
@ -316,12 +314,14 @@ vmexit:
return;
#ifndef _MSC_VER
#define dbg(op,num) {\
interact();\
op();\
++count[num];\
if(top<canary)\
interact();\
op();\
++count[num];\
if(top<canary)\
goto *code[++pc];\
die("stack overflow");\
goto *code[++pc];\
goto vmexit;}
}
intg: dbg(o_intg ,op_intg );
intl: dbg(o_intl ,op_intl );

View File

@ -76,10 +76,11 @@ struct nas_ref
nas_ref(const u8 t,const i64 n):type(t){val.cnt=n;}
// vm_num
nas_ref(const u8 t,const f64 n):type(t){val.num=n;}
// vm_str/vm_func/vm_vec/vm_hash/vm_upval/vm_obj
// nas_val
nas_ref(const u8 t,nas_val* n):type(t){val.gcobj=n;}
// vm_addr
nas_ref(const u8 t,nas_ref* n):type(t){val.addr=n;}
// copy
nas_ref(const nas_ref& nr):type(nr.type),val(nr.val){}
bool operator==(const nas_ref& nr){return type==nr.type && val.gcobj==nr.val.gcobj;}
bool operator!=(const nas_ref& nr){return type!=nr.type || val.gcobj!=nr.val.gcobj;}

View File

@ -1035,6 +1035,7 @@ vmexit:
if(top<canary)\
goto *code[++pc];\
die("stack overflow");\
goto *code[++pc];\
}
// do not cause stackoverflow
#define exec_nodie(op) {op();goto *code[++pc];}

268
stl/json.nas Normal file
View File

@ -0,0 +1,268 @@
# lib json.nas
# 2021 ValKmjolnir
var JSON=func(){
var (
j_eof,
j_lbrace,
j_rbrace,
j_lbracket,
j_rbracket,
j_comma,
j_colon,
j_str,
j_num,
j_id
)=(0,1,2,3,4,5,6,7,8,9);
var j_content=[
"eof",
"`{`",
"`}`",
"`[`",
"`]`",
"`,`",
"`:`",
"string",
"number",
"identifier"
];
var text='';
var line=1;
var text_size=0;
var ptr=0;
var token={content:'',type:''};
var content={};
var init=func(){
text='';
line=1;
text_size=0;
ptr=0;
content={};
token={content:'',type:''};
}
var isnum=func(c){
return '0'<=c and c<='9';
}
var isid=func(c){
var tmp=c[0];
return ('a'[0]<=tmp and tmp<='z'[0]) or
('A'[0]<=tmp and tmp<='Z'[0]) or
c=='_';
}
var check=func(){
var c=text[ptr];
return (
c=='{' or c=='}' or
c=='[' or c==']' or
c==',' or c==':' or
c=='\"' or c=='\'' or
isnum(c) or isid(c)
);
}
var get=func(str){
init();
if(!size(str))
die("empty string");
text=split('',str);
text_size=size(text);
return;
}
var next=func(){
while(ptr<text_size and !check()){
if(text[ptr]=='\n')
line+=1;
ptr+=1;
}
if(ptr>=text_size){
token.content="eof";
token.type=j_eof;
return;
}
var c=text[ptr];
if(c=='{'){
token.content='{';
token.type=j_lbrace;
}elsif(c=='}'){
token.content='}';
token.type=j_rbrace;
}elsif(c=='['){
token.content='[';
token.type=j_lbracket;
}elsif(c==']'){
token.content=']';
token.type=j_rbracket;
}elsif(c==','){
token.content=',';
token.type=j_comma;
}elsif(c==':'){
token.content=':';
token.type=j_colon;
}elsif(c=='\"' or c=='\''){
var strbegin=c;
var s="";
ptr+=1;
while(ptr<text_size and text[ptr]!=strbegin){
s~=text[ptr];
ptr+=1;
}
token.content=s;
token.type=j_str;
}elsif(isnum(c)){
var s=c;
ptr+=1;
while(ptr<text_size and ((isnum(text[ptr]) or text[ptr]=='.'))){
s~=text[ptr];
ptr+=1;
}
ptr-=1;
token.content=num(s);
token.type=j_num;
}elsif(isid(c)){
var s=c;
ptr+=1;
while(ptr<text_size and (isid(text[ptr]) or isnum(text[ptr]))){
s~=text[ptr];
ptr+=1;
}
ptr-=1;
token.content=s;
token.type=j_id;
}
ptr+=1;
return;
}
var match=func(type){
if(token.type!=type)
print("line ",line,": expect ",j_content[type]," but get `",token.content,"`.\n");
next();
return;
}
var hash_gen=func(){
var hash={};
match(j_lbrace);
member(hash);
while(token.type==j_comma){
match(j_comma);
member(hash);
}
match(j_rbrace);
return hash;
}
var vec_gen=func(){
var vec=[];
match(j_lbracket);
if(token.type==j_lbrace){
append(vec,hash_gen());
}elsif(token.type==j_lbracket){
append(vec,vec_gen());
}elsif(token.type==j_str or token.type==j_num){
append(vec,token.content);
next();
}
while(token.type==j_comma){
match(j_comma);
if(token.type==j_lbrace){
append(vec,me.hash_gen());
}elsif(token.type==j_lbracket){
append(vec,vec_gen());
}elsif(token.type==j_str or token.type==j_num){
append(vec,token.content);
next();
}
}
match(j_rbracket);
return vec;
}
var member=func(hash){
var name=token.content;
if(token.type==j_rbrace){
return;
}
if(token.type==j_str){
match(j_str);
}else{
match(j_id);
}
match(j_colon);
if(token.type==j_lbrace){
hash[name]=hash_gen();
}elsif(token.type==j_lbracket){
hash[name]=vec_gen();
}elsif(token.type==j_str or token.type==j_num){
hash[name]=token.content;
next();
}
return;
}
return {
parse:func(str){
if(typeof(str)!="str")
die("JSON.parse: must use string");
get(str);
next();
match(j_lbrace);
member(content);
while(token.type==j_comma){
match(j_comma);
member(content);
}
match(j_rbrace);
var res=content;
init();
return res;
},
stringify:func(hash){
if(typeof(hash)!="hash")
die("JSON.stringify: must use hashmap");
var s="";
var gen=func(elem){
var t=typeof(elem);
if(t=="num"){
s~=elem;
}elsif(t=="str"){
s~='"'~elem~'"';
}elsif(t=="vec"){
vgen(elem);
}elsif(t=="hash"){
hgen(elem);
}else{
s~='"undefined"';
}
}
var vgen=func(v){
s~="[";
var vsize=size(v);
for(var i=0;i<vsize;i+=1){
gen(v[i]);
if(i!=vsize-1)
s~=",";
}
s~="]";
}
var hgen=func(h){
s~="{";
var k=keys(h);
var vsize=size(k);
for(var i=0;i<vsize;i+=1){
s~=k[i]~":";
gen(h[k[i]]);
if(i!=vsize-1)
s~=",";
}
s~="}";
}
hgen(hash);
return s;
}
};
}();

View File

@ -19,6 +19,7 @@ var source=[
var lib=[
"fg_env.nas",
"file.nas",
"json.nas",
"lib.nas",
"list.nas",
"log.nas",

View File

@ -35,6 +35,38 @@ func(){
}
}();
# test crash in coroutines
var co=coroutine.create(func{
var b=func(){b()}
coroutine.yield(b);
b();
coroutine.yield(0);
});
println("coroutine yield: ",coroutine.resume(co));
println("coroutine state:\e[32m ",coroutine.status(co),"\e[0m");
println("coroutine error: ",coroutine.resume(co));
println("coroutine state:\e[91m ",coroutine.status(co),"\e[0m");
println("coroutine yield: ",coroutine.resume(co));
println("coroutine state:\e[91m ",coroutine.status(co),"\e[0m");
var co=coroutine.create(func{
var a=1;
var b=func(){
b();
}
coroutine.yield(b);
coroutine.yield(b());
});
println("coroutine yield: ",coroutine.resume(co));
println("coroutine state:\e[32m ",coroutine.status(co),"\e[0m");
println("coroutine error: ",coroutine.resume(co));
println("coroutine state:\e[91m ",coroutine.status(co),"\e[0m");
println("coroutine yield: ",coroutine.resume(co));
println("coroutine state:\e[91m ",coroutine.status(co),"\e[0m");
println("ok");
# pressure test
var productor=func(){
for(var i=0;;i+=1)
@ -62,17 +94,3 @@ tm.stamp();
while(tm.elapsedMSec()<total)
consumer();
println("\nexecute ",counter," tasks during ",total," ms, avg ",counter/total," tasks/ms.");
var co=coroutine.create(func{
var b=func(){b()}
coroutine.yield(b);
b();
coroutine.yield(0);
});
println("coroutine yield: ",coroutine.resume(co));
println("coroutine state:\e[32m ",coroutine.status(co),"\e[0m");
println("coroutine error: ",coroutine.resume(co));
println("coroutine state:\e[91m ",coroutine.status(co),"\e[0m");
println("coroutine yield: ",coroutine.resume(co));
println("coroutine state:\e[91m ",coroutine.status(co),"\e[0m");

View File

@ -1,278 +1,4 @@
#lib json.nas
var JSON=func(){
var (
j_eof,
j_lbrace,
j_rbrace,
j_lbracket,
j_rbracket,
j_comma,
j_colon,
j_str,
j_num,
j_id
)=(
0,
1,
2,
3,
4,
5,
6,
7,
8,
9
);
var j_content=[
"eof",
"`{`",
"`}`",
"`[`",
"`]`",
"`,`",
"`:`",
"string",
"number",
"identifier"
];
var text='';
var line=1;
var text_size=0;
var ptr=0;
var token={content:'',type:''};
var content={};
var init=func(){
line=1;
text_size=0;
ptr=0;
content={};
token={content:'',type:''};
text='';
}
var isnum=func(c){
return '0'<=c and c<='9';
}
var isid=func(c){
var tmp=c[0];
return ('a'[0]<=tmp and tmp<='z'[0]) or
('A'[0]<=tmp and tmp<='Z'[0]) or
c=='_';
}
var check=func(){
var c=text[ptr];
return (
c=='{' or c=='}' or
c=='[' or c==']' or
c==',' or c==':' or
c=='\"' or c=='\'' or
isnum(c) or isid(c)
);
}
var get=func(str){
init();
if(!size(str))
die("empty string");
text=split('',str);
text_size=size(text);
return;
}
var next=func(){
while(ptr<text_size and !check()){
if(text[ptr]=='\n')
line+=1;
ptr+=1;
}
if(ptr>=text_size){
token.content="eof";
token.type=j_eof;
return;
}
var c=text[ptr];
if(c=='{'){
token.content='{';
token.type=j_lbrace;
}elsif(c=='}'){
token.content='}';
token.type=j_rbrace;
}elsif(c=='['){
token.content='[';
token.type=j_lbracket;
}elsif(c==']'){
token.content=']';
token.type=j_rbracket;
}elsif(c==','){
token.content=',';
token.type=j_comma;
}elsif(c==':'){
token.content=':';
token.type=j_colon;
}elsif(c=='\"' or c=='\''){
var strbegin=c;
var s="";
ptr+=1;
while(ptr<text_size and text[ptr]!=strbegin){
s~=text[ptr];
ptr+=1;
}
token.content=s;
token.type=j_str;
}elsif(isnum(c)){
var s=c;
ptr+=1;
while(ptr<text_size and ((isnum(text[ptr]) or text[ptr]=='.'))){
s~=text[ptr];
ptr+=1;
}
ptr-=1;
token.content=num(s);
token.type=j_num;
}elsif(isid(c)){
var s=c;
ptr+=1;
while(ptr<text_size and (isid(text[ptr]) or isnum(text[ptr]))){
s~=text[ptr];
ptr+=1;
}
ptr-=1;
token.content=s;
token.type=j_id;
}
ptr+=1;
return;
}
var match=func(type){
if(token.type!=type)
print("line ",line,": expect ",j_content[type]," but get `",token.content,"`.\n");
next();
return;
}
var hash_gen=func(){
var hash={};
match(j_lbrace);
member(hash);
while(token.type==j_comma){
match(j_comma);
member(hash);
}
match(j_rbrace);
return hash;
}
var vec_gen=func(){
var vec=[];
match(j_lbracket);
if(token.type==j_lbrace)
append(vec,hash_gen());
elsif(token.type==j_lbracket)
append(vec,vec_gen());
elsif(token.type==j_str or token.type==j_num){
append(vec,token.content);
next();
}
while(token.type==j_comma){
match(j_comma);
if(token.type==j_lbrace)
append(vec,me.hash_gen());
elsif(token.type==j_lbracket)
append(vec,vec_gen());
elsif(token.type==j_str or token.type==j_num){
append(vec,token.content);
next();
}
}
match(j_rbracket);
return vec;
}
var member=func(hash){
var name=token.content;
if(token.type==j_rbrace)
return;
if(token.type==j_str)
match(j_str);
else
match(j_id);
match(j_colon);
if(token.type==j_lbrace)
hash[name]=hash_gen();
elsif(token.type==j_lbracket)
hash[name]=vec_gen();
elsif(token.type==j_str or token.type==j_num){
hash[name]=token.content;
next();
}
return;
}
return {
parse:func(str){
if(typeof(str)!="str")
die("JSON.parse: must use string");
get(str);
next();
match(j_lbrace);
member(content);
while(token.type==j_comma){
match(j_comma);
member(content);
}
match(j_rbrace);
var res=content;
init();
return res;
},
stringify:func(hash){
if(typeof(hash)!="hash")
die("JSON.stringify: must use hashmap");
var s="";
var gen=func(elem){
var t=typeof(elem);
if(t=="num")
s~=elem;
elsif(t=="str")
s~='"'~elem~'"';
elsif(t=="vec")
vgen(elem);
elsif(t=="hash")
hgen(elem);
else
s~='"undefined"';
}
var vgen=func(v){
s~="[";
var vsize=size(v);
for(var i=0;i<vsize;i+=1){
gen(v[i]);
if(i!=vsize-1)
s~=",";
}
s~="]";
}
var hgen=func(h){
s~="{";
var k=keys(h);
var vsize=size(k);
for(var i=0;i<vsize;i+=1){
s~=k[i]~":";
gen(h[k[i]]);
if(i!=vsize-1)
s~=",";
}
s~="}";
}
hgen(hash);
return s;
}
};
}();
import.stl.json;
var ss=JSON.stringify({
vec:[0,1,2],

View File

@ -33,6 +33,7 @@ var compare=func(){
var filechecksum=func(){
var files=[
"./stl/fg_env.nas", "./stl/file.nas",
"./stl/json.nas",
"./stl/lib.nas", "./stl/list.nas",
"./stl/log.nas", "./stl/module.nas",
"./stl/padding.nas", "./stl/process_bar.nas",