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);
+    }
+}


Reply via email to