Nasal-Interpreter/std/json.nas

289 lines
6.5 KiB
Plaintext

# lib json.nas
# 2021 ValKmjolnir
var JSON=func() {
var (
j_eof,
j_lbrace,
j_rbrace,
j_lbrkt,
j_rbrkt,
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 init=func() {
text='';
line=1;
text_size=0;
ptr=0;
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=char(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)) {
println("JSON.parse: empty string");
str="[]";
}
text=str;
text_size=size(text);
return;
}
var next=func() {
while(ptr<text_size and !check()) {
if(char(text[ptr])=='\n')
line+=1;
ptr+=1;
}
if(ptr>=text_size) {
token.content="eof";
token.type=j_eof;
return;
}
var c=char(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_lbrkt;
} elsif(c==']') {
token.content=']';
token.type=j_rbrkt;
} 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 char(text[ptr])!=strbegin) {
s~=char(text[ptr]);
ptr+=1;
if(char(text[ptr-1])=="\\" and ptr<text_size) {
s~=char(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(char(text[ptr])) or char(text[ptr])=='.'))) {
s~=char(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(char(text[ptr])) or isnum(char(text[ptr])))) {
s~=char(text[ptr]);
ptr+=1;
}
ptr-=1;
token.content=s;
token.type=j_id;
}
ptr+=1;
return;
}
var match=func(type) {
if(token.type!=type)
println("JSON.parse: line ",line,": expect ",j_content[type]," but get `",token.content,"`.");
next();
return;
}
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_lbrkt) {
hash[name]=vec_gen();
} elsif(token.type==j_str or token.type==j_num) {
hash[name]=token.content;
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_lbrkt);
if(token.type==j_lbrace) {
append(vec,hash_gen());
} elsif(token.type==j_lbrkt) {
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,hash_gen());
} elsif(token.type==j_lbrkt) {
append(vec,vec_gen());
} elsif(token.type==j_str or token.type==j_num) {
append(vec,token.content);
next();
}
}
match(j_rbrkt);
return vec;
}
return {
parse:func(str) {
if(typeof(str)!="str") {
println("JSON.parse: must use string");
return [];
}
get(str);
next();
if(token.type==j_lbrkt) {
var res=vec_gen();
} else {
var res=hash_gen();
}
init();
return res;
}
};
}();
JSON.stringify=func(object) {
if(typeof(object)!="hash" and typeof(object)!="vec") {
println("JSON.stringify: must use hashmap or vector");
return "[]";
}
var s="";
var gen=func(elem) {
var t=typeof(elem);
if(t=="num") {
s~=str(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~="}";
}
if(typeof(object)=="vec") {
vgen(object);
} else {
hgen(object);
}
return s;
}