⚡ add stl/json.nas & fix bug
bug: may cause program crash if stack overflow occurs on main stack
This commit is contained in:
parent
405175061a
commit
7a93527948
16
nasal_dbg.h
16
nasal_dbg.h
|
@ -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 );
|
||||
|
|
|
@ -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;}
|
||||
|
|
|
@ -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];}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
}();
|
|
@ -19,6 +19,7 @@ var source=[
|
|||
var lib=[
|
||||
"fg_env.nas",
|
||||
"file.nas",
|
||||
"json.nas",
|
||||
"lib.nas",
|
||||
"list.nas",
|
||||
"log.nas",
|
||||
|
|
|
@ -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");
|
276
test/json.nas
276
test/json.nas
|
@ -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],
|
||||
|
|
|
@ -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",
|
||||
|
|
Loading…
Reference in New Issue