You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by he...@apache.org on 2015/08/27 22:00:20 UTC
svn commit: r1698223 - in /commons/proper/jexl/trunk/src:
main/java/org/apache/commons/jexl3/internal/
test/java/org/apache/commons/jexl3/
Author: henrib
Date: Thu Aug 27 20:00:20 2015
New Revision: 1698223
URL: http://svn.apache.org/r1698223
Log:
JEXL:
Refactored template code into multiple files
Added:
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/TemplateDebugger.java (with props)
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/TemplateScript.java (with props)
Modified:
commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/TemplateEngine.java
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArithmeticTest.java
commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/IssuesTest.java
Added: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/TemplateDebugger.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/TemplateDebugger.java?rev=1698223&view=auto
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/TemplateDebugger.java (added)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/TemplateDebugger.java Thu Aug 27 20:00:20 2015
@@ -0,0 +1,291 @@
+/*
+ * 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.
+ */
+package org.apache.commons.jexl3.internal;
+
+import org.apache.commons.jexl3.JxltEngine;
+import org.apache.commons.jexl3.internal.TemplateEngine.CompositeExpression;
+import org.apache.commons.jexl3.internal.TemplateEngine.ConstantExpression;
+import org.apache.commons.jexl3.internal.TemplateEngine.DeferredExpression;
+import org.apache.commons.jexl3.internal.TemplateEngine.ImmediateExpression;
+import org.apache.commons.jexl3.internal.TemplateEngine.NestedExpression;
+import org.apache.commons.jexl3.internal.TemplateEngine.TemplateExpression;
+
+import org.apache.commons.jexl3.parser.ASTBlock;
+import org.apache.commons.jexl3.parser.ASTFunctionNode;
+import org.apache.commons.jexl3.parser.ASTIdentifier;
+import org.apache.commons.jexl3.parser.ASTJexlScript;
+import org.apache.commons.jexl3.parser.ASTNumberLiteral;
+import org.apache.commons.jexl3.parser.JexlNode;
+
+/**
+ * A visitor for templates.
+ * <p>A friend (ala C++) of template engine.
+ */
+public class TemplateDebugger extends Debugger {
+ /** The outer script. */
+ private ASTJexlScript script;
+ /** The expressions called by the script through jexl:print. */
+ private TemplateExpression[] exprs;
+
+ /**
+ * Default ctor.
+ */
+ public TemplateDebugger() {
+ }
+
+ /**
+ * Position the debugger on the root of a template expression.
+ * @param je the expression
+ * @return true if the expression was a {@link TemplateExpression} instance, false otherwise
+ */
+ public boolean debug(JxltEngine.Expression je) {
+ if (je instanceof TemplateExpression) {
+ TemplateEngine.TemplateExpression te = (TemplateEngine.TemplateExpression) je;
+ return visit(te, this) != null;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Position the debugger on the root of a template script.
+ * @param jt the template
+ * @return true if the template was a {@link TemplateScript} instance, false otherwise
+ */
+ public boolean debug(JxltEngine.Template jt) {
+ if (jt instanceof TemplateScript) {
+ TemplateScript ts = (TemplateScript) jt;
+ // ensure expr is not null for templates
+ this.exprs = ts.getExpressions() == null? new TemplateExpression[0] : ts.getExpressions();
+ this.script = ts.getScript();
+ start = 0;
+ end = 0;
+ indentLevel = 0;
+ builder.setLength(0);
+ cause = script;
+ int num = script.jjtGetNumChildren();
+ for (int i = 0; i < num; ++i) {
+ JexlNode child = script.jjtGetChild(i);
+ acceptStatement(child, null);
+ }
+ if (builder.length() > 0 && builder.charAt(builder.length() - 1) != '\n') {
+ builder.append('\n');
+ }
+ end = builder.length();
+ return end > 0;
+ } else {
+ return false;
+ }
+ }
+
+
+ @Override
+ protected Object visit(ASTBlock node, Object data) {
+ // if not really a template, use super impl
+ if (exprs == null) {
+ return super.visit(node, data);
+ }
+ // open the block
+ builder.append('{');
+ if (indent > 0) {
+ indentLevel += 1;
+ builder.append('\n');
+ } else {
+ builder.append(' ');
+ }
+ int num = node.jjtGetNumChildren();
+ for (int i = 0; i < num; ++i) {
+ JexlNode child = node.jjtGetChild(i);
+ acceptStatement(child, data);
+ }
+ // before we close this block node, $$ might be needed
+ newJexlLine();
+ if (indent > 0) {
+ indentLevel -= 1;
+ for (int i = 0; i < indentLevel; ++i) {
+ for(int s = 0; s < indent; ++s) {
+ builder.append(' ');
+ }
+ }
+ }
+ builder.append('}');
+ // closed the block
+ return data;
+ }
+
+ @Override
+ protected Object acceptStatement(JexlNode child, Object data) {
+ // if not really a template, use super impl
+ if (exprs != null) {
+ int printe = getPrintStatement(child);
+ if (printe >= 0) {
+ // statement is an expr
+ TemplateExpression te = exprs[printe];
+ return visit(te, data);
+ }
+ // if statement is not a jexl:print(...), need to prepend '$$'
+ newJexlLine();
+ }
+ return super.acceptStatement(child, data);
+ }
+
+ /**
+ * In a template, any statement that is not 'jexl:print(n)' must be prefixed by "$$".
+ * @param child the node to check
+ * @return the expression number or -1 if the node is not a jexl:print
+ */
+ private int getPrintStatement(JexlNode child) {
+ if (child instanceof ASTFunctionNode) {
+ ASTFunctionNode node = (ASTFunctionNode) child;
+ int num = node.jjtGetNumChildren();
+ if (num == 3) {
+ ASTIdentifier ns = (ASTIdentifier) node.jjtGetChild(0);
+ ASTIdentifier fn = (ASTIdentifier) node.jjtGetChild(1);
+ JexlNode args = node.jjtGetChild(2);
+ if ("jexl".equals(ns.getName())
+ && "print".equals(fn.getName())
+ && args.jjtGetNumChildren() == 1
+ && args.jjtGetChild(0) instanceof ASTNumberLiteral) {
+ ASTNumberLiteral exprn = (ASTNumberLiteral) args.jjtGetChild(0);
+ int n = exprn.getLiteral().intValue();
+ if (exprs != null && n >= 0 && n < exprs.length) {
+ return n;
+ }
+ }
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Insert $$ and \n when needed.
+ */
+ private void newJexlLine() {
+ int length = builder.length();
+ if (length == 0) {
+ builder.append("$$ ");
+ } else {
+ for (int i = length - 1; i >= 0; --i) {
+ char c = builder.charAt(i);
+ if (c == '\n') {
+ builder.append("$$ ");
+ break;
+ }
+ if (c == '}') {
+ builder.append("\n$$ ");
+ break;
+ }
+ if (c != ' ') {
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * Visit a template expression.
+ * @param expr the constant expression
+ * @param data the visitor argument
+ * @return the visitor argument
+ */
+ private Object visit(TemplateExpression expr, Object data) {
+ Object r;
+ switch (expr.getType()) {
+ case CONSTANT:
+ r = visit((ConstantExpression) expr, data);
+ break;
+ case IMMEDIATE:
+ r = visit((ImmediateExpression) expr, data);
+ break;
+ case DEFERRED:
+ r = visit((DeferredExpression) expr, data);
+ break;
+ case NESTED:
+ r = visit((NestedExpression) expr, data);
+ break;
+ case COMPOSITE:
+ r = visit((CompositeExpression) expr, data);
+ break;
+ default:
+ r = null;
+ }
+ return r;
+ }
+
+ /**
+ * Visit a constant expression.
+ * @param expr the constant expression
+ * @param data the visitor argument
+ * @return the visitor argument
+ */
+ private Object visit(ConstantExpression expr, Object data) {
+ expr.asString(builder);
+ return data;
+ }
+
+ /**
+ * Visit an immediate expression.
+ * @param expr the immediate expression
+ * @param data the visitor argument
+ * @return the visitor argument
+ */
+ private Object visit(ImmediateExpression expr, Object data) {
+ builder.append(expr.isImmediate() ? '$' : '#');
+ builder.append('{');
+ super.accept(expr.node, data);
+ builder.append('}');
+ return data;
+ }
+
+ /**
+ * Visit a deferred expression.
+ * @param expr the deferred expression
+ * @param data the visitor argument
+ * @return the visitor argument
+ */
+ private Object visit(DeferredExpression expr, Object data) {
+ builder.append(expr.isImmediate() ? '$' : '#');
+ builder.append('{');
+ super.accept(expr.node, data);
+ builder.append('}');
+ return data;
+ }
+
+ /**
+ * Visit a nested expression.
+ * @param expr the nested expression
+ * @param data the visitor argument
+ * @return the visitor argument
+ */
+ private Object visit(NestedExpression expr, Object data) {
+ super.accept(expr.node, data);
+ return data;
+ }
+ /**
+ * Visit a composite expression.
+ * @param expr the composite expression
+ * @param data the visitor argument
+ * @return the visitor argument
+ */
+ private Object visit(CompositeExpression expr, Object data) {
+ for (TemplateExpression ce : expr.exprs) {
+ visit(ce, data);
+ }
+ return data;
+ }
+
+}
Propchange: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/TemplateDebugger.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/TemplateEngine.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/TemplateEngine.java?rev=1698223&r1=1698222&r2=1698223&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/TemplateEngine.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/TemplateEngine.java Thu Aug 27 20:00:20 2015
@@ -17,11 +17,9 @@
package org.apache.commons.jexl3.internal;
import org.apache.commons.jexl3.JexlContext;
-import org.apache.commons.jexl3.JexlEngine;
import org.apache.commons.jexl3.JexlException;
import org.apache.commons.jexl3.JexlInfo;
import org.apache.commons.jexl3.JxltEngine;
-import org.apache.commons.jexl3.internal.Engine.VarCollector;
import org.apache.commons.jexl3.introspection.JexlMethod;
import org.apache.commons.jexl3.introspection.JexlUberspect;
import org.apache.commons.jexl3.parser.ASTJexlScript;
@@ -45,10 +43,10 @@ import java.util.Set;
* @since 3.0
*/
public final class TemplateEngine extends JxltEngine {
- /** The JEXL engine instance. */
- private final Engine jexl;
/** The TemplateExpression cache. */
private final Engine.SoftCache<String, TemplateExpression> cache;
+ /** The JEXL engine instance. */
+ private final Engine jexl;
/** The first character for immediate expressions. */
private final char immediateChar;
/** The first character for deferred expressions. */
@@ -73,11 +71,25 @@ public final class TemplateEngine extend
}
/**
+ * @return the immediate character
+ */
+ char getImmediateChar() {
+ return immediateChar;
+ }
+
+ /**
+ * @return the deferred character
+ */
+ char getDeferredChar() {
+ return deferredChar;
+ }
+
+ /**
* Types of expressions.
* Each instance carries a counter index per (composite sub-) template expression type.
* @see ExpressionBuilder
*/
- private static enum ExpressionType {
+ static enum ExpressionType {
/** Constant TemplateExpression, count index 0. */
CONSTANT(0),
/** Immediate TemplateExpression, count index 1. */
@@ -105,7 +117,7 @@ public final class TemplateEngine extend
* A helper class to build expressions.
* Keeps count of sub-expressions by type.
*/
- private static final class ExpressionBuilder {
+ static final class ExpressionBuilder {
/** Per TemplateExpression type counters. */
private final int[] counts;
/** The list of expressions. */
@@ -181,7 +193,7 @@ public final class TemplateEngine extend
* @return the JexlEngine
*/
@Override
- public JexlEngine getEngine() {
+ public Engine getEngine() {
return jexl;
}
@@ -198,7 +210,7 @@ public final class TemplateEngine extend
/**
* The abstract base class for all unified expressions, immediate '${...}' and deferred '#{...}'.
*/
- private abstract class TemplateExpression implements Expression {
+ abstract class TemplateExpression implements Expression {
/** The source of this template expression(see {@link TemplateEngine.TemplateExpression#prepare}). */
protected final TemplateExpression source;
@@ -347,7 +359,7 @@ public final class TemplateEngine extend
}
/** A constant unified expression. */
- private class ConstantExpression extends TemplateExpression {
+ class ConstantExpression extends TemplateExpression {
/** The constant held by this unified expression. */
private final Object value;
@@ -391,7 +403,7 @@ public final class TemplateEngine extend
}
/** The base for Jexl based unified expressions. */
- private abstract class JexlBasedExpression extends TemplateExpression {
+ abstract class JexlBasedExpression extends TemplateExpression {
/** The JEXL string for this unified expression. */
protected final CharSequence expr;
/** The JEXL node for this unified expression. */
@@ -442,7 +454,7 @@ public final class TemplateEngine extend
}
/** An immediate unified expression: ${jexl}. */
- private class ImmediateExpression extends JexlBasedExpression {
+ class ImmediateExpression extends JexlBasedExpression {
/**
* Creates an immediate unified expression.
* @param expr the unified expression as a string
@@ -467,7 +479,7 @@ public final class TemplateEngine extend
}
/** A deferred unified expression: #{jexl}. */
- private class DeferredExpression extends JexlBasedExpression {
+ class DeferredExpression extends JexlBasedExpression {
/**
* Creates a deferred unified expression.
* @param expr the unified expression as a string
@@ -504,7 +516,7 @@ public final class TemplateEngine extend
* #{...${jexl}...}
* Note that the deferred syntax is JEXL's.
*/
- private class NestedExpression extends JexlBasedExpression {
+ class NestedExpression extends JexlBasedExpression {
/**
* Creates a nested unified expression.
* @param expr the unified expression as a string
@@ -548,7 +560,7 @@ public final class TemplateEngine extend
}
/** A composite unified expression: "... ${...} ... #{...} ...". */
- private class CompositeExpression extends TemplateExpression {
+ class CompositeExpression extends TemplateExpression {
/** Bit encoded (deferred count > 0) bit 1, (immediate count > 0) bit 0. */
private final int meta;
/** The list of sub-expression resulting from parsing. */
@@ -732,7 +744,7 @@ public final class TemplateEngine extend
* @return the unified expression instance
* @throws JexlException if an error occur during parsing
*/
- private TemplateExpression parseExpression(JexlInfo info, String expr, Scope scope) {
+ TemplateExpression parseExpression(JexlInfo info, String expr, Scope scope) {
final int size = expr.length();
final ExpressionBuilder builder = new ExpressionBuilder(0);
final StringBuilder strb = new StringBuilder(size);
@@ -899,7 +911,7 @@ public final class TemplateEngine extend
/**
* The enum capturing the difference between verbatim and code source fragments.
*/
- private static enum BlockType {
+ static enum BlockType {
/** Block is to be output "as is" but may be a unified expression. */
VERBATIM,
/** Block is a directive, ie a fragment of JEXL code. */
@@ -909,7 +921,7 @@ public final class TemplateEngine extend
/**
* Abstract the source fragments, verbatim or immediate typed text blocks.
*/
- private static final class Block {
+ static final class Block {
/** The type of block, verbatim or directive. */
private final BlockType type;
/** The block start line info. */
@@ -920,7 +932,7 @@ public final class TemplateEngine extend
/**
* Creates a new block.
* @param theType the block type
- * @param theLine the line number
+ * @param theLine the line number
* @param theBlock the content
*/
Block(BlockType theType, int theLine, String theBlock) {
@@ -929,20 +941,44 @@ public final class TemplateEngine extend
body = theBlock;
}
+ /**
+ * @return type
+ */
+ BlockType getType() {
+ return type;
+ }
+
+ /**
+ * @return line
+ */
+ int getLine() {
+ return line;
+ }
+
+ /**
+ * @return body
+ */
+ String getBody() {
+ return body;
+ }
+
@Override
public String toString() {
if (BlockType.VERBATIM.equals(type)) {
return body;
} else {
StringBuilder strb = new StringBuilder(64);
- toString(strb, "$$");
+ Iterator<CharSequence> lines = readLines(new StringReader(body));
+ while (lines.hasNext()) {
+ strb.append("$$").append(lines.next());
+ }
return strb.toString();
}
}
/**
* Appends this block string representation to a builder.
- * @param strb the string builder to append to
+ * @param strb the string builder to append to
* @param prefix the line prefix (immediate or deferred)
*/
protected void toString(StringBuilder strb, String prefix) {
@@ -951,165 +987,12 @@ public final class TemplateEngine extend
} else {
Iterator<CharSequence> lines = readLines(new StringReader(body));
while (lines.hasNext()) {
- strb.append(prefix);
- strb.append(lines.next());
+ strb.append(prefix).append(lines.next());
}
}
}
}
- /**
- * A Template instance.
- */
- public final class TemplateScript implements Template {
- /** The prefix marker. */
- private final String prefix;
- /** The array of source blocks. */
- private final Block[] source;
- /** The resulting script. */
- private final ASTJexlScript script;
- /** The TemplateEngine expressions called by the script. */
- private final TemplateExpression[] exprs;
-
- /**
- * Creates a new template from an character input.
- * @param info the source info
- * @param directive the prefix for lines of code; can not be "$", "${", "#" or "#{"
- * since this would preclude being able to differentiate directives and template expressions
- * @param reader the input reader
- * @param parms the parameter names
- * @throws NullPointerException if either the directive prefix or input is null
- * @throws IllegalArgumentException if the directive prefix is invalid
- */
- public TemplateScript(JexlInfo info, String directive, Reader reader, String... parms) {
- if (directive == null) {
- throw new NullPointerException("null prefix");
- }
- if (Character.toString(immediateChar).equals(directive)
- || (Character.toString(immediateChar) + "{").equals(directive)
- || Character.toString(deferredChar).equals(directive)
- || (Character.toString(deferredChar) + "{").equals(directive)) {
- throw new IllegalArgumentException(directive + ": is not a valid directive pattern");
- }
- if (reader == null) {
- throw new NullPointerException("null input");
- }
- Scope scope = parms == null ? null : new Scope(null, parms);
- prefix = directive;
- List<Block> blocks = readTemplate(prefix, reader);
- List<TemplateExpression> uexprs = new ArrayList<TemplateExpression>();
- StringBuilder strb = new StringBuilder();
- int nuexpr = 0;
- int codeStart = -1;
- for (int b = 0; b < blocks.size(); ++b) {
- Block block = blocks.get(b);
- if (block.type == BlockType.VERBATIM) {
- strb.append("jexl:print(");
- strb.append(nuexpr++);
- strb.append(");");
- } else {
- // keep track of first block of code, the frame creator
- if (codeStart < 0) {
- codeStart = b;
- }
- strb.append(block.body);
- }
- }
- // create the script
- if (info == null) {
- info = jexl.createInfo();
- }
- // allow lambda defining params
- script = jexl.parse(info.at(0, 0), strb.toString(), scope, false, false).script();
- scope = script.getScope();
- // createExpression the exprs using the code frame for those appearing after the first block of code
- for (int b = 0; b < blocks.size(); ++b) {
- Block block = blocks.get(b);
- if (block.type == BlockType.VERBATIM) {
- uexprs.add(parseExpression(info.at(block.line, 0), block.body, b > codeStart ? scope : null));
- }
- }
- source = blocks.toArray(new Block[blocks.size()]);
- exprs = uexprs.toArray(new TemplateExpression[uexprs.size()]);
- }
-
- /**
- * Private ctor used to expand deferred expressions during prepare.
- * @param thePrefix the directive prefix
- * @param theSource the source
- * @param theScript the script
- * @param theExprs the expressions
- */
- private TemplateScript(String thePrefix, Block[] theSource,
- ASTJexlScript theScript, TemplateExpression[] theExprs) {
- prefix = thePrefix;
- source = theSource;
- script = theScript;
- exprs = theExprs;
- }
-
- @Override
- public String toString() {
- StringBuilder strb = new StringBuilder();
- for (Block block : source) {
- block.toString(strb, prefix);
- }
- return strb.toString();
- }
-
- @Override
- public String asString() {
- StringBuilder strb = new StringBuilder();
- int e = 0;
- for (int b = 0; b < source.length; ++b) {
- Block block = source[b];
- if (block.type == BlockType.DIRECTIVE) {
- strb.append(prefix);
- } else {
- exprs[e++].asString(strb);
- }
- }
- return strb.toString();
- }
-
- @Override
- public TemplateScript prepare(JexlContext context) {
- Scope.Frame frame = script.createFrame((Object[]) null);
- TemplateContext tcontext = new TemplateContext(context, frame, exprs, null);
- TemplateExpression[] immediates = new TemplateExpression[exprs.length];
- for (int e = 0; e < exprs.length; ++e) {
- immediates[e] = exprs[e].prepare(frame, tcontext);
- }
- return new TemplateScript(prefix, source, script, immediates);
- }
-
- @Override
- public void evaluate(JexlContext context, Writer writer) {
- evaluate(context, writer, (Object[]) null);
- }
-
- @Override
- public void evaluate(JexlContext context, Writer writer, Object... args) {
- Scope.Frame frame = script.createFrame(args);
- TemplateContext tcontext = new TemplateContext(context, frame, exprs, writer);
- Interpreter interpreter = jexl.createInterpreter(tcontext, frame);
- interpreter.interpret(script);
- }
-
- @Override
- public Set<List<String>> getVariables() {
- VarCollector collector = new VarCollector();
- for (TemplateExpression expr : exprs) {
- expr.getVariables(collector);
- }
- return collector.collected();
- }
-
- @Override
- public String[] getParameters() {
- return script.getParameters();
- }
- }
/**
* The type of context to use during evaluation of templates.
@@ -1292,7 +1175,7 @@ public final class TemplateEngine extend
boolean eol = false;
try {
while ((c = reader.read()) >= 0) {
- if (eol && (c != '\n' && c != '\r')) {
+ if (eol) {// && (c != '\n' && c != '\r')) {
reader.reset();
break;
}
@@ -1405,7 +1288,6 @@ public final class TemplateEngine extend
@Override
public TemplateScript createTemplate(JexlInfo info, String prefix, Reader source, String... parms) {
- return new TemplateScript(info, prefix, source, parms);
+ return new TemplateScript(this, info, prefix, source, parms);
}
-
}
\ No newline at end of file
Added: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/TemplateScript.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/TemplateScript.java?rev=1698223&view=auto
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/TemplateScript.java (added)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/TemplateScript.java Thu Aug 27 20:00:20 2015
@@ -0,0 +1,213 @@
+/*
+ * 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.
+ */
+package org.apache.commons.jexl3.internal;
+
+import org.apache.commons.jexl3.JexlContext;
+import org.apache.commons.jexl3.JexlInfo;
+import org.apache.commons.jexl3.JxltEngine;
+import org.apache.commons.jexl3.internal.TemplateEngine.Block;
+import org.apache.commons.jexl3.internal.TemplateEngine.BlockType;
+import org.apache.commons.jexl3.internal.TemplateEngine.TemplateContext;
+import org.apache.commons.jexl3.internal.TemplateEngine.TemplateExpression;
+import org.apache.commons.jexl3.parser.ASTJexlScript;
+import java.io.Reader;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * A Template instance.
+ */
+public final class TemplateScript implements JxltEngine.Template {
+ /** The prefix marker. */
+ private final String prefix;
+ /** The array of source blocks. */
+ private final Block[] source;
+ /** The resulting script. */
+ private final ASTJexlScript script;
+ /** The TemplateEngine expressions called by the script. */
+ private final TemplateExpression[] exprs;
+ /** The engine. */
+ private final TemplateEngine jxlt;
+
+ /**
+ * Creates a new template from an character input.
+ * @param engine the template engine
+ * @param info the source info
+ * @param directive the prefix for lines of code; can not be "$", "${", "#" or "#{"
+ since this would preclude being able to differentiate directives and jxlt expressions
+ * @param reader the input reader
+ * @param parms the parameter names
+ * @throws NullPointerException if either the directive prefix or input is null
+ * @throws IllegalArgumentException if the directive prefix is invalid
+ */
+ public TemplateScript(TemplateEngine engine, JexlInfo info, String directive, Reader reader, String... parms) {
+ if (directive == null) {
+ throw new NullPointerException("null prefix");
+ }
+ if (Character.toString(engine.getImmediateChar()).equals(directive)
+ || (Character.toString(engine.getImmediateChar()) + "{").equals(directive)
+ || Character.toString(engine.getDeferredChar()).equals(directive)
+ || (Character.toString(engine.getDeferredChar()) + "{").equals(directive)) {
+ throw new IllegalArgumentException(directive + ": is not a valid directive pattern");
+ }
+ if (reader == null) {
+ throw new NullPointerException("null input");
+ }
+ this.jxlt = engine;
+ Scope scope = parms == null ? null : new Scope(null, parms);
+ prefix = directive;
+ List<Block> blocks = jxlt.readTemplate(prefix, reader);
+ List<TemplateExpression> uexprs = new ArrayList<TemplateExpression>();
+ StringBuilder strb = new StringBuilder();
+ int nuexpr = 0;
+ int codeStart = -1;
+ for (int b = 0; b < blocks.size(); ++b) {
+ Block block = blocks.get(b);
+ if (block.getType() == BlockType.VERBATIM) {
+ strb.append("jexl:print(");
+ strb.append(nuexpr++);
+ strb.append(");\n");
+ } else {
+ // keep track of first block of code, the frame creator
+ if (codeStart < 0) {
+ codeStart = b;
+ }
+ strb.append(block.getBody());
+ }
+ }
+ // create the script
+ if (info == null) {
+ info = jxlt.getEngine().createInfo();
+ }
+ // allow lambda defining params
+ script = jxlt.getEngine().parse(info.at(0, 0), strb.toString(), scope, false, false).script();
+ scope = script.getScope();
+ // create the exprs using the code frame for those appearing after the first block of code
+ for (int b = 0; b < blocks.size(); ++b) {
+ Block block = blocks.get(b);
+ if (block.getType() == BlockType.VERBATIM) {
+ uexprs.add(
+ jxlt.parseExpression(
+ info.at(block.getLine(), 0),
+ block.getBody(),
+ b > codeStart ? scope : null)
+ );
+ }
+ }
+ source = blocks.toArray(new Block[blocks.size()]);
+ exprs = uexprs.toArray(new TemplateExpression[uexprs.size()]);
+ }
+
+ /**
+ * Private ctor used to expand deferred expressions during prepare.
+ * @param engine the template engine
+ * @param thePrefix the directive prefix
+ * @param theSource the source
+ * @param theScript the script
+ * @param theExprs the expressions
+ */
+ TemplateScript(TemplateEngine engine,
+ String thePrefix,
+ Block[] theSource,
+ ASTJexlScript theScript,
+ TemplateExpression[] theExprs) {
+ jxlt = engine;
+ prefix = thePrefix;
+ source = theSource;
+ script = theScript;
+ exprs = theExprs;
+ }
+
+ /**
+ * @return script
+ */
+ ASTJexlScript getScript() {
+ return script;
+ }
+
+ /**
+ * @return exprs
+ */
+ TemplateExpression[] getExpressions() {
+ return exprs;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder strb = new StringBuilder();
+ for (Block block : source) {
+ block.toString(strb, prefix);
+ }
+ return strb.toString();
+ }
+
+ @Override
+ public String asString() {
+ StringBuilder strb = new StringBuilder();
+ int e = 0;
+ for (int b = 0; b < source.length; ++b) {
+ Block block = source[b];
+ if (block.getType() == BlockType.DIRECTIVE) {
+ strb.append(prefix);
+ } else {
+ exprs[e++].asString(strb);
+ }
+ }
+ return strb.toString();
+ }
+
+ @Override
+ public TemplateScript prepare(JexlContext context) {
+ Scope.Frame frame = script.createFrame((Object[]) null);
+ TemplateContext tcontext = jxlt.new TemplateContext(context, frame, exprs, null);
+ TemplateExpression[] immediates = new TemplateExpression[exprs.length];
+ for (int e = 0; e < exprs.length; ++e) {
+ immediates[e] = exprs[e].prepare(frame, tcontext);
+ }
+ return new TemplateScript(jxlt, prefix, source, script, immediates);
+ }
+
+ @Override
+ public void evaluate(JexlContext context, Writer writer) {
+ evaluate(context, writer, (Object[]) null);
+ }
+
+ @Override
+ public void evaluate(JexlContext context, Writer writer, Object... args) {
+ Scope.Frame frame = script.createFrame(args);
+ TemplateContext tcontext = jxlt.new TemplateContext(context, frame, exprs, writer);
+ Interpreter interpreter = jxlt.getEngine().createInterpreter(tcontext, frame);
+ interpreter.interpret(script);
+ }
+
+ @Override
+ public Set<List<String>> getVariables() {
+ Engine.VarCollector collector = new Engine.VarCollector();
+ for (TemplateExpression expr : exprs) {
+ expr.getVariables(collector);
+ }
+ return collector.collected();
+ }
+
+ @Override
+ public String[] getParameters() {
+ return script.getParameters();
+ }
+
+}
Propchange: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/TemplateScript.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArithmeticTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArithmeticTest.java?rev=1698223&r1=1698222&r2=1698223&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArithmeticTest.java (original)
+++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArithmeticTest.java Thu Aug 27 20:00:20 2015
@@ -449,7 +449,7 @@ public class ArithmeticTest extends Jexl
Object r1 = jexl.createExpression("463.0B + 0.1B").evaluate(jc);
Assert.assertEquals(java.math.BigDecimal.class, r1.getClass());
}
-
+
public void testMinusClass() throws Exception {
JexlEngine jexl = new JexlBuilder().create();
JexlContext jc = new MapContext();
@@ -928,6 +928,28 @@ public class ArithmeticTest extends Jexl
}
}
+ public class Callable173 {
+ public Object call(String... arg) {
+ return 42;
+ }
+ public Object call(Integer... arg) {
+ return arg[0] * arg[1];
+ }
+ }
+
+ @Test
+ public void testJexl173() throws Exception {
+ JexlEngine jexl = new JexlBuilder().create();
+ JexlContext jc = new MapContext();
+ Callable173 c173 = new Callable173();
+ JexlScript e = jexl.createScript( "c173(9, 6)", "c173" );
+ Object result = e.execute(jc, c173);
+ Assert.assertEquals(54, result);
+ e = jexl.createScript( "c173('fourty', 'two')", "c173" );
+ result = e.execute(jc, c173);
+ Assert.assertEquals(42, result);
+
+ }
public static class Arithmetic132 extends JexlArithmetic {
public Arithmetic132() {
Modified: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/IssuesTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/IssuesTest.java?rev=1698223&r1=1698222&r2=1698223&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/IssuesTest.java (original)
+++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/IssuesTest.java Thu Aug 27 20:00:20 2015
@@ -22,9 +22,7 @@ import java.math.MathContext;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.jexl3.internal.introspection.Uberspect;
-import org.apache.commons.jexl3.introspection.JexlMethod;
import java.io.File;
-import java.io.StringWriter;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;