Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
429ee13
basic setup for fixing #2633 by wrapping the character buffer under t…
jurgenvinju Feb 11, 2026
fcac23c
cleaning up a bit
jurgenvinju Feb 11, 2026
ebaa91b
this works. but now a better way to detect a read
jurgenvinju Feb 11, 2026
6b0804e
knowing when to start from the new tracker position is important
jurgenvinju Feb 11, 2026
602798b
Merge branch 'main' into fix/json-offsets
jurgenvinju Feb 11, 2026
0272df0
cleaning up parameters and error reporting
jurgenvinju Feb 12, 2026
3813c21
fixed broken header
jurgenvinju Feb 12, 2026
db3001c
testing.json is now longer to no longer need the carriage returns to …
jurgenvinju Feb 12, 2026
a191a82
testing and working on asserts
jurgenvinju Feb 12, 2026
9741013
make sure tracking is really of when a JsonReader is passed in, to av…
jurgenvinju Feb 12, 2026
1a32824
forgot to implement the degenerate parse error
jurgenvinju Feb 12, 2026
f0356b8
cleaning up
jurgenvinju Feb 12, 2026
32c114e
added some comments
jurgenvinju Feb 12, 2026
44c9e77
reset testing.json
jurgenvinju Feb 12, 2026
d8dec4d
commented read better and added fix by @DavyLandman for when off!=0
jurgenvinju Feb 12, 2026
1f6c294
added tests by @davylandman and fixed off-by-one with length of origi…
jurgenvinju Feb 13, 2026
37077dc
fixing off-by-ones
jurgenvinju Feb 13, 2026
b5e1a04
reset
jurgenvinju Feb 13, 2026
4b8ea99
refactored and simplified use of the wrapped reader. Also improved te…
jurgenvinju Feb 17, 2026
dd3f686
removed unused readCount
jurgenvinju Feb 17, 2026
f4ca19c
ignored a test again
jurgenvinju Feb 17, 2026
b431dfe
Merge branch 'main' into fix/json-offsets
jurgenvinju Feb 17, 2026
38de5d5
removed test printlns
jurgenvinju Feb 17, 2026
c3dfa18
Merge branch 'main' into fix/json-offsets
jurgenvinju Feb 18, 2026
e7a4679
removed dead import
jurgenvinju Feb 18, 2026
199423e
fixed comment by @davylandman
jurgenvinju Feb 18, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion src/org/rascalmpl/exceptions/RuntimeExceptionFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ public class RuntimeExceptionFactory {
// NotImplemented
public static final Type ParseError = TF.constructor(TS, Exception, "ParseError", TF.sourceLocationType(), "location");

// this comes from lang::json::IO
public static final Type NoOffsetParseError = TF.constructor(TS, Exception, "NoOffsetParseError", TF.sourceLocationType(), "location", TF.integerType(), "line", TF.integerType(), "column");

public static final Type PathNotFound = TF.constructor(TS,Exception,"PathNotFound",TF.sourceLocationType(), "location");

public static final Type PermissionDenied = TF.constructor(TS,Exception,"PermissionDenied",TF.stringType(), "message");
Expand Down Expand Up @@ -684,7 +687,12 @@ public static Throw jsonParseError(ISourceLocation loc, String cause, String pat
.asWithKeywordParameters().setParameter("path", VF.string(path)));
}


public static Throw jsonParseError(ISourceLocation file, int line, int col, String cause, String path) {
return new Throw(VF.constructor(NoOffsetParseError, file, VF.integer(line), VF.integer(col))
.asWithKeywordParameters().setParameter("reason", VF.string(cause))
.asWithKeywordParameters().setParameter("path", VF.string(path)));
}

public static Throw parseError(ISourceLocation loc, AbstractAST ast, StackTrace trace) {
return new Throw(VF.constructor(ParseError, loc), ast != null ? ast.getLocation() : null, trace);
}
Expand Down Expand Up @@ -793,4 +801,6 @@ public static Throw parseErrorRecovery(IValue trigger, ISourceLocation loc) {
public static Throw parseErrorRecoveryNoSuchField(String name, ISourceLocation loc) {
return new Throw(VF.constructor(ParseErrorRecovery, VF.constructor(NoSuchField, VF.string(name)), loc));
}


}
76 changes: 38 additions & 38 deletions src/org/rascalmpl/library/lang/json/IO.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,16 @@
*
* Contributors:
*
* * Jurgen J. Vinju - Jurgen.Vinju@cwi.nl - CWI * Mark Hills - Mark.Hills@cwi.nl (CWI) * Arnold
* Lankamp - Arnold.Lankamp@cwi.nl * Bert Lisser - Bert.Lisser@cwi.nl
* * Jurgen J. Vinju - Jurgen.Vinju@cwi.nl - CWI
* * Mark Hills - Mark.Hills@cwi.nl (CWI)
* * Arnold - Lankamp - Arnold.Lankamp@cwi.nl
* * Bert Lisser - Bert.Lisser@cwi.nl
*******************************************************************************/
package org.rascalmpl.library.lang.json;

import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.nio.charset.Charset;
Expand All @@ -38,7 +41,6 @@
import io.usethesource.vallang.type.Type;
import io.usethesource.vallang.type.TypeStore;

import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;

public class IO {
Expand All @@ -51,63 +53,55 @@ public IO(IRascalValueFactory values, IRascalMonitor monitor) {
this.monitor = monitor;
}

public IValue readJSON(IValue type, ISourceLocation loc, IString dateTimeFormat, IBool lenient, IBool trackOrigins,
IFunction parsers, IMap nulls, IBool explicitConstructorNames, IBool explicitDataTypes) {
private IValue doReadJSON(Reader in,
IValue type, ISourceLocation loc, IString dateTimeFormat, IBool lenient, IBool trackOrigins,
IFunction parsers, IMap nulls, IBool explicitConstructorNames, IBool explicitDataTypes) throws IOException {

TypeStore store = new TypeStore();
Type start = new TypeReifier(values).valueToType((IConstructor) type, store);

if (parsers.getType() instanceof ReifiedType && parsers.getType().getTypeParameters().getFieldType(0).isTop()) {
// ignore the default parser
parsers = null;
}

try (JsonReader in = new JsonReader(URIResolverRegistry.getInstance().getCharacterReader(loc))) {
in.setLenient(lenient.getValue());
try {
return new JsonValueReader(values, store, monitor, loc)
.setCalendarFormat(dateTimeFormat.getValue())
.setParsers(parsers)
.setNulls(unreify(nulls))
.setExplicitConstructorNames(explicitConstructorNames.getValue())
.setExplicitDataTypes(explicitDataTypes.getValue())
.setTrackOrigins(trackOrigins.getValue())
.read(in, start);
}
catch (IOException e) {
throw RuntimeExceptionFactory.io(e);
.setCalendarFormat(dateTimeFormat.getValue())
.setLenient(lenient.getValue())
.setParsers(parsers)
.setNulls(unreify(nulls))
.setExplicitConstructorNames(explicitConstructorNames.getValue())
.setExplicitDataTypes(explicitDataTypes.getValue())
.setTrackOrigins(trackOrigins.getValue())
.read(in, start);
}
catch (NullPointerException e) {
throw RuntimeExceptionFactory.io("NPE in error handling code");
}
}

public IValue readJSON(
IValue type, ISourceLocation loc, IString dateTimeFormat, IBool lenient, IBool trackOrigins,
IFunction parsers, IMap nulls, IBool explicitConstructorNames, IBool explicitDataTypes) {

private Map<Type, IValue> unreify(IMap nulls) {
var tr = new TypeReifier(values);
return nulls.stream().map(t -> (ITuple) t)
.collect(Collectors.toMap(t -> tr.valueToType((IConstructor) t.get(0)), t -> t.get(1)));
try (Reader in = URIResolverRegistry.getInstance().getCharacterReader(loc)) {
return doReadJSON(in, type, loc, dateTimeFormat, lenient, trackOrigins, parsers, nulls, explicitConstructorNames, explicitDataTypes);
}
catch (IOException e) {
throw RuntimeExceptionFactory.io(e);
}
}

public IValue parseJSON(IValue type, IString src, IString dateTimeFormat, IBool lenient, IBool trackOrigins,
IFunction parsers, IMap nulls, IBool explicitConstructorNames, IBool explicitDataTypes) {
TypeStore store = new TypeStore();
Type start = new TypeReifier(values).valueToType((IConstructor) type, store);

try (JsonReader in = new JsonReader(new StringReader(src.getValue()))) {
in.setLenient(lenient.getValue());
return new JsonValueReader(values, store, monitor,null)
.setCalendarFormat(dateTimeFormat.getValue())
.setParsers(parsers)
.setNulls(unreify(nulls))
.setTrackOrigins(trackOrigins.getValue())
.setExplicitConstructorNames(explicitConstructorNames.getValue())
.setExplicitDataTypes(explicitDataTypes.getValue())
.read(in, start);

try (Reader in = new StringReader(src.getValue())) {
return doReadJSON(in, type, null, dateTimeFormat, lenient, trackOrigins, parsers, nulls, explicitConstructorNames, explicitDataTypes);
}
catch (IOException e) {
throw RuntimeExceptionFactory.io(e);
}
catch (NullPointerException e) {
throw RuntimeExceptionFactory.io("NPE");
}
}

public void writeJSON(ISourceLocation loc, IValue value, IBool unpackedLocations, IString dateTimeFormat,
Expand Down Expand Up @@ -162,4 +156,10 @@ public IString asJSON(IValue value, IBool unpackedLocations, IString dateTimeFor
throw RuntimeExceptionFactory.io(e);
}
}

private Map<Type, IValue> unreify(IMap nulls) {
var tr = new TypeReifier(values);
return nulls.stream().map(t -> (ITuple) t)
.collect(Collectors.toMap(t -> tr.valueToType((IConstructor) t.get(0)), t -> t.get(1)));
}
}
9 changes: 8 additions & 1 deletion src/org/rascalmpl/library/lang/json/IO.rsc
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,14 @@ import Exception;
* `cause` is a factual diagnosis of what was expected at that position, versus what was found.
* `path` is a path query string into the JSON value from the root down to the leaf where the error was detected.
}
data RuntimeException(str cause="", str path="");
@benefits{
* ((NoOffsetParseError)) is for when accurate offset tracking is turned off. Typically this is _on_
even if `trackOrigins=false`, when we call the json parsers from Rascal.
}
data RuntimeException(str cause="", str path="")
= ParseError(loc location)
| NoOffsetParseError(loc location, int line, int column)
;

private str DEFAULT_DATETIME_FORMAT = "yyyy-MM-dd\'T\'HH:mm:ssZ";

Expand Down
Loading
Loading