Modified: velocity/engine/branches/2.0_Exp/src/java/org/apache/velocity/runtime/parser/ParserTreeConstants.java URL: http://svn.apache.org/viewvc/velocity/engine/branches/2.0_Exp/src/java/org/apache/velocity/runtime/parser/ParserTreeConstants.java?rev=741397&r1=741396&r2=741397&view=diff ============================================================================== --- velocity/engine/branches/2.0_Exp/src/java/org/apache/velocity/runtime/parser/ParserTreeConstants.java (original) +++ velocity/engine/branches/2.0_Exp/src/java/org/apache/velocity/runtime/parser/ParserTreeConstants.java Fri Feb 6 04:24:49 2009 @@ -1,4 +1,5 @@ -/* Generated By:JavaCC: Do not edit this line. ParserTreeConstants.java Version 4.1 */ +/* Generated By:JJTree: Do not edit this line. ParserTreeConstants.java */ + package org.apache.velocity.runtime.parser; public interface ParserTreeConstants @@ -29,23 +30,25 @@ public int JJTELSESTATEMENT = 23; public int JJTELSEIFSTATEMENT = 24; public int JJTSETDIRECTIVE = 25; - public int JJTSTOP = 26; - public int JJTEXPRESSION = 27; - public int JJTASSIGNMENT = 28; - public int JJTORNODE = 29; - public int JJTANDNODE = 30; - public int JJTEQNODE = 31; - public int JJTNENODE = 32; - public int JJTLTNODE = 33; - public int JJTGTNODE = 34; - public int JJTLENODE = 35; - public int JJTGENODE = 36; - public int JJTADDNODE = 37; - public int JJTSUBTRACTNODE = 38; - public int JJTMULNODE = 39; - public int JJTDIVNODE = 40; - public int JJTMODNODE = 41; - public int JJTNOTNODE = 42; + public int JJTLOCALDIRECTIVE = 26; + public int JJTGLOBALDIRECTIVE = 27; + public int JJTSTOP = 28; + public int JJTEXPRESSION = 29; + public int JJTASSIGNMENT = 30; + public int JJTORNODE = 31; + public int JJTANDNODE = 32; + public int JJTEQNODE = 33; + public int JJTNENODE = 34; + public int JJTLTNODE = 35; + public int JJTGTNODE = 36; + public int JJTLENODE = 37; + public int JJTGENODE = 38; + public int JJTADDNODE = 39; + public int JJTSUBTRACTNODE = 40; + public int JJTMULNODE = 41; + public int JJTDIVNODE = 42; + public int JJTMODNODE = 43; + public int JJTNOTNODE = 44; public String[] jjtNodeName = { @@ -75,6 +78,8 @@ "ElseStatement", "ElseIfStatement", "SetDirective", + "LocalDirective", + "GlobalDirective", "Stop", "Expression", "Assignment", @@ -94,4 +99,3 @@ "NotNode", }; } -/* JavaCC - OriginalChecksum=6486d1e0227c52f059ed205018b7b6fa (do not edit this line) */
Added: velocity/engine/branches/2.0_Exp/src/java/org/apache/velocity/runtime/parser/node/ASTGlobalDirective.java URL: http://svn.apache.org/viewvc/velocity/engine/branches/2.0_Exp/src/java/org/apache/velocity/runtime/parser/node/ASTGlobalDirective.java?rev=741397&view=auto ============================================================================== --- velocity/engine/branches/2.0_Exp/src/java/org/apache/velocity/runtime/parser/node/ASTGlobalDirective.java (added) +++ velocity/engine/branches/2.0_Exp/src/java/org/apache/velocity/runtime/parser/node/ASTGlobalDirective.java Fri Feb 6 04:24:49 2009 @@ -0,0 +1,47 @@ +package org.apache.velocity.runtime.parser.node; + +/* + * 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. + */ + +import org.apache.velocity.context.Context.Scope; +import org.apache.velocity.runtime.parser.Parser; + +/** + * Implements the #global directive functionality + * This directive shadows the functionality of <code>ASTSetDirective</code> + * but alters it's behavior to only affect the global scope. This is done + * by overriding the <code>getScope()</code> method. + */ +public class ASTGlobalDirective extends ASTSetDirective +{ + public ASTGlobalDirective(int id) + { + super(id); + } + + public ASTGlobalDirective(Parser p, int id) + { + super(p, id); + } + + public Scope getScope() + { + return Scope.GLOBAL; + } +} Added: velocity/engine/branches/2.0_Exp/src/java/org/apache/velocity/runtime/parser/node/ASTLocalDirective.java URL: http://svn.apache.org/viewvc/velocity/engine/branches/2.0_Exp/src/java/org/apache/velocity/runtime/parser/node/ASTLocalDirective.java?rev=741397&view=auto ============================================================================== --- velocity/engine/branches/2.0_Exp/src/java/org/apache/velocity/runtime/parser/node/ASTLocalDirective.java (added) +++ velocity/engine/branches/2.0_Exp/src/java/org/apache/velocity/runtime/parser/node/ASTLocalDirective.java Fri Feb 6 04:24:49 2009 @@ -0,0 +1,47 @@ +package org.apache.velocity.runtime.parser.node; + +/* + * 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. + */ + +import org.apache.velocity.context.Context.Scope; +import org.apache.velocity.runtime.parser.Parser; + +/** + * Implements the #local directive functionality + * This directive shadows the functionality of <code>ASTSetDirective</code> + * but alters it's behavior to only affect the local scope. This is done + * by overriding the <code>getScope()</code> method. + */ +public class ASTLocalDirective extends ASTSetDirective +{ + public ASTLocalDirective(int id) + { + super(id); + } + + public ASTLocalDirective(Parser p, int id) + { + super(p, id); + } + + public Scope getScope() + { + return Scope.LOCAL; + } +} Modified: velocity/engine/branches/2.0_Exp/src/java/org/apache/velocity/runtime/parser/node/ASTReference.java URL: http://svn.apache.org/viewvc/velocity/engine/branches/2.0_Exp/src/java/org/apache/velocity/runtime/parser/node/ASTReference.java?rev=741397&r1=741396&r2=741397&view=diff ============================================================================== --- velocity/engine/branches/2.0_Exp/src/java/org/apache/velocity/runtime/parser/node/ASTReference.java (original) +++ velocity/engine/branches/2.0_Exp/src/java/org/apache/velocity/runtime/parser/node/ASTReference.java Fri Feb 6 04:24:49 2009 @@ -26,6 +26,7 @@ import org.apache.velocity.app.event.EventHandlerUtil; import org.apache.velocity.context.Context; import org.apache.velocity.context.InternalContextAdapter; +import org.apache.velocity.context.Context.Scope; import org.apache.velocity.exception.MethodInvocationException; import org.apache.velocity.exception.TemplateInitException; import org.apache.velocity.exception.VelocityException; @@ -227,7 +228,7 @@ * get the root object from the context */ - Object result = getVariableValue(context, rootString); + Object result = getVariableValue(context, rootString, Scope.DEFAULT); if (result == null && !strictRef) { @@ -574,12 +575,12 @@ * @return true if successful, false otherwise * @throws MethodInvocationException */ - public boolean setValue( InternalContextAdapter context, Object value) + public boolean setValue(InternalContextAdapter context, Object value, Scope scope) throws MethodInvocationException { if (jjtGetNumChildren() == 0) { - context.put(rootString, value); + context.put(rootString, value, scope); return true; } @@ -589,7 +590,7 @@ * object we will apply reflection to. */ - Object result = getVariableValue(context, rootString); + Object result = getVariableValue(context, rootString, scope); if (result == null) { @@ -969,12 +970,12 @@ * @return The evaluated value of the variable. * @throws MethodInvocationException */ - public Object getVariableValue(Context context, String variable) throws MethodInvocationException + public Object getVariableValue(InternalContextAdapter context, String variable, Scope scope) { Object obj = null; try { - obj = context.get(variable); + obj = context.get(variable, scope); } catch(RuntimeException e) { @@ -983,9 +984,9 @@ throw e; } - if (strictRef && obj == null) + if (obj == null && strictRef) { - if (!context.containsKey(variable)) + if (!context.containsKey(variable, scope)) { log.error("Variable $" + variable + " has not been set at " + Log.formatFileString(uberInfo)); Modified: velocity/engine/branches/2.0_Exp/src/java/org/apache/velocity/runtime/parser/node/ASTSetDirective.java URL: http://svn.apache.org/viewvc/velocity/engine/branches/2.0_Exp/src/java/org/apache/velocity/runtime/parser/node/ASTSetDirective.java?rev=741397&r1=741396&r2=741397&view=diff ============================================================================== --- velocity/engine/branches/2.0_Exp/src/java/org/apache/velocity/runtime/parser/node/ASTSetDirective.java (original) +++ velocity/engine/branches/2.0_Exp/src/java/org/apache/velocity/runtime/parser/node/ASTSetDirective.java Fri Feb 6 04:24:49 2009 @@ -24,6 +24,7 @@ import org.apache.velocity.app.event.EventHandlerUtil; import org.apache.velocity.context.InternalContextAdapter; +import org.apache.velocity.context.Context.Scope; import org.apache.velocity.exception.MethodInvocationException; import org.apache.velocity.exception.TemplateInitException; import org.apache.velocity.runtime.RuntimeConstants; @@ -183,45 +184,22 @@ rightReference = ((ASTExpression) right).getLastToken().image; } EventHandlerUtil.invalidSetMethod(rsvc, context, leftReference, rightReference, uberInfo); - - /* - * if RHS is null, remove simple LHS from context - * or call setValue() with a null value for complex LHS - */ - if (left.jjtGetNumChildren() == 0) - { - context.remove( leftReference ); - } - else - { - left.setValue(context, null); - } - - return false; - - } - else - { - /* - * if the LHS is simple, just punch the value into the context - * otherwise, use the setValue() method do to it. - * Maybe we should always use setValue() - */ - - if (left.jjtGetNumChildren() == 0) - { - context.put( leftReference, value); - } - else - { - left.setValue(context, value); - } } - - return true; + + return left.setValue(context, value, getScope()); } /** + * Return the scope this set directive will operate under. We override this method + * with the #global and #local directives to specify the appropriate scope. + */ + public Scope getScope() + { + return Scope.DEFAULT; + } + + + /** * returns the ASTReference that is the LHS of the set statememt * * @return left hand side of #set statement Modified: velocity/engine/branches/2.0_Exp/src/parser/Parser.jjt URL: http://svn.apache.org/viewvc/velocity/engine/branches/2.0_Exp/src/parser/Parser.jjt?rev=741397&r1=741396&r2=741397&view=diff ============================================================================== --- velocity/engine/branches/2.0_Exp/src/parser/Parser.jjt (original) +++ velocity/engine/branches/2.0_Exp/src/parser/Parser.jjt Fri Feb 6 04:24:49 2009 @@ -710,6 +710,79 @@ } } + +<DEFAULT, REFERENCE, REFMODIFIER, REFMOD2> +TOKEN: +{ + <LOCAL_DIRECTIVE: (" "|"\t")* ("#local" | "#{local}") (" ")* "("> + { + if (! inComment) + { + inDirective = true; + + if ( debugPrint ) + System.out.print("#local : going to " + DIRECTIVE ); + + stateStackPush(); + inSet = true; + SwitchTo(DIRECTIVE); + } + + /* + * need the LPAREN action + */ + + if (!inComment) + { + lparen++; + + /* + * If in REFERENCE and we have seen the dot, then move + * to REFMOD2 -> Modifier() + */ + + if (curLexState == REFMODIFIER ) + SwitchTo( REFMOD2 ); + } + } +} + +<DEFAULT, REFERENCE, REFMODIFIER, REFMOD2> +TOKEN: +{ + <GLOBAL_DIRECTIVE: (" "|"\t")* ("#global" | "#{global}") (" ")* "("> + { + if (! inComment) + { + inDirective = true; + + if ( debugPrint ) + System.out.print("#global : going to " + DIRECTIVE ); + + stateStackPush(); + inSet = true; + SwitchTo(DIRECTIVE); + } + + /* + * need the LPAREN action + */ + + if (!inComment) + { + lparen++; + + /* + * If in REFERENCE and we have seen the dot, then move + * to REFMOD2 -> Modifier() + */ + + if (curLexState == REFMODIFIER ) + SwitchTo( REFMOD2 ); + } + } +} + <*> MORE : { @@ -1244,6 +1317,8 @@ | Comment() | Textblock() | SetDirective() +| LocalDirective() +| GlobalDirective() | EscapedDirective() | Escape() | Directive() @@ -1828,6 +1903,39 @@ } /** + * Meant to shadow the behavior of Set but only affect local contexts + */ +void LocalDirective() : {} +{ + <LOCAL_DIRECTIVE>([<WHITESPACE>] Reference() [<WHITESPACE>] <EQUALS> Expression() <RPAREN> + { + /* + * ensure that inSet is false. Leads to some amusing bugs... + */ + + token_source.inSet = false; + } + [<NEWLINE>] ) +} + +/** + * Meant to shadow the behavior of Set but only affect the global context + */ +void GlobalDirective() : {} +{ + <GLOBAL_DIRECTIVE>([<WHITESPACE>] Reference() [<WHITESPACE>] <EQUALS> Expression() <RPAREN> + { + /* + * ensure that inSet is false. Leads to some amusing bugs... + */ + + token_source.inSet = false; + } + [<NEWLINE>] ) +} + + +/** * This method corresponds to the #stop * directive which just simulates and EOF * so that parsing stops. The #stop directive Added: velocity/engine/branches/2.0_Exp/src/test/org/apache/velocity/test/GlobalTestCase.java URL: http://svn.apache.org/viewvc/velocity/engine/branches/2.0_Exp/src/test/org/apache/velocity/test/GlobalTestCase.java?rev=741397&view=auto ============================================================================== --- velocity/engine/branches/2.0_Exp/src/test/org/apache/velocity/test/GlobalTestCase.java (added) +++ velocity/engine/branches/2.0_Exp/src/test/org/apache/velocity/test/GlobalTestCase.java Fri Feb 6 04:24:49 2009 @@ -0,0 +1,81 @@ +package org.apache.velocity.test; + +/* + * 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. + */ + +import org.apache.velocity.exception.ParseErrorException; +import org.apache.velocity.runtime.RuntimeConstants; + +/** + * This class tests the GlobalDirective functionality. + */ +public class GlobalTestCase extends BaseTestCase +{ + public GlobalTestCase(String name) + { + super(name); + DEBUG = true; + } + + public void setUp() throws Exception + { + super.setUp(); + engine.setProperty(RuntimeConstants.VM_CONTEXT_LOCALSCOPE, true); + engine.setProperty(RuntimeConstants.RUNTIME_REFERENCES_STRICT, true); + } + + public void testSimple() + { + // define a macro for testing + assertEvalEquals("","#macro(foo)#set($bar = \"a\")#global($bar = \"b\")$bar#end"); + assertEvalEquals("ab", "#foo()$bar"); + assertEvalEquals("ab", "#set($bar=\"c\")#foo()$bar"); + assertEvalEquals("ab", "#global($bar=\"c\")#foo()$bar"); + } + + public void testNested() + { + // define inner macro + assertEvalEquals("","#macro(inner)#set($bar = \"x\")$bar#global($bar = \"y\")$bar#end"); + // define outer macro + assertEvalEquals("","#macro(outer)#set($bar = \"a\")$bar#inner()$bar#global($bar = \"b\")$bar#end"); + assertEvalEquals("axxaab","#outer()$bar"); + assertEvalEquals("axxaab","#set($bar = \"z\")#outer()$bar"); + } + + public void testExistance() + { + assertEvalEquals("yes","#macro(foo)#global($bar = \"b\")#if($bar)yes#{else}no#end#end#foo()"); + } + + public void testExistance2() + { + assertEvalEquals("no","#macro(foo)#set($bar = \"b\")#end#foo()#if($bar)yes#{else}no#end"); + } + + public void testProperties() + { + assertEvalEquals("1223", "#set($bar = {\"a\":1})$bar.a#macro(foo)#set($bar = {\"a\":2})$bar.a#global($bar.a = 3)$bar.a#end#foo()$bar.a"); + } + + public void testProperties2() + { + assertEvalException("#macro(foo)#set($bar = {\"a\":2})$bar.a#global($bar.a = 3)$bar.a#end#foo()"); + } +} Added: velocity/engine/branches/2.0_Exp/src/test/org/apache/velocity/test/LocalDirectiveTestCase.java URL: http://svn.apache.org/viewvc/velocity/engine/branches/2.0_Exp/src/test/org/apache/velocity/test/LocalDirectiveTestCase.java?rev=741397&view=auto ============================================================================== --- velocity/engine/branches/2.0_Exp/src/test/org/apache/velocity/test/LocalDirectiveTestCase.java (added) +++ velocity/engine/branches/2.0_Exp/src/test/org/apache/velocity/test/LocalDirectiveTestCase.java Fri Feb 6 04:24:49 2009 @@ -0,0 +1,59 @@ +package org.apache.velocity.test; + +/* + * 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. + */ + +import org.apache.velocity.exception.ParseErrorException; +import org.apache.velocity.runtime.RuntimeConstants; + +/** + * This class tests the LocalDirective functionality. + */ +public class LocalDirectiveTestCase extends BaseTestCase +{ + public LocalDirectiveTestCase(String name) + { + super(name); + DEBUG = true; + } + + public void testSimple() throws Exception + { + String template = "#macro(foo $value) #local($counter = $value + 1)$counter#end #set($counter = 2) $counter #foo($counter) $counter"; + String result = " 2 3 2"; + + assertEvalEquals(result, template); + } + + public void testNestedCallsWithLocal() throws Exception + { + String template = "#set($a = 1) #macro(bar $n)#local($a = $n+ 1) $a #end #macro(foo $num)#local($a = $num + 1) $a #bar($a)#end #foo(1) $a"; + String result = " 2 3 1"; + + assertEvalEquals(result, template); + } + + public void testLocalWithMap() throws Exception + { + String template = "#macro(foo)#local($map.foo = 'bar')$map.foo#end #set($map = { 'foo': 'woogie' }) #foo() $map.foo"; + String result = " woogie woogie"; + + assertEvalEquals(result, template); + } +}
