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
commit 0d51800d90fb783a65d266ea41d0bdad1709edb4 Author: henrib <[email protected]> AuthorDate: Thu Jun 3 13:31:47 2021 +0200 JEXL-348: refined grammar using semantic infos and a syntactic kludge as fallback to allow user disambiguation of namespace usage, tests --- .../apache/commons/jexl3/parser/JexlParser.java | 62 +++++++++------------- .../apache/commons/jexl3/ContextNamespaceTest.java | 9 ++-- .../org/apache/commons/jexl3/Issues300Test.java | 9 +++- 3 files changed, 39 insertions(+), 41 deletions(-) diff --git a/src/main/java/org/apache/commons/jexl3/parser/JexlParser.java b/src/main/java/org/apache/commons/jexl3/parser/JexlParser.java index 3116916..59dcb3e 100644 --- a/src/main/java/org/apache/commons/jexl3/parser/JexlParser.java +++ b/src/main/java/org/apache/commons/jexl3/parser/JexlParser.java @@ -31,7 +31,6 @@ import java.util.ArrayDeque; import java.util.Arrays; import java.util.Deque; import java.util.HashSet; -import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; @@ -131,6 +130,7 @@ public abstract class JexlParser extends StringParser { loopCount = 0; blocks.clear(); block = null; + this.setFeatures(features); } /** @@ -138,7 +138,7 @@ public abstract class JexlParser extends StringParser { * @param lstr the list of strings * @return the dotted version */ - protected static String stringify(final List<String> lstr) { + protected static String stringify(final Iterable<String> lstr) { final StringBuilder strb = new StringBuilder(); boolean dot = false; for(final String str : lstr) { @@ -183,7 +183,7 @@ public abstract class JexlParser extends StringParser { /** * Sets a new set of options. - * @param features + * @param features the parser features */ protected void setFeatures(final JexlFeatures features) { this.featureController.setFeatures(features); @@ -269,7 +269,7 @@ public abstract class JexlParser extends StringParser { * Checks if a symbol is defined in lexical scopes. * <p>This works with with parsed scripts in template resolution only. * @param info an info linked to a node - * @param symbol + * @param symbol the symbol number * @return true if symbol accessible in lexical scope */ private boolean isSymbolDeclared(final JexlNode.Info info, final int symbol) { @@ -364,15 +364,13 @@ public abstract class JexlParser extends StringParser { * if it is already declared */ private boolean declareSymbol(final int symbol) { - if (blocks != null) { - for (final LexicalUnit lu : blocks) { - if (lu.hasSymbol(symbol)) { - return false; - } - // stop at first new scope reset, aka lambda - if (lu instanceof ASTJexlLambda) { - break; - } + for (final LexicalUnit lu : blocks) { + if (lu.hasSymbol(symbol)) { + return false; + } + // stop at first new scope reset, aka lambda + if (lu instanceof ASTJexlLambda) { + break; } } return block == null || block.declareSymbol(symbol); @@ -381,10 +379,10 @@ public abstract class JexlParser extends StringParser { /** * Declares a local variable. * <p> This method creates an new entry in the symbol map. </p> - * @param var the identifier used to declare + * @param variable the identifier used to declare * @param token the variable name toekn */ - protected void declareVariable(final ASTVar var, final Token token) { + protected void declareVariable(final ASTVar variable, final Token token) { final String name = token.image; if (!allowVariable(name)) { throwFeatureException(JexlFeatures.LOCAL_VAR, token); @@ -393,16 +391,16 @@ public abstract class JexlParser extends StringParser { frame = new Scope(null, (String[]) null); } final int symbol = frame.declareVariable(name); - var.setSymbol(symbol, name); + variable.setSymbol(symbol, name); if (frame.isCapturedSymbol(symbol)) { - var.setCaptured(true); + variable.setCaptured(true); } // lexical feature error if (!declareSymbol(symbol)) { if (getFeatures().isLexical()) { - throw new JexlException(var, name + ": variable is already declared"); + throw new JexlException(variable, name + ": variable is already declared"); } - var.setRedefined(true); + variable.setRedefined(true); } } @@ -421,7 +419,7 @@ public abstract class JexlParser extends StringParser { throwFeatureException(JexlFeatures.PRAGMA, getToken(0)); } if (pragmas == null) { - pragmas = new TreeMap<String, Object>(); + pragmas = new TreeMap<>(); } // declaring a namespace Predicate<String> ns = getFeatures().namespaceTest(); @@ -495,10 +493,6 @@ public abstract class JexlParser extends StringParser { // Overriden by generated code } - final protected void Identifier() throws ParseException { - Identifier(false); - } - /** * Overridden in actual parser to access tokens stack. * @param index 0 to get current token @@ -515,8 +509,7 @@ public abstract class JexlParser extends StringParser { /** * The set of assignment operators as classes. */ - @SuppressWarnings("unchecked") - private static final Set<Class<? extends JexlNode>> ASSIGN_NODES = new HashSet<Class<? extends JexlNode>>( + private static final Set<Class<? extends JexlNode>> ASSIGN_NODES = new HashSet<>( Arrays.asList( ASTAssignment.class, ASTSetAddNode.class, @@ -542,9 +535,9 @@ public abstract class JexlParser extends StringParser { * <p> * Detects "Ambiguous statement" and 'non-left value assignment'.</p> * @param node the node - * @throws ParseException + * @throws JexlException.Parsing when parsing fails */ - protected void jjtreeCloseNodeScope(final JexlNode node) throws ParseException { + protected void jjtreeCloseNodeScope(final JexlNode node) { if (node instanceof ASTAmbiguous) { throwAmbiguousException(node); } @@ -572,6 +565,7 @@ public abstract class JexlParser extends StringParser { * Throws Ambiguous exception. * <p>Seeks the end of the ambiguous statement to recover. * @param node the first token in ambiguous expression + * @throws JexlException.Ambiguous in all cases */ protected void throwAmbiguousException(final JexlNode node) { final JexlInfo begin = node.jexlInfo(); @@ -585,6 +579,7 @@ public abstract class JexlParser extends StringParser { * Throws a feature exception. * @param feature the feature code * @param info the exception surroundings + * @throws JexlException.Feature in all cases */ protected void throwFeatureException(final int feature, final JexlInfo info) { final String msg = info != null? readSourceLine(source, info.getLine()) : null; @@ -595,6 +590,8 @@ public abstract class JexlParser extends StringParser { * Throws a feature exception. * @param feature the feature code * @param token the token that triggered it + * @throws JexlException.Parsing if actual error token can not be found + * @throws JexlException.Feature in all other cases */ protected void throwFeatureException(final int feature, Token token) { if (token == null) { @@ -608,18 +605,11 @@ public abstract class JexlParser extends StringParser { } /** - * Throws a parsing exception. - * @param node the node that caused it - */ - protected void throwParsingException(final JexlNode node) { - throwParsingException(null, null); - } - - /** * Creates a parsing exception. * @param xclazz the class of exception * @param tok the token to report * @param <T> the parsing exception subclass + * @throws JexlException.Parsing in all cases */ protected <T extends JexlException.Parsing> void throwParsingException(final Class<T> xclazz, Token tok) { JexlInfo xinfo = null; diff --git a/src/test/java/org/apache/commons/jexl3/ContextNamespaceTest.java b/src/test/java/org/apache/commons/jexl3/ContextNamespaceTest.java index c06b8bb..942fa95 100644 --- a/src/test/java/org/apache/commons/jexl3/ContextNamespaceTest.java +++ b/src/test/java/org/apache/commons/jexl3/ContextNamespaceTest.java @@ -164,10 +164,11 @@ public class ContextNamespaceTest extends JexlTestCase { public void testNamespace348b() throws Exception { JexlContext ctxt = new ContextNs348(); final JexlEngine jexl = new JexlBuilder().safe(false).create(); - run348a(jexl, ctxt, "ns:"); // no space for ns name - run348b(jexl, ctxt, "ns:"); // no space for ns name - run348c(jexl, ctxt); - run348d(jexl, ctxt); + // no space for ns name as syntactic hint + run348a(jexl, ctxt, "ns:"); + run348b(jexl, ctxt, "ns:"); + run348c(jexl, ctxt, "ns:"); + run348d(jexl, ctxt, "ns:"); } @Test diff --git a/src/test/java/org/apache/commons/jexl3/Issues300Test.java b/src/test/java/org/apache/commons/jexl3/Issues300Test.java index f3267d4..b5f774d 100644 --- a/src/test/java/org/apache/commons/jexl3/Issues300Test.java +++ b/src/test/java/org/apache/commons/jexl3/Issues300Test.java @@ -497,7 +497,7 @@ public class Issues300Test { final JexlExpression expr = jexl.createExpression("new()"); Assert.fail("should not parse"); } catch (final JexlException.Parsing xparse) { - Assert.assertTrue(xparse.toString().contains("new")); + Assert.assertTrue(xparse.toString().contains(")")); } } @@ -593,4 +593,11 @@ public class Issues300Test { result = script.execute(ctxt); Assert.assertFalse((Boolean) result); } + + @Test public void test349() throws Exception { + String text = "(A ? C.D : E)"; + JexlEngine jexl = new JexlBuilder().safe(true).create(); + JexlExpression expr = jexl.createExpression(text); + JexlScript script = jexl.createScript(text); + } }
