#line 1375 "/home/ubuntu/felix/src/packages/web.fdoc"
open class Json
{
variant Jvalue =
| Jstring of string
| Jnumber of string
| Jdictionary of list[Jpair]
| Jarray of list [Jvalue]
| Jname of string
;
typedef Jpair = Jvalue * Jvalue;
fun str (s:Jvalue, v:Jvalue) : string => str s + ': ' + str v;
fun str (v: Jvalue) : string => match v with
| Jstring s => '"' + s + '"'
| Jnumber i => i
| Jdictionary d => "{" + cat ", " (map str of (Jpair) d) + "}"
| Jarray a => "[" + cat ", " (map str of (Jvalue) a) + "]"
| Jname a => a
endmatch
;
variant ParseResult =
| Good of Jvalue
| Bad of int
;
fun parse_json(s:string): ParseResult = {
var i = skip_white s 0;
def i, var v = parse_value s i;
i = skip_white s i;
if s.[i] != "".char do
return Bad i;
else
return v;
done
}
private fun skip_white (s:string) (var i:int) = {
while s.[i] in " \t\r\n" do ++i; done
return i;
}
private fun parse_value (s:string) (i:int): int * ParseResult =>
if s.[i] in "-0123456789" then parse_number s i
elif s.[i] == '"'.char then parse_string s (i+1)
elif s.[i] == "{".char then parse_dictionary s (i+1)
elif s.[i] == "[".char then parse_array s (i+1)
elif s.[i] in "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" then parse_name s i
else i, Bad i
endif
;
private fun parse_name (s:string) (var i:int) = {
var j = s.[i].string;
++i;
while s.[i] in "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_" do
j += s.[i];
++i;
done
if j in ("true","false","null") do
return i,Good (Jname j);
else
return i, Bad i;
done
}
private fun parse_number (s:string) (var i:int) = {
var j = "";
if s.[i] == "-".char do
j += s.[i];
++i;
done
if s.[i] == "0".char do
j+= s.[i];
++i;
goto point;
done
if s.[i] in "123456789" do
j += s.[i];
++i;
else
goto bad;
done
while s.[i] in "0123456789" do
j += s.[i];
++i;
done
point:>
if s.[i] != ".".char goto exponent;
j += s.[i];
++i;
fraction:>
if s.[i] in "0123456789" do
while s.[i] in "0123456789" do
j += s.[i];
++i;
done
else
goto bad;
done
exponent:>
if s.[i] in "eE" do
j += s.[i];
++i;
else
goto good;
done
if s.[i] in "+-" do
j += s.[i];
++i;
done
if s.[i] in "0123456789" do
while s.[i] in "0123456789" do
j += s.[i];
++i;
done
else
goto bad;
done
good:>
return i,Good (Jnumber j);
bad:>
return i, Bad i;
}
private fun parse_string (s:string) (var i:int) = {
var r = "";
ordinary:>
while s.[i] != "".char and s.[i] != '"'.char and s.[i] != "\\".char do
if s.[i].ord < 32 goto bad;
r += s.[i];
++i;
done
if s.[i] == '"'.char do
++i;
goto good;
elif s.[i] == "\\".char do
r += s.[i];
++i;
if s.[i] in '"\\/bfnrt' do
r += s.[i];
++i;
goto ordinary;
elif s.[i] == "u".char do
r += s.[i];
++i;
if s.[i] in "0123456789ABCDEFabcdef" do r += s.[i]; ++i; else goto bad; done
if s.[i] in "0123456789ABCDEFabcdef" do r += s.[i]; ++i; else goto bad; done
if s.[i] in "0123456789ABCDEFabcdef" do r += s.[i]; ++i; else goto bad; done
if s.[i] in "0123456789ABCDEFabcdef" do r += s.[i]; ++i; else goto bad; done
goto ordinary;
else
goto bad;
done
else
goto bad;
done
good:>
return i,Good (Jstring r);
bad:>
return i, Bad i;
}
private fun parse_dictionary (s:string) (var i:int) = {
var elts = #list[Jvalue * Jvalue];
i = skip_white s i;
while s.[i] != "}".char do
if s.[i] == '"'.char do
def i, var ms = parse_string s (i+1);
match ms with
| Good sv =>
i = skip_white s i;
if s.[i] == ":".char do
++i;
i = skip_white s i;
def i, var mv = parse_value s i;
match mv with
| Good v =>
elts += sv,v;
i = skip_white s i;
| Bad j => return i, Bad j;
endmatch;
else
return i, Bad i;
done
if s.[i] == ",".char do
++i;
i = skip_white s i;
elif s.[i] == "}".char do ;
else
return i, Bad i;
done
| Bad j => return i, Bad j;
endmatch;
else
return i, Bad i;
done
done
++i;
i = skip_white s i;
return i, Good (Jdictionary elts);
}
private fun parse_array (s:string) (var i:int) = {
var elts = #list[Jvalue];
i = skip_white s i;
while s.[i] != "]".char do
def i, var mv = parse_value s i;
match mv with
| Good v => elts += v;
i = skip_white s i;
if s.[i] == ",".char do
++i;
i = skip_white s i;
elif s.[i] == "]".char do ;
else
return i, Bad i;
done
| Bad j => return i, Bad j;
endmatch;
done
++i;
i = skip_white s i;
return i, Good (Jarray elts);
}
}