You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@freemarker.apache.org by dd...@apache.org on 2018/06/16 11:42:30 UTC
[1/3] freemarker git commit: Some ground work to support dialects
later. Added classes like Dialect and StaticallyLinkedNamespaceEntry,
but these are non-public for now, and just drafts,
and aren't actually used by the templates. The final ones will need
Repository: freemarker
Updated Branches:
refs/heads/3 056635cd6 -> e8e58ffa5
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/DefaultTemplateLanguage.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/DefaultTemplateLanguage.java b/freemarker-core/src/main/java/org/apache/freemarker/core/DefaultTemplateLanguage.java
index 644ab25..df61532 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/DefaultTemplateLanguage.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/DefaultTemplateLanguage.java
@@ -41,29 +41,37 @@ public final class DefaultTemplateLanguage extends TemplateLanguage {
* from the {@link Configuration} (or {@link TemplateConfiguration}). Avoid it, as it's problematic for tooling.
*/
public static final DefaultTemplateLanguage F3AC = new DefaultTemplateLanguage("f3ac", true,
+ DefaultDialect.INSTANCE,
null, null,
TagSyntax.ANGLE_BRACKET, InterpolationSyntax.DOLLAR);
public static final DefaultTemplateLanguage F3SC = new DefaultTemplateLanguage("f3sc", true,
+ DefaultDialect.INSTANCE,
null, null,
TagSyntax.SQUARE_BRACKET, InterpolationSyntax.SQUARE_BRACKET);
public static final DefaultTemplateLanguage F3AH = new DefaultTemplateLanguage("f3ah", true,
+ DefaultDialect.INSTANCE,
HTMLOutputFormat.INSTANCE, AutoEscapingPolicy.ENABLE_IF_DEFAULT,
TagSyntax.ANGLE_BRACKET, InterpolationSyntax.DOLLAR);
public static final DefaultTemplateLanguage F3AX = new DefaultTemplateLanguage("f3ax", true,
+ DefaultDialect.INSTANCE,
XMLOutputFormat.INSTANCE, AutoEscapingPolicy.ENABLE_IF_DEFAULT,
TagSyntax.ANGLE_BRACKET, InterpolationSyntax.DOLLAR);
public static final DefaultTemplateLanguage F3AU = new DefaultTemplateLanguage("f3au", true,
+ DefaultDialect.INSTANCE,
UndefinedOutputFormat.INSTANCE, AutoEscapingPolicy.ENABLE_IF_DEFAULT,
TagSyntax.ANGLE_BRACKET, InterpolationSyntax.DOLLAR);
public static final DefaultTemplateLanguage F3SH = new DefaultTemplateLanguage("f3sh", true,
+ DefaultDialect.INSTANCE,
HTMLOutputFormat.INSTANCE, AutoEscapingPolicy.ENABLE_IF_DEFAULT,
TagSyntax.SQUARE_BRACKET, InterpolationSyntax.SQUARE_BRACKET);
public static final DefaultTemplateLanguage F3SX = new DefaultTemplateLanguage("f3sx", true,
+ DefaultDialect.INSTANCE,
XMLOutputFormat.INSTANCE, AutoEscapingPolicy.ENABLE_IF_DEFAULT,
TagSyntax.SQUARE_BRACKET, InterpolationSyntax.SQUARE_BRACKET);
public static final DefaultTemplateLanguage F3SU = new DefaultTemplateLanguage("f3su", true,
+ DefaultDialect.INSTANCE,
UndefinedOutputFormat.INSTANCE, AutoEscapingPolicy.ENABLE_IF_DEFAULT,
TagSyntax.SQUARE_BRACKET, InterpolationSyntax.SQUARE_BRACKET);
@@ -81,11 +89,11 @@ public final class DefaultTemplateLanguage extends TemplateLanguage {
* call this yourself; use constants like {@link #F3AH} instead when possible.
*
* @param fileExtension
- * See in {@link TemplateLanguage#TemplateLanguage(String, OutputFormat, AutoEscapingPolicy)}
+ * See in {@link TemplateLanguage#TemplateLanguage(String, Dialect, OutputFormat, AutoEscapingPolicy)}
* @param outputFormat
- * See in {@link TemplateLanguage#TemplateLanguage(String, OutputFormat, AutoEscapingPolicy)}
+ * See in {@link TemplateLanguage#TemplateLanguage(String, Dialect, OutputFormat, AutoEscapingPolicy)}
* @param autoEscapingPolicy
- * See in {@link TemplateLanguage#TemplateLanguage(String, OutputFormat, AutoEscapingPolicy)}
+ * See in {@link TemplateLanguage#TemplateLanguage(String, Dialect, OutputFormat, AutoEscapingPolicy)}
* @param tagSyntax
* The tag syntax used; not {@code null}.
* @param interpolationSyntax
@@ -93,20 +101,21 @@ public final class DefaultTemplateLanguage extends TemplateLanguage {
*/
public DefaultTemplateLanguage(
String fileExtension,
+ Dialect dialect,
OutputFormat outputFormat, AutoEscapingPolicy autoEscapingPolicy,
TagSyntax tagSyntax, InterpolationSyntax interpolationSyntax) {
- this(fileExtension, false, outputFormat, autoEscapingPolicy, tagSyntax, interpolationSyntax);
+ this(fileExtension, false, dialect, outputFormat, autoEscapingPolicy, tagSyntax, interpolationSyntax);
}
/**
- * Used internally to allow extensions starting with "f"
+ * Used internally to allow extensions starting with "f" (as those are reserved for FreeMarker)
*/
DefaultTemplateLanguage(
- String fileExtension,
- boolean allowExtensionStartingWithF,
+ String fileExtension, boolean allowExtensionStartingWithF,
+ Dialect dialect,
OutputFormat outputFormat, AutoEscapingPolicy autoEscapingPolicy,
TagSyntax tagSyntax, InterpolationSyntax interpolationSyntax) {
- super(fileExtension, allowExtensionStartingWithF, outputFormat, autoEscapingPolicy);
+ super(fileExtension, allowExtensionStartingWithF, dialect, outputFormat, autoEscapingPolicy);
_NullArgumentException.check("tagSyntax", tagSyntax);
_NullArgumentException.check("interpolationSyntax", interpolationSyntax);
this.tagSyntax = tagSyntax;
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/Dialect.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/Dialect.java b/freemarker-core/src/main/java/org/apache/freemarker/core/Dialect.java
new file mode 100644
index 0000000..056bce5
--- /dev/null
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/Dialect.java
@@ -0,0 +1,127 @@
+/*
+ * 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.freemarker.core;
+
+/**
+ * A {@linkplain TemplateLanguage template language} dialect; specifies what predefined callables (like directives,
+ * built-ins) are available in the template language, but it doesn't specify the syntax. Unlike callables exposed to
+ * templates otherwise, callables that are part of the dialect use the same syntax as the callables traditionally
+ * predefined ones (like {@code <#if ...>}, {@code ?upperCase}", etc.), and they are linked statically (see
+ * {@link StaticallyLinkedNamespaceEntry} for the advantages).
+ *
+ * <p>
+ * A {@link Dialect} object is usually a static singleton. If you need internal state that's bound to a
+ * {@link Configuration} instance, you can do that in the {@link ConfiguredDialect} created by
+ * {@link Dialect#createConfiguredDialect(Configuration)} object.
+ *
+ * @see StaticallyLinkedNamespaceEntry
+ */
+//TODO [FM3] will be public. Also, then move it into core.dialect?
+abstract class Dialect {
+
+ private final String name;
+ private final Version version;
+
+ public Dialect(String name, Version version) {
+ this.name = name;
+ this.version = version;
+ }
+
+ /**
+ * The informal name of this dialect (maybe used in error messages)
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * The version number of this dialect (maybe used in error messages).
+ */
+ public Version getVersion() {
+ return version;
+ }
+
+ /**
+ * Creates a {@link ConfiguredDialect} object that's bound to the parameter {@link Configuration} object. FreeMarker
+ * calls this method of each {@link Dialect} that will be used with the {@link Configuration} when the
+ * {@link Configuration} object is constructed.
+ *
+ * @param cfg
+ * The fully initialized {@link Configuration}, except that some {@link Dialect}-s in it may not have an
+ * associated {@link ConfiguredDialect} yet. This {@link Configuration} is not yet "safely published"
+ * (see in the Java Memory Model), so it must not be exposed to other threads by this method.
+ *
+ * @throws ConfigurationException
+ * If any problem occurs, it should be wrapped into this.
+ */
+ public abstract ConfiguredDialect createConfiguredDialect(Configuration cfg) throws ConfigurationException;
+
+ /**
+ * A {@link Dialect} that is bound to a {@link Configuration}. While a dialect is in principle a static singleton,
+ * and so is independent of any particular {@link Configuration} object, some dialects may have internal state
+ * initialized depending on some {@link Configuration} settings.
+ *
+ * <p>
+ * Instances should be created by {@link Dialect#createConfiguredDialect(Configuration)}. The concrete
+ * {@link ConfiguredDialect} is usually private and is a nested class in the concrete {@link Dialect}, which
+ * overrides {@link Dialect#createConfiguredDialect(Configuration)} to return the concrete instance
+ *
+ * <p>
+ * The main function of a {@link ConfiguredDialect} is to expose the namespace of the dialect. The dialect namespace
+ * contains the entries that are statically linked, and can usually can be accessed without any namespace prefix (
+ * usually, as the exact details depend on the template language). For example, for the default dialect the
+ * namespace contains entries like "if", "list", "upperCase", and so on.
+ */
+ //TODO [FM3] will be public. Also, then move it into core.dialect?
+ abstract class ConfiguredDialect {
+
+ /**
+ * Returns a namespace entry of this dialect. or {@code null} if there's no match.
+ */
+ public abstract StaticallyLinkedNamespaceEntry getNamespaceEntry(String name);
+
+ /**
+ * To iterate through the namespace entries of this dialect.
+ */
+ public abstract Iterable<StaticallyLinkedNamespaceEntry> getNamespaceEntries();
+
+ /**
+ * Returns the {@link Dialect} whose {@link Dialect#createConfiguredDialect(Configuration)} method has created this
+ * instance.
+ */
+ public final Dialect getDialect() {
+ return Dialect.this;
+ }
+
+ }
+
+ // Final implementation, as {@link Dialect}-s maybe used as hash keys.
+ @Override
+ public final int hashCode() {
+ return super.hashCode();
+ }
+
+ // Final implementation, as {@link Dialect}-s maybe used as hash keys.
+ @Override
+ public final boolean equals(Object obj) {
+ return super.equals(obj);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/Environment.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/Environment.java b/freemarker-core/src/main/java/org/apache/freemarker/core/Environment.java
index 38a4f17..637901e 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/Environment.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/Environment.java
@@ -63,6 +63,8 @@ import org.apache.freemarker.core.model.TemplateNumberModel;
import org.apache.freemarker.core.model.TemplateSequenceModel;
import org.apache.freemarker.core.model.TemplateStringModel;
import org.apache.freemarker.core.model.impl.SimpleHash;
+import org.apache.freemarker.core.outputformat.MarkupOutputFormat;
+import org.apache.freemarker.core.outputformat.OutputFormat;
import org.apache.freemarker.core.templateresolver.MalformedTemplateNameException;
import org.apache.freemarker.core.templateresolver.TemplateResolver;
import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateNameFormat;
@@ -70,6 +72,7 @@ import org.apache.freemarker.core.util.CallableUtils;
import org.apache.freemarker.core.util.StringToIndexMap;
import org.apache.freemarker.core.util._DateUtils;
import org.apache.freemarker.core.util._DateUtils.DateToISO8601CalendarFactory;
+import org.apache.freemarker.core.util._NullArgumentException;
import org.apache.freemarker.core.util._NullWriter;
import org.apache.freemarker.core.util._StringUtils;
import org.apache.freemarker.core.valueformat.TemplateDateFormat;
@@ -280,7 +283,7 @@ public final class Environment extends MutableProcessingConfiguration<Environmen
clearCachedValues();
try {
doAutoImportsAndIncludes(this);
- visit(getMainTemplate().getRootASTNode());
+ executeElement(getMainTemplate().getRootASTNode());
// It's here as we must not flush if there was an exception.
if (getAutoFlush()) {
out.flush();
@@ -366,17 +369,18 @@ public final class Environment extends MutableProcessingConfiguration<Environmen
/**
* "Visit" the template element.
*/
- void visit(ASTElement element) throws IOException, TemplateException {
+ // TODO [FM3] will be public
+ void executeElement(ASTElement element) throws IOException, TemplateException {
// ATTENTION: This method body is manually "inlined" into visit(ASTElement[]); keep them in sync!
pushElement(element);
try {
- ASTElement[] templateElementsToVisit = element.accept(this);
+ ASTElement[] templateElementsToVisit = element.execute(this);
if (templateElementsToVisit != null) {
for (ASTElement el : templateElementsToVisit) {
if (el == null) {
break; // Skip unused trailing buffer capacity
}
- visit(el);
+ executeElement(el);
}
}
} catch (TemplateException te) {
@@ -386,12 +390,20 @@ public final class Environment extends MutableProcessingConfiguration<Environmen
}
// ATTENTION: This method body above is manually "inlined" into visit(ASTElement[]); keep them in sync!
}
+
+ // TODO [FM3] will be public
+ final void executeNestedContent(ASTDirective parentCall) throws IOException, TemplateException {
+ executeElements(parentCall.getChildBuffer());
+ }
/**
+ * Executes the elements passed in (which is usually the return value of {@link ASTElement#getChildBuffer()}).
+ *
* @param elementBuffer
* The elements to visit; might contains trailing {@code null}-s. Can be {@code null}.
*/
- final void visit(ASTElement[] elementBuffer) throws IOException, TemplateException {
+ // TODO [FM3] will be public
+ final void executeElements(ASTElement[] elementBuffer) throws IOException, TemplateException {
if (elementBuffer == null) {
return;
}
@@ -404,13 +416,13 @@ public final class Environment extends MutableProcessingConfiguration<Environmen
// We don't just let Hotspot to do it, as we want a hard guarantee regarding maximum stack usage.
pushElement(element);
try {
- ASTElement[] templateElementsToVisit = element.accept(this);
+ ASTElement[] templateElementsToVisit = element.execute(this);
if (templateElementsToVisit != null) {
for (ASTElement el : templateElementsToVisit) {
if (el == null) {
break; // Skip unused trailing buffer capacity
}
- visit(el);
+ executeElement(el);
}
}
} catch (TemplateException te) {
@@ -429,13 +441,27 @@ public final class Environment extends MutableProcessingConfiguration<Environmen
private static final TemplateModel[] NO_OUT_ARGS = new TemplateModel[0];
- void visit(
- ASTElement[] childBuffer,
- final StringToIndexMap nestedContentParamNames, final TemplateModel[] nestedContentParamValues,
- Writer out)
- throws IOException, TemplateException {
+ /**
+ * Executes the nested content of a {@link ASTDirective}.
+ *
+ * @param directiveCall
+ * This is the directive call AST node whose nested content we will execute.
+ * @param nestedContentParamNames
+ * The names of the nested content parameters as they were declared by the directive call. For example
+ * {@code code <#list m as k, v>...</#list>}, a call of the {@code list} directive, declares "k" at index
+ * 0, and "v" at index 1.
+ * @param nestedContentParamValues
+ * The actual values of the nested content parameters, which will be visible for the nested content as
+ * variables. The caller of this method <em>must</em> ensure that {@code nestedContentParamNames} doesn't
+ * return an index that's out of bounds in {@code nestedContentParamValues}!
+ */
+ // TODO [FM3] will be public
+ void executeNestedContent(
+ ASTDirective directiveCall,
+ final StringToIndexMap nestedContentParamNames, final TemplateModel[] nestedContentParamValues) throws IOException, TemplateException {
+ ASTElement[] childBuffer = directiveCall.getChildBuffer();
if (nestedContentParamNames == null) { // This is by far the most frequent case
- visit(childBuffer, out);
+ executeElements(childBuffer);
} else {
pushLocalContext(new LocalContext() {
@Override
@@ -450,24 +476,13 @@ public final class Environment extends MutableProcessingConfiguration<Environmen
}
});
try {
- visit(childBuffer, out);
+ executeElements(childBuffer);
} finally {
popLocalContext();
}
}
}
- void visit(ASTElement[] childBuffer, Writer out) throws IOException, TemplateException {
- // TODO [FM][CF] The plan is that `out` will be the root read only sink, so then it will work differently
- Writer prevOut = this.out;
- this.out = out;
- try {
- visit(childBuffer);
- } finally {
- this.out = prevOut;
- }
- }
-
/**
* Visit a block using buffering/recovery
*/
@@ -482,7 +497,7 @@ public final class Environment extends MutableProcessingConfiguration<Environmen
boolean lastInAttemptBlock = inAttemptBlock;
try {
inAttemptBlock = true;
- visit(attemptedSection);
+ executeElement(attemptedSection);
} catch (TemplateException te) {
thrownException = te;
} finally {
@@ -493,7 +508,7 @@ public final class Environment extends MutableProcessingConfiguration<Environmen
if (thrownException != null) {
try {
recoveredErrorStack.add(thrownException);
- visit(recoverySection);
+ executeElement(recoverySection);
} finally {
recoveredErrorStack.remove(recoveredErrorStack.size() - 1);
}
@@ -988,11 +1003,11 @@ public final class Environment extends MutableProcessingConfiguration<Environmen
return _EvalUtils.compare(leftValue, _EvalUtils.CMP_OP_GREATER_THAN_EQUALS, rightValue, this);
}
- public void setOut(Writer out) {
+ public final void setOut(Writer out) {
this.out = out;
}
- public Writer getOut() {
+ public final Writer getOut() {
return out;
}
@@ -1049,6 +1064,67 @@ public final class Environment extends MutableProcessingConfiguration<Environmen
return _EvalUtils.coerceModelToPlainText(tm, null, null, this);
}
+ /**
+ * Evaluates the expression and prints its value as if it was printed with an interpolation (like
+ * <code>${exp}</code>).
+ *
+ * @param outputFormat
+ * Acts like the output format in a template where an interpolation is called. Not {@code null}.
+ * @param autoEscapingPolicy
+ * Acts like the auto escaping policy in a template where an interpolation is called. Not {@code null}.
+ */
+ // TODO [FM3] will be public
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ void interpolate(
+ ASTExpression exp,
+ OutputFormat outputFormat, AutoEscapingPolicy autoEscapingPolicy,
+ Environment env) throws IOException, TemplateException {
+ interpolate(exp.eval(env), exp, outputFormat, autoEscapingPolicy, env);
+ }
+
+ /**
+ * Same as {@link #interpolate(ASTExpression, OutputFormat, AutoEscapingPolicy, Environment)}, but is used in the
+ * rare case where you have already evaluated the expression.
+ *
+ * @param value
+ * The value resulting from evaluating {@code exp}
+ * @param exp
+ * The expression whose evaluation was resulted in {@code value}. It won't be evaluated again, but is
+ * still used for error messages. {@code null} is tolerated, but should be avoided due to the resulting
+ * poorer quality error messages.
+ */
+ void interpolate(
+ TemplateModel value, ASTExpression exp,
+ OutputFormat outputFormat, AutoEscapingPolicy autoEscapingPolicy,
+ Environment env) throws IOException, TemplateException {
+ _NullArgumentException.check("outputFormat", outputFormat);
+ _NullArgumentException.check("autoEscapingPolicy", autoEscapingPolicy);
+
+ final Writer out = env.getOut();
+
+ final Object moOrStr = _EvalUtils.coerceModelToPlainTextOrMarkup(value, exp, null, env);
+ if (moOrStr instanceof String) {
+ final String s = (String) moOrStr;
+
+ MarkupOutputFormat markupOutputFormat;
+ if (outputFormat instanceof MarkupOutputFormat) {
+ markupOutputFormat = (MarkupOutputFormat) outputFormat;
+ if (autoEscapingPolicy == AutoEscapingPolicy.ENABLE_IF_SUPPORTED
+ || autoEscapingPolicy == AutoEscapingPolicy.ENABLE_IF_DEFAULT
+ && markupOutputFormat.isAutoEscapedByDefault()) {
+ markupOutputFormat.output(s, out);
+ } else {
+ out.write(s);
+ }
+ } else {
+ out.write(s);
+ }
+ } else {
+ final TemplateMarkupOutputModel mo = (TemplateMarkupOutputModel) moOrStr;
+ _EvalUtils.printTemplateMarkupOutputModel(mo, outputFormat, out, exp);
+ }
+ }
+
String formatBoolean(boolean value, boolean fallbackToTrueFalse) throws TemplateException {
TemplateBooleanFormat templateBooleanFormat = getTemplateBooleanFormat();
if (value) {
@@ -2135,7 +2211,7 @@ public final class Environment extends MutableProcessingConfiguration<Environmen
}
static void appendInstructionStackItem(ASTElement stackEl, StringBuilder sb) {
- sb.append(MessageUtils.shorten(stackEl.getDescription(), 40));
+ sb.append(MessageUtils.shorten(stackEl.getLabelWithParameters(), 40));
sb.append(" [");
ASTDirMacroOrFunction enclosingMacro = getEnclosingMacro(stackEl);
@@ -2286,7 +2362,7 @@ public final class Environment extends MutableProcessingConfiguration<Environmen
};
}
- private void pushElement(ASTElement element) {
+ void pushElement(ASTElement element) {
final int newSize = ++instructionStackSize;
ASTElement[] instructionStack = this.instructionStack;
if (newSize > instructionStack.length) {
@@ -2300,7 +2376,7 @@ public final class Environment extends MutableProcessingConfiguration<Environmen
instructionStack[newSize - 1] = element;
}
- private void popElement() {
+ void popElement() {
instructionStackSize--;
}
@@ -2481,7 +2557,7 @@ public final class Environment extends MutableProcessingConfiguration<Environmen
final Template prevTemplate;
importMacros(includedTemplate);
- visit(includedTemplate.getRootASTNode());
+ executeElement(includedTemplate.getRootASTNode());
}
/**
@@ -2976,7 +3052,7 @@ public final class Environment extends MutableProcessingConfiguration<Environmen
: callableDefinition.getName();
}
- protected void genericExecute(TemplateModel[] args, CallPlace callPlace, Writer out, Environment env)
+ protected void genericExecute(TemplateModel[] args, CallPlace callPlace, Environment env)
throws TemplateException, IOException {
pushElement(callableDefinition);
try {
@@ -2996,7 +3072,7 @@ public final class Environment extends MutableProcessingConfiguration<Environmen
// Note: Default expressions are evaluated here, so namespace, stack, etc. must be already set
setLocalsFromArguments(macroCtx, args);
- visit(callableDefinition.getChildBuffer(), out);
+ executeElements(callableDefinition.getChildBuffer());
} catch (ASTDirReturn.Return re) {
// Not an error, just a <#return>
} catch (TemplateException te) {
@@ -3079,7 +3155,14 @@ public final class Environment extends MutableProcessingConfiguration<Environmen
if (getCallableDefinition() == ASTDirMacroOrFunction.PASS_MACRO) {
return;
}
- genericExecute(args, callPlace, out, env);
+
+ Writer prevOut = env.getOut();
+ try {
+ env.setOut(out);
+ genericExecute(args, callPlace, env);
+ } finally {
+ env.setOut(prevOut);
+ }
}
@Override
@@ -3115,11 +3198,15 @@ public final class Environment extends MutableProcessingConfiguration<Environmen
public TemplateModel execute(TemplateModel[] args, CallPlace callPlace, Environment env)
throws TemplateException {
env.setLastReturnValue(null);
+ Writer prevOut = env.getOut();
try {
- genericExecute(args, callPlace, _NullWriter.INSTANCE, env);
+ env.setOut(_NullWriter.INSTANCE);
+ genericExecute(args, callPlace, env);
} catch (IOException e) {
// Should not occur
throw new TemplateException("Unexpected exception during function execution", e, env);
+ } finally {
+ env.setOut(prevOut);
}
return env.getLastReturnValue();
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/MessageUtils.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/MessageUtils.java b/freemarker-core/src/main/java/org/apache/freemarker/core/MessageUtils.java
index e79bed2..a139a0a 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/MessageUtils.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/MessageUtils.java
@@ -31,6 +31,7 @@ import org.apache.freemarker.core.model.TemplateNumberModel;
import org.apache.freemarker.core.model.TemplateSequenceModel;
import org.apache.freemarker.core.model.TemplateStringModel;
import org.apache.freemarker.core.util.BugException;
+import org.apache.freemarker.core.util.StringToIndexMap;
import org.apache.freemarker.core.util.TemplateLanguageUtils;
import org.apache.freemarker.core.util._StringUtils;
import org.apache.freemarker.core.valueformat.TemplateDateFormat;
@@ -146,6 +147,9 @@ class MessageUtils {
* The truncation is always signaled with a a {@code "..."} at the end of the result string.
*/
static String shorten(String s, int maxLength) {
+ if (s == null) {
+ return null;
+ }
if (maxLength < 5) maxLength = 5;
boolean isTruncated = false;
@@ -359,4 +363,19 @@ class MessageUtils {
return errorDescBuilder;
}
+ static _ErrorDescriptionBuilder newBadNumberOfNestedContentParameterPassedMessage(
+ StringToIndexMap paramNamesOnCallPlace,
+ int numberOfParamsAtCallee) {
+ int numberOfParamsAtCallPlace = paramNamesOnCallPlace != null ? paramNamesOnCallPlace.size() : 0;
+ return new _ErrorDescriptionBuilder(
+ "The invocation declares ", (numberOfParamsAtCallPlace != 0 ? numberOfParamsAtCallPlace : "no"),
+ " nested content parameter(s)",
+ (numberOfParamsAtCallPlace != 0
+ ? new Object[] { " (", new _DelayedJQuotedListing(paramNamesOnCallPlace.getKeys()), ")", }
+ : ""),
+ ", but the called object intends to pass ",
+ numberOfParamsAtCallee, " parameters. You need to declare ", numberOfParamsAtCallee,
+ " nested content parameters.");
+ }
+
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ParsingConfiguration.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ParsingConfiguration.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ParsingConfiguration.java
index 983c05d..f17b778 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ParsingConfiguration.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ParsingConfiguration.java
@@ -50,7 +50,10 @@ public interface ParsingConfiguration {
* {@link TemplateLanguage#getAutoEscapingPolicy() autoEscapingPolicy}, that overrides the value of
* the {@linkplain #getOutputFormat() outputFormat} and {@link #getAutoEscapingPolicy() autoEscapingPolicy}
* settings that are coming from {@link Configuration#getTemplateConfigurations templateConfigurations}, from the
- * {@link Configuration}, or from any other {@link ParsingConfiguration}.
+ * {@link Configuration}, or from any other {@link ParsingConfiguration}. Most {@link TemplateLanguage}-s should
+ * have non-{@code null} for those settings, to prevent confusion on the template author side. There can be
+ * exceptions from this though, like {@link DefaultTemplateLanguage#F3AC} (where the "C" at the end stands for
+ * "configurable") has {@code null} for these settings.
*
* @see ParsingConfiguration#getRecognizeStandardFileExtensions()
*/
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/StaticLinkingCheckException.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/StaticLinkingCheckException.java b/freemarker-core/src/main/java/org/apache/freemarker/core/StaticLinkingCheckException.java
new file mode 100644
index 0000000..50587b8
--- /dev/null
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/StaticLinkingCheckException.java
@@ -0,0 +1,74 @@
+/*
+ * 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.freemarker.core;
+
+import org.apache.freemarker.core.util._NullArgumentException;
+
+/**
+ * Exception thrown when a {@link Dialect} detects a problem during parsing (such a required parameter to a directive is
+ * missing). The exception will be converted to a {@link ParseException} by the parser, where the error message and
+ * cause exception will be the same as of the {@link StaticLinkingCheckException}.
+ */
+//TODO [FM3][DIALECTS] will be public
+@SuppressWarnings("serial")
+final class StaticLinkingCheckException extends Exception {
+
+ private final _ErrorDescriptionBuilder messageBuilder;
+ private String builtMessage;
+ private final String simpleMessage;
+
+ public StaticLinkingCheckException(_ErrorDescriptionBuilder messageBuilder) {
+ this(messageBuilder, null);
+ }
+
+ public StaticLinkingCheckException(_ErrorDescriptionBuilder messageBuilder, Throwable cause) {
+ _NullArgumentException.check("messageBuilder", messageBuilder);
+ this.messageBuilder = messageBuilder;
+ simpleMessage = null;
+ }
+
+ public StaticLinkingCheckException(String message) {
+ this(message, null);
+ }
+
+ public StaticLinkingCheckException(String message, Throwable cause) {
+ _NullArgumentException.check("message", message);
+ this.messageBuilder = null;
+ simpleMessage = message;
+ }
+
+ @Override
+ public String getMessage() {
+ if (simpleMessage != null) {
+ return simpleMessage;
+ }
+
+ String builtDescription = this.builtMessage;
+ if (builtDescription != null) {
+ return builtDescription;
+ }
+ synchronized (this) {
+ builtDescription = messageBuilder.toString();
+ this.builtMessage = builtDescription;
+ }
+ return builtDescription;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/StaticallyLinkedNamespaceEntry.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/StaticallyLinkedNamespaceEntry.java b/freemarker-core/src/main/java/org/apache/freemarker/core/StaticallyLinkedNamespaceEntry.java
new file mode 100644
index 0000000..87ba7f7
--- /dev/null
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/StaticallyLinkedNamespaceEntry.java
@@ -0,0 +1,117 @@
+package org.apache.freemarker.core;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.freemarker.core.model.TemplateCallableModel;
+import org.apache.freemarker.core.model.TemplateDirectiveModel;
+import org.apache.freemarker.core.model.TemplateFunctionModel;
+import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.util.CommonSupplier;
+import org.apache.freemarker.core.util._NullArgumentException;
+
+/**
+ * A template language namespace entry that's linked statically to the referring template (TODO [FM3] for planned
+ * Dialects feature, currently unused).
+ * Static linking allows detecting mistakes during template parsing (as opposed to during the later template
+ * processing), can make accessing the value faster (by avoiding runtime lookup), and allows callables to have
+ * parse-time effects. Currently used in {@link Dialect}.
+ */
+//TODO [FM3][FREEMARKER-99][DIALECTS] will be public. Also move it into core.dialect?
+final class StaticallyLinkedNamespaceEntry {
+
+ private final String name;
+ private final TemplateModel value;
+ private final CommonSupplier<ASTDirective> directiveCallNodeFactory;
+ private final CommonSupplier<ASTExpFunctionCall> functionCallNodeFactory;
+
+ /**
+ * @param name
+ * Variable name in the namespace of the dialect
+ * @param value
+ * The runtime value of the entry. Not {@code null}.
+ * If this entry is a {@link TemplateCallableModel} that's not callable dynamically (as it has
+ * parse-time effects or such dependencies), then the corresponding {@code execute} method should to
+ * throw exception explaining that, but the {@link TemplateCallableModel} will be still used by the
+ * parser to retrieve meta-data such as
+ * {@link TemplateDirectiveModel#getDirectiveArgumentArrayLayout()},
+ * {@link TemplateDirectiveModel#isNestedContentSupported()},
+ * {@link TemplateFunctionModel#getFunctionArgumentArrayLayout()}.
+ * @param directiveCallNodeFactory
+ * If this entry is usable as directive, the factory for the corresponding {@linkplain ASTNode AST node}.
+ * At least one of {@code directiveCallNodeFactory} and {@code functionCallNodeFactory} must be
+ * non-{@code null}. It must be ensured that the behavior of this node is consistent with argument array
+ * layout and other meta-data present in the entry {@code value}.
+ * @param functionCallNodeFactory
+ * If this entry is usable as function (or like an FM2 "built-in"), the factory for the corresponding
+ * {@linkplain ASTNode AST node}. Not {@code null}. It must be ensured that the behavior of this node is consistent with argument array
+ * layout and other meta-data present in the entry {@code value}.
+ */
+ public StaticallyLinkedNamespaceEntry(
+ String name, TemplateModel value,
+ CommonSupplier<ASTDirective> directiveCallNodeFactory,
+ CommonSupplier<ASTExpFunctionCall> functionCallNodeFactory) {
+ _NullArgumentException.check("name", name);
+ this.name = name;
+ if (directiveCallNodeFactory == null && functionCallNodeFactory == null) {
+ throw new IllegalArgumentException(
+ "At least one of \"directiveCallNodeFactory\" and \"functionCallNodeFactory\" must be non-null.");
+ }
+ this.directiveCallNodeFactory = directiveCallNodeFactory;
+ this.functionCallNodeFactory = functionCallNodeFactory;
+ this.value = value;
+ }
+
+ /**
+ * See similarly named
+ * {@linkplain #StaticallyLinkedNamespaceEntry(String, TemplateModel, CommonSupplier, CommonSupplier) constructor}
+ * parameter.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * See similarly named
+ * {@linkplain #StaticallyLinkedNamespaceEntry(String, TemplateModel, CommonSupplier, CommonSupplier) constructor}
+ * parameter.
+ */
+ public CommonSupplier<ASTDirective> getDirectiveCallNodeFactory() {
+ return directiveCallNodeFactory;
+ }
+
+ /**
+ * See similarly named
+ * {@linkplain #StaticallyLinkedNamespaceEntry(String, TemplateModel, CommonSupplier, CommonSupplier) constructor}
+ * parameter.
+ */
+ public CommonSupplier<ASTExpFunctionCall> getFunctionCallNodeFactory() {
+ return functionCallNodeFactory;
+ }
+
+ /**
+ * See similarly named
+ * {@linkplain #StaticallyLinkedNamespaceEntry(String, TemplateModel, CommonSupplier, CommonSupplier) constructor}
+ * parameter.
+ */
+ public TemplateModel getValue() {
+ return value;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/Template.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/Template.java b/freemarker-core/src/main/java/org/apache/freemarker/core/Template.java
index 42e2686..c184281 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/Template.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/Template.java
@@ -122,7 +122,7 @@ public class Template implements ProcessingConfiguration, CustomStateScope {
private AutoEscapingPolicy autoEscapingPolicy;
// Values from template content that are detected automatically:
private Charset actualSourceEncoding;
- TagSyntax actualTagSyntax; // TODO [FM3][CF] Should be private
+ TagSyntax actualTagSyntax; // TODO [FM3][FREEMARKER-99] Should be private
private InterpolationSyntax interpolationSyntax;
// Custom state:
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/TemplateConfiguration.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/TemplateConfiguration.java b/freemarker-core/src/main/java/org/apache/freemarker/core/TemplateConfiguration.java
index 8627059..1b1b9a9 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/TemplateConfiguration.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/TemplateConfiguration.java
@@ -36,10 +36,11 @@ import org.apache.freemarker.core.valueformat.TemplateNumberFormatFactory;
/**
* A partial set of configuration settings used for customizing the {@link Configuration}-level settings for individual
* {@link Template}-s (or rather, for a group of templates). That it's partial means that you should call the
- * corresponding {@code isXxxSet()} before getting a settings, or else you may cause
- * {@link CoreSettingValueNotSetException}. (There's no fallback to the {@link Configuration}-level settings to keep the
- * dependency graph of configuration related beans non-cyclic. As user code seldom reads settings directly from
- * {@link TemplateConfiguration}-s anyway, this compromise was chosen.)
+ * corresponding {@code isXxxSet()} before getting a setting, or else you may cause
+ * {@link CoreSettingValueNotSetException}. (There's no fallback to the {@link Configuration}-level settings implemented
+ * in this class, to keep the dependency graph of configuration related beans non-cyclic. Instead, the caller of this
+ * API must implement the fallback itself. As user code hardly ever reads directly from {@link TemplateConfiguration}-s,
+ * this compromise was chosen.)
* <p>
* Note on the {@code locale} setting: When used with the standard template loading/caching mechanism ({@link
* Configuration#getTemplate(String)} and its overloads), localized template lookup happens before the {@code locale}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/TemplateElementArrayBuilder.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/TemplateElementArrayBuilder.java b/freemarker-core/src/main/java/org/apache/freemarker/core/TemplateElementArrayBuilder.java
index 4bc9a4f..734622e 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/TemplateElementArrayBuilder.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/TemplateElementArrayBuilder.java
@@ -83,18 +83,5 @@ class TemplateElements {
}
}
}
-
- /**
- * Used for some backward compatibility hacks.
- */
- ASTImplicitParent asMixedContent() {
- ASTImplicitParent mixedContent = new ASTImplicitParent();
- if (count != 0) {
- ASTElement first = buffer[0];
- mixedContent.setChildren(this);
- mixedContent.setLocation(first.getTemplate(), first, getLast());
- }
- return mixedContent;
- }
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/TemplateElementsToVisit.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/TemplateElementsToVisit.java b/freemarker-core/src/main/java/org/apache/freemarker/core/TemplateElementsToVisit.java
index 145916c..defcf5d 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/TemplateElementsToVisit.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/TemplateElementsToVisit.java
@@ -22,9 +22,9 @@ import java.util.Collection;
import java.util.Collections;
/**
- * Used as the return value of {@link ASTElement#accept(Environment)} when the invoked element has nested elements
+ * Used as the return value of {@link ASTElement#execute(Environment)} when the invoked element has nested elements
* to invoke. It would be more natural to invoke child elements before returning from
- * {@link ASTElement#accept(Environment)}, however, if there's nothing to do after the child elements were invoked,
+ * {@link ASTElement#execute(Environment)}, however, if there's nothing to do after the child elements were invoked,
* that would mean wasting stack space.
*/
class TemplateElementsToVisit {
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/TemplateLanguage.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/TemplateLanguage.java b/freemarker-core/src/main/java/org/apache/freemarker/core/TemplateLanguage.java
index 3b1a812..98002c9 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/TemplateLanguage.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/TemplateLanguage.java
@@ -29,9 +29,8 @@ import org.apache.freemarker.core.util._NullArgumentException;
import org.apache.freemarker.core.util._StringUtils;
/**
- * Represents a template language; a template language specifies the syntax, and usually also the {@link OutputFormat}
- * and {@link AutoEscapingPolicy} of the template. In the future (TODO [FM3]) custom template languages may also
- * specify the dialect (which is the set of core directives and functions).
+ * Represents a template language; a template language specifies the syntax, the {@link Dialect}, and usually also the
+ * {@link OutputFormat} and {@link AutoEscapingPolicy}.
*
* <p><em>Currently this class is not mature, so it can't be implemented outside FreeMarker,
* also its methods shouldn't be called from outside FreeMarker.</em>
@@ -48,6 +47,7 @@ public abstract class TemplateLanguage {
private final String fileExtension;
private final OutputFormat outputFormat;
private final AutoEscapingPolicy autoEscapingPolicy;
+ private final Dialect dialect;
// Package visibility to prevent user implementations until this API is mature.
@@ -70,14 +70,14 @@ public abstract class TemplateLanguage {
* If the {@code #fileExtension} argument contains upper case letter or dot, or if it starts with "f"
* and the language isn't defined by the FreeMarker project.
*/
- public TemplateLanguage(String fileExtension, OutputFormat outputFormat, AutoEscapingPolicy autoEscapingPolicy) {
- this(fileExtension, false, outputFormat, autoEscapingPolicy);
+ public TemplateLanguage(String fileExtension, Dialect dialect, OutputFormat outputFormat, AutoEscapingPolicy autoEscapingPolicy) {
+ this(fileExtension, false, dialect, outputFormat, autoEscapingPolicy);
}
/**
- * Non-public constructor used for languages defined by the FreeMarker project.
+ * Used internally to allow extensions starting with "f" (as those are reserved for FreeMarker)
*/
- TemplateLanguage(String fileExtension, boolean allowExtensionStartingWithF,
+ TemplateLanguage(String fileExtension, boolean allowExtensionStartingWithF, Dialect dialect,
OutputFormat outputFormat, AutoEscapingPolicy autoEscapingPolicy) {
_NullArgumentException.check("fileExtension", fileExtension);
for (int i = 0; i < fileExtension.length(); i++) {
@@ -94,6 +94,10 @@ public abstract class TemplateLanguage {
"The \"fileExtension\" argument can't start with 'f' for an user-defined language.");
}
this.fileExtension = fileExtension;
+
+ _NullArgumentException.check("dialect", dialect);
+ this.dialect = dialect;
+
this.outputFormat = outputFormat;
this.autoEscapingPolicy = autoEscapingPolicy;
}
@@ -123,13 +127,15 @@ public abstract class TemplateLanguage {
public String getFileExtension() {
return fileExtension;
}
-
- @Override
- public final String toString() {
- return "TemplateLanguage(" + _StringUtils.jQuote(fileExtension) + ")";
- }
/**
+ * Returns the {@link Dialect} used by this template language; not {@code null}.
+ */
+ public Dialect getDialect() {
+ return dialect;
+ }
+
+ /**
* The {@link OutputFormat} that this language enforces, or else {@code null} (and it comes from the
* {@link ParsingConfiguration}).
*
@@ -151,4 +157,9 @@ public abstract class TemplateLanguage {
return autoEscapingPolicy;
}
+ @Override
+ public final String toString() {
+ return "TemplateLanguage(" + _StringUtils.jQuote(fileExtension) + ")";
+ }
+
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ThreadInterruptionSupportTemplatePostProcessor.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ThreadInterruptionSupportTemplatePostProcessor.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ThreadInterruptionSupportTemplatePostProcessor.java
index be7877c..874a896 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ThreadInterruptionSupportTemplatePostProcessor.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ThreadInterruptionSupportTemplatePostProcessor.java
@@ -56,7 +56,7 @@ class ThreadInterruptionSupportTemplatePostProcessor extends TemplatePostProcess
final int childCount = te.getChildCount();
for (int i = 0; i < childCount; i++) {
- addInterruptionChecks(te.getChild(i));
+ addInterruptionChecks(te.fastGetChild(i));
}
if (te.isNestedBlockRepeater()) {
@@ -79,7 +79,7 @@ class ThreadInterruptionSupportTemplatePostProcessor extends TemplatePostProcess
}
@Override
- ASTElement[] accept(Environment env) throws TemplateException, IOException {
+ ASTElement[] execute(Environment env) throws TemplateException, IOException {
// As the API doesn't allow throwing InterruptedException here (nor anywhere else, most importantly,
// Template.process can't throw it), we must not clear the "interrupted" flag of the thread.
if (Thread.currentThread().isInterrupted()) {
@@ -89,12 +89,12 @@ class ThreadInterruptionSupportTemplatePostProcessor extends TemplatePostProcess
}
@Override
- protected String dump(boolean canonical) {
- return canonical ? "" : "<#--" + getASTNodeDescriptor() + "--#>";
+ String dump(boolean canonical) {
+ return canonical ? "" : "<#--" + getLabelWithoutParameters() + "--#>";
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return "##threadInterruptionCheck";
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/UnparsedTemplateLanguage.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/UnparsedTemplateLanguage.java b/freemarker-core/src/main/java/org/apache/freemarker/core/UnparsedTemplateLanguage.java
index 2119ee3..6fe58f5 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/UnparsedTemplateLanguage.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/UnparsedTemplateLanguage.java
@@ -45,7 +45,8 @@ public final class UnparsedTemplateLanguage extends TemplateLanguage {
private UnparsedTemplateLanguage(String fileExtension, boolean allowExtensionStartingWithF,
OutputFormat outputFormat) {
- super(fileExtension, allowExtensionStartingWithF, outputFormat, AutoEscapingPolicy.ENABLE_IF_DEFAULT);
+ super(fileExtension, allowExtensionStartingWithF, DefaultDialect.INSTANCE,
+ outputFormat, AutoEscapingPolicy.ENABLE_IF_DEFAULT);
}
/**
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/UnsupportedFM2TemplateLanguage.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/UnsupportedFM2TemplateLanguage.java b/freemarker-core/src/main/java/org/apache/freemarker/core/UnsupportedFM2TemplateLanguage.java
index 158a35a..e67091d 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/UnsupportedFM2TemplateLanguage.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/UnsupportedFM2TemplateLanguage.java
@@ -41,7 +41,7 @@ class UnsupportedFM2TemplateLanguage extends TemplateLanguage {
private UnsupportedFM2TemplateLanguage(String fileExtension, OutputFormat outputFormat,
AutoEscapingPolicy autoEscapingPolicy) {
- super(fileExtension, true, outputFormat, autoEscapingPolicy);
+ super(fileExtension, true, DefaultDialect.INSTANCE, outputFormat, autoEscapingPolicy);
}
@Override
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/_CallableUtils.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/_CallableUtils.java b/freemarker-core/src/main/java/org/apache/freemarker/core/_CallableUtils.java
index 542a2f2..a4132c0 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/_CallableUtils.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/_CallableUtils.java
@@ -57,7 +57,7 @@ public class _CallableUtils {
throws TemplateException {
if (namedArgs != null) {
throw new TemplateException(env,
- getNamedArgumentsNotSupportedMessage(callable, namedArgs[0], calledAsFunction));
+ getNamedArgumentsNotSupportedMessage(callable, namedArgs[0].name, calledAsFunction));
}
TemplateModel[] execArgs;
@@ -77,8 +77,8 @@ public class _CallableUtils {
ASTExpression[] positionalArgs, NamedArgument[] namedArgs, ArgumentArrayLayout argsLayout,
TemplateCallableModel callable, boolean calledAsFunction,
Environment env) throws TemplateException {
- int predefPosArgCnt = argsLayout.getPredefinedPositionalArgumentCount();
- int posVarargsArgIdx = argsLayout.getPositionalVarargsArgumentIndex();
+ final int predefPosArgCnt = argsLayout.getPredefinedPositionalArgumentCount();
+ final int posVarargsArgIdx = argsLayout.getPositionalVarargsArgumentIndex();
TemplateModel[] execArgs = new TemplateModel[argsLayout.getTotalLength()];
@@ -104,44 +104,14 @@ public class _CallableUtils {
}
execArgs[posVarargsArgIdx] = varargsSeq;
} else if (positionalArgs != null && positionalArgs.length > predefPosArgCnt) {
- checkSupportsAnyParameters(callable, argsLayout, calledAsFunction);
- List<String> validPredefNames = argsLayout.getPredefinedNamedArgumentsMap().getKeys();
- _ErrorDescriptionBuilder errorDesc = new _ErrorDescriptionBuilder(
- getMessagePartWhenCallingSomethingColon(callable, calledAsFunction),
- "This ", getCallableTypeName(callable, calledAsFunction),
- " ",
- (predefPosArgCnt != 0
- ? new Object[]{ "can only have ", predefPosArgCnt }
- : "can't have"
- ),
- " arguments passed by position, but the invocation has ",
- positionalArgs.length, " such arguments.",
- (!argsLayout.isPositionalParametersSupported() && argsLayout.isNamedParametersSupported() ?
- new Object[] {
- " Try to pass arguments by name (as in ",
- (callable instanceof TemplateDirectiveModel
- ? "<@example x=1 y=2 />"
- : "example(x=1, y=2)"),
- ")",
- (!validPredefNames.isEmpty()
- ? new Object[] { " The supported parameter names are: ",
- new _DelayedJQuotedListing(validPredefNames)}
- : _CollectionUtils.EMPTY_OBJECT_ARRAY)}
- : "")
- );
- if (callable instanceof Environment.TemplateLanguageDirective
- && !argsLayout.isPositionalParametersSupported() && argsLayout.isNamedParametersSupported()) {
- errorDesc.tip("You can pass a parameter by position (i.e., without specifying its name, as you"
- + " have tried now) when the macro has defined that parameter to be a positional parameter. "
- + "See in the documentation how, and when that's a good practice.");
- }
- throw new TemplateException(env, errorDesc);
+ throw new TemplateException(env,
+ newPositionalArgDoesNotFitArgLayoutErrorDesc(argsLayout, callable, calledAsFunction));
}
int namedVarargsArgumentIndex = argsLayout.getNamedVarargsArgumentIndex();
NativeHashEx namedVarargsHash = null;
if (namedArgs != null) {
- StringToIndexMap predefNamedArgsMap = argsLayout.getPredefinedNamedArgumentsMap();
+ final StringToIndexMap predefNamedArgsMap = argsLayout.getPredefinedNamedArgumentsMap();
for (NamedArgument namedArg : namedArgs) {
int argIdx = predefNamedArgsMap.get(namedArg.name);
if (argIdx != -1) {
@@ -149,20 +119,9 @@ public class _CallableUtils {
} else {
if (namedVarargsHash == null) {
if (namedVarargsArgumentIndex == -1) {
- checkSupportsAnyParameters(callable, argsLayout, calledAsFunction);
- Collection<String> validNames = predefNamedArgsMap.getKeys();
throw new TemplateException(env,
- validNames == null || validNames.isEmpty()
- ? getNamedArgumentsNotSupportedMessage(
- callable, namedArg, calledAsFunction)
- : new Object[] {
- getMessagePartWhenCallingSomethingColon(callable, calledAsFunction),
- "This ", getCallableTypeName(callable, calledAsFunction),
- " has no parameter that's passed by name and is called ",
- new _DelayedJQuote(namedArg.name),
- ". The supported parameter names are:\n",
- new _DelayedJQuotedListing(validNames)
- });
+ newNamedArgumentDoesNotArgLayoutErrorDesc(
+ argsLayout, namedArg.name, callable, calledAsFunction));
}
namedVarargsHash = new NativeHashEx();
@@ -177,13 +136,88 @@ public class _CallableUtils {
return execArgs;
}
+ static _ErrorDescriptionBuilder newPositionalArgDoesNotFitArgLayoutErrorDesc(
+ ArgumentArrayLayout argsLayout, TemplateCallableModel callable, boolean calledAsFunction) {
+ _ErrorDescriptionBuilder noParamsED = checkSupportsAnyParameters(callable, argsLayout, calledAsFunction);
+ if (noParamsED != null) {
+ return noParamsED;
+ }
+
+ List<String> validPredefNames;
+ _ErrorDescriptionBuilder errorDesc = new _ErrorDescriptionBuilder(
+ getMessagePartWhenCallingSomethingColon(callable, calledAsFunction),
+ "This ", getCallableTypeName(callable, calledAsFunction),
+ " ",
+ (argsLayout.getPredefinedPositionalArgumentCount() != 0
+ ? new Object[]{ "can only have ", argsLayout.getPredefinedPositionalArgumentCount() }
+ : "can't have"
+ ),
+ " arguments passed by position, but the invocation tries to pass in more.",
+ (!argsLayout.isPositionalParametersSupported() && argsLayout.isNamedParametersSupported() ?
+ new Object[] {
+ " Try to pass arguments by name (as in ",
+ (callable instanceof TemplateDirectiveModel
+ ? "<@example x=1 y=2 />"
+ : "example(x=1, y=2)"),
+ ")",
+ (!(validPredefNames = argsLayout.getPredefinedNamedArgumentsMap().getKeys())
+ .isEmpty()
+ ? new Object[] {
+ " The supported parameter names are: ",
+ new _DelayedJQuotedListing(validPredefNames)
+ }
+ : _CollectionUtils.EMPTY_OBJECT_ARRAY)}
+ : "")
+ );
+ if (callable instanceof Environment.TemplateLanguageDirective
+ && !argsLayout.isPositionalParametersSupported() && argsLayout.isNamedParametersSupported()) {
+ errorDesc.tip("You can pass a parameter by position (i.e., without specifying its name, as you"
+ + " have tried now) when the directuve (the macro) has defined that parameter to be a "
+ + "positional parameter. See in the documentation how, and when that's a good practice.");
+ }
+ return errorDesc;
+ }
+
+ static _ErrorDescriptionBuilder newNamedArgumentDoesNotArgLayoutErrorDesc(ArgumentArrayLayout argsLayout,
+ String argName, TemplateCallableModel callable, boolean calledAsFunction) {
+ _ErrorDescriptionBuilder noParamsED = checkSupportsAnyParameters(callable, argsLayout, calledAsFunction);
+ if (noParamsED != null) {
+ return noParamsED;
+ }
+
+ Collection<String> validNames = argsLayout.getPredefinedNamedArgumentsMap().getKeys();
+ _ErrorDescriptionBuilder errorDesc = new _ErrorDescriptionBuilder(
+ validNames == null || validNames.isEmpty()
+ ? getNamedArgumentsNotSupportedMessage(
+ callable, argName, calledAsFunction)
+ : new Object[] {
+ getMessagePartWhenCallingSomethingColon(callable, calledAsFunction),
+ "This ", getCallableTypeName(callable, calledAsFunction),
+ " has no parameter that's passed by name and is called ",
+ new _DelayedJQuote(argName),
+ ". The supported parameter names are:\n",
+ new _DelayedJQuotedListing(validNames)
+ });
+ return errorDesc;
+ }
+
+ static private _ErrorDescriptionBuilder checkSupportsAnyParameters(
+ TemplateCallableModel callable, ArgumentArrayLayout argsLayout, boolean calledAsFunction) {
+ return argsLayout.getTotalLength() == 0
+ ? new _ErrorDescriptionBuilder(
+ getMessagePartWhenCallingSomethingColon(callable, calledAsFunction),
+ "This ", getCallableTypeName(callable, calledAsFunction),
+ " doesn't support any parameters.")
+ : null;
+ }
+
private static Object[] getNamedArgumentsNotSupportedMessage(TemplateCallableModel callable,
- _CallableUtils.NamedArgument namedArg, boolean calledAsFunction) {
+ String argName, boolean calledAsFunction) {
return new Object[] {
getMessagePartWhenCallingSomethingColon(callable, calledAsFunction),
"This ", getCallableTypeName(callable, calledAsFunction),
" can't have arguments that are passed by name (like ",
- new _DelayedJQuote(namedArg.name), "). Try to pass arguments by position "
+ new _DelayedJQuote(argName), "). Try to pass arguments by position "
+ "(i.e, without name, as in ",
(callable instanceof TemplateDirectiveModel
? "<@example arg1, arg2, arg3 />"
@@ -192,17 +226,6 @@ public class _CallableUtils {
};
}
- static private void checkSupportsAnyParameters(
- TemplateCallableModel callable, ArgumentArrayLayout argsLayout, boolean calledAsFunction)
- throws TemplateException {
- if (argsLayout.getTotalLength() == 0) {
- throw new TemplateException(
- getMessagePartWhenCallingSomethingColon(callable, calledAsFunction),
- "This ", getCallableTypeName(callable, calledAsFunction),
- " doesn't support any parameters.");
- }
- }
-
/**
* Something like {@code "When calling function \"lib.f3ah:foo\": " or "When calling ?leftPad: "}
*/
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/_Debug.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/_Debug.java b/freemarker-core/src/main/java/org/apache/freemarker/core/_Debug.java
index e15374b..c94e369 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/_Debug.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/_Debug.java
@@ -19,7 +19,6 @@
package org.apache.freemarker.core;
import java.util.ArrayList;
-import java.util.Enumeration;
import java.util.List;
/**
@@ -42,7 +41,7 @@ public final class _Debug {
// TODO: Ensure there always is a parent by making sure
// that the root element in the template is always a ASTImplicitParent
// Also make sure it doesn't conflict with anyone's code.
- parent.setChildAt(parent.getIndex(te), db);
+ parent.setChildAt(indexOfChild(parent, te), db);
}
public static void removeDebugBreak(Template t, int line) {
@@ -62,7 +61,16 @@ public final class _Debug {
return;
}
ASTElement parent = db.getParent();
- parent.setChildAt(parent.getIndex(db), db.getChild(0));
+ parent.setChildAt(indexOfChild(parent, db), db.fastGetChild(0));
+ }
+
+ private static final int indexOfChild(ASTElement parent, ASTElement node) {
+ for (int i = 0; i < parent.getChildCount(); i++) {
+ if (parent.getChild(i) == node) {
+ return i;
+ }
+ }
+ return -1;
}
private static ASTElement findTemplateElement(ASTElement te, int line) {
@@ -70,9 +78,8 @@ public final class _Debug {
return null;
}
// Find the narrowest match
- List childMatches = new ArrayList();
- for (Enumeration children = te.children(); children.hasMoreElements(); ) {
- ASTElement child = (ASTElement) children.nextElement();
+ List<ASTElement> childMatches = new ArrayList<>();
+ for (ASTElement child : te.getChildren()) {
ASTElement childmatch = findTemplateElement(child, line);
if (childmatch != null) {
childMatches.add(childmatch);
@@ -81,7 +88,7 @@ public final class _Debug {
//find a match that exactly matches the begin/end line
ASTElement bestMatch = null;
for (int i = 0; i < childMatches.size(); i++) {
- ASTElement e = (ASTElement) childMatches.get(i);
+ ASTElement e = childMatches.get(i);
if ( bestMatch == null ) {
bestMatch = e;
@@ -110,9 +117,9 @@ public final class _Debug {
private static void removeDebugBreaks(ASTElement te) {
int count = te.getChildCount();
for (int i = 0; i < count; ++i) {
- ASTElement child = te.getChild(i);
+ ASTElement child = te.fastGetChild(i);
while (child instanceof ASTDebugBreak) {
- ASTElement dbchild = child.getChild(0);
+ ASTElement dbchild = child.fastGetChild(0);
te.setChildAt(i, dbchild);
child = dbchild;
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/_ErrorDescriptionBuilder.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/_ErrorDescriptionBuilder.java b/freemarker-core/src/main/java/org/apache/freemarker/core/_ErrorDescriptionBuilder.java
index 7d96e3d..f00da1a 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/_ErrorDescriptionBuilder.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/_ErrorDescriptionBuilder.java
@@ -35,6 +35,7 @@ import org.slf4j.LoggerFactory;
* Note that this class isn't serializable, thus the containing exception should render the message before it's
* serialized.
*/
+//TODO [FM3] will be public
public class _ErrorDescriptionBuilder {
private static final Logger LOG = LoggerFactory.getLogger(_ErrorDescriptionBuilder.class);
@@ -77,7 +78,7 @@ public class _ErrorDescriptionBuilder {
Blaming blaming = findBlaming(parentElement, blamed, 0);
if (blaming != null) {
sb.append("For ");
- String nss = blaming.blamer.getASTNodeDescriptor();
+ String nss = blaming.blamer.getLabelWithoutParameters();
char q = nss.indexOf('"') == -1 ? '\"' : '`';
sb.append(q).append(nss).append(q);
sb.append(" ").append(blaming.roleOfblamed).append(": ");
@@ -117,7 +118,8 @@ public class _ErrorDescriptionBuilder {
}
sb.append(" [");
- sb.append(blamed.getStartLocation());
+ sb.append(MessageUtils.formatLocationForEvaluationError(
+ blamed.getTemplate(), blamed.getBeginLine(), blamed.getEndLine()));
sb.append(']');
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/_EvalUtils.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/_EvalUtils.java b/freemarker-core/src/main/java/org/apache/freemarker/core/_EvalUtils.java
index 525ed82..150bb6e 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/_EvalUtils.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/_EvalUtils.java
@@ -21,6 +21,8 @@ package org.apache.freemarker.core;
import static org.apache.freemarker.core.MessageUtils.*;
+import java.io.IOException;
+import java.io.Writer;
import java.util.Date;
import org.apache.freemarker.core.arithmetic.ArithmeticEngine;
@@ -33,6 +35,7 @@ import org.apache.freemarker.core.model.TemplateModel;
import org.apache.freemarker.core.model.TemplateNumberModel;
import org.apache.freemarker.core.model.TemplateStringModel;
import org.apache.freemarker.core.outputformat.MarkupOutputFormat;
+import org.apache.freemarker.core.outputformat.OutputFormat;
import org.apache.freemarker.core.util.BugException;
import org.apache.freemarker.core.util._ClassUtils;
import org.apache.freemarker.core.valueformat.TemplateDateFormat;
@@ -338,6 +341,9 @@ public class _EvalUtils {
*
* @param seqTip
* Tip to display if the value type is not coercable, but it's iterable.
+ * @param exp
+ * The expression that was evaluated to {@code tm}. This can be {@code null}, however that may results
+ * in poor quality error messages.
*
* @return Never {@code null}
*/
@@ -540,5 +546,29 @@ public class _EvalUtils {
? env.getArithmeticEngine()
: tObj.getTemplate().getParsingConfiguration().getArithmeticEngine();
}
+
+ public static void printTemplateMarkupOutputModel(final TemplateMarkupOutputModel mo, OutputFormat outputFormat,
+ final Writer out, ASTExpression exp) throws TemplateException, IOException {
+ final MarkupOutputFormat moOF = mo.getOutputFormat();
+ // ATTENTION: Keep this logic in sync. ?esc/?noEsc's logic!
+ if (moOF != outputFormat && !outputFormat.isOutputFormatMixingAllowed()) {
+ final String srcPlainText;
+ // ATTENTION: Keep this logic in sync. ?esc/?noEsc's logic!
+ srcPlainText = moOF.getSourcePlainText(mo);
+ if (srcPlainText == null) {
+ throw new TemplateException(exp,
+ "The value to print is in ", new _DelayedToString(moOF),
+ " format, which differs from the current output format, ",
+ new _DelayedToString(outputFormat), ". Format conversion wasn't possible.");
+ }
+ if (outputFormat instanceof MarkupOutputFormat) {
+ ((MarkupOutputFormat) outputFormat).output(srcPlainText, out);
+ } else {
+ out.write(srcPlainText);
+ }
+ } else {
+ moOF.output(mo, out);
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/util/_ArrayAdapterList.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/util/_ArrayAdapterList.java b/freemarker-core/src/main/java/org/apache/freemarker/core/util/_ArrayAdapterList.java
index b653f7f..95c06bc 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/util/_ArrayAdapterList.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/util/_ArrayAdapterList.java
@@ -51,7 +51,7 @@ public class _ArrayAdapterList<E> extends AbstractList<E> {
@Override
public Iterator<E> iterator() {
- return new _ArrayIterator(array);
+ return new _ArrayIterator<E>(array);
}
@Override
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/util/_ArrayEnumeration.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/util/_ArrayEnumeration.java b/freemarker-core/src/main/java/org/apache/freemarker/core/util/_ArrayEnumeration.java
deleted file mode 100644
index 1c82658..0000000
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/util/_ArrayEnumeration.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 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.freemarker.core.util;
-
-import java.util.Enumeration;
-import java.util.NoSuchElementException;
-
-/** Don't use this; used internally by FreeMarker, might changes without notice. */
-public class _ArrayEnumeration implements Enumeration {
-
- private final Object[] array;
- private final int size;
- private int nextIndex;
-
- public _ArrayEnumeration(Object[] array, int size) {
- this.array = array;
- this.size = size;
- nextIndex = 0;
- }
-
- @Override
- public boolean hasMoreElements() {
- return nextIndex < size;
- }
-
- @Override
- public Object nextElement() {
- if (nextIndex >= size) {
- throw new NoSuchElementException();
- }
- return array[nextIndex++];
- }
-
-}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/util/_ArrayIterator.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/util/_ArrayIterator.java b/freemarker-core/src/main/java/org/apache/freemarker/core/util/_ArrayIterator.java
index 7e02449..0ff9241 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/util/_ArrayIterator.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/util/_ArrayIterator.java
@@ -23,12 +23,12 @@ import java.util.Iterator;
import java.util.NoSuchElementException;
/** Don't use this; used internally by FreeMarker, might changes without notice. */
-public class _ArrayIterator implements Iterator {
+public class _ArrayIterator<T> implements Iterator<T> {
- private final Object[] array;
+ private final T[] array;
private int nextIndex;
- public _ArrayIterator(Object[] array) {
+ public _ArrayIterator(T[] array) {
this.array = array;
nextIndex = 0;
}
@@ -39,7 +39,7 @@ public class _ArrayIterator implements Iterator {
}
@Override
- public Object next() {
+ public T next() {
if (nextIndex >= array.length) {
throw new NoSuchElementException();
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/util/_NullArgumentException.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/util/_NullArgumentException.java b/freemarker-core/src/main/java/org/apache/freemarker/core/util/_NullArgumentException.java
index 4e7f777..d9cdad9 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/util/_NullArgumentException.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/util/_NullArgumentException.java
@@ -22,6 +22,7 @@ package org.apache.freemarker.core.util;
/**
* Indicates that an argument that must be non-{@code null} was {@code null}.
*/
+@SuppressWarnings("serial")
public class _NullArgumentException extends IllegalArgumentException {
public _NullArgumentException() {
@@ -46,6 +47,7 @@ public class _NullArgumentException extends IllegalArgumentException {
}
/**
+ * Convenience method to protect against a {@code null} argument.
*/
public static void check(Object argumentValue) {
if (argumentValue == null) {
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/javacc/FTL.jj
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/javacc/FTL.jj b/freemarker-core/src/main/javacc/FTL.jj
index aff3750..11e7ed2 100644
--- a/freemarker-core/src/main/javacc/FTL.jj
+++ b/freemarker-core/src/main/javacc/FTL.jj
@@ -30,6 +30,7 @@ PARSER_BEGIN(FMParser)
package org.apache.freemarker.core;
import org.apache.freemarker.core.*;
+import org.apache.freemarker.core.Dialect.ConfiguredDialect;
import org.apache.freemarker.core.outputformat.*;
import org.apache.freemarker.core.outputformat.impl.*;
import org.apache.freemarker.core.model.*;
@@ -84,6 +85,7 @@ public class FMParser {
private boolean autoEscaping;
private ParsingConfiguration pCfg;
DefaultTemplateLanguage templateLanguage;
+ ConfiguredDialect configuredDialect;
private InputStream streamToUnmarkWhenEncEstabd;
/** Keeps track of #list nesting. */
@@ -113,6 +115,7 @@ public class FMParser {
private StringToIndexMap.Entry[] topNestedContentParamNamesBuffer;
private int topNestedContentParamNamesLength;
+
FMParser(Template template, Reader reader,
ParsingConfiguration pCfg,
InputStream streamToUnmarkWhenEncEstabd) {
@@ -143,6 +146,7 @@ public class FMParser {
token_source.incompatibleImprovements = incompatibleImprovements;
this.incompatibleImprovements = incompatibleImprovements;
+ // We know that it's a DefaultTemplateLanguage, as this is the parser of the DefaultTemplateLanguage.
templateLanguage = (DefaultTemplateLanguage) pCfg.getTemplateLanguage();
outputFormat = pCfg.getOutputFormat();
@@ -165,6 +169,8 @@ public class FMParser {
token_source.interpolationSyntax = templateLanguage.getInterpolationSyntax();
this.stripWhitespace = pCfg.getWhitespaceStripping();
+
+ configuredDialect = template.getConfiguration().getConfiguredDialect(templateLanguage.getDialect());
}
void setupStringLiteralMode(FMParserTokenManager parentTokenSource, OutputFormat outputFormat) {
@@ -3315,7 +3321,7 @@ ASTElement DynamicTopLevelCall() :
)
|
(
- // This could be part of the positional paramter choice, but we can give better error messages this way.
+ // This could be part of the positional parameter choice, but we can give better error messages this way.
t = <COMMA>
{
if (prevChoiceComma != null) {
[2/3] freemarker git commit: Some ground work to support dialects
later. Added classes like Dialect and StaticallyLinkedNamespaceEntry,
but these are non-public for now, and just drafts,
and aren't actually used by the templates. The final ones will need
Posted by dd...@apache.org.
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirSep.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirSep.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirSep.java
index 9482f9c..1624732 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirSep.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirSep.java
@@ -32,12 +32,12 @@ class ASTDirSep extends ASTDirective {
}
@Override
- ASTElement[] accept(Environment env) throws TemplateException, IOException {
+ ASTElement[] execute(Environment env) throws TemplateException, IOException {
final IterationContext iterCtx = ASTDirList.findEnclosingIterationContext(env, null);
if (iterCtx == null) {
// The parser should prevent this situation
throw new TemplateException(env,
- getASTNodeDescriptor(), " without iteration in context");
+ getLabelWithoutParameters(), " without iteration in context");
}
if (iterCtx.hasNext()) {
@@ -52,22 +52,22 @@ class ASTDirSep extends ASTDirective {
}
@Override
- protected String dump(boolean canonical) {
+ String dump(boolean canonical) {
StringBuilder sb = new StringBuilder();
if (canonical) sb.append('<');
- sb.append(getASTNodeDescriptor());
+ sb.append(getLabelWithoutParameters());
if (canonical) {
sb.append('>');
sb.append(getChildrenCanonicalForm());
sb.append("</");
- sb.append(getASTNodeDescriptor());
+ sb.append(getLabelWithoutParameters());
sb.append('>');
}
return sb.toString();
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return "#sep";
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirSetting.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirSetting.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirSetting.java
index 953fa7f..9d76aef 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirSetting.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirSetting.java
@@ -104,7 +104,7 @@ final class ASTDirSetting extends ASTDirective {
}
@Override
- ASTElement[] accept(Environment env) throws TemplateException {
+ ASTElement[] execute(Environment env) throws TemplateException {
TemplateModel mval = value.eval(env);
String strval;
if (mval instanceof TemplateStringModel) {
@@ -125,10 +125,10 @@ final class ASTDirSetting extends ASTDirective {
}
@Override
- protected String dump(boolean canonical) {
+ String dump(boolean canonical) {
StringBuilder sb = new StringBuilder();
if (canonical) sb.append('<');
- sb.append(getASTNodeDescriptor());
+ sb.append(getLabelWithoutParameters());
sb.append(' ');
sb.append(_StringUtils.toFTLTopLevelTragetIdentifier(key));
sb.append('=');
@@ -138,7 +138,7 @@ final class ASTDirSetting extends ASTDirective {
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return "#setting";
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirStop.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirStop.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirStop.java
index bef9654..dcee928 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirStop.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirStop.java
@@ -31,7 +31,7 @@ final class ASTDirStop extends ASTDirective {
}
@Override
- ASTElement[] accept(Environment env) throws TemplateException {
+ ASTElement[] execute(Environment env) throws TemplateException {
if (exp == null) {
throw new StopException(env);
}
@@ -39,10 +39,10 @@ final class ASTDirStop extends ASTDirective {
}
@Override
- protected String dump(boolean canonical) {
+ String dump(boolean canonical) {
StringBuilder sb = new StringBuilder();
if (canonical) sb.append('<');
- sb.append(getASTNodeDescriptor());
+ sb.append(getLabelWithoutParameters());
if (exp != null) {
sb.append(' ');
sb.append(exp.getCanonicalForm());
@@ -52,7 +52,7 @@ final class ASTDirStop extends ASTDirective {
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return "#stop";
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirSwitch.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirSwitch.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirSwitch.java
index 296dd48..909e88d 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirSwitch.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirSwitch.java
@@ -39,7 +39,7 @@ final class ASTDirSwitch extends ASTDirective {
int ignoredCnt = ignoredSectionBeforeFirstCase != null ? ignoredSectionBeforeFirstCase.getChildCount() : 0;
setChildBufferCapacity(ignoredCnt + 4);
for (int i = 0; i < ignoredCnt; i++) {
- addChild(ignoredSectionBeforeFirstCase.getChild(i));
+ addChild(ignoredSectionBeforeFirstCase.fastGetChild(i));
}
firstCaseIndex = ignoredCnt; // Note that normally postParseCleanup will overwrite this
}
@@ -52,13 +52,13 @@ final class ASTDirSwitch extends ASTDirective {
}
@Override
- ASTElement[] accept(Environment env)
+ ASTElement[] execute(Environment env)
throws TemplateException, IOException {
boolean processedCase = false;
int ln = getChildCount();
try {
for (int i = firstCaseIndex; i < ln; i++) {
- ASTDirCase cas = (ASTDirCase) getChild(i);
+ ASTDirCase cas = (ASTDirCase) fastGetChild(i);
boolean processCase = false;
// Fall through if a previous case tested true.
@@ -71,7 +71,7 @@ final class ASTDirSwitch extends ASTDirective {
_EvalUtils.CMP_OP_EQUALS, "case==", cas.condition, cas.condition, env);
}
if (processCase) {
- env.visit(cas);
+ env.executeElement(cas);
processedCase = true;
}
}
@@ -79,7 +79,7 @@ final class ASTDirSwitch extends ASTDirective {
// If we didn't process any nestedElements, and we have a default,
// process it.
if (!processedCase && defaultCase != null) {
- env.visit(defaultCase);
+ env.executeElement(defaultCase);
}
} catch (BreakOrContinueException br) {
// #break was called
@@ -88,25 +88,25 @@ final class ASTDirSwitch extends ASTDirective {
}
@Override
- protected String dump(boolean canonical) {
+ String dump(boolean canonical) {
StringBuilder buf = new StringBuilder();
if (canonical) buf.append('<');
- buf.append(getASTNodeDescriptor());
+ buf.append(getLabelWithoutParameters());
buf.append(' ');
buf.append(searched.getCanonicalForm());
if (canonical) {
buf.append('>');
int ln = getChildCount();
for (int i = 0; i < ln; i++) {
- buf.append(getChild(i).getCanonicalForm());
+ buf.append(fastGetChild(i).getCanonicalForm());
}
- buf.append("</").append(getASTNodeDescriptor()).append('>');
+ buf.append("</").append(getLabelWithoutParameters()).append('>');
}
return buf.toString();
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return "#switch";
}
@@ -139,7 +139,7 @@ final class ASTDirSwitch extends ASTDirective {
// The first #case might have shifted in the child array, so we have to find it again:
int ln = getChildCount();
int i = 0;
- while (i < ln && !(getChild(i) instanceof ASTDirCase)) {
+ while (i < ln && !(fastGetChild(i) instanceof ASTDirCase)) {
i++;
}
firstCaseIndex = i;
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirTOrRtOrLtOrNt.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirTOrRtOrLtOrNt.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirTOrRtOrLtOrNt.java
index 5b79e30..102d1c9 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirTOrRtOrLtOrNt.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirTOrRtOrLtOrNt.java
@@ -37,22 +37,22 @@ final class ASTDirTOrRtOrLtOrNt extends ASTDirective {
}
@Override
- ASTElement[] accept(Environment env) {
+ ASTElement[] execute(Environment env) {
// This instruction does nothing at render-time, only parse-time.
return null;
}
@Override
- protected String dump(boolean canonical) {
+ String dump(boolean canonical) {
StringBuilder sb = new StringBuilder();
if (canonical) sb.append('<');
- sb.append(getASTNodeDescriptor());
+ sb.append(getLabelWithoutParameters());
if (canonical) sb.append("/>");
return sb.toString();
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
if (left && right) {
return "#t";
} else if (left) {
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirVisit.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirVisit.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirVisit.java
index d2a6e4d..181bb00 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirVisit.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirVisit.java
@@ -40,7 +40,7 @@ final class ASTDirVisit extends ASTDirective {
}
@Override
- ASTElement[] accept(Environment env) throws IOException, TemplateException {
+ ASTElement[] execute(Environment env) throws IOException, TemplateException {
TemplateModel node = targetNode.eval(env);
if (!(node instanceof TemplateNodeModel)) {
throw MessageUtils.newUnexpectedOperandTypeException(targetNode, node, TemplateNodeModel.class, env);
@@ -72,10 +72,10 @@ final class ASTDirVisit extends ASTDirective {
}
@Override
- protected String dump(boolean canonical) {
+ String dump(boolean canonical) {
StringBuilder sb = new StringBuilder();
if (canonical) sb.append('<');
- sb.append(getASTNodeDescriptor());
+ sb.append(getLabelWithoutParameters());
sb.append(' ');
sb.append(targetNode.getCanonicalForm());
if (namespaces != null) {
@@ -87,7 +87,7 @@ final class ASTDirVisit extends ASTDirective {
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return "#visit";
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirective.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirective.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirective.java
index 6015376..40cdc90 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirective.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirective.java
@@ -22,9 +22,13 @@ import java.util.Collections;
import java.util.Set;
import java.util.TreeSet;
+import org.apache.freemarker.core.util.StringToIndexMap;
+
/**
* AST directive node superclass.
+ * Concrete instances are normally created using {@link StaticallyLinkedNamespaceEntry#getDirectiveCallNodeFactory()}/
*/
+// TODO [FM3] will be public
abstract class ASTDirective extends ASTElement {
static final Set<String> BUILT_IN_DIRECTIVE_NAMES;
@@ -75,5 +79,64 @@ abstract class ASTDirective extends ASTElement {
BUILT_IN_DIRECTIVE_NAMES = Collections.unmodifiableSet(names);
}
+
+ /**
+ * Called by the parser to when it has parsed a parameter value expression for a positional parameter.
+ *
+ * <p>
+ * It's guaranteed that either {@link #setPositionalArgument(int, ASTExpression)} or
+ * {@link #setNamedArgument(String, ASTExpression)} is called for each parameter in the source code exactly once, in
+ * the order as the corresponding parameters occur in the source code. (While {@link DefaultTemplateLanguage}
+ * guarantees that positional parameters are before the named parameters, other {@link TemplateLanguage}-s may don't
+ * have such restriction.)
+ *
+ * @param position
+ * The 0-based position of the parameter among the positional parameters.
+ */
+ public void setPositionalArgument(int position, ASTExpression valueExp)
+ throws StaticLinkingCheckException {
+ // TODO [FM3][FREEMARKER-99] Will be abstract
+ }
+
+ /**
+ * Called by the parser when it has parsed a parameter expression.
+ *
+ * <p>See guarantees regarding the call order and the number of calls in the description of
+ * {@link #setPositionalArgument(int, ASTExpression)}.
+ */
+ public void setNamedArgument(String name, ASTExpression valueExp)
+ throws StaticLinkingCheckException {
+ // TODO [FM3][FREEMARKER-99] Will be abstract
+ }
+
+ /**
+ * Called by the parser when it has already passed in all arguments (via
+ * {@link #setPositionalArgument(int, ASTExpression)} and such). This allows the directive to check if all required
+ * arguments were provided, and some more. It also sets the nested content parameter names (like {@code "i", "j"} in
+ * {@code <#list m as i, j>}). (These two operations are packed into this method together as optimization, though
+ * admittedly the gain is very small.)
+ *
+ * @param nestedContentParamNames
+ * Will be {@code null} exactly if there are 0 nested content parameters.
+ */
+ public void checkArgumentsAndSetNestedContentParameters(StringToIndexMap nestedContentParamNames)
+ throws StaticLinkingCheckException {
+ // TODO [FM3][FREEMARKER-99] Will be abstract
+ }
+
+ /**
+ * Tells if this directive can have nested content; the parser may need this information.
+ */
+ public boolean isNestedContentSupported() {
+ // TODO [FM3][FREEMARKER-99] Will be abstract
+ return true;
+ }
+
+ /**
+ * @return {@code null} if there was no nested content parameter
+ */
+ public StringToIndexMap getNestedContentParamNames() {
+ return null;
+ }
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDynamicTopLevelCall.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDynamicTopLevelCall.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDynamicTopLevelCall.java
index dd8394f..a84460f 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDynamicTopLevelCall.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDynamicTopLevelCall.java
@@ -83,7 +83,7 @@ class ASTDynamicTopLevelCall extends ASTDirective implements CallPlace {
}
@Override
- ASTElement[] accept(Environment env) throws TemplateException, IOException {
+ ASTElement[] execute(Environment env) throws TemplateException, IOException {
TemplateCallableModel callableValue;
TemplateDirectiveModel directive;
TemplateFunctionModel function;
@@ -157,7 +157,7 @@ class ASTDynamicTopLevelCall extends ASTDirective implements CallPlace {
}
@Override
- protected String dump(boolean canonical) {
+ String dump(boolean canonical) {
StringBuilder sb = new StringBuilder();
if (canonical) sb.append('<');
sb.append('@');
@@ -211,7 +211,7 @@ class ASTDynamicTopLevelCall extends ASTDirective implements CallPlace {
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return "@";
}
@@ -286,7 +286,7 @@ class ASTDynamicTopLevelCall extends ASTDirective implements CallPlace {
@Override
public boolean hasNestedContent() {
int childCount = getChildCount();
- return childCount != 0 && (childCount > 1 || !(getChild(0) instanceof ASTThreadInterruptionCheck));
+ return childCount != 0 && (childCount > 1 || !(fastGetChild(0) instanceof ASTThreadInterruptionCheck));
}
@Override
@@ -301,16 +301,16 @@ class ASTDynamicTopLevelCall extends ASTDirective implements CallPlace {
int nestedContentParamValuesSize = nestedContentArgs != null ? nestedContentArgs.length : 0;
if (nestedContentParamValuesSize != nestedContentParamNamesSize) {
throw new TemplateException(env,
- "The invocation declares ", (nestedContentParamNamesSize != 0 ? nestedContentParamNamesSize : "no"),
- " nested content parameter(s)",
- (nestedContentParamNamesSize != 0
- ? new Object[] { " (", new _DelayedJQuotedListing(nestedContentParamNames.getKeys()), ")", }
- : ""),
- ", but the called object intends to pass ",
- nestedContentParamValuesSize, " parameters. You need to declare ", nestedContentParamValuesSize,
- " nested content parameters.");
+ MessageUtils.newBadNumberOfNestedContentParameterPassedMessage(
+ nestedContentParamNames, nestedContentParamValuesSize));
+ }
+ Writer prevOut = env.getOut();
+ try {
+ env.setOut(out);
+ env.executeNestedContent(this, nestedContentParamNames, nestedContentArgs);
+ } finally {
+ env.setOut(prevOut);
}
- env.visit(getChildBuffer(), nestedContentParamNames, nestedContentArgs, out);
}
@Override
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTElement.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTElement.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTElement.java
index 5bc68e0..5309177 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTElement.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTElement.java
@@ -21,14 +21,14 @@ package org.apache.freemarker.core;
import java.io.IOException;
import java.util.Collections;
-import java.util.Enumeration;
-
-import org.apache.freemarker.core.util._ArrayEnumeration;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
/**
* AST non-expression node superclass: Superclass of directive calls, interpolations, static text, top-level comments,
* or other such non-expression node in the parsed template.
*/
+//TODO [FM3] will be public
abstract class ASTElement extends ASTNode {
private static final int INITIAL_CHILD_BUFFER_CAPACITY = 6;
@@ -51,10 +51,13 @@ abstract class ASTElement extends ASTNode {
* The index of the element in the parent's {@link #childBuffer} array.
*/
private int index;
+
+ // Package visible constructor to prevent instantiating outside FreeMarker
+ ASTElement() { }
/**
* Executes this {@link ASTElement}. Usually should not be called directly, but through
- * {@link Environment#visit(ASTElement)} or a similar {@link Environment} method.
+ * {@link Environment#executeElement(ASTElement)} or a similar {@link Environment} method.
*
* @param env
* The runtime environment
@@ -64,42 +67,32 @@ abstract class ASTElement extends ASTNode {
* executing them inside this method is a trick used for decreasing stack usage when there's nothing to do
* after the children was processed anyway.
*/
- abstract ASTElement[] accept(Environment env) throws TemplateException, IOException;
+ abstract ASTElement[] execute(Environment env) throws TemplateException, IOException;
/**
- * One-line description of the element, that contain all the information that is used in {@link #getCanonicalForm()}
- * , except the nested content (elements) of the element. The expressions inside the element (the parameters) has to
- * be shown. Meant to be used for stack traces, also for tree views that don't go down to the expression-level.
- * There are no backward-compatibility guarantees regarding the format used ATM, but it must be regular enough to be
- * machine-parseable, and it must contain all information necessary for restoring an AST equivalent to the original.
- *
- * This final implementation calls {@link #dump(boolean) dump(false)}.
+ * Single line description of the element, which contain information about what kind of element it is, what are its
+ * parameters, but doesn't contain the child nodes. Meant to be used for stack traces, also for tree views (that
+ * don't want to show the parameters as spearate nodes). There are no backward-compatibility guarantees regarding
+ * the format used at the moment.
*
+ * @see #getLabelWithoutParameters()
* @see #getCanonicalForm()
- * @see #getASTNodeDescriptor()
*/
- public final String getDescription() {
+ public final String getLabelWithParameters() {
return dump(false);
}
- /**
- * This final implementation calls {@link #dump(boolean) dump(false)}.
- */
@Override
public final String getCanonicalForm() {
return dump(true);
}
final String getChildrenCanonicalForm() {
- return getChildrenCanonicalForm(childBuffer);
- }
-
- static String getChildrenCanonicalForm(ASTElement[] children) {
- if (children == null) {
+ if (childBuffer == null) {
return "";
}
StringBuilder sb = new StringBuilder();
- for (ASTElement child : children) {
+ for (ASTElement child : childBuffer) {
if (child == null) {
break;
}
@@ -107,7 +100,7 @@ abstract class ASTElement extends ASTNode {
}
return sb.toString();
}
-
+
/**
* Tells if the element should show up in error stack traces. Note that this will be ignored for the top (current)
* element of a stack trace, as that's always shown.
@@ -125,53 +118,51 @@ abstract class ASTElement extends ASTNode {
abstract boolean isNestedBlockRepeater();
/**
- * Brings the implementation of {@link #getCanonicalForm()} and {@link #getDescription()} to a single place. Don't
+ * Brings the implementation of {@link #getCanonicalForm()} and {@link #getLabelWithParameters()} to a single place. Don't
* call those methods in method on {@code this}, because that will result in infinite recursion!
*
* @param canonical
* if {@code true}, it calculates the return value of {@link #getCanonicalForm()}, otherwise of
- * {@link #getDescription()}.
+ * {@link #getLabelWithParameters()}.
*/
- abstract protected String dump(boolean canonical);
-
- // Methods to implement TemplateNodeModel
-
- public String getNodeName() {
- String className = getClass().getName();
- int shortNameOffset = className.lastIndexOf('.') + 1;
- return className.substring(shortNameOffset);
- }
-
- // Methods so that we can implement the Swing TreeNode API.
-
- public boolean isLeaf() {
- return childCount == 0;
- }
+ abstract String dump(boolean canonical);
- public int getIndex(ASTElement node) {
- for (int i = 0; i < childCount; i++) {
- if (childBuffer[i].equals(node)) {
- return i;
+ /**
+ * Note: For element with {@code #nested}, this will hide the {@code #nested} when that's an
+ * {@link ASTImplicitParent}.
+ */
+ public final Iterable<ASTElement> getChildren() {
+ return childBuffer != null ? new Iterable<ASTElement>() {
+ @Override
+ public Iterator<ASTElement> iterator() {
+ return new _ChildIterator();
}
- }
- return -1;
+ } : Collections.<ASTElement>emptyList();
}
- public int getChildCount() {
+ public final int getChildCount() {
return childCount;
}
/**
- * Note: For element with {@code #nestedBlock}, this will hide the {@code #nestedBlock} when that's a
- * {@link ASTImplicitParent}.
+ * Return the child node at the given index.
+ *
+ * @throws IndexOutOfBoundsException
+ * if the index is out of range, such as not less than {@link #getChildCount()}.
*/
- public Enumeration children() {
- return childBuffer != null
- ? new _ArrayEnumeration(childBuffer, childCount)
- : Collections.enumeration(Collections.EMPTY_LIST);
+ public final ASTElement getChild(int index) {
+ if (index >= childCount) {
+ throw new IndexOutOfBoundsException("Index " + index + " is out of bounds. There are " + childCount
+ + " child node(s).");
+ }
+ return fastGetChild(index);
+ }
+
+ final ASTElement fastGetChild(int index) {
+ return childBuffer[index];
}
- public void setChildAt(int index, ASTElement element) {
+ final void setChildAt(int index, ASTElement element) {
if (index < childCount && index >= 0) {
childBuffer[index] = element;
element.index = index;
@@ -230,11 +221,7 @@ abstract class ASTElement extends ASTNode {
lChildBuffer[index] = nestedElement;
childCount = lChildCount + 1;
}
-
- final ASTElement getChild(int index) {
- return childBuffer[index];
- }
-
+
/**
* @return Array containing 1 or more nested elements with optional trailing {@code null}-s, or is {@code null}
* exactly if there are no nested elements.
@@ -386,7 +373,8 @@ abstract class ASTElement extends ASTNode {
private ASTElement getFirstLeaf() {
ASTElement te = this;
- while (!te.isLeaf() && !(te instanceof ASTDirMacroOrFunction) && !(te instanceof ASTDirCapturingAssignment)) {
+ while (te.getChildCount() != 0 && !(te instanceof ASTDirMacroOrFunction)
+ && !(te instanceof ASTDirCapturingAssignment)) {
// A macro or macro invocation is treated as a leaf here for special reasons
te = te.getFirstChild();
}
@@ -395,7 +383,8 @@ abstract class ASTElement extends ASTNode {
private ASTElement getLastLeaf() {
ASTElement te = this;
- while (!te.isLeaf() && !(te instanceof ASTDirMacroOrFunction) && !(te instanceof ASTDirCapturingAssignment)) {
+ while (te.getChildCount() != 0 && !(te instanceof ASTDirMacroOrFunction)
+ && !(te instanceof ASTDirCapturingAssignment)) {
// A macro or macro invocation is treated as a leaf here for special reasons
te = te.getLastChild();
}
@@ -435,4 +424,29 @@ abstract class ASTElement extends ASTNode {
boolean heedsTrailingWhitespace() {
return false;
}
+
+ private class _ChildIterator implements Iterator<ASTElement> {
+
+ private int nextIndex;
+
+ @Override
+ public boolean hasNext() {
+ return nextIndex < childCount;
+ }
+
+ @Override
+ public ASTElement next() {
+ if (nextIndex >= childCount) {
+ throw new NoSuchElementException();
+ }
+ return childBuffer[nextIndex++];
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ }
+
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpAddOrConcat.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpAddOrConcat.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpAddOrConcat.java
index 38ed36d..040235b 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpAddOrConcat.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpAddOrConcat.java
@@ -152,7 +152,7 @@ final class ASTExpAddOrConcat extends ASTExpression {
}
@Override
- protected ASTExpression deepCloneWithIdentifierReplaced_inner(
+ ASTExpression deepCloneWithIdentifierReplaced_inner(
String replacedIdentifier, ASTExpression replacement, ReplacemenetState replacementState) {
return new ASTExpAddOrConcat(
left.deepCloneWithIdentifierReplaced(replacedIdentifier, replacement, replacementState),
@@ -165,7 +165,7 @@ final class ASTExpAddOrConcat extends ASTExpression {
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return "+";
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpAnd.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpAnd.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpAnd.java
index ec60b26..e6958cf 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpAnd.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpAnd.java
@@ -45,7 +45,7 @@ final class ASTExpAnd extends ASTExpBoolean {
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return "&&";
}
@@ -55,7 +55,7 @@ final class ASTExpAnd extends ASTExpBoolean {
}
@Override
- protected ASTExpression deepCloneWithIdentifierReplaced_inner(
+ ASTExpression deepCloneWithIdentifierReplaced_inner(
String replacedIdentifier, ASTExpression replacement, ReplacemenetState replacementState) {
return new ASTExpAnd(
lho.deepCloneWithIdentifierReplaced(replacedIdentifier, replacement, replacementState),
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpArithmetic.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpArithmetic.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpArithmetic.java
index 632baca..579a96b 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpArithmetic.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpArithmetic.java
@@ -85,7 +85,7 @@ final class ASTExpArithmetic extends ASTExpression {
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return String.valueOf(getOperatorSymbol(operator));
}
@@ -99,7 +99,7 @@ final class ASTExpArithmetic extends ASTExpression {
}
@Override
- protected ASTExpression deepCloneWithIdentifierReplaced_inner(
+ ASTExpression deepCloneWithIdentifierReplaced_inner(
String replacedIdentifier, ASTExpression replacement, ReplacemenetState replacementState) {
return new ASTExpArithmetic(
lho.deepCloneWithIdentifierReplaced(replacedIdentifier, replacement, replacementState),
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpBooleanLiteral.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpBooleanLiteral.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpBooleanLiteral.java
index 0cb9c50..bb2bada 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpBooleanLiteral.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpBooleanLiteral.java
@@ -48,16 +48,11 @@ final class ASTExpBooleanLiteral extends ASTExpression {
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return getCanonicalForm();
}
@Override
- public String toString() {
- return val ? TemplateBooleanFormat.C_TRUE : TemplateBooleanFormat.C_FALSE;
- }
-
- @Override
TemplateModel _eval(Environment env) {
return val ? TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE;
}
@@ -68,7 +63,7 @@ final class ASTExpBooleanLiteral extends ASTExpression {
}
@Override
- protected ASTExpression deepCloneWithIdentifierReplaced_inner(
+ ASTExpression deepCloneWithIdentifierReplaced_inner(
String replacedIdentifier, ASTExpression replacement, ReplacemenetState replacementState) {
return new ASTExpBooleanLiteral(val);
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpBuiltIn.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpBuiltIn.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpBuiltIn.java
index 3ff5c0a..6324cf4 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpBuiltIn.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpBuiltIn.java
@@ -384,7 +384,7 @@ abstract class ASTExpBuiltIn extends ASTExpression implements Cloneable {
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return "?" + key;
}
@@ -394,7 +394,7 @@ abstract class ASTExpBuiltIn extends ASTExpression implements Cloneable {
}
@Override
- protected ASTExpression deepCloneWithIdentifierReplaced_inner(
+ ASTExpression deepCloneWithIdentifierReplaced_inner(
String replacedIdentifier, ASTExpression replacement, ReplacemenetState replacementState) {
try {
ASTExpBuiltIn clone = (ASTExpBuiltIn) clone();
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpBuiltInVariable.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpBuiltInVariable.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpBuiltInVariable.java
index 08b9218..42fe3f1 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpBuiltInVariable.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpBuiltInVariable.java
@@ -220,17 +220,12 @@ final class ASTExpBuiltInVariable extends ASTExpression {
}
@Override
- public String toString() {
- return "." + name;
- }
-
- @Override
public String getCanonicalForm() {
return "." + name;
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return getCanonicalForm();
}
@@ -240,7 +235,7 @@ final class ASTExpBuiltInVariable extends ASTExpression {
}
@Override
- protected ASTExpression deepCloneWithIdentifierReplaced_inner(
+ ASTExpression deepCloneWithIdentifierReplaced_inner(
String replacedIdentifier, ASTExpression replacement, ReplacemenetState replacementState) {
return this;
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpComparison.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpComparison.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpComparison.java
index c7d92f0..9b6beac 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpComparison.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpComparison.java
@@ -68,7 +68,7 @@ final class ASTExpComparison extends ASTExpBoolean {
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return opString;
}
@@ -78,7 +78,7 @@ final class ASTExpComparison extends ASTExpBoolean {
}
@Override
- protected ASTExpression deepCloneWithIdentifierReplaced_inner(
+ ASTExpression deepCloneWithIdentifierReplaced_inner(
String replacedIdentifier, ASTExpression replacement, ReplacemenetState replacementState) {
return new ASTExpComparison(
left.deepCloneWithIdentifierReplaced(replacedIdentifier, replacement, replacementState),
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpDefault.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpDefault.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpDefault.java
index 04c1afc..0aac874 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpDefault.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpDefault.java
@@ -169,7 +169,7 @@ class ASTExpDefault extends ASTExpression {
}
@Override
- protected ASTExpression deepCloneWithIdentifierReplaced_inner(String replacedIdentifier, ASTExpression replacement, ReplacemenetState replacementState) {
+ ASTExpression deepCloneWithIdentifierReplaced_inner(String replacedIdentifier, ASTExpression replacement, ReplacemenetState replacementState) {
return new ASTExpDefault(
lho.deepCloneWithIdentifierReplaced(replacedIdentifier, replacement, replacementState),
rho != null
@@ -186,7 +186,7 @@ class ASTExpDefault extends ASTExpression {
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return "...!...";
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpDot.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpDot.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpDot.java
index 1e67fad..a041909 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpDot.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpDot.java
@@ -46,11 +46,11 @@ final class ASTExpDot extends ASTExpression {
@Override
public String getCanonicalForm() {
- return target.getCanonicalForm() + getASTNodeDescriptor() + _StringUtils.toFTLIdentifierReferenceAfterDot(key);
+ return target.getCanonicalForm() + getLabelWithoutParameters() + _StringUtils.toFTLIdentifierReferenceAfterDot(key);
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return ".";
}
@@ -60,7 +60,7 @@ final class ASTExpDot extends ASTExpression {
}
@Override
- protected ASTExpression deepCloneWithIdentifierReplaced_inner(
+ ASTExpression deepCloneWithIdentifierReplaced_inner(
String replacedIdentifier, ASTExpression replacement, ReplacemenetState replacementState) {
return new ASTExpDot(
target.deepCloneWithIdentifierReplaced(replacedIdentifier, replacement, replacementState),
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpDynamicKeyName.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpDynamicKeyName.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpDynamicKeyName.java
index e14e009..29e902a 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpDynamicKeyName.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpDynamicKeyName.java
@@ -237,7 +237,7 @@ final class ASTExpDynamicKeyName extends ASTExpression {
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return "...[...]";
}
@@ -262,7 +262,7 @@ final class ASTExpDynamicKeyName extends ASTExpression {
}
@Override
- protected ASTExpression deepCloneWithIdentifierReplaced_inner(
+ ASTExpression deepCloneWithIdentifierReplaced_inner(
String replacedIdentifier, ASTExpression replacement, ReplacemenetState replacementState) {
return new ASTExpDynamicKeyName(
target.deepCloneWithIdentifierReplaced(replacedIdentifier, replacement, replacementState),
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpExists.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpExists.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpExists.java
index 24f6e19..ce96532 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpExists.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpExists.java
@@ -58,18 +58,18 @@ class ASTExpExists extends ASTExpression {
}
@Override
- protected ASTExpression deepCloneWithIdentifierReplaced_inner(String replacedIdentifier, ASTExpression replacement, ReplacemenetState replacementState) {
+ ASTExpression deepCloneWithIdentifierReplaced_inner(String replacedIdentifier, ASTExpression replacement, ReplacemenetState replacementState) {
return new ASTExpExists(
exp.deepCloneWithIdentifierReplaced(replacedIdentifier, replacement, replacementState));
}
@Override
public String getCanonicalForm() {
- return exp.getCanonicalForm() + getASTNodeDescriptor();
+ return exp.getCanonicalForm() + getLabelWithoutParameters();
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return "??";
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpFunctionCall.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpFunctionCall.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpFunctionCall.java
index 07985c8..8621085 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpFunctionCall.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpFunctionCall.java
@@ -36,7 +36,7 @@ import org.apache.freemarker.core.util._StringUtils;
/**
* AST expression node: {@code exp(args)}.
*/
-final class ASTExpFunctionCall extends ASTExpression implements CallPlace {
+public final class ASTExpFunctionCall extends ASTExpression implements CallPlace {
private final ASTExpression functionExp;
private final ASTExpression[] positionalArgs;
@@ -110,7 +110,7 @@ final class ASTExpFunctionCall extends ASTExpression implements CallPlace {
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return "...(...)";
}
@@ -124,7 +124,7 @@ final class ASTExpFunctionCall extends ASTExpression implements CallPlace {
}
@Override
- protected ASTExpression deepCloneWithIdentifierReplaced_inner(
+ ASTExpression deepCloneWithIdentifierReplaced_inner(
String replacedIdentifier, ASTExpression replacement, ReplacemenetState replacementState) {
ASTExpression[] positionalArgsClone;
if (positionalArgs != null) {
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpHashLiteral.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpHashLiteral.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpHashLiteral.java
index 6c337dd..e2df12f 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpHashLiteral.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpHashLiteral.java
@@ -68,7 +68,7 @@ final class ASTExpHashLiteral extends ASTExpression {
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return "{...}";
}
@@ -89,7 +89,7 @@ final class ASTExpHashLiteral extends ASTExpression {
@Override
- protected ASTExpression deepCloneWithIdentifierReplaced_inner(
+ ASTExpression deepCloneWithIdentifierReplaced_inner(
String replacedIdentifier, ASTExpression replacement, ReplacemenetState replacementState) {
ArrayList clonedKeys = (ArrayList) keys.clone();
for (ListIterator iter = clonedKeys.listIterator(); iter.hasNext(); ) {
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpListLiteral.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpListLiteral.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpListLiteral.java
index 1d3f8d9..42ef089 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpListLiteral.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpListLiteral.java
@@ -70,7 +70,7 @@ final class ASTExpListLiteral extends ASTExpression {
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return "[...]";
}
@@ -113,7 +113,7 @@ final class ASTExpListLiteral extends ASTExpression {
@SuppressWarnings("unchecked")
@Override
- protected ASTExpression deepCloneWithIdentifierReplaced_inner(
+ ASTExpression deepCloneWithIdentifierReplaced_inner(
String replacedIdentifier, ASTExpression replacement, ReplacemenetState replacementState) {
ArrayList<ASTExpression> clonedValues = (ArrayList<ASTExpression>) items.clone();
for (ListIterator<ASTExpression> iter = clonedValues.listIterator(); iter.hasNext(); ) {
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpNegateOrPlus.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpNegateOrPlus.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpNegateOrPlus.java
index 820e2e7..f0a0bf4 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpNegateOrPlus.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpNegateOrPlus.java
@@ -67,7 +67,7 @@ final class ASTExpNegateOrPlus extends ASTExpression {
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return isMinus ? "-..." : "+...";
}
@@ -77,7 +77,7 @@ final class ASTExpNegateOrPlus extends ASTExpression {
}
@Override
- protected ASTExpression deepCloneWithIdentifierReplaced_inner(
+ ASTExpression deepCloneWithIdentifierReplaced_inner(
String replacedIdentifier, ASTExpression replacement, ReplacemenetState replacementState) {
return new ASTExpNegateOrPlus(
target.deepCloneWithIdentifierReplaced(replacedIdentifier, replacement, replacementState),
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpNot.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpNot.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpNot.java
index 934c58e..6344624 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpNot.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpNot.java
@@ -41,7 +41,7 @@ final class ASTExpNot extends ASTExpBoolean {
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return "!";
}
@@ -51,7 +51,7 @@ final class ASTExpNot extends ASTExpBoolean {
}
@Override
- protected ASTExpression deepCloneWithIdentifierReplaced_inner(
+ ASTExpression deepCloneWithIdentifierReplaced_inner(
String replacedIdentifier, ASTExpression replacement, ReplacemenetState replacementState) {
return new ASTExpNot(
target.deepCloneWithIdentifierReplaced(replacedIdentifier, replacement, replacementState));
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpNumberLiteral.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpNumberLiteral.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpNumberLiteral.java
index a61629d..a98fc78 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpNumberLiteral.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpNumberLiteral.java
@@ -59,7 +59,7 @@ final class ASTExpNumberLiteral extends ASTExpression implements TemplateNumberM
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return getCanonicalForm();
}
@@ -69,7 +69,7 @@ final class ASTExpNumberLiteral extends ASTExpression implements TemplateNumberM
}
@Override
- protected ASTExpression deepCloneWithIdentifierReplaced_inner(
+ ASTExpression deepCloneWithIdentifierReplaced_inner(
String replacedIdentifier, ASTExpression replacement, ReplacemenetState replacementState) {
return new ASTExpNumberLiteral(value);
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpOr.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpOr.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpOr.java
index e9d64a0..5222b50 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpOr.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpOr.java
@@ -45,7 +45,7 @@ final class ASTExpOr extends ASTExpBoolean {
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return "||";
}
@@ -55,7 +55,7 @@ final class ASTExpOr extends ASTExpBoolean {
}
@Override
- protected ASTExpression deepCloneWithIdentifierReplaced_inner(
+ ASTExpression deepCloneWithIdentifierReplaced_inner(
String replacedIdentifier, ASTExpression replacement, ReplacemenetState replacementState) {
return new ASTExpOr(
lho.deepCloneWithIdentifierReplaced(replacedIdentifier, replacement, replacementState),
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpParenthesis.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpParenthesis.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpParenthesis.java
index 9f64b3d..b7d82b7 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpParenthesis.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpParenthesis.java
@@ -43,7 +43,7 @@ final class ASTExpParenthesis extends ASTExpression {
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return "(...)";
}
@@ -62,7 +62,7 @@ final class ASTExpParenthesis extends ASTExpression {
}
@Override
- protected ASTExpression deepCloneWithIdentifierReplaced_inner(
+ ASTExpression deepCloneWithIdentifierReplaced_inner(
String replacedIdentifier, ASTExpression replacement, ReplacemenetState replacementState) {
return new ASTExpParenthesis(
nested.deepCloneWithIdentifierReplaced(replacedIdentifier, replacement, replacementState));
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpRange.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpRange.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpRange.java
index edd80a5..2037fbc 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpRange.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpRange.java
@@ -62,11 +62,11 @@ final class ASTExpRange extends ASTExpression {
@Override
public String getCanonicalForm() {
String rhs = rho != null ? rho.getCanonicalForm() : "";
- return lho.getCanonicalForm() + getASTNodeDescriptor() + rhs;
+ return lho.getCanonicalForm() + getLabelWithoutParameters() + rhs;
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
switch (endType) {
case END_EXCLUSIVE: return "..<";
case END_INCLUSIVE: return "..";
@@ -83,7 +83,7 @@ final class ASTExpRange extends ASTExpression {
}
@Override
- protected ASTExpression deepCloneWithIdentifierReplaced_inner(
+ ASTExpression deepCloneWithIdentifierReplaced_inner(
String replacedIdentifier, ASTExpression replacement, ReplacemenetState replacementState) {
return new ASTExpRange(
lho.deepCloneWithIdentifierReplaced(replacedIdentifier, replacement, replacementState),
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpStringLiteral.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpStringLiteral.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpStringLiteral.java
index c20de82..6c8d222 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpStringLiteral.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpStringLiteral.java
@@ -171,7 +171,7 @@ final class ASTExpStringLiteral extends ASTExpression implements TemplateStringM
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return dynamicValue == null ? getCanonicalForm() : "dynamic \"...\"";
}
@@ -181,7 +181,7 @@ final class ASTExpStringLiteral extends ASTExpression implements TemplateStringM
}
@Override
- protected ASTExpression deepCloneWithIdentifierReplaced_inner(
+ ASTExpression deepCloneWithIdentifierReplaced_inner(
String replacedIdentifier, ASTExpression replacement, ReplacemenetState replacementState) {
ASTExpStringLiteral cloned = new ASTExpStringLiteral(value);
// FIXME: replacedIdentifier should be searched inside interpolatedOutput too:
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpVariable.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpVariable.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpVariable.java
index 1044403..b261c26 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpVariable.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpVariable.java
@@ -61,7 +61,7 @@ final class ASTExpVariable extends ASTExpression {
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return getCanonicalForm();
}
@@ -86,7 +86,7 @@ final class ASTExpVariable extends ASTExpression {
}
@Override
- protected ASTExpression deepCloneWithIdentifierReplaced_inner(
+ ASTExpression deepCloneWithIdentifierReplaced_inner(
String replacedIdentifier, ASTExpression replacement, ReplacemenetState replacementState) {
if (name.equals(replacedIdentifier)) {
if (replacementState.replacementAlreadyInUse) {
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpression.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpression.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpression.java
index 31c855e..b15d1d0 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpression.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpression.java
@@ -34,6 +34,7 @@ import org.apache.freemarker.core.model.impl.BeanModel;
/**
* AST expression node superclass
*/
+//TODO [FM3] will be public
abstract class ASTExpression extends ASTNode {
/**
@@ -51,6 +52,9 @@ abstract class ASTExpression extends ASTNode {
// Hook in here to set the constant value if possible.
+ // Package visible constructor to prevent extending this class outside FreeMarker
+ ASTExpression () { }
+
@Override
void setLocation(Template template, int beginColumn, int beginLine, int endColumn, int endLine) {
super.setLocation(template, beginColumn, beginLine, endColumn, endLine);
@@ -63,11 +67,10 @@ abstract class ASTExpression extends ASTNode {
}
}
- final TemplateModel getAsTemplateModel(Environment env) throws TemplateException {
- return eval(env);
- }
-
- final TemplateModel eval(Environment env) throws TemplateException {
+ /**
+ * Evaluates the expression, returning its current value.
+ */
+ public final TemplateModel eval(Environment env) throws TemplateException {
try {
return constantValue != null ? constantValue : _eval(env);
} catch (FlowControlException | TemplateException e) {
@@ -179,7 +182,7 @@ abstract class ASTExpression extends ASTNode {
* This should return an equivalent new expression object (or an identifier replacement expression).
* The position need not be filled, unless it will be different from the position of what we were cloning.
*/
- protected abstract ASTExpression deepCloneWithIdentifierReplaced_inner(
+ abstract ASTExpression deepCloneWithIdentifierReplaced_inner(
String replacedIdentifier, ASTExpression replacement, ReplacemenetState replacementState);
static boolean isEmpty(TemplateModel model) throws TemplateException {
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTImplicitParent.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTImplicitParent.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTImplicitParent.java
index 97991a7..f87da42 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTImplicitParent.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTImplicitParent.java
@@ -25,15 +25,17 @@ import java.io.IOException;
* AST directive-like node, used where there's no other parent for a list of {@link ASTElement}-s. Most often occurs as
* the root node of the AST.
*/
+//TODO [FM3] will be public
final class ASTImplicitParent extends ASTElement {
+ // Package visible constructor to prevent instantiating outside FreeMarker
ASTImplicitParent() { }
@Override
ASTElement postParseCleanup(boolean stripWhitespace)
throws ParseException {
super.postParseCleanup(stripWhitespace);
- return getChildCount() == 1 ? getChild(0) : this;
+ return getChildCount() == 1 ? fastGetChild(0) : this;
}
/**
@@ -41,20 +43,19 @@ final class ASTImplicitParent extends ASTElement {
* and outputs the resulting text.
*/
@Override
- ASTElement[] accept(Environment env)
- throws TemplateException, IOException {
+ ASTElement[] execute(Environment env) throws TemplateException, IOException {
return getChildBuffer();
}
@Override
- protected String dump(boolean canonical) {
+ String dump(boolean canonical) {
if (canonical) {
return getChildrenCanonicalForm();
} else {
if (getParent() == null) {
return "root";
}
- return getASTNodeDescriptor(); // ASTImplicitParent is uninteresting in a stack trace.
+ return getLabelWithoutParameters(); // ASTImplicitParent is uninteresting in a stack trace.
}
}
@@ -62,7 +63,7 @@ final class ASTImplicitParent extends ASTElement {
protected boolean isOutputCacheable() {
int ln = getChildCount();
for (int i = 0; i < ln; i++) {
- if (!getChild(i).isOutputCacheable()) {
+ if (!fastGetChild(i).isOutputCacheable()) {
return false;
}
}
@@ -70,7 +71,7 @@ final class ASTImplicitParent extends ASTElement {
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return "#mixedContent";
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTInterpolation.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTInterpolation.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTInterpolation.java
index 6ce0b7e..56805d2 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTInterpolation.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTInterpolation.java
@@ -31,6 +31,7 @@ import org.apache.freemarker.core.util.TemplateLanguageUtils;
/**
* AST interpolation node: <tt>${exp}</tt>
*/
+//TODO [FM3] will be public
final class ASTInterpolation extends ASTElement {
private final ASTExpression expression;
@@ -42,7 +43,7 @@ final class ASTInterpolation extends ASTElement {
private final OutputFormat outputFormat;
private final MarkupOutputFormat markupOutputFormat;
private final boolean autoEscape;
-
+
ASTInterpolation(
ASTExpression expression, ASTExpression escapedExpression,
OutputFormat outputFormat, boolean autoEscape) {
@@ -58,9 +59,21 @@ final class ASTInterpolation extends ASTElement {
* Outputs the string value of the enclosed expression.
*/
@Override
- ASTElement[] accept(Environment env) throws TemplateException, IOException {
- final Object moOrStr = calculateInterpolatedStringOrMarkup(env);
+ ASTElement[] execute(Environment env) throws TemplateException, IOException {
+ printStringOrTemplateOutputModel(
+ escapedExpression, outputFormat, markupOutputFormat, autoEscape, env);
+ return null;
+ }
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ static void printStringOrTemplateOutputModel(
+ ASTExpression exp,
+ OutputFormat outputFormat,
+ MarkupOutputFormat markupOutputFormat, boolean autoEscape,
+ Environment env) throws IOException, TemplateException {
final Writer out = env.getOut();
+
+ final Object moOrStr = _EvalUtils.coerceModelToPlainTextOrMarkup(exp.eval(env), exp, null, env);
if (moOrStr instanceof String) {
final String s = (String) moOrStr;
if (autoEscape) {
@@ -70,28 +83,8 @@ final class ASTInterpolation extends ASTElement {
}
} else {
final TemplateMarkupOutputModel mo = (TemplateMarkupOutputModel) moOrStr;
- final MarkupOutputFormat moOF = mo.getOutputFormat();
- // ATTENTION: Keep this logic in sync. ?esc/?noEsc's logic!
- if (moOF != outputFormat && !outputFormat.isOutputFormatMixingAllowed()) {
- final String srcPlainText;
- // ATTENTION: Keep this logic in sync. ?esc/?noEsc's logic!
- srcPlainText = moOF.getSourcePlainText(mo);
- if (srcPlainText == null) {
- throw new TemplateException(escapedExpression,
- "The value to print is in ", new _DelayedToString(moOF),
- " format, which differs from the current output format, ",
- new _DelayedToString(outputFormat), ". Format conversion wasn't possible.");
- }
- if (outputFormat instanceof MarkupOutputFormat) {
- ((MarkupOutputFormat) outputFormat).output(srcPlainText, out);
- } else {
- out.write(srcPlainText);
- }
- } else {
- moOF.output(mo, out);
- }
+ _EvalUtils.printTemplateMarkupOutputModel(mo, outputFormat, out, exp);
}
- return null;
}
/**
@@ -104,7 +97,7 @@ final class ASTInterpolation extends ASTElement {
}
@Override
- protected final String dump(boolean canonical) {
+ final String dump(boolean canonical) {
return dump(canonical, false);
}
@@ -137,7 +130,7 @@ final class ASTInterpolation extends ASTElement {
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return "${...}";
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTNode.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTNode.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTNode.java
index 4ca9b7f..bcce5de 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTNode.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTNode.java
@@ -20,8 +20,21 @@
package org.apache.freemarker.core;
/**
- * AST node: The superclass of all AST nodes
+ * Superclass of all AST (Abstract Syntax Tree) nodes.
+ * <p>
+ * The AST is a tree data structure that represent the complete content of a template (static content, directive calls,
+ * interpolations and the expressions inside them, possibly comments as well), without the complexities of syntactical
+ * details. The AST is generated from the source code (which is text) by the parser of the {@link TemplateLanguage},
+ * and focuses on the meaning of the template. Thus, if the same template is rewritten in different template languages
+ * (like F3AH is converted to F3SH), the resulting AST-s will remain practically identical.
+ * <p>
+ * When a {@link Template} is processed, FreeMarker executes the AST directly. (In theory the AST could be translated
+ * further to byte code, FreeMarker doesn't try to do that, at least currently.)
+ * <p>
+ * The AST can also be used to analyze the content of templates, such as to discover its dependencies (on data-model
+ * variables, on other templates).
*/
+//TODO [FM3] will be public
abstract class ASTNode {
private Template template;
@@ -67,51 +80,46 @@ abstract class ASTNode {
this.endLine = endLine;
}
+ // Package visible constructor to prevent extending this class outside FreeMarker
+ ASTNode() { }
+
+ /**
+ * The template that contains this node.
+ */
+ public Template getTemplate() {
+ return template;
+ }
+
+ /**
+ * 1-based column number of the last character of this node in the source code. 0 if not available.
+ */
public final int getBeginColumn() {
return beginColumn;
}
+ /**
+ * 1-based line number of the first character of this node in the source code. 0 if not available.
+ */
+ // TODO [FM3] No negative number hack in ?eval and such.
public final int getBeginLine() {
return beginLine;
}
- public final int getEndColumn() {
- return endColumn;
- }
-
- public final int getEndLine() {
- return endLine;
- }
-
/**
- * Returns a string that indicates
- * where in the template source, this object is.
+ * 1-based column number of the first character of this node in the source code. 0 if not available.
*/
- public String getStartLocation() {
- return MessageUtils.formatLocationForEvaluationError(template, beginLine, beginColumn);
+ public final int getEndColumn() {
+ return endColumn;
}
/**
- * As of 2.3.20. the same as {@link #getStartLocation}. Meant to be used where there's a risk of XSS
- * when viewing error messages.
+ * 1-based line number of the last character of this node in the source code. 0 if not available.
*/
- public String getStartLocationQuoted() {
- return getStartLocation();
- }
-
- public String getEndLocation() {
- return MessageUtils.formatLocationForEvaluationError(template, endLine, endColumn);
+ public final int getEndLine() {
+ return endLine;
}
- /**
- * As of 2.3.20. the same as {@link #getEndLocation}. Meant to be used where there's a risk of XSS
- * when viewing error messages.
- */
- public String getEndLocationQuoted() {
- return getEndLocation();
- }
-
- public final String getSource() {
+ final String getSource() {
String s;
if (template != null) {
s = template.getSource(beginColumn, beginLine, endColumn, endLine);
@@ -124,14 +132,9 @@ abstract class ASTNode {
}
@Override
- public String toString() {
+ public final String toString() {
String s;
- try {
- s = getSource();
- } catch (Exception e) { // REVISIT: A bit of a hack? (JR)
- s = null;
- }
- return s != null ? s : getCanonicalForm();
+ return (s = getSource()) != null ? s : getCanonicalForm();
}
/**
@@ -155,10 +158,6 @@ abstract class ASTNode {
return true;
}
- public Template getTemplate() {
- return template;
- }
-
ASTNode copyLocationFrom(ASTNode from) {
template = from.template;
beginColumn = from.beginColumn;
@@ -169,12 +168,14 @@ abstract class ASTNode {
}
/**
- * FTL generated from the AST of the node, which must be parseable to an AST that does the same as the original
- * source, assuming we turn off automatic white-space removal when parsing the canonical form.
+ * Template source code generated from the AST of this node.
+ * When parsed, it should result in a practically identical AST that does the same as the original
+ * source, assuming that you turn off automatic white-space removal when parsing the canonical form.
*
- * @see ASTElement#getDescription()
- * @see #getASTNodeDescriptor()
+ * @see ASTElement#getLabelWithParameters()
+ * @see #getLabelWithoutParameters()
*/
+ // TODO [FM3] The whitespace problem isn't OK; do pretty-formatting, outside core if too big.
abstract public String getCanonicalForm();
/**
@@ -185,9 +186,9 @@ abstract class ASTNode {
* leaf nodes the symbols should be the canonical form of value.
*
* @see #getCanonicalForm()
- * @see ASTElement#getDescription()
+ * @see ASTElement#getLabelWithParameters()
*/
- abstract String getASTNodeDescriptor();
+ public abstract String getLabelWithoutParameters();
/**
* Returns highest valid parameter index + 1. So one should scan indexes with {@link #getParameterValue(int)}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTStaticText.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTStaticText.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTStaticText.java
index 76f1019..4e8ec95 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTStaticText.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTStaticText.java
@@ -27,6 +27,7 @@ import org.apache.freemarker.core.util._StringUtils;
/**
* AST node representing static text.
*/
+//TODO [FM3] will be public
final class ASTStaticText extends ASTElement {
// We're using char[] instead of String for storing the text block because
@@ -37,11 +38,11 @@ final class ASTStaticText extends ASTElement {
private char[] text;
private final boolean unparsed;
- public ASTStaticText(String text) {
+ ASTStaticText(String text) {
this(text, false);
}
- public ASTStaticText(String text, boolean unparsed) {
+ ASTStaticText(String text, boolean unparsed) {
this(text.toCharArray(), unparsed);
}
@@ -56,19 +57,15 @@ final class ASTStaticText extends ASTElement {
/**
* Simply outputs the text.
- *
- * @deprecated This is an internal API; don't call or override it.
*/
- @Deprecated
@Override
- public ASTElement[] accept(Environment env)
- throws IOException {
+ ASTElement[] execute(Environment env) throws IOException {
env.getOut().write(text);
return null;
}
@Override
- protected String dump(boolean canonical) {
+ String dump(boolean canonical) {
if (canonical) {
String text = new String(this.text);
if (unparsed) {
@@ -81,7 +78,7 @@ final class ASTStaticText extends ASTElement {
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return "#text";
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInWithParseTimeParameters.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInWithParseTimeParameters.java b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInWithParseTimeParameters.java
index 47a37bd..31aeb00 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInWithParseTimeParameters.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInWithParseTimeParameters.java
@@ -48,8 +48,8 @@ abstract class BuiltInWithParseTimeParameters extends SpecialBuiltIn {
}
@Override
- String getASTNodeDescriptor() {
- return super.getASTNodeDescriptor() + "(...)";
+ public String getLabelWithoutParameters() {
+ return super.getLabelWithoutParameters() + "(...)";
}
@Override
@@ -90,7 +90,7 @@ abstract class BuiltInWithParseTimeParameters extends SpecialBuiltIn {
}
@Override
- protected ASTExpression deepCloneWithIdentifierReplaced_inner(
+ ASTExpression deepCloneWithIdentifierReplaced_inner(
String replacedIdentifier, ASTExpression replacement, ReplacemenetState replacementState) {
final ASTExpression clone = super.deepCloneWithIdentifierReplaced_inner(replacedIdentifier, replacement, replacementState);
cloneArguments(clone, replacedIdentifier, replacement, replacementState);
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/CallPlace.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/CallPlace.java b/freemarker-core/src/main/java/org/apache/freemarker/core/CallPlace.java
index 6b9ba34..6135d3a 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/CallPlace.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/CallPlace.java
@@ -65,6 +65,8 @@ public interface CallPlace {
* that many nested content parameters as the length of this array. If you want to allow the caller to not
* declare some of the nested content parameters, then you have to make this array shorter according to
* {@link #getNestedContentParameterCount()}.
+ * @param out
+ * The {@link Writer} to print.
*/
void executeNestedContent(TemplateModel[] nestedContentArgs, Writer out, Environment env)
throws TemplateException, IOException;
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/Configuration.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/Configuration.java b/freemarker-core/src/main/java/org/apache/freemarker/core/Configuration.java
index be9f802..9a9d13b 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/Configuration.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/Configuration.java
@@ -43,6 +43,7 @@ import java.util.TimeZone;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
+import org.apache.freemarker.core.Dialect.ConfiguredDialect;
import org.apache.freemarker.core.arithmetic.ArithmeticEngine;
import org.apache.freemarker.core.arithmetic.impl.BigDecimalArithmeticEngine;
import org.apache.freemarker.core.model.ObjectWrapper;
@@ -175,6 +176,7 @@ public final class Configuration implements TopLevelConfiguration, CustomStateSc
private final Long templateUpdateDelayMilliseconds;
private final Boolean localizedTemplateLookup;
private final List<OutputFormat> registeredCustomOutputFormats;
+ private final Map<Dialect, ConfiguredDialect> configuredDialects;
private final Map<String, OutputFormat> registeredCustomOutputFormatsByName;
private final Map<String, Object> sharedVariables;
private final Map<String, TemplateModel> wrappedSharedVariables;
@@ -441,6 +443,12 @@ public final class Configuration implements TopLevelConfiguration, CustomStateSc
this.templateConfigurations = templateConfigurations;
templateResolver.setDependencies(new TemplateResolverDependenciesImpl(this, templateResolver));
+
+ // ATTENTION! Creating the configuredDialects must be the last thing, as here the user code can already access
+ // this Configuration!
+ configuredDialects = new HashMap<>();
+ // TODO [FM3] This is hard-code for now, but later we need to add the "dialects" configuration setting
+ configuredDialects.put(DefaultDialect.INSTANCE, DefaultDialect.INSTANCE.createConfiguredDialect(this));
}
private void checkSettingIsNullForThisTemplateResolver(
@@ -671,8 +679,8 @@ public final class Configuration implements TopLevelConfiguration, CustomStateSc
throw new IllegalArgumentException("Missing opening '{' in: " + name);
}
- MarkupOutputFormat outerOF = getMarkupOutputFormatForCombined(name.substring(0, openBrcIdx));
- MarkupOutputFormat innerOF = getMarkupOutputFormatForCombined(
+ MarkupOutputFormat<?> outerOF = getMarkupOutputFormatForCombined(name.substring(0, openBrcIdx));
+ MarkupOutputFormat<?> innerOF = getMarkupOutputFormatForCombined(
name.substring(openBrcIdx + 1, name.length() - 1));
return new CombinedMarkupOutputFormat(name, outerOF, innerOF);
@@ -708,6 +716,21 @@ public final class Configuration implements TopLevelConfiguration, CustomStateSc
return stdOF;
}
}
+
+ /**
+ * Same as {@link #getOutputFormat(String)}, but also throws {@link UnregisteredOutputFormatException} of the
+ * output format doesn't extend {@link MarkupOutputFormat}.
+ */
+ public MarkupOutputFormat<?> getMarkupOutputFormat(String name) throws UnregisteredOutputFormatException {
+ OutputFormat outputFormat = getOutputFormat(name);
+ if (!(outputFormat instanceof MarkupOutputFormat<?>)) {
+ // TODO [FM3] It's kind of silly, but so is introducing a subclass exception just for this...
+ throw new UnregisteredOutputFormatException(
+ "The " + _StringUtils.jQuote(name) + " output format (class " + outputFormat.getClass().getName()
+ + " is registered, but doesn't implement " + MarkupOutputFormat.class.getName() + ".");
+ }
+ return (MarkupOutputFormat<?>) outputFormat;
+ }
/**
* Returns the argument {@link OutputFormat} as is, unless a {@link #getRegisteredCustomOutputFormats()
@@ -815,7 +838,7 @@ public final class Configuration implements TopLevelConfiguration, CustomStateSc
public TemplateLanguage getTemplateLanguage() {
return templateLanguage;
}
-
+
/**
* Always {@code true} in {@link Configuration}-s; even if this setting wasn't set in the builder, it gets a default
* value in the {@link Configuration}.
@@ -824,6 +847,30 @@ public final class Configuration implements TopLevelConfiguration, CustomStateSc
public boolean isTemplateLanguageSet() {
return true;
}
+
+ /**
+ * Returns the {@link ConfiguredDialect} for a {@link Dialect} that's known by this {@link Configuration}.
+ *
+ * @param dialect
+ * Not {@code null}.
+ *
+ * @return Never {@code null}. When invoked on the same {@link Configuration} with the same {@link Dialect}
+ * instance, it always returns the same {@link ConfiguredDialect} instance.
+ *
+ * @throws IllegalStateException
+ * If the {@link Dialect} is not know by this {@link Configuration}. (TODO [FM3]: For now it only knows
+ * {@link DefaultDialect#INSTANCE}, but that will change later when custom {@link TemplateLanguage}-s
+ * can be added to the {@link Configuration}.)
+ */
+ public ConfiguredDialect getConfiguredDialect(Dialect dialect) {
+ _NullArgumentException.check("dialect", dialect);
+ ConfiguredDialect configuredDialect = configuredDialects.get(dialect);
+ if (configuredDialect == null) {
+ throw new IllegalStateException("No such " + Dialect.class.getName() + " was added to this Configuration: "
+ + dialect);
+ }
+ return configuredDialect;
+ }
@Override
public int getTabSize() {
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/DefaultDialect.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/DefaultDialect.java b/freemarker-core/src/main/java/org/apache/freemarker/core/DefaultDialect.java
new file mode 100644
index 0000000..b04351a
--- /dev/null
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/DefaultDialect.java
@@ -0,0 +1,82 @@
+package org.apache.freemarker.core;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.freemarker.core.outputformat.MarkupOutputFormat;
+import org.apache.freemarker.core.outputformat.UnregisteredOutputFormatException;
+import org.apache.freemarker.core.outputformat.impl.HTMLOutputFormat;
+
+/**
+ * The default {@link Dialect} for FreeMarker. Most applications are expected to use this.
+ */
+//TODO [FM3][DIALECTS] will be public. Also, then move it into core.dialect?
+final class DefaultDialect extends Dialect {
+
+ public static final DefaultDialect INSTANCE = new DefaultDialect();
+
+ private DefaultDialect() {
+ super("Default FreeMarker 3 Dialect", Configuration.getVersion());
+ }
+
+ @Override
+ public ConfiguredDialect createConfiguredDialect(Configuration cfg) {
+ return new ConfiguredDefaultDialect(cfg);
+ }
+
+ private class ConfiguredDefaultDialect extends ConfiguredDialect {
+ private final Map<String, StaticallyLinkedNamespaceEntry> namespaceEntriesByName;
+
+ ConfiguredDefaultDialect(Configuration cfg) {
+ MarkupOutputFormat<?> htmlOutputFormat;
+ try {
+ htmlOutputFormat = cfg.getMarkupOutputFormat(HTMLOutputFormat.INSTANCE.getName());
+ } catch (UnregisteredOutputFormatException e) {
+ throw new ConfigurationException("Couldn't get HTML output format.", e);
+ }
+ namespaceEntriesByName = new HashMap<>(16, 0.5f); // The speed of get(key) is important
+ //!!T Test entries until FREEMARKER-99 is finished:
+ addNamespaceEntry(
+ new StaticallyLinkedNamespaceEntry("adhocTest1", ASTDirAdhocTest1.VALUE,
+ new ASTDirAdhocTest1.Factory(htmlOutputFormat), null));
+ addNamespaceEntry(
+ new StaticallyLinkedNamespaceEntry("adhocTest2", ASTDirAdhocTest2.VALUE,
+ ASTDirAdhocTest2.FACTORY, null));
+ }
+
+ @Override
+ public StaticallyLinkedNamespaceEntry getNamespaceEntry(String name) {
+ return namespaceEntriesByName.get(name);
+ }
+
+ @Override
+ public Iterable<StaticallyLinkedNamespaceEntry> getNamespaceEntries() {
+ return namespaceEntriesByName.values();
+ }
+
+ private void addNamespaceEntry(StaticallyLinkedNamespaceEntry entry) {
+ namespaceEntriesByName.put(entry.getName(), entry);
+ }
+
+ }
+
+}
[3/3] freemarker git commit: Some ground work to support dialects
later. Added classes like Dialect and StaticallyLinkedNamespaceEntry,
but these are non-public for now, and just drafts,
and aren't actually used by the templates. The final ones will need
Posted by dd...@apache.org.
Some ground work to support dialects later. Added classes like Dialect and StaticallyLinkedNamespaceEntry, but these are non-public for now, and just drafts, and aren't actually used by the templates. The final ones will need more features to be able to replace the trickier built-in directives. Note that some early version (not a public API) of dialects will be needed for FREEMARKER-99, which is why I started this.
Along the way, some internal renaming in the ASTNode related API-s. Most notably visit(...) to execute(...), as we don't use the visitor pattern.
Project: http://git-wip-us.apache.org/repos/asf/freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/freemarker/commit/e8e58ffa
Tree: http://git-wip-us.apache.org/repos/asf/freemarker/tree/e8e58ffa
Diff: http://git-wip-us.apache.org/repos/asf/freemarker/diff/e8e58ffa
Branch: refs/heads/3
Commit: e8e58ffa52937ae4e67d03edb81dd76c84ac9118
Parents: 056635c
Author: ddekany <dd...@apache.org>
Authored: Wed Apr 18 19:19:08 2018 +0200
Committer: ddekany <dd...@apache.org>
Committed: Sat Jun 16 13:42:15 2018 +0200
----------------------------------------------------------------------
README.md | 3 +
.../org/apache/freemarker/core/ASTPrinter.java | 10 +-
.../core/GetOptionalTemplateTest.java | 2 +-
.../core/InterpolationSyntaxTest.java | 2 +
.../core/MistakenlyPublicImportAPIsTest.java | 9 +-
.../core/TemplateCallableModelTest.java | 2 +-
.../freemarker/core/TemplateLanguageTest.java | 5 +-
.../org/apache/freemarker/core/ASTComment.java | 8 +-
.../apache/freemarker/core/ASTDebugBreak.java | 15 +-
.../freemarker/core/ASTDirAdhocTest1.java | 211 +++++++++++++++++++
.../freemarker/core/ASTDirAdhocTest2.java | 165 +++++++++++++++
.../freemarker/core/ASTDirAssignment.java | 8 +-
.../core/ASTDirAssignmentsContainer.java | 10 +-
.../core/ASTDirAttemptRecoverContainer.java | 12 +-
.../apache/freemarker/core/ASTDirAutoEsc.java | 10 +-
.../org/apache/freemarker/core/ASTDirBreak.java | 8 +-
.../core/ASTDirCapturingAssignment.java | 19 +-
.../org/apache/freemarker/core/ASTDirCase.java | 8 +-
.../apache/freemarker/core/ASTDirCompress.java | 15 +-
.../apache/freemarker/core/ASTDirContinue.java | 8 +-
.../freemarker/core/ASTDirElseOfList.java | 10 +-
.../apache/freemarker/core/ASTDirEscape.java | 10 +-
.../apache/freemarker/core/ASTDirFallback.java | 8 +-
.../org/apache/freemarker/core/ASTDirFlush.java | 8 +-
.../core/ASTDirIfElseIfElseContainer.java | 14 +-
.../freemarker/core/ASTDirIfOrElseOrElseIf.java | 8 +-
.../apache/freemarker/core/ASTDirImport.java | 8 +-
.../apache/freemarker/core/ASTDirInclude.java | 8 +-
.../org/apache/freemarker/core/ASTDirItems.java | 12 +-
.../org/apache/freemarker/core/ASTDirList.java | 18 +-
.../core/ASTDirListElseContainer.java | 12 +-
.../freemarker/core/ASTDirMacroOrFunction.java | 10 +-
.../apache/freemarker/core/ASTDirNested.java | 8 +-
.../apache/freemarker/core/ASTDirNoAutoEsc.java | 10 +-
.../apache/freemarker/core/ASTDirNoEscape.java | 12 +-
.../freemarker/core/ASTDirOutputFormat.java | 12 +-
.../apache/freemarker/core/ASTDirRecover.java | 10 +-
.../apache/freemarker/core/ASTDirRecurse.java | 8 +-
.../apache/freemarker/core/ASTDirReturn.java | 8 +-
.../org/apache/freemarker/core/ASTDirSep.java | 12 +-
.../apache/freemarker/core/ASTDirSetting.java | 8 +-
.../org/apache/freemarker/core/ASTDirStop.java | 8 +-
.../apache/freemarker/core/ASTDirSwitch.java | 22 +-
.../freemarker/core/ASTDirTOrRtOrLtOrNt.java | 8 +-
.../org/apache/freemarker/core/ASTDirVisit.java | 8 +-
.../apache/freemarker/core/ASTDirective.java | 63 ++++++
.../freemarker/core/ASTDynamicTopLevelCall.java | 26 +--
.../org/apache/freemarker/core/ASTElement.java | 138 ++++++------
.../freemarker/core/ASTExpAddOrConcat.java | 4 +-
.../org/apache/freemarker/core/ASTExpAnd.java | 4 +-
.../freemarker/core/ASTExpArithmetic.java | 4 +-
.../freemarker/core/ASTExpBooleanLiteral.java | 9 +-
.../apache/freemarker/core/ASTExpBuiltIn.java | 4 +-
.../freemarker/core/ASTExpBuiltInVariable.java | 9 +-
.../freemarker/core/ASTExpComparison.java | 4 +-
.../apache/freemarker/core/ASTExpDefault.java | 4 +-
.../org/apache/freemarker/core/ASTExpDot.java | 6 +-
.../freemarker/core/ASTExpDynamicKeyName.java | 4 +-
.../apache/freemarker/core/ASTExpExists.java | 6 +-
.../freemarker/core/ASTExpFunctionCall.java | 6 +-
.../freemarker/core/ASTExpHashLiteral.java | 4 +-
.../freemarker/core/ASTExpListLiteral.java | 4 +-
.../freemarker/core/ASTExpNegateOrPlus.java | 4 +-
.../org/apache/freemarker/core/ASTExpNot.java | 4 +-
.../freemarker/core/ASTExpNumberLiteral.java | 4 +-
.../org/apache/freemarker/core/ASTExpOr.java | 4 +-
.../freemarker/core/ASTExpParenthesis.java | 4 +-
.../org/apache/freemarker/core/ASTExpRange.java | 6 +-
.../freemarker/core/ASTExpStringLiteral.java | 4 +-
.../apache/freemarker/core/ASTExpVariable.java | 4 +-
.../apache/freemarker/core/ASTExpression.java | 15 +-
.../freemarker/core/ASTImplicitParent.java | 15 +-
.../freemarker/core/ASTInterpolation.java | 45 ++--
.../org/apache/freemarker/core/ASTNode.java | 95 ++++-----
.../apache/freemarker/core/ASTStaticText.java | 15 +-
.../core/BuiltInWithParseTimeParameters.java | 6 +-
.../org/apache/freemarker/core/CallPlace.java | 2 +
.../apache/freemarker/core/Configuration.java | 53 ++++-
.../apache/freemarker/core/DefaultDialect.java | 82 +++++++
.../core/DefaultTemplateLanguage.java | 25 ++-
.../org/apache/freemarker/core/Dialect.java | 127 +++++++++++
.../org/apache/freemarker/core/Environment.java | 161 ++++++++++----
.../apache/freemarker/core/MessageUtils.java | 19 ++
.../freemarker/core/ParsingConfiguration.java | 5 +-
.../core/StaticLinkingCheckException.java | 74 +++++++
.../core/StaticallyLinkedNamespaceEntry.java | 117 ++++++++++
.../org/apache/freemarker/core/Template.java | 2 +-
.../freemarker/core/TemplateConfiguration.java | 9 +-
.../core/TemplateElementArrayBuilder.java | 13 --
.../core/TemplateElementsToVisit.java | 4 +-
.../freemarker/core/TemplateLanguage.java | 35 +--
...nterruptionSupportTemplatePostProcessor.java | 10 +-
.../core/UnparsedTemplateLanguage.java | 3 +-
.../core/UnsupportedFM2TemplateLanguage.java | 2 +-
.../apache/freemarker/core/_CallableUtils.java | 147 +++++++------
.../java/org/apache/freemarker/core/_Debug.java | 25 ++-
.../core/_ErrorDescriptionBuilder.java | 6 +-
.../org/apache/freemarker/core/_EvalUtils.java | 30 +++
.../freemarker/core/util/_ArrayAdapterList.java | 2 +-
.../freemarker/core/util/_ArrayEnumeration.java | 51 -----
.../freemarker/core/util/_ArrayIterator.java | 8 +-
.../core/util/_NullArgumentException.java | 2 +
freemarker-core/src/main/javacc/FTL.jj | 8 +-
103 files changed, 1691 insertions(+), 645 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/README.md
----------------------------------------------------------------------
diff --git a/README.md b/README.md
index 15a5f33..7d34e6d 100644
--- a/README.md
+++ b/README.md
@@ -201,6 +201,9 @@ Last tested Eclipse Oxygen (4.7.0)
- Fro each project: Project -> Properties -> FindBugs -> [x] Run Automatically
- There should 0 errors. But sometimes the plugin fails to take the
@SuppressFBWarnings annotations into account; then use Project -> Clean.
+- Setting type filters (not required, but convenient): "Window" -> "Preferences" ->
+ "Java" -> "Appearance" -> "Type filter", "Add..." these:
+ `javax.swing.*`, `freemarker.*`, `com.sun.*`
### IntelliJ IDEA
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core-test/src/test/java/org/apache/freemarker/core/ASTPrinter.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/ASTPrinter.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/ASTPrinter.java
index 8157c19..297e975 100644
--- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/ASTPrinter.java
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/ASTPrinter.java
@@ -35,7 +35,6 @@ import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CodingErrorAction;
import java.nio.charset.StandardCharsets;
-import java.util.Enumeration;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
@@ -261,7 +260,7 @@ public class ASTPrinter {
private static void validateAST(ASTElement te) {
int childCount = te.getChildCount();
for (int i = 0; i < childCount; i++) {
- ASTElement child = te.getChild(i);
+ ASTElement child = te.fastGetChild(i);
ASTElement parentElement = child.getParent();
// As ASTImplicitParent.accept does nothing but returns its children, it's optimized out in the final
// AST tree. While it will be present as a child, the parent element also will have children
@@ -321,7 +320,7 @@ public class ASTPrinter {
ASTNode tObj = (ASTNode) node;
printNodeLineStart(paramRole, ind, out);
- out.write(tObj.getASTNodeDescriptor());
+ out.write(tObj.getLabelWithoutParameters());
printNodeLineEnd(node, out, opts);
if (opts.getShowConstantValue() && node instanceof ASTExpression) {
@@ -345,9 +344,8 @@ public class ASTPrinter {
printNode(value, ind + INDENTATION, role, opts, out);
}
if (tObj instanceof ASTElement) {
- Enumeration enu = ((ASTElement) tObj).children();
- while (enu.hasMoreElements()) {
- printNode(enu.nextElement(), INDENTATION + ind, null, opts, out);
+ for (ASTElement child : ((ASTElement) tObj).getChildren()) {
+ printNode(child, INDENTATION + ind, null, opts, out);
}
}
} else {
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core-test/src/test/java/org/apache/freemarker/core/GetOptionalTemplateTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/GetOptionalTemplateTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/GetOptionalTemplateTest.java
index 22d6aff..f6c973e 100644
--- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/GetOptionalTemplateTest.java
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/GetOptionalTemplateTest.java
@@ -107,7 +107,7 @@ public class GetOptionalTemplateTest extends TemplateTest {
@Test
public void testWrongArguments() throws Exception {
assertErrorContains("<#assign t = .getOptionalTemplate()>", "argument");
- assertErrorContains("<#assign t = .getOptionalTemplate('1', '2', '3')>", "arguments", "3");
+ assertErrorContains("<#assign t = .getOptionalTemplate('1', '2', '3')>", "1", "arguments", "more");
assertErrorContains("<#assign t = .getOptionalTemplate(1)>", "1st argument", "string", "number");
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core-test/src/test/java/org/apache/freemarker/core/InterpolationSyntaxTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/InterpolationSyntaxTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/InterpolationSyntaxTest.java
index 2bf4200..9865c18 100644
--- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/InterpolationSyntaxTest.java
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/InterpolationSyntaxTest.java
@@ -33,11 +33,13 @@ public class InterpolationSyntaxTest extends TemplateTest {
/** Non-standard template language */
private final TemplateLanguage F3ASU = new DefaultTemplateLanguage("dummy",
+ DefaultDialect.INSTANCE,
UndefinedOutputFormat.INSTANCE, AutoEscapingPolicy.ENABLE_IF_DEFAULT,
TagSyntax.ANGLE_BRACKET, InterpolationSyntax.SQUARE_BRACKET);
/** Non-standard template language */
private final TemplateLanguage F3SDU = new DefaultTemplateLanguage("dummy",
+ DefaultDialect.INSTANCE,
UndefinedOutputFormat.INSTANCE, AutoEscapingPolicy.ENABLE_IF_DEFAULT,
TagSyntax.SQUARE_BRACKET, InterpolationSyntax.DOLLAR);
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core-test/src/test/java/org/apache/freemarker/core/MistakenlyPublicImportAPIsTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/MistakenlyPublicImportAPIsTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/MistakenlyPublicImportAPIsTest.java
index 5fcee97..be85eeb 100644
--- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/MistakenlyPublicImportAPIsTest.java
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/MistakenlyPublicImportAPIsTest.java
@@ -35,9 +35,12 @@ import org.junit.Test;
/**
* These are things that users shouldn't do, but we shouldn't break backward compatibility without knowing about it.
+ *
+ * TODO [FM3] Now we should make this illegal, but I'm not sure how to catch when the user does this.
*/
public class MistakenlyPublicImportAPIsTest {
+
@Test
public void testImportCopying() throws IOException, TemplateException {
StringTemplateLoader tl = new StringTemplateLoader();
@@ -60,7 +63,7 @@ public class MistakenlyPublicImportAPIsTest {
t2.process(null, _NullWriter.INSTANCE);
fail();
} catch (InvalidReferenceException e) {
- // Apparenly, it has never worked like this...
+ // Apparently, it has never worked like this...
assertEquals("i1", e.getBlamedExpressionString());
}
}
@@ -72,6 +75,7 @@ public class MistakenlyPublicImportAPIsTest {
assertThat(i1, instanceOf(Namespace.class));
TemplateModel i2 = env.getVariable("i2");
assertThat(i2, instanceOf(Namespace.class));
+ Environment originalEnv = env;
{
Template t2 = new Template(null, "<@i1.m/>", cfg);
@@ -80,6 +84,7 @@ public class MistakenlyPublicImportAPIsTest {
env = t2.createProcessingEnvironment(null, sw);
env.setVariable("i1", i1);
+ originalEnv.setOut(sw); // The imported macros are still bound to and will use this.
env.process();
assertEquals("1", sw.toString());
}
@@ -88,10 +93,12 @@ public class MistakenlyPublicImportAPIsTest {
Template t2 = new Template(null, "<@i2.m/>", cfg);
StringWriter sw = new StringWriter();
+ env.setOut(sw); // In the old Environment instance, to which the imported macros are bound.
env = t2.createProcessingEnvironment(null, sw);
env.setVariable("i2", i2);
try {
+ originalEnv.setOut(sw); // The imported macros are still bound to and will use this.
env.process();
assertEquals("2", sw.toString());
} catch (NullPointerException e) {
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateCallableModelTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateCallableModelTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateCallableModelTest.java
index a1e684d..8675d13 100644
--- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateCallableModelTest.java
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateCallableModelTest.java
@@ -219,7 +219,7 @@ public class TemplateCallableModelTest extends TemplateTest {
@Test
@SuppressWarnings("ThrowableNotThrown")
public void testRuntimeErrors() throws IOException, TemplateException {
- assertErrorContains("<@p 9, 9, 9 />", "can only have 2", "3", "by position");
+ assertErrorContains("<@p 9, 9, 9 />", "can only have 2", "more", "by position");
assertErrorContains("<@n 9 />", "can't have arguments passed by position");
assertErrorContains("<@n n3=9 />", "has no", "\"n3\"", "supported", "\"n1\", \"n2\"");
assertErrorContains("<@p n1=9 />", "directive", "can't have arguments that are passed by name", "\"n1\"",
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateLanguageTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateLanguageTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateLanguageTest.java
index 069394b..3bcc382 100644
--- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateLanguageTest.java
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateLanguageTest.java
@@ -67,12 +67,13 @@ public class TemplateLanguageTest {
public DummyTemplateLanguage(String fileExtension, OutputFormat outputFormat,
AutoEscapingPolicy autoEscapingPolicy) {
- super(fileExtension, outputFormat, autoEscapingPolicy);
+ super(fileExtension, DefaultDialect.INSTANCE, outputFormat, autoEscapingPolicy);
}
DummyTemplateLanguage(String fileExtension, boolean allowExtensionStartingWithF, OutputFormat outputFormat,
AutoEscapingPolicy autoEscapingPolicy) {
- super(fileExtension, allowExtensionStartingWithF, outputFormat, autoEscapingPolicy);
+ super(fileExtension, allowExtensionStartingWithF, DefaultDialect.INSTANCE,
+ outputFormat, autoEscapingPolicy);
}
@Override
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTComment.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTComment.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTComment.java
index 8a16965..2224fa1 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTComment.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTComment.java
@@ -24,6 +24,7 @@ import org.apache.freemarker.core.util._StringUtils;
/**
* AST comment node
*/
+//TODO [FM3] will be public
final class ASTComment extends ASTElement {
private final String text;
@@ -33,13 +34,13 @@ final class ASTComment extends ASTElement {
}
@Override
- ASTElement[] accept(Environment env) {
+ ASTElement[] execute(Environment env) {
// do nothing, skip the body
return null;
}
@Override
- protected String dump(boolean canonical) {
+ String dump(boolean canonical) {
if (canonical) {
return "<#--" + text + "-->";
} else {
@@ -48,10 +49,9 @@ final class ASTComment extends ASTElement {
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return "#--...--";
}
-
@Override
int getParameterCount() {
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDebugBreak.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDebugBreak.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDebugBreak.java
index 562a2cb..0634ffc 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDebugBreak.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDebugBreak.java
@@ -27,23 +27,24 @@ import org.apache.freemarker.core.debug._DebuggerService;
* AST node: A debug breakpoint
*/
class ASTDebugBreak extends ASTElement {
- public ASTDebugBreak(ASTElement nestedBlock) {
+
+ ASTDebugBreak(ASTElement nestedBlock) {
addChild(nestedBlock);
copyLocationFrom(nestedBlock);
}
@Override
- protected ASTElement[] accept(Environment env) throws TemplateException, IOException {
+ protected ASTElement[] execute(Environment env) throws TemplateException, IOException {
if (!_DebuggerService.suspendEnvironment(
- env, getTemplate().getSourceName(), getChild(0).getBeginLine())) {
- return getChild(0).accept(env);
+ env, getTemplate().getSourceName(), fastGetChild(0).getBeginLine())) {
+ return fastGetChild(0).execute(env);
} else {
throw new StopException(env, "Stopped by debugger");
}
}
@Override
- protected String dump(boolean canonical) {
+ String dump(boolean canonical) {
if (canonical) {
StringBuilder sb = new StringBuilder();
sb.append("<#-- ");
@@ -52,7 +53,7 @@ class ASTDebugBreak extends ASTElement {
sb.append(" /-->");
} else {
sb.append(" -->");
- sb.append(getChild(0).getCanonicalForm());
+ sb.append(fastGetChild(0).getCanonicalForm());
sb.append("<#--/ debug break -->");
}
return sb.toString();
@@ -62,7 +63,7 @@ class ASTDebugBreak extends ASTElement {
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return "#debugBreak";
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirAdhocTest1.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirAdhocTest1.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirAdhocTest1.java
new file mode 100644
index 0000000..69d40ef
--- /dev/null
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirAdhocTest1.java
@@ -0,0 +1,211 @@
+package org.apache.freemarker.core;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.IOException;
+import java.io.Writer;
+
+import org.apache.freemarker.core.model.ArgumentArrayLayout;
+import org.apache.freemarker.core.model.TemplateDirectiveModel;
+import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.model.impl.SimpleNumber;
+import org.apache.freemarker.core.outputformat.MarkupOutputFormat;
+import org.apache.freemarker.core.util.CallableUtils;
+import org.apache.freemarker.core.util.CommonSupplier;
+import org.apache.freemarker.core.util.StringToIndexMap;
+
+/**
+ * Example of an AST directive that's bound to some Configuration setting (the htmlOutputFormat in this case).
+ */
+//TODO [FM3][FREEMARKER-99] Delete this class when we are finished.
+class ASTDirAdhocTest1 extends ASTDirective {
+ private final MarkupOutputFormat<?> htmlOutputFormat;
+ private ASTExpression p1;
+ private ASTExpression p2;
+ private ASTExpression n1;
+ private ASTExpression n2;
+ private StringToIndexMap nestedContentParamNames;
+
+ private ASTDirAdhocTest1(MarkupOutputFormat<?> htmlOutputFormat) {
+ this.htmlOutputFormat = htmlOutputFormat;
+ }
+
+ static class Factory implements CommonSupplier<ASTDirective> {
+ private final MarkupOutputFormat<?> htmlOutputFormat;
+
+ Factory(MarkupOutputFormat<?> htmlOutputFormat) {
+ this.htmlOutputFormat = htmlOutputFormat;
+ }
+
+ @Override
+ public ASTDirective get() {
+ return new ASTDirAdhocTest1(htmlOutputFormat);
+ }
+ }
+
+ static TemplateDirectiveModel VALUE = new TemplateDirectiveModel() {
+
+ @Override
+ public void execute(TemplateModel[] args, CallPlace callPlace, Writer out, Environment env)
+ throws TemplateException, IOException {
+ throw new UnsupportedOperationException("execute not implemented");
+ }
+
+ @Override
+ public boolean isNestedContentSupported() {
+ return true;
+ }
+
+ @Override
+ public ArgumentArrayLayout getDirectiveArgumentArrayLayout() {
+ return ARGS_LAYOUT;
+ }
+
+ };
+
+ private static final ArgumentArrayLayout ARGS_LAYOUT = ArgumentArrayLayout.create(2, false,
+ StringToIndexMap.of("n1", 2, "n2", 3), false);
+
+ @Override
+ public void setPositionalArgument(int position, ASTExpression valueExp) throws StaticLinkingCheckException {
+ if (position == 0) {
+ p1 = valueExp;
+ } else if (position == 1) {
+ p2 = valueExp;
+ } else {
+ // TODO: Standardize error message; see CallableUtils
+ throw new StaticLinkingCheckException(new _ErrorDescriptionBuilder(
+ "Too many positional arguments; can only have ",
+ ARGS_LAYOUT.getPredefinedPositionalArgumentCount(), "."));
+ }
+ }
+
+ @Override
+ public void setNamedArgument(String name, ASTExpression valueExp) throws StaticLinkingCheckException {
+ if (name.equals("n1")) {
+ n1 = valueExp;
+ } else if (name.equals("n2")) {
+ n2 = valueExp;
+ } else {
+ // TODO: Standardize error message; see CallableUtils
+ throw new StaticLinkingCheckException(new _ErrorDescriptionBuilder(
+ "Unsupported parameter name ", new _DelayedJQuote(name), ". The supported parameters are: ",
+ new _DelayedJQuotedListing(ARGS_LAYOUT.getPredefinedNamedArgumentsMap().getKeys())));
+ }
+ }
+
+ @Override
+ public void checkArgumentsAndSetNestedContentParameters(StringToIndexMap nestedContentParamNames)
+ throws StaticLinkingCheckException {
+ // TODO: Standardize error message; see CallableUtils
+ if (p1 == null) {
+ throw new StaticLinkingCheckException(new _ErrorDescriptionBuilder(
+ "Missing mandatory ", new _DelayedOrdinal(1), " positional argument"));
+ }
+ // TODO: Standardize error message; see CallableUtils
+ if (n1 == null) {
+ throw new StaticLinkingCheckException(new _ErrorDescriptionBuilder(
+ "Missing mandatory named argument, ", new _DelayedJQuote("n1")));
+ }
+
+ // TODO: Make this check easier?
+ if (nestedContentParamNames == null || nestedContentParamNames.size() != 1) {
+ throw new StaticLinkingCheckException(
+ MessageUtils.newBadNumberOfNestedContentParameterPassedMessage(nestedContentParamNames, 1));
+ }
+ this.nestedContentParamNames = nestedContentParamNames;
+ }
+
+ @Override
+ public StringToIndexMap getNestedContentParamNames() {
+ return nestedContentParamNames;
+ }
+
+ @Override
+ ASTElement[] execute(Environment env) throws TemplateException, IOException {
+ env.pushElement(this);
+ try {
+ Writer out = env.getOut();
+ out.write("#foo(");
+ // TODO Bind to cfg.getOutputFormat("HTML")
+
+ int p1Int = CallableUtils.castArgumentValueToInt(p1.eval(env), 0, false, 0, VALUE, false);
+
+ env.interpolate(p1, htmlOutputFormat, AutoEscapingPolicy.ENABLE_IF_DEFAULT, env);
+ if (p2 != null) {
+ out.write(", ");
+ env.interpolate(p2, htmlOutputFormat, AutoEscapingPolicy.ENABLE_IF_DEFAULT, env);
+ }
+ out.write(", n1=");
+ env.interpolate(n1, htmlOutputFormat, AutoEscapingPolicy.ENABLE_IF_DEFAULT, env);
+ if (n2 != null) {
+ out.write(", n2=");
+ env.interpolate(n2, htmlOutputFormat, AutoEscapingPolicy.ENABLE_IF_DEFAULT, env);
+ }
+ out.write(") {\n");
+
+ for (int i = 0; i < p1Int; i++) {
+ env.executeNestedContent(this, nestedContentParamNames, new TemplateModel[] { new SimpleNumber(i) });
+ }
+
+ out.write("}-foo\n");
+ return null;
+ } finally {
+ env.popElement();
+ }
+ }
+
+ @Override
+ boolean isNestedBlockRepeater() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ String dump(boolean canonical) {
+ return "<#adhocTest1 ...>";
+ }
+
+ @Override
+ public String getLabelWithoutParameters() {
+ return "#adhocTest1";
+ }
+
+ @Override
+ int getParameterCount() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ Object getParameterValue(int idx) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ ParameterRole getParameterRole(int idx) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+
+
+}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirAdhocTest2.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirAdhocTest2.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirAdhocTest2.java
new file mode 100644
index 0000000..1b03af8
--- /dev/null
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirAdhocTest2.java
@@ -0,0 +1,165 @@
+package org.apache.freemarker.core;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.IOException;
+import java.io.Writer;
+
+import org.apache.freemarker.core.model.ArgumentArrayLayout;
+import org.apache.freemarker.core.model.TemplateDirectiveModel;
+import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.util.CallableUtils;
+import org.apache.freemarker.core.util.CommonSupplier;
+import org.apache.freemarker.core.util.StringToIndexMap;
+
+/**
+ * Example of an AST directive that's not bound to some Configuration setting.
+ */
+//TODO [FM3][FREEMARKER-99] Delete this class when we are finished.
+class ASTDirAdhocTest2 extends ASTDirective {
+ private ASTExpression countExp;
+
+ private ASTDirAdhocTest2() {
+ //
+ }
+
+ final static CommonSupplier<ASTDirective> FACTORY = new CommonSupplier<ASTDirective>() {
+ @Override
+ public ASTDirective get() throws Exception {
+ return new ASTDirAdhocTest2();
+ }
+ };
+
+ static TemplateDirectiveModel VALUE = new TemplateDirectiveModel() {
+
+ @Override
+ public void execute(TemplateModel[] args, CallPlace callPlace, Writer out, Environment env)
+ throws TemplateException, IOException {
+ throw new UnsupportedOperationException("execute not implemented");
+ }
+
+ @Override
+ public boolean isNestedContentSupported() {
+ return true;
+ }
+
+ @Override
+ public ArgumentArrayLayout getDirectiveArgumentArrayLayout() {
+ return ARGS_LAYOUT;
+ }
+
+ };
+
+ private static final ArgumentArrayLayout ARGS_LAYOUT = ArgumentArrayLayout.SINGLE_POSITIONAL_PARAMETER;
+
+ @Override
+ public void setPositionalArgument(int position, ASTExpression valueExp) throws StaticLinkingCheckException {
+ if (position == 0) {
+ countExp = valueExp;
+ } else {
+ // TODO: Standardize error message; see CallableUtils
+ throw new StaticLinkingCheckException(new _ErrorDescriptionBuilder(
+ "Too many positional arguments; can only have ",
+ ARGS_LAYOUT.getPredefinedPositionalArgumentCount(), "."));
+ }
+ }
+
+ @Override
+ public void setNamedArgument(String name, ASTExpression valueExp) throws StaticLinkingCheckException {
+ // TODO: Standardize error message; see CallableUtils
+ throw new StaticLinkingCheckException(new _ErrorDescriptionBuilder(
+ "Unsupported parameter name ", new _DelayedJQuote(name), ". This directive has no named parameters."));
+ }
+
+ @Override
+ public void checkArgumentsAndSetNestedContentParameters(StringToIndexMap nestedContentParamNames)
+ throws StaticLinkingCheckException {
+ // TODO: Standardize error message; see CallableUtils
+ if (countExp == null) {
+ throw new StaticLinkingCheckException(new _ErrorDescriptionBuilder(
+ "Missing mandatory ", new _DelayedOrdinal(1), " positional argument"));
+ }
+
+ // TODO: Standardize error message; see CallableUtils
+ if (nestedContentParamNames != null) {
+ throw new StaticLinkingCheckException("This directive doesn't support nested content parameters.");
+ }
+ }
+
+ @Override
+ public StringToIndexMap getNestedContentParamNames() {
+ return null;
+ }
+
+ @Override
+ ASTElement[] execute(Environment env) throws TemplateException, IOException {
+ env.pushElement(this);
+ try {
+ Writer out = env.getOut();
+ int count = CallableUtils.castArgumentValueToInt(countExp.eval(env), 0, false, 0, VALUE, false);
+ for (int i = 0; i < count; i++) {
+ out.write(".");
+ }
+ return null;
+ } finally {
+ env.popElement();
+ }
+ }
+
+ @Override
+ boolean isNestedBlockRepeater() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ String dump(boolean canonical) {
+ return "<#adhocTest2 ...>";
+ }
+
+ @Override
+ public String getLabelWithoutParameters() {
+ return "#adhocTest2";
+ }
+
+ @Override
+ int getParameterCount() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ Object getParameterValue(int idx) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ ParameterRole getParameterRole(int idx) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public boolean isNestedContentSupported() {
+ return false;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirAssignment.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirAssignment.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirAssignment.java
index 26a6d69..aba716d 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirAssignment.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirAssignment.java
@@ -102,7 +102,7 @@ final class ASTDirAssignment extends ASTDirective {
}
@Override
- ASTElement[] accept(Environment env) throws TemplateException {
+ ASTElement[] execute(Environment env) throws TemplateException {
final Environment.Namespace namespace;
if (namespaceExp == null) {
switch (scope) {
@@ -187,9 +187,9 @@ final class ASTDirAssignment extends ASTDirective {
}
@Override
- protected String dump(boolean canonical) {
+ String dump(boolean canonical) {
StringBuilder buf = new StringBuilder();
- String dn = getParent() instanceof ASTDirAssignmentsContainer ? null : getASTNodeDescriptor();
+ String dn = getParent() instanceof ASTDirAssignmentsContainer ? null : getLabelWithoutParameters();
if (dn != null) {
if (canonical) buf.append("<");
buf.append(dn);
@@ -217,7 +217,7 @@ final class ASTDirAssignment extends ASTDirective {
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return getDirectiveName(scope);
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirAssignmentsContainer.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirAssignmentsContainer.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirAssignmentsContainer.java
index 3cd1e91..b572795 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirAssignmentsContainer.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirAssignmentsContainer.java
@@ -44,17 +44,17 @@ final class ASTDirAssignmentsContainer extends ASTDirective {
this.namespaceExp = namespaceExp;
int ln = getChildCount();
for (int i = 0; i < ln; i++) {
- ((ASTDirAssignment) getChild(i)).setNamespaceExp(namespaceExp);
+ ((ASTDirAssignment) fastGetChild(i)).setNamespaceExp(namespaceExp);
}
}
@Override
- ASTElement[] accept(Environment env) throws TemplateException, IOException {
+ ASTElement[] execute(Environment env) throws TemplateException, IOException {
return getChildBuffer();
}
@Override
- protected String dump(boolean canonical) {
+ String dump(boolean canonical) {
StringBuilder buf = new StringBuilder();
if (canonical) buf.append('<');
buf.append(ASTDirAssignment.getDirectiveName(scope));
@@ -65,7 +65,7 @@ final class ASTDirAssignmentsContainer extends ASTDirective {
if (i != 0) {
buf.append(", ");
}
- ASTDirAssignment assignment = (ASTDirAssignment) getChild(i);
+ ASTDirAssignment assignment = (ASTDirAssignment) fastGetChild(i);
buf.append(assignment.getCanonicalForm());
}
} else {
@@ -103,7 +103,7 @@ final class ASTDirAssignmentsContainer extends ASTDirective {
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return ASTDirAssignment.getDirectiveName(scope);
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirAttemptRecoverContainer.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirAttemptRecoverContainer.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirAttemptRecoverContainer.java
index 19aff47..d996420 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirAttemptRecoverContainer.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirAttemptRecoverContainer.java
@@ -40,20 +40,20 @@ final class ASTDirAttemptRecoverContainer extends ASTDirective {
}
@Override
- ASTElement[] accept(Environment env) throws TemplateException, IOException {
+ ASTElement[] execute(Environment env) throws TemplateException, IOException {
env.visitAttemptRecover(this, attemptedSection, recoverySection);
return null;
}
@Override
- protected String dump(boolean canonical) {
+ String dump(boolean canonical) {
if (!canonical) {
- return getASTNodeDescriptor();
+ return getLabelWithoutParameters();
} else {
StringBuilder buf = new StringBuilder();
- buf.append("<").append(getASTNodeDescriptor()).append(">");
+ buf.append("<").append(getLabelWithoutParameters()).append(">");
buf.append(getChildrenCanonicalForm());
- buf.append("</").append(getASTNodeDescriptor()).append(">");
+ buf.append("</").append(getLabelWithoutParameters()).append(">");
return buf.toString();
}
}
@@ -76,7 +76,7 @@ final class ASTDirAttemptRecoverContainer extends ASTDirective {
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return "#attempt";
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirAutoEsc.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirAutoEsc.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirAutoEsc.java
index b982e56..9e52f30 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirAutoEsc.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirAutoEsc.java
@@ -31,21 +31,21 @@ final class ASTDirAutoEsc extends ASTDirective {
}
@Override
- ASTElement[] accept(Environment env) throws TemplateException, IOException {
+ ASTElement[] execute(Environment env) throws TemplateException, IOException {
return getChildBuffer();
}
@Override
- protected String dump(boolean canonical) {
+ String dump(boolean canonical) {
if (canonical) {
- return "<" + getASTNodeDescriptor() + "\">" + getChildrenCanonicalForm() + "</" + getASTNodeDescriptor() + ">";
+ return "<" + getLabelWithoutParameters() + "\">" + getChildrenCanonicalForm() + "</" + getLabelWithoutParameters() + ">";
} else {
- return getASTNodeDescriptor();
+ return getLabelWithoutParameters();
}
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return "#autoEsc";
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirBreak.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirBreak.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirBreak.java
index 128e684..428f4be 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirBreak.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirBreak.java
@@ -25,17 +25,17 @@ package org.apache.freemarker.core;
final class ASTDirBreak extends ASTDirective {
@Override
- ASTElement[] accept(Environment env) {
+ ASTElement[] execute(Environment env) {
throw BreakOrContinueException.BREAK_INSTANCE;
}
@Override
- protected String dump(boolean canonical) {
- return canonical ? "<" + getASTNodeDescriptor() + "/>" : getASTNodeDescriptor();
+ String dump(boolean canonical) {
+ return canonical ? "<" + getLabelWithoutParameters() + "/>" : getLabelWithoutParameters();
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return "#break";
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirCapturingAssignment.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirCapturingAssignment.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirCapturingAssignment.java
index 6fc4c5f..f151ba5 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirCapturingAssignment.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirCapturingAssignment.java
@@ -21,6 +21,7 @@ package org.apache.freemarker.core;
import java.io.IOException;
import java.io.StringWriter;
+import java.io.Writer;
import org.apache.freemarker.core.model.TemplateModel;
import org.apache.freemarker.core.model.impl.SimpleString;
@@ -46,13 +47,19 @@ final class ASTDirCapturingAssignment extends ASTDirective {
}
@Override
- ASTElement[] accept(Environment env) throws TemplateException, IOException {
+ ASTElement[] execute(Environment env) throws TemplateException, IOException {
ASTElement[] children = getChildBuffer();
TemplateModel capturedValue;
if (children != null) {
StringWriter out = new StringWriter();
- env.visit(children, out);
+ Writer prevOut = env.getOut();
+ try {
+ env.setOut(out);
+ env.executeElements(children);
+ } finally {
+ env.setOut(prevOut);
+ }
capturedValue = capturedStringToModel(out.toString());
} else {
capturedValue = capturedStringToModel("");
@@ -79,10 +86,10 @@ final class ASTDirCapturingAssignment extends ASTDirective {
}
@Override
- protected String dump(boolean canonical) {
+ String dump(boolean canonical) {
StringBuilder sb = new StringBuilder();
if (canonical) sb.append("<");
- sb.append(getASTNodeDescriptor());
+ sb.append(getLabelWithoutParameters());
sb.append(' ');
sb.append(varName);
if (namespaceExp != null) {
@@ -93,7 +100,7 @@ final class ASTDirCapturingAssignment extends ASTDirective {
sb.append('>');
sb.append(getChildrenCanonicalForm());
sb.append("</");
- sb.append(getASTNodeDescriptor());
+ sb.append(getLabelWithoutParameters());
sb.append('>');
} else {
sb.append(" = .nestedOutput");
@@ -102,7 +109,7 @@ final class ASTDirCapturingAssignment extends ASTDirective {
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return ASTDirAssignment.getDirectiveName(scope);
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirCase.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirCase.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirCase.java
index eca7ae4..6a4cfab 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirCase.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirCase.java
@@ -35,15 +35,15 @@ final class ASTDirCase extends ASTDirective {
}
@Override
- ASTElement[] accept(Environment env) {
+ ASTElement[] execute(Environment env) {
return getChildBuffer();
}
@Override
- protected String dump(boolean canonical) {
+ String dump(boolean canonical) {
StringBuilder sb = new StringBuilder();
if (canonical) sb.append('<');
- sb.append(getASTNodeDescriptor());
+ sb.append(getLabelWithoutParameters());
if (condition != null) {
sb.append(' ');
sb.append(condition.getCanonicalForm());
@@ -56,7 +56,7 @@ final class ASTDirCase extends ASTDirective {
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return condition != null ? "#case" : "#default";
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirCompress.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirCompress.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirCompress.java
index 6bdda37..b03c16d 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirCompress.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirCompress.java
@@ -34,30 +34,33 @@ final class ASTDirCompress extends ASTDirective {
}
@Override
- ASTElement[] accept(Environment env) throws TemplateException, IOException {
+ ASTElement[] execute(Environment env) throws TemplateException, IOException {
ASTElement[] childBuffer = getChildBuffer();
if (childBuffer != null) {
CompressWriter out = new CompressWriter(env.getOut(), 2048, false);
+ Writer prevOut = env.getOut();
try {
- env.visit(childBuffer, out);
+ env.setOut(out);
+ env.executeElements(childBuffer);
} finally {
out.close();
+ env.setOut(prevOut);
}
}
return null;
}
@Override
- protected String dump(boolean canonical) {
+ String dump(boolean canonical) {
if (canonical) {
- return "<" + getASTNodeDescriptor() + ">" + getChildrenCanonicalForm() + "</" + getASTNodeDescriptor() + ">";
+ return "<" + getLabelWithoutParameters() + ">" + getChildrenCanonicalForm() + "</" + getLabelWithoutParameters() + ">";
} else {
- return getASTNodeDescriptor();
+ return getLabelWithoutParameters();
}
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return "#compress";
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirContinue.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirContinue.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirContinue.java
index 4d18785..8ca7afa 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirContinue.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirContinue.java
@@ -25,17 +25,17 @@ package org.apache.freemarker.core;
final class ASTDirContinue extends ASTDirective {
@Override
- ASTElement[] accept(Environment env) {
+ ASTElement[] execute(Environment env) {
throw BreakOrContinueException.CONTINUE_INSTANCE;
}
@Override
- protected String dump(boolean canonical) {
- return canonical ? "<" + getASTNodeDescriptor() + "/>" : getASTNodeDescriptor();
+ String dump(boolean canonical) {
+ return canonical ? "<" + getLabelWithoutParameters() + "/>" : getLabelWithoutParameters();
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return "#continue";
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirElseOfList.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirElseOfList.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirElseOfList.java
index 31ebea7..6126904 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirElseOfList.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirElseOfList.java
@@ -31,24 +31,24 @@ final class ASTDirElseOfList extends ASTDirective {
}
@Override
- ASTElement[] accept(Environment env) throws TemplateException, IOException {
+ ASTElement[] execute(Environment env) throws TemplateException, IOException {
return getChildBuffer();
}
@Override
- protected String dump(boolean canonical) {
+ String dump(boolean canonical) {
if (canonical) {
StringBuilder buf = new StringBuilder();
- buf.append('<').append(getASTNodeDescriptor()).append('>');
+ buf.append('<').append(getLabelWithoutParameters()).append('>');
buf.append(getChildrenCanonicalForm());
return buf.toString();
} else {
- return getASTNodeDescriptor();
+ return getLabelWithoutParameters();
}
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return "#else";
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirEscape.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirEscape.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirEscape.java
index 7a324cd..57678d3 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirEscape.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirEscape.java
@@ -47,7 +47,7 @@ class ASTDirEscape extends ASTDirective {
}
@Override
- ASTElement[] accept(Environment env) throws TemplateException, IOException {
+ ASTElement[] execute(Environment env) throws TemplateException, IOException {
return getChildBuffer();
}
@@ -56,22 +56,22 @@ class ASTDirEscape extends ASTDirective {
}
@Override
- protected String dump(boolean canonical) {
+ String dump(boolean canonical) {
StringBuilder sb = new StringBuilder();
if (canonical) sb.append('<');
- sb.append(getASTNodeDescriptor())
+ sb.append(getLabelWithoutParameters())
.append(' ').append(_StringUtils.toFTLTopLevelIdentifierReference(variable))
.append(" as ").append(expr.getCanonicalForm());
if (canonical) {
sb.append('>');
sb.append(getChildrenCanonicalForm());
- sb.append("</").append(getASTNodeDescriptor()).append('>');
+ sb.append("</").append(getLabelWithoutParameters()).append('>');
}
return sb.toString();
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return "#escape";
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirFallback.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirFallback.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirFallback.java
index 255de11..0ddb5d6 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirFallback.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirFallback.java
@@ -27,18 +27,18 @@ import java.io.IOException;
final class ASTDirFallback extends ASTDirective {
@Override
- ASTElement[] accept(Environment env) throws IOException, TemplateException {
+ ASTElement[] execute(Environment env) throws IOException, TemplateException {
env.fallback();
return null;
}
@Override
- protected String dump(boolean canonical) {
- return canonical ? "<" + getASTNodeDescriptor() + "/>" : getASTNodeDescriptor();
+ String dump(boolean canonical) {
+ return canonical ? "<" + getLabelWithoutParameters() + "/>" : getLabelWithoutParameters();
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return "#fallback";
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirFlush.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirFlush.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirFlush.java
index 469eff8..0b2faed 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirFlush.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirFlush.java
@@ -27,18 +27,18 @@ import java.io.IOException;
final class ASTDirFlush extends ASTDirective {
@Override
- ASTElement[] accept(Environment env) throws IOException {
+ ASTElement[] execute(Environment env) throws IOException {
env.getOut().flush();
return null;
}
@Override
- protected String dump(boolean canonical) {
- return canonical ? "<" + getASTNodeDescriptor() + "/>" : getASTNodeDescriptor();
+ String dump(boolean canonical) {
+ return canonical ? "<" + getLabelWithoutParameters() + "/>" : getLabelWithoutParameters();
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return "#flush";
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirIfElseIfElseContainer.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirIfElseIfElseContainer.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirIfElseIfElseContainer.java
index 8a250bf..1c8fad7 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirIfElseIfElseContainer.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirIfElseIfElseContainer.java
@@ -38,10 +38,10 @@ final class ASTDirIfElseIfElseContainer extends ASTDirective {
}
@Override
- ASTElement[] accept(Environment env) throws TemplateException, IOException {
+ ASTElement[] execute(Environment env) throws TemplateException, IOException {
int ln = getChildCount();
for (int i = 0; i < ln; i++) {
- ASTDirIfOrElseOrElseIf cblock = (ASTDirIfOrElseOrElseIf) getChild(i);
+ ASTDirIfOrElseOrElseIf cblock = (ASTDirIfOrElseOrElseIf) fastGetChild(i);
ASTExpression condition = cblock.condition;
env.replaceElementStackTop(cblock);
if (condition == null || condition.evalToBoolean(env)) {
@@ -55,7 +55,7 @@ final class ASTDirIfElseIfElseContainer extends ASTDirective {
ASTElement postParseCleanup(boolean stripWhitespace)
throws ParseException {
if (getChildCount() == 1) {
- ASTDirIfOrElseOrElseIf cblock = (ASTDirIfOrElseOrElseIf) getChild(0);
+ ASTDirIfOrElseOrElseIf cblock = (ASTDirIfOrElseOrElseIf) fastGetChild(0);
cblock.setLocation(getTemplate(), cblock, this);
return cblock.postParseCleanup(stripWhitespace);
} else {
@@ -64,23 +64,23 @@ final class ASTDirIfElseIfElseContainer extends ASTDirective {
}
@Override
- protected String dump(boolean canonical) {
+ String dump(boolean canonical) {
if (canonical) {
StringBuilder buf = new StringBuilder();
int ln = getChildCount();
for (int i = 0; i < ln; i++) {
- ASTDirIfOrElseOrElseIf cblock = (ASTDirIfOrElseOrElseIf) getChild(i);
+ ASTDirIfOrElseOrElseIf cblock = (ASTDirIfOrElseOrElseIf) fastGetChild(i);
buf.append(cblock.dump(canonical));
}
buf.append("</#if>");
return buf.toString();
} else {
- return getASTNodeDescriptor();
+ return getLabelWithoutParameters();
}
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return "#if-#elseIf-#else-container";
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirIfOrElseOrElseIf.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirIfOrElseOrElseIf.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirIfOrElseOrElseIf.java
index 28178d9..cb6a8cf 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirIfOrElseOrElseIf.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirIfOrElseOrElseIf.java
@@ -44,7 +44,7 @@ final class ASTDirIfOrElseOrElseIf extends ASTDirective {
}
@Override
- ASTElement[] accept(Environment env) throws TemplateException, IOException {
+ ASTElement[] execute(Environment env) throws TemplateException, IOException {
if (condition == null || condition.evalToBoolean(env)) {
return getChildBuffer();
}
@@ -52,10 +52,10 @@ final class ASTDirIfOrElseOrElseIf extends ASTDirective {
}
@Override
- protected String dump(boolean canonical) {
+ String dump(boolean canonical) {
StringBuilder buf = new StringBuilder();
if (canonical) buf.append('<');
- buf.append(getASTNodeDescriptor());
+ buf.append(getLabelWithoutParameters());
if (condition != null) {
buf.append(' ');
buf.append(condition.getCanonicalForm());
@@ -71,7 +71,7 @@ final class ASTDirIfOrElseOrElseIf extends ASTDirective {
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
if (type == TYPE_ELSE) {
return "#else";
} else if (type == TYPE_IF) {
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirImport.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirImport.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirImport.java
index 88cfeb5..9d7b522 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirImport.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirImport.java
@@ -45,7 +45,7 @@ final class ASTDirImport extends ASTDirective {
}
@Override
- ASTElement[] accept(Environment env) throws TemplateException, IOException {
+ ASTElement[] execute(Environment env) throws TemplateException, IOException {
final String importedTemplateName = importedTemplateNameExp.evalAndCoerceToPlainText(env);
final String fullImportedTemplateName;
try {
@@ -68,10 +68,10 @@ final class ASTDirImport extends ASTDirective {
}
@Override
- protected String dump(boolean canonical) {
+ String dump(boolean canonical) {
StringBuilder buf = new StringBuilder();
if (canonical) buf.append('<');
- buf.append(getASTNodeDescriptor());
+ buf.append(getLabelWithoutParameters());
buf.append(' ');
buf.append(importedTemplateNameExp.getCanonicalForm());
buf.append(" as ");
@@ -81,7 +81,7 @@ final class ASTDirImport extends ASTDirective {
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return "#import";
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirInclude.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirInclude.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirInclude.java
index 76ce1f6..5afc30a 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirInclude.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirInclude.java
@@ -56,7 +56,7 @@ final class ASTDirInclude extends ASTDirective {
}
@Override
- ASTElement[] accept(Environment env) throws TemplateException, IOException {
+ ASTElement[] execute(Environment env) throws TemplateException, IOException {
final String includedTemplateName = includedTemplateNameExp.evalAndCoerceToPlainText(env);
final String fullIncludedTemplateName;
try {
@@ -93,10 +93,10 @@ final class ASTDirInclude extends ASTDirective {
}
@Override
- protected String dump(boolean canonical) {
+ String dump(boolean canonical) {
StringBuilder buf = new StringBuilder();
if (canonical) buf.append('<');
- buf.append(getASTNodeDescriptor());
+ buf.append(getLabelWithoutParameters());
buf.append(' ');
buf.append(includedTemplateNameExp.getCanonicalForm());
if (ignoreMissingExp != null) {
@@ -107,7 +107,7 @@ final class ASTDirInclude extends ASTDirective {
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return "#include";
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirItems.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirItems.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirItems.java
index cf85b77..04aaf94 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirItems.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirItems.java
@@ -43,12 +43,12 @@ class ASTDirItems extends ASTDirective {
}
@Override
- ASTElement[] accept(Environment env) throws TemplateException, IOException {
+ ASTElement[] execute(Environment env) throws TemplateException, IOException {
final IterationContext iterCtx = ASTDirList.findEnclosingIterationContext(env, null);
if (iterCtx == null) {
// The parser should prevent this situation
throw new TemplateException(env,
- getASTNodeDescriptor(), " without iteration in context");
+ getLabelWithoutParameters(), " without iteration in context");
}
iterCtx.loopForItemsElement(env, getChildBuffer(), nestedContentParamName, nestedContentParam2Name);
@@ -61,10 +61,10 @@ class ASTDirItems extends ASTDirective {
}
@Override
- protected String dump(boolean canonical) {
+ String dump(boolean canonical) {
StringBuilder sb = new StringBuilder();
if (canonical) sb.append('<');
- sb.append(getASTNodeDescriptor());
+ sb.append(getLabelWithoutParameters());
sb.append(" as ");
sb.append(_StringUtils.toFTLTopLevelIdentifierReference(nestedContentParamName));
if (nestedContentParam2Name != null) {
@@ -75,14 +75,14 @@ class ASTDirItems extends ASTDirective {
sb.append('>');
sb.append(getChildrenCanonicalForm());
sb.append("</");
- sb.append(getASTNodeDescriptor());
+ sb.append(getLabelWithoutParameters());
sb.append('>');
}
return sb.toString();
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return "#items";
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirList.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirList.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirList.java
index 8034018..201c96c 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirList.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirList.java
@@ -78,7 +78,7 @@ final class ASTDirList extends ASTDirective {
}
@Override
- ASTElement[] accept(Environment env) throws TemplateException, IOException {
+ ASTElement[] execute(Environment env) throws TemplateException, IOException {
acceptWithResult(env);
return null;
}
@@ -117,10 +117,10 @@ final class ASTDirList extends ASTDirective {
}
@Override
- protected String dump(boolean canonical) {
+ String dump(boolean canonical) {
StringBuilder buf = new StringBuilder();
if (canonical) buf.append('<');
- buf.append(getASTNodeDescriptor());
+ buf.append(getLabelWithoutParameters());
buf.append(' ');
buf.append(listedExp.getCanonicalForm());
if (nestedContentParamName != null) {
@@ -136,7 +136,7 @@ final class ASTDirList extends ASTDirective {
buf.append(getChildrenCanonicalForm());
if (!(getParent() instanceof ASTDirListElseContainer)) {
buf.append("</");
- buf.append(getASTNodeDescriptor());
+ buf.append(getLabelWithoutParameters());
buf.append('>');
}
}
@@ -179,7 +179,7 @@ final class ASTDirList extends ASTDirective {
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return "#list";
}
@@ -266,7 +266,7 @@ final class ASTDirList extends ASTDirective {
nestedContentParam = iterModel.next();
hasNext = iterModel.hasNext();
try {
- env.visit(childBuffer);
+ env.executeElements(childBuffer);
} catch (BreakOrContinueException br) {
if (br == BreakOrContinueException.BREAK_INSTANCE) {
break listLoop;
@@ -279,7 +279,7 @@ final class ASTDirList extends ASTDirective {
// We must reuse this later, because TemplateIterableModel-s that wrap an Iterator only
// allow one iterator() call.
openedIterator = iterModel;
- env.visit(childBuffer);
+ env.executeElements(childBuffer);
}
}
} else if (listedValue instanceof TemplateHashModelEx) {
@@ -316,7 +316,7 @@ final class ASTDirList extends ASTDirective {
nestedContentParam2 = kvp.getValue();
hasNext = kvpIter.hasNext();
try {
- env.visit(childBuffer);
+ env.executeElements(childBuffer);
} catch (BreakOrContinueException br) {
if (br == BreakOrContinueException.BREAK_INSTANCE) {
break listLoop;
@@ -328,7 +328,7 @@ final class ASTDirList extends ASTDirective {
} else {
// We will reuse this at the #iterms
openedIterator = kvpIter;
- env.visit(childBuffer);
+ env.executeElements(childBuffer);
}
}
} else if (listedValue instanceof TemplateIterableModel) {
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirListElseContainer.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirListElseContainer.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirListElseContainer.java
index 686b03c..47cc9f7 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirListElseContainer.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirListElseContainer.java
@@ -37,9 +37,9 @@ class ASTDirListElseContainer extends ASTDirective {
}
@Override
- ASTElement[] accept(Environment env) throws TemplateException, IOException {
+ ASTElement[] execute(Environment env) throws TemplateException, IOException {
if (!listPart.acceptWithResult(env)) {
- return elsePart.accept(env);
+ return elsePart.execute(env);
}
return null;
}
@@ -50,23 +50,23 @@ class ASTDirListElseContainer extends ASTDirective {
}
@Override
- protected String dump(boolean canonical) {
+ String dump(boolean canonical) {
if (canonical) {
StringBuilder buf = new StringBuilder();
int ln = getChildCount();
for (int i = 0; i < ln; i++) {
- ASTElement element = getChild(i);
+ ASTElement element = fastGetChild(i);
buf.append(element.dump(canonical));
}
buf.append("</#list>");
return buf.toString();
} else {
- return getASTNodeDescriptor();
+ return getLabelWithoutParameters();
}
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return "#list-#else-container";
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirMacroOrFunction.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirMacroOrFunction.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirMacroOrFunction.java
index 786bfcf..3c64eaa 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirMacroOrFunction.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirMacroOrFunction.java
@@ -112,13 +112,13 @@ final class ASTDirMacroOrFunction extends ASTDirective implements TemplateModel
}
@Override
- ASTElement[] accept(Environment env) {
+ ASTElement[] execute(Environment env) {
env.visitMacroOrFunctionDefinition(this);
return null;
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return function ? "#function" : "#macro";
}
@@ -138,10 +138,10 @@ final class ASTDirMacroOrFunction extends ASTDirective implements TemplateModel
}
@Override
- protected String dump(boolean canonical) {
+ String dump(boolean canonical) {
StringBuilder sb = new StringBuilder();
if (canonical) sb.append('<');
- sb.append(getASTNodeDescriptor());
+ sb.append(getLabelWithoutParameters());
sb.append(' ');
sb.append(_StringUtils.toFTLTopLevelTragetIdentifier(name));
@@ -236,7 +236,7 @@ final class ASTDirMacroOrFunction extends ASTDirective implements TemplateModel
if (canonical) {
sb.append('>');
sb.append(getChildrenCanonicalForm());
- sb.append("</").append(getASTNodeDescriptor()).append('>');
+ sb.append("</").append(getLabelWithoutParameters()).append('>');
}
return sb.toString();
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirNested.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirNested.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirNested.java
index 25344e6..df0074e 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirNested.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirNested.java
@@ -42,7 +42,7 @@ final class ASTDirNested extends ASTDirective {
}
@Override
- ASTElement[] accept(Environment env) throws IOException, TemplateException {
+ ASTElement[] execute(Environment env) throws IOException, TemplateException {
CallPlace macroCallPlace = env.getCurrentMacroContext().callPlace;
// When nestedContParamCnt < nestedContentParameters.getCollectionSize(), then we just skip calculating the
@@ -68,10 +68,10 @@ final class ASTDirNested extends ASTDirective {
}
@Override
- protected String dump(boolean canonical) {
+ String dump(boolean canonical) {
StringBuilder sb = new StringBuilder();
if (canonical) sb.append('<');
- sb.append(getASTNodeDescriptor());
+ sb.append(getLabelWithoutParameters());
if (nestedContentParameters != null) {
for (int i = 0; i < nestedContentParameters.size(); i++) {
sb.append(' ');
@@ -83,7 +83,7 @@ final class ASTDirNested extends ASTDirective {
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return "#nested";
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirNoAutoEsc.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirNoAutoEsc.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirNoAutoEsc.java
index a3ef03d..5bbc6c7 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirNoAutoEsc.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirNoAutoEsc.java
@@ -31,21 +31,21 @@ final class ASTDirNoAutoEsc extends ASTDirective {
}
@Override
- ASTElement[] accept(Environment env) throws TemplateException, IOException {
+ ASTElement[] execute(Environment env) throws TemplateException, IOException {
return getChildBuffer();
}
@Override
- protected String dump(boolean canonical) {
+ String dump(boolean canonical) {
if (canonical) {
- return "<" + getASTNodeDescriptor() + "\">" + getChildrenCanonicalForm() + "</" + getASTNodeDescriptor() + ">";
+ return "<" + getLabelWithoutParameters() + "\">" + getChildrenCanonicalForm() + "</" + getLabelWithoutParameters() + ">";
} else {
- return getASTNodeDescriptor();
+ return getLabelWithoutParameters();
}
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return "#noAutoEsc";
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirNoEscape.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirNoEscape.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirNoEscape.java
index 61a32b8..b3af156 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirNoEscape.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirNoEscape.java
@@ -31,17 +31,17 @@ class ASTDirNoEscape extends ASTDirective {
}
@Override
- ASTElement[] accept(Environment env) throws TemplateException, IOException {
+ ASTElement[] execute(Environment env) throws TemplateException, IOException {
return getChildBuffer();
}
@Override
- protected String dump(boolean canonical) {
+ String dump(boolean canonical) {
if (canonical) {
- return "<" + getASTNodeDescriptor() + '>' + getChildrenCanonicalForm()
- + "</" + getASTNodeDescriptor() + '>';
+ return "<" + getLabelWithoutParameters() + '>' + getChildrenCanonicalForm()
+ + "</" + getLabelWithoutParameters() + '>';
} else {
- return getASTNodeDescriptor();
+ return getLabelWithoutParameters();
}
}
@@ -61,7 +61,7 @@ class ASTDirNoEscape extends ASTDirective {
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return "#noEscape";
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirOutputFormat.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirOutputFormat.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirOutputFormat.java
index c2aa7b8..33912ab 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirOutputFormat.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirOutputFormat.java
@@ -34,22 +34,22 @@ final class ASTDirOutputFormat extends ASTDirective {
}
@Override
- ASTElement[] accept(Environment env) throws TemplateException, IOException {
+ ASTElement[] execute(Environment env) throws TemplateException, IOException {
return getChildBuffer();
}
@Override
- protected String dump(boolean canonical) {
+ String dump(boolean canonical) {
if (canonical) {
- return "<" + getASTNodeDescriptor() + " \"" + paramExp.getCanonicalForm() + "\">"
- + getChildrenCanonicalForm() + "</" + getASTNodeDescriptor() + ">";
+ return "<" + getLabelWithoutParameters() + " \"" + paramExp.getCanonicalForm() + "\">"
+ + getChildrenCanonicalForm() + "</" + getLabelWithoutParameters() + ">";
} else {
- return getASTNodeDescriptor();
+ return getLabelWithoutParameters();
}
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return "#outputFormat";
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirRecover.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirRecover.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirRecover.java
index 7879f18..b441eeb 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirRecover.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirRecover.java
@@ -31,24 +31,24 @@ final class ASTDirRecover extends ASTDirective {
}
@Override
- ASTElement[] accept(Environment env) throws TemplateException, IOException {
+ ASTElement[] execute(Environment env) throws TemplateException, IOException {
return getChildBuffer();
}
@Override
- protected String dump(boolean canonical) {
+ String dump(boolean canonical) {
if (canonical) {
StringBuilder buf = new StringBuilder();
- buf.append('<').append(getASTNodeDescriptor()).append('>');
+ buf.append('<').append(getLabelWithoutParameters()).append('>');
buf.append(getChildrenCanonicalForm());
return buf.toString();
} else {
- return getASTNodeDescriptor();
+ return getLabelWithoutParameters();
}
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return "#recover";
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirRecurse.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirRecurse.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirRecurse.java
index 1904edc..1a491f5 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirRecurse.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirRecurse.java
@@ -41,7 +41,7 @@ final class ASTDirRecurse extends ASTDirective {
}
@Override
- ASTElement[] accept(Environment env) throws IOException, TemplateException {
+ ASTElement[] execute(Environment env) throws IOException, TemplateException {
TemplateModel node = targetNode == null ? null : targetNode.eval(env);
if (node != null && !(node instanceof TemplateNodeModel)) {
throw MessageUtils.newUnexpectedOperandTypeException(
@@ -75,10 +75,10 @@ final class ASTDirRecurse extends ASTDirective {
}
@Override
- protected String dump(boolean canonical) {
+ String dump(boolean canonical) {
StringBuilder sb = new StringBuilder();
if (canonical) sb.append('<');
- sb.append(getASTNodeDescriptor());
+ sb.append(getLabelWithoutParameters());
if (targetNode != null) {
sb.append(' ');
sb.append(targetNode.getCanonicalForm());
@@ -92,7 +92,7 @@ final class ASTDirRecurse extends ASTDirective {
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return "#recurse";
}
http://git-wip-us.apache.org/repos/asf/freemarker/blob/e8e58ffa/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirReturn.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirReturn.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirReturn.java
index c5d23b3..5a24eef 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirReturn.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDirReturn.java
@@ -31,7 +31,7 @@ final class ASTDirReturn extends ASTDirective {
}
@Override
- ASTElement[] accept(Environment env) throws TemplateException {
+ ASTElement[] execute(Environment env) throws TemplateException {
if (exp != null) {
env.setLastReturnValue(exp.eval(env));
}
@@ -43,10 +43,10 @@ final class ASTDirReturn extends ASTDirective {
}
@Override
- protected String dump(boolean canonical) {
+ String dump(boolean canonical) {
StringBuilder sb = new StringBuilder();
if (canonical) sb.append('<');
- sb.append(getASTNodeDescriptor());
+ sb.append(getLabelWithoutParameters());
if (exp != null) {
sb.append(' ');
sb.append(exp.getCanonicalForm());
@@ -56,7 +56,7 @@ final class ASTDirReturn extends ASTDirective {
}
@Override
- String getASTNodeDescriptor() {
+ public String getLabelWithoutParameters() {
return "#return";
}