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;