/*
 * 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 freemarker.core;

import freemarker.template.Template;

Internal API - subject to change: Represent a node in the parsed template (either a Expression or a TemplateElement).
See Also:
Deprecated:This is an internal FreeMarker API with no backward compatibility guarantees, so you shouldn't depend on it.
/** * <b>Internal API - subject to change:</b> Represent a node in the parsed template (either a {@link Expression} or a * {@link TemplateElement}). * * @see TemplateElement * @see Expression * * @deprecated This is an internal FreeMarker API with no backward compatibility guarantees, so you shouldn't depend on * it. */
@Deprecated public abstract class TemplateObject { private Template template; int beginColumn, beginLine, endColumn, endLine;
This is needed for an ?eval hack; the expression AST nodes will be the descendants of the template, however, we can't give their position in the template, only in the dynamic string that's evaluated. That's signaled by a negative line numbers, starting from this constant as line 1.
/** This is needed for an ?eval hack; the expression AST nodes will be the descendants of the template, however, * we can't give their position in the template, only in the dynamic string that's evaluated. That's signaled * by a negative line numbers, starting from this constant as line 1. */
static final int RUNTIME_EVAL_LINE_DISPLACEMENT = -1000000000; final void setLocation(Template template, Token begin, Token end) { setLocation(template, begin.beginColumn, begin.beginLine, end.endColumn, end.endLine); } final void setLocation(Template template, Token tagBegin, Token tagEnd, TemplateElements children) { TemplateElement lastChild = children.getLast(); if (lastChild != null) { // [<#if exp>children]<#else> setLocation(template, tagBegin, lastChild); } else { // [<#if exp>]<#else> setLocation(template, tagBegin, tagEnd); } } final void setLocation(Template template, Token begin, TemplateObject end) { setLocation(template, begin.beginColumn, begin.beginLine, end.endColumn, end.endLine); } final void setLocation(Template template, TemplateObject begin, Token end) { setLocation(template, begin.beginColumn, begin.beginLine, end.endColumn, end.endLine); } final void setLocation(Template template, TemplateObject begin, TemplateObject end) { setLocation(template, begin.beginColumn, begin.beginLine, end.endColumn, end.endLine); } void setLocation(Template template, int beginColumn, int beginLine, int endColumn, int endLine) { this.template = template; this.beginColumn = beginColumn; this.beginLine = beginLine; this.endColumn = endColumn; this.endLine = endLine; } public final int getBeginColumn() { return beginColumn; } 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.
/** * Returns a string that indicates * where in the template source, this object is. */
public String getStartLocation() { return _MessageUtil.formatLocationForEvaluationError(template, beginLine, beginColumn); }
As of 2.3.20. the same as getStartLocation. Meant to be used where there's a risk of XSS when viewing error messages.
/** * 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. */
public String getStartLocationQuoted() { return getStartLocation(); } public String getEndLocation() { return _MessageUtil.formatLocationForEvaluationError(template, endLine, endColumn); }
As of 2.3.20. the same as getEndLocation. Meant to be used where there's a risk of XSS when viewing error messages.
/** * 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() { String s; if (template != null) { s = template.getSource(beginColumn, beginLine, endColumn, endLine); } else { s = null; } // Can't just return null for backward-compatibility... return s != null ? s : getCanonicalForm(); } @Override public String toString() { String s; try { s = getSource(); } catch (Exception e) { // REVISIT: A bit of a hack? (JR) s = null; } return s != null ? s : getCanonicalForm(); }
Returns:whether the point in the template file specified by the column and line numbers is contained within this template object.
/** * @return whether the point in the template file specified by the * column and line numbers is contained within this template object. */
public boolean contains(int column, int line) { if (line < beginLine || line > endLine) { return false; } if (line == beginLine) { if (column < beginColumn) { return false; } } if (line == endLine) { if (column > endColumn) { return false; } } return true; } public Template getTemplate() { return template; } TemplateObject copyLocationFrom(TemplateObject from) { template = from.template; beginColumn = from.beginColumn; beginLine = from.beginLine; endColumn = from.endColumn; endLine = from.endLine; return this; }
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.
See Also:
/** * 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. * * @see TemplateElement#getDescription() * @see #getNodeTypeSymbol() */
abstract public String getCanonicalForm();
A very sort single-line string that describes what kind of AST node this is, without describing any embedded expression or child element. Examples: "#if", "+", "${...}. These values should be suitable as tree node labels in a tree view. Yet, they should be consistent and complete enough so that an AST that is equivalent with the original could be reconstructed from the tree view. Thus, for literal values that are leaf nodes the symbols should be the canonical form of value.
See Also:
/** * A very sort single-line string that describes what kind of AST node this is, without describing any * embedded expression or child element. Examples: {@code "#if"}, {@code "+"}, <tt>"${...}</tt>. These values should * be suitable as tree node labels in a tree view. Yet, they should be consistent and complete enough so that an AST * that is equivalent with the original could be reconstructed from the tree view. Thus, for literal values that are * leaf nodes the symbols should be the canonical form of value. * * @see #getCanonicalForm() * @see TemplateElement#getDescription() */
abstract String getNodeTypeSymbol();
Returns highest valid parameter index + 1. So one should scan indexes with getParameterValue(int) starting from 0 up until but excluding this. For example, for the binary "+" operator this will give 2, so the legal indexes are 0 and 1. Note that if a parameter is optional in a template-object-type and happens to be omitted in an instance, this will still return the same value and the value of that parameter will be null.
/** * Returns highest valid parameter index + 1. So one should scan indexes with {@link #getParameterValue(int)} * starting from 0 up until but excluding this. For example, for the binary "+" operator this will give 2, so the * legal indexes are 0 and 1. Note that if a parameter is optional in a template-object-type and happens to be * omitted in an instance, this will still return the same value and the value of that parameter will be * {@code null}. */
abstract int getParameterCount();
Returns the value of the parameter identified by the index. For example, the binary "+" operator will have an LHO Expression at index 0, and and RHO Expression at index 1. Or, the binary "." operator will have an LHO Expression at index 0, and an RHO String(!) at index 1. Or, the #include directive will have a path Expression at index 0, a "parse" Expression at index 1, etc.

The index value doesn't correspond to the source-code location in general. It's an arbitrary identifier that corresponds to the role of the parameter instead. This also means that when a parameter is omitted, the index of the other parameters won't shift. @return null or any kind of Object, very often an Expression. However, if there's a TemplateObject stored inside the returned value, it must itself be be a TemplateObject too, otherwise the AST couldn't be (easily) fully traversed. That is, non-TemplateObject values can only be used for leafs. @throws IndexOutOfBoundsException if idx is less than 0 or not less than getParameterCount().

/** * Returns the value of the parameter identified by the index. For example, the binary "+" operator will have an * LHO {@link Expression} at index 0, and and RHO {@link Expression} at index 1. Or, the binary "." operator will * have an LHO {@link Expression} at index 0, and an RHO {@link String}(!) at index 1. Or, the {@code #include} * directive will have a path {@link Expression} at index 0, a "parse" {@link Expression} at index 1, etc. * * <p>The index value doesn't correspond to the source-code location in general. It's an arbitrary identifier * that corresponds to the role of the parameter instead. This also means that when a parameter is omitted, the * index of the other parameters won't shift. * * @return {@code null} or any kind of {@link Object}, very often an {@link Expression}. However, if there's * a {@link TemplateObject} stored inside the returned value, it must itself be be a {@link TemplateObject} * too, otherwise the AST couldn't be (easily) fully traversed. That is, non-{@link TemplateObject} values * can only be used for leafs. * * @throws IndexOutOfBoundsException if {@code idx} is less than 0 or not less than {@link #getParameterCount()}. */
abstract Object getParameterValue(int idx);
Returns the role of the parameter at the given index, like ParameterRole.LEFT_HAND_OPERAND. As of this writing (2013-06-17), for directive parameters it will always give ParameterRole.UNKNOWN, because there was no need to be more specific so far. This should be improved as need. @throws IndexOutOfBoundsException if idx is less than 0 or not less than getParameterCount().
/** * Returns the role of the parameter at the given index, like {@link ParameterRole#LEFT_HAND_OPERAND}. * * As of this writing (2013-06-17), for directive parameters it will always give {@link ParameterRole#UNKNOWN}, * because there was no need to be more specific so far. This should be improved as need. * * @throws IndexOutOfBoundsException if {@code idx} is less than 0 or not less than {@link #getParameterCount()}. */
abstract ParameterRole getParameterRole(int idx); }