You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by he...@apache.org on 2015/08/27 21:57:16 UTC

svn commit: r1698221 - in /commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3: internal/Debugger.java internal/Engine.java internal/Scope.java parser/ASTJxltLiteral.java parser/Parser.jjt parser/ParserVisitor.java

Author: henrib
Date: Thu Aug 27 19:57:16 2015
New Revision: 1698221

URL: http://svn.apache.org/r1698221
Log:
JEXL:
Implemented JEXL-177; multiline formats use backquote (`) as delimiter and interpolate ${...} expressions

Added:
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTJxltLiteral.java   (with props)
Modified:
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Debugger.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Engine.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Scope.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/Parser.jjt
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ParserVisitor.java

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Debugger.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Debugger.java?rev=1698221&r1=1698220&r2=1698221&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Debugger.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Debugger.java Thu Aug 27 19:57:16 2015
@@ -51,6 +51,7 @@ import org.apache.commons.jexl3.parser.A
 import org.apache.commons.jexl3.parser.ASTIfStatement;
 import org.apache.commons.jexl3.parser.ASTJexlLambda;
 import org.apache.commons.jexl3.parser.ASTJexlScript;
+import org.apache.commons.jexl3.parser.ASTJxltLiteral;
 import org.apache.commons.jexl3.parser.ASTLENode;
 import org.apache.commons.jexl3.parser.ASTLTNode;
 import org.apache.commons.jexl3.parser.ASTMapEntry;
@@ -98,23 +99,23 @@ import java.util.regex.Pattern;
  * Helps pinpoint the cause of problems in expressions that fail during evaluation.
  * <p>
  * It rebuilds an expression string from the tree and the start/end offsets of the cause in that string.
- * This implies that exceptions during evaluation do allways carry the node that's causing the error.
+ * This implies that exceptions during evaluation do always carry the node that's causing the error.
  * </p>
  * @since 2.0
  */
-public final class Debugger extends ParserVisitor implements JexlInfo.Detail {
+public class Debugger extends ParserVisitor implements JexlInfo.Detail {
     /** The builder to compose messages. */
-    private final StringBuilder builder = new StringBuilder();
+    protected final StringBuilder builder = new StringBuilder();
     /** The cause of the issue to debug. */
-    private JexlNode cause = null;
+    protected JexlNode cause = null;
     /** The starting character location offset of the cause in the builder. */
-    private int start = 0;
+    protected int start = 0;
     /** The ending character location offset of the cause in the builder. */
-    private int end = 0;
+    protected int end = 0;
     /** The indentation level. */
-    private int indentLevel = 0;
+    protected int indentLevel = 0;
     /** Perform indentation?. */
-    private boolean indent = true;
+    protected int indent = 2;
 
     /**
      * Creates a Debugger.
@@ -167,18 +168,17 @@ public final class Debugger extends Pars
         start = 0;
         end = 0;
         indentLevel = 0;
-        indent = true;
         if (node != null) {
             builder.setLength(0);
             cause = node;
             // make arg cause become the root cause
-            JexlNode root = node;
+            JexlNode walk = node;
             if (r) {
-                while (root.jjtGetParent() != null) {
-                    root = root.jjtGetParent();
+                while (walk.jjtGetParent() != null) {
+                    walk = walk.jjtGetParent();
                 }
             }
-            root.jjtAccept(this, null);
+            accept(walk, null);
         }
         return end > 0;
     }
@@ -201,11 +201,10 @@ public final class Debugger extends Pars
         start = 0;
         end = 0;
         indentLevel = 0;
-        indent = true;
         if (node != null) {
             builder.setLength(0);
-            this.cause = node;
-            node.jjtAccept(this, null);
+            cause = node;
+            accept(node, null);
         }
         return builder.toString();
     }
@@ -227,12 +226,25 @@ public final class Debugger extends Pars
     }
 
     /**
+     * Sets the indentation level.
+     * @param level the number of spaces for indentation, none if less or equal to zero
+     */
+    public void setIndentation(int level) {
+        if (level <= 0) {
+            indent = 0;
+        } else {
+            indent = level;
+        }
+        indentLevel = 0;
+    }
+
+    /**
      * Checks if a child node is the cause to debug &amp; adds its representation to the rebuilt expression.
      * @param node the child node
      * @param data visitor pattern argument
      * @return visitor pattern value
      */
-    private Object accept(JexlNode node, Object data) {
+    protected Object accept(JexlNode node, Object data) {
         if (node == cause) {
             start = builder.length();
         }
@@ -249,22 +261,25 @@ public final class Debugger extends Pars
      * @param data  visitor pattern argument
      * @return visitor pattern value
      */
-    private Object acceptStatement(JexlNode child, Object data) {
-        if (indent) {
+    protected Object acceptStatement(JexlNode child, Object data) {
+        JexlNode parent = child.jjtGetParent();
+        if (indent > 0 && (parent instanceof ASTBlock || parent instanceof ASTJexlScript)) {
             for (int i = 0; i < indentLevel; ++i) {
-                builder.append("    ");
+                for(int s = 0; s < indent; ++s) {
+                    builder.append(' ');
+                }
             }
         }
         Object value = accept(child, data);
         // blocks, if, for & while dont need a ';' at end
         if (!(child instanceof ASTJexlScript
-                || child instanceof ASTBlock
-                || child instanceof ASTIfStatement
-                || child instanceof ASTForeachStatement
-                || child instanceof ASTWhileStatement)) {
-            builder.append(";");
-            if (indent) {
-                builder.append("\n");
+            || child instanceof ASTBlock
+            || child instanceof ASTIfStatement
+            || child instanceof ASTForeachStatement
+            || child instanceof ASTWhileStatement)) {
+            builder.append(';');
+            if (indent > 0) {
+                builder.append('\n');
             } else {
                 builder.append(' ');
             }
@@ -279,7 +294,7 @@ public final class Debugger extends Pars
      * @param data  visitor pattern argument
      * @return visitor pattern value
      */
-    private Object check(JexlNode node, String image, Object data) {
+    protected Object check(JexlNode node, String image, Object data) {
         if (node == cause) {
             start = builder.length();
         }
@@ -303,10 +318,10 @@ public final class Debugger extends Pars
      * @param data  visitor pattern argument
      * @return visitor pattern value
      */
-    private Object infixChildren(JexlNode node, String infix, boolean paren, Object data) {
+    protected Object infixChildren(JexlNode node, String infix, boolean paren, Object data) {
         int num = node.jjtGetNumChildren(); //child.jjtGetNumChildren() > 1;
         if (paren) {
-            builder.append("(");
+            builder.append('(');
         }
         for (int i = 0; i < num; ++i) {
             if (i > 0) {
@@ -315,7 +330,7 @@ public final class Debugger extends Pars
             accept(node.jjtGetChild(i), data);
         }
         if (paren) {
-            builder.append(")");
+            builder.append(')');
         }
         return data;
     }
@@ -328,15 +343,15 @@ public final class Debugger extends Pars
      * @param data   visitor pattern argument
      * @return visitor pattern value
      */
-    private Object prefixChild(JexlNode node, String prefix, Object data) {
+    protected Object prefixChild(JexlNode node, String prefix, Object data) {
         boolean paren = node.jjtGetChild(0).jjtGetNumChildren() > 1;
         builder.append(prefix);
         if (paren) {
-            builder.append("(");
+            builder.append('(');
         }
         accept(node.jjtGetChild(0), data);
         if (paren) {
-            builder.append(")");
+            builder.append(')');
         }
         return data;
     }
@@ -358,14 +373,14 @@ public final class Debugger extends Pars
      * @param data visitor pattern argument
      * @return visitor pattern value
      */
-    private Object additiveNode(JexlNode node, String op, Object data) {
+    protected Object additiveNode(JexlNode node, String op, Object data) {
         // need parenthesis if not in operator precedence order
         boolean paren = node.jjtGetParent() instanceof ASTMulNode
                 || node.jjtGetParent() instanceof ASTDivNode
                 || node.jjtGetParent() instanceof ASTModNode;
         int num = node.jjtGetNumChildren();
         if (paren) {
-            builder.append("(");
+            builder.append('(');
         }
         accept(node.jjtGetChild(0), data);
         for (int i = 1; i < num; ++i) {
@@ -373,7 +388,7 @@ public final class Debugger extends Pars
             accept(node.jjtGetChild(i), data);
         }
         if (paren) {
-            builder.append(")");
+            builder.append(')');
         }
         return data;
     }
@@ -387,9 +402,9 @@ public final class Debugger extends Pars
     protected Object visit(ASTArrayAccess node, Object data) {
         int num = node.jjtGetNumChildren();
         for (int i = 0; i < num; ++i) {
-            builder.append("[");
+            builder.append('[');
             accept(node.jjtGetChild(i), data);
-            builder.append("]");
+            builder.append(']');
         }
         return data;
     }
@@ -449,20 +464,27 @@ public final class Debugger extends Pars
 
     @Override
     protected Object visit(ASTBlock node, Object data) {
-        builder.append("{");
-        if (indent) {
-            builder.append("\n");
+        builder.append('{');
+        if (indent > 0) {
+            indentLevel += 1;
+            builder.append('\n');
         } else {
             builder.append(' ');
         }
-        indentLevel += 1;
         int num = node.jjtGetNumChildren();
         for (int i = 0; i < num; ++i) {
             JexlNode child = node.jjtGetChild(i);
             acceptStatement(child, data);
         }
-        indentLevel -= 1;
-        builder.append("}");
+        if (indent > 0) {
+            indentLevel -= 1;
+            for (int i = 0; i < indentLevel; ++i) {
+                for(int s = 0; s < indent; ++s) {
+                    builder.append(' ');
+                }
+            }
+        }
+        builder.append('}');
         return data;
     }
 
@@ -555,9 +577,9 @@ public final class Debugger extends Pars
         return infixChildren(node, " > ", false, data);
     }
     /** Checks identifiers that contain space, quote, double-quotes or backspace. */
-    private static final Pattern QUOTED_IDENTIFIER = Pattern.compile("['\"\\s\\\\]");
+    protected static final Pattern QUOTED_IDENTIFIER = Pattern.compile("['\"\\s\\\\]");
     /** Checks number used as identifiers. */
-    private static final Pattern NUMBER_IDENTIFIER = Pattern.compile("^\\d*$");
+    protected static final Pattern NUMBER_IDENTIFIER = Pattern.compile("^\\d*$");
 
     @Override
     protected Object visit(ASTIdentifier node, Object data) {
@@ -603,9 +625,19 @@ public final class Debugger extends Pars
         return check(node, node.toString(), data);
     }
 
+    /**
+     * A pseudo visitor for parameters.
+     * @param p the parameter name
+     * @param data the visitor argument
+     * @return the parameter name to use
+     */
+    protected String visitParameter(String p, Object data) {
+        return p;
+    }
+
     @Override
     protected Object visit(ASTJexlScript node, Object data) {
-        boolean ii = true;
+        // if lambda, produce parameters
         if (node instanceof ASTJexlLambda) {
             JexlNode parent = node.jjtGetParent();
             // use lambda syntax if not assigned
@@ -616,10 +648,10 @@ public final class Debugger extends Pars
             builder.append('(');
             String[] params = node.getParameters();
             if (params != null && params.length > 0) {
-                builder.append(params[0]);
+                builder.append(visitParameter(params[0], data));
                 for (int p = 1; p < params.length; ++p) {
                     builder.append(", ");
-                    builder.append(params[p]);
+                    builder.append(visitParameter(params[p], data));
                 }
             }
             builder.append(')');
@@ -627,12 +659,10 @@ public final class Debugger extends Pars
                 builder.append(' ');
             } else {
                 builder.append("->");
-                ii = false;
             }
+            // we will need a block...
         }
-        if (!ii) {
-            indent = false;
-        }
+        // no parameters or done with them
         int num = node.jjtGetNumChildren();
         if (num == 1 && !(node instanceof ASTJexlLambda)) {
             data = accept(node.jjtGetChild(0), data);
@@ -642,9 +672,6 @@ public final class Debugger extends Pars
                 acceptStatement(child, data);
             }
         }
-        if (!ii) {
-            indent = true;
-        }
         return data;
     }
 
@@ -672,11 +699,11 @@ public final class Debugger extends Pars
         builder.append("{ ");
         if (num > 0) {
             accept(node.jjtGetChild(0), data);
-                for (int i = 1; i < num; ++i) {
-                    builder.append(",");
-                    accept(node.jjtGetChild(i), data);
-                }
+            for (int i = 1; i < num; ++i) {
+                builder.append(",");
+                accept(node.jjtGetChild(i), data);
             }
+        }
         builder.append(" }");
         return data;
     }
@@ -701,8 +728,7 @@ public final class Debugger extends Pars
     @Override
     protected Object visit(ASTConstructorNode node, Object data) {
         int num = node.jjtGetNumChildren();
-        builder.append("new ");
-        builder.append("(");
+        builder.append("new(");
         accept(node.jjtGetChild(0), data);
         for (int i = 1; i < num; ++i) {
             builder.append(", ");
@@ -929,4 +955,10 @@ public final class Debugger extends Pars
     protected Object visit(ASTSetXorNode node, Object data) {
         return infixChildren(node, " ^= ", false, data);
     }
+
+    @Override
+    protected Object visit(ASTJxltLiteral node, Object data) {
+        String img = node.getLiteral().replace("`", "\\`");
+        return check(node, "`" + img + "`", data);
+    }
 }
\ No newline at end of file

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Engine.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Engine.java?rev=1698221&r1=1698220&r2=1698221&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Engine.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Engine.java Thu Aug 27 19:57:16 2015
@@ -71,8 +71,7 @@ public class Engine extends JexlEngine {
                 new Uberspect(LogManager.getLogger(JexlEngine.class), JexlUberspect.JEXL_STRATEGY);
 
         /** Non-instantiable. */
-        private UberspectHolder() {
-        }
+        private UberspectHolder() {}
     }
     /**
      * The JexlUberspect instance.
@@ -120,6 +119,10 @@ public class Engine extends JexlEngine {
      */
     protected final Charset charset;
     /**
+     * The default jxlt engine.
+     */
+    protected volatile TemplateEngine jxlt = null;
+    /**
      * The default cache load factor.
      */
     private static final float LOAD_FACTOR = 0.75f;
@@ -149,9 +152,9 @@ public class Engine extends JexlEngine {
         }
         this.logger = conf.logger() == null ? LogManager.getLogger(JexlEngine.class) : conf.logger();
         this.functions = conf.namespaces() == null ? Collections.<String, Object>emptyMap() : conf.namespaces();
-        this.silent = conf.silent() == null ? false : conf.silent().booleanValue();
-        this.debug = conf.debug() == null ? true : conf.debug().booleanValue();
-        this.strict = conf.strict() == null ? true : conf.strict().booleanValue();
+        this.silent = conf.silent() == null ? false : conf.silent();
+        this.debug = conf.debug() == null ? true : conf.debug();
+        this.strict = conf.strict() == null ? true : conf.strict();
         this.arithmetic = conf.arithmetic() == null ? new JexlArithmetic(this.strict) : conf.arithmetic();
         this.cache = conf.cache() <= 0 ? null : new SoftCache<String, ASTJexlScript>(conf.cache());
         this.cacheThreshold = conf.cacheThreshold();
@@ -710,4 +713,21 @@ public class Engine extends JexlEngine {
         }
         return null;
     }
+
+    /**
+     * Gets and/or creates a default template engine.
+     * @return a template engine
+     */
+    protected TemplateEngine jxlt() {
+        TemplateEngine e = jxlt;
+        if (e == null) {
+            synchronized(this) {
+                if (jxlt == null) {
+                    e = new TemplateEngine(this, true, 0, '$', '#');
+                    jxlt = e;
+                }
+            }
+        }
+        return e;
+    }
 }

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Scope.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Scope.java?rev=1698221&r1=1698220&r2=1698221&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Scope.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Scope.java Thu Aug 27 19:57:16 2015
@@ -74,24 +74,20 @@ public final class Scope {
 
     @Override
     public boolean equals(Object o) {
-        return o instanceof Scope && equals((Scope) o);
-    }
-
-    /**
-     * Whether this frame is equal to another.
-     * @param frame the frame to compare to
-     * @return true if equal, false otherwise
-     */
-    public boolean equals(Scope frame) {
-        if (this == frame) {
+        if (this == o) {
             return true;
-        } else if (frame == null || parms != frame.parms) {
+        }
+        if (!(o instanceof Scope)) {
             return false;
-        } else if (namedVariables == null) {
-            return frame.namedVariables == null;
-        } else {
-            return namedVariables.equals(frame.namedVariables);
         }
+        Scope scope = (Scope) o;
+        if (parms != scope.parms) {
+            return false;
+        }
+        if (namedVariables == null) {
+            return scope.namedVariables == null;
+        }
+        return namedVariables.equals(scope.namedVariables);
     }
 
     /**
@@ -197,7 +193,7 @@ public final class Scope {
                     arguments[target.intValue()] = arg;
                 }
             }
-            return new Frame(arguments);
+            return new Frame(this, arguments);
         } else {
             return null;
         }
@@ -280,17 +276,29 @@ public final class Scope {
      * @since 3.0
      */
     public static final class Frame {
+        /** The scope. */
+        private final Scope scope;
         /** The actual stack frame. */
         private final Object[] stack;
 
         /**
          * Creates a new frame.
+         * @param s the scope
          * @param r the stack frame
          */
-        public Frame(Object[] r) {
+        public Frame(Scope s, Object[] r) {
+            scope = s;
             stack = r;
         }
 
+        /**
+         * Gets the scope.
+         * @return this frame scope
+         */
+        public Scope getScope() {
+            return scope;
+        }
+
         @Override
         public int hashCode() {
             return Arrays.deepHashCode(this.stack);
@@ -335,7 +343,7 @@ public final class Scope {
             if (stack != null && values != null && values.length > 0) {
                 Object[] copy = stack.clone();
                 System.arraycopy(values, 0, copy, 0, Math.min(copy.length, values.length));
-                return new Frame(copy);
+                return new Frame(scope, copy);
             }
             return this;
         }

Added: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTJxltLiteral.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTJxltLiteral.java?rev=1698221&view=auto
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTJxltLiteral.java (added)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTJxltLiteral.java Thu Aug 27 19:57:16 2015
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.jexl3.parser;
+
+public final class ASTJxltLiteral extends JexlNode {
+    /** The actual literal value; the inherited 'value' member may host a cached template expression. */
+    private String literal = null;
+
+    ASTJxltLiteral(int id) {
+        super(id);
+    }
+
+    ASTJxltLiteral(Parser p, int id) {
+        super(p, id);
+    }
+
+    void setLiteral(String literal) {
+        this.literal = literal;
+    }
+
+    /**
+     * Gets the literal value.
+     * @return the string literal
+     */
+    public String getLiteral() {
+        return this.literal;
+    }
+
+    @Override
+    public String toString() {
+        return this.literal;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Object jjtAccept(ParserVisitor visitor, Object data) {
+        return visitor.visit(this, data);
+    }
+}

Propchange: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTJxltLiteral.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/Parser.jjt
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/Parser.jjt?rev=1698221&r1=1698220&r2=1698221&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/Parser.jjt (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/Parser.jjt Thu Aug 27 19:57:16 2015
@@ -228,6 +228,13 @@ PARSER_END(Parser)
   >
 }
 
+<*> TOKEN :
+{
+  < JXLT_LITERAL:
+    "`" (~["`","\\"] | "\\" ~["\u0000"])* "`"
+  >
+}
+
 /***************************************
  *      Statements
  ***************************************/
@@ -560,6 +567,8 @@ void Literal() #void :
 |
   BooleanLiteral()
 |
+  JxltLiteral()
+|
   StringLiteral()
 |
   NullLiteral()
@@ -614,6 +623,16 @@ void StringLiteral() :
   { jjtThis.setLiteral(Parser.buildString(t.image, true)); }
 }
 
+
+void JxltLiteral() #JxltLiteral :
+{
+   Token t;
+}
+{
+   t=<JXLT_LITERAL>
+   { jjtThis.setLiteral(Parser.buildString(t.image, true)); }
+}
+
 void ExtendedLiteral() #ExtendedLiteral() : {}
 {
    <ELIPSIS>

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ParserVisitor.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ParserVisitor.java?rev=1698221&r1=1698220&r2=1698221&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ParserVisitor.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ParserVisitor.java Thu Aug 27 19:57:16 2015
@@ -175,4 +175,6 @@ public abstract class ParserVisitor {
     protected abstract Object visit(ASTSetOrNode node, Object data);
 
     protected abstract Object visit(ASTSetXorNode node, Object data);
+
+    protected abstract Object visit(ASTJxltLiteral node, Object data);
 }