Skip to content

Commit

Permalink
resolved more merge problems
Browse files Browse the repository at this point in the history
  • Loading branch information
jurgenvinju committed Dec 10, 2024
1 parent 89ece88 commit f62cca3
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 66 deletions.
121 changes: 92 additions & 29 deletions src/org/rascalmpl/library/lang/json/internal/JsonValueReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -544,26 +544,84 @@ private IValue visitStringAsAbstractData(Type type) throws IOException {
* @throws IOException
*/
private IValue visitObjectAsAbstractData(Type type) throws IOException {
Set<Type> alternatives = store.lookupAlternatives(type);
if (alternatives.size() > 1) {
monitor.warning("selecting arbitrary constructor for " + type, vf.sourceLocation(in.getPath()));
}
Type cons = alternatives.iterator().next();

Set<Type> alternatives = null;

in.beginObject();
int startPos = getPos();
int startLine = getLine();
int startCol = getCol();

// use explicit information in the JSON to select and filter constructors from the TypeStore
// we expect always to have the field _constructor before _type.
if (explicitConstructorNames || explicitDataTypes) {
String consName = null;
String typeName = null; // this one is optional, and the order with cons is not defined.
String consLabel = in.nextName();

// first we read either a cons name or a type name
if (explicitConstructorNames && "_constructor".equals(consLabel)) {
consName = in.nextString();
}
else if (explicitDataTypes && "_type".equals(consLabel)) {
typeName = in.nextString();
}

// optionally read the second field
if (explicitDataTypes && typeName == null) {
// we've read a constructor name, but we still need a type name
consLabel = in.nextName();
if (explicitDataTypes && "_type".equals(consLabel)) {
typeName = in.nextString();
}
}
else if (explicitDataTypes && consName == null) {
// we've read type name, but we still need a constructor name
consLabel = in.nextName();
if (explicitDataTypes && "_constructor".equals(consLabel)) {
consName = in.nextString();
}
}

if (explicitDataTypes && typeName == null) {
throw parseErrorHere("Missing a _type field: " + in.getPath());
}
else if (explicitConstructorNames && consName == null) {
throw parseErrorHere("Missing a _constructor field: " + in.getPath());
}

if (typeName != null && consName != null) {
// first focus on the given type name
var dataType = TF.abstractDataType(store, typeName);
alternatives = store.lookupConstructor(dataType, consName);
}
else {
// we only have a constructor name
// lookup over all data types by constructor name
alternatives = store.lookupConstructors(consName);
}
}
else {
alternatives = store.lookupAlternatives(type);
}

if (alternatives.size() > 1) {
monitor.warning("selecting arbitrary constructor for " + type, vf.sourceLocation(in.getPath()));
}
else if (alternatives.size() == 0) {
throw parseErrorHere("No fitting constructor found for " + in.getPath());
}

Type cons = alternatives.iterator().next();

IValue[] args = new IValue[cons.getArity()];
Map<String,IValue> kwParams = new HashMap<>();

if (!cons.hasFieldNames() && cons.getArity() != 0) {
throw parseErrorHere("For the object encoding constructors must have field names " + in.getPath());
}

while (in.hasNext()) {
String label = nextName();
String label = in.nextName();
if (cons.hasField(label)) {
IValue val = read(in, cons.getFieldType(label));
if (val != null) {
Expand All @@ -578,29 +636,35 @@ else if (cons.hasKeywordField(label, store)) {
IValue val = read(in, store.getKeywordParameterType(cons, label));
// null can still happen if the nulls map doesn't have a default
if (val != null) {
// if the value is null we'd use the default value of the defined field in the constructor
kwParams.put(label, val);
// if the value is null we'd use the default value of the defined field in the constructor
kwParams.put(label, val);
}
}
}
else { // its a normal arg, pass its label to the child
if (!explicitConstructorNames && "_constructor".equals(label)) {
// ignore additional _constructor fields.
in.nextString(); // skip the constructor value
continue;
}
else if (!explicitDataTypes && "_type".equals(label)) {
// ignore additional _type fields.
in.nextString(); // skip the type value
continue;
else {
var nullValue = inferNullValue(nulls, cons.getAbstractDataType());
if (nullValue != null) {
kwParams.put(label, nullValue);
}
else {
// field label does not match data type definition
}
}
else { // its a normal arg, pass its label to the child
if (!explicitConstructorNames && "_constructor".equals(label)) {
// ignore additional _constructor fields.
in.nextString(); // skip the constructor value
continue;
}
else if (!explicitDataTypes && "_type".equals(label)) {
// ignore additional _type fields.
in.nextString(); // skip the type value
continue;
}
else {
// field label does not match data type definition
throw parseErrorHere("Unknown field " + label + ":" + in.getPath());
}
}
}
}

}
in.endObject();
int endPos = getPos();
int endLine = getLine();
Expand All @@ -612,11 +676,10 @@ else if (!explicitDataTypes && "_type".equals(label)) {
}
}

if (originTracking) {
if (src != null) {
kwParams.put(kwParams.containsKey("src") ? "rascal-src" : "src", vf.sourceLocation(src, startPos, endPos - startPos + 1, startLine, endLine, startCol, endCol + 1));
}


return vf.constructor(cons, args, kwParams);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,8 @@ test bool dealWithNull() {
assert parseJSON(#map[str,Maybe[str]], "{\"bla\": \"foo\"}") == ("bla":just("foo"));
// keyword parameters and null
assert parseJSON(#Cons, "{\"bla\": \"foo\"}") == cons(bla="foo");
assert parseJSON(#Cons, "{\"bla\": null}") == cons();
assert cons(bla="foo") := parseJSON(#Cons, "{\"bla\": \"foo\"}");
assert cons() := parseJSON(#Cons, "{\"bla\": null}");
return true;
}
Expand Down Expand Up @@ -147,44 +147,11 @@ test bool explicitDataTypes() {
assert json == "{\"_constructor\":\"data4\",\"_type\":\"DATA4\",\"e\":{\"_constructor\":\"z\",\"_type\":\"Enum\"}}";
// _constructor and _type must be the first fields
assert parseJSON(#DATA4, json, explicitDataTypes=true) == tmp;
assert tmp := parseJSON(#DATA4, json, explicitDataTypes=true) ;
// _type and _constructor may appear in a different order
flippedJson = "{\"_type\":\"DATA4\",\"_constructor\":\"data4\",\"e\":{\"_constructor\":\"z\",\"_type\":\"Enum\"}}";
assert parseJSON(#DATA4, flippedJson, explicitDataTypes=true) == tmp;
// here we can't be sure to get z() back, but we will get some Enum
assert data4(e=Enum _) := parseJSON(#DATA4, json, explicitDataTypes=false);
return true;
}
test bool explicitConstructorNames() {
example = data4(e=z());
json = asJSON(example, explicitConstructorNames=true);
assert json == "{\"_constructor\":\"data4\",\"e\":{\"_constructor\":\"z\"}}";
assert parseJSON(#DATA4, json, explicitConstructorNames=true) == example;
// here we can't be sure to get z() back, but we will get some Enum
assert data4(e=Enum _) := parseJSON(#DATA4, json, explicitConstructorNames=false);
return true;
}
test bool explicitDataTypes() {
example = data4(e=z());
json = asJSON(example, explicitDataTypes=true);
assert json == "{\"_constructor\":\"data4\",\"_type\":\"DATA4\",\"e\":{\"_constructor\":\"z\",\"_type\":\"Enum\"}}";
// _constructor and _type must be the first fields
assert parseJSON(#DATA4, json, explicitDataTypes=true) == example;
// _type and _constructor may appear in a different order
flippedJson = "{\"_type\":\"DATA4\",\"_constructor\":\"data4\",\"e\":{\"_constructor\":\"z\",\"_type\":\"Enum\"}}";
assert parseJSON(#DATA4, flippedJson, explicitDataTypes=true) == example;
assert tmp := parseJSON(#DATA4, flippedJson, explicitDataTypes=true);
// here we can't be sure to get z() back, but we will get some Enum
assert data4(e=Enum _) := parseJSON(#DATA4, json, explicitDataTypes=false);
Expand Down

0 comments on commit f62cca3

Please sign in to comment.