This is an automated email from the ASF dual-hosted git repository.

henrib pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-jexl.git


The following commit(s) were added to refs/heads/master by this push:
     new a69782b  JEXL-306: attempting behavior harmonization; modified tests
a69782b is described below

commit a69782bea469a766f71f12f76e9d5154b7415be4
Author: henrib <[email protected]>
AuthorDate: Mon Jun 10 18:34:09 2019 +0200

    JEXL-306: attempting behavior harmonization; modified tests
---
 .../apache/commons/jexl3/internal/Interpreter.java | 41 +++++++++++++++++---
 .../org/apache/commons/jexl3/parser/JexlNode.java  | 25 ++++++++----
 .../org/apache/commons/jexl3/Issues300Test.java    | 45 +++++++++++++++++++++-
 3 files changed, 98 insertions(+), 13 deletions(-)

diff --git a/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java 
b/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java
index f0aaa66..77dd729 100644
--- a/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java
+++ b/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java
@@ -864,7 +864,22 @@ public class Interpreter extends InterpreterBase {
 
     @Override
     protected Object visit(ASTTernaryNode node, Object data) {
-        Object condition = node.jjtGetChild(0).jjtAccept(this, data);
+        Object condition = null;
+        try {
+            condition = node.jjtGetChild(0).jjtAccept(this, data);
+        } catch(JexlException.Property xprop) {
+            if (!jexl.safe) {
+                throw xprop;
+            }
+            if (logger.isDebugEnabled()) {
+                logger.debug(node, xprop);
+            }
+        } catch(JexlException.Variable xvar) {
+            if (logger.isDebugEnabled()) {
+                logger.debug(node, xvar);
+            }
+        }
+        // ternary as in "x ? y : z"
         if (node.jjtGetNumChildren() == 3) {
             if (condition != null && arithmetic.toBoolean(condition)) {
                 return node.jjtGetChild(1).jjtAccept(this, data);
@@ -872,6 +887,7 @@ public class Interpreter extends InterpreterBase {
                 return node.jjtGetChild(2).jjtAccept(this, data);
             }
         }
+        // elvis as in "x ?: z"
         if (condition != null && arithmetic.toBoolean(condition)) {
             return condition;
         } else {
@@ -881,7 +897,22 @@ public class Interpreter extends InterpreterBase {
 
     @Override
     protected Object visit(ASTNullpNode node, Object data) {
-        Object lhs = node.jjtGetChild(0).jjtAccept(this, data);
+        Object lhs = null;
+        try {
+            lhs = node.jjtGetChild(0).jjtAccept(this, data);
+        } catch(JexlException.Property xprop) {
+            if (!jexl.safe) {
+                throw xprop;
+            }
+            if (logger.isDebugEnabled()) {
+                logger.debug(node, xprop);
+            }
+        } catch(JexlException.Variable xvar) {
+            if (logger.isDebugEnabled()) {
+                logger.debug(node, xvar);
+            }
+        }
+        // null elision as in "x ?? z"
         return lhs != null? lhs : node.jjtGetChild(1).jjtAccept(this, data);
     }
 
@@ -952,7 +983,7 @@ public class Interpreter extends InterpreterBase {
             if (value == null
                 && !(node.jjtGetParent() instanceof ASTReference)
                 && !(context.has(name))
-                && !node.isTernaryProtected()) {
+                /*&& !node.isTernaryProtected()*/) {
                 return jexl.safe
                         ? null
                         : unsolvableVariable(node, name, !(node.getSymbol() >= 
0 || context.has(name)));
@@ -1025,7 +1056,7 @@ public class Interpreter extends InterpreterBase {
     }
 
     @Override
-    protected Object visit(ASTReference node, Object data) {
+    protected Object visit(final ASTReference node, Object data) {
         cancelCheck(node);
         final int numChildren = node.jjtGetNumChildren();
         final JexlNode parent = node.jjtGetParent();
@@ -1119,7 +1150,7 @@ public class Interpreter extends InterpreterBase {
             }
         }
         // am I the left-hand side of a safe op ?
-        if (object == null && !node.isTernaryProtected()) {
+        if (object == null/* && !node.isTernaryProtected()*/) {
             if (ptyNode != null) {
                 if (ptyNode.isSafeLhs(jexl.safe)) {
                     return null;
diff --git a/src/main/java/org/apache/commons/jexl3/parser/JexlNode.java 
b/src/main/java/org/apache/commons/jexl3/parser/JexlNode.java
index 092467a..a62aa2f 100644
--- a/src/main/java/org/apache/commons/jexl3/parser/JexlNode.java
+++ b/src/main/java/org/apache/commons/jexl3/parser/JexlNode.java
@@ -262,19 +262,30 @@ public abstract class JexlNode extends SimpleNode {
         JexlNode node = this;
         for (JexlNode walk = node.jjtGetParent(); walk != null; walk = 
walk.jjtGetParent()) {
             // protect only the condition part of the ternay
-            if (walk instanceof ASTTernaryNode && node == walk.jjtGetChild(0)) 
{
-                return true;
-            }
-            if (walk instanceof ASTNullpNode && node == walk.jjtGetChild(0)) {
-                return true;
+            if (walk instanceof ASTTernaryNode || walk instanceof 
ASTNullpNode) {
+                if (node.isDescendantOf(walk.jjtGetChild(0))) {
+                    return true;
+                }
+                continue;
             }
             if (!(walk instanceof ASTReference || walk instanceof 
ASTArrayAccess)) {
                 break;
             }
-            node = walk;
         }
         return false;
     }
 
-
+    /**
+     * Whether this node is descendant or self of another.
+     * @param asc the (potential) ascendant
+     * @return true if descendant or self, false otherwise
+     */
+    private boolean isDescendantOf(JexlNode asc) {
+        for (JexlNode walk = this; walk != null; walk = walk.jjtGetParent()) {
+            if (walk == asc) {
+                return true;
+            }
+        }
+        return false;
+    }
 }
diff --git a/src/test/java/org/apache/commons/jexl3/Issues300Test.java 
b/src/test/java/org/apache/commons/jexl3/Issues300Test.java
index 65a3b13..78c221b 100644
--- a/src/test/java/org/apache/commons/jexl3/Issues300Test.java
+++ b/src/test/java/org/apache/commons/jexl3/Issues300Test.java
@@ -123,5 +123,48 @@ public class Issues300Test {
         String str1 = e.getParsedText();
         Assert.assertEquals(str0, str1);
     }
-
+    
+    @Test
+    public void testIssue306() throws Exception {
+        JexlEngine jexl = new JexlBuilder().create();
+        JexlScript e = jexl.createScript("x.y ?: 2");
+        Object o1 = e.execute(null);
+        Assert.assertEquals(2, o1);
+        Object o2 = e.execute(null);
+        Assert.assertEquals(2, o2);
+    }
+    
+    @Test
+    public void testIssue306a() throws Exception {
+        JexlEngine jexl = new JexlBuilder().create();
+        JexlScript e = jexl.createScript("x.y ?: 2", "x");
+        try {
+            Object o = e.execute(null, new Object());
+            Assert.fail(e.toString());
+        } catch (JexlException xany) {
+            Assert.assertTrue(xany.toString().contains("y"));
+        }
+        Object o = e.execute(null);
+        Assert.assertEquals(2, o);
+    }
+    
+    @Test
+    public void testIssue306b() throws Exception {
+        JexlEngine jexl = new JexlBuilder().create();
+        JexlScript e = jexl.createScript("x?.y ?: 2", "x");
+        Object o1 = e.execute(null, new Object());
+        Assert.assertEquals(2, o1);
+        Object o2 = e.execute(null);
+        Assert.assertEquals(2, o2);
+    }
+    
+    @Test
+    public void testIssue306c() throws Exception {
+        JexlEngine jexl = new JexlBuilder().safe(true).create();
+        JexlScript e = jexl.createScript("x.y ?: 2", "x");
+        Object o = e.execute(null, new Object());
+        Assert.assertEquals(2, o);
+        o = e.execute(null);
+        Assert.assertEquals(2, o);
+    }
 }

Reply via email to