http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/7d784b2b/src/main/java/org/apache/freemarker/core/ast/ISOLikeTemplateDateFormat.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/freemarker/core/ast/ISOLikeTemplateDateFormat.java b/src/main/java/org/apache/freemarker/core/ast/ISOLikeTemplateDateFormat.java deleted file mode 100644 index ed94371..0000000 --- a/src/main/java/org/apache/freemarker/core/ast/ISOLikeTemplateDateFormat.java +++ /dev/null @@ -1,263 +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 java.util.TimeZone; - -import org.apache.freemarker.core.model.TemplateDateModel; -import org.apache.freemarker.core.model.TemplateModelException; -import org.apache.freemarker.core.util._DateUtil; -import org.apache.freemarker.core.util._StringUtil; -import org.apache.freemarker.core.util._DateUtil.CalendarFieldsToDateConverter; -import org.apache.freemarker.core.util._DateUtil.DateParseException; -import org.apache.freemarker.core.util._DateUtil.DateToISO8601CalendarFactory; - -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; - -abstract class ISOLikeTemplateDateFormat extends TemplateDateFormat { - - private static final String XS_LESS_THAN_SECONDS_ACCURACY_ERROR_MESSAGE - = "Less than seconds accuracy isn't allowed by the XML Schema format"; - private final ISOLikeTemplateDateFormatFactory factory; - private final Environment env; - protected final int dateType; - protected final boolean zonelessInput; - protected final TimeZone timeZone; - protected final Boolean forceUTC; - protected final Boolean showZoneOffset; - protected final int accuracy; - - /** - * @param formatString The value of the ..._format setting, like "iso nz". - * @param parsingStart The index of the char in the {@code settingValue} that directly after the prefix that has - * indicated the exact formatter class (like "iso" or "xs") - */ - public ISOLikeTemplateDateFormat( - final String formatString, int parsingStart, - int dateType, boolean zonelessInput, - TimeZone timeZone, - ISOLikeTemplateDateFormatFactory factory, Environment env) - throws InvalidFormatParametersException, UnknownDateTypeFormattingUnsupportedException { - this.factory = factory; - this.env = env; - if (dateType == TemplateDateModel.UNKNOWN) { - throw new UnknownDateTypeFormattingUnsupportedException(); - } - - this.dateType = dateType; - this.zonelessInput = zonelessInput; - - final int ln = formatString.length(); - boolean afterSeparator = false; - int i = parsingStart; - int accuracy = _DateUtil.ACCURACY_MILLISECONDS; - Boolean showZoneOffset = null; - Boolean forceUTC = Boolean.FALSE; - while (i < ln) { - final char c = formatString.charAt(i++); - if (c == '_' || c == ' ') { - afterSeparator = true; - } else { - if (!afterSeparator) { - throw new InvalidFormatParametersException( - "Missing space or \"_\" before \"" + c + "\" (at char pos. " + i + ")."); - } - - switch (c) { - case 'h': - case 'm': - case 's': - if (accuracy != _DateUtil.ACCURACY_MILLISECONDS) { - throw new InvalidFormatParametersException( - "Character \"" + c + "\" is unexpected as accuracy was already specified earlier " - + "(at char pos. " + i + ")."); - } - switch (c) { - case 'h': - if (isXSMode()) { - throw new InvalidFormatParametersException( - XS_LESS_THAN_SECONDS_ACCURACY_ERROR_MESSAGE); - } - accuracy = _DateUtil.ACCURACY_HOURS; - break; - case 'm': - if (i < ln && formatString.charAt(i) == 's') { - i++; - accuracy = _DateUtil.ACCURACY_MILLISECONDS_FORCED; - } else { - if (isXSMode()) { - throw new InvalidFormatParametersException( - XS_LESS_THAN_SECONDS_ACCURACY_ERROR_MESSAGE); - } - accuracy = _DateUtil.ACCURACY_MINUTES; - } - break; - case 's': - accuracy = _DateUtil.ACCURACY_SECONDS; - break; - } - break; - case 'f': - if (i < ln && formatString.charAt(i) == 'u') { - checkForceUTCNotSet(forceUTC); - i++; - forceUTC = Boolean.TRUE; - break; - } - // Falls through - case 'n': - if (showZoneOffset != null) { - throw new InvalidFormatParametersException( - "Character \"" + c + "\" is unexpected as zone offset visibility was already " - + "specified earlier. (at char pos. " + i + ")."); - } - switch (c) { - case 'n': - if (i < ln && formatString.charAt(i) == 'z') { - i++; - showZoneOffset = Boolean.FALSE; - } else { - throw new InvalidFormatParametersException( - "\"n\" must be followed by \"z\" (at char pos. " + i + ")."); - } - break; - case 'f': - if (i < ln && formatString.charAt(i) == 'z') { - i++; - showZoneOffset = Boolean.TRUE; - } else { - throw new InvalidFormatParametersException( - "\"f\" must be followed by \"z\" (at char pos. " + i + ")."); - } - break; - } - break; - case 'u': - checkForceUTCNotSet(forceUTC); - forceUTC = null; // means UTC will be used except for zonelessInput - break; - default: - throw new InvalidFormatParametersException( - "Unexpected character, " + _StringUtil.jQuote(String.valueOf(c)) - + ". Expected the beginning of one of: h, m, s, ms, nz, fz, u" - + " (at char pos. " + i + ")."); - } // switch - afterSeparator = false; - } // else - } // while - - this.accuracy = accuracy; - this.showZoneOffset = showZoneOffset; - this.forceUTC = forceUTC; - this.timeZone = timeZone; - } - - private void checkForceUTCNotSet(Boolean fourceUTC) throws InvalidFormatParametersException { - if (fourceUTC != Boolean.FALSE) { - throw new InvalidFormatParametersException( - "The UTC usage option was already set earlier."); - } - } - - @Override - public final String formatToPlainText(TemplateDateModel dateModel) throws TemplateModelException { - final Date date = TemplateFormatUtil.getNonNullDate(dateModel); - return format( - date, - dateType != TemplateDateModel.TIME, - dateType != TemplateDateModel.DATE, - showZoneOffset == null - ? !zonelessInput - : showZoneOffset.booleanValue(), - accuracy, - (forceUTC == null ? !zonelessInput : forceUTC.booleanValue()) ? _DateUtil.UTC : timeZone, - factory.getISOBuiltInCalendar(env)); - } - - protected abstract String format(Date date, - boolean datePart, boolean timePart, boolean offsetPart, - int accuracy, - TimeZone timeZone, - DateToISO8601CalendarFactory calendarFactory); - - @Override - @SuppressFBWarnings(value = "RC_REF_COMPARISON_BAD_PRACTICE_BOOLEAN", - justification = "Known to use the singleton Boolean-s only") - public final Date parse(String s, int dateType) throws UnparsableValueException { - CalendarFieldsToDateConverter calToDateConverter = factory.getCalendarFieldsToDateCalculator(env); - TimeZone tz = forceUTC != Boolean.FALSE ? _DateUtil.UTC : timeZone; - try { - if (dateType == TemplateDateModel.DATE) { - return parseDate(s, tz, calToDateConverter); - } else if (dateType == TemplateDateModel.TIME) { - return parseTime(s, tz, calToDateConverter); - } else if (dateType == TemplateDateModel.DATETIME) { - return parseDateTime(s, tz, calToDateConverter); - } else { - throw new BugException("Unexpected date type: " + dateType); - } - } catch (DateParseException e) { - throw new UnparsableValueException(e.getMessage(), e); - } - } - - protected abstract Date parseDate( - String s, TimeZone tz, - CalendarFieldsToDateConverter calToDateConverter) - throws DateParseException; - - protected abstract Date parseTime( - String s, TimeZone tz, - CalendarFieldsToDateConverter calToDateConverter) - throws DateParseException; - - protected abstract Date parseDateTime( - String s, TimeZone tz, - CalendarFieldsToDateConverter calToDateConverter) - throws DateParseException; - - @Override - public final String getDescription() { - switch (dateType) { - case TemplateDateModel.DATE: return getDateDescription(); - case TemplateDateModel.TIME: return getTimeDescription(); - case TemplateDateModel.DATETIME: return getDateTimeDescription(); - default: return "<error: wrong format dateType>"; - } - } - - protected abstract String getDateDescription(); - protected abstract String getTimeDescription(); - protected abstract String getDateTimeDescription(); - - @Override - public final boolean isLocaleBound() { - return false; - } - - @Override - public boolean isTimeZoneBound() { - return true; - } - - protected abstract boolean isXSMode(); - -}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/7d784b2b/src/main/java/org/apache/freemarker/core/ast/ISOLikeTemplateDateFormatFactory.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/freemarker/core/ast/ISOLikeTemplateDateFormatFactory.java b/src/main/java/org/apache/freemarker/core/ast/ISOLikeTemplateDateFormatFactory.java deleted file mode 100644 index e51f2d0..0000000 --- a/src/main/java/org/apache/freemarker/core/ast/ISOLikeTemplateDateFormatFactory.java +++ /dev/null @@ -1,52 +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.util._DateUtil.CalendarFieldsToDateConverter; -import org.apache.freemarker.core.util._DateUtil.DateToISO8601CalendarFactory; -import org.apache.freemarker.core.util._DateUtil.TrivialCalendarFieldsToDateConverter; -import org.apache.freemarker.core.util._DateUtil.TrivialDateToISO8601CalendarFactory; - -abstract class ISOLikeTemplateDateFormatFactory extends TemplateDateFormatFactory { - - private static final Object DATE_TO_CAL_CONVERTER_KEY = new Object(); - private static final Object CAL_TO_DATE_CONVERTER_KEY = new Object(); - - protected ISOLikeTemplateDateFormatFactory() { } - - public DateToISO8601CalendarFactory getISOBuiltInCalendar(Environment env) { - DateToISO8601CalendarFactory r = (DateToISO8601CalendarFactory) env.getCustomState(DATE_TO_CAL_CONVERTER_KEY); - if (r == null) { - r = new TrivialDateToISO8601CalendarFactory(); - env.setCustomState(DATE_TO_CAL_CONVERTER_KEY, r); - } - return r; - } - - public CalendarFieldsToDateConverter getCalendarFieldsToDateCalculator(Environment env) { - CalendarFieldsToDateConverter r = (CalendarFieldsToDateConverter) env.getCustomState(CAL_TO_DATE_CONVERTER_KEY); - if (r == null) { - r = new TrivialCalendarFieldsToDateConverter(); - env.setCustomState(CAL_TO_DATE_CONVERTER_KEY, r); - } - return r; - } - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/7d784b2b/src/main/java/org/apache/freemarker/core/ast/ISOTemplateDateFormat.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/freemarker/core/ast/ISOTemplateDateFormat.java b/src/main/java/org/apache/freemarker/core/ast/ISOTemplateDateFormat.java deleted file mode 100644 index 7bff342..0000000 --- a/src/main/java/org/apache/freemarker/core/ast/ISOTemplateDateFormat.java +++ /dev/null @@ -1,87 +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 java.util.TimeZone; - -import org.apache.freemarker.core.util._DateUtil; -import org.apache.freemarker.core.util._DateUtil.CalendarFieldsToDateConverter; -import org.apache.freemarker.core.util._DateUtil.DateParseException; -import org.apache.freemarker.core.util._DateUtil.DateToISO8601CalendarFactory; - -final class ISOTemplateDateFormat extends ISOLikeTemplateDateFormat { - - ISOTemplateDateFormat( - String settingValue, int parsingStart, - int dateType, boolean zonelessInput, - TimeZone timeZone, - ISOLikeTemplateDateFormatFactory factory, - Environment env) - throws InvalidFormatParametersException, UnknownDateTypeFormattingUnsupportedException { - super(settingValue, parsingStart, dateType, zonelessInput, timeZone, factory, env); - } - - @Override - protected String format(Date date, boolean datePart, boolean timePart, boolean offsetPart, int accuracy, - TimeZone timeZone, DateToISO8601CalendarFactory calendarFactory) { - return _DateUtil.dateToISO8601String( - date, datePart, timePart, timePart && offsetPart, accuracy, timeZone, calendarFactory); - } - - @Override - protected Date parseDate(String s, TimeZone tz, CalendarFieldsToDateConverter calToDateConverter) - throws DateParseException { - return _DateUtil.parseISO8601Date(s, tz, calToDateConverter); - } - - @Override - protected Date parseTime(String s, TimeZone tz, CalendarFieldsToDateConverter calToDateConverter) - throws DateParseException { - return _DateUtil.parseISO8601Time(s, tz, calToDateConverter); - } - - @Override - protected Date parseDateTime(String s, TimeZone tz, - CalendarFieldsToDateConverter calToDateConverter) throws DateParseException { - return _DateUtil.parseISO8601DateTime(s, tz, calToDateConverter); - } - - @Override - protected String getDateDescription() { - return "ISO 8601 (subset) date"; - } - - @Override - protected String getTimeDescription() { - return "ISO 8601 (subset) time"; - } - - @Override - protected String getDateTimeDescription() { - return "ISO 8601 (subset) date-time"; - } - - @Override - protected boolean isXSMode() { - return false; - } - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/7d784b2b/src/main/java/org/apache/freemarker/core/ast/ISOTemplateDateFormatFactory.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/freemarker/core/ast/ISOTemplateDateFormatFactory.java b/src/main/java/org/apache/freemarker/core/ast/ISOTemplateDateFormatFactory.java deleted file mode 100644 index 4f5d484..0000000 --- a/src/main/java/org/apache/freemarker/core/ast/ISOTemplateDateFormatFactory.java +++ /dev/null @@ -1,43 +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.Locale; -import java.util.TimeZone; - -class ISOTemplateDateFormatFactory extends ISOLikeTemplateDateFormatFactory { - - static final ISOTemplateDateFormatFactory INSTANCE = new ISOTemplateDateFormatFactory(); - - private ISOTemplateDateFormatFactory() { - // Not meant to be instantiated - } - - @Override - public TemplateDateFormat get(String params, int dateType, Locale locale, TimeZone timeZone, boolean zonelessInput, - Environment env) throws UnknownDateTypeFormattingUnsupportedException, InvalidFormatParametersException { - // We don't cache these as creating them is cheap (only 10% speedup of ${d?string.xs} with caching) - return new ISOTemplateDateFormat( - params, 3, - dateType, zonelessInput, - timeZone, this, env); - } - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/7d784b2b/src/main/java/org/apache/freemarker/core/ast/Identifier.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/freemarker/core/ast/Identifier.java b/src/main/java/org/apache/freemarker/core/ast/Identifier.java deleted file mode 100644 index 3ac82d5..0000000 --- a/src/main/java/org/apache/freemarker/core/ast/Identifier.java +++ /dev/null @@ -1,106 +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.TemplateModel; -import org.apache.freemarker.core.util._StringUtil; - -/** - * A reference to a top-level variable - */ -final class Identifier extends Expression { - - private final String name; - - Identifier(String name) { - this.name = name; - } - - @Override - TemplateModel _eval(Environment env) throws TemplateException { - try { - return env.getVariable(name); - } catch (NullPointerException e) { - if (env == null) { - throw new _MiscTemplateException( - "Variables are not available (certainly you are in a parse-time executed directive). " - + "The name of the variable you tried to read: ", name); - } else { - throw e; - } - } - } - - @Override - public String getCanonicalForm() { - return _StringUtil.toFTLTopLevelIdentifierReference(name); - } - - /** - * The name of the identifier without any escaping or other syntactical distortions. - */ - String getName() { - return name; - } - - @Override - String getNodeTypeSymbol() { - return getCanonicalForm(); - } - - @Override - boolean isLiteral() { - return false; - } - - @Override - int getParameterCount() { - return 0; - } - - @Override - Object getParameterValue(int idx) { - throw new IndexOutOfBoundsException(); - } - - @Override - ParameterRole getParameterRole(int idx) { - throw new IndexOutOfBoundsException(); - } - - @Override - protected Expression deepCloneWithIdentifierReplaced_inner( - String replacedIdentifier, Expression replacement, ReplacemenetState replacementState) { - if (name.equals(replacedIdentifier)) { - if (replacementState.replacementAlreadyInUse) { - Expression clone = replacement.deepCloneWithIdentifierReplaced(null, null, replacementState); - clone.copyLocationFrom(replacement); - return clone; - } else { - replacementState.replacementAlreadyInUse = true; - return replacement; - } - } else { - return new Identifier(name); - } - } - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/7d784b2b/src/main/java/org/apache/freemarker/core/ast/IfBlock.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/freemarker/core/ast/IfBlock.java b/src/main/java/org/apache/freemarker/core/ast/IfBlock.java deleted file mode 100644 index 4d7ef5c..0000000 --- a/src/main/java/org/apache/freemarker/core/ast/IfBlock.java +++ /dev/null @@ -1,109 +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; - -/** - * Container for a group of related #if, #elseif and #else elements. - * Each such block is a nested {@link ConditionalBlock}. Note that if an #if has no #else of #elseif, - * {@link ConditionalBlock} doesn't need this parent element. - */ -final class IfBlock extends TemplateElement { - - IfBlock(ConditionalBlock block) { - setChildBufferCapacity(1); - addBlock(block); - } - - void addBlock(ConditionalBlock block) { - addChild(block); - } - - @Override - TemplateElement[] accept(Environment env) throws TemplateException, IOException { - int ln = getChildCount(); - for (int i = 0; i < ln; i++) { - ConditionalBlock cblock = (ConditionalBlock) getChild(i); - Expression condition = cblock.condition; - env.replaceElementStackTop(cblock); - if (condition == null || condition.evalToBoolean(env)) { - return cblock.getChildBuffer(); - } - } - return null; - } - - @Override - TemplateElement postParseCleanup(boolean stripWhitespace) - throws ParseException { - if (getChildCount() == 1) { - ConditionalBlock cblock = (ConditionalBlock) getChild(0); - cblock.setLocation(getTemplate(), cblock, this); - return cblock.postParseCleanup(stripWhitespace); - } else { - return super.postParseCleanup(stripWhitespace); - } - } - - @Override - protected String dump(boolean canonical) { - if (canonical) { - StringBuilder buf = new StringBuilder(); - int ln = getChildCount(); - for (int i = 0; i < ln; i++) { - ConditionalBlock cblock = (ConditionalBlock) getChild(i); - buf.append(cblock.dump(canonical)); - } - buf.append("</#if>"); - return buf.toString(); - } else { - return getNodeTypeSymbol(); - } - } - - @Override - String getNodeTypeSymbol() { - return "#if-#elseif-#else-container"; - } - - @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/Include.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/freemarker/core/ast/Include.java b/src/main/java/org/apache/freemarker/core/ast/Include.java deleted file mode 100644 index 8e9d78b..0000000 --- a/src/main/java/org/apache/freemarker/core/ast/Include.java +++ /dev/null @@ -1,259 +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.Template; -import org.apache.freemarker.core.TemplateException; -import org.apache.freemarker.core.model.TemplateModel; -import org.apache.freemarker.core.model.TemplateScalarModel; -import org.apache.freemarker.core.templateresolver.MalformedTemplateNameException; -import org.apache.freemarker.core.util._StringUtil; - - -/** - * An instruction that gets another template - * and processes it within the current template. - */ -final class Include extends TemplateElement { - - private final Expression includedTemplateNameExp, encodingExp, parseExp, ignoreMissingExp; - private final String encoding; - private final Boolean parse; - private final Boolean ignoreMissingExpPrecalcedValue; - - /** - * @param template the template that this <tt>#include</tt> is a part of. - * @param includedTemplateNameExp the path of the template to be included. - * @param encodingExp the encoding to be used or null, if it's the default. - * @param parseExp whether the template should be parsed (or is raw text) - */ - Include(Template template, - Expression includedTemplateNameExp, - Expression encodingExp, Expression parseExp, Expression ignoreMissingExp) throws ParseException { - this.includedTemplateNameExp = includedTemplateNameExp; - - this.encodingExp = encodingExp; - if (encodingExp == null) { - encoding = null; - } else { - if (encodingExp.isLiteral()) { - try { - TemplateModel tm = encodingExp.eval(null); - if (!(tm instanceof TemplateScalarModel)) { - throw new ParseException("Expected a string as the value of the \"encoding\" argument", - encodingExp); - } - encoding = ((TemplateScalarModel) tm).getAsString(); - } catch (TemplateException e) { - // evaluation of literals must not throw a TemplateException - throw new BugException(e); - } - } else { - encoding = null; - } - } - - this.parseExp = parseExp; - if (parseExp == null) { - parse = Boolean.TRUE; - } else { - if (parseExp.isLiteral()) { - try { - if (parseExp instanceof StringLiteral) { - // Legacy - parse = Boolean.valueOf(_StringUtil.getYesNo(parseExp.evalAndCoerceToPlainText(null))); - } else { - try { - parse = Boolean.valueOf(parseExp.evalToBoolean(template.getConfiguration())); - } catch (NonBooleanException e) { - throw new ParseException("Expected a boolean or string as the value of the parse attribute", - parseExp, e); - } - } - } catch (TemplateException e) { - // evaluation of literals must not throw a TemplateException - throw new BugException(e); - } - } else { - parse = null; - } - } - - this.ignoreMissingExp = ignoreMissingExp; - if (ignoreMissingExp != null && ignoreMissingExp.isLiteral()) { - try { - try { - ignoreMissingExpPrecalcedValue = Boolean.valueOf( - ignoreMissingExp.evalToBoolean(template.getConfiguration())); - } catch (NonBooleanException e) { - throw new ParseException("Expected a boolean as the value of the \"ignore_missing\" attribute", - ignoreMissingExp, e); - } - } catch (TemplateException e) { - // evaluation of literals must not throw a TemplateException - throw new BugException(e); - } - } else { - ignoreMissingExpPrecalcedValue = null; - } - } - - @Override - TemplateElement[] accept(Environment env) throws TemplateException, IOException { - final String includedTemplateName = includedTemplateNameExp.evalAndCoerceToPlainText(env); - final String fullIncludedTemplateName; - try { - fullIncludedTemplateName = env.toFullTemplateName(getTemplate().getName(), includedTemplateName); - } catch (MalformedTemplateNameException e) { - throw new _MiscTemplateException(e, env, - "Malformed template name ", new _DelayedJQuote(e.getTemplateName()), ":\n", - e.getMalformednessDescription()); - } - - final String encoding = this.encoding != null - ? this.encoding - : (encodingExp != null - ? encodingExp.evalAndCoerceToPlainText(env) - : null); - - final boolean parse; - if (this.parse != null) { - parse = this.parse.booleanValue(); - } else { - TemplateModel tm = parseExp.eval(env); - if (tm instanceof TemplateScalarModel) { - // Legacy - parse = getYesNo(parseExp, EvalUtil.modelToString((TemplateScalarModel) tm, parseExp, env)); - } else { - parse = parseExp.modelToBoolean(tm, env); - } - } - - final boolean ignoreMissing; - if (ignoreMissingExpPrecalcedValue != null) { - ignoreMissing = ignoreMissingExpPrecalcedValue.booleanValue(); - } else if (ignoreMissingExp != null) { - ignoreMissing = ignoreMissingExp.evalToBoolean(env); - } else { - ignoreMissing = false; - } - - final Template includedTemplate; - try { - includedTemplate = env.getTemplateForInclusion(fullIncludedTemplateName, encoding, parse, ignoreMissing); - } catch (IOException e) { - throw new _MiscTemplateException(e, env, - "Template inclusion failed (for parameter value ", - new _DelayedJQuote(includedTemplateName), - "):\n", new _DelayedGetMessage(e)); - } - - if (includedTemplate != null) { - env.include(includedTemplate); - } - return null; - } - - @Override - protected String dump(boolean canonical) { - StringBuilder buf = new StringBuilder(); - if (canonical) buf.append('<'); - buf.append(getNodeTypeSymbol()); - buf.append(' '); - buf.append(includedTemplateNameExp.getCanonicalForm()); - if (encodingExp != null) { - buf.append(" encoding=").append(encodingExp.getCanonicalForm()); - } - if (parseExp != null) { - buf.append(" parse=").append(parseExp.getCanonicalForm()); - } - if (ignoreMissingExp != null) { - buf.append(" ignore_missing=").append(ignoreMissingExp.getCanonicalForm()); - } - if (canonical) buf.append("/>"); - return buf.toString(); - } - - @Override - String getNodeTypeSymbol() { - return "#include"; - } - - @Override - int getParameterCount() { - return 3; - } - - @Override - Object getParameterValue(int idx) { - switch (idx) { - case 0: return includedTemplateNameExp; - case 1: return parseExp; - case 2: return encodingExp; - case 3: return ignoreMissingExp; - default: throw new IndexOutOfBoundsException(); - } - } - - @Override - ParameterRole getParameterRole(int idx) { - switch (idx) { - case 0: return ParameterRole.TEMPLATE_NAME; - case 1: return ParameterRole.PARSE_PARAMETER; - case 2: return ParameterRole.ENCODING_PARAMETER; - case 3: return ParameterRole.IGNORE_MISSING_PARAMETER; - default: throw new IndexOutOfBoundsException(); - } - } - - @Override - boolean isNestedBlockRepeater() { - return false; - } - - private boolean getYesNo(Expression exp, String s) throws TemplateException { - try { - return _StringUtil.getYesNo(s); - } catch (IllegalArgumentException iae) { - throw new _MiscTemplateException(exp, - "Value must be boolean (or one of these strings: " - + "\"n\", \"no\", \"f\", \"false\", \"y\", \"yes\", \"t\", \"true\"), but it was ", - new _DelayedJQuote(s), "."); - } - } - -/* - boolean heedsOpeningWhitespace() { - return true; - } - - boolean heedsTrailingWhitespace() { - return true; - } -*/ - - @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/Interpolation.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/freemarker/core/ast/Interpolation.java b/src/main/java/org/apache/freemarker/core/ast/Interpolation.java deleted file mode 100644 index 573f3c2..0000000 --- a/src/main/java/org/apache/freemarker/core/ast/Interpolation.java +++ /dev/null @@ -1,48 +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; - -abstract class Interpolation extends TemplateElement { - - protected abstract String dump(boolean canonical, boolean inStringLiteral); - - @Override - protected final String dump(boolean canonical) { - return dump(canonical, false); - } - - final String getCanonicalFormInStringLiteral() { - return dump(true, true); - } - - /** - * Returns the already type-converted value that this interpolation will insert into the output. - * - * @return A {@link String} or {@link TemplateMarkupOutputModel}. Not {@code null}. - */ - protected abstract Object calculateInterpolatedStringOrMarkup(Environment env) throws TemplateException; - - @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/Interpret.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/freemarker/core/ast/Interpret.java b/src/main/java/org/apache/freemarker/core/ast/Interpret.java deleted file mode 100644 index 8c4274c..0000000 --- a/src/main/java/org/apache/freemarker/core/ast/Interpret.java +++ /dev/null @@ -1,157 +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.StringReader; -import java.io.Writer; -import java.util.Map; - -import org.apache.freemarker.core.Template; -import org.apache.freemarker.core.TemplateException; -import org.apache.freemarker.core.model.TemplateModel; -import org.apache.freemarker.core.model.TemplateModelException; -import org.apache.freemarker.core.model.TemplateScalarModel; -import org.apache.freemarker.core.model.TemplateSequenceModel; -import org.apache.freemarker.core.model.TemplateTransformModel; - - -/** - * A method that takes a parameter and evaluates it as a scalar, - * then treats that scalar as template source code and returns a - * transform model that evaluates the template in place. - * The template inherits the configuration and environment of the executing - * template. By default, its name will be equal to - * <tt>executingTemplate.getName() + "$anonymous_interpreted"</tt>. You can - * specify another parameter to the method call in which case the - * template name suffix is the specified id instead of "anonymous_interpreted". - */ -class Interpret extends OutputFormatBoundBuiltIn { - - /** - * Constructs a template on-the-fly and returns it embedded in a - * {@link TemplateTransformModel}. - * - * <p>The built-in has two arguments: - * the arguments passed to the method. It can receive at - * least one and at most two arguments, both must evaluate to a scalar. - * The first scalar is interpreted as a template source code and a template - * is built from it. The second (optional) is used to give the generated - * template a name. - * - * @return a {@link TemplateTransformModel} that when executed inside - * a <tt><transform></tt> block will process the generated template - * just as if it had been <tt><transform></tt>-ed at that point. - */ - @Override - protected TemplateModel calculateResult(Environment env) throws TemplateException { - TemplateModel model = target.eval(env); - Expression sourceExpr = null; - String id = "anonymous_interpreted"; - if (model instanceof TemplateSequenceModel) { - sourceExpr = ((Expression) new DynamicKeyName(target, new NumberLiteral(Integer.valueOf(0))).copyLocationFrom(target)); - if (((TemplateSequenceModel) model).size() > 1) { - id = ((Expression) new DynamicKeyName(target, new NumberLiteral(Integer.valueOf(1))).copyLocationFrom(target)).evalAndCoerceToPlainText(env); - } - } else if (model instanceof TemplateScalarModel) { - sourceExpr = target; - } else { - throw new UnexpectedTypeException( - target, model, - "sequence or string", new Class[] { TemplateSequenceModel.class, TemplateScalarModel.class }, - env); - } - String templateSource = sourceExpr.evalAndCoerceToPlainText(env); - Template parentTemplate = env.getCurrentTemplate(); - - final Template interpretedTemplate; - try { - ParserConfiguration pCfg = parentTemplate.getParserConfiguration(); - // pCfg.outputFormat is exceptional: it's inherited from the lexical context - if (pCfg.getOutputFormat() != outputFormat) { - pCfg = new _ParserConfigurationWithInheritedFormat( - pCfg, outputFormat, Integer.valueOf(autoEscapingPolicy)); - } - interpretedTemplate = new Template( - (parentTemplate.getName() != null ? parentTemplate.getName() : "nameless_template") + "->" + id, - null, - new StringReader(templateSource), - parentTemplate.getConfiguration(), pCfg, - null); - } catch (IOException e) { - throw new _MiscTemplateException(this, e, env, new Object[] { - "Template parsing with \"?", key, "\" has failed with this error:\n\n", - MessageUtil.EMBEDDED_MESSAGE_BEGIN, - new _DelayedGetMessage(e), - MessageUtil.EMBEDDED_MESSAGE_END, - "\n\nThe failed expression:" }); - } - - interpretedTemplate.setLocale(env.getLocale()); - return new TemplateProcessorModel(interpretedTemplate); - } - - private class TemplateProcessorModel - implements - TemplateTransformModel { - private final Template template; - - TemplateProcessorModel(Template template) { - this.template = template; - } - - @Override - public Writer getWriter(final Writer out, Map args) throws TemplateModelException, IOException { - try { - Environment env = Environment.getCurrentEnvironment(); - boolean lastFIRE = env.setFastInvalidReferenceExceptions(false); - try { - env.include(template); - } finally { - env.setFastInvalidReferenceExceptions(lastFIRE); - } - } catch (Exception e) { - throw new _TemplateModelException(e, - "Template created with \"?", key, "\" has stopped with this error:\n\n", - MessageUtil.EMBEDDED_MESSAGE_BEGIN, - new _DelayedGetMessage(e), - MessageUtil.EMBEDDED_MESSAGE_END); - } - - return new Writer(out) - { - @Override - public void close() { - } - - @Override - public void flush() throws IOException { - out.flush(); - } - - @Override - public void write(char[] cbuf, int off, int len) throws IOException { - out.write(cbuf, off, len); - } - }; - } - } - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/7d784b2b/src/main/java/org/apache/freemarker/core/ast/InvalidFormatParametersException.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/freemarker/core/ast/InvalidFormatParametersException.java b/src/main/java/org/apache/freemarker/core/ast/InvalidFormatParametersException.java deleted file mode 100644 index a9f7a12..0000000 --- a/src/main/java/org/apache/freemarker/core/ast/InvalidFormatParametersException.java +++ /dev/null @@ -1,37 +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; - -/** - * Used when creating {@link TemplateDateFormat}-s and {@link TemplateNumberFormat}-s to indicate that the parameters - * part of the format string (like some kind of pattern) is malformed. - * - * @since 2.3.24 - */ -public final class InvalidFormatParametersException extends InvalidFormatStringException { - - public InvalidFormatParametersException(String message, Throwable cause) { - super(message, cause); - } - - public InvalidFormatParametersException(String message) { - this(message, null); - } - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/7d784b2b/src/main/java/org/apache/freemarker/core/ast/InvalidFormatStringException.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/freemarker/core/ast/InvalidFormatStringException.java b/src/main/java/org/apache/freemarker/core/ast/InvalidFormatStringException.java deleted file mode 100644 index 61a7151..0000000 --- a/src/main/java/org/apache/freemarker/core/ast/InvalidFormatStringException.java +++ /dev/null @@ -1,37 +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; - -/** - * Used when creating {@link TemplateDateFormat}-s and {@link TemplateNumberFormat}-s to indicate that the format - * string (like the value of the {@code dateFormat} setting) is malformed. - * - * @since 2.3.24 - */ -public abstract class InvalidFormatStringException extends TemplateValueFormatException { - - public InvalidFormatStringException(String message, Throwable cause) { - super(message, cause); - } - - public InvalidFormatStringException(String message) { - this(message, null); - } - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/7d784b2b/src/main/java/org/apache/freemarker/core/ast/InvalidReferenceException.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/freemarker/core/ast/InvalidReferenceException.java b/src/main/java/org/apache/freemarker/core/ast/InvalidReferenceException.java deleted file mode 100644 index 50b44dc..0000000 --- a/src/main/java/org/apache/freemarker/core/ast/InvalidReferenceException.java +++ /dev/null @@ -1,169 +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; - -/** - * A subclass of {@link TemplateException} that says that an FTL expression has evaluated to {@code null} or it refers - * to something that doesn't exist. At least in FreeMarker 2.3.x these two cases aren't distinguished. - */ -public class InvalidReferenceException extends TemplateException { - - static final InvalidReferenceException FAST_INSTANCE; - static { - Environment prevEnv = Environment.getCurrentEnvironment(); - try { - Environment.setCurrentEnvironment(null); - FAST_INSTANCE = new InvalidReferenceException( - "Invalid reference. Details are unavilable, as this should have been handled by an FTL construct. " - + "If it wasn't, that's problably a bug in FreeMarker.", - null); - } finally { - Environment.setCurrentEnvironment(prevEnv); - } - } - - private static final Object[] TIP = { - "If the failing expression is known to be legally refer to something that's sometimes null or missing, " - + "either specify a default value like myOptionalVar!myDefault, or use ", - "<#if myOptionalVar??>", "when-present", "<#else>", "when-missing", "</#if>", - ". (These only cover the last step of the expression; to cover the whole expression, " - + "use parenthesis: (myOptionalVar.foo)!myDefault, (myOptionalVar.foo)??" - }; - - private static final Object[] TIP_MISSING_ASSIGNMENT_TARGET = { - "If the target variable is known to be legally null or missing sometimes, instead of something like ", - "<#assign x += 1>", ", you could write ", "<#if x??>", "<#assign x += 1>", "</#if>", - " or ", "<#assign x = (x!0) + 1>" - }; - - private static final String TIP_NO_DOLLAR = - "Variable references must not start with \"$\", unless the \"$\" is really part of the variable name."; - - private static final String TIP_LAST_STEP_DOT = - "It's the step after the last dot that caused this error, not those before it."; - - private static final String TIP_LAST_STEP_SQUARE_BRACKET = - "It's the final [] step that caused this error, not those before it."; - - private static final String TIP_JSP_TAGLIBS = - "The \"JspTaglibs\" variable isn't a core FreeMarker feature; " - + "it's only available when templates are invoked through org.apache.freemarker.servlet.FreemarkerServlet" - + " (or other custom FreeMarker-JSP integration solution)."; - - /** - * Creates and invalid reference exception that contains no information about what was missing or null. - * As such, try to avoid this constructor. - */ - public InvalidReferenceException(Environment env) { - super("Invalid reference: The expression has evaluated to null or refers to something that doesn't exist.", - env); - } - - /** - * Creates and invalid reference exception that contains no programmatically extractable information about the - * blamed expression. As such, try to avoid this constructor, unless need to raise this expression from outside - * the FreeMarker core. - */ - public InvalidReferenceException(String description, Environment env) { - super(description, env); - } - - /** - * This is the recommended constructor, but it's only used internally, and has no backward compatibility guarantees. - * - * @param expression The expression that evaluates to missing or null. The last step of the expression should be - * the failing one, like in {@code goodStep.failingStep.furtherStep} it should only contain - * {@code goodStep.failingStep}. - */ - InvalidReferenceException(_ErrorDescriptionBuilder description, Environment env, Expression expression) { - super(null, env, expression, description); - } - - /** - * Use this whenever possible, as it returns {@link #FAST_INSTANCE} instead of creating a new instance, when - * appropriate. - */ - static InvalidReferenceException getInstance(Expression blamed, Environment env) { - if (env != null && env.getFastInvalidReferenceExceptions()) { - return FAST_INSTANCE; - } else { - if (blamed != null) { - final _ErrorDescriptionBuilder errDescBuilder - = new _ErrorDescriptionBuilder("The following has evaluated to null or missing:").blame(blamed); - if (endsWithDollarVariable(blamed)) { - errDescBuilder.tips(TIP_NO_DOLLAR, TIP); - } else if (blamed instanceof Dot) { - final String rho = ((Dot) blamed).getRHO(); - String nameFixTip = null; - if ("size".equals(rho)) { - nameFixTip = "To query the size of a collection or map use ?size, like myList?size"; - } else if ("length".equals(rho)) { - nameFixTip = "To query the length of a string use ?length, like myString?size"; - } - errDescBuilder.tips( - nameFixTip == null - ? new Object[] { TIP_LAST_STEP_DOT, TIP } - : new Object[] { TIP_LAST_STEP_DOT, nameFixTip, TIP }); - } else if (blamed instanceof DynamicKeyName) { - errDescBuilder.tips(TIP_LAST_STEP_SQUARE_BRACKET, TIP); - } else if (blamed instanceof Identifier - && ((Identifier) blamed).getName().equals("JspTaglibs")) { - errDescBuilder.tips(TIP_JSP_TAGLIBS, TIP); - } else { - errDescBuilder.tip(TIP); - } - return new InvalidReferenceException(errDescBuilder, env, blamed); - } else { - return new InvalidReferenceException(env); - } - } - } - - /** - * Used for assignments that use operators like {@code +=}, when the target variable was null/missing. - */ - static InvalidReferenceException getInstance(String missingAssignedVarName, String assignmentOperator, - Environment env) { - if (env != null && env.getFastInvalidReferenceExceptions()) { - return FAST_INSTANCE; - } else { - final _ErrorDescriptionBuilder errDescBuilder = new _ErrorDescriptionBuilder( - "The target variable of the assignment, ", - new _DelayedJQuote(missingAssignedVarName), - ", was null or missing, but the \"", - assignmentOperator, "\" operator needs to get its value before assigning to it." - ); - if (missingAssignedVarName.startsWith("$")) { - errDescBuilder.tips(TIP_NO_DOLLAR, TIP_MISSING_ASSIGNMENT_TARGET); - } else { - errDescBuilder.tip(TIP_MISSING_ASSIGNMENT_TARGET); - } - return new InvalidReferenceException(errDescBuilder, env, null); - } - } - - private static boolean endsWithDollarVariable(Expression blame) { - return blame instanceof Identifier && ((Identifier) blame).getName().startsWith("$") - || blame instanceof Dot && ((Dot) blame).getRHO().startsWith("$"); - } - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/7d784b2b/src/main/java/org/apache/freemarker/core/ast/Items.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/freemarker/core/ast/Items.java b/src/main/java/org/apache/freemarker/core/ast/Items.java deleted file mode 100644 index 6f9fa40..0000000 --- a/src/main/java/org/apache/freemarker/core/ast/Items.java +++ /dev/null @@ -1,121 +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.IteratorBlock.IterationContext; -import org.apache.freemarker.core.util._StringUtil; - -/** - * An #items element. - */ -class Items extends TemplateElement { - - private final String loopVarName; - private final String loopVar2Name; - - /** - * @param loopVar2Name - * For non-hash listings always {@code null}, for hash listings {@code loopVarName} and - * {@code loopVarName2} holds the key- and value loop variable names. - */ - Items(String loopVarName, String loopVar2Name, TemplateElements children) { - this.loopVarName = loopVarName; - this.loopVar2Name = loopVar2Name; - setChildren(children); - } - - @Override - TemplateElement[] accept(Environment env) throws TemplateException, IOException { - final IterationContext iterCtx = IteratorBlock.findEnclosingIterationContext(env, null); - if (iterCtx == null) { - // The parser should prevent this situation - throw new _MiscTemplateException(env, - getNodeTypeSymbol(), " without iteration in context"); - } - - iterCtx.loopForItemsElement(env, getChildBuffer(), loopVarName, loopVar2Name); - return null; - } - - @Override - boolean isNestedBlockRepeater() { - return true; - } - - @Override - protected String dump(boolean canonical) { - StringBuilder sb = new StringBuilder(); - if (canonical) sb.append('<'); - sb.append(getNodeTypeSymbol()); - sb.append(" as "); - sb.append(_StringUtil.toFTLTopLevelIdentifierReference(loopVarName)); - if (loopVar2Name != null) { - sb.append(", "); - sb.append(_StringUtil.toFTLTopLevelIdentifierReference(loopVar2Name)); - } - if (canonical) { - sb.append('>'); - sb.append(getChildrenCanonicalForm()); - sb.append("</"); - sb.append(getNodeTypeSymbol()); - sb.append('>'); - } - return sb.toString(); - } - - @Override - String getNodeTypeSymbol() { - return "#items"; - } - - @Override - int getParameterCount() { - return loopVar2Name != null ? 2 : 1; - } - - @Override - Object getParameterValue(int idx) { - switch (idx) { - case 0: - if (loopVarName == null) throw new IndexOutOfBoundsException(); - return loopVarName; - case 1: - if (loopVar2Name == null) throw new IndexOutOfBoundsException(); - return loopVar2Name; - default: throw new IndexOutOfBoundsException(); - } - } - - @Override - ParameterRole getParameterRole(int idx) { - switch (idx) { - case 0: - if (loopVarName == null) throw new IndexOutOfBoundsException(); - return ParameterRole.TARGET_LOOP_VARIABLE; - case 1: - if (loopVar2Name == null) throw new IndexOutOfBoundsException(); - return ParameterRole.TARGET_LOOP_VARIABLE; - default: throw new IndexOutOfBoundsException(); - } - } - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/7d784b2b/src/main/java/org/apache/freemarker/core/ast/IteratorBlock.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/freemarker/core/ast/IteratorBlock.java b/src/main/java/org/apache/freemarker/core/ast/IteratorBlock.java deleted file mode 100644 index 1ee3c0d..0000000 --- a/src/main/java/org/apache/freemarker/core/ast/IteratorBlock.java +++ /dev/null @@ -1,476 +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.util.ArrayList; -import java.util.Collection; -import java.util.Collections; - -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.TemplateHashModelEx; -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.TemplateScalarModel; -import org.apache.freemarker.core.model.TemplateSequenceModel; -import org.apache.freemarker.core.model.TemplateHashModelEx2.KeyValuePair; -import org.apache.freemarker.core.model.TemplateHashModelEx2.KeyValuePairIterator; -import org.apache.freemarker.core.model.impl.SimpleNumber; -import org.apache.freemarker.core.util._StringUtil; - -/** - * A #list (or #foreach) element, or pre-#else section of it inside a {@link ListElseContainer}. - */ -final class IteratorBlock extends TemplateElement { - - private final Expression listedExp; - private final String loopVarName; - private final String loopVar2Name; - private final boolean hashListing; - private final boolean forEach; - - /** - * @param listedExp - * a variable referring to a sequence or collection or extended hash to list - * @param loopVarName - * The name of the variable that will hold the value of the current item when looping through listed value, - * or {@code null} if we have a nested {@code #items}. If this is a hash listing then this variable will holds the value - * of the hash key. - * @param loopVar2Name - * The name of the variable that will hold the value of the current item when looping through the list, - * or {@code null} if we have a nested {@code #items}. If this is a hash listing then it variable will hold the value - * from the key-value pair. - * @param childrenBeforeElse - * The nested content to execute if the listed value wasn't empty; can't be {@code null}. If the loop variable - * was specified in the start tag, this is also what we will iterate over. - * @param hashListing - * Whether this is a key-value pair listing, or a usual listing. This is properly set even if we have - * a nested {@code #items}. - * @param forEach - * Whether this is {@code #foreach} or a {@code #list}. - */ - IteratorBlock(Expression listedExp, - String loopVarName, - String loopVar2Name, - TemplateElements childrenBeforeElse, - boolean hashListing, - boolean forEach) { - this.listedExp = listedExp; - this.loopVarName = loopVarName; - this.loopVar2Name = loopVar2Name; - setChildren(childrenBeforeElse); - this.hashListing = hashListing; - this.forEach = forEach; - } - - boolean isHashListing() { - return hashListing; - } - - @Override - TemplateElement[] accept(Environment env) throws TemplateException, IOException { - acceptWithResult(env); - return null; - } - - boolean acceptWithResult(Environment env) throws TemplateException, IOException { - TemplateModel listedValue = listedExp.eval(env); - if (listedValue == null) { - listedExp.assertNonNull(null, env); - } - - return env.visitIteratorBlock(new IterationContext(listedValue, loopVarName, loopVar2Name)); - } - - /** - * @param loopVariableName - * Then name of the loop variable whose context we are looking for, or {@code null} if we simply look for - * the innermost context. - * @return The matching context or {@code null} if no such context exists. - */ - static IterationContext findEnclosingIterationContext(Environment env, String loopVariableName) - throws _MiscTemplateException { - LocalContextStack ctxStack = env.getLocalContextStack(); - if (ctxStack != null) { - for (int i = ctxStack.size() - 1; i >= 0; i--) { - Object ctx = ctxStack.get(i); - if (ctx instanceof IterationContext - && (loopVariableName == null - || loopVariableName.equals(((IterationContext) ctx).getLoopVariableName()) - || loopVariableName.equals(((IterationContext) ctx).getLoopVariable2Name()) - )) { - return (IterationContext) ctx; - } - } - } - return null; - } - - @Override - protected String dump(boolean canonical) { - StringBuilder buf = new StringBuilder(); - if (canonical) buf.append('<'); - buf.append(getNodeTypeSymbol()); - buf.append(' '); - if (forEach) { - buf.append(_StringUtil.toFTLTopLevelIdentifierReference(loopVarName)); - buf.append(" in "); - buf.append(listedExp.getCanonicalForm()); - } else { - buf.append(listedExp.getCanonicalForm()); - if (loopVarName != null) { - buf.append(" as "); - buf.append(_StringUtil.toFTLTopLevelIdentifierReference(loopVarName)); - if (loopVar2Name != null) { - buf.append(", "); - buf.append(_StringUtil.toFTLTopLevelIdentifierReference(loopVar2Name)); - } - } - } - if (canonical) { - buf.append(">"); - buf.append(getChildrenCanonicalForm()); - if (!(getParentElement() instanceof ListElseContainer)) { - buf.append("</"); - buf.append(getNodeTypeSymbol()); - buf.append('>'); - } - } - return buf.toString(); - } - - @Override - int getParameterCount() { - return 1 + (loopVarName != null ? 1 : 0) + (loopVar2Name != null ? 1 : 0); - } - - @Override - Object getParameterValue(int idx) { - switch (idx) { - case 0: - return listedExp; - case 1: - if (loopVarName == null) throw new IndexOutOfBoundsException(); - return loopVarName; - case 2: - if (loopVar2Name == null) throw new IndexOutOfBoundsException(); - return loopVar2Name; - default: throw new IndexOutOfBoundsException(); - } - } - - @Override - ParameterRole getParameterRole(int idx) { - switch (idx) { - case 0: - return ParameterRole.LIST_SOURCE; - case 1: - if (loopVarName == null) throw new IndexOutOfBoundsException(); - return ParameterRole.TARGET_LOOP_VARIABLE; - case 2: - if (loopVar2Name == null) throw new IndexOutOfBoundsException(); - return ParameterRole.TARGET_LOOP_VARIABLE; - default: throw new IndexOutOfBoundsException(); - } - } - - @Override - String getNodeTypeSymbol() { - return forEach ? "#foreach" : "#list"; - } - - @Override - boolean isNestedBlockRepeater() { - return loopVarName != null; - } - - /** - * Holds the context of a #list (or #forEach) directive. - */ - class IterationContext implements LocalContext { - - private static final String LOOP_STATE_HAS_NEXT = "_has_next"; // lenght: 9 - private static final String LOOP_STATE_INDEX = "_index"; // length 6 - - private Object openedIterator; - private boolean hasNext; - private TemplateModel loopVar; - private TemplateModel loopVar2; - private int index; - private boolean alreadyEntered; - private Collection localVarNames = null; - - /** If the {@code #list} has nested {@code #items}, it's {@code null} outside the {@code #items}. */ - private String loopVarName; - /** Used if we list key-value pairs */ - private String loopVar2Name; - - private final TemplateModel listedValue; - - public IterationContext(TemplateModel listedValue, String loopVarName, String loopVar2Name) { - this.listedValue = listedValue; - this.loopVarName = loopVarName; - this.loopVar2Name = loopVar2Name; - } - - boolean accept(Environment env) throws TemplateException, IOException { - return executeNestedContent(env, getChildBuffer()); - } - - void loopForItemsElement(Environment env, TemplateElement[] childBuffer, String loopVarName, String loopVar2Name) - throws NonSequenceOrCollectionException, TemplateModelException, InvalidReferenceException, - TemplateException, IOException { - try { - if (alreadyEntered) { - throw new _MiscTemplateException(env, - "The #items directive was already entered earlier for this listing."); - } - alreadyEntered = true; - this.loopVarName = loopVarName; - this.loopVar2Name = loopVar2Name; - executeNestedContent(env, childBuffer); - } finally { - this.loopVarName = null; - this.loopVar2Name = null; - } - } - - /** - * Executes the given block for the {@link #listedValue}: if {@link #loopVarName} is non-{@code null}, then for - * each list item once, otherwise once if {@link #listedValue} isn't empty. - */ - private boolean executeNestedContent(Environment env, TemplateElement[] childBuffer) - throws TemplateModelException, TemplateException, IOException, NonSequenceOrCollectionException, - InvalidReferenceException { - return !hashListing - ? executedNestedContentForCollOrSeqListing(env, childBuffer) - : executedNestedContentForHashListing(env, childBuffer); - } - - private boolean executedNestedContentForCollOrSeqListing(Environment env, TemplateElement[] childBuffer) - throws TemplateModelException, IOException, TemplateException, - NonSequenceOrCollectionException, InvalidReferenceException { - final boolean listNotEmpty; - if (listedValue instanceof TemplateCollectionModel) { - final TemplateCollectionModel collModel = (TemplateCollectionModel) listedValue; - final TemplateModelIterator iterModel - = openedIterator == null ? collModel.iterator() - : ((TemplateModelIterator) openedIterator); - listNotEmpty = iterModel.hasNext(); - if (listNotEmpty) { - if (loopVarName != null) { - try { - do { - loopVar = iterModel.next(); - hasNext = iterModel.hasNext(); - env.visit(childBuffer); - index++; - } while (hasNext); - } catch (BreakInstruction.Break br) { - // Silently exit loop - } - openedIterator = null; - } else { - // We must reuse this later, because TemplateCollectionModel-s that wrap an Iterator only - // allow one iterator() call. - openedIterator = iterModel; - env.visit(childBuffer); - } - } - } else if (listedValue instanceof TemplateSequenceModel) { - final TemplateSequenceModel seqModel = (TemplateSequenceModel) listedValue; - final int size = seqModel.size(); - listNotEmpty = size != 0; - if (listNotEmpty) { - if (loopVarName != null) { - try { - for (index = 0; index < size; index++) { - loopVar = seqModel.get(index); - hasNext = (size > index + 1); - env.visit(childBuffer); - } - } catch (BreakInstruction.Break br) { - // Silently exit loop - } - } else { - env.visit(childBuffer); - } - } - } else if (listedValue instanceof TemplateHashModelEx - && !NonSequenceOrCollectionException.isWrappedIterable(listedValue)) { - throw new NonSequenceOrCollectionException(env, - new _ErrorDescriptionBuilder("The value you try to list is ", - new _DelayedAOrAn(new _DelayedFTLTypeDescription(listedValue)), - ", thus you must specify two loop variables after the \"as\"; one for the key, and " - + "another for the value, like ", "<#... as k, v>", ")." - )); - } else { - throw new NonSequenceOrCollectionException( - listedExp, listedValue, env); - } - return listNotEmpty; - } - - private boolean executedNestedContentForHashListing(Environment env, TemplateElement[] childBuffer) - throws TemplateModelException, IOException, TemplateException { - final boolean hashNotEmpty; - if (listedValue instanceof TemplateHashModelEx) { - TemplateHashModelEx listedHash = (TemplateHashModelEx) listedValue; - if (listedHash instanceof TemplateHashModelEx2) { - KeyValuePairIterator kvpIter - = openedIterator == null ? ((TemplateHashModelEx2) listedHash).keyValuePairIterator() - : (KeyValuePairIterator) openedIterator; - hashNotEmpty = kvpIter.hasNext(); - if (hashNotEmpty) { - if (loopVarName != null) { - try { - do { - KeyValuePair kvp = kvpIter.next(); - loopVar = kvp.getKey(); - loopVar2 = kvp.getValue(); - hasNext = kvpIter.hasNext(); - env.visit(childBuffer); - index++; - } while (hasNext); - } catch (BreakInstruction.Break br) { - // Silently exit loop - } - openedIterator = null; - } else { - // We will reuse this at the #iterms - openedIterator = kvpIter; - env.visit(childBuffer); - } - } - } else { // not a TemplateHashModelEx2, but still a TemplateHashModelEx - TemplateModelIterator keysIter = listedHash.keys().iterator(); - hashNotEmpty = keysIter.hasNext(); - if (hashNotEmpty) { - if (loopVarName != null) { - try { - do { - loopVar = keysIter.next(); - if (!(loopVar instanceof TemplateScalarModel)) { - throw new NonStringException(env, - new _ErrorDescriptionBuilder( - "When listing key-value pairs of traditional hash " - + "implementations, all keys must be strings, but one of them " - + "was ", - new _DelayedAOrAn(new _DelayedFTLTypeDescription(loopVar)), "." - ).tip("The listed value's TemplateModel class was ", - new _DelayedShortClassName(listedValue.getClass()), - ", which doesn't implement ", - new _DelayedShortClassName(TemplateHashModelEx2.class), - ", which leads to this restriction.")); - } - loopVar2 = listedHash.get(((TemplateScalarModel) loopVar).getAsString()); - hasNext = keysIter.hasNext(); - env.visit(childBuffer); - index++; - } while (hasNext); - } catch (BreakInstruction.Break br) { - // Silently exit loop - } - } else { - env.visit(childBuffer); - } - } - } - } else if (listedValue instanceof TemplateCollectionModel - || listedValue instanceof TemplateSequenceModel) { - throw new NonSequenceOrCollectionException(env, - new _ErrorDescriptionBuilder("The value you try to list is ", - new _DelayedAOrAn(new _DelayedFTLTypeDescription(listedValue)), - ", thus you must specify only one loop variable after the \"as\" (there's no separate " - + "key and value)." - )); - } else { - throw new NonExtendedHashException( - listedExp, listedValue, env); - } - return hashNotEmpty; - } - - String getLoopVariableName() { - return loopVarName; - } - - String getLoopVariable2Name() { - return loopVar2Name; - } - - @Override - public TemplateModel getLocalVariable(String name) { - String loopVarName = this.loopVarName; - if (loopVarName != null && name.startsWith(loopVarName)) { - switch(name.length() - loopVarName.length()) { - case 0: - return loopVar; - case 6: - if (name.endsWith(LOOP_STATE_INDEX)) { - return new SimpleNumber(index); - } - break; - case 9: - if (name.endsWith(LOOP_STATE_HAS_NEXT)) { - return hasNext ? TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE; - } - break; - } - } - - if (name.equals(loopVar2Name)) { - return loopVar2; - } - - return null; - } - - @Override - public Collection getLocalVariableNames() { - String loopVarName = this.loopVarName; - if (loopVarName != null) { - if (localVarNames == null) { - localVarNames = new ArrayList(3); - localVarNames.add(loopVarName); - localVarNames.add(loopVarName + LOOP_STATE_INDEX); - localVarNames.add(loopVarName + LOOP_STATE_HAS_NEXT); - } - return localVarNames; - } else { - return Collections.EMPTY_LIST; - } - } - - boolean hasNext() { - return hasNext; - } - - int getIndex() { - return index; - } - - } - -}
