Return-Path: Delivered-To: apmail-commons-commits-archive@minotaur.apache.org Received: (qmail 63589 invoked from network); 26 Mar 2010 15:08:35 -0000 Received: from unknown (HELO mail.apache.org) (140.211.11.3) by 140.211.11.9 with SMTP; 26 Mar 2010 15:08:35 -0000 Received: (qmail 81941 invoked by uid 500); 26 Mar 2010 15:08:35 -0000 Delivered-To: apmail-commons-commits-archive@commons.apache.org Received: (qmail 81883 invoked by uid 500); 26 Mar 2010 15:08:35 -0000 Mailing-List: contact commits-help@commons.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@commons.apache.org Delivered-To: mailing list commits@commons.apache.org Received: (qmail 81876 invoked by uid 99); 26 Mar 2010 15:08:35 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 26 Mar 2010 15:08:35 +0000 X-ASF-Spam-Status: No, hits=-1070.2 required=10.0 tests=ALL_TRUSTED,AWL X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 26 Mar 2010 15:08:33 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id DAF4C238898B; Fri, 26 Mar 2010 15:08:12 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r927903 - in /commons/proper/jexl/trunk/src: main/java/org/apache/commons/jexl2/ main/java/org/apache/commons/jexl2/parser/ test/java/org/apache/commons/jexl2/ Date: Fri, 26 Mar 2010 15:08:12 -0000 To: commits@commons.apache.org From: henrib@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20100326150812.DAF4C238898B@eris.apache.org> Author: henrib Date: Fri Mar 26 15:08:12 2010 New Revision: 927903 URL: http://svn.apache.org/viewvc?rev=927903&view=rev Log: Fix JEXL-100; Added JexlNode.Literal to improve cache abilities and usage, used as base for AST{Integer,String}Literal; Reviewed assignment and reference related code to improve antish variable handling; Added related tests and improve coverage Added: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/ASTIntegerLiteral.java (with props) commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/ASTStringLiteral.java (with props) Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/Interpreter.java commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/JexlNode.java commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/ArrayAccessTest.java commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/AssignTest.java commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/IssuesTest.java Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/Interpreter.java URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/Interpreter.java?rev=927903&r1=927902&r2=927903&view=diff ============================================================================== --- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/Interpreter.java (original) +++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/Interpreter.java Fri Mar 26 15:08:12 2010 @@ -348,8 +348,12 @@ public class Interpreter implements Pars int numChildren = node.jjtGetNumChildren(); for (int i = 1; i < numChildren; i++) { JexlNode nindex = node.jjtGetChild(i); - Object index = nindex.jjtAccept(this, null); - object = getAttribute(object, index, nindex); + if (nindex instanceof JexlNode.Literal) { + object = nindex.jjtAccept(this, object); + } else { + Object index = nindex.jjtAccept(this, null); + object = getAttribute(object, index, nindex); + } } return object; @@ -415,34 +419,13 @@ public class Interpreter implements Pars } // 2: last objectNode will perform assignement in all cases propertyNode = left.jjtGetChild(last); + boolean antVar = false; if (propertyNode instanceof ASTIdentifier) { property = ((ASTIdentifier) propertyNode).image; - // deal with ant variable - if (isVariable && object == null) { - if (variableName != null) { - if (last > 0) { - variableName.append('.'); - } - variableName.append(property); - property = variableName.toString(); - } - context.set(String.valueOf(property), right); - return right; - } + antVar = true; } else if (propertyNode instanceof ASTIntegerLiteral) { - property = visit((ASTIntegerLiteral) propertyNode, null); - // deal with ant variable - if (isVariable && object == null) { - if (variableName != null) { - if (last > 0) { - variableName.append('.'); - } - variableName.append(property); - property = variableName.toString(); - } - context.set(String.valueOf(property), right); - return right; - } + property = ((ASTIntegerLiteral) propertyNode).getLiteral(); + antVar = true; } else if (propertyNode instanceof ASTArrayAccess) { // first objectNode is the identifier objectNode = propertyNode; @@ -458,13 +441,31 @@ public class Interpreter implements Pars last = narray.jjtGetNumChildren() - 1; for (int i = 1; i < last; i++) { objectNode = narray.jjtGetChild(i); - Object index = objectNode.jjtAccept(this, null); - object = getAttribute(object, index, objectNode); + if (objectNode instanceof JexlNode.Literal) { + object = objectNode.jjtAccept(this, object); + } else { + Object index = objectNode.jjtAccept(this, null); + object = getAttribute(object, index, objectNode); + } } property = narray.jjtGetChild(last).jjtAccept(this, null); } else { throw new JexlException(objectNode, "illegal assignment form"); } + // deal with ant variable; set context + if (antVar) { + if (isVariable && object == null) { + if (variableName != null) { + if (last > 0) { + variableName.append('.'); + } + variableName.append(property); + property = variableName.toString(); + } + context.set(String.valueOf(property), right); + return right; + } + } if (property == null) { // no property, we fail throw new JexlException(propertyNode, "property is null"); @@ -574,12 +575,12 @@ public class Interpreter implements Pars if (o.getClass().isArray() && ((Object[]) o).length == 0) { return Boolean.TRUE; } - if (o instanceof Collection && ((Collection) o).isEmpty()) { - return Boolean.TRUE; + if (o instanceof Collection) { + return ((Collection) o).isEmpty()? Boolean.TRUE : Boolean.FALSE; } // Map isn't a collection - if (o instanceof Map && ((Map) o).isEmpty()) { - return Boolean.TRUE; + if (o instanceof Map) { + return ((Map) o).isEmpty()? Boolean.TRUE : Boolean.FALSE; } return Boolean.FALSE; } @@ -602,8 +603,8 @@ public class Interpreter implements Pars /** {@inheritDoc} */ public Object visit(ASTFloatLiteral node, Object data) { - Float value = (Float) node.jjtGetValue(); - if (value == null) { + Object value = node.jjtGetValue(); + if (!(value instanceof Float)) { value = Float.valueOf(node.image); node.jjtSetValue(value); } @@ -726,15 +727,9 @@ public class Interpreter implements Pars /** {@inheritDoc} */ public Object visit(ASTIntegerLiteral node, Object data) { if (data != null) { - Integer value = Integer.valueOf(node.image); - return getAttribute(data, value, node); - } - Integer value = (Integer) node.jjtGetValue(); - if (value == null) { - value = Integer.valueOf(node.image); - node.jjtSetValue(value); + return getAttribute(data, node.getLiteral(), node); } - return value; + return node.getLiteral(); } /** {@inheritDoc} */ @@ -1044,15 +1039,20 @@ public class Interpreter implements Pars int v = 0; for (int c = 0; c < numChildren; c++) { JexlNode theNode = node.jjtGetChild(c); - isVariable &= (theNode instanceof ASTIdentifier); - result = theNode.jjtAccept(this, result); + // integer literals may be part of an antish var name only if no bean was found so far + if (result == null && theNode instanceof ASTIntegerLiteral) { + isVariable &= v > 0; + } else { + isVariable &= (theNode instanceof ASTIdentifier); + result = theNode.jjtAccept(this, result); + } // if we get null back a result, check for an ant variable if (result == null && isVariable) { if (v == 0) { variableName = new StringBuilder(node.jjtGetChild(0).image); v = 1; } - for(; v <= c; ++v) { + for (; v <= c; ++v) { variableName.append('.'); variableName.append(node.jjtGetChild(v).image); } @@ -1061,8 +1061,8 @@ public class Interpreter implements Pars } if (result == null) { if (isVariable - && !(node.jjtGetParent() instanceof ASTTernaryNode) - && !context.has(variableName.toString())) { + && !(node.jjtGetParent() instanceof ASTTernaryNode) + && !context.has(variableName.toString())) { JexlException xjexl = new JexlException(node, "undefined variable " + variableName.toString()); return unknownVariable(xjexl); } @@ -1088,6 +1088,9 @@ public class Interpreter implements Pars /** {@inheritDoc} */ public Object visit(ASTStringLiteral node, Object data) { + if (data != null) { + return getAttribute(data, node.getLiteral(), node); + } return node.image; } Added: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/ASTIntegerLiteral.java URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/ASTIntegerLiteral.java?rev=927903&view=auto ============================================================================== --- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/ASTIntegerLiteral.java (added) +++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/ASTIntegerLiteral.java Fri Mar 26 15:08:12 2010 @@ -0,0 +1,42 @@ +/* + * 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.jexl2.parser; + +public class ASTIntegerLiteral extends JexlNode implements JexlNode.Literal { + /** The type literal value. */ + private Integer literal; + + public ASTIntegerLiteral(int id) { + super(id); + } + + public ASTIntegerLiteral(Parser p, int id) { + super(p, id); + } + + public Integer getLiteral() { + if (literal == null) { + literal = Integer.valueOf(image); + } + return literal; + } + + /** Accept the visitor. **/ + public Object jjtAccept(ParserVisitor visitor, Object data) { + return visitor.visit(this, data); + } +} Propchange: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/ASTIntegerLiteral.java ------------------------------------------------------------------------------ svn:eol-style = native Added: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/ASTStringLiteral.java URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/ASTStringLiteral.java?rev=927903&view=auto ============================================================================== --- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/ASTStringLiteral.java (added) +++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/ASTStringLiteral.java Fri Mar 26 15:08:12 2010 @@ -0,0 +1,37 @@ +/* + * 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.jexl2.parser; + +public class ASTStringLiteral extends JexlNode implements JexlNode.Literal { + + public ASTStringLiteral(int id) { + super(id); + } + + public ASTStringLiteral(Parser p, int id) { + super(p, id); + } + + public String getLiteral() { + return image; + } + + /** Accept the visitor. **/ + public Object jjtAccept(ParserVisitor visitor, Object data) { + return visitor.visit(this, data); + } +} Propchange: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/ASTStringLiteral.java ------------------------------------------------------------------------------ svn:eol-style = native Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/JexlNode.java URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/JexlNode.java?rev=927903&r1=927902&r2=927903&view=diff ============================================================================== --- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/JexlNode.java (original) +++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/parser/JexlNode.java Fri Mar 26 15:08:12 2010 @@ -24,6 +24,13 @@ import org.apache.commons.jexl2.JexlInfo * @since 2.0 */ public abstract class JexlNode extends SimpleNode implements JexlInfo { + /** A marker interface for literals. + * @param the literal type + */ + public interface Literal { + T getLiteral(); + } + /** token value. */ public String image; Modified: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/ArrayAccessTest.java URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/ArrayAccessTest.java?rev=927903&r1=927902&r2=927903&view=diff ============================================================================== --- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/ArrayAccessTest.java (original) +++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/ArrayAccessTest.java Fri Mar 26 15:08:12 2010 @@ -123,7 +123,7 @@ public class ArrayAccessTest extends Jex asserter.assertExpression("foo.array[1]", GET_METHOD_ARRAY[1]); asserter.assertExpression("foo.array.1", GET_METHOD_ARRAY[1]); asserter.assertExpression("foo.array2[1][1]", GET_METHOD_ARRAY2[1][1]); - // asserter.assertExpression("foo.array2.1.1", GET_METHOD_ARRAY2[1][1]); + asserter.assertExpression("foo.array2[1].1", GET_METHOD_ARRAY2[1][1]); } // This is JEXL-26 @@ -133,9 +133,11 @@ public class ArrayAccessTest extends Jex asserter.setVariable("objects", objects); asserter.setVariable("status", "Enabled"); asserter.assertExpression("objects[1].status", null); + asserter.assertExpression("objects.1.status", null); asserter.setVariable("base.status", "Ok"); asserter.assertExpression("base.objects[1].status", null); + asserter.assertExpression("base.objects.1.status", null); } public void testArrayMethods() throws Exception { @@ -148,4 +150,70 @@ public class ArrayAccessTest extends Jex asserter.assertExpression("objects.set(1, 'dion')", "array"); asserter.assertExpression("objects[1]", "dion"); } + + public void testArrayArray() throws Exception { + Integer i42 = Integer.valueOf(42); + Integer i43 = Integer.valueOf(43); + String s42 = "fourty-two"; + String s43 = "fourty-three"; + Object[] foo = new Object[3]; + foo[0] = foo; + foo[1] = i42; + foo[2] = s42; + asserter.setVariable("foo", foo); + asserter.setVariable("zero", 0); + asserter.setVariable("one", 1); + asserter.setVariable("two", 2); + for(int l = 0; l < 2; ++l) { + asserter.assertExpression("foo[0]", foo); + asserter.assertExpression("foo[0][0]", foo); + asserter.assertExpression("foo[1]", foo[1]); + asserter.assertExpression("foo[0][1]", foo[1]); + asserter.assertExpression("foo[0][1] = 43", i43); + asserter.assertExpression("foo[0][1]", i43); + asserter.assertExpression("foo[0][1] = 42", i42); + asserter.assertExpression("foo[0][1]", i42); + asserter.assertExpression("foo[0][0][1]", foo[1]); + asserter.assertExpression("foo[0][0][1] = 43", i43); + asserter.assertExpression("foo[0][0][1]", i43); + asserter.assertExpression("foo[0][0][1] = 42", i42); + asserter.assertExpression("foo[0][0][1]", i42); + asserter.assertExpression("foo[2]", foo[2]); + asserter.assertExpression("foo[0][2]", foo[2]); + asserter.assertExpression("foo[0][2] = 'fourty-three'", s43); + asserter.assertExpression("foo[0][2]", s43); + asserter.assertExpression("foo[0][2] = 'fourty-two'", s42); + asserter.assertExpression("foo[0][2]", s42); + asserter.assertExpression("foo[0][0][2]", foo[2]); + asserter.assertExpression("foo[0][0][2] = 'fourty-three'", s43); + asserter.assertExpression("foo[0][0][2]", s43); + asserter.assertExpression("foo[0][0][2] = 'fourty-two'", s42); + asserter.assertExpression("foo[0][0][2]", s42); + + asserter.assertExpression("foo[zero]", foo); + asserter.assertExpression("foo[zero][zero]", foo); + asserter.assertExpression("foo[one]", foo[1]); + asserter.assertExpression("foo[zero][one]", foo[1]); + asserter.assertExpression("foo[zero][one] = 43", i43); + asserter.assertExpression("foo[zero][one]", i43); + asserter.assertExpression("foo[zero][one] = 42", i42); + asserter.assertExpression("foo[zero][one]", i42); + asserter.assertExpression("foo[zero][zero][one]", foo[1]); + asserter.assertExpression("foo[zero][zero][one] = 43", i43); + asserter.assertExpression("foo[zero][zero][one]", i43); + asserter.assertExpression("foo[zero][zero][one] = 42", i42); + asserter.assertExpression("foo[zero][zero][one]", i42); + asserter.assertExpression("foo[two]", foo[2]); + asserter.assertExpression("foo[zero][two]", foo[2]); + asserter.assertExpression("foo[zero][two] = 'fourty-three'", s43); + asserter.assertExpression("foo[zero][two]", s43); + asserter.assertExpression("foo[zero][two] = 'fourty-two'", s42); + asserter.assertExpression("foo[zero][two]", s42); + asserter.assertExpression("foo[zero][zero][two]", foo[2]); + asserter.assertExpression("foo[zero][zero][two] = 'fourty-three'", s43); + asserter.assertExpression("foo[zero][zero][two]", s43); + asserter.assertExpression("foo[zero][zero][two] = 'fourty-two'", s42); + asserter.assertExpression("foo[zero][zero][two]", s42); + } + } } \ No newline at end of file Modified: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/AssignTest.java URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/AssignTest.java?rev=927903&r1=927902&r2=927903&view=diff ============================================================================== --- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/AssignTest.java (original) +++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/AssignTest.java Fri Mar 26 15:08:12 2010 @@ -85,6 +85,16 @@ public class AssignTest extends JexlTest o = check.evaluate(jc); assertEquals("Result is not 10", new Integer(10), o); } + + public void testAntishInteger() throws Exception { + Expression assign = ENGINE.createExpression("froboz.0 = 10"); + Expression check = ENGINE.createExpression("froboz.0"); + JexlContext jc = new MapContext(); + Object o = assign.evaluate(jc); + assertEquals("Result is not 10", new Integer(10), o); + o = check.evaluate(jc); + assertEquals("Result is not 10", new Integer(10), o); + } public void testBeanish() throws Exception { Expression assign = ENGINE.createExpression("froboz.value = 10"); Modified: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/IssuesTest.java URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/IssuesTest.java?rev=927903&r1=927902&r2=927903&view=diff ============================================================================== --- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/IssuesTest.java (original) +++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/IssuesTest.java Fri Mar 26 15:08:12 2010 @@ -376,13 +376,18 @@ public class IssuesTest extends JexlTest public void test100() throws Exception { JexlEngine jexl = new JexlEngine(); jexl.setCache(4); - String expr = "foo[0]"; JexlContext ctxt = new MapContext(); int[] foo = { 42 }; ctxt.set("foo", foo); - + Object value ; for(int l = 0; l < 2; ++l) { - Object value = jexl.createExpression(expr).evaluate(ctxt); + value = jexl.createExpression("foo[0]").evaluate(ctxt); + assertEquals(42, value); + value = jexl.createExpression("foo[0] = 43").evaluate(ctxt); + assertEquals(43, value); + value = jexl.createExpression("foo.0").evaluate(ctxt); + assertEquals(43, value); + value = jexl.createExpression("foo.0 = 42").evaluate(ctxt); assertEquals(42, value); } }