rascal
rascal copied to clipboard
`parseJSON` does not support `null` in JSON
Reproduce:
rascal>import lang::json::IO;
ok
rascal>parseJSON(#map[str,value], "{\"bla\": null}");
|std:///lang/json/IO.rsc|(2599,303,<49,0>,<52,144>): IO("NPE")
at *** somewhere ***(|std:///lang/json/IO.rsc|(2599,303,<49,0>,<52,144>))
at parseJSON(|std:///lang/json/IO.rsc|(2895,5,<52,137>,<52,142>)ok
As Rascal does not support null, we need a sentinel value, but this cannot be chosen by the implementation. Suggestion: a keyword parameter specifying a custom value to use in case of null.
Just to be sure: the parser supports null currently only when the current field is the name of a keyword field of the current data-type.
How about we just return nothing() if no specific type is expected? And we could add support for null and non-null in case we expect Maybe[.]
rascal>parseJSON(#map[str,value], "{\"bla\": null}")
map[str, value]: ("bla":"null"())
rascal>parseJSON(#map[str,value], "{\"bla\": null}", nulls=(#value:-1))
map[str, value]: ("bla":-1)
rascal>parseJSON(#map[str,Maybe[str]], "{\"bla\": null}")
map[str, Maybe[str]]: ("bla":nothing())
rascal>parseJSON(#map[str,Maybe[str]], "{\"bla\": \"foo\"}")
map[str, Maybe[str]]: ("bla":just("foo"))
rascal>data Cons = cons(str bla = "null");
ok
rascal>parseJSON(#Cons, "{\"bla\": \"foo\"}")
Cons: cons(bla="foo")
rascal>parseJSON(#Cons, "{\"bla\": null}")
Cons: cons()
rascal>parseJSON(#Cons, "{\"bla\": null}").bla
str: "null"
@tvdstorm Don't know what to do when writing these values back. Should the null values be written as null again? Or just as they are? Support we have (#int:-1) while reading integer nulls. Should -1 be written as null again when we use the same nulls map?
Also improved error reporting while we are at it. All internal parse errors and malformedness in the Gson parser is lifted to a Rascal ParseError with the JSON path query to the position, and offset, lengths, line/col, and the diagnostic.