Author: hlship
Date: Thu Jan 8 14:46:48 2009
New Revision: 732861
URL: http://svn.apache.org/viewvc?rev=732861&view=rev
Log:
TAP5-79: Improve Tapestry's property expression language to include OGNL-like
features
- Add '!' (boolean not) operator
Added:
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/Switch.java
Modified:
tapestry/tapestry5/trunk/src/site/apt/guide/propexp.apt
tapestry/tapestry5/trunk/tapestry-core/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionLexer.g
tapestry/tapestry5/trunk/tapestry-core/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionParser.g
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/BasePropertyConduit.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImplTest.java
tapestry/tapestry5/trunk/tapestry-core/tapestry-core.iml
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ClassFabUtils.java
Modified: tapestry/tapestry5/trunk/src/site/apt/guide/propexp.apt
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/src/site/apt/guide/propexp.apt?rev=732861&r1=732860&r2=732861&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/src/site/apt/guide/propexp.apt (original)
+++ tapestry/tapestry5/trunk/src/site/apt/guide/propexp.apt Thu Jan 8 14:46:48
2009
@@ -47,7 +47,7 @@
Grammar
---
-expression : keyword | rangeOp | constant | propertyChain | list;
+expression : keyword | rangeOp | constant | propertyChain | list | notOp;
keyword : 'null' | 'true' | 'false' | 'this';
@@ -67,7 +67,9 @@
list : '[' expressionList? ']';
expressionList : expression (',' expression)*;
-
+
+notOpt : '!' expression;
+
---
Notes:
@@ -90,6 +92,8 @@
* 'this' is the root object (i.e., the containing component).
+ * The not operator coerces the expression to a boolean (so it can be used on
strings, numbers, etc.).
+
[]
Method matching is based on method name and number of parameters, but not
parameter types. The
Modified:
tapestry/tapestry5/trunk/tapestry-core/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionLexer.g
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionLexer.g?rev=732861&r1=732860&r2=732861&view=diff
==============================================================================
---
tapestry/tapestry5/trunk/tapestry-core/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionLexer.g
(original)
+++
tapestry/tapestry5/trunk/tapestry-core/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionLexer.g
Thu Jan 8 14:46:48 2009
@@ -53,6 +53,7 @@
LBRACKET: '[';
RBRACKET: ']';
COMMA : ',';
+BANG : '!';
fragment QUOTE
: '\'';
Modified:
tapestry/tapestry5/trunk/tapestry-core/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionParser.g
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionParser.g?rev=732861&r1=732860&r2=732861&view=diff
==============================================================================
---
tapestry/tapestry5/trunk/tapestry-core/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionParser.g
(original)
+++
tapestry/tapestry5/trunk/tapestry-core/src/main/antlr/org/apache/tapestry5/internal/antlr/PropertyExpressionParser.g
Thu Jan 8 14:46:48 2009
@@ -29,6 +29,8 @@
INVOKE;
// A List (top level, or as method parameter)
LIST;
+ // Not operation (invert a boolean)
+ NOT;
}
@header
@@ -45,6 +47,7 @@
| constant
| propertyChain
| list
+ | notOp
;
keyword : NULL | TRUE | FALSE | THIS;
@@ -76,7 +79,13 @@
rangeopArg
: INTEGER
- | propertyChain;
+ | propertyChain
+ ;
list : LBRACKET RBRACKET -> ^(LIST)
- | LBRACKET expressionList RBRACKET -> ^(LIST expressionList);
+ | LBRACKET expressionList RBRACKET -> ^(LIST expressionList)
+ ;
+
+
+notOp : BANG expression -> ^(NOT expression)
+ ;
Modified:
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/BasePropertyConduit.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/BasePropertyConduit.java?rev=732861&r1=732860&r2=732861&view=diff
==============================================================================
---
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/BasePropertyConduit.java
(original)
+++
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/BasePropertyConduit.java
Thu Jan 8 14:46:48 2009
@@ -75,4 +75,9 @@
{
return typeCoercer.coerce(value, type);
}
+
+ public final Boolean invert(Object value)
+ {
+ return coerce(value, Boolean.class).equals(Boolean.FALSE);
+ }
}
Modified:
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java?rev=732861&r1=732860&r2=732861&view=diff
==============================================================================
---
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
(original)
+++
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImpl.java
Thu Jan 8 14:46:48 2009
@@ -56,11 +56,14 @@
private static final Method RANGE;
+ private static final Method INVERT;
+
static
{
try
{
RANGE = BasePropertyConduit.class.getMethod("range", int.class,
int.class);
+ INVERT = BasePropertyConduit.class.getMethod("invert",
Object.class);
}
catch (NoSuchMethodException ex)
{
@@ -457,8 +460,16 @@
return;
+ case NOT:
+ createNotOpGetter(node);
+ createNoOpSetter();
+
+ conduitPropertyType = boolean.class;
+
+ return;
+
default:
- throw unexpectedNodeType(node, IDENTIFIER, INVOKE,
RANGEOP, LIST);
+ throw unexpectedNodeType(node, IDENTIFIER, INVOKE,
RANGEOP, LIST, NOT);
}
}
@@ -475,6 +486,20 @@
classFab.addMethod(Modifier.PUBLIC, GET_SIGNATURE,
builder.toString());
}
+ private void createNotOpGetter(Tree node)
+ {
+ BodyBuilder builder = new BodyBuilder().begin();
+
+ addRootVariable(builder);
+
+ builder.addln("return %s;", createMethodInvocation(builder, node,
0, INVERT));
+
+ builder.end();
+
+ classFab.addMethod(Modifier.PUBLIC, GET_SIGNATURE,
builder.toString());
+ }
+
+
public void createListGetter(Tree node)
{
BodyBuilder builder = new BodyBuilder().begin();
@@ -506,12 +531,22 @@
return listName;
}
+ private String createNotOp(BodyBuilder builder, Tree node)
+ {
+ String flagName = nextVariableName(Boolean.class);
+ GeneratedTerm term = subexpression(builder, node.getChild(0));
+
+ builder.addln("Boolean %s = invert(($w) %s);", flagName,
term.getVariableName());
+
+ return flagName;
+ }
+
/**
* Evalutates the node as a sub expression, storing the result into a
new variable, whose name is returned.
*
* @param builder to receive generated code
* @param node root of tree of nodes to be evaluated
- * @return name of variable containing expression
+ * @return GeneratedTerm identifying the name of the variable and its
type
*/
private GeneratedTerm subexpression(BodyBuilder builder, Tree node)
{
@@ -579,6 +614,15 @@
break;
+ case NOT:
+
+ previousVariableName = createNotOp(builder, node);
+ activeType = boolean.class;
+
+ node = null;
+
+ break;
+
case LIST:
previousVariableName = createListConstructor(builder,
node);
@@ -715,6 +759,8 @@
Class parameterType = parameterTypes[i];
+ boolean needsUnwrap = false;
+
if (!parameterType.isAssignableFrom(actualType))
{
String coerced = nextVariableName(parameterType);
@@ -729,12 +775,19 @@
variableName = coerced;
}
-
- // TODO: Casting, coercing, unwrapping primitives.
+ else
+ {
+ needsUnwrap = parameterType.isPrimitive();
+ }
if (i > 0) builder.append(", ");
builder.append(variableName);
+
+ if (needsUnwrap)
+ {
+
builder.append(".").append(ClassFabUtils.getUnwrapMethodName(parameterType)).append("()");
+ }
}
return builder.append(")").toString();
Modified:
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImplTest.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImplTest.java?rev=732861&r1=732860&r2=732861&view=diff
==============================================================================
---
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImplTest.java
(original)
+++
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PropertyConduitSourceImplTest.java
Thu Jan 8 14:46:48 2009
@@ -368,4 +368,31 @@
assertListsEquals(l, new Long(1), new Double(2.0), "Bart");
}
+
+ @Test
+ public void not_operator()
+ {
+ PropertyConduit conduit = source.create(IntegerHolder.class, "!
value");
+ IntegerHolder holder = new IntegerHolder();
+
+ assertEquals(conduit.get(holder), Boolean.TRUE);
+
+ holder.setValue(99);
+
+ assertEquals(conduit.get(holder), Boolean.FALSE);
+ }
+
+ @Test
+ public void no_operator_in_subexpression()
+ {
+ PropertyConduit conduit = source.create(Switch.class, "label(!
value)");
+
+ Switch sw = new Switch();
+
+ assertEquals(conduit.get(sw), "aye");
+
+ sw.setValue(true);
+
+ assertEquals(conduit.get(sw), "nay");
+ }
}
Added:
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/Switch.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/Switch.java?rev=732861&view=auto
==============================================================================
---
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/Switch.java
(added)
+++
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/Switch.java
Thu Jan 8 14:46:48 2009
@@ -0,0 +1,35 @@
+// Copyright 2009 The Apache Software Foundation
+//
+// Licensed 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.tapestry5.internal.services;
+
+public class Switch
+{
+ private boolean value;
+
+ public boolean isValue()
+ {
+ return value;
+ }
+
+ public void setValue(boolean value)
+ {
+ this.value = value;
+ }
+
+ public String label(boolean flag)
+ {
+ return flag ? "aye" : "nay";
+ }
+}
Modified: tapestry/tapestry5/trunk/tapestry-core/tapestry-core.iml
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/tapestry-core.iml?rev=732861&r1=732860&r2=732861&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/tapestry-core.iml (original)
+++ tapestry/tapestry5/trunk/tapestry-core/tapestry-core.iml Thu Jan 8
14:46:48 2009
@@ -9,7 +9,6 @@
<sourceFolder url="file://$MODULE_DIR$/src/test/java"
isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/resources"
isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/target/generated-sources/antlr"
isTestSource="false" />
- <excludeFolder url="file://$MODULE_DIR$/target" />
<excludeFolder url="file://$MODULE_DIR$/test-output" />
</content>
<orderEntry type="inheritedJdk" />
Modified:
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ClassFabUtils.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ClassFabUtils.java?rev=732861&r1=732860&r2=732861&view=diff
==============================================================================
---
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ClassFabUtils.java
(original)
+++
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ClassFabUtils.java
Thu Jan 8 14:46:48 2009
@@ -204,6 +204,17 @@
return String.format("(%s)%s", desiredType, reference);
}
+ /**
+ * Given a primitive type, finds the unwrap method of the corresponding
wrapper type.
+ *
+ * @param primitiveType
+ * @return method name
+ */
+ public static String getUnwrapMethodName(Class primitiveType)
+ {
+ return
PRIMITIVE_TYPE_NAME_TO_PRIMITIVE_INFO.get(primitiveType.getName()).unwrapMethod;
+ }
+
/**
* Given a type name, determines if that is the name of a primitive type.
@@ -244,7 +255,7 @@
{
classFab.addField("_creator", Modifier.PRIVATE | Modifier.FINAL,
ObjectCreator.class);
- classFab.addConstructor(new Class[] { ObjectCreator.class }, null,
"_creator = $1;");
+ classFab.addConstructor(new Class[] {ObjectCreator.class}, null,
"_creator = $1;");
String body = format("return (%s) _creator.createObject();",
serviceInterface.getName());