Skip to content

Commit 7eaca93

Browse files
committed
Yet more adventures with lambda expressions.
I suspect - but haven't yet checked - that there is scope to make the code more efficient and/or reduce duplication. git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@1504657 13f79535-47bb-0310-9956-ffa450edef68
1 parent ce158ac commit 7eaca93

3 files changed

Lines changed: 109 additions & 18 deletions

File tree

java/org/apache/el/parser/AstFunction.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,12 +98,18 @@ public Object getValue(EvaluationContext ctx)
9898
// Build arguments
9999
int i = 0;
100100
while (obj instanceof LambdaExpression &&
101-
i < this.jjtGetNumChildren()) {
101+
i < jjtGetNumChildren()) {
102102
Node args = jjtGetChild(i);
103103
obj = ((LambdaExpression) obj).invoke(
104104
((AstMethodParameters) args).getParameters(ctx));
105105
i++;
106106
}
107+
if (i < jjtGetNumChildren()) {
108+
// Haven't consumed all the sets of parameters therefore
109+
// there were too many sets of parameters
110+
throw new ELException(MessageFactory.get(
111+
"error.lambda.tooManyMethodParameterSets"));
112+
}
107113
return obj;
108114
}
109115
}

java/org/apache/el/parser/AstLambdaExpression.java

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -36,22 +36,39 @@ public AstLambdaExpression(int id) {
3636
@Override
3737
public Object getValue(EvaluationContext ctx) throws ELException {
3838

39-
// Check that there are not more sets of method parameters than there
40-
// are nested lambda expressions
39+
// Check;
40+
// - that there are not more sets of method parameters than there are
41+
// nested lambda expressions
42+
// - if any of the nested expressions declare formal parameters
4143
int methodParameterSetCount = jjtGetNumChildren() - 2;
42-
if (methodParameterSetCount > 0) {
43-
// We know this node is an expression
44-
methodParameterSetCount--;
45-
Node n = this.jjtGetChild(1);
46-
while (methodParameterSetCount > 0) {
47-
if (n.jjtGetNumChildren() <2 ||
48-
!(n.jjtGetChild(0) instanceof AstLambdaParameters)) {
49-
throw new ELException(MessageFactory.get(
50-
"error.lambda.tooManyMethodParameterSets"));
44+
boolean declaresParameters = false;
45+
// We know this node is an expression
46+
int lambdaExpressionCount = 1;
47+
// child at index 1 is the expression
48+
Node n = jjtGetChild(1);
49+
while (n instanceof AstLambdaExpression) {
50+
lambdaExpressionCount++;
51+
if (n.jjtGetChild(0) instanceof AstLambdaParameters) {
52+
if (!declaresParameters &&
53+
n.jjtGetChild(0).jjtGetNumChildren() > 0) {
54+
declaresParameters = true;
5155
}
5256
n = n.jjtGetChild(1);
53-
methodParameterSetCount--;
57+
} else {
58+
n = null;
59+
}
60+
}
61+
if (methodParameterSetCount > lambdaExpressionCount) {
62+
throw new ELException(MessageFactory.get(
63+
"error.lambda.tooManyMethodParameterSets"));
64+
}
65+
// Also need to check parents for declaration of formal parameters
66+
n = parent;
67+
while (!declaresParameters && n instanceof AstLambdaExpression) {
68+
if (n.jjtGetChild(0).jjtGetNumChildren() > 0) {
69+
declaresParameters = true;
5470
}
71+
n = n.jjtGetParent();
5572
}
5673

5774
// First child is always parameters even if there aren't any
@@ -74,10 +91,9 @@ public Object getValue(EvaluationContext ctx) throws ELException {
7491
le.setELContext(ctx);
7592

7693
if (jjtGetNumChildren() == 2) {
77-
if (formalParameters.isEmpty() &&
78-
!(parent instanceof AstLambdaExpression)) {
79-
// No formal parameters or method parameters and not a nested
80-
// expression so invoke the expression.
94+
if (formalParameters.isEmpty() && !declaresParameters) {
95+
// No formal parameters or method parameters and not nested
96+
// inside another lambda expression so invoke the expression.
8197
return le.invoke(ctx, (Object[]) null);
8298
} else {
8399
// Has formal parameters but no method parameters or is a nested

test/org/apache/el/parser/TestAstLambdaExpression.java

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,11 +147,80 @@ public void testNested06() {
147147

148148

149149
@Test
150-
public void testLambdaAsFunction() {
150+
public void testNested07() {
151+
ELProcessor processor = new ELProcessor();
152+
Object result =
153+
processor.getValue("()->()->()->42",
154+
Integer.class);
155+
Assert.assertEquals(Integer.valueOf(42), result);
156+
}
157+
158+
159+
@Test
160+
public void testLambdaAsFunction01() {
151161
ELProcessor processor = new ELProcessor();
152162
Object result =
153163
processor.getValue("v = (x->y->x-y); v(2)(1)",
154164
Integer.class);
155165
Assert.assertEquals(Integer.valueOf(1), result);
156166
}
167+
168+
169+
@Test
170+
public void testLambdaAsFunction02() {
171+
ELProcessor processor = new ELProcessor();
172+
Object result =
173+
processor.getValue("v = (()->y->2-y); v()(1)",
174+
Integer.class);
175+
Assert.assertEquals(Integer.valueOf(1), result);
176+
}
177+
178+
179+
@Test
180+
public void testLambdaAsFunction03() {
181+
ELProcessor processor = new ELProcessor();
182+
Object result =
183+
processor.getValue("v = (()->y->()->2-y); v()(1)()",
184+
Integer.class);
185+
Assert.assertEquals(Integer.valueOf(1), result);
186+
}
187+
188+
189+
@Test(expected=ELException.class)
190+
public void testLambdaAsFunction04() {
191+
ELProcessor processor = new ELProcessor();
192+
// More method parameters than there are nested lambda expressions
193+
processor.getValue("v = (()->y->()->2-y); v()(1)()()",
194+
Integer.class);
195+
}
196+
197+
198+
@Test
199+
public void testLambdaAsFunction05() {
200+
ELProcessor processor = new ELProcessor();
201+
Object result =
202+
processor.getValue("v = (()->y->()->x->x-y); v()(1)()(2)",
203+
Integer.class);
204+
Assert.assertEquals(Integer.valueOf(1), result);
205+
}
206+
207+
208+
@Test
209+
public void testLambdaAsFunction06() {
210+
ELProcessor processor = new ELProcessor();
211+
Object result =
212+
processor.getValue("v = (()->y->()->()->x->x-y); v()(1)()()(2)",
213+
Integer.class);
214+
Assert.assertEquals(Integer.valueOf(1), result);
215+
}
216+
217+
218+
@Test
219+
public void testLambdaAsFunction07() {
220+
ELProcessor processor = new ELProcessor();
221+
Object result =
222+
processor.getValue("v = (()->y->()->()->x->x-y); v()(1)()(3)(2)",
223+
Integer.class);
224+
Assert.assertEquals(Integer.valueOf(1), result);
225+
}
157226
}

0 commit comments

Comments
 (0)