http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/7d784b2b/src/main/java/org/apache/freemarker/core/ast/EscapeBlock.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/freemarker/core/ast/EscapeBlock.java b/src/main/java/org/apache/freemarker/core/ast/EscapeBlock.java deleted file mode 100644 index 07f02b5..0000000 --- a/src/main/java/org/apache/freemarker/core/ast/EscapeBlock.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.freemarker.core.ast; - -import java.io.IOException; - -import org.apache.freemarker.core.TemplateException; -import org.apache.freemarker.core.ast.Expression.ReplacemenetState; -import org.apache.freemarker.core.util._StringUtil; - -/** - * Representation of the compile-time #escape directive. - */ -class EscapeBlock extends TemplateElement { - - private final String variable; - private final Expression expr; - private Expression escapedExpr; - - - EscapeBlock(String variable, Expression expr, Expression escapedExpr) { - this.variable = variable; - this.expr = expr; - this.escapedExpr = escapedExpr; - } - - void setContent(TemplateElements children) { - setChildren(children); - // We don't need it anymore at this point - escapedExpr = null; - } - - @Override - TemplateElement[] accept(Environment env) throws TemplateException, IOException { - return getChildBuffer(); - } - - Expression doEscape(Expression expression) { - return escapedExpr.deepCloneWithIdentifierReplaced(variable, expression, new ReplacemenetState()); - } - - @Override - protected String dump(boolean canonical) { - StringBuilder sb = new StringBuilder(); - if (canonical) sb.append('<'); - sb.append(getNodeTypeSymbol()) - .append(' ').append(_StringUtil.toFTLTopLevelIdentifierReference(variable)) - .append(" as ").append(expr.getCanonicalForm()); - if (canonical) { - sb.append('>'); - sb.append(getChildrenCanonicalForm()); - sb.append("</").append(getNodeTypeSymbol()).append('>'); - } - return sb.toString(); - } - - @Override - String getNodeTypeSymbol() { - return "#escape"; - } - - @Override - int getParameterCount() { - return 2; - } - - @Override - Object getParameterValue(int idx) { - switch (idx) { - case 0: return variable; - case 1: return expr; - default: throw new IndexOutOfBoundsException(); - } - } - - @Override - ParameterRole getParameterRole(int idx) { - switch (idx) { - case 0: return ParameterRole.PLACEHOLDER_VARIABLE; - case 1: return ParameterRole.EXPRESSION_TEMPLATE; - default: throw new IndexOutOfBoundsException(); - } - } - - @Override - boolean isOutputCacheable() { - return true; - } - - @Override - boolean isNestedBlockRepeater() { - return false; - } - -}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/7d784b2b/src/main/java/org/apache/freemarker/core/ast/EvalUtil.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/freemarker/core/ast/EvalUtil.java b/src/main/java/org/apache/freemarker/core/ast/EvalUtil.java deleted file mode 100644 index a55769d..0000000 --- a/src/main/java/org/apache/freemarker/core/ast/EvalUtil.java +++ /dev/null @@ -1,540 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.freemarker.core.ast; - -import java.util.Date; - -import org.apache.freemarker.core.TemplateException; -import org.apache.freemarker.core.model.TemplateBooleanModel; -import org.apache.freemarker.core.model.TemplateCollectionModel; -import org.apache.freemarker.core.model.TemplateDateModel; -import org.apache.freemarker.core.model.TemplateModel; -import org.apache.freemarker.core.model.TemplateModelException; -import org.apache.freemarker.core.model.TemplateNumberModel; -import org.apache.freemarker.core.model.TemplateScalarModel; -import org.apache.freemarker.core.model.TemplateSequenceModel; - -/** - * Internally used static utilities for evaluation expressions. - */ -class EvalUtil { - static final int CMP_OP_EQUALS = 1; - static final int CMP_OP_NOT_EQUALS = 2; - static final int CMP_OP_LESS_THAN = 3; - static final int CMP_OP_GREATER_THAN = 4; - static final int CMP_OP_LESS_THAN_EQUALS = 5; - static final int CMP_OP_GREATER_THAN_EQUALS = 6; - // If you add a new operator here, update the "compare" and "cmpOpToString" methods! - - // Prevents instantination. - private EvalUtil() { } - - /** - * @param expr {@code null} is allowed, but may results in less helpful error messages - * @param env {@code null} is allowed - */ - static String modelToString(TemplateScalarModel model, Expression expr, Environment env) - throws TemplateModelException { - String value = model.getAsString(); - if (value == null) { - throw newModelHasStoredNullException(String.class, model, expr); - } - return value; - } - - /** - * @param expr {@code null} is allowed, but may results in less helpful error messages - */ - static Number modelToNumber(TemplateNumberModel model, Expression expr) - throws TemplateModelException { - Number value = model.getAsNumber(); - if (value == null) throw newModelHasStoredNullException(Number.class, model, expr); - return value; - } - - /** - * @param expr {@code null} is allowed, but may results in less helpful error messages - */ - static Date modelToDate(TemplateDateModel model, Expression expr) - throws TemplateModelException { - Date value = model.getAsDate(); - if (value == null) throw newModelHasStoredNullException(Date.class, model, expr); - return value; - } - - /** Signals the buggy case where we have a non-null model, but it wraps a null. */ - static TemplateModelException newModelHasStoredNullException( - Class expected, TemplateModel model, Expression expr) { - return new _TemplateModelException(expr, - _TemplateModelException.modelHasStoredNullDescription(expected, model)); - } - - /** - * Compares two expressions according the rules of the FTL comparator operators. - * - * @param leftExp not {@code null} - * @param operator one of the {@code COMP_OP_...} constants, like {@link #CMP_OP_EQUALS}. - * @param operatorString can be null {@code null}; the actual operator used, used for more accurate error message. - * @param rightExp not {@code null} - * @param env {@code null} is tolerated, but should be avoided - */ - static boolean compare( - Expression leftExp, - int operator, String operatorString, - Expression rightExp, - Expression defaultBlamed, - Environment env) throws TemplateException { - TemplateModel ltm = leftExp.eval(env); - TemplateModel rtm = rightExp.eval(env); - return compare( - ltm, leftExp, - operator, operatorString, - rtm, rightExp, - defaultBlamed, false, - false, false, false, - env); - } - - /** - * Compares values according the rules of the FTL comparator operators; if the {@link Expression}-s are - * accessible, use {@link #compare(Expression, int, String, Expression, Expression, Environment)} instead, as - * that gives better error messages. - * - * @param leftValue maybe {@code null}, which will usually cause the appropriate {@link TemplateException}. - * @param operator one of the {@code COMP_OP_...} constants, like {@link #CMP_OP_EQUALS}. - * @param rightValue maybe {@code null}, which will usually cause the appropriate {@link TemplateException}. - * @param env {@code null} is tolerated, but should be avoided - */ - static boolean compare( - TemplateModel leftValue, int operator, TemplateModel rightValue, - Environment env) throws TemplateException { - return compare( - leftValue, null, - operator, null, - rightValue, null, - null, false, - false, false, false, - env); - } - - /** - * Same as {@link #compare(TemplateModel, int, TemplateModel, Environment)}, but if the two types are incompatible, - * they are treated as non-equal instead of throwing an exception. Comparing dates of different types will - * still throw an exception, however. - */ - static boolean compareLenient( - TemplateModel leftValue, int operator, TemplateModel rightValue, - Environment env) throws TemplateException { - return compare( - leftValue, null, - operator, null, - rightValue, null, - null, false, - true, false, false, - env); - } - - private static final String VALUE_OF_THE_COMPARISON_IS_UNKNOWN_DATE_LIKE - = "value of the comparison is a date-like value where " - + "it's not known if it's a date (no time part), time, or date-time, " - + "and thus can't be used in a comparison."; - - /** - * @param leftExp {@code null} is allowed, but may results in less helpful error messages - * @param operator one of the {@code COMP_OP_...} constants, like {@link #CMP_OP_EQUALS}. - * @param operatorString can be null {@code null}; the actual operator used, used for more accurate error message. - * @param rightExp {@code null} is allowed, but may results in less helpful error messages - * @param defaultBlamed {@code null} allowed; the expression to which the error will point to if something goes - * wrong that is not specific to the left or right side expression, or if that expression is {@code null}. - * @param typeMismatchMeansNotEqual If the two types are incompatible, they are treated as non-equal instead - * of throwing an exception. Comparing dates of different types will still throw an exception, however. - * @param leftNullReturnsFalse if {@code true}, a {@code null} left value will not cause exception, but make the - * expression {@code false}. - * @param rightNullReturnsFalse if {@code true}, a {@code null} right value will not cause exception, but make the - * expression {@code false}. - */ - static boolean compare( - TemplateModel leftValue, Expression leftExp, - int operator, String operatorString, - TemplateModel rightValue, Expression rightExp, - Expression defaultBlamed, boolean quoteOperandsInErrors, - boolean typeMismatchMeansNotEqual, - boolean leftNullReturnsFalse, boolean rightNullReturnsFalse, - Environment env) throws TemplateException { - if (leftValue == null) { - if (leftNullReturnsFalse) { - return false; - } else { - if (leftExp != null) { - throw InvalidReferenceException.getInstance(leftExp, env); - } else { - throw new _MiscTemplateException(defaultBlamed, env, - "The left operand of the comparison was undefined or null."); - } - } - } - - if (rightValue == null) { - if (rightNullReturnsFalse) { - return false; - } else { - if (rightExp != null) { - throw InvalidReferenceException.getInstance(rightExp, env); - } else { - throw new _MiscTemplateException(defaultBlamed, env, - "The right operand of the comparison was undefined or null."); - } - } - } - - final int cmpResult; - if (leftValue instanceof TemplateNumberModel && rightValue instanceof TemplateNumberModel) { - Number leftNum = EvalUtil.modelToNumber((TemplateNumberModel) leftValue, leftExp); - Number rightNum = EvalUtil.modelToNumber((TemplateNumberModel) rightValue, rightExp); - ArithmeticEngine ae = - env != null - ? env.getArithmeticEngine() - : (leftExp != null - ? leftExp.getTemplate().getArithmeticEngine() - : ArithmeticEngine.BIGDECIMAL_ENGINE); - try { - cmpResult = ae.compareNumbers(leftNum, rightNum); - } catch (RuntimeException e) { - throw new _MiscTemplateException(defaultBlamed, e, env, new Object[] - { "Unexpected error while comparing two numbers: ", e }); - } - } else if (leftValue instanceof TemplateDateModel && rightValue instanceof TemplateDateModel) { - TemplateDateModel leftDateModel = (TemplateDateModel) leftValue; - TemplateDateModel rightDateModel = (TemplateDateModel) rightValue; - - int leftDateType = leftDateModel.getDateType(); - int rightDateType = rightDateModel.getDateType(); - - if (leftDateType == TemplateDateModel.UNKNOWN || rightDateType == TemplateDateModel.UNKNOWN) { - String sideName; - Expression sideExp; - if (leftDateType == TemplateDateModel.UNKNOWN) { - sideName = "left"; - sideExp = leftExp; - } else { - sideName = "right"; - sideExp = rightExp; - } - - throw new _MiscTemplateException(sideExp != null ? sideExp : defaultBlamed, env, - "The ", sideName, " ", VALUE_OF_THE_COMPARISON_IS_UNKNOWN_DATE_LIKE); - } - - if (leftDateType != rightDateType) { - ; - throw new _MiscTemplateException(defaultBlamed, env, - "Can't compare dates of different types. Left date type is ", - TemplateDateModel.TYPE_NAMES.get(leftDateType), ", right date type is ", - TemplateDateModel.TYPE_NAMES.get(rightDateType), "."); - } - - Date leftDate = EvalUtil.modelToDate(leftDateModel, leftExp); - Date rightDate = EvalUtil.modelToDate(rightDateModel, rightExp); - cmpResult = leftDate.compareTo(rightDate); - } else if (leftValue instanceof TemplateScalarModel && rightValue instanceof TemplateScalarModel) { - if (operator != CMP_OP_EQUALS && operator != CMP_OP_NOT_EQUALS) { - throw new _MiscTemplateException(defaultBlamed, env, - "Can't use operator \"", cmpOpToString(operator, operatorString), "\" on string values."); - } - String leftString = EvalUtil.modelToString((TemplateScalarModel) leftValue, leftExp, env); - String rightString = EvalUtil.modelToString((TemplateScalarModel) rightValue, rightExp, env); - // FIXME NBC: Don't use the Collator here. That's locale-specific, but ==/!= should not be. - cmpResult = env.getCollator().compare(leftString, rightString); - } else if (leftValue instanceof TemplateBooleanModel && rightValue instanceof TemplateBooleanModel) { - if (operator != CMP_OP_EQUALS && operator != CMP_OP_NOT_EQUALS) { - throw new _MiscTemplateException(defaultBlamed, env, - "Can't use operator \"", cmpOpToString(operator, operatorString), "\" on boolean values."); - } - boolean leftBool = ((TemplateBooleanModel) leftValue).getAsBoolean(); - boolean rightBool = ((TemplateBooleanModel) rightValue).getAsBoolean(); - cmpResult = (leftBool ? 1 : 0) - (rightBool ? 1 : 0); - } else { - if (typeMismatchMeansNotEqual) { - if (operator == CMP_OP_EQUALS) { - return false; - } else if (operator == CMP_OP_NOT_EQUALS) { - return true; - } - // Falls through - } - throw new _MiscTemplateException(defaultBlamed, env, - "Can't compare values of these types. ", - "Allowed comparisons are between two numbers, two strings, two dates, or two booleans.\n", - "Left hand operand ", - (quoteOperandsInErrors && leftExp != null - ? new Object[] { "(", new _DelayedGetCanonicalForm(leftExp), ") value " } - : ""), - "is ", new _DelayedAOrAn(new _DelayedFTLTypeDescription(leftValue)), ".\n", - "Right hand operand ", - (quoteOperandsInErrors && rightExp != null - ? new Object[] { "(", new _DelayedGetCanonicalForm(rightExp), ") value " } - : ""), - "is ", new _DelayedAOrAn(new _DelayedFTLTypeDescription(rightValue)), - "."); - } - - switch (operator) { - case CMP_OP_EQUALS: return cmpResult == 0; - case CMP_OP_NOT_EQUALS: return cmpResult != 0; - case CMP_OP_LESS_THAN: return cmpResult < 0; - case CMP_OP_GREATER_THAN: return cmpResult > 0; - case CMP_OP_LESS_THAN_EQUALS: return cmpResult <= 0; - case CMP_OP_GREATER_THAN_EQUALS: return cmpResult >= 0; - default: throw new BugException("Unsupported comparator operator code: " + operator); - } - } - - private static String cmpOpToString(int operator, String operatorString) { - if (operatorString != null) { - return operatorString; - } else { - switch (operator) { - case CMP_OP_EQUALS: return "equals"; - case CMP_OP_NOT_EQUALS: return "not-equals"; - case CMP_OP_LESS_THAN: return "less-than"; - case CMP_OP_GREATER_THAN: return "greater-than"; - case CMP_OP_LESS_THAN_EQUALS: return "less-than-equals"; - case CMP_OP_GREATER_THAN_EQUALS: return "greater-than-equals"; - default: return "???"; - } - } - } - - /** - * Converts a value to plain text {@link String}, or a {@link TemplateMarkupOutputModel} if that's what the - * {@link TemplateValueFormat} involved produces. - * - * @param seqTip - * Tip to display if the value type is not coercable, but it's sequence or collection. - * - * @return Never {@code null} - * @throws TemplateException - */ - static Object coerceModelToStringOrMarkup(TemplateModel tm, Expression exp, String seqTip, Environment env) - throws TemplateException { - return coerceModelToStringOrMarkup(tm, exp, false, seqTip, env); - } - - /** - * @return {@code null} if the {@code returnNullOnNonCoercableType} parameter is {@code true}, and the coercion is - * not possible, because of the type is not right for it. - * - * @see #coerceModelToStringOrMarkup(TemplateModel, Expression, String, Environment) - */ - static Object coerceModelToStringOrMarkup( - TemplateModel tm, Expression exp, boolean returnNullOnNonCoercableType, String seqTip, Environment env) - throws TemplateException { - if (tm instanceof TemplateNumberModel) { - TemplateNumberModel tnm = (TemplateNumberModel) tm; - TemplateNumberFormat format = env.getTemplateNumberFormat(exp, false); - try { - return assertFormatResultNotNull(format.format(tnm)); - } catch (TemplateValueFormatException e) { - throw MessageUtil.newCantFormatNumberException(format, exp, e, false); - } - } else if (tm instanceof TemplateDateModel) { - TemplateDateModel tdm = (TemplateDateModel) tm; - TemplateDateFormat format = env.getTemplateDateFormat(tdm, exp, false); - try { - return assertFormatResultNotNull(format.format(tdm)); - } catch (TemplateValueFormatException e) { - throw MessageUtil.newCantFormatDateException(format, exp, e, false); - } - } else if (tm instanceof TemplateMarkupOutputModel) { - return tm; - } else { - return coerceModelToTextualCommon(tm, exp, seqTip, true, returnNullOnNonCoercableType, env); - } - } - - /** - * Like {@link #coerceModelToStringOrMarkup(TemplateModel, Expression, String, Environment)}, but gives error - * if the result is markup. This is what you normally use where markup results can't be used. - * - * @param seqTip - * Tip to display if the value type is not coercable, but it's sequence or collection. - * - * @return Never {@code null} - */ - static String coerceModelToStringOrUnsupportedMarkup( - TemplateModel tm, Expression exp, String seqTip, Environment env) - throws TemplateException { - if (tm instanceof TemplateNumberModel) { - TemplateNumberModel tnm = (TemplateNumberModel) tm; - TemplateNumberFormat format = env.getTemplateNumberFormat(exp, false); - try { - return ensureFormatResultString(format.format(tnm), exp, env); - } catch (TemplateValueFormatException e) { - throw MessageUtil.newCantFormatNumberException(format, exp, e, false); - } - } else if (tm instanceof TemplateDateModel) { - TemplateDateModel tdm = (TemplateDateModel) tm; - TemplateDateFormat format = env.getTemplateDateFormat(tdm, exp, false); - try { - return ensureFormatResultString(format.format(tdm), exp, env); - } catch (TemplateValueFormatException e) { - throw MessageUtil.newCantFormatDateException(format, exp, e, false); - } - } else { - return coerceModelToTextualCommon(tm, exp, seqTip, false, false, env); - } - } - - /** - * Converts a value to plain text {@link String}, even if the {@link TemplateValueFormat} involved normally produces - * markup. This should be used rarely, where the user clearly intend to use the plain text variant of the format. - * - * @param seqTip - * Tip to display if the value type is not coercable, but it's sequence or collection. - * - * @return Never {@code null} - */ - static String coerceModelToPlainText(TemplateModel tm, Expression exp, String seqTip, - Environment env) throws TemplateException { - if (tm instanceof TemplateNumberModel) { - return assertFormatResultNotNull(env.formatNumberToPlainText((TemplateNumberModel) tm, exp, false)); - } else if (tm instanceof TemplateDateModel) { - return assertFormatResultNotNull(env.formatDateToPlainText((TemplateDateModel) tm, exp, false)); - } else { - return coerceModelToTextualCommon(tm, exp, seqTip, false, false, env); - } - } - - /** - * @param tm - * If {@code null} that's an exception - * - * @param supportsTOM - * Whether the caller {@code coerceModelTo...} method could handle a {@link TemplateMarkupOutputModel}. - * - * @return Never {@code null} - */ - private static String coerceModelToTextualCommon( - TemplateModel tm, Expression exp, String seqHint, boolean supportsTOM, boolean returnNullOnNonCoercableType, - Environment env) - throws TemplateModelException, InvalidReferenceException, TemplateException, - NonStringOrTemplateOutputException, NonStringException { - if (tm instanceof TemplateScalarModel) { - return modelToString((TemplateScalarModel) tm, exp, env); - } else if (tm == null) { - if (exp != null) { - throw InvalidReferenceException.getInstance(exp, env); - } else { - throw new InvalidReferenceException( - "Null/missing value (no more informatoin avilable)", - env); - } - } else if (tm instanceof TemplateBooleanModel) { - // [FM3] This should be before TemplateScalarModel, but automatic boolean-to-string is only non-error since - // 2.3.20, so to keep backward compatibility we couldn't insert this before TemplateScalarModel. - boolean booleanValue = ((TemplateBooleanModel) tm).getAsBoolean(); - return env.formatBoolean(booleanValue, false); - } else { - if (returnNullOnNonCoercableType) { - return null; - } - if (seqHint != null && (tm instanceof TemplateSequenceModel || tm instanceof TemplateCollectionModel)) { - if (supportsTOM) { - throw new NonStringOrTemplateOutputException(exp, tm, seqHint, env); - } else { - throw new NonStringException(exp, tm, seqHint, env); - } - } else { - if (supportsTOM) { - throw new NonStringOrTemplateOutputException(exp, tm, env); - } else { - throw new NonStringException(exp, tm, env); - } - } - } - } - - private static String ensureFormatResultString(Object formatResult, Expression exp, Environment env) - throws NonStringException { - if (formatResult instanceof String) { - return (String) formatResult; - } - - assertFormatResultNotNull(formatResult); - - TemplateMarkupOutputModel mo = (TemplateMarkupOutputModel) formatResult; - _ErrorDescriptionBuilder desc = new _ErrorDescriptionBuilder( - "Value was formatted to convert it to string, but the result was markup of ouput format ", - new _DelayedJQuote(mo.getOutputFormat()), ".") - .tip("Use value?string to force formatting to plain text.") - .blame(exp); - throw new NonStringException(null, desc); - } - - static String assertFormatResultNotNull(String r) { - if (r != null) { - return r; - } - throw new NullPointerException("TemplateValueFormatter result can't be null"); - } - - static Object assertFormatResultNotNull(Object r) { - if (r != null) { - return r; - } - throw new NullPointerException("TemplateValueFormatter result can't be null"); - } - - static TemplateMarkupOutputModel concatMarkupOutputs(TemplateObject parent, TemplateMarkupOutputModel leftMO, - TemplateMarkupOutputModel rightMO) throws TemplateException { - MarkupOutputFormat leftOF = leftMO.getOutputFormat(); - MarkupOutputFormat rightOF = rightMO.getOutputFormat(); - if (rightOF != leftOF) { - String rightPT; - String leftPT; - if ((rightPT = rightOF.getSourcePlainText(rightMO)) != null) { - return leftOF.concat(leftMO, leftOF.fromPlainTextByEscaping(rightPT)); - } else if ((leftPT = leftOF.getSourcePlainText(leftMO)) != null) { - return rightOF.concat(rightOF.fromPlainTextByEscaping(leftPT), rightMO); - } else { - Object[] message = { "Concatenation left hand operand is in ", new _DelayedToString(leftOF), - " format, while the right hand operand is in ", new _DelayedToString(rightOF), - ". Conversion to common format wasn't possible." }; - if (parent instanceof Expression) { - throw new _MiscTemplateException((Expression) parent, message); - } else { - throw new _MiscTemplateException(message); - } - } - } else { - return leftOF.concat(leftMO, rightMO); - } - } - - /** - * Returns an {@link ArithmeticEngine} even if {@code env} is {@code null}, because we are in parsing phase. - */ - static ArithmeticEngine getArithmeticEngine(Environment env, TemplateObject tObj) { - return env != null - ? env.getArithmeticEngine() - : tObj.getTemplate().getParserConfiguration().getArithmeticEngine(); - } - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/7d784b2b/src/main/java/org/apache/freemarker/core/ast/ExistenceBuiltins.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/freemarker/core/ast/ExistenceBuiltins.java b/src/main/java/org/apache/freemarker/core/ast/ExistenceBuiltins.java deleted file mode 100644 index 2fc343b..0000000 --- a/src/main/java/org/apache/freemarker/core/ast/ExistenceBuiltins.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.freemarker.core.ast; - -import java.util.List; - -import org.apache.freemarker.core.TemplateException; -import org.apache.freemarker.core.model.TemplateBooleanModel; -import org.apache.freemarker.core.model.TemplateMethodModelEx; -import org.apache.freemarker.core.model.TemplateModel; -import org.apache.freemarker.core.model.TemplateModelException; - -/** - * A holder for builtins that deal with null left-hand values. - */ -class ExistenceBuiltins { - - // Can't be instantiated - private ExistenceBuiltins() { } - - private static abstract class ExistenceBuiltIn extends BuiltIn { - - protected TemplateModel evalMaybeNonexistentTarget(Environment env) throws TemplateException { - TemplateModel tm; - if (target instanceof ParentheticalExpression) { - boolean lastFIRE = env.setFastInvalidReferenceExceptions(true); - try { - tm = target.eval(env); - } catch (InvalidReferenceException ire) { - tm = null; - } finally { - env.setFastInvalidReferenceExceptions(lastFIRE); - } - } else { - tm = target.eval(env); - } - return tm; - } - - } - - static class defaultBI extends ExistenceBuiltins.ExistenceBuiltIn { - - @Override - TemplateModel _eval(final Environment env) throws TemplateException { - TemplateModel model = evalMaybeNonexistentTarget(env); - return model == null ? FIRST_NON_NULL_METHOD : new ConstantMethod(model); - } - - private static class ConstantMethod implements TemplateMethodModelEx { - private final TemplateModel constant; - - ConstantMethod(TemplateModel constant) { - this.constant = constant; - } - - @Override - public Object exec(List args) { - return constant; - } - } - - /** - * A method that goes through the arguments one by one and returns - * the first one that is non-null. If all args are null, returns null. - */ - private static final TemplateMethodModelEx FIRST_NON_NULL_METHOD = - new TemplateMethodModelEx() { - @Override - public Object exec(List args) throws TemplateModelException { - int argCnt = args.size(); - if (argCnt == 0) throw MessageUtil.newArgCntError("?default", argCnt, 1, Integer.MAX_VALUE); - for (int i = 0; i < argCnt; i++ ) { - TemplateModel result = (TemplateModel) args.get(i); - if (result != null) return result; - } - return null; - } - }; - } - - static class existsBI extends ExistenceBuiltins.ExistenceBuiltIn { - @Override - TemplateModel _eval(Environment env) throws TemplateException { - return evalMaybeNonexistentTarget(env) == null ? TemplateBooleanModel.FALSE : TemplateBooleanModel.TRUE; - } - - @Override - boolean evalToBoolean(Environment env) throws TemplateException { - return _eval(env) == TemplateBooleanModel.TRUE; - } - } - - static class has_contentBI extends ExistenceBuiltins.ExistenceBuiltIn { - @Override - TemplateModel _eval(Environment env) throws TemplateException { - return Expression.isEmpty(evalMaybeNonexistentTarget(env)) - ? TemplateBooleanModel.FALSE - : TemplateBooleanModel.TRUE; - } - - @Override - boolean evalToBoolean(Environment env) throws TemplateException { - return _eval(env) == TemplateBooleanModel.TRUE; - } - } - - static class if_existsBI extends ExistenceBuiltins.ExistenceBuiltIn { - @Override - TemplateModel _eval(Environment env) - throws TemplateException { - TemplateModel model = evalMaybeNonexistentTarget(env); - return model == null ? TemplateModel.NOTHING : model; - } - } - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/7d784b2b/src/main/java/org/apache/freemarker/core/ast/ExistsExpression.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/freemarker/core/ast/ExistsExpression.java b/src/main/java/org/apache/freemarker/core/ast/ExistsExpression.java deleted file mode 100755 index 166fc62..0000000 --- a/src/main/java/org/apache/freemarker/core/ast/ExistsExpression.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - - -package org.apache.freemarker.core.ast; - -import org.apache.freemarker.core.TemplateException; -import org.apache.freemarker.core.model.TemplateBooleanModel; -import org.apache.freemarker.core.model.TemplateModel; - -/** {@code exp??} and {@code (exp)??} */ -class ExistsExpression extends Expression { - - protected final Expression exp; - - ExistsExpression(Expression exp) { - this.exp = exp; - } - - @Override - TemplateModel _eval(Environment env) throws TemplateException { - TemplateModel tm; - if (exp instanceof ParentheticalExpression) { - boolean lastFIRE = env.setFastInvalidReferenceExceptions(true); - try { - tm = exp.eval(env); - } catch (InvalidReferenceException ire) { - tm = null; - } finally { - env.setFastInvalidReferenceExceptions(lastFIRE); - } - } else { - tm = exp.eval(env); - } - return tm == null ? TemplateBooleanModel.FALSE : TemplateBooleanModel.TRUE; - } - - @Override - boolean isLiteral() { - return false; - } - - @Override - protected Expression deepCloneWithIdentifierReplaced_inner(String replacedIdentifier, Expression replacement, ReplacemenetState replacementState) { - return new ExistsExpression( - exp.deepCloneWithIdentifierReplaced(replacedIdentifier, replacement, replacementState)); - } - - @Override - public String getCanonicalForm() { - return exp.getCanonicalForm() + getNodeTypeSymbol(); - } - - @Override - String getNodeTypeSymbol() { - return "??"; - } - - @Override - int getParameterCount() { - return 1; - } - - @Override - Object getParameterValue(int idx) { - return exp; - } - - @Override - ParameterRole getParameterRole(int idx) { - return ParameterRole.LEFT_HAND_OPERAND; - } - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/7d784b2b/src/main/java/org/apache/freemarker/core/ast/Expression.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/freemarker/core/ast/Expression.java b/src/main/java/org/apache/freemarker/core/ast/Expression.java deleted file mode 100644 index 7f3c9bb..0000000 --- a/src/main/java/org/apache/freemarker/core/ast/Expression.java +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.freemarker.core.ast; - -import org.apache.freemarker.core.Configuration; -import org.apache.freemarker.core.Template; -import org.apache.freemarker.core.TemplateException; -import org.apache.freemarker.core.model.TemplateBooleanModel; -import org.apache.freemarker.core.model.TemplateCollectionModel; -import org.apache.freemarker.core.model.TemplateDateModel; -import org.apache.freemarker.core.model.TemplateHashModel; -import org.apache.freemarker.core.model.TemplateModel; -import org.apache.freemarker.core.model.TemplateModelException; -import org.apache.freemarker.core.model.TemplateNumberModel; -import org.apache.freemarker.core.model.TemplateScalarModel; -import org.apache.freemarker.core.model.TemplateSequenceModel; -import org.apache.freemarker.core.model.impl.beans.BeanModel; - -/** - * <b>Internal API - subject to change:</b> Represent expression nodes in the parsed template. - * - * @deprecated This is an internal FreeMarker API with no backward compatibility guarantees, so you shouldn't depend on - * it. - */ -@Deprecated -abstract public class Expression extends TemplateObject { - - /** - * @param env might be {@code null}, if this kind of expression can be evaluated during parsing (as opposed to - * during template execution). - */ - abstract TemplateModel _eval(Environment env) throws TemplateException; - - abstract boolean isLiteral(); - - // Used to store a constant return value for this expression. Only if it - // is possible, of course. - - TemplateModel constantValue; - - // Hook in here to set the constant value if possible. - - @Override - void setLocation(Template template, int beginColumn, int beginLine, int endColumn, int endLine) { - super.setLocation(template, beginColumn, beginLine, endColumn, endLine); - if (isLiteral()) { - try { - constantValue = _eval(null); - } catch (Exception e) { - // deliberately ignore. - } - } - } - - final TemplateModel getAsTemplateModel(Environment env) throws TemplateException { - return eval(env); - } - - final TemplateModel eval(Environment env) throws TemplateException { - return constantValue != null ? constantValue : _eval(env); - } - - String evalAndCoerceToPlainText(Environment env) throws TemplateException { - return EvalUtil.coerceModelToPlainText(eval(env), this, null, env); - } - - /** - * @param seqTip Tip to display if the value type is not coercable, but it's sequence or collection. - */ - String evalAndCoerceToPlainText(Environment env, String seqTip) throws TemplateException { - return EvalUtil.coerceModelToPlainText(eval(env), this, seqTip, env); - } - - Object evalAndCoerceToStringOrMarkup(Environment env) throws TemplateException { - return EvalUtil.coerceModelToStringOrMarkup(eval(env), this, null, env); - } - - /** - * @param seqTip Tip to display if the value type is not coercable, but it's sequence or collection. - */ - Object evalAndCoerceToStringOrMarkup(Environment env, String seqTip) throws TemplateException { - return EvalUtil.coerceModelToStringOrMarkup(eval(env), this, seqTip, env); - } - - String evalAndCoerceToStringOrUnsupportedMarkup(Environment env) throws TemplateException { - return EvalUtil.coerceModelToStringOrUnsupportedMarkup(eval(env), this, null, env); - } - - /** - * @param seqTip Tip to display if the value type is not coercable, but it's sequence or collection. - */ - String evalAndCoerceToStringOrUnsupportedMarkup(Environment env, String seqTip) throws TemplateException { - return EvalUtil.coerceModelToStringOrUnsupportedMarkup(eval(env), this, seqTip, env); - } - - Number evalToNumber(Environment env) throws TemplateException { - TemplateModel model = eval(env); - return modelToNumber(model, env); - } - - Number modelToNumber(TemplateModel model, Environment env) throws TemplateException { - if (model instanceof TemplateNumberModel) { - return EvalUtil.modelToNumber((TemplateNumberModel) model, this); - } else { - throw new NonNumericalException(this, model, env); - } - } - - boolean evalToBoolean(Environment env) throws TemplateException { - return evalToBoolean(env, null); - } - - boolean evalToBoolean(Configuration cfg) throws TemplateException { - return evalToBoolean(null, cfg); - } - - TemplateModel evalToNonMissing(Environment env) throws TemplateException { - TemplateModel result = eval(env); - assertNonNull(result, env); - return result; - } - - private boolean evalToBoolean(Environment env, Configuration cfg) throws TemplateException { - TemplateModel model = eval(env); - return modelToBoolean(model, env, cfg); - } - - boolean modelToBoolean(TemplateModel model, Environment env) throws TemplateException { - return modelToBoolean(model, env, null); - } - - boolean modelToBoolean(TemplateModel model, Configuration cfg) throws TemplateException { - return modelToBoolean(model, null, cfg); - } - - private boolean modelToBoolean(TemplateModel model, Environment env, Configuration cfg) throws TemplateException { - if (model instanceof TemplateBooleanModel) { - return ((TemplateBooleanModel) model).getAsBoolean(); - } else { - throw new NonBooleanException(this, model, env); - } - } - - final Expression deepCloneWithIdentifierReplaced( - String replacedIdentifier, Expression replacement, ReplacemenetState replacementState) { - Expression clone = deepCloneWithIdentifierReplaced_inner(replacedIdentifier, replacement, replacementState); - if (clone.beginLine == 0) { - clone.copyLocationFrom(this); - } - return clone; - } - - static class ReplacemenetState { - /** - * If the replacement expression is not in use yet, we don't have to clone it. - */ - boolean replacementAlreadyInUse; - } - - /** - * 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 Expression deepCloneWithIdentifierReplaced_inner( - String replacedIdentifier, Expression replacement, ReplacemenetState replacementState); - - static boolean isEmpty(TemplateModel model) throws TemplateModelException { - if (model instanceof BeanModel) { - return ((BeanModel) model).isEmpty(); - } else if (model instanceof TemplateSequenceModel) { - return ((TemplateSequenceModel) model).size() == 0; - } else if (model instanceof TemplateScalarModel) { - String s = ((TemplateScalarModel) model).getAsString(); - return (s == null || s.length() == 0); - } else if (model == null) { - return true; - } else if (model instanceof TemplateMarkupOutputModel) { // Note: happens just after FTL string check - TemplateMarkupOutputModel mo = (TemplateMarkupOutputModel) model; - return mo.getOutputFormat().isEmpty(mo); - } else if (model instanceof TemplateCollectionModel) { - return !((TemplateCollectionModel) model).iterator().hasNext(); - } else if (model instanceof TemplateHashModel) { - return ((TemplateHashModel) model).isEmpty(); - } else if (model instanceof TemplateNumberModel - || model instanceof TemplateDateModel - || model instanceof TemplateBooleanModel) { - return false; - } else { - return true; - } - } - - void assertNonNull(TemplateModel model, Environment env) throws InvalidReferenceException { - if (model == null) throw InvalidReferenceException.getInstance(this, env); - } - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/7d784b2b/src/main/java/org/apache/freemarker/core/ast/ExtendedDecimalFormatParser.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/freemarker/core/ast/ExtendedDecimalFormatParser.java b/src/main/java/org/apache/freemarker/core/ast/ExtendedDecimalFormatParser.java deleted file mode 100644 index 4f09696..0000000 --- a/src/main/java/org/apache/freemarker/core/ast/ExtendedDecimalFormatParser.java +++ /dev/null @@ -1,525 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.freemarker.core.ast; - -import java.math.RoundingMode; -import java.text.DecimalFormat; -import java.text.DecimalFormatSymbols; -import java.text.ParseException; -import java.util.Arrays; -import java.util.Currency; -import java.util.HashMap; -import java.util.Locale; -import java.util.Set; - -import org.apache.freemarker.core.util._StringUtil; - -class ExtendedDecimalFormatParser { - - private static final String PARAM_ROUNDING_MODE = "roundingMode"; - private static final String PARAM_MULTIPIER = "multipier"; - private static final String PARAM_DECIMAL_SEPARATOR = "decimalSeparator"; - private static final String PARAM_MONETARY_DECIMAL_SEPARATOR = "monetaryDecimalSeparator"; - private static final String PARAM_GROUP_SEPARATOR = "groupingSeparator"; - private static final String PARAM_EXPONENT_SEPARATOR = "exponentSeparator"; - private static final String PARAM_MINUS_SIGN = "minusSign"; - private static final String PARAM_INFINITY = "infinity"; - private static final String PARAM_NAN = "nan"; - private static final String PARAM_PERCENT = "percent"; - private static final String PARAM_PER_MILL = "perMill"; - private static final String PARAM_ZERO_DIGIT = "zeroDigit"; - private static final String PARAM_CURRENCY_CODE = "currencyCode"; - private static final String PARAM_CURRENCY_SYMBOL = "currencySymbol"; - - private static final String PARAM_VALUE_RND_UP = "up"; - private static final String PARAM_VALUE_RND_DOWN = "down"; - private static final String PARAM_VALUE_RND_CEILING = "ceiling"; - private static final String PARAM_VALUE_RND_FLOOR = "floor"; - private static final String PARAM_VALUE_RND_HALF_DOWN = "halfDown"; - private static final String PARAM_VALUE_RND_HALF_EVEN = "halfEven"; - private static final String PARAM_VALUE_RND_HALF_UP = "halfUp"; - private static final String PARAM_VALUE_RND_UNNECESSARY = "unnecessary"; - - private static final HashMap<String, ? extends ParameterHandler> PARAM_HANDLERS; - static { - HashMap<String, ParameterHandler> m = new HashMap<>(); - m.put(PARAM_ROUNDING_MODE, new ParameterHandler() { - @Override - public void handle(ExtendedDecimalFormatParser parser, String value) - throws InvalidParameterValueException { - RoundingMode parsedValue; - if (value.equals(PARAM_VALUE_RND_UP)) { - parsedValue = RoundingMode.UP; - } else if (value.equals(PARAM_VALUE_RND_DOWN)) { - parsedValue = RoundingMode.DOWN; - } else if (value.equals(PARAM_VALUE_RND_CEILING)) { - parsedValue = RoundingMode.CEILING; - } else if (value.equals(PARAM_VALUE_RND_FLOOR)) { - parsedValue = RoundingMode.FLOOR; - } else if (value.equals(PARAM_VALUE_RND_HALF_DOWN)) { - parsedValue = RoundingMode.HALF_DOWN; - } else if (value.equals(PARAM_VALUE_RND_HALF_EVEN)) { - parsedValue = RoundingMode.HALF_EVEN; - } else if (value.equals(PARAM_VALUE_RND_HALF_UP)) { - parsedValue = RoundingMode.HALF_UP; - } else if (value.equals(PARAM_VALUE_RND_UNNECESSARY)) { - parsedValue = RoundingMode.UNNECESSARY; - } else { - throw new InvalidParameterValueException("Should be one of: u, d, c, f, hd, he, hu, un"); - } - - parser.roundingMode = parsedValue; - } - }); - m.put(PARAM_MULTIPIER, new ParameterHandler() { - @Override - public void handle(ExtendedDecimalFormatParser parser, String value) - throws InvalidParameterValueException { - try { - parser.multipier = Integer.valueOf(value); - } catch (NumberFormatException e) { - throw new InvalidParameterValueException("Malformed integer."); - } - } - }); - m.put(PARAM_DECIMAL_SEPARATOR, new ParameterHandler() { - @Override - public void handle(ExtendedDecimalFormatParser parser, String value) - throws InvalidParameterValueException { - if (value.length() != 1) { - throw new InvalidParameterValueException("Must contain exactly 1 character."); - } - parser.symbols.setDecimalSeparator(value.charAt(0)); - } - }); - m.put(PARAM_MONETARY_DECIMAL_SEPARATOR, new ParameterHandler() { - @Override - public void handle(ExtendedDecimalFormatParser parser, String value) - throws InvalidParameterValueException { - if (value.length() != 1) { - throw new InvalidParameterValueException("Must contain exactly 1 character."); - } - parser.symbols.setMonetaryDecimalSeparator(value.charAt(0)); - } - }); - m.put(PARAM_GROUP_SEPARATOR, new ParameterHandler() { - @Override - public void handle(ExtendedDecimalFormatParser parser, String value) - throws InvalidParameterValueException { - if (value.length() != 1) { - throw new InvalidParameterValueException("Must contain exactly 1 character."); - } - parser.symbols.setGroupingSeparator(value.charAt(0)); - } - }); - m.put(PARAM_EXPONENT_SEPARATOR, new ParameterHandler() { - @Override - public void handle(ExtendedDecimalFormatParser parser, String value) - throws InvalidParameterValueException { - parser.symbols.setExponentSeparator(value); - } - }); - m.put(PARAM_MINUS_SIGN, new ParameterHandler() { - @Override - public void handle(ExtendedDecimalFormatParser parser, String value) - throws InvalidParameterValueException { - if (value.length() != 1) { - throw new InvalidParameterValueException("Must contain exactly 1 character."); - } - parser.symbols.setMinusSign(value.charAt(0)); - } - }); - m.put(PARAM_INFINITY, new ParameterHandler() { - @Override - public void handle(ExtendedDecimalFormatParser parser, String value) - throws InvalidParameterValueException { - parser.symbols.setInfinity(value); - } - }); - m.put(PARAM_NAN, new ParameterHandler() { - @Override - public void handle(ExtendedDecimalFormatParser parser, String value) - throws InvalidParameterValueException { - parser.symbols.setNaN(value); - } - }); - m.put(PARAM_PERCENT, new ParameterHandler() { - @Override - public void handle(ExtendedDecimalFormatParser parser, String value) - throws InvalidParameterValueException { - if (value.length() != 1) { - throw new InvalidParameterValueException("Must contain exactly 1 character."); - } - parser.symbols.setPercent(value.charAt(0)); - } - }); - m.put(PARAM_PER_MILL, new ParameterHandler() { - @Override - public void handle(ExtendedDecimalFormatParser parser, String value) - throws InvalidParameterValueException { - if (value.length() != 1) { - throw new InvalidParameterValueException("Must contain exactly 1 character."); - } - parser.symbols.setPerMill(value.charAt(0)); - } - }); - m.put(PARAM_ZERO_DIGIT, new ParameterHandler() { - @Override - public void handle(ExtendedDecimalFormatParser parser, String value) - throws InvalidParameterValueException { - if (value.length() != 1) { - throw new InvalidParameterValueException("Must contain exactly 1 character."); - } - parser.symbols.setZeroDigit(value.charAt(0)); - } - }); - m.put(PARAM_CURRENCY_CODE, new ParameterHandler() { - @Override - public void handle(ExtendedDecimalFormatParser parser, String value) - throws InvalidParameterValueException { - Currency currency; - try { - currency = Currency.getInstance(value); - } catch (IllegalArgumentException e) { - throw new InvalidParameterValueException("Not a known ISO 4217 code."); - } - parser.symbols.setCurrency(currency); - } - }); - PARAM_HANDLERS = m; - } - - private static final String SNIP_MARK = "[...]"; - private static final int MAX_QUOTATION_LENGTH = 10; // Must be more than SNIP_MARK.length! - - private final String src; - private int pos = 0; - - private final DecimalFormatSymbols symbols; - private RoundingMode roundingMode; - private Integer multipier; - - static DecimalFormat parse(String formatString, Locale locale) throws ParseException { - return new ExtendedDecimalFormatParser(formatString, locale).parse(); - } - - private DecimalFormat parse() throws ParseException { - String stdPattern = fetchStandardPattern(); - skipWS(); - parseFormatStringExtension(); - - DecimalFormat decimalFormat; - try { - decimalFormat = new DecimalFormat(stdPattern, symbols); - } catch (IllegalArgumentException e) { - ParseException pe = new ParseException(e.getMessage(), 0); - if (e.getCause() != null) { - try { - e.initCause(e.getCause()); - } catch (Exception e2) { - // Supress - } - } - throw pe; - } - - if (roundingMode != null) { - decimalFormat.setRoundingMode(roundingMode); - } - - if (multipier != null) { - decimalFormat.setMultiplier(multipier.intValue()); - } - - return decimalFormat; - } - - private void parseFormatStringExtension() throws ParseException { - int ln = src.length(); - - if (pos == ln) { - return; - } - - String currencySymbol = null; // Exceptional, as must be applied after "currency code" - fetchParamters: do { - int namePos = pos; - String name = fetchName(); - if (name == null) { - throw newExpectedSgParseException("name"); - } - - skipWS(); - - if (!fetchChar('=')) { - throw newExpectedSgParseException("\"=\""); - } - - skipWS(); - - int valuePos = pos; - String value = fetchValue(); - if (value == null) { - throw newExpectedSgParseException("value"); - } - int paramEndPos = pos; - - ParameterHandler handler = PARAM_HANDLERS.get(name); - if (handler == null) { - if (name.equals(PARAM_CURRENCY_SYMBOL)) { - currencySymbol = value; - } else { - throw newUnknownParameterException(name, namePos); - } - } else { - try { - handler.handle(this, value); - } catch (InvalidParameterValueException e) { - throw newInvalidParameterValueException(name, value, valuePos, e); - } - } - - skipWS(); - - // Optional comma - if (fetchChar(',')) { - skipWS(); - } else { - if (pos == ln) { - break fetchParamters; - } - if (pos == paramEndPos) { - throw newExpectedSgParseException("parameter separator whitespace or comma"); - } - } - } while (true); - - // This is brought out to here to ensure that it's applied after "currency code": - if (currencySymbol != null) { - symbols.setCurrencySymbol(currencySymbol); - } - } - - private ParseException newInvalidParameterValueException(String name, String value, int valuePos, - InvalidParameterValueException e) { - return new java.text.ParseException( - _StringUtil.jQuote(value) + " is an invalid value for the \"" + name + "\" parameter: " - + e.message, - valuePos); - } - - private ParseException newUnknownParameterException(String name, int namePos) throws ParseException { - StringBuilder sb = new StringBuilder(128); - sb.append("Unsupported parameter name, ").append(_StringUtil.jQuote(name)); - sb.append(". The supported names are: "); - Set<String> legalNames = PARAM_HANDLERS.keySet(); - String[] legalNameArr = legalNames.toArray(new String[legalNames.size()]); - Arrays.sort(legalNameArr); - for (int i = 0; i < legalNameArr.length; i++) { - if (i != 0) { - sb.append(", "); - } - sb.append(legalNameArr[i]); - } - return new java.text.ParseException(sb.toString(), namePos); - } - - private void skipWS() { - int ln = src.length(); - while (pos < ln && isWS(src.charAt(pos))) { - pos++; - } - } - - private boolean fetchChar(char fetchedChar) { - if (pos < src.length() && src.charAt(pos) == fetchedChar) { - pos++; - return true; - } else { - return false; - } - } - - private boolean isWS(char c) { - return c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\u00A0'; - } - - private String fetchName() throws ParseException { - int ln = src.length(); - int startPos = pos; - boolean firstChar = true; - scanUntilEnd: while (pos < ln) { - char c = src.charAt(pos); - if (firstChar) { - if (!Character.isJavaIdentifierStart(c)) { - break scanUntilEnd; - } - firstChar = false; - } else if (!Character.isJavaIdentifierPart(c)) { - break scanUntilEnd; - } - pos++; - } - return !firstChar ? src.substring(startPos, pos) : null; - } - - private String fetchValue() throws ParseException { - int ln = src.length(); - int startPos = pos; - char openedQuot = 0; - boolean needsUnescaping = false; - scanUntilEnd: while (pos < ln) { - char c = src.charAt(pos); - if (c == '\'' || c == '"') { - if (openedQuot == 0) { - if (startPos != pos) { - throw new java.text.ParseException( - "The " + c + " character can only be used for quoting values, " - + "but it was in the middle of an non-quoted value.", - pos); - } - openedQuot = c; - } else if (c == openedQuot) { - if (pos + 1 < ln && src.charAt(pos + 1) == openedQuot) { - pos++; // skip doubled quote (escaping) - needsUnescaping = true; - } else { - String str = src.substring(startPos + 1, pos); - pos++; - return needsUnescaping ? unescape(str, openedQuot) : str; - } - } - } else { - if (openedQuot == 0 && !Character.isJavaIdentifierPart(c)) { - break scanUntilEnd; - } - } - pos++; - } // while - if (openedQuot != 0) { - throw new java.text.ParseException( - "The " + openedQuot - + " quotation wasn't closed when the end of the source was reached.", - pos); - } - return startPos == pos ? null : src.substring(startPos, pos); - } - - private String unescape(String s, char openedQuot) { - return openedQuot == '\'' ? _StringUtil.replace(s, "\'\'", "\'") : _StringUtil.replace(s, "\"\"", "\""); - } - - private String fetchStandardPattern() { - int pos = this.pos; - int ln = src.length(); - int semicolonCnt = 0; - boolean quotedMode = false; - findStdPartEnd: while (pos < ln) { - char c = src.charAt(pos); - if (c == ';' && !quotedMode) { - semicolonCnt++; - if (semicolonCnt == 2) { - break findStdPartEnd; - } - } else if (c == '\'') { - if (quotedMode) { - if (pos + 1 < ln && src.charAt(pos + 1) == '\'') { - // Skips "''" used for escaping "'" - pos++; - } else { - quotedMode = false; - } - } else { - quotedMode = true; - } - } - pos++; - } - - String stdFormatStr; - if (semicolonCnt < 2) { // We have a standard DecimalFormat string - // Note that "0.0;" and "0.0" gives the same result with DecimalFormat, so we leave a ';' there - stdFormatStr = src; - } else { // `pos` points to the 2nd ';' - int stdEndPos = pos; - if (src.charAt(pos - 1) == ';') { // we have a ";;" - // Note that ";;" is illegal in DecimalFormat, so this is backward compatible. - stdEndPos--; - } - stdFormatStr = src.substring(0, stdEndPos); - } - - if (pos < ln) { - pos++; // Skips closing ';' - } - this.pos = pos; - - return stdFormatStr; - } - - private ExtendedDecimalFormatParser(String formatString, Locale locale) { - src = formatString; - symbols = new DecimalFormatSymbols(locale); - } - - private ParseException newExpectedSgParseException(String expectedThing) { - String quotation; - - // Ignore trailing WS when calculating the length: - int i = src.length() - 1; - while (i >= 0 && Character.isWhitespace(src.charAt(i))) { - i--; - } - int ln = i + 1; - - if (pos < ln) { - int qEndPos = pos + MAX_QUOTATION_LENGTH; - if (qEndPos >= ln) { - quotation = src.substring(pos, ln); - } else { - quotation = src.substring(pos, qEndPos - SNIP_MARK.length()) + SNIP_MARK; - } - } else { - quotation = null; - } - - return new ParseException( - "Expected a(n) " + expectedThing + " at position " + pos + " (0-based), but " - + (quotation == null ? "reached the end of the input." : "found: " + quotation), - pos); - } - - private interface ParameterHandler { - - void handle(ExtendedDecimalFormatParser parser, String value) - throws InvalidParameterValueException; - - } - - private static class InvalidParameterValueException extends Exception { - - private final String message; - - public InvalidParameterValueException(String message) { - this.message = message; - } - - } - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/7d784b2b/src/main/java/org/apache/freemarker/core/ast/FallbackInstruction.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/freemarker/core/ast/FallbackInstruction.java b/src/main/java/org/apache/freemarker/core/ast/FallbackInstruction.java deleted file mode 100644 index d5fe03c..0000000 --- a/src/main/java/org/apache/freemarker/core/ast/FallbackInstruction.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.freemarker.core.ast; - -import java.io.IOException; - -import org.apache.freemarker.core.TemplateException; - -final class FallbackInstruction extends TemplateElement { - - @Override - TemplateElement[] accept(Environment env) throws IOException, TemplateException { - env.fallback(); - return null; - } - - @Override - protected String dump(boolean canonical) { - return canonical ? "<" + getNodeTypeSymbol() + "/>" : getNodeTypeSymbol(); - } - - @Override - String getNodeTypeSymbol() { - return "#fallback"; - } - - @Override - int getParameterCount() { - return 0; - } - - @Override - Object getParameterValue(int idx) { - throw new IndexOutOfBoundsException(); - } - - @Override - ParameterRole getParameterRole(int idx) { - throw new IndexOutOfBoundsException(); - } - - @Override - boolean isNestedBlockRepeater() { - return false; - } - - @Override - boolean isShownInStackTrace() { - return true; - } - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/7d784b2b/src/main/java/org/apache/freemarker/core/ast/FlushInstruction.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/freemarker/core/ast/FlushInstruction.java b/src/main/java/org/apache/freemarker/core/ast/FlushInstruction.java deleted file mode 100644 index fd9518a..0000000 --- a/src/main/java/org/apache/freemarker/core/ast/FlushInstruction.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.freemarker.core.ast; - -import java.io.IOException; - -/** - * An instruction that flushes the output stream. - */ -final class FlushInstruction extends TemplateElement { - - @Override - TemplateElement[] accept(Environment env) throws IOException { - env.getOut().flush(); - return null; - } - - @Override - protected String dump(boolean canonical) { - return canonical ? "<" + getNodeTypeSymbol() + "/>" : getNodeTypeSymbol(); - } - - @Override - String getNodeTypeSymbol() { - return "#flush"; - } - - @Override - int getParameterCount() { - return 0; - } - - @Override - Object getParameterValue(int idx) { - throw new IndexOutOfBoundsException(); - } - - @Override - ParameterRole getParameterRole(int idx) { - throw new IndexOutOfBoundsException(); - } - - @Override - boolean isNestedBlockRepeater() { - return false; - } - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/7d784b2b/src/main/java/org/apache/freemarker/core/ast/HTMLOutputFormat.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/freemarker/core/ast/HTMLOutputFormat.java b/src/main/java/org/apache/freemarker/core/ast/HTMLOutputFormat.java deleted file mode 100644 index ca0ae6d..0000000 --- a/src/main/java/org/apache/freemarker/core/ast/HTMLOutputFormat.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.freemarker.core.ast; - -import java.io.IOException; -import java.io.Writer; - -import org.apache.freemarker.core.model.TemplateModelException; -import org.apache.freemarker.core.util._StringUtil; - -/** - * Represents the HTML output format (MIME type "text/html", name "HTML"). This format escapes by default (via - * {@link _StringUtil#XHTMLEnc(String)}). The {@code ?html}, {@code ?xhtml} and {@code ?xml} built-ins silently bypass - * template output values of the type produced by this output format ({@link TemplateHTMLOutputModel}). - * - * @since 2.3.24 - */ -public final class HTMLOutputFormat extends CommonMarkupOutputFormat<TemplateHTMLOutputModel> { - - /** - * The only instance (singleton) of this {@link OutputFormat}. - */ - public static final HTMLOutputFormat INSTANCE = new HTMLOutputFormat(); - - private HTMLOutputFormat() { - // Only to decrease visibility - } - - @Override - public String getName() { - return "HTML"; - } - - @Override - public String getMimeType() { - return "text/html"; - } - - @Override - public void output(String textToEsc, Writer out) throws IOException, TemplateModelException { - _StringUtil.XHTMLEnc(textToEsc, out); - } - - @Override - public String escapePlainText(String plainTextContent) { - return _StringUtil.XHTMLEnc(plainTextContent); - } - - @Override - public boolean isLegacyBuiltInBypassed(String builtInName) { - return builtInName.equals("html") || builtInName.equals("xml") || builtInName.equals("xhtml"); - } - - @Override - protected TemplateHTMLOutputModel newTemplateMarkupOutputModel(String plainTextContent, String markupContent) { - return new TemplateHTMLOutputModel(plainTextContent, markupContent); - } - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/7d784b2b/src/main/java/org/apache/freemarker/core/ast/HashLiteral.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/freemarker/core/ast/HashLiteral.java b/src/main/java/org/apache/freemarker/core/ast/HashLiteral.java deleted file mode 100644 index 1b8bf3a..0000000 --- a/src/main/java/org/apache/freemarker/core/ast/HashLiteral.java +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.freemarker.core.ast; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.ListIterator; - -import org.apache.freemarker.core.TemplateException; -import org.apache.freemarker.core.model.TemplateCollectionModel; -import org.apache.freemarker.core.model.TemplateHashModelEx2; -import org.apache.freemarker.core.model.TemplateModel; -import org.apache.freemarker.core.model.TemplateModelException; -import org.apache.freemarker.core.model.TemplateModelIterator; -import org.apache.freemarker.core.model.impl.SimpleSequence; - -final class HashLiteral extends Expression { - - private final ArrayList keys, values; - private final int size; - - HashLiteral(ArrayList/*<Expression>*/ keys, ArrayList/*<Expression>*/ values) { - this.keys = keys; - this.values = values; - size = keys.size(); - keys.trimToSize(); - values.trimToSize(); - } - - @Override - TemplateModel _eval(Environment env) throws TemplateException { - return new SequenceHash(env); - } - - @Override - public String getCanonicalForm() { - StringBuilder buf = new StringBuilder("{"); - for (int i = 0; i < size; i++) { - Expression key = (Expression) keys.get(i); - Expression value = (Expression) values.get(i); - buf.append(key.getCanonicalForm()); - buf.append(": "); - buf.append(value.getCanonicalForm()); - if (i != size - 1) { - buf.append(", "); - } - } - buf.append("}"); - return buf.toString(); - } - - @Override - String getNodeTypeSymbol() { - return "{...}"; - } - - @Override - boolean isLiteral() { - if (constantValue != null) { - return true; - } - for (int i = 0; i < size; i++) { - Expression key = (Expression) keys.get(i); - Expression value = (Expression) values.get(i); - if (!key.isLiteral() || !value.isLiteral()) { - return false; - } - } - return true; - } - - - @Override - protected Expression deepCloneWithIdentifierReplaced_inner( - String replacedIdentifier, Expression replacement, ReplacemenetState replacementState) { - ArrayList clonedKeys = (ArrayList) keys.clone(); - for (ListIterator iter = clonedKeys.listIterator(); iter.hasNext(); ) { - iter.set(((Expression) iter.next()).deepCloneWithIdentifierReplaced( - replacedIdentifier, replacement, replacementState)); - } - ArrayList clonedValues = (ArrayList) values.clone(); - for (ListIterator iter = clonedValues.listIterator(); iter.hasNext(); ) { - iter.set(((Expression) iter.next()).deepCloneWithIdentifierReplaced( - replacedIdentifier, replacement, replacementState)); - } - return new HashLiteral(clonedKeys, clonedValues); - } - - private class SequenceHash implements TemplateHashModelEx2 { - - private HashMap map; // maps keys to integer offset - private TemplateCollectionModel keyCollection, valueCollection; // ordered lists of keys and values - - SequenceHash(Environment env) throws TemplateException { - map = new LinkedHashMap(); - for (int i = 0; i < size; i++) { - Expression keyExp = (Expression) keys.get(i); - Expression valExp = (Expression) values.get(i); - String key = keyExp.evalAndCoerceToPlainText(env); - TemplateModel value = valExp.eval(env); - valExp.assertNonNull(value, env); - map.put(key, value); - } - } - - @Override - public int size() { - return size; - } - - @Override - public TemplateCollectionModel keys() { - if (keyCollection == null) { - keyCollection = new CollectionAndSequence(new SimpleSequence(map.keySet())); - } - return keyCollection; - } - - @Override - public TemplateCollectionModel values() { - if (valueCollection == null) { - valueCollection = new CollectionAndSequence(new SimpleSequence(map.values())); - } - return valueCollection; - } - - @Override - public TemplateModel get(String key) { - return (TemplateModel) map.get(key); - } - - @Override - public boolean isEmpty() { - return size == 0; - } - - @Override - public String toString() { - return getCanonicalForm(); - } - - @Override - public KeyValuePairIterator keyValuePairIterator() throws TemplateModelException { - return new KeyValuePairIterator() { - private final TemplateModelIterator keyIterator = keys().iterator(); - private final TemplateModelIterator valueIterator = values().iterator(); - - @Override - public boolean hasNext() throws TemplateModelException { - return keyIterator.hasNext(); - } - - @Override - public KeyValuePair next() throws TemplateModelException { - return new KeyValuePair() { - private final TemplateModel key = keyIterator.next(); - private final TemplateModel value = valueIterator.next(); - - @Override - public TemplateModel getKey() throws TemplateModelException { - return key; - } - - @Override - public TemplateModel getValue() throws TemplateModelException { - return value; - } - - }; - } - - }; - } - - } - - @Override - int getParameterCount() { - return size * 2; - } - - @Override - Object getParameterValue(int idx) { - checkIndex(idx); - return idx % 2 == 0 ? keys.get(idx / 2) : values.get(idx / 2); - } - - @Override - ParameterRole getParameterRole(int idx) { - checkIndex(idx); - return idx % 2 == 0 ? ParameterRole.ITEM_KEY : ParameterRole.ITEM_VALUE; - } - - private void checkIndex(int idx) { - if (idx >= size * 2) { - throw new IndexOutOfBoundsException(); - } - } - -}
