From c0473addc3a192397240655ea9d023f80971e269 Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Fri, 15 Sep 2017 11:04:31 +0200 Subject: [PATCH] we need to be able to parse json from string values directly sometimes --- src/org/rascalmpl/library/lang/json/IO.java | 20 ++++++++++++++ src/org/rascalmpl/library/lang/json/IO.rsc | 30 +++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/src/org/rascalmpl/library/lang/json/IO.java b/src/org/rascalmpl/library/lang/json/IO.java index 70885a17a42..f97a1239ce2 100644 --- a/src/org/rascalmpl/library/lang/json/IO.java +++ b/src/org/rascalmpl/library/lang/json/IO.java @@ -16,6 +16,7 @@ import java.io.IOException; import java.io.OutputStreamWriter; +import java.io.StringReader; import java.nio.charset.Charset; import org.rascalmpl.interpreter.IEvaluatorContext; @@ -96,6 +97,25 @@ public IValue readJSON(IValue type, ISourceLocation loc, IBool implicitConstruct } } + public IValue parseJSON(IValue type, IString src, IBool implicitConstructors, IBool implicitNodes, IString dateTimeFormat) { + TypeStore store = new TypeStore(); + Type start = new TypeReifier(values).valueToType((IConstructor) type, store); + + try (JsonReader in = new JsonReader(new StringReader(src.getValue()))) { + return new JsonValueReader(values, store) + .setConstructorsAsObjects(implicitConstructors.getValue()) + .setNodesAsObjects(implicitNodes.getValue()) + .setCalendarFormat(dateTimeFormat.getValue()) + .read(in, start); + } + catch (IOException e) { + throw RuntimeExceptionFactory.io(values.string(e.getMessage()), null, null); + } + catch (NullPointerException e) { + throw RuntimeExceptionFactory.io(values.string("NPE"), null, null); + } + } + public void writeJSON(ISourceLocation loc, IValue value, IBool implicitConstructors, IBool implicitNodes, IString dateTimeFormat, IBool dateTimeAsInt) { try (JsonWriter out = new JsonWriter(new OutputStreamWriter(URIResolverRegistry.getInstance().getOutputStream(loc, false), Charset.forName("UTF8")))) { new JsonValueWriter() diff --git a/src/org/rascalmpl/library/lang/json/IO.rsc b/src/org/rascalmpl/library/lang/json/IO.rsc index 20a54df0573..04eb2da1e9c 100644 --- a/src/org/rascalmpl/library/lang/json/IO.rsc +++ b/src/org/rascalmpl/library/lang/json/IO.rsc @@ -57,6 +57,36 @@ A similar distinction is made for values of type `node`, configured using the `i } java &T readJSON(type[&T] expected, loc src, bool implicitConstructors = true, bool implicitNodes = true, str dateTimeFormat = "yyyy-MM-dd\'T\'HH:mm:ss\'Z\'"); +@javaClass{org.rascalmpl.library.lang.json.IO} +@doc{parses JSON values from a string +In general the translation behaves as follows: + * Objects translate to map[str,value] by default, unless a node is expected (properties are then translated to keyword fields) + * Arrays translate to lists by default, or to a set if that is expected or a tuple if that is expected. Arrays may also be interpreted as constructors or nodes (see below) + * Booleans translate to bools + * If the expected type provided is a datetime then an int instant is mapped and if a string is found then the dateTimeFormat parameter will be used to configure the parsing of a date-time string + * If the expected type provided is an ADT then this reader will map Json objects in a particular way, as configured by the implicitNodes and implicitConstructor + parameters. + * If num, int, real or rat are expected both strings and number values are mapped + * If loc is expected than strings which look like URI are parsed (containing :/) or a file:/// URI is build, or if an object is found each separate field of + a location object is read from the respective properties: { scheme : str, authority: str?, path: str?, fragment: str?, query: str?, offset: int, length: int, begin: [bl, bc], end: [el, ec]} + +In "implicitConstructor" mode the name of a property will be used as the name of the nested constructor. So this expects data definitions to line up constructor +names with field names: `data MyType = myConstructor(MyType2 myConstructor2); data MyType2 = myConstructor2(int i)` + ^_______________________________^ + +This would then map the Json input `"myConstructor" : { myConstructor2 : { "i" : 1 } }` to the Rascal value `myConstructor(myConstructor2(1))` + +In this mode field names for keyword parameters map to keyword parameters and field names to positional parameters map to positional parameters (which do not have +to be printed in order in the Json input file). + +In explicit constructor mode (`implicitConstructor==false`) the following array-based encoding is expected for constructor trees, by example: + `[ "myConstructor", [ ["myConstructor2", [ 1 ] ] ] ]` and when there are keyword parameters we allow a third field of the array which is an object mapping + Json properties to Rascal keyword fields. + +A similar distinction is made for values of type `node`, configured using the `implicitNode` parameter. +} +java &T parseJSON(type[&T] expected, str src, bool implicitConstructors = true, bool implicitNodes = true, str dateTimeFormat = "yyyy-MM-dd\'T\'HH:mm:ss\'Z\'"); + @javaClass{org.rascalmpl.library.lang.json.IO} java void writeJSON(loc target, value val, bool implicitConstructors=true, bool implicitNodes=true, str dateTimeFormat="yyyy-MM-dd\'T\'HH:mm:ss\'Z\'", bool dateTimeAsInt=false);