What? You would dare to impose your view of configurable whitespace
gobbling upon the rest of us after only a mere decade of discussion?
What will we talk about for the next 10 years? :-)
On Tue, Aug 30, 2016 at 12:18 PM, <cbris...@apache.org> wrote:
Author: cbrisson
Date: Tue Aug 30 16:18:33 2016
New Revision: 1758416
URL: http://svn.apache.org/viewvc?rev=1758416&view=rev
Log:
[engine] Add a configurable space gobbling feature, to control
indentation in the generated code.
Possible values for the 'space.gobbling' configuration key:
- none : no space gobbling at all
- bc : Velocity 1.x backward compatible space gobbling
- lines (the default) : gobbles whitespaces and endline from lines
containing a single VTL directive
- structured (beta stage) : like 'lines', but also fixes indentation in
embedded text blocks
The commit also includes some lookahead optimizations and cleaning in
the javacc parser code.
Added:
velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/parser/node/IndentationFixer.java
velocity/engine/trunk/velocity-engine-core/src/test/
java/org/apache/velocity/test/SpaceGobblingTestCase.java
- copied, changed from r1754151, velocity/engine/trunk/
velocity-engine-core/src/test/java/org/apache/velocity/test/
util/introspection/ConversionHandlerTestCase.java
velocity/engine/trunk/velocity-engine-core/src/test/
resources/gobbling/
velocity/engine/trunk/velocity-engine-core/src/test/
resources/gobbling/compare/
velocity/engine/trunk/velocity-engine-core/src/test/
resources/gobbling/compare/foreach_smart.vtl.BC
velocity/engine/trunk/velocity-engine-core/src/test/
resources/gobbling/compare/foreach_smart.vtl.NONE
velocity/engine/trunk/velocity-engine-core/src/test/
resources/gobbling/compare/foreach_smart.vtl.SMART
velocity/engine/trunk/velocity-engine-core/src/test/
resources/gobbling/compare/foreach_smart.vtl.STRUCTURED
velocity/engine/trunk/velocity-engine-core/src/test/
resources/gobbling/compare/foreach_structured.vtl.BC
velocity/engine/trunk/velocity-engine-core/src/test/
resources/gobbling/compare/foreach_structured.vtl.NONE
velocity/engine/trunk/velocity-engine-core/src/test/
resources/gobbling/compare/foreach_structured.vtl.SMART
velocity/engine/trunk/velocity-engine-core/src/test/
resources/gobbling/compare/foreach_structured.vtl.STRUCTURED
velocity/engine/trunk/velocity-engine-core/src/test/
resources/gobbling/compare/if.vtl.BC
velocity/engine/trunk/velocity-engine-core/src/test/
resources/gobbling/compare/if.vtl.NONE
velocity/engine/trunk/velocity-engine-core/src/test/
resources/gobbling/compare/if.vtl.SMART
velocity/engine/trunk/velocity-engine-core/src/test/
resources/gobbling/compare/if.vtl.STRUCTURED
velocity/engine/trunk/velocity-engine-core/src/test/
resources/gobbling/compare/macro.vtl.BC
velocity/engine/trunk/velocity-engine-core/src/test/
resources/gobbling/compare/macro.vtl.NONE
velocity/engine/trunk/velocity-engine-core/src/test/
resources/gobbling/compare/macro.vtl.SMART
velocity/engine/trunk/velocity-engine-core/src/test/
resources/gobbling/compare/macro.vtl.STRUCTURED
velocity/engine/trunk/velocity-engine-core/src/test/
resources/gobbling/compare/set.vtl.BC
velocity/engine/trunk/velocity-engine-core/src/test/
resources/gobbling/compare/set.vtl.NONE
velocity/engine/trunk/velocity-engine-core/src/test/
resources/gobbling/compare/set.vtl.SMART
velocity/engine/trunk/velocity-engine-core/src/test/
resources/gobbling/compare/set.vtl.STRUCTURED
velocity/engine/trunk/velocity-engine-core/src/test/
resources/gobbling/compare/structured.vtl.BC
velocity/engine/trunk/velocity-engine-core/src/test/
resources/gobbling/compare/structured.vtl.NONE
velocity/engine/trunk/velocity-engine-core/src/test/
resources/gobbling/compare/structured.vtl.SMART
velocity/engine/trunk/velocity-engine-core/src/test/
resources/gobbling/compare/structured.vtl.STRUCTURED
velocity/engine/trunk/velocity-engine-core/src/test/
resources/gobbling/foreach_smart.vtl
velocity/engine/trunk/velocity-engine-core/src/test/
resources/gobbling/foreach_structured.vtl
velocity/engine/trunk/velocity-engine-core/src/test/
resources/gobbling/if.vtl
velocity/engine/trunk/velocity-engine-core/src/test/
resources/gobbling/macro.vtl
velocity/engine/trunk/velocity-engine-core/src/test/
resources/gobbling/set.vtl
velocity/engine/trunk/velocity-engine-core/src/test/
resources/gobbling/structured.vtl
Modified:
velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/RuntimeConstants.java
velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/RuntimeInstance.java
velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/RuntimeServices.java
velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/parser/node/ASTBlock.java
velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/parser/node/ASTDirective.java
velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/parser/node/ASTElseIfStatement.java
velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/parser/node/ASTIfStatement.java
velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/parser/node/ASTSetDirective.java
velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/parser/node/ASTText.java
velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/parser/node/NodeUtils.java
velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/parser/node/ParserVisitor.java
velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/visitor/BaseVisitor.java
velocity/engine/trunk/velocity-engine-core/src/main/
parser/Parser.jjt
velocity/engine/trunk/velocity-engine-core/src/main/
resources/org/apache/velocity/runtime/defaults/velocity.properties
velocity/engine/trunk/velocity-engine-core/src/test/
java/org/apache/velocity/test/InlineScopeVMTestCase.java
velocity/engine/trunk/velocity-engine-core/src/test/
java/org/apache/velocity/test/ScopeTestCase.java
velocity/engine/trunk/velocity-engine-core/src/test/
java/org/apache/velocity/test/TemplateTestCase.java
velocity/engine/trunk/velocity-engine-core/src/test/
java/org/apache/velocity/test/issues/Velocity615TestCase.java
velocity/engine/trunk/velocity-engine-core/src/test/
java/org/apache/velocity/test/issues/Velocity631TestCase.java
velocity/engine/trunk/velocity-engine-core/src/test/
resources/conversion/compare/matrix.cmp
Modified: velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/RuntimeConstants.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/
velocity-engine-core/src/main/java/org/apache/velocity/
runtime/RuntimeConstants.java?rev=1758416&r1=1758415&r2=1758416&view=diff
============================================================
==================
--- velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/RuntimeConstants.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/RuntimeConstants.java Tue Aug 30
16:18:33 2016
@@ -266,6 +266,19 @@ public interface RuntimeConstants
*/
String PARSER_POOL_SIZE = "parser.pool.size";
+ /**
+ * Space gobbling mode
+ */
+ String SPACE_GOBBLING = "space.gobbling";
+
+ /**
+ * Space gobbling modes
+ */
+ public enum SpaceGobbling
+ {
+ NONE, BC, LINES, STRUCTURED
+ }
+
/*
* ------------------------------------------------------------
----------
* These constants are used internally by the Velocity runtime i.e.
Modified: velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/RuntimeInstance.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/
velocity-engine-core/src/main/java/org/apache/velocity/
runtime/RuntimeInstance.java?rev=1758416&r1=1758415&r2=1758416&view=diff
============================================================
==================
--- velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/RuntimeInstance.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/RuntimeInstance.java Tue Aug 30 16:18:33
2016
@@ -55,7 +55,6 @@ import org.apache.velocity.util.introspe
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
@@ -66,6 +65,7 @@ import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
+import java.util.NoSuchElementException;
import java.util.Properties;
/**
@@ -193,6 +193,11 @@ public class RuntimeInstance implements
private Uberspect uberSpect;
private String encoding;
+ /*
+ * Space gobbling mode
+ */
+ private SpaceGobbling spaceGobbling;
+
/**
* Creates a new RuntimeInstance object.
*/
@@ -334,7 +339,19 @@ public class RuntimeInstance implements
*/
private void initializeSelfProperties()
{
+ /* initialize string interning (defaults to false) */
stringInterning = getBoolean(RUNTIME_STRING_INTERNING, true);
+
+ /* initialize indentation mode (defaults to 'lines') */
+ String im = getString(SPACE_GOBBLING, "lines");
+ try
+ {
+ spaceGobbling = SpaceGobbling.valueOf(im.toUpperCase());
+ }
+ catch (NoSuchElementException nse)
+ {
+ spaceGobbling = SpaceGobbling.LINES;
+ }
}
/**
@@ -1847,4 +1864,13 @@ public class RuntimeInstance implements
{
return stringInterning;
}
+
+ /**
+ * get space gobbling mode
+ * @return indentation mode
+ */
+ public SpaceGobbling getSpaceGobbling()
+ {
+ return spaceGobbling;
+ }
}
Modified: velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/RuntimeServices.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/
velocity-engine-core/src/main/java/org/apache/velocity/
runtime/RuntimeServices.java?rev=1758416&r1=1758415&r2=1758416&view=diff
============================================================
==================
--- velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/RuntimeServices.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/RuntimeServices.java Tue Aug 30 16:18:33
2016
@@ -26,6 +26,7 @@ import org.apache.velocity.context.Conte
import org.apache.velocity.exception.MethodInvocationException;
import org.apache.velocity.exception.ParseErrorException;
import org.apache.velocity.exception.ResourceNotFoundException;
+import org.apache.velocity.runtime.RuntimeConstants.SpaceGobbling;
import org.apache.velocity.runtime.directive.Directive;
import org.apache.velocity.runtime.directive.Macro;
import org.apache.velocity.runtime.parser.ParseException;
@@ -34,7 +35,6 @@ import org.apache.velocity.runtime.parse
import org.apache.velocity.runtime.parser.node.SimpleNode;
import org.apache.velocity.runtime.resource.ContentResource;
import org.apache.velocity.util.ExtProperties;
-import org.apache.velocity.util.introspection.Introspector;
import org.apache.velocity.util.introspection.Uberspect;
import org.slf4j.Logger;
@@ -466,4 +466,6 @@ public interface RuntimeServices
public Directive getDirective(String name);
public boolean useStringInterning();
+
+ public SpaceGobbling getSpaceGobbling();
}
Modified: velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/parser/node/ASTBlock.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/
velocity-engine-core/src/main/java/org/apache/velocity/
runtime/parser/node/ASTBlock.java?rev=1758416&r1=1758415&
r2=1758416&view=diff
============================================================
==================
--- velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/parser/node/ASTBlock.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/parser/node/ASTBlock.java Tue Aug 30
16:18:33 2016
@@ -24,6 +24,7 @@ import org.apache.velocity.exception.Met
import org.apache.velocity.exception.ParseErrorException;
import org.apache.velocity.exception.ResourceNotFoundException;
import org.apache.velocity.exception.TemplateInitException;
+import org.apache.velocity.runtime.RuntimeConstants.SpaceGobbling;
import org.apache.velocity.runtime.parser.Parser;
import java.io.IOException;
@@ -35,6 +36,12 @@ import java.io.Writer;
*/
public class ASTBlock extends SimpleNode
{
+ private String prefix = "";
+ private String postfix = "";
+
+ // used during parsing
+ public boolean endsWithNewline = false;
+
/**
* @param id
*/
@@ -61,29 +68,76 @@ public class ASTBlock extends SimpleNode
}
/**
+ * @throws TemplateInitException
+ * @see org.apache.velocity.runtime.parser.node.Node#init(org.
apache.velocity.context.InternalContextAdapter, java.lang.Object)
+ */
+ public Object init( InternalContextAdapter context, Object data)
throws TemplateInitException
+ {
+ Object obj = super.init(context, data);
+ cleanupParserAndTokens(); // drop reference to Parser and all
JavaCC Tokens
+ return obj;
+ }
+
+ /**
+ * set indentation prefix
+ * @param prefix
+ */
+ public void setPrefix(String prefix)
+ {
+ this.prefix = prefix;
+ }
+
+ /**
+ * get indentation prefix
+ * @return indentation prefix
+ */
+ public String getPrefix()
+ {
+ return prefix;
+ }
+
+ /**
+ * set indentation postfix
+ * @param postfix
+ */
+ public void setPostfix(String postfix)
+ {
+ this.postfix = postfix;
+ }
+
+ /**
+ * get indentation postfix
+ * @return indentation prefix
+ */
+ public String getPostfix()
+ {
+ return postfix;
+ }
+
+ /**
* @see org.apache.velocity.runtime.parser.node.SimpleNode#render(
org.apache.velocity.context.InternalContextAdapter, java.io.Writer)
*/
public boolean render( InternalContextAdapter context, Writer
writer)
throws IOException, MethodInvocationException,
ResourceNotFoundException, ParseErrorException
{
+ SpaceGobbling spaceGobbling = rsvc.getSpaceGobbling();
+
+ if (spaceGobbling == SpaceGobbling.NONE)
+ {
+ writer.write(prefix);
+ }
+
int i, k = jjtGetNumChildren();
for (i = 0; i < k; i++)
jjtGetChild(i).render(context, writer);
+ if (spaceGobbling.compareTo(SpaceGobbling.LINES) < 0)
+ {
+ writer.write(postfix);
+ }
+
return true;
}
-
- /**
- * @throws TemplateInitException
- * @see org.apache.velocity.runtime.parser.node.Node#init(org.
apache.velocity.context.InternalContextAdapter, java.lang.Object)
- */
- public Object init( InternalContextAdapter context, Object data)
throws TemplateInitException
- {
- Object obj = super.init(context, data);
- cleanupParserAndTokens(); // drop reference to Parser and all
JavaCC Tokens
- return obj;
- }
-
}
Modified: velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/parser/node/ASTDirective.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/
velocity-engine-core/src/main/java/org/apache/velocity/
runtime/parser/node/ASTDirective.java?rev=1758416&
r1=1758415&r2=1758416&view=diff
============================================================
==================
--- velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/parser/node/ASTDirective.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/parser/node/ASTDirective.java Tue Aug 30
16:18:33 2016
@@ -25,11 +25,14 @@ import org.apache.velocity.exception.Par
import org.apache.velocity.exception.ResourceNotFoundException;
import org.apache.velocity.exception.TemplateInitException;
import org.apache.velocity.exception.VelocityException;
+import org.apache.velocity.runtime.RuntimeConstants.SpaceGobbling;
import org.apache.velocity.runtime.directive.BlockMacro;
import org.apache.velocity.runtime.directive.Directive;
import org.apache.velocity.runtime.directive.RuntimeMacro;
import org.apache.velocity.runtime.parser.ParseException;
import org.apache.velocity.runtime.parser.Parser;
+import org.apache.velocity.runtime.parser.ParserConstants;
+import org.apache.velocity.runtime.parser.Token;
import java.io.IOException;
import java.io.Writer;
@@ -55,6 +58,9 @@ public class ASTDirective extends Simple
private boolean isDirective;
private boolean isInitialized;
+ private String prefix = "";
+ private String postfix = "";
+
/**
* @param id
*/
@@ -121,7 +127,9 @@ public class ASTDirective extends Simple
e);
}
- directive.setLocation(getLine(), getColumn(),
getTemplate());
+ Token t = first;
+ if (t.kind == ParserConstants.WHITESPACE) t = t.next;
+ directive.setLocation(t.beginLine, t.beginColumn,
getTemplate());
directive.init(rsvc, context, this);
}
else if( directiveName.startsWith("@") )
@@ -191,28 +199,87 @@ public class ASTDirective extends Simple
saveTokenImages();
cleanupParserAndTokens();
}
+
+ if (rsvc.getSpaceGobbling() == SpaceGobbling.STRUCTURED &&
isInitialized && isDirective && directive.getType() == Directive.BLOCK)
+ {
+ NodeUtils.fixIndentation(this, prefix);
+ }
return data;
}
/**
+ * set indentation prefix
+ * @param prefix
+ */
+ public void setPrefix(String prefix)
+ {
+ this.prefix = prefix;
+ }
+
+ /**
+ * get indentation prefix
+ * @return indentation prefix
+ */
+ public String getPrefix()
+ {
+ return prefix;
+ }
+
+ /**
+ * set indentation postfix
+ * @param postfix
+ */
+ public void setPostfix(String postfix)
+ {
+ this.postfix = postfix;
+ }
+
+ public int getDirectiveType()
+ {
+ return directive.getType();
+ }
+
+ /**
+ * get indentation postfix
+ * @return indentation prefix
+ */
+ public String getPostfix()
+ {
+ return postfix;
+ }
+
+ /**
* @see org.apache.velocity.runtime.parser.node.SimpleNode#render(
org.apache.velocity.context.InternalContextAdapter, java.io.Writer)
*/
public boolean render( InternalContextAdapter context, Writer
writer)
throws IOException,MethodInvocationException,
ResourceNotFoundException, ParseErrorException
{
+ SpaceGobbling spaceGobbling = rsvc.getSpaceGobbling();
/*
* normal processing
*/
if (isDirective)
{
+ if (spaceGobbling.compareTo(SpaceGobbling.LINES) < 0)
+ {
+ writer.write(prefix);
+ }
+
directive.render(context, writer, this);
+
+ if (spaceGobbling == SpaceGobbling.NONE)
+ {
+ writer.write(postfix);
+ }
}
else
{
+ writer.write(prefix);
writer.write( "#");
- writer.write( directiveName );
+ writer.write(directiveName);
+ writer.write(postfix);
}
return true;
Modified: velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/parser/node/ASTElseIfStatement.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/
velocity-engine-core/src/main/java/org/apache/velocity/
runtime/parser/node/ASTElseIfStatement.java?rev=
1758416&r1=1758415&r2=1758416&view=diff
============================================================
==================
--- velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/parser/node/ASTElseIfStatement.java
(original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/parser/node/ASTElseIfStatement.java Tue
Aug 30 16:18:33 2016
@@ -24,6 +24,7 @@ import org.apache.velocity.exception.Met
import org.apache.velocity.exception.ParseErrorException;
import org.apache.velocity.exception.ResourceNotFoundException;
import org.apache.velocity.exception.TemplateInitException;
+import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.parser.Parser;
import java.io.IOException;
@@ -59,6 +60,17 @@ public class ASTElseIfStatement extends
}
/**
+ * @throws TemplateInitException
+ * @see org.apache.velocity.runtime.parser.node.Node#init(org.
apache.velocity.context.InternalContextAdapter, java.lang.Object)
+ */
+ public Object init( InternalContextAdapter context, Object data)
throws TemplateInitException
+ {
+ Object obj = super.init(context, data);
+ cleanupParserAndTokens(); // drop reference to Parser and all
JavaCC Tokens
+ return obj;
+ }
+
+ /**
* @see org.apache.velocity.runtime.parser.node.SimpleNode#
jjtAccept(org.apache.velocity.runtime.parser.node.ParserVisitor,
java.lang.Object)
*/
public Object jjtAccept(ParserVisitor visitor, Object data)
@@ -92,16 +104,4 @@ public class ASTElseIfStatement extends
{
return jjtGetChild(1).render( context, writer );
}
-
- /**
- * @throws TemplateInitException
- * @see org.apache.velocity.runtime.parser.node.Node#init(org.
apache.velocity.context.InternalContextAdapter, java.lang.Object)
- */
- public Object init( InternalContextAdapter context, Object data)
throws TemplateInitException
- {
- Object obj = super.init(context, data);
- cleanupParserAndTokens(); // drop reference to Parser and all
JavaCC Tokens
- return obj;
- }
-
}
Modified: velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/parser/node/ASTIfStatement.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/
velocity-engine-core/src/main/java/org/apache/velocity/
runtime/parser/node/ASTIfStatement.java?rev=1758416&r1=1758415&r2=1758416&
view=diff
============================================================
==================
--- velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/parser/node/ASTIfStatement.java
(original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/parser/node/ASTIfStatement.java Tue Aug
30 16:18:33 2016
@@ -34,6 +34,7 @@ import org.apache.velocity.exception.Met
import org.apache.velocity.exception.ParseErrorException;
import org.apache.velocity.exception.ResourceNotFoundException;
import org.apache.velocity.exception.TemplateInitException;
+import org.apache.velocity.runtime.RuntimeConstants.SpaceGobbling;
import org.apache.velocity.runtime.parser.Parser;
import java.io.IOException;
@@ -45,6 +46,9 @@ import java.io.Writer;
*/
public class ASTIfStatement extends SimpleNode
{
+ private String prefix = "";
+ private String postfix = "";
+
/**
* @param id
*/
@@ -62,7 +66,6 @@ public class ASTIfStatement extends Simp
super(p, id);
}
-
/**
* @see org.apache.velocity.runtime.parser.node.SimpleNode#
jjtAccept(org.apache.velocity.runtime.parser.node.ParserVisitor,
java.lang.Object)
*/
@@ -72,12 +75,73 @@ public class ASTIfStatement extends Simp
}
/**
+ * @throws TemplateInitException
+ * @see org.apache.velocity.runtime.parser.node.Node#init(org.
apache.velocity.context.InternalContextAdapter, java.lang.Object)
+ */
+ public Object init( InternalContextAdapter context, Object data)
throws TemplateInitException
+ {
+ Object obj = super.init(context, data);
+
+ /* handle structured space gobbling */
+ if (rsvc.getSpaceGobbling() == SpaceGobbling.STRUCTURED &&
postfix.length() > 0)
+ {
+ NodeUtils.fixIndentation(this, prefix);
+ }
+
+ cleanupParserAndTokens(); // drop reference to Parser and all
JavaCC Tokens
+ return obj;
+ }
+
+ /**
+ * set indentation prefix
+ * @param prefix
+ */
+ public void setPrefix(String prefix)
+ {
+ this.prefix = prefix;
+ }
+
+ /**
+ * get indentation prefix
+ * @return prefix
+ */
+ public String getPrefix()
+ {
+ return prefix;
+ }
+
+ /**
+ * set indentation postfix
+ * @param postfix
+ */
+ public void setPostfix(String postfix)
+ {
+ this.postfix = postfix;
+ }
+
+ /**
+ * get indentation postfix
+ * @return postfix
+ */
+ public String getPostfix()
+ {
+ return postfix;
+ }
+
+ /**
* @see org.apache.velocity.runtime.parser.node.SimpleNode#render(
org.apache.velocity.context.InternalContextAdapter, java.io.Writer)
*/
public boolean render( InternalContextAdapter context, Writer
writer)
throws IOException,MethodInvocationException,
ResourceNotFoundException, ParseErrorException
{
+ SpaceGobbling spaceGobbling = rsvc.getSpaceGobbling();
+
+ if (spaceGobbling.compareTo(SpaceGobbling.LINES) < 0)
+ {
+ writer.write(prefix);
+ }
+
/*
* Check if the #if(expression) construct evaluates to true:
* if so render and leave immediately because there
@@ -105,15 +169,20 @@ public class ASTIfStatement extends Simp
if (jjtGetChild(i).evaluate(context))
{
jjtGetChild(i).render(context, writer);
- return true;
+ break;
}
}
+ if (spaceGobbling == SpaceGobbling.NONE)
+ {
+ writer.write(postfix);
+ }
+
/*
- * This is reached when an ASTIfStatement
- * consists of an if/elseif sequence where
- * none of the nodes evaluate to true.
+ * This is reached without rendering anything when an
ASTIfStatement
+ * consists of an if/elseif sequence where none of the nodes
evaluate to true.
*/
+
return true;
}
@@ -124,15 +193,4 @@ public class ASTIfStatement extends Simp
public void process( InternalContextAdapter context, ParserVisitor
visitor)
{
}
-
- /**
- * @throws TemplateInitException
- * @see org.apache.velocity.runtime.parser.node.Node#init(org.
apache.velocity.context.InternalContextAdapter, java.lang.Object)
- */
- public Object init( InternalContextAdapter context, Object data)
throws TemplateInitException
- {
- Object obj = super.init(context, data);
- cleanupParserAndTokens(); // drop reference to Parser and all
JavaCC Tokens
- return obj;
- }
}
\ No newline at end of file
Modified: velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/parser/node/ASTSetDirective.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/
velocity-engine-core/src/main/java/org/apache/velocity/
runtime/parser/node/ASTSetDirective.java?rev=
1758416&r1=1758415&r2=1758416&view=diff
============================================================
==================
--- velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/parser/node/ASTSetDirective.java
(original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/parser/node/ASTSetDirective.java Tue Aug
30 16:18:33 2016
@@ -24,6 +24,7 @@ import org.apache.velocity.context.Inter
import org.apache.velocity.exception.MethodInvocationException;
import org.apache.velocity.exception.TemplateInitException;
import org.apache.velocity.runtime.RuntimeConstants;
+import org.apache.velocity.runtime.RuntimeConstants.SpaceGobbling;
import org.apache.velocity.runtime.parser.Parser;
import org.apache.velocity.util.introspection.Info;
@@ -43,6 +44,8 @@ public class ASTSetDirective extends Sim
private Node right = null;
private ASTReference left = null;
private boolean isInitialized;
+ private String prefix = "";
+ private String postfix = "";
/**
* This is really immutable after the init, so keep one for this
node
@@ -111,7 +114,29 @@ public class ASTSetDirective extends Sim
* grab this now. No need to redo each time
*/
leftReference = left.firstImage.substring(1);
-
+
+ /* handle backward compatible space gobbling if asked so */
+ if (rsvc.getSpaceGobbling() == SpaceGobbling.BC)
+ {
+ Node previousNode = null;
+ for (int brother = 0; brother <
parent.jjtGetNumChildren(); ++brother)
+ {
+ Node node = parent.jjtGetChild(brother);
+ if (node == this) break;
+ previousNode = node;
+ }
+ if (previousNode == null) prefix = "";
+ else if (previousNode instanceof ASTText)
+ {
+ ASTText text = (ASTText)previousNode;
+ if (text.getCtext().matches("[ \t]*"))
+ {
+ text.setCtext("");
+ }
+ }
+ else prefix = "";
+ }
+
isInitialized = true;
cleanupParserAndTokens();
@@ -121,6 +146,42 @@ public class ASTSetDirective extends Sim
}
/**
+ * set indentation prefix
+ * @param prefix
+ */
+ public void setPrefix(String prefix)
+ {
+ this.prefix = prefix;
+ }
+
+ /**
+ * get indentation prefix
+ * @return indentation prefix
+ */
+ public String getPrefix()
+ {
+ return prefix;
+ }
+
+ /**
+ * set indentation postfix
+ * @param postfix
+ */
+ public void setPostfix(String postfix)
+ {
+ this.postfix = postfix;
+ }
+
+ /**
+ * get indentation postfix
+ * @return indentation prefix
+ */
+ public String getPostfix()
+ {
+ return postfix;
+ }
+
+ /**
* puts the value of the RHS into the context under the key of
the LHS
* @param context
* @param writer
@@ -131,6 +192,18 @@ public class ASTSetDirective extends Sim
public boolean render( InternalContextAdapter context, Writer
writer)
throws IOException, MethodInvocationException
{
+ SpaceGobbling spaceGobbling = rsvc.getSpaceGobbling();
+
+ /* Velocity 1.x space gobbling for #set is rather wacky:
+ prefix is eaten *only* if previous token is not a text node.
+ We handle this by appropriately emptying the prefix in BC
mode.
+ */
+
+ if (spaceGobbling.compareTo(SpaceGobbling.LINES) < 0)
+ {
+ writer.write(prefix);
+ }
+
/*
* get the RHS node, and its value
*/
@@ -146,7 +219,13 @@ public class ASTSetDirective extends Sim
}
EventHandlerUtil.invalidSetMethod(rsvc, context,
leftReference, rightReference, uberInfo);
}
-
+
+ if (spaceGobbling == SpaceGobbling.NONE)
+ {
+ writer.write(postfix);
+ }
+
+
return left.setValue(context, value);
}
Modified: velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/parser/node/ASTText.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/
velocity-engine-core/src/main/java/org/apache/velocity/
runtime/parser/node/ASTText.java?rev=1758416&r1=1758415&
r2=1758416&view=diff
============================================================
==================
--- velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/parser/node/ASTText.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/parser/node/ASTText.java Tue Aug 30
16:18:33 2016
@@ -32,7 +32,7 @@ import java.io.Writer;
*/
public class ASTText extends SimpleNode
{
- private char[] ctext;
+ private String ctext;
/**
* @param id
@@ -52,6 +52,24 @@ public class ASTText extends SimpleNode
}
/**
+ * text getter
+ * @return ctext
+ */
+ public String getCtext()
+ {
+ return ctext;
+ }
+
+ /**
+ * text setter
+ * @param ctext
+ */
+ public void setCtext(String ctext)
+ {
+ this.ctext = ctext;
+ }
+
+ /**
* @see org.apache.velocity.runtime.parser.node.SimpleNode#
jjtAccept(org.apache.velocity.runtime.parser.node.ParserVisitor,
java.lang.Object)
*/
public Object jjtAccept(ParserVisitor visitor, Object data)
@@ -65,11 +83,14 @@ public class ASTText extends SimpleNode
public Object init( InternalContextAdapter context, Object data)
throws TemplateInitException
{
+ StringBuilder builder = new StringBuilder();
Token t = getFirstToken();
-
- String text = NodeUtils.tokenLiteral( t );
-
- ctext = text.toCharArray();
+ for (; t != getLastToken(); t = t.next)
+ {
+ builder.append(NodeUtils.tokenLiteral(t));
+ }
+ builder.append(NodeUtils.tokenLiteral(t));
+ ctext = builder.toString();
cleanupParserAndTokens();
Added: velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/parser/node/IndentationFixer.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/
velocity-engine-core/src/main/java/org/apache/velocity/
runtime/parser/node/IndentationFixer.java?rev=1758416&view=auto
============================================================
==================
--- velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/parser/node/IndentationFixer.java (added)
+++ velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/parser/node/IndentationFixer.java Tue
Aug 30 16:18:33 2016
@@ -0,0 +1,362 @@
+package org.apache.velocity.runtime.parser.node;
+
+import org.apache.velocity.runtime.directive.Directive;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Helper class to fix indentation in structured mode.
+ */
+
+public class IndentationFixer implements ParserVisitor
+{
+ protected String parentIndentation = null;
+ protected String extraIndentation = null;
+ protected Pattern fix = null;
+
+ protected void fillExtraIndentation(String prefix)
+ {
+ Pattern captureExtraIndentation = Pattern.compile("^" +
parentIndentation + "(\\s+)");
+ Matcher matcher = captureExtraIndentation.matcher(prefix);
+ if (matcher.find())
+ {
+ extraIndentation = matcher.group(1);
+ fix = Pattern.compile("^" + parentIndentation +
extraIndentation, Pattern.MULTILINE);
+ }
+ else
+ {
+ extraIndentation = "";
+ }
+ }
+
+ public IndentationFixer(String parentIndentation)
+ {
+ this.parentIndentation = parentIndentation;
+ }
+
+ @Override
+ public Object visit(SimpleNode node, Object data)
+ {
+ return null;
+ }
+
+ @Override
+ public Object visit(ASTprocess node, Object data)
+ {
+ return null;
+ }
+
+ @Override
+ public Object visit(ASTText node, Object data)
+ {
+ String text = node.getCtext();
+ if (extraIndentation == null)
+ {
+ fillExtraIndentation(text);
+ }
+ if (extraIndentation.length() > 0)
+ {
+ Matcher matcher = fix.matcher(text);
+ node.setCtext(matcher.replaceAll(parentIndentation));
+ }
+ return null;
+ }
+
+ @Override
+ public Object visit(ASTEscapedDirective node, Object data)
+ {
+ return null;
+ }
+
+ @Override
+ public Object visit(ASTEscape node, Object data)
+ {
+ return null;
+ }
+
+ @Override
+ public Object visit(ASTComment node, Object data)
+ {
+ return null;
+ }
+
+ @Override
+ public Object visit(ASTTextblock node, Object data)
+ {
+ return null;
+ }
+
+ @Override
+ public Object visit(ASTFloatingPointLiteral node, Object data)
+ {
+ return null;
+ }
+
+ @Override
+ public Object visit(ASTIntegerLiteral node, Object data)
+ {
+ return null;
+ }
+
+ @Override
+ public Object visit(ASTStringLiteral node, Object data)
+ {
+ return null;
+ }
+
+ @Override
+ public Object visit(ASTIdentifier node, Object data)
+ {
+ return null;
+ }
+
+ @Override
+ public Object visit(ASTWord node, Object data)
+ {
+ return null;
+ }
+
+ @Override
+ public Object visit(ASTDirectiveAssign node, Object data)
+ {
+ return null;
+ }
+
+ @Override
+ public Object visit(ASTDirective node, Object data)
+ {
+ String prefix = node.getPrefix();
+ if (prefix.length() > 0)
+ {
+ if (extraIndentation == null)
+ {
+ fillExtraIndentation(prefix);
+ }
+ if (extraIndentation.length() > 0)
+ {
+ Matcher matcher = fix.matcher(prefix);
+ node.setPrefix(matcher.replaceAll(parentIndentation));
+ if (node.getDirectiveType() == Directive.BLOCK)
+ {
+ node.childrenAccept(this, null);
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public Object visit(ASTBlock node, Object data)
+ {
+ String prefix = node.getPrefix();
+ if (prefix.length() > 0)
+ {
+ node.childrenAccept(this, null);
+ }
+ return null;
+ }
+
+ @Override
+ public Object visit(ASTMap node, Object data)
+ {
+ return null;
+ }
+
+ @Override
+ public Object visit(ASTObjectArray node, Object data)
+ {
+ return null;
+ }
+
+ @Override
+ public Object visit(ASTIntegerRange node, Object data)
+ {
+ return null;
+ }
+
+ @Override
+ public Object visit(ASTMethod node, Object data)
+ {
+ return null;
+ }
+
+ @Override
+ public Object visit(ASTIndex node, Object data)
+ {
+ return null;
+ }
+
+ @Override
+ public Object visit(ASTReference node, Object data)
+ {
+ return null;
+ }
+
+ @Override
+ public Object visit(ASTTrue node, Object data)
+ {
+ return null;
+ }
+
+ @Override
+ public Object visit(ASTFalse node, Object data)
+ {
+ return null;
+ }
+
+ @Override
+ public Object visit(ASTIfStatement node, Object data)
+ {
+ String prefix = node.getPrefix();
+ if (prefix.length() > 0)
+ {
+ if (extraIndentation == null)
+ {
+ fillExtraIndentation(prefix);
+ }
+ if (extraIndentation.length() > 0)
+ {
+ Matcher matcher = fix.matcher(prefix);
+ node.setPrefix(matcher.replaceAll(parentIndentation));
+ node.childrenAccept(this, null);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public Object visit(ASTElseStatement node, Object data)
+ {
+ if (extraIndentation != null && extraIndentation.length() > 0)
+ {
+ node.childrenAccept(this, null);
+ }
+ return null;
+ }
+
+ @Override
+ public Object visit(ASTElseIfStatement node, Object data)
+ {
+ if (extraIndentation != null && extraIndentation.length() > 0)
+ {
+ node.childrenAccept(this, null);
+ }
+ return null;
+ }
+
+ @Override
+ public Object visit(ASTSetDirective node, Object data)
+ {
+ String prefix = node.getPrefix();
+ if (prefix.length() > 0)
+ {
+ if (extraIndentation == null)
+ {
+ fillExtraIndentation(prefix);
+ }
+ if (extraIndentation.length() > 0)
+ {
+ Matcher matcher = fix.matcher(prefix);
+ node.setPrefix(matcher.replaceAll(parentIndentation));
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public Object visit(ASTExpression node, Object data)
+ {
+ return null;
+ }
+
+ @Override
+ public Object visit(ASTAssignment node, Object data)
+ {
+ return null;
+ }
+
+ @Override
+ public Object visit(ASTOrNode node, Object data)
+ {
+ return null;
+ }
+
+ @Override
+ public Object visit(ASTAndNode node, Object data)
+ {
+ return null;
+ }
+
+ @Override
+ public Object visit(ASTEQNode node, Object data)
+ {
+ return null;
+ }
+
+ @Override
+ public Object visit(ASTNENode node, Object data)
+ {
+ return null;
+ }
+
+ @Override
+ public Object visit(ASTLTNode node, Object data)
+ {
+ return null;
+ }
+
+ @Override
+ public Object visit(ASTGTNode node, Object data)
+ {
+ return null;
+ }
+
+ @Override
+ public Object visit(ASTLENode node, Object data)
+ {
+ return null;
+ }
+
+ @Override
+ public Object visit(ASTGENode node, Object data)
+ {
+ return null;
+ }
+
+ @Override
+ public Object visit(ASTAddNode node, Object data)
+ {
+ return null;
+ }
+
+ @Override
+ public Object visit(ASTSubtractNode node, Object data)
+ {
+ return null;
+ }
+
+ @Override
+ public Object visit(ASTMulNode node, Object data)
+ {
+ return null;
+ }
+
+ @Override
+ public Object visit(ASTDivNode node, Object data)
+ {
+ return null;
+ }
+
+ @Override
+ public Object visit(ASTModNode node, Object data)
+ {
+ return null;
+ }
+
+ @Override
+ public Object visit(ASTNotNode node, Object data)
+ {
+ return null;
+ }
+}
Modified: velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/parser/node/NodeUtils.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/
velocity-engine-core/src/main/java/org/apache/velocity/
runtime/parser/node/NodeUtils.java?rev=1758416&r1=1758415&
r2=1758416&view=diff
============================================================
==================
--- velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/parser/node/NodeUtils.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/parser/node/NodeUtils.java Tue Aug 30
16:18:33 2016
@@ -147,4 +147,17 @@ public class NodeUtils
return t.image;
}
}
+
+ /**
+ * Fix children indentation in structured space gobbling mode.
+ * @param parent
+ * @param parentIndentation
+ * @param extraIndentation
+ * @return
+ */
+ public static void fixIndentation(SimpleNode parent, String
parentIndentation)
+ {
+ IndentationFixer fixer = new IndentationFixer(
parentIndentation);
+ parent.childrenAccept(fixer, null);
+ }
}
Modified: velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/parser/node/ParserVisitor.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/
velocity-engine-core/src/main/java/org/apache/velocity/
runtime/parser/node/ParserVisitor.java?rev=1758416&r1=1758415&r2=1758416&
view=diff
============================================================
==================
--- velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/parser/node/ParserVisitor.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/parser/node/ParserVisitor.java Tue Aug
30 16:18:33 2016
@@ -41,6 +41,7 @@ public interface ParserVisitor
* @param data
* @return The object rendered by this node.
*/
+
public Object visit(ASTprocess node, Object data);
/**
@@ -48,6 +49,13 @@ public interface ParserVisitor
* @param data
* @return The object rendered by this node.
*/
+ public Object visit(ASTText node, Object data);
+
+ /**
+ * @param node
+ * @param data
+ * @return The object rendered by this node.
+ */
public Object visit(ASTEscapedDirective node, Object data);
/**
@@ -63,6 +71,12 @@ public interface ParserVisitor
* @return The object rendered by this node.
*/
public Object visit(ASTComment node, Object data);
+ /**
+ * @param node
+ * @param data
+ * @return The object rendered by this node.
+ */
+ public Object visit(ASTTextblock node, Object data);
/**
* @param node
@@ -104,6 +118,13 @@ public interface ParserVisitor
* @param data
* @return The object rendered by this node.
*/
+
+ public Object visit(ASTDirectiveAssign node, Object data);
+ /**
+ * @param node
+ * @param data
+ * @return The object rendered by this node.
+ */
public Object visit(ASTDirective node, Object data);
/**
@@ -146,28 +167,28 @@ public interface ParserVisitor
* @param data
* @return The object rendered by this node.
*/
- public Object visit(ASTReference node, Object data);
+ public Object visit(ASTIndex node, Object data);
/**
* @param node
* @param data
* @return The object rendered by this node.
*/
- public Object visit(ASTTrue node, Object data);
+ public Object visit(ASTReference node, Object data);
/**
* @param node
* @param data
* @return The object rendered by this node.
*/
- public Object visit(ASTFalse node, Object data);
+ public Object visit(ASTTrue node, Object data);
/**
* @param node
* @param data
* @return The object rendered by this node.
*/
- public Object visit(ASTText node, Object data);
+ public Object visit(ASTFalse node, Object data);
/**
* @param node
Modified: velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/visitor/BaseVisitor.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/
velocity-engine-core/src/main/java/org/apache/velocity/
runtime/visitor/BaseVisitor.java?rev=1758416&r1=1758415&
r2=1758416&view=diff
============================================================
==================
--- velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/visitor/BaseVisitor.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/
java/org/apache/velocity/runtime/visitor/BaseVisitor.java Tue Aug 30
16:18:33 2016
@@ -266,6 +266,15 @@ public abstract class BaseVisitor implem
}
/**
+ * @see org.apache.velocity.runtime.parser.node.ParserVisitor#
visit(org.apache.velocity.runtime.parser.node.ASTIndex, java.lang.Object)
+ */
+ public Object visit(ASTIndex node, Object data)
+ {
+ data = node.childrenAccept(this, data);
+ return data;
+ }
+
+ /**
* @see org.apache.velocity.runtime.parser.node.ParserVisitor#
visit(org.apache.velocity.runtime.parser.node.ASTReference,
java.lang.Object)
*/
public Object visit(ASTReference node, Object data)
@@ -347,6 +356,15 @@ public abstract class BaseVisitor implem
}
/**
+ * @see org.apache.velocity.runtime.parser.node.ParserVisitor#
visit(org.apache.velocity.runtime.parser.node.ASTTextblock,
java.lang.Object)
+ */
+ public Object visit(ASTTextblock node, Object data)
+ {
+ data = node.childrenAccept(this, data);
+ return data;
+ }
+
+ /**
* @see org.apache.velocity.runtime.parser.node.ParserVisitor#
visit(org.apache.velocity.runtime.parser.node.ASTObjectArray,
java.lang.Object)
*/
public Object visit(ASTObjectArray node, Object data)
@@ -371,6 +389,15 @@ public abstract class BaseVisitor implem
{
data = node.childrenAccept(this, data);
return data;
+ }
+
+ /**
+ * @see org.apache.velocity.runtime.parser.node.ParserVisitor#
visit(org.apache.velocity.runtime.parser.node.ASTDirectiveAssign,
java.lang.Object)
+ */
+ public Object visit(ASTDirectiveAssign node, Object data)
+ {
+ data = node.childrenAccept(this, data);
+ return data;
}
/**
Modified: velocity/engine/trunk/velocity-engine-core/src/main/
parser/Parser.jjt
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/
velocity-engine-core/src/main/parser/Parser.jjt?rev=1758416&
r1=1758415&r2=1758416&view=diff
============================================================
==================
--- velocity/engine/trunk/velocity-engine-core/src/main/parser/Parser.jjt
(original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/parser/Parser.jjt
Tue Aug 30 16:18:33 2016
@@ -70,8 +70,9 @@ options
/**
* for debugging purposes. Keep false
*/
- DEBUG_PARSER=false;
- DEBUG_TOKEN_MANAGER=false;
+ DEBUG_PARSER = false;
+ DEBUG_LOOKAHEAD = false;
+ DEBUG_TOKEN_MANAGER = false;
}
PARSER_BEGIN(Parser)
@@ -393,7 +394,6 @@ TOKEN_MGR_DECLS:
public boolean debugPrint = false;
private boolean inReference;
- public boolean inDirective;
private boolean inComment;
public boolean inSet;
@@ -468,7 +468,6 @@ TOKEN_MGR_DECLS:
lparen = 0;
rparen = 0;
inReference = false;
- inDirective = false;
inComment = false;
inSet = false;
@@ -544,13 +543,9 @@ TOKEN_MGR_DECLS:
*
* Tokens
*
- * Note : we now have another state, REFMODIFIER. This is sort of a
- * type of REFERENCE state, simply use to use the DIRECTIVE token
- * set when we are processing a $foo.bar() construct
- *
* -------------------------------------------------------------------------
*/
-<REFERENCE, REFMODIFIER>
+<REFERENCE, REFMODIFIER, REFMOD3>
TOKEN:
{
<INDEX_LBRACKET: "[">
@@ -623,10 +618,7 @@ TOKEN:
<DIRECTIVE>
TOKEN:
{
- /*
- * We will eat any whitespace upto and including a newline for
directives
- */
- <RPAREN: ")" ( ( " " | "\t" )* ( "\n" | "\r" | "\r\n" ))?>
+ <RPAREN: ")">
{
RPARENHandler();
}
@@ -648,7 +640,7 @@ TOKEN:
* $foo.bar().blargh().woogie().doogie()
*/
- SwitchTo( REFERENCE );
+ SwitchTo( REFMOD3 );
}
}
@@ -676,11 +668,6 @@ TOKEN:
/*
- * needed because #set is so wacky in it's desired behavior. We want
set
- * to eat any preceeding whitespace so it is invisible in formatting.
- * (As it should be.) If this works well, I am going to chuck the
whole MORE:
- * token abomination.
- *
* We added the lexical states REFERENCE, REFMODIFIER, REFMOD2 to
* address JIRA issue VELOCITY-631. With SET_DIRECTIVE only in the
* DEFAULT lexical state the following VTL fails "$a#set($b = 1)"
@@ -695,12 +682,10 @@ TOKEN:
<DEFAULT, REFERENCE, REFMODIFIER, REFMOD2>
TOKEN:
{
- <SET_DIRECTIVE: (" "|"\t")* ("#set" | "#{set}") (" "|"\t")* "(">
+ <SET_DIRECTIVE: ("#set" | "#{set}") (" "|"\t")* "(">
{
if (! inComment)
{
- inDirective = true;
-
if ( debugPrint )
System.out.print("#set : going to " + DIRECTIVE );
@@ -833,8 +818,6 @@ MORE :
stateStackPop();
}
- inDirective = true;
-
if ( debugPrint )
System.out.print("# : going to " + DIRECTIVE );
@@ -844,7 +827,6 @@ MORE :
}
}
-
// treat the single line comment case separately
// to avoid ##<EOF> errors
<DEFAULT,PRE_DIRECTIVE,DIRECTIVE,REFERENCE>
@@ -867,14 +849,6 @@ TOKEN :
}
}
-TOKEN :
-{
- <DOUBLE_ESCAPE : "\\\\">
-| <ESCAPE: "\\" >
-| <TEXT: (~["$", "#", "\\"])+ >
-}
-
-
/* ------------------------------------------------------------
-----------
*
* *_COMMENT Lexical tokens
@@ -939,10 +913,20 @@ MORE :
*
* ----------------------------------------------------------------------
*/
-<DIRECTIVE,REFMOD2,REFINDEX>
+<DEFAULT,REFINDEX,REFMOD2,DIRECTIVE>
TOKEN:
{
- <WHITESPACE : ([" ","\t", "\n", "\r"])+ >
+ <WHITESPACE : ([" ","\t"])+>
+| <NEWLINE : ("\n" | "\r" | "\r\n") >
+ {
+ if ( debugPrint )
+ System.out.println(" NEWLINE :");
+
+// stateStackPop();
+
+ if (inSet)
+ inSet = false;
+ }
}
<DIRECTIVE,REFMOD2,REFINDEX>
@@ -993,25 +977,6 @@ TOKEN:
| <FALSE: "false">
}
-<DIRECTIVE>
-TOKEN :
-{
- <NEWLINE: "\n" | "\r" | "\r\n" >
- {
- if ( debugPrint )
- System.out.println(" NEWLINE :");
-
- stateStackPop();
-
- if (inSet)
- inSet = false;
-
- if (inDirective)
- inDirective = false;
- }
-}
-
-
<DIRECTIVE,REFMOD2>
TOKEN :
{
@@ -1035,10 +1000,8 @@ TOKEN :
<PRE_DIRECTIVE>
TOKEN :
{
- <END: ( "end" ( ( " " | "\t" )* ( "\n" | "\r" | "\r\n" ) )? )
- | ("{end}" ( ( " " | "\t" )* ( "\n" | "\r" | "\r\n" ) )? ) >
+ <END: ( "end" | "{end}" )>
{
- inDirective = false;
stateStackPop();
}
@@ -1047,16 +1010,13 @@ TOKEN :
SwitchTo(DIRECTIVE);
}
-| <ELSEIF_DIRECTIVE: "elseif" | "{elseif}">
+| <ELSEIF: "elseif" | "{elseif}">
{
SwitchTo(DIRECTIVE);
}
-| <ELSE_DIRECTIVE:
- ( "else" ( ( " " | "\t" )* ( "\n" | "\r" | "\r\n" ) )? )
- | ( "{else}" ( ( " " | "\t" )* ( "\n" | "\r" | "\r\n" ) )? ) >
- {
- inDirective = false;
+| <ELSE: "else" | "{else}">
+ {
stateStackPop();
}
}
@@ -1145,17 +1105,17 @@ TOKEN:
* for each state can be different.
*
* $foo.bar( "arg" )
- * ^ ^ ^
- * | | |
- * ----------- > REFERENCE : state initiated by the '$' character.
Continues
- * | | until end of the reference, or the . character.
- * |------ > REFMODIFIER : state switched to when the <DOT> is
encountered.
- * | note that this is a switch, not a push. See notes
at bottom
- * | re stateStack.
- * |-- > REFMOD2 : state switch to when the LPAREN is
encountered.
- * again, this is a switch, not a push.
+ * ^ ^ ^ ^
+ * | | | |
+ * |_________________ > REFERENCE : state initiated by the '$'
character. Continues
+ * | | | until end of the reference, or the .
character.
+ * |_____________ > REFMODIFIER : state switched to when the
<DOT> is encountered.
+ * | | note that this is a switch, not a push. See
notes at bottom.
+ * |_________ > REFMOD2 : state switch to when the LPAREN is
encountered.
+ * | again, this is a switch, not a push.
+ * |_ > REFMOD3 : state only checking for a possible
'.' or '[' continuation.
*
- * During the REFERENCE or REFMODIFIER lex states we will switch to
+ * During the REFERENCE, REFMODIFIER or REFMOD3 lex states we will
switch to
* REFINDEX if a bracket is encountered '['. for example: $foo[1]
* or $foo.bar[1], $foo.bar( "arg" )[1]
*
----------------------------------------------------------------------------
*/
@@ -1166,7 +1126,12 @@ TOKEN :
<#ALPHA_CHAR: ["a"-"z", "A"-"Z", "_"] >
| <#IDENTIFIER_CHAR: [ "a"-"z", "A"-"Z", "0"-"9", "_" ] >
| <IDENTIFIER: ( <ALPHA_CHAR> ) (<IDENTIFIER_CHAR>)* >
-| <DOT: "." <ALPHA_CHAR>>
+}
+
+<REFERENCE,REFMODIFIER,REFMOD2,REFMOD3>
+TOKEN:
+{
+ <DOT: "." <ALPHA_CHAR>>
{
/*
* push the alpha char back into the stream so the following
identifier
@@ -1189,8 +1154,7 @@ TOKEN :
}
}
-
-<REFERENCE,REFMODIFIER>
+<REFERENCE,REFMODIFIER,REFMOD3>
TOKEN :
{
<LCURLY: "{">
@@ -1200,7 +1164,7 @@ TOKEN :
}
}
-<REFERENCE,REFMODIFIER,REFMOD>
+<REFERENCE,REFMODIFIER,REFMOD,REFMOD3>
SPECIAL_TOKEN :
{
<REFERENCE_TERMINATOR: ~[] >
@@ -1229,11 +1193,25 @@ SPECIAL_TOKEN :
System.out.print("DIRECTIVE_TERM :");
input_stream.backup(1);
- inDirective = false;
stateStackPop();
}
}
+/* TEXT must end with a newline, and contain at least one
non-whitespace character in the first line,
+ so that the <WHITESPACE> <NEWLINE> sequence is not read as a TEXT
(needed for space gobbling)
+*/
+TOKEN :
+{
+ <DOUBLE_ESCAPE : "\\\\">
+| <ESCAPE: "\\" >
+| <TEXT: (~["$", "#", "\\", "\r", "\n"])* (~["$", "#", "\\", "\r",
"\n", " ", "\t"])+ (~["$", "#", "\\", "\r", "\n"])* <NEWLINE> ((~["$", "#",
"\\", "\r", "\n"])* <NEWLINE>)* >
+}
+
+TOKEN :
+{
+ <INLINE_TEXT: (~["$", "#", "\\", "\r", "\n"])+ >
+}
+
/**
* This method is what starts the whole parsing
* process. After the parsing is complete and
@@ -1243,9 +1221,12 @@ SPECIAL_TOKEN :
* which implements the ParserVisitor interface
* which is generated automatically by JavaCC
*/
-SimpleNode process() : {}
+SimpleNode process() :
+{
+ boolean afterNewline = true;
+}
{
- ( Statement() )* <EOF>
+ ( LOOKAHEAD({ getToken(1).kind != EOF }) afterNewline =
Statement(afterNewline) )* <EOF>
{ return jjtThis; }
}
@@ -1253,17 +1234,23 @@ SimpleNode process() : {}
* These are the types of statements that
* are acceptable in Velocity templates.
*/
-void Statement() #void : {}
+boolean Statement(boolean afterNewline) #void :
{
- IfStatement()
-| LOOKAHEAD(2) Reference()
-| Comment()
-| Textblock()
-| SetDirective()
-| EscapedDirective()
-| Escape()
-| Directive()
-| Text()
+ boolean b = false;
+}
+{
+ LOOKAHEAD( { getToken(1).kind == IF_DIRECTIVE || afterNewline &&
getToken(1).kind == WHITESPACE && getToken(2).kind == IF_DIRECTIVE } ) b =
IfStatement() { return b ; }
+| LOOKAHEAD(2) Reference() { return false; }
+| LOOKAHEAD(2) Comment() { return false; }
+| Textblock() { return false; }
+| LOOKAHEAD( { getToken(1).kind == SET_DIRECTIVE || afterNewline &&
getToken(1).kind == WHITESPACE && getToken(2).kind == SET_DIRECTIVE } ) b =
SetDirective() { return b; }
+| EscapedDirective() { return false; }
+| Escape() { return false; }
+| LOOKAHEAD( { getToken(1).kind == WORD || getToken(1).kind ==
BRACKETED_WORD || afterNewline && getToken(1).kind == WHITESPACE && (
getToken(2).kind == WORD || getToken(2).kind == BRACKETED_WORD ) } ) b =
Directive() { return b; }
+| b = Text() { return b; }
+| (<NEWLINE>) #Text { return true; }
+| (<INLINE_TEXT> ((<TEXT>)? { b = true; }) ) #Text { return b; }
+| (<WHITESPACE>) #Text { return false; }
}
/**
@@ -1314,8 +1301,8 @@ void Escape() : {}
*/
switch(t.next.kind ) {
case IF_DIRECTIVE :
- case ELSE_DIRECTIVE :
- case ELSEIF_DIRECTIVE :
+ case ELSE :
+ case ELSEIF :
case END :
control = true;
break;
@@ -1414,7 +1401,7 @@ int DirectiveArg() #void : {}
/*
* Need to put this before the floating point expansion
*/
-| LOOKAHEAD( <LBRACKET> [<WHITESPACE>] ( Reference() |
IntegerLiteral()) [<WHITESPACE>] <DOUBLEDOT> ) IntegerRange()
+| LOOKAHEAD( <LBRACKET> (<WHITESPACE> | <NEWLINE>)* ( Reference() |
IntegerLiteral()) (<WHITESPACE> | <NEWLINE>)* <DOUBLEDOT> )
IntegerRange()
{
return ParserTreeConstants.JJTINTEGERRANGE;
}
@@ -1449,10 +1436,11 @@ void DirectiveAssign() : {}
/**
* Supports the Pluggable Directives
* #foo( arg+ )
+ * @returns true if ends with a newline
*/
-SimpleNode Directive() :
+boolean Directive() :
{
- Token t = null;
+ Token id = null, t = null, u = null;
int argType;
int argPos = 0;
Directive d;
@@ -1460,23 +1448,32 @@ SimpleNode Directive() :
boolean isVM = false;
boolean isMacro = false;
ArrayList argtypes = new ArrayList(4);
+ boolean newlineAtEnd = false, newlineBeforeStatement = false;
+ String blockPrefix = "";
+ ASTBlock block = null;
}
{
-
+ [
+ (t = <WHITESPACE>)
+ {
+ jjtThis.setPrefix(t.image);
+ t = null;
+ }
+ ]
/*
* note that if we were escaped, that is now handled by
* EscapedDirective()
*/
- ((t = <WORD>) | (t = <BRACKETED_WORD>))
+ ((id = <WORD>) | (id = <BRACKETED_WORD>))
{
String directiveName;
- if (t.kind == ParserConstants.BRACKETED_WORD)
+ if (id.kind == ParserConstants.BRACKETED_WORD)
{
- directiveName = t.image.substring(2, t.image.length() - 1);
+ directiveName = id.image.substring(2, id.image.length() -
1);
}
else
{
- directiveName = t.image.substring(1);
+ directiveName = id.image.substring(1);
}
d = getDirective(directiveName);
@@ -1526,7 +1523,6 @@ SimpleNode Directive() :
*/
token_source.SwitchTo(DIRECTIVE);
-
argPos = 0;
}
@@ -1538,14 +1534,16 @@ SimpleNode Directive() :
/*
* if this is indeed a token, match the #foo ( arg ) pattern
*/
- ([<WHITESPACE>] <LPAREN> ( LOOKAHEAD(2) [<WHITESPACE>] [<COMMA>
[<WHITESPACE>]]
+ ((<WHITESPACE> | <NEWLINE>)* <LPAREN> ( LOOKAHEAD(2) (<WHITESPACE>
| <NEWLINE>)* [<COMMA> (<WHITESPACE> | <NEWLINE>)*]
(
[LOOKAHEAD( { isMacro && isAssignment() })
- DirectiveAssign() [<WHITESPACE>] <EQUALS> [<WHITESPACE>]
+ DirectiveAssign() (<WHITESPACE> | <NEWLINE>)* <EQUALS> (
<WHITESPACE> | <NEWLINE> )*
{
argtypes.add(ParserTreeConstants.JJTDIRECTIVEASSIGN);
}
]
+ LOOKAHEAD( { getToken(1).kind != RPAREN } )
+ (
argType = DirectiveArg()
{
argtypes.add(argType);
@@ -1554,48 +1552,84 @@ SimpleNode Directive() :
if (isVM)
{
throw new MacroParseException("Invalid argument
"
- + (argPos+1) + " in macro call " + t.image,
currentTemplate.getName(), t);
+ + (argPos+1) + " in macro call " + id.image,
currentTemplate.getName(), id);
}
}
argPos++;
}
+ )
|
{
if (!isMacro)
{
// We only allow line comments in macro definitions for
now
- throw new MacroParseException("A Line comment is not
allowed in " + t.image
- + " arguments", currentTemplate.getName(), t);
+ throw new MacroParseException("A Line comment is not
allowed in " + id.image
+ + " arguments", currentTemplate.getName(), id);
}
}
<SINGLE_LINE_COMMENT_START> [<SINGLE_LINE_COMMENT>]
)
- )* [<WHITESPACE>] <RPAREN>)
+ )* (<WHITESPACE> | <NEWLINE>)* <RPAREN>
+ [
+ LOOKAHEAD(2) ( [ ( t = <WHITESPACE> ) ] ( u = <NEWLINE> ) )
+ {
+ if (directiveType == Directive.LINE)
+ {
+ jjtThis.setPostfix(t == null ? u.image : t.image +
u.image);
+ newlineAtEnd = true;
+ }
+ else
+ {
+ blockPrefix = (t == null ? u.image : t.image + u.image);
+ newlineBeforeStatement = true;
+ }
+ t = u = null;
+ }
+ ]
+ )
|
{
token_source.stateStackPop();
- token_source.inDirective = false;
}
)
{
if (d != null)
{
- d.checkArgs(argtypes, t, currentTemplate.getName());
+ d.checkArgs(argtypes, id, currentTemplate.getName());
}
-
if (directiveType == Directive.LINE)
{
- return jjtThis;
+ return newlineAtEnd;
}
}
/*
* and the following block if the PD needs it
*/
-
- ( Statement() )* #Block
- <END>
+ (((
+ LOOKAHEAD( { getToken(1).kind != END && (
!newlineBeforeStatement || getToken(1).kind != WHITESPACE ||
getToken(2).kind != END ) }) newlineBeforeStatement = Statement(
newlineBeforeStatement))*
+ {
+ block = jjtThis;
+ block.setPrefix(blockPrefix);
+ })
+ #Block)
+ [ LOOKAHEAD( 1, { newlineBeforeStatement })
+ (t = <WHITESPACE>)
+ {
+ block.setPostfix(t.image);
+ t = null;
+ }
+ ]
+ (<END>
+ [ LOOKAHEAD(2) ( [ ( t = <WHITESPACE> ) ] ( u = <NEWLINE> ) )
+ {
+ jjtThis.setPostfix(t == null ? u.image : t.image + u.image);
+ t = u = null;
+ newlineAtEnd = true;
+ }
+ ]
+ )
{
/*
* VM : if we are processing a #macro directive, we need to
@@ -1615,14 +1649,14 @@ SimpleNode Directive() :
if (d != null)
{
- d.checkArgs(argtypes, t, currentTemplate.getName());
+ d.checkArgs(argtypes, id, currentTemplate.getName());
}
/*
* VM : end
*/
- return jjtThis;
+ return newlineAtEnd;
}
}
@@ -1637,7 +1671,7 @@ void Map() : {}
(
LOOKAHEAD(2) Parameter() <COLON> Parameter() (<COMMA> Parameter()
<COLON> Parameter() )*
|
- [ <WHITESPACE> ]
+ ( <WHITESPACE> | <NEWLINE> )*
)
/** note: need both tokens as they are generated in different
states **/
@@ -1657,11 +1691,11 @@ void ObjectArray() : {}
*/
void IntegerRange() : {}
{
- <LBRACKET> [<WHITESPACE>]
+ <LBRACKET> (<WHITESPACE> | <NEWLINE>)*
( Reference() | IntegerLiteral())
- [<WHITESPACE>] <DOUBLEDOT> [<WHITESPACE>]
+ (<WHITESPACE>|<NEWLINE>)* <DOUBLEDOT> (<WHITESPACE>|<NEWLINE>)*
(Reference() | IntegerLiteral())
- [<WHITESPACE>] <RBRACKET>
+ (<WHITESPACE>|<NEWLINE>)* <RBRACKET>
}
@@ -1670,7 +1704,7 @@ void IntegerRange() : {}
*/
void IndexParameter() #void: {}
{
- [<WHITESPACE>]
+ (<WHITESPACE>|<NEWLINE>)*
(
StringLiteral()
| IntegerLiteral()
@@ -1678,7 +1712,7 @@ void IndexParameter() #void: {}
| False()
| Reference()
)
- [ <WHITESPACE>]
+ (<WHITESPACE>|<NEWLINE>)*
}
@@ -1689,11 +1723,11 @@ void IndexParameter() #void: {}
*/
void Parameter() #void: {}
{
- [<WHITESPACE>]
+ (<WHITESPACE>|<NEWLINE>)*
(
StringLiteral()
| IntegerLiteral()
- | LOOKAHEAD( <LBRACKET> [<WHITESPACE>] ( Reference() |
IntegerLiteral()) [<WHITESPACE>] <DOUBLEDOT> ) IntegerRange()
+ | LOOKAHEAD( <LBRACKET> ( <WHITESPACE> | <NEWLINE> )* (
Reference() | IntegerLiteral()) ( <WHITESPACE> | <NEWLINE> )*
<DOUBLEDOT> ) IntegerRange()
| Map()
| ObjectArray()
| True()
@@ -1768,20 +1802,21 @@ TOKEN :
* This method is responsible for allowing
* all non-grammar text to pass through
* unscathed.
+ * @returns true if last read token was a newline
*/
-void Text() : {}
+boolean Text() : {}
{
- <TEXT>
-| <DOT>
-| <RPAREN>
-| <LPAREN>
-| <INTEGER_LITERAL>
-| <FLOATING_POINT_LITERAL>
-| <STRING_LITERAL>
-| <ESCAPE>
-| <LCURLY>
-| <RCURLY>
-| <EMPTY_INDEX>
+ <TEXT> { return true; }
+ | <DOT> { return false; }
+ | <RPAREN> { return false; }
+ | <LPAREN> { return false; }
+ | <INTEGER_LITERAL> { return false; }
+ | <FLOATING_POINT_LITERAL> { return false; }
+ | <STRING_LITERAL> { return false; }
+ | <ESCAPE> { return false; }
+ | <LCURLY> { return false; }
+ | <RCURLY> { return false; }
+ | <EMPTY_INDEX> { return false; }
}
/* ------------------------------------------------------------
-----------
@@ -1790,26 +1825,130 @@ void Text() : {}
*
* ------------------------------------------------------------
----------*/
-void IfStatement() : {}
+boolean IfStatement() :
{
- <IF_DIRECTIVE> [<WHITESPACE>] <LPAREN> Expression() <RPAREN>
- ( Statement() )* #Block
- [ LOOKAHEAD(1) ( ElseIfStatement() )+ ]
- [ LOOKAHEAD(1) ElseStatement() ]
+ Token t = null, u = null;
+ ASTBlock lastBlock = null;
+ boolean afterNewline = false, newlineAtEnd = false;
+}
+{
+ [ ( t = <WHITESPACE> )
+ {
+ jjtThis.setPrefix(t.image);
+ t = null;
+ }
+ ]
+ <IF_DIRECTIVE> ( <WHITESPACE> | <NEWLINE> )* <LPAREN> Expression()
<RPAREN>
+ (
+ [
+ LOOKAHEAD(2) ( [ ( t = <WHITESPACE> ) ] ( u = <NEWLINE> ) )
+ {
+ jjtThis.setPrefix(t == null ? u.image : t.image + u.image);
+ t = u = null;
+ afterNewline = true;
+ }
+ ]
+ ( LOOKAHEAD(
+ {
+ (getToken(1).kind != ELSEIF && getToken(1).kind != ELSE &&
getToken(1).kind != END) &&
+ (!afterNewline || getToken(1).kind != WHITESPACE ||
(getToken(2).kind != ELSEIF && getToken(2).kind != ELSE && getToken(2).kind
!= END))
+ })
+ afterNewline = Statement(afterNewline) )*
+ {
+ lastBlock = jjtThis;
+ }
+ ) #Block
+ [ LOOKAHEAD( { getToken(1).kind == ELSEIF || (afterNewline &&
getToken(1).kind == WHITESPACE && getToken(2).kind == ELSEIF) })
+ ( LOOKAHEAD( { getToken(1).kind == ELSEIF || (afterNewline &&
getToken(1).kind == WHITESPACE && getToken(2).kind == ELSEIF) }) (
lastBlock = ElseIfStatement(lastBlock) { afterNewline =
lastBlock.endsWithNewline; } ))+ ]
+ [ LOOKAHEAD( { getToken(1).kind == ELSE || (afterNewline &&
getToken(1).kind == WHITESPACE && getToken(2).kind == ELSE) } ) lastBlock =
ElseStatement(lastBlock) { afterNewline = lastBlock.endsWithNewline; } ]
+ [ LOOKAHEAD( 1, { afterNewline } ) ( t = <WHITESPACE> )
+ {
+ lastBlock.setPostfix(t.image);
+ t = null;
+ }
+ ]
<END>
+ [
+ LOOKAHEAD(2) ( [ ( t = <WHITESPACE> ) ] ( u = <NEWLINE> ) )
+ {
+ jjtThis.setPostfix(t == null ? u.image : t.image +
u.image);
+ newlineAtEnd = true;
+ }
+ ]
+ {
+ return newlineAtEnd;
+ }
}
-void ElseStatement() : {}
+ASTBlock ElseStatement(ASTBlock previousBlock) :
{
- <ELSE_DIRECTIVE>
- ( Statement() )* #Block
+ Token t = null, u = null;
+ ASTBlock block = null;
+ boolean afterNewline = false;
+}
+{
+ [ ( t = <WHITESPACE> )
+ {
+ previousBlock.setPostfix(t.image);
+ t = null;
+ }
+ ]
+ <ELSE>
+ (
+ [
+ LOOKAHEAD(2) ( [ ( t = <WHITESPACE> ) ] ( u = <NEWLINE> ) )
+ {
+ jjtThis.setPrefix(t == null ? u.image : t.image + u.image);
+ t = u = null;
+ afterNewline = true;
+ }
+ ]
+ ( LOOKAHEAD( { getToken(1).kind != END && (!afterNewline ||
getToken(1).kind != WHITESPACE || getToken(2).kind != END) }) afterNewline
= Statement(afterNewline) )*
+ {
+ block = jjtThis;
+ block.endsWithNewline = afterNewline;
+ }
+ )
+ #Block
+ {
+ return block;
+ }
}
-void ElseIfStatement() : {}
+ASTBlock ElseIfStatement(ASTBlock previousBlock) :
{
- <ELSEIF_DIRECTIVE> [<WHITESPACE>]
- <LPAREN> Expression() <RPAREN>
- ( Statement() )* #Block
+ Token t = null, u = null;
+ ASTBlock block = null;
+ boolean afterNewline = false;
+}
+{
+ [ ( t = <WHITESPACE> )
+ {
+ previousBlock.setPostfix(t.image);
+ t = null;
+ }
+ ]
+ <ELSEIF> ( <WHITESPACE> | <NEWLINE> )*
+ <LPAREN> Expression() <RPAREN>
+ (
+ [
+ LOOKAHEAD(2) ( [ ( t = <WHITESPACE> ) ] ( u = <NEWLINE> ) )
+ {
+ jjtThis.setPrefix(t == null ? u.image : t.image + u.image);
+ t = u = null;
+ afterNewline = true;
+ }
+ ]
+ ( LOOKAHEAD( { (getToken(1).kind != ELSEIF && getToken(1).kind !=
ELSE && getToken(1).kind != END) && (!afterNewline || getToken(1).kind !=
WHITESPACE || (getToken(2).kind != ELSEIF && getToken(2).kind != ELSE &&
getToken(2).kind != END)) }) afterNewline = Statement(afterNewline) )*
+ {
+ block = jjtThis;
+ block.endsWithNewline = afterNewline;
+ }
+ )
+ #Block
+ {
+ return block;
+ }
}
/**
@@ -1817,9 +1956,19 @@ void ElseIfStatement() : {}
* #set( expr )
* #set expr
*/
-void SetDirective() : {}
+boolean SetDirective() :
+{
+ Token t = null, u = null;
+ boolean endsWithNewline = false;
+}
{
- <SET_DIRECTIVE>([<WHITESPACE>] Reference() [<WHITESPACE>] <EQUALS>
Expression() <RPAREN>
+ [ ( t = <WHITESPACE> )
+ {
+ jjtThis.setPrefix(t.image);
+ t = null;
+ }
+ ]
+ <SET_DIRECTIVE>(( <WHITESPACE> | <NEWLINE> )* Reference() (
<WHITESPACE> | <NEWLINE> )* <EQUALS> Expression() <RPAREN>
{
/*
* ensure that inSet is false. Leads to some amusing bugs...
@@ -1827,7 +1976,16 @@ void SetDirective() : {}
token_source.inSet = false;
}
- [<NEWLINE>] )
+ [
+ LOOKAHEAD(2) ( [ ( t = <WHITESPACE> ) ] ( u = <NEWLINE> ) )
+ {
+ jjtThis.setPostfix(t == null ? u.image : t.image +
u.image);
+ endsWithNewline = true;
+ }
+ ] )
+ {
+ return endsWithNewline;
+ }
}
/* ------------------------------------------------------------
-----------
@@ -1902,18 +2060,21 @@ void MultiplicativeExpression() #void :
void UnaryExpression() #void : {}
{
- LOOKAHEAD(2) [<WHITESPACE>] <LOGICAL_NOT> UnaryExpression()
#NotNode(1)
-| PrimaryExpression()
+ ( <WHITESPACE> | <NEWLINE> )*
+ (
+ <LOGICAL_NOT> UnaryExpression() #NotNode(1)
+ | PrimaryExpression()
+ )
}
void PrimaryExpression() #void : {}
{
- [<WHITESPACE>]
+ ( <WHITESPACE> | <NEWLINE> )*
(
StringLiteral()
| Reference()
| IntegerLiteral()
- | LOOKAHEAD( <LBRACKET> [<WHITESPACE>] ( Reference() |
IntegerLiteral()) [<WHITESPACE>] <DOUBLEDOT> ) IntegerRange()
+ | LOOKAHEAD( <LBRACKET> ( <WHITESPACE> | <NEWLINE> )* (
Reference() | IntegerLiteral()) ( <WHITESPACE> | <NEWLINE> )*
<DOUBLEDOT> ) IntegerRange()
| FloatingPointLiteral()
| Map()
| ObjectArray()
@@ -1921,7 +2082,7 @@ void PrimaryExpression() #void : {}
| False()
| <LPAREN> Expression() <RPAREN>
)
- [<WHITESPACE>]
+ ( <WHITESPACE> | <NEWLINE> )*
}
Modified: velocity/engine/trunk/velocity-engine-core/src/main/
resources/org/apache/velocity/runtime/defaults/velocity.properties
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/
velocity-engine-core/src/main/resources/org/apache/velocity/
runtime/defaults/velocity.properties?rev=1758416&r1=
1758415&r2=1758416&view=diff
============================================================
==================
--- velocity/engine/trunk/velocity-engine-core/src/main/
resources/org/apache/velocity/runtime/defaults/velocity.properties
(original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/
resources/org/apache/velocity/runtime/defaults/velocity.properties Tue
Aug 30 16:18:33 2016
@@ -223,4 +223,10 @@ introspector.restrict.classes = java.lan
introspector.restrict.classes = java.lang.ThreadGroup
introspector.restrict.classes = java.lang.ThreadLocal
+# ------------------------------------------------------------
----------------
+# SPACE GOBBLING
+# ------------------------------------------------------------
----------------
+# Possible values: none, bc (aka Backward Compatible), lines, structured
+# ------------------------------------------------------------
----------------
+space.gobbling = lines
Modified: velocity/engine/trunk/velocity-engine-core/src/test/
java/org/apache/velocity/test/InlineScopeVMTestCase.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/
velocity-engine-core/src/test/java/org/apache/velocity/test/
InlineScopeVMTestCase.java?rev=1758416&r1=1758415&r2=1758416&view=diff
============================================================
==================
--- velocity/engine/trunk/velocity-engine-core/src/test/
java/org/apache/velocity/test/InlineScopeVMTestCase.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/test/
java/org/apache/velocity/test/InlineScopeVMTestCase.java Tue Aug 30
16:18:33 2016
@@ -60,7 +60,7 @@ public class InlineScopeVMTestCase exten
Velocity.VM_PERM_ALLOW_INLINE_REPLACE_GLOBAL, "true");
Velocity.setProperty(
- Velocity.VM_PERM_INLINE_LOCAL, "true");
+ Velocity.VM_PERM_INLINE_LOCAL, "true");
Velocity.setProperty(
Velocity.FILE_RESOURCE_LOADER_PATH,
FILE_RESOURCE_LOADER_PATH);
@@ -68,6 +68,8 @@ public class InlineScopeVMTestCase exten
Velocity.setProperty(
Velocity.RUNTIME_LOG_INSTANCE, new TestLogger());
+ Velocity.setProperty("space.gobbling", "bc");
+
Velocity.init();
}
Modified: velocity/engine/trunk/velocity-engine-core/src/test/
java/org/apache/velocity/test/ScopeTestCase.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/
velocity-engine-core/src/test/java/org/apache/velocity/test/
ScopeTestCase.java?rev=1758416&r1=1758415&r2=1758416&view=diff
============================================================
==================
--- velocity/engine/trunk/velocity-engine-core/src/test/
java/org/apache/velocity/test/ScopeTestCase.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/test/
java/org/apache/velocity/test/ScopeTestCase.java Tue Aug 30 16:18:33 2016
@@ -43,6 +43,7 @@ public class ScopeTestCase extends BaseT
engine.setProperty("macro.provide.scope.control", "true");
engine.setProperty("template.provide.scope.control", "true");
engine.setProperty("vm.provide.scope.control", "true");
+ engine.setProperty("space.gobbling", "bc");
}
public void testScopeGetLeakIntoInner()
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@velocity.apache.org
For additional commands, e-mail: dev-h...@velocity.apache.org