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:31 UTC
[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
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);
+ }
+
+ }
+
+}