diff --git a/src/main/java/com/dashjoin/jsonata/Parser.java b/src/main/java/com/dashjoin/jsonata/Parser.java index 553494f..5749d5c 100644 --- a/src/main/java/com/dashjoin/jsonata/Parser.java +++ b/src/main/java/com/dashjoin/jsonata/Parser.java @@ -28,6 +28,7 @@ import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; +import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -40,7 +41,7 @@ //var parseSignature = require('./signature'); @SuppressWarnings({"unchecked"}) -public class Parser { +public class Parser implements Serializable { boolean dbg = false; @@ -92,7 +93,7 @@ public static T clone(T object) { } } - public class Symbol implements Cloneable { + public class Symbol implements Cloneable, Serializable { //Symbol s; String id; @@ -505,7 +506,7 @@ public Parser() { c.value = "("; Symbol p = new Symbol(); c.procedure = p; p.type = "variable"; p.value = "exists"; - c.arguments = List.of(left); + c.arguments = List.of(Parser.clone(left)); } this.then = left; this._else = expression(0); @@ -812,7 +813,12 @@ Symbol led(Symbol left) { @Override Symbol led(Symbol left) { this.type = "condition"; - this.condition = left; + // Deep-clone `left` so the condition and then branches have + // independent AST nodes. Sharing the same reference causes + // post-parse processing (e.g. predicate stages, unary minus + // folding on number literals) to mutate the same node twice, + // producing wrong results (see #773 for the equivalent ?? fix). + this.condition = Parser.clone(left); this.then = left; this._else = expression(0); return this; diff --git a/src/main/java/com/dashjoin/jsonata/Tokenizer.java b/src/main/java/com/dashjoin/jsonata/Tokenizer.java index 1da1ec9..fb538e7 100644 --- a/src/main/java/com/dashjoin/jsonata/Tokenizer.java +++ b/src/main/java/com/dashjoin/jsonata/Tokenizer.java @@ -28,7 +28,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -public class Tokenizer { // = function (path) { +public class Tokenizer implements java.io.Serializable { // = function (path) { static HashMap operators = new HashMap() {{ put(".", 75);