You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@freemarker.apache.org by dd...@apache.org on 2017/08/08 18:03:06 UTC
[2/2] incubator-freemarker git commit: Renamed `FTLUtil` to
`TemplateLanguageUtils` (as the FTL name will be abandoned in FM3,
and supporting multiple languages are planned in the future).
Renamed `FTLUtil` to `TemplateLanguageUtils` (as the FTL name will be abandoned in FM3, and supporting multiple languages are planned in the future).
Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/a5ac9983
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/a5ac9983
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/a5ac9983
Branch: refs/heads/3
Commit: a5ac9983f22ca59fe465c937b3737badf293ba85
Parents: ebb39b8
Author: ddekany <dd...@apache.org>
Authored: Tue Aug 8 20:02:53 2017 +0200
Committer: ddekany <dd...@apache.org>
Committed: Tue Aug 8 20:02:53 2017 +0200
----------------------------------------------------------------------
FM3-CHANGE-LOG.txt | 2 +
.../core/FM2ASTToFM3SourceConverter.java | 43 +-
.../org/apache/freemarker/core/ASTPrinter.java | 4 +-
.../templatesuite/models/OverloadedMethods.java | 6 +-
.../core/userpkg/TestTemplateCallableModel.java | 4 +-
.../freemarker/core/util/FTLUtilTest.java | 128 ---
.../core/util/TemplateLanguageUtilsTest.java | 128 +++
.../freemarker/core/ASTDollarInterpolation.java | 4 +-
.../freemarker/core/ASTExpStringLiteral.java | 6 +-
.../core/MutableProcessingConfiguration.java | 4 +-
.../apache/freemarker/core/_CallableUtils.java | 10 +-
.../core/_DelayedFTLTypeDescription.java | 4 +-
.../core/_ObjectBuilderSettingEvaluator.java | 4 +-
.../freemarker/core/model/TemplateModel.java | 4 +-
.../core/model/impl/OverloadedMethods.java | 4 +-
.../apache/freemarker/core/util/FTLUtil.java | 872 -------------------
.../core/util/TemplateLanguageUtils.java | 872 +++++++++++++++++++
.../freemarker/core/util/_StringUtils.java | 10 +-
freemarker-core/src/main/javacc/FTL.jj | 4 +-
.../test/templateutil/AssertDirective.java | 4 +-
20 files changed, 1060 insertions(+), 1057 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/a5ac9983/FM3-CHANGE-LOG.txt
----------------------------------------------------------------------
diff --git a/FM3-CHANGE-LOG.txt b/FM3-CHANGE-LOG.txt
index 685160a..0d6a14b 100644
--- a/FM3-CHANGE-LOG.txt
+++ b/FM3-CHANGE-LOG.txt
@@ -469,6 +469,8 @@ Core / Miscellaneous
- Removed `NestedContentNotSupportedException`, as `TemplateDirectiveModel.isNestedContentSupported()` now takes care
of that problem.
- CallPlaceCustomDataInitializationException is not a checked exception anymore (now it extends RuntimeException)
+- Renamed `FTLUtil` to `TemplateLanguageUtils` (as the FTL name will be abandoned in FM3, and supporting multiple
+ languages are planned in the future)
Build / development process changes
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/a5ac9983/freemarker-converter/src/main/java/freemarker/core/FM2ASTToFM3SourceConverter.java
----------------------------------------------------------------------
diff --git a/freemarker-converter/src/main/java/freemarker/core/FM2ASTToFM3SourceConverter.java b/freemarker-converter/src/main/java/freemarker/core/FM2ASTToFM3SourceConverter.java
index 1b171bd..2ff86e9 100644
--- a/freemarker-converter/src/main/java/freemarker/core/FM2ASTToFM3SourceConverter.java
+++ b/freemarker-converter/src/main/java/freemarker/core/FM2ASTToFM3SourceConverter.java
@@ -35,7 +35,7 @@ import org.apache.freemarker.converter.ConversionMarkers;
import org.apache.freemarker.converter.ConverterException;
import org.apache.freemarker.converter.ConverterUtils;
import org.apache.freemarker.converter.UnconvertableLegacyFeatureException;
-import org.apache.freemarker.core.util.FTLUtil;
+import org.apache.freemarker.core.util.TemplateLanguageUtils;
import org.apache.freemarker.core.util._ClassUtils;
import org.apache.freemarker.core.util._NullArgumentException;
import org.apache.freemarker.core.util._ObjectHolder;
@@ -461,7 +461,7 @@ public class FM2ASTToFM3SourceConverter {
int paramIdx = 1;
while (paramIdx < node.getParameterCount()) {
String paramName = getParam(node, paramIdx++, ParameterRole.ARGUMENT_NAME, String.class);
- print(FTLUtil.escapeIdentifier(paramName));
+ print(TemplateLanguageUtils.escapeIdentifier(paramName));
pos = getPositionAfterIdentifier(pos);
pos = printSeparatorAndWSAndExpComments(pos, "=");
@@ -592,7 +592,7 @@ public class FM2ASTToFM3SourceConverter {
int pos = printDirStartTagPartBeforeParams(node, "setting");
- print(FTLUtil.escapeIdentifier(convertSettingName(
+ print(TemplateLanguageUtils.escapeIdentifier(convertSettingName(
getParam(node, 0, ParameterRole.ITEM_KEY, String.class),
node)));
pos = getPositionAfterIdentifier(pos);
@@ -676,11 +676,11 @@ public class FM2ASTToFM3SourceConverter {
paramCnt >= 2 ? getParam(node, 1, ParameterRole.TARGET_LOOP_VARIABLE, String.class)
: null;
- print(FTLUtil.escapeIdentifier(nestedContParamName1));
+ print(TemplateLanguageUtils.escapeIdentifier(nestedContParamName1));
pos = getPositionAfterIdentifier(pos);
if (nestedContParamName2 != null) {
pos = printSeparatorAndWSAndExpComments(pos, ",");
- print(FTLUtil.escapeIdentifier(nestedContParamName2));
+ print(TemplateLanguageUtils.escapeIdentifier(nestedContParamName2));
pos = getPositionAfterIdentifier(pos);
}
@@ -734,13 +734,13 @@ public class FM2ASTToFM3SourceConverter {
if (loopVal1 != null) { // #list xs as <v1 | v1, v2>
pos = printSeparatorAndWSAndExpComments(getEndPositionExclusive(listSource), "as");
- print(FTLUtil.escapeIdentifier(loopVal1));
+ print(TemplateLanguageUtils.escapeIdentifier(loopVal1));
pos = getPositionAfterAssignmentTargetIdentifier(pos);
if (loopVal2 != null) { // #list xs as <v1, v2>
pos = printSeparatorAndWSAndExpComments(pos, ",");
- print(FTLUtil.escapeIdentifier(loopVal2));
+ print(TemplateLanguageUtils.escapeIdentifier(loopVal2));
pos = getPositionAfterAssignmentTargetIdentifier(pos);
}
@@ -780,7 +780,7 @@ public class FM2ASTToFM3SourceConverter {
printExp(listSource);
printWithConvertedExpComments(ConverterUtils.rightTrim(postVar2WSAndComment));
print(" as ");
- print(FTLUtil.escapeIdentifier(loopVal1));
+ print(TemplateLanguageUtils.escapeIdentifier(loopVal1));
printWithConvertedExpComments(ConverterUtils.rightTrim(postVar1WSAndComment));
printWithConvertedExpComments(ConverterUtils.rightTrim(postInWSAndComment));
} else {
@@ -892,7 +892,7 @@ public class FM2ASTToFM3SourceConverter {
int pos = printSeparatorAndWSAndExpComments(getEndPositionExclusive(templateName), "as");
- print(FTLUtil.escapeIdentifier(getParam(node, 1, ParameterRole.NAMESPACE, String.class)));
+ print(TemplateLanguageUtils.escapeIdentifier(getParam(node, 1, ParameterRole.NAMESPACE, String.class)));
pos = getPositionAfterIdentifier(pos);
printDirStartTagEnd(node, pos, false);
@@ -925,7 +925,7 @@ public class FM2ASTToFM3SourceConverter {
int pos = printDirStartTagPartBeforeParams(node, "escape");
pos = getPositionAfterIdentifier(pos);
- print(FTLUtil.escapeIdentifier(getParam(node, 0, ParameterRole.PLACEHOLDER_VARIABLE, String.class)));
+ print(TemplateLanguageUtils.escapeIdentifier(getParam(node, 0, ParameterRole.PLACEHOLDER_VARIABLE, String.class)));
pos = printSeparatorAndWSAndExpComments(pos, "as");
@@ -1023,7 +1023,7 @@ public class FM2ASTToFM3SourceConverter {
int pos = printDirAssignmentCommonTagTillAssignmentExp(node, 1);
- print(FTLUtil.escapeIdentifier(getParam(node, 0, ParameterRole.ASSIGNMENT_TARGET, String.class)));
+ print(TemplateLanguageUtils.escapeIdentifier(getParam(node, 0, ParameterRole.ASSIGNMENT_TARGET, String.class)));
pos = getPositionAfterAssignmentTargetIdentifier(pos);
Expression namespace = getParam(node, 2, ParameterRole.NAMESPACE, Expression.class);
@@ -1075,7 +1075,7 @@ public class FM2ASTToFM3SourceConverter {
private int printDirAssignmentCommonExp(Assignment node, int pos) throws ConverterException {
String target = getParam(node, 0, ParameterRole.ASSIGNMENT_TARGET, String.class);
- print(FTLUtil.escapeIdentifier(target));
+ print(TemplateLanguageUtils.escapeIdentifier(target));
pos = getPositionAfterAssignmentTargetIdentifier(pos);
pos = printWSAndExpComments(pos);
@@ -1118,7 +1118,7 @@ public class FM2ASTToFM3SourceConverter {
int pos = printDirStartTagPartBeforeParams(node, tagName);
String assignedName = getParam(node, 0, ParameterRole.ASSIGNMENT_TARGET, String.class);
- print(FTLUtil.escapeIdentifier(assignedName));
+ print(TemplateLanguageUtils.escapeIdentifier(assignedName));
pos = getPositionAfterAssignmentTargetIdentifier(pos);
{
@@ -1154,7 +1154,7 @@ public class FM2ASTToFM3SourceConverter {
int paramIdx = 1;
while (node.getParameterRole(paramIdx) == ParameterRole.PARAMETER_NAME) {
String paramName = getParam(node, paramIdx++, ParameterRole.PARAMETER_NAME, String.class);
- print(FTLUtil.escapeIdentifier(paramName));
+ print(TemplateLanguageUtils.escapeIdentifier(paramName));
pos = getPositionAfterIdentifier(pos);
Expression paramDefault = getParam(node, paramIdx++, ParameterRole.PARAMETER_DEFAULT, Expression.class);
@@ -1204,7 +1204,7 @@ public class FM2ASTToFM3SourceConverter {
}
String paramName = getParam(node, paramIdx++, ParameterRole.CATCH_ALL_PARAMETER_NAME, String.class);
if (paramName != null) {
- print(FTLUtil.escapeIdentifier(paramName));
+ print(TemplateLanguageUtils.escapeIdentifier(paramName));
pos = getPositionAfterIdentifier(pos);
pos = printWSAndExpComments(pos);
assertNodeContent(src.startsWith("...", pos), node,
@@ -1312,7 +1312,7 @@ public class FM2ASTToFM3SourceConverter {
if (ftlDirMode) {
paramName = convertFtlHeaderParamName(paramName);
}
- print(FTLUtil.escapeIdentifier(paramName));
+ print(TemplateLanguageUtils.escapeIdentifier(paramName));
printSeparatorAndWSAndExpComments(pos, "=");
printExp(argValue);
@@ -1620,7 +1620,7 @@ public class FM2ASTToFM3SourceConverter {
printSeparatorAndWSAndExpComments(getEndPositionExclusive(lho), ".");
rho = mapStringHashKey(rho);
- print(rho.startsWith("*") ? rho : FTLUtil.escapeIdentifier(rho));
+ print(rho.startsWith("*") ? rho : TemplateLanguageUtils.escapeIdentifier(rho));
}
private String mapStringHashKey(String key) {
@@ -1794,7 +1794,7 @@ public class FM2ASTToFM3SourceConverter {
}
private void printExpIdentifier(Identifier node) {
- print(FTLUtil.escapeIdentifier(node.getName()));
+ print(TemplateLanguageUtils.escapeIdentifier(node.getName()));
}
private void printExpMethodCall(MethodCall node) throws ConverterException {
@@ -1911,7 +1911,7 @@ public class FM2ASTToFM3SourceConverter {
if (parameterCount == 0) {
_NullArgumentException.check("value", value);
if (!rawString) {
- print(FTLUtil.escapeStringLiteralPart(value, quote, escapeAmp, escapeLT, escapeGT));
+ print(TemplateLanguageUtils.escapeStringLiteralPart(value, quote, escapeAmp, escapeLT, escapeGT));
} else {
print(value);
}
@@ -1925,7 +1925,8 @@ public class FM2ASTToFM3SourceConverter {
for (int paramIdx = 0; paramIdx < parameterCount; paramIdx++) {
Object param = getParam(node, paramIdx, ParameterRole.VALUE_PART, Object.class);
if (param instanceof String) {
- print(FTLUtil.escapeStringLiteralPart((String) param, quote, escapeAmp, escapeLT, escapeGT));
+ print(TemplateLanguageUtils
+ .escapeStringLiteralPart((String) param, quote, escapeAmp, escapeLT, escapeGT));
} else {
assertNodeContent(param instanceof Interpolation, node,
"Unexpected parameter type: {}", param.getClass().getName());
@@ -1944,7 +1945,7 @@ public class FM2ASTToFM3SourceConverter {
String interp = out.substring(interpStartPos, interpEndPos);
out.setLength(interpStartPos + 2); // +2 to keep the "${"
String inerpInside = interp.substring(2, interp.length() - 1);
- print(FTLUtil.escapeStringLiteralPart(inerpInside, quote)); // For now we escape as FTL2
+ print(TemplateLanguageUtils.escapeStringLiteralPart(inerpInside, quote)); // For now we escape as FTL2
print(interp.charAt(interp.length() - 1)); // "}"
}
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/a5ac9983/freemarker-core-test/src/test/java/org/apache/freemarker/core/ASTPrinter.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/ASTPrinter.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/ASTPrinter.java
index 2bc1eea..8157c19 100644
--- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/ASTPrinter.java
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/ASTPrinter.java
@@ -40,7 +40,7 @@ import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import org.apache.freemarker.core.model.TemplateModel;
-import org.apache.freemarker.core.util.FTLUtil;
+import org.apache.freemarker.core.util.TemplateLanguageUtils;
import org.apache.freemarker.core.util._ClassUtils;
import org.apache.freemarker.core.util._StringUtils;
import org.apache.freemarker.test.TestConfigurationBuilder;
@@ -330,7 +330,7 @@ public class ASTPrinter {
out.write(INDENTATION);
out.write(ind);
out.write("= const ");
- out.write(FTLUtil.getTypeDescription(tm));
+ out.write(TemplateLanguageUtils.getTypeDescription(tm));
out.write(' ');
out.write(tm.toString());
out.write('\n');
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/a5ac9983/freemarker-core-test/src/test/java/org/apache/freemarker/core/templatesuite/models/OverloadedMethods.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/templatesuite/models/OverloadedMethods.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/templatesuite/models/OverloadedMethods.java
index 4eac8cc..1e7d3a2 100644
--- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/templatesuite/models/OverloadedMethods.java
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/templatesuite/models/OverloadedMethods.java
@@ -26,7 +26,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
-import org.apache.freemarker.core.util.FTLUtil;
+import org.apache.freemarker.core.util.TemplateLanguageUtils;
/**
* For testing overloaded method selection.
@@ -149,9 +149,9 @@ public class OverloadedMethods {
if (value == null) {
return "null";
} else if (value instanceof Character) {
- return "'" + FTLUtil.escapeStringLiteralPart(value.toString()) + "'";
+ return "'" + TemplateLanguageUtils.escapeStringLiteralPart(value.toString()) + "'";
} else if (value instanceof String) {
- return "\"" + FTLUtil.escapeStringLiteralPart((String) value) + "\"";
+ return "\"" + TemplateLanguageUtils.escapeStringLiteralPart((String) value) + "\"";
} else if (value instanceof Map) {
StringBuilder sb = new StringBuilder();
sb.append("{");
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/a5ac9983/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TestTemplateCallableModel.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TestTemplateCallableModel.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TestTemplateCallableModel.java
index 9cedddd..6b36cf8 100644
--- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TestTemplateCallableModel.java
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TestTemplateCallableModel.java
@@ -28,7 +28,7 @@ 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.util.FTLUtil;
+import org.apache.freemarker.core.util.TemplateLanguageUtils;
import org.apache.freemarker.core.util._StringUtils;
public abstract class TestTemplateCallableModel implements TemplateCallableModel {
@@ -64,7 +64,7 @@ public abstract class TestTemplateCallableModel implements TemplateCallableModel
} else if (value instanceof TemplateNumberModel) {
sb.append(((TemplateNumberModel) value).getAsNumber().toString());
} else if (value instanceof TemplateScalarModel) {
- sb.append(FTLUtil.toStringLiteral(((TemplateScalarModel) value).getAsString()));
+ sb.append(TemplateLanguageUtils.toStringLiteral(((TemplateScalarModel) value).getAsString()));
} else if (value instanceof TemplateSequenceModel) {
int len = ((TemplateSequenceModel) value).size();
sb.append('[');
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/a5ac9983/freemarker-core-test/src/test/java/org/apache/freemarker/core/util/FTLUtilTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/util/FTLUtilTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/util/FTLUtilTest.java
deleted file mode 100644
index aab0dbe..0000000
--- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/util/FTLUtilTest.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.freemarker.core.util;
-
-import static junit.framework.TestCase.assertFalse;
-import static junit.framework.TestCase.assertNull;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import org.junit.Test;
-
-public class FTLUtilTest {
-
- @Test
- public void testEscapeStringLiteralPart() {
- assertEquals("", FTLUtil.escapeStringLiteralPart(""));
- assertEquals("abc", FTLUtil.escapeStringLiteralPart("abc"));
- assertEquals("{", FTLUtil.escapeStringLiteralPart("{"));
- assertEquals("a{b}c", FTLUtil.escapeStringLiteralPart("a{b}c"));
- assertEquals("a#b", FTLUtil.escapeStringLiteralPart("a#b"));
- assertEquals("a$b", FTLUtil.escapeStringLiteralPart("a$b"));
- // Find related: [interpolation prefixes]
- assertEquals("a#{b}c", FTLUtil.escapeStringLiteralPart("a#{b}c"));
- assertEquals("a$\\{b}c", FTLUtil.escapeStringLiteralPart("a${b}c"));
- assertEquals("a'c\\\"d", FTLUtil.escapeStringLiteralPart("a'c\"d", '"'));
- assertEquals("a\\'c\"d", FTLUtil.escapeStringLiteralPart("a'c\"d", '\''));
- assertEquals("a\\'c\"d", FTLUtil.escapeStringLiteralPart("a'c\"d", '\''));
- assertEquals("\\n\\r\\t\\f\\x0002\\\\", FTLUtil.escapeStringLiteralPart("\n\r\t\f\u0002\\"));
- assertEquals("\\l\\g\\a", FTLUtil.escapeStringLiteralPart("<>&"));
- }
-
- @Test
- public void testEscapeStringLiteralAll() {
- assertFTLEsc("", "", "", "", "\"\"");
- assertFTLEsc("\'", "\\'", "'", "\\'", "\"'\"");
- assertFTLEsc("\"", "\\\"", "\\\"", "\"", "'\"'");
- assertFTLEsc("\"", "\\\"", "\\\"", "\"", "'\"'");
- assertFTLEsc("foo", "foo", "foo", "foo", "\"foo\"");
- assertFTLEsc("foo's", "foo\\'s", "foo's", "foo\\'s", "\"foo's\"");
- assertFTLEsc("foo \"", "foo \\\"", "foo \\\"", "foo \"", "'foo \"'");
- assertFTLEsc("foo's \"", "foo\\'s \\\"", "foo's \\\"", "foo\\'s \"", "\"foo's \\\"\"");
- assertFTLEsc("foo\nb\u0000c", "foo\\nb\\x0000c", "foo\\nb\\x0000c", "foo\\nb\\x0000c", "\"foo\\nb\\x0000c\"");
- }
-
- private void assertFTLEsc(String s, String partAny, String partQuot, String partApos, String quoted) {
- assertEquals(partAny, FTLUtil.escapeStringLiteralPart(s));
- assertEquals(partQuot, FTLUtil.escapeStringLiteralPart(s, '\"'));
- assertEquals(partApos, FTLUtil.escapeStringLiteralPart(s, '\''));
- assertEquals(quoted, FTLUtil.toStringLiteral(s));
- }
-
- @Test
- public void testUnescapeStringLiteralPart() throws Exception {
- assertEquals("", FTLUtil.unescapeStringLiteralPart(""));
- assertEquals("1", FTLUtil.unescapeStringLiteralPart("1"));
- assertEquals("123", FTLUtil.unescapeStringLiteralPart("123"));
- assertEquals("1&2&3", FTLUtil.unescapeStringLiteralPart("1\\a2\\a3"));
- assertEquals("&", FTLUtil.unescapeStringLiteralPart("\\a"));
- assertEquals("&&&", FTLUtil.unescapeStringLiteralPart("\\a\\a\\a"));
- assertEquals(
- "\u0000\u0000&\u0000\u0000\u0000\u0000",
- FTLUtil.unescapeStringLiteralPart("\\x0000\\x0000\\a\\x0000\\x000\\x00\\x0"));
- assertEquals(
- "'\"\n\b\u0000c><&{\\",
- FTLUtil.unescapeStringLiteralPart("\\'\\\"\\n\\b\\x0000c\\g\\l\\a\\{\\\\"));
- }
-
- @Test
- public void testEscapeIdentifier() {
- assertNull(FTLUtil.escapeIdentifier(null));
- assertEquals("", FTLUtil.escapeIdentifier(""));
- assertEquals("a", FTLUtil.escapeIdentifier("a"));
- assertEquals("ab", FTLUtil.escapeIdentifier("ab"));
- assertEquals("\\.", FTLUtil.escapeIdentifier("."));
- assertEquals("\\.\\:\\-", FTLUtil.escapeIdentifier(".:-"));
- assertEquals("a\\.b", FTLUtil.escapeIdentifier("a.b"));
- assertEquals("a\\.b\\:c\\-d", FTLUtil.escapeIdentifier("a.b:c-d"));
- }
-
- @Test
- public void testIsNonEscapedIdentifierStart() {
- assertTrue(FTLUtil.isNonEscapedIdentifierPart('a'));
- assertTrue(FTLUtil.isNonEscapedIdentifierPart('á'));
- assertTrue(FTLUtil.isNonEscapedIdentifierPart('1'));
- assertFalse(FTLUtil.isNonEscapedIdentifierPart('-'));
- assertFalse(FTLUtil.isNonEscapedIdentifierPart(' '));
- assertFalse(FTLUtil.isNonEscapedIdentifierPart('\u0000'));
- assertFalse(FTLUtil.isNonEscapedIdentifierPart('\\'));
- }
-
- @Test
- public void testisNonEscapedIdentifierStart() {
- assertTrue(FTLUtil.isNonEscapedIdentifierStart('a'));
- assertTrue(FTLUtil.isNonEscapedIdentifierStart('á'));
- assertFalse(FTLUtil.isNonEscapedIdentifierStart('1'));
- assertFalse(FTLUtil.isNonEscapedIdentifierStart('-'));
- assertFalse(FTLUtil.isNonEscapedIdentifierStart(' '));
- assertFalse(FTLUtil.isNonEscapedIdentifierStart('\u0000'));
- assertFalse(FTLUtil.isNonEscapedIdentifierStart('\\'));
- }
-
- @Test
- public void testToStringLiteral() {
- assertNull(FTLUtil.toStringLiteral(null));
- assertEquals("\"\"", FTLUtil.toStringLiteral(""));
- assertEquals("'foo\"bar\"baaz\\''", FTLUtil.toStringLiteral("foo\"bar\"baaz'"));
- assertEquals("\"foo'bar'baaz\\\"\"", FTLUtil.toStringLiteral("foo'bar'baaz\""));
- assertEquals("r\"\\d\"", FTLUtil.toStringLiteral("\\d"));
- assertEquals("r'\\d\"'", FTLUtil.toStringLiteral("\\d\""));
- }
-
-}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/a5ac9983/freemarker-core-test/src/test/java/org/apache/freemarker/core/util/TemplateLanguageUtilsTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/util/TemplateLanguageUtilsTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/util/TemplateLanguageUtilsTest.java
new file mode 100644
index 0000000..aae4699
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/util/TemplateLanguageUtilsTest.java
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.freemarker.core.util;
+
+import static junit.framework.TestCase.assertFalse;
+import static junit.framework.TestCase.assertNull;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+public class TemplateLanguageUtilsTest {
+
+ @Test
+ public void testEscapeStringLiteralPart() {
+ assertEquals("", TemplateLanguageUtils.escapeStringLiteralPart(""));
+ assertEquals("abc", TemplateLanguageUtils.escapeStringLiteralPart("abc"));
+ assertEquals("{", TemplateLanguageUtils.escapeStringLiteralPart("{"));
+ assertEquals("a{b}c", TemplateLanguageUtils.escapeStringLiteralPart("a{b}c"));
+ assertEquals("a#b", TemplateLanguageUtils.escapeStringLiteralPart("a#b"));
+ assertEquals("a$b", TemplateLanguageUtils.escapeStringLiteralPart("a$b"));
+ // Find related: [interpolation prefixes]
+ assertEquals("a#{b}c", TemplateLanguageUtils.escapeStringLiteralPart("a#{b}c"));
+ assertEquals("a$\\{b}c", TemplateLanguageUtils.escapeStringLiteralPart("a${b}c"));
+ assertEquals("a'c\\\"d", TemplateLanguageUtils.escapeStringLiteralPart("a'c\"d", '"'));
+ assertEquals("a\\'c\"d", TemplateLanguageUtils.escapeStringLiteralPart("a'c\"d", '\''));
+ assertEquals("a\\'c\"d", TemplateLanguageUtils.escapeStringLiteralPart("a'c\"d", '\''));
+ assertEquals("\\n\\r\\t\\f\\x0002\\\\", TemplateLanguageUtils.escapeStringLiteralPart("\n\r\t\f\u0002\\"));
+ assertEquals("\\l\\g\\a", TemplateLanguageUtils.escapeStringLiteralPart("<>&"));
+ }
+
+ @Test
+ public void testEscapeStringLiteralAll() {
+ assertFTLEsc("", "", "", "", "\"\"");
+ assertFTLEsc("\'", "\\'", "'", "\\'", "\"'\"");
+ assertFTLEsc("\"", "\\\"", "\\\"", "\"", "'\"'");
+ assertFTLEsc("\"", "\\\"", "\\\"", "\"", "'\"'");
+ assertFTLEsc("foo", "foo", "foo", "foo", "\"foo\"");
+ assertFTLEsc("foo's", "foo\\'s", "foo's", "foo\\'s", "\"foo's\"");
+ assertFTLEsc("foo \"", "foo \\\"", "foo \\\"", "foo \"", "'foo \"'");
+ assertFTLEsc("foo's \"", "foo\\'s \\\"", "foo's \\\"", "foo\\'s \"", "\"foo's \\\"\"");
+ assertFTLEsc("foo\nb\u0000c", "foo\\nb\\x0000c", "foo\\nb\\x0000c", "foo\\nb\\x0000c", "\"foo\\nb\\x0000c\"");
+ }
+
+ private void assertFTLEsc(String s, String partAny, String partQuot, String partApos, String quoted) {
+ assertEquals(partAny, TemplateLanguageUtils.escapeStringLiteralPart(s));
+ assertEquals(partQuot, TemplateLanguageUtils.escapeStringLiteralPart(s, '\"'));
+ assertEquals(partApos, TemplateLanguageUtils.escapeStringLiteralPart(s, '\''));
+ assertEquals(quoted, TemplateLanguageUtils.toStringLiteral(s));
+ }
+
+ @Test
+ public void testUnescapeStringLiteralPart() throws Exception {
+ assertEquals("", TemplateLanguageUtils.unescapeStringLiteralPart(""));
+ assertEquals("1", TemplateLanguageUtils.unescapeStringLiteralPart("1"));
+ assertEquals("123", TemplateLanguageUtils.unescapeStringLiteralPart("123"));
+ assertEquals("1&2&3", TemplateLanguageUtils.unescapeStringLiteralPart("1\\a2\\a3"));
+ assertEquals("&", TemplateLanguageUtils.unescapeStringLiteralPart("\\a"));
+ assertEquals("&&&", TemplateLanguageUtils.unescapeStringLiteralPart("\\a\\a\\a"));
+ assertEquals(
+ "\u0000\u0000&\u0000\u0000\u0000\u0000",
+ TemplateLanguageUtils.unescapeStringLiteralPart("\\x0000\\x0000\\a\\x0000\\x000\\x00\\x0"));
+ assertEquals(
+ "'\"\n\b\u0000c><&{\\",
+ TemplateLanguageUtils.unescapeStringLiteralPart("\\'\\\"\\n\\b\\x0000c\\g\\l\\a\\{\\\\"));
+ }
+
+ @Test
+ public void testEscapeIdentifier() {
+ assertNull(TemplateLanguageUtils.escapeIdentifier(null));
+ assertEquals("", TemplateLanguageUtils.escapeIdentifier(""));
+ assertEquals("a", TemplateLanguageUtils.escapeIdentifier("a"));
+ assertEquals("ab", TemplateLanguageUtils.escapeIdentifier("ab"));
+ assertEquals("\\.", TemplateLanguageUtils.escapeIdentifier("."));
+ assertEquals("\\.\\:\\-", TemplateLanguageUtils.escapeIdentifier(".:-"));
+ assertEquals("a\\.b", TemplateLanguageUtils.escapeIdentifier("a.b"));
+ assertEquals("a\\.b\\:c\\-d", TemplateLanguageUtils.escapeIdentifier("a.b:c-d"));
+ }
+
+ @Test
+ public void testIsNonEscapedIdentifierStart() {
+ assertTrue(TemplateLanguageUtils.isNonEscapedIdentifierPart('a'));
+ assertTrue(TemplateLanguageUtils.isNonEscapedIdentifierPart('á'));
+ assertTrue(TemplateLanguageUtils.isNonEscapedIdentifierPart('1'));
+ assertFalse(TemplateLanguageUtils.isNonEscapedIdentifierPart('-'));
+ assertFalse(TemplateLanguageUtils.isNonEscapedIdentifierPart(' '));
+ assertFalse(TemplateLanguageUtils.isNonEscapedIdentifierPart('\u0000'));
+ assertFalse(TemplateLanguageUtils.isNonEscapedIdentifierPart('\\'));
+ }
+
+ @Test
+ public void testisNonEscapedIdentifierStart() {
+ assertTrue(TemplateLanguageUtils.isNonEscapedIdentifierStart('a'));
+ assertTrue(TemplateLanguageUtils.isNonEscapedIdentifierStart('á'));
+ assertFalse(TemplateLanguageUtils.isNonEscapedIdentifierStart('1'));
+ assertFalse(TemplateLanguageUtils.isNonEscapedIdentifierStart('-'));
+ assertFalse(TemplateLanguageUtils.isNonEscapedIdentifierStart(' '));
+ assertFalse(TemplateLanguageUtils.isNonEscapedIdentifierStart('\u0000'));
+ assertFalse(TemplateLanguageUtils.isNonEscapedIdentifierStart('\\'));
+ }
+
+ @Test
+ public void testToStringLiteral() {
+ assertNull(TemplateLanguageUtils.toStringLiteral(null));
+ assertEquals("\"\"", TemplateLanguageUtils.toStringLiteral(""));
+ assertEquals("'foo\"bar\"baaz\\''", TemplateLanguageUtils.toStringLiteral("foo\"bar\"baaz'"));
+ assertEquals("\"foo'bar'baaz\\\"\"", TemplateLanguageUtils.toStringLiteral("foo'bar'baaz\""));
+ assertEquals("r\"\\d\"", TemplateLanguageUtils.toStringLiteral("\\d"));
+ assertEquals("r'\\d\"'", TemplateLanguageUtils.toStringLiteral("\\d\""));
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/a5ac9983/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDollarInterpolation.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDollarInterpolation.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDollarInterpolation.java
index 9003b07..c422d93 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDollarInterpolation.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTDollarInterpolation.java
@@ -25,7 +25,7 @@ import java.io.Writer;
import org.apache.freemarker.core.model.TemplateMarkupOutputModel;
import org.apache.freemarker.core.outputformat.MarkupOutputFormat;
import org.apache.freemarker.core.outputformat.OutputFormat;
-import org.apache.freemarker.core.util.FTLUtil;
+import org.apache.freemarker.core.util.TemplateLanguageUtils;
/**
* AST interpolation node: <tt>${exp}</tt>
@@ -103,7 +103,7 @@ final class ASTDollarInterpolation extends ASTInterpolation {
StringBuilder sb = new StringBuilder();
sb.append("${");
final String exprCF = expression.getCanonicalForm();
- sb.append(inStringLiteral ? FTLUtil.escapeStringLiteralPart(exprCF, '"') : exprCF);
+ sb.append(inStringLiteral ? TemplateLanguageUtils.escapeStringLiteralPart(exprCF, '"') : exprCF);
sb.append("}");
if (!canonical && expression != escapedExpression) {
sb.append(" auto-escaped");
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/a5ac9983/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpStringLiteral.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpStringLiteral.java b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpStringLiteral.java
index 0dbcfb1..194ccef 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpStringLiteral.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/ASTExpStringLiteral.java
@@ -27,7 +27,7 @@ import org.apache.freemarker.core.model.TemplateModel;
import org.apache.freemarker.core.model.TemplateScalarModel;
import org.apache.freemarker.core.model.impl.SimpleScalar;
import org.apache.freemarker.core.outputformat.OutputFormat;
-import org.apache.freemarker.core.util.FTLUtil;
+import org.apache.freemarker.core.util.TemplateLanguageUtils;
/**
* AST expression node: string literal
@@ -149,7 +149,7 @@ final class ASTExpStringLiteral extends ASTExpression implements TemplateScalarM
@Override
public String getCanonicalForm() {
if (dynamicValue == null) {
- return FTLUtil.toStringLiteral(value);
+ return TemplateLanguageUtils.toStringLiteral(value);
} else {
StringBuilder sb = new StringBuilder();
sb.append('"');
@@ -157,7 +157,7 @@ final class ASTExpStringLiteral extends ASTExpression implements TemplateScalarM
if (child instanceof ASTInterpolation) {
sb.append(((ASTInterpolation) child).getCanonicalFormInStringLiteral());
} else {
- sb.append(FTLUtil.escapeStringLiteralPart((String) child, '"'));
+ sb.append(TemplateLanguageUtils.escapeStringLiteralPart((String) child, '"'));
}
}
sb.append('"');
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/a5ac9983/freemarker-core/src/main/java/org/apache/freemarker/core/MutableProcessingConfiguration.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/MutableProcessingConfiguration.java b/freemarker-core/src/main/java/org/apache/freemarker/core/MutableProcessingConfiguration.java
index d1684d3..2f2db0e 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/MutableProcessingConfiguration.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/MutableProcessingConfiguration.java
@@ -58,7 +58,7 @@ import org.apache.freemarker.core.templateresolver.OrMatcher;
import org.apache.freemarker.core.templateresolver.PathGlobMatcher;
import org.apache.freemarker.core.templateresolver.PathRegexMatcher;
import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateNameFormat;
-import org.apache.freemarker.core.util.FTLUtil;
+import org.apache.freemarker.core.util.TemplateLanguageUtils;
import org.apache.freemarker.core.util.GenericParseException;
import org.apache.freemarker.core.util.OptInTemplateClassResolver;
import org.apache.freemarker.core.util._ClassUtils;
@@ -2209,7 +2209,7 @@ public abstract class MutableProcessingConfiguration<SelfT extends MutableProces
if (w.startsWith("'") || w.startsWith("\"")) {
w = w.substring(1, w.length() - 1);
}
- return FTLUtil.unescapeStringLiteralPart(w);
+ return TemplateLanguageUtils.unescapeStringLiteralPart(w);
}
String fetchKeyword() throws GenericParseException {
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/a5ac9983/freemarker-core/src/main/java/org/apache/freemarker/core/_CallableUtils.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/_CallableUtils.java b/freemarker-core/src/main/java/org/apache/freemarker/core/_CallableUtils.java
index 81a5aa0..fb2143a 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/_CallableUtils.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/_CallableUtils.java
@@ -34,7 +34,7 @@ import org.apache.freemarker.core.model.TemplateModel;
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.util.FTLUtil;
+import org.apache.freemarker.core.util.TemplateLanguageUtils;
import org.apache.freemarker.core.util.StringToIndexMap;
import org.apache.freemarker.core.util._CollectionUtils;
@@ -238,7 +238,7 @@ public final class _CallableUtils {
checkSupportsAnyParameters(callableValue, argsLayout, env);
List<String> validPredefNames = argsLayout.getPredefinedNamedArgumentsMap().getKeys();
_ErrorDescriptionBuilder errorDesc = new _ErrorDescriptionBuilder(
- "The called ", FTLUtil.getCallableTypeName(callableValue), " ",
+ "The called ", TemplateLanguageUtils.getCallableTypeName(callableValue), " ",
(predefPosArgCnt != 0
? new Object[]{ "can only have ", predefPosArgCnt }
: "can't have"
@@ -286,7 +286,7 @@ public final class _CallableUtils {
validNames == null || validNames.isEmpty()
? getNamedArgumentsNotSupportedMessage(callableValue, namedArg)
: new Object[] {
- "The called ", FTLUtil.getCallableTypeName(callableValue),
+ "The called ", TemplateLanguageUtils.getCallableTypeName(callableValue),
" has no parameter that's passed by name and is called ",
new _DelayedJQuote(namedArg.name),
". The supported parameter names are:\n",
@@ -309,7 +309,7 @@ public final class _CallableUtils {
private static Object[] getNamedArgumentsNotSupportedMessage(TemplateCallableModel callableValue,
NamedArgument namedArg) {
return new Object[] {
- "The called ", FTLUtil.getCallableTypeName(callableValue),
+ "The called ", TemplateLanguageUtils.getCallableTypeName(callableValue),
" can't have arguments that are passed by name (like ",
new _DelayedJQuote(namedArg.name), "). Try to pass arguments by position "
+ "(i.e, without name, as in ",
@@ -325,7 +325,7 @@ public final class _CallableUtils {
throws TemplateException {
if (argsLayout.getTotalLength() == 0) {
throw new _MiscTemplateException(env,
- "The called ", FTLUtil.getCallableTypeName(callableValue), " doesn't support any parameters.");
+ "The called ", TemplateLanguageUtils.getCallableTypeName(callableValue), " doesn't support any parameters.");
}
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/a5ac9983/freemarker-core/src/main/java/org/apache/freemarker/core/_DelayedFTLTypeDescription.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/_DelayedFTLTypeDescription.java b/freemarker-core/src/main/java/org/apache/freemarker/core/_DelayedFTLTypeDescription.java
index 21b6d55..2bdaa6d 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/_DelayedFTLTypeDescription.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/_DelayedFTLTypeDescription.java
@@ -20,7 +20,7 @@
package org.apache.freemarker.core;
import org.apache.freemarker.core.model.TemplateModel;
-import org.apache.freemarker.core.util.FTLUtil;
+import org.apache.freemarker.core.util.TemplateLanguageUtils;
/** Don't use this; used internally by FreeMarker, might changes without notice. */
public class _DelayedFTLTypeDescription extends _DelayedConversionToString {
@@ -31,7 +31,7 @@ public class _DelayedFTLTypeDescription extends _DelayedConversionToString {
@Override
protected String doConversion(Object obj) {
- return FTLUtil.getTypeDescription((TemplateModel) obj);
+ return TemplateLanguageUtils.getTypeDescription((TemplateModel) obj);
}
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/a5ac9983/freemarker-core/src/main/java/org/apache/freemarker/core/_ObjectBuilderSettingEvaluator.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/_ObjectBuilderSettingEvaluator.java b/freemarker-core/src/main/java/org/apache/freemarker/core/_ObjectBuilderSettingEvaluator.java
index 7be4511..7fcf25d 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/_ObjectBuilderSettingEvaluator.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/_ObjectBuilderSettingEvaluator.java
@@ -58,7 +58,7 @@ import org.apache.freemarker.core.templateresolver.OrMatcher;
import org.apache.freemarker.core.templateresolver.PathGlobMatcher;
import org.apache.freemarker.core.templateresolver.PathRegexMatcher;
import org.apache.freemarker.core.util.BugException;
-import org.apache.freemarker.core.util.FTLUtil;
+import org.apache.freemarker.core.util.TemplateLanguageUtils;
import org.apache.freemarker.core.util.GenericParseException;
import org.apache.freemarker.core.util._ClassUtils;
import org.apache.freemarker.core.util._StringUtils;
@@ -533,7 +533,7 @@ public class _ObjectBuilderSettingEvaluator {
final String sInside = src.substring(startPos + (raw ? 2 : 1), pos);
try {
pos++; // skip closing quotation mark
- return raw ? sInside : FTLUtil.unescapeStringLiteralPart(sInside);
+ return raw ? sInside : TemplateLanguageUtils.unescapeStringLiteralPart(sInside);
} catch (GenericParseException e) {
throw new _ObjectBuilderSettingEvaluationException("Malformed string literal: " + sInside, e);
}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/a5ac9983/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateModel.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateModel.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateModel.java
index bbe3c03..b4247c7 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateModel.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/TemplateModel.java
@@ -20,7 +20,7 @@
package org.apache.freemarker.core.model;
import org.apache.freemarker.core.Configuration;
-import org.apache.freemarker.core.util.FTLUtil;
+import org.apache.freemarker.core.util.TemplateLanguageUtils;
/**
* The common super-interface of the interfaces that stand for the FreeMarker Template Language (FTL) data types.
@@ -42,7 +42,7 @@ import org.apache.freemarker.core.util.FTLUtil;
* these types: string, number, boolean, date. The intended applications are like string+hash, string+method,
* hash+sequence, etc.
*
- * @see FTLUtil#getTypeDescription(TemplateModel)
+ * @see TemplateLanguageUtils#getTypeDescription(TemplateModel)
*/
public interface TemplateModel {
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/a5ac9983/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/OverloadedMethods.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/OverloadedMethods.java b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/OverloadedMethods.java
index 5912424..11a45bd 100644
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/OverloadedMethods.java
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/model/impl/OverloadedMethods.java
@@ -30,7 +30,7 @@ import org.apache.freemarker.core._TemplateModelException;
import org.apache.freemarker.core.model.TemplateMarkupOutputModel;
import org.apache.freemarker.core.model.TemplateModel;
import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.util.FTLUtil;
+import org.apache.freemarker.core.util.TemplateLanguageUtils;
import org.apache.freemarker.core.util._ClassUtils;
/**
@@ -216,7 +216,7 @@ final class OverloadedMethods {
private _DelayedConversionToString getTMActualParameterTypes(TemplateModel[] args) {
final String[] argumentTypeDescs = new String[args.length];
for (int i = 0; i < args.length; i++) {
- argumentTypeDescs[i] = FTLUtil.getTypeDescription(args[i]);
+ argumentTypeDescs[i] = TemplateLanguageUtils.getTypeDescription(args[i]);
}
return new DelayedCallSignatureToString(argumentTypeDescs) {
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/a5ac9983/freemarker-core/src/main/java/org/apache/freemarker/core/util/FTLUtil.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/util/FTLUtil.java b/freemarker-core/src/main/java/org/apache/freemarker/core/util/FTLUtil.java
deleted file mode 100644
index 1b5e04a..0000000
--- a/freemarker-core/src/main/java/org/apache/freemarker/core/util/FTLUtil.java
+++ /dev/null
@@ -1,872 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.freemarker.core.util;
-
-import java.util.HashSet;
-import java.util.Set;
-
-import org.apache.freemarker.core.Environment;
-import org.apache.freemarker.core._CoreAPI;
-import org.apache.freemarker.core.model.AdapterTemplateModel;
-import org.apache.freemarker.core.model.TemplateBooleanModel;
-import org.apache.freemarker.core.model.TemplateCallableModel;
-import org.apache.freemarker.core.model.TemplateCollectionModel;
-import org.apache.freemarker.core.model.TemplateCollectionModelEx;
-import org.apache.freemarker.core.model.TemplateDateModel;
-import org.apache.freemarker.core.model.TemplateDirectiveModel;
-import org.apache.freemarker.core.model.TemplateFunctionModel;
-import org.apache.freemarker.core.model.TemplateHashModel;
-import org.apache.freemarker.core.model.TemplateHashModelEx;
-import org.apache.freemarker.core.model.TemplateMarkupOutputModel;
-import org.apache.freemarker.core.model.TemplateModel;
-import org.apache.freemarker.core.model.TemplateModelIterator;
-import org.apache.freemarker.core.model.TemplateNodeModel;
-import org.apache.freemarker.core.model.TemplateNodeModelEx;
-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.WrapperTemplateModel;
-import org.apache.freemarker.core.model.impl.BeanAndStringModel;
-import org.apache.freemarker.core.model.impl.BeanModel;
-import org.apache.freemarker.core.model.impl.JavaMethodModel;
-
-/**
- * Static utility methods that perform tasks specific to the FreeMarker Template Language (FTL).
- * This is meant to be used from outside FreeMarker (i.e., it's an official, published API), not just from inside it.
- */
-// TODO [FM3] This name won't be good if the template language isn't called "FTL"...
-public final class FTLUtil {
-
- private static final char[] ESCAPES = createEscapes();
-
- private FTLUtil() {
- // Not meant to be instantiated
- }
-
- private static char[] createEscapes() {
- char[] escapes = new char['\\' + 1];
- for (int i = 0; i < 32; ++i) {
- escapes[i] = 1;
- }
- escapes['\\'] = '\\';
- escapes['\''] = '\'';
- escapes['"'] = '"';
- escapes['<'] = 'l';
- escapes['>'] = 'g';
- escapes['&'] = 'a';
- escapes['\b'] = 'b';
- escapes['\t'] = 't';
- escapes['\n'] = 'n';
- escapes['\f'] = 'f';
- escapes['\r'] = 'r';
- return escapes;
- }
-
- /**
- * Escapes a string according the FTL string literal escaping rules, assuming the literal is quoted with
- * {@code quotation}; it doesn't add the quotation marks themselves. {@code '&'}, {@code '<'}, and {@code '>'}
- * characters will be escaped.
- *
- * @param quotation Either {@code '"'} or {@code '\''}. It's assumed that the string literal whose part we calculate is
- * enclosed within this kind of quotation mark. Thus, the other kind of quotation character will not be
- * escaped in the result.
- */
- public static String escapeStringLiteralPart(String s, char quotation) {
- return escapeStringLiteralPart(s, quotation, false, true, true, true);
- }
-
- /**
- * Escapes a string according the FTL string literal escaping rules, assuming the literal is quoted with
- * {@code quotation}; it doesn't add the quotation marks themselves.
- *
- * @param quotation See in {@link #escapeStringLiteralPart(String, char)}
- * @param escapeAmp Whether to escape {@code '&'}
- * @param escapeLT Whether to escape {@code '<'}
- * @param escapeGT Whether to escape {@code '>'}
- */
- public static String escapeStringLiteralPart(String s, char quotation,
- boolean escapeAmp, boolean escapeLT, boolean escapeGT) {
- return escapeStringLiteralPart(s, quotation, false, escapeAmp, escapeLT, escapeGT);
- }
-
- /**
- * Escapes a string according the FTL string literal escaping rules; it doesn't add the quotation marks themselves.
- * As this method doesn't know if the string literal is quoted with regular quotation marks or apostrophe quote, it
- * will escape both.
- *
- * @see #escapeStringLiteralPart(String, char)
- */
- public static String escapeStringLiteralPart(String s) {
- return escapeStringLiteralPart(s, (char) 0, false);
- }
-
- private static String escapeStringLiteralPart(String s, char quotation, boolean addQuotation) {
- return escapeStringLiteralPart(s, quotation, addQuotation, true, true, true);
- }
-
- private static String escapeStringLiteralPart(String s, char quotation, boolean addQuotation,
- boolean escapeAmp, boolean escapeLT, boolean escapeGT) {
- final int ln = s.length();
-
- final char otherQuotation;
- if (quotation == 0) {
- otherQuotation = 0;
- } else if (quotation == '"') {
- otherQuotation = '\'';
- } else if (quotation == '\'') {
- otherQuotation = '"';
- } else {
- throw new IllegalArgumentException("Unsupported quotation character: " + quotation);
- }
-
- final int escLn = ESCAPES.length;
- StringBuilder buf = null;
- for (int i = 0; i < ln; i++) {
- char c = s.charAt(i);
- char escape =
- c < escLn ? ESCAPES[c] :
- c == '{' && i > 0 && isInterpolationStart(s.charAt(i - 1)) ? '{' :
- 0;
- if (escape == 0 || escape == otherQuotation
- || c == '&' && !escapeAmp || c == '<' && !escapeLT || c == '>' && !escapeGT) {
- if (buf != null) {
- buf.append(c);
- }
- } else {
- if (buf == null) {
- buf = new StringBuilder(s.length() + 4 + (addQuotation ? 2 : 0));
- if (addQuotation) {
- buf.append(quotation);
- }
- buf.append(s.substring(0, i));
- }
- if (escape == 1) {
- // hex encoding for characters below 0x20
- // that have no other escape representation
- buf.append("\\x00");
- int c2 = (c >> 4) & 0x0F;
- c = (char) (c & 0x0F);
- buf.append((char) (c2 < 10 ? c2 + '0' : c2 - 10 + 'A'));
- buf.append((char) (c < 10 ? c + '0' : c - 10 + 'A'));
- } else {
- buf.append('\\');
- buf.append(escape);
- }
- }
- }
-
- if (buf == null) {
- return addQuotation ? quotation + s + quotation : s;
- } else {
- if (addQuotation) {
- buf.append(quotation);
- }
- return buf.toString();
- }
- }
-
- private static boolean isInterpolationStart(char c) {
- // Find related: [interpolation prefixes]
- return c == '$';
- }
-
- /**
- * Unescapes a string that was escaped to be part of an FTL string literal. The string to unescape most not include
- * the two quotation marks or two apostrophe-quotes that delimit the literal.
- * <p>
- * \\, \", \', \n, \t, \r, \b and \f will be replaced according to
- * Java rules. In additional, it knows \g, \l, \a and \{ which are
- * replaced with <, >, & and { respectively.
- * \x works as hexadecimal character code escape. The character
- * codes are interpreted according to UCS basic plane (Unicode).
- * "f\x006Fo", "f\x06Fo" and "f\x6Fo" will be "foo".
- * "f\x006F123" will be "foo123" as the maximum number of digits is 4.
- * <p>
- * All other \X (where X is any character not mentioned above or End-of-string)
- * will cause a ParseException.
- *
- * @param s String literal <em>without</em> the surrounding quotation marks
- * @return String with all escape sequences resolved
- * @throws GenericParseException if there string contains illegal escapes
- */
- public static String unescapeStringLiteralPart(String s) throws GenericParseException {
-
- int idx = s.indexOf('\\');
- if (idx == -1) {
- return s;
- }
-
- int lidx = s.length() - 1;
- int bidx = 0;
- StringBuilder buf = new StringBuilder(lidx);
- do {
- buf.append(s.substring(bidx, idx));
- if (idx >= lidx) {
- throw new GenericParseException("The last character of string literal is backslash");
- }
- char c = s.charAt(idx + 1);
- switch (c) {
- case '"':
- buf.append('"');
- bidx = idx + 2;
- break;
- case '\'':
- buf.append('\'');
- bidx = idx + 2;
- break;
- case '\\':
- buf.append('\\');
- bidx = idx + 2;
- break;
- case 'n':
- buf.append('\n');
- bidx = idx + 2;
- break;
- case 'r':
- buf.append('\r');
- bidx = idx + 2;
- break;
- case 't':
- buf.append('\t');
- bidx = idx + 2;
- break;
- case 'f':
- buf.append('\f');
- bidx = idx + 2;
- break;
- case 'b':
- buf.append('\b');
- bidx = idx + 2;
- break;
- case 'g':
- buf.append('>');
- bidx = idx + 2;
- break;
- case 'l':
- buf.append('<');
- bidx = idx + 2;
- break;
- case 'a':
- buf.append('&');
- bidx = idx + 2;
- break;
- case '{':
- buf.append('{');
- bidx = idx + 2;
- break;
- case 'x': {
- idx += 2;
- int x = idx;
- int y = 0;
- int z = lidx > idx + 3 ? idx + 3 : lidx;
- while (idx <= z) {
- char b = s.charAt(idx);
- if (b >= '0' && b <= '9') {
- y <<= 4;
- y += b - '0';
- } else if (b >= 'a' && b <= 'f') {
- y <<= 4;
- y += b - 'a' + 10;
- } else if (b >= 'A' && b <= 'F') {
- y <<= 4;
- y += b - 'A' + 10;
- } else {
- break;
- }
- idx++;
- }
- if (x < idx) {
- buf.append((char) y);
- } else {
- throw new GenericParseException("Invalid \\x escape in a string literal");
- }
- bidx = idx;
- break;
- }
- default:
- throw new GenericParseException("Invalid escape sequence (\\" + c + ") in a string literal");
- }
- idx = s.indexOf('\\', bidx);
- } while (idx != -1);
- buf.append(s.substring(bidx));
-
- return buf.toString();
- }
-
- /**
- * Creates a <em>quoted</em> FTL string literal from a string, using escaping where necessary. The result either
- * uses regular quotation marks (UCS 0x22) or apostrophe-quotes (UCS 0x27), or it will be a raw string literal
- * (like {@code r"can contain backslash anywhere"}).
- * This is decided based on the number of regular quotation marks, apostrophe-quotes, and backslashes.
- *
- * @param s The value that should be converted to an FTL string literal whose evaluated value equals to {@code s}
- */
- public static String toStringLiteral(String s) {
- if (s == null) {
- return null;
- }
-
- int aposCnt = 0;
- int quotCnt = 0;
- int backslashCnt = 0;
- for (int i = 0; i < s.length(); i++) {
- char c = s.charAt(i);
- if (c == '\'') {
- aposCnt++;
- } else if (c == '"') {
- quotCnt++;
- } else if (c == '\\') {
- backslashCnt++;
- }
- }
-
- if (backslashCnt != 0) {
- if (quotCnt == 0) {
- return "r\"" + s + "\"";
- } else if (aposCnt == 0) {
- return "r\'" + s + "\'";
- }
- }
-
- char quotation;
- if (aposCnt < quotCnt ) {
- quotation = '\'';
- } else {
- quotation = '\"';
- }
- return escapeStringLiteralPart(s, quotation, true);
- }
-
- /**
- * Tells if a character can occur on the beginning of an FTL identifier expression (without escaping).
- */
- public static boolean isNonEscapedIdentifierStart(final char c) {
- // This code was generated on JDK 1.8.0_20 Win64 with src/main/misc/identifierChars/IdentifierCharGenerator.java
- if (c < 0xAA) { // This branch was edited for speed.
- if (c >= 'a' && c <= 'z' || c >= '@' && c <= 'Z') {
- return true;
- } else {
- return c == '$' || c == '_';
- }
- } else { // c >= 0xAA
- if (c < 0xA7F8) {
- if (c < 0x2D6F) {
- if (c < 0x2128) {
- if (c < 0x2090) {
- if (c < 0xD8) {
- if (c < 0xBA) {
- return c == 0xAA || c == 0xB5;
- } else { // c >= 0xBA
- return c == 0xBA || c >= 0xC0 && c <= 0xD6;
- }
- } else { // c >= 0xD8
- if (c < 0x2071) {
- return c >= 0xD8 && c <= 0xF6 || c >= 0xF8 && c <= 0x1FFF;
- } else { // c >= 0x2071
- return c == 0x2071 || c == 0x207F;
- }
- }
- } else { // c >= 0x2090
- if (c < 0x2115) {
- if (c < 0x2107) {
- return c >= 0x2090 && c <= 0x209C || c == 0x2102;
- } else { // c >= 0x2107
- return c == 0x2107 || c >= 0x210A && c <= 0x2113;
- }
- } else { // c >= 0x2115
- if (c < 0x2124) {
- return c == 0x2115 || c >= 0x2119 && c <= 0x211D;
- } else { // c >= 0x2124
- return c == 0x2124 || c == 0x2126;
- }
- }
- }
- } else { // c >= 0x2128
- if (c < 0x2C30) {
- if (c < 0x2145) {
- if (c < 0x212F) {
- return c == 0x2128 || c >= 0x212A && c <= 0x212D;
- } else { // c >= 0x212F
- return c >= 0x212F && c <= 0x2139 || c >= 0x213C && c <= 0x213F;
- }
- } else { // c >= 0x2145
- if (c < 0x2183) {
- return c >= 0x2145 && c <= 0x2149 || c == 0x214E;
- } else { // c >= 0x2183
- return c >= 0x2183 && c <= 0x2184 || c >= 0x2C00 && c <= 0x2C2E;
- }
- }
- } else { // c >= 0x2C30
- if (c < 0x2D00) {
- if (c < 0x2CEB) {
- return c >= 0x2C30 && c <= 0x2C5E || c >= 0x2C60 && c <= 0x2CE4;
- } else { // c >= 0x2CEB
- return c >= 0x2CEB && c <= 0x2CEE || c >= 0x2CF2 && c <= 0x2CF3;
- }
- } else { // c >= 0x2D00
- if (c < 0x2D2D) {
- return c >= 0x2D00 && c <= 0x2D25 || c == 0x2D27;
- } else { // c >= 0x2D2D
- return c == 0x2D2D || c >= 0x2D30 && c <= 0x2D67;
- }
- }
- }
- }
- } else { // c >= 0x2D6F
- if (c < 0x31F0) {
- if (c < 0x2DD0) {
- if (c < 0x2DB0) {
- if (c < 0x2DA0) {
- return c == 0x2D6F || c >= 0x2D80 && c <= 0x2D96;
- } else { // c >= 0x2DA0
- return c >= 0x2DA0 && c <= 0x2DA6 || c >= 0x2DA8 && c <= 0x2DAE;
- }
- } else { // c >= 0x2DB0
- if (c < 0x2DC0) {
- return c >= 0x2DB0 && c <= 0x2DB6 || c >= 0x2DB8 && c <= 0x2DBE;
- } else { // c >= 0x2DC0
- return c >= 0x2DC0 && c <= 0x2DC6 || c >= 0x2DC8 && c <= 0x2DCE;
- }
- }
- } else { // c >= 0x2DD0
- if (c < 0x3031) {
- if (c < 0x2E2F) {
- return c >= 0x2DD0 && c <= 0x2DD6 || c >= 0x2DD8 && c <= 0x2DDE;
- } else { // c >= 0x2E2F
- return c == 0x2E2F || c >= 0x3005 && c <= 0x3006;
- }
- } else { // c >= 0x3031
- if (c < 0x3040) {
- return c >= 0x3031 && c <= 0x3035 || c >= 0x303B && c <= 0x303C;
- } else { // c >= 0x3040
- return c >= 0x3040 && c <= 0x318F || c >= 0x31A0 && c <= 0x31BA;
- }
- }
- }
- } else { // c >= 0x31F0
- if (c < 0xA67F) {
- if (c < 0xA4D0) {
- if (c < 0x3400) {
- return c >= 0x31F0 && c <= 0x31FF || c >= 0x3300 && c <= 0x337F;
- } else { // c >= 0x3400
- return c >= 0x3400 && c <= 0x4DB5 || c >= 0x4E00 && c <= 0xA48C;
- }
- } else { // c >= 0xA4D0
- if (c < 0xA610) {
- return c >= 0xA4D0 && c <= 0xA4FD || c >= 0xA500 && c <= 0xA60C;
- } else { // c >= 0xA610
- return c >= 0xA610 && c <= 0xA62B || c >= 0xA640 && c <= 0xA66E;
- }
- }
- } else { // c >= 0xA67F
- if (c < 0xA78B) {
- if (c < 0xA717) {
- return c >= 0xA67F && c <= 0xA697 || c >= 0xA6A0 && c <= 0xA6E5;
- } else { // c >= 0xA717
- return c >= 0xA717 && c <= 0xA71F || c >= 0xA722 && c <= 0xA788;
- }
- } else { // c >= 0xA78B
- if (c < 0xA7A0) {
- return c >= 0xA78B && c <= 0xA78E || c >= 0xA790 && c <= 0xA793;
- } else { // c >= 0xA7A0
- return c >= 0xA7A0 && c <= 0xA7AA;
- }
- }
- }
- }
- }
- } else { // c >= 0xA7F8
- if (c < 0xAB20) {
- if (c < 0xAA44) {
- if (c < 0xA8FB) {
- if (c < 0xA840) {
- if (c < 0xA807) {
- return c >= 0xA7F8 && c <= 0xA801 || c >= 0xA803 && c <= 0xA805;
- } else { // c >= 0xA807
- return c >= 0xA807 && c <= 0xA80A || c >= 0xA80C && c <= 0xA822;
- }
- } else { // c >= 0xA840
- if (c < 0xA8D0) {
- return c >= 0xA840 && c <= 0xA873 || c >= 0xA882 && c <= 0xA8B3;
- } else { // c >= 0xA8D0
- return c >= 0xA8D0 && c <= 0xA8D9 || c >= 0xA8F2 && c <= 0xA8F7;
- }
- }
- } else { // c >= 0xA8FB
- if (c < 0xA984) {
- if (c < 0xA930) {
- return c == 0xA8FB || c >= 0xA900 && c <= 0xA925;
- } else { // c >= 0xA930
- return c >= 0xA930 && c <= 0xA946 || c >= 0xA960 && c <= 0xA97C;
- }
- } else { // c >= 0xA984
- if (c < 0xAA00) {
- return c >= 0xA984 && c <= 0xA9B2 || c >= 0xA9CF && c <= 0xA9D9;
- } else { // c >= 0xAA00
- return c >= 0xAA00 && c <= 0xAA28 || c >= 0xAA40 && c <= 0xAA42;
- }
- }
- }
- } else { // c >= 0xAA44
- if (c < 0xAAC0) {
- if (c < 0xAA80) {
- if (c < 0xAA60) {
- return c >= 0xAA44 && c <= 0xAA4B || c >= 0xAA50 && c <= 0xAA59;
- } else { // c >= 0xAA60
- return c >= 0xAA60 && c <= 0xAA76 || c == 0xAA7A;
- }
- } else { // c >= 0xAA80
- if (c < 0xAAB5) {
- return c >= 0xAA80 && c <= 0xAAAF || c == 0xAAB1;
- } else { // c >= 0xAAB5
- return c >= 0xAAB5 && c <= 0xAAB6 || c >= 0xAAB9 && c <= 0xAABD;
- }
- }
- } else { // c >= 0xAAC0
- if (c < 0xAAF2) {
- if (c < 0xAADB) {
- return c == 0xAAC0 || c == 0xAAC2;
- } else { // c >= 0xAADB
- return c >= 0xAADB && c <= 0xAADD || c >= 0xAAE0 && c <= 0xAAEA;
- }
- } else { // c >= 0xAAF2
- if (c < 0xAB09) {
- return c >= 0xAAF2 && c <= 0xAAF4 || c >= 0xAB01 && c <= 0xAB06;
- } else { // c >= 0xAB09
- return c >= 0xAB09 && c <= 0xAB0E || c >= 0xAB11 && c <= 0xAB16;
- }
- }
- }
- }
- } else { // c >= 0xAB20
- if (c < 0xFB46) {
- if (c < 0xFB13) {
- if (c < 0xAC00) {
- if (c < 0xABC0) {
- return c >= 0xAB20 && c <= 0xAB26 || c >= 0xAB28 && c <= 0xAB2E;
- } else { // c >= 0xABC0
- return c >= 0xABC0 && c <= 0xABE2 || c >= 0xABF0 && c <= 0xABF9;
- }
- } else { // c >= 0xAC00
- if (c < 0xD7CB) {
- return c >= 0xAC00 && c <= 0xD7A3 || c >= 0xD7B0 && c <= 0xD7C6;
- } else { // c >= 0xD7CB
- return c >= 0xD7CB && c <= 0xD7FB || c >= 0xF900 && c <= 0xFB06;
- }
- }
- } else { // c >= 0xFB13
- if (c < 0xFB38) {
- if (c < 0xFB1F) {
- return c >= 0xFB13 && c <= 0xFB17 || c == 0xFB1D;
- } else { // c >= 0xFB1F
- return c >= 0xFB1F && c <= 0xFB28 || c >= 0xFB2A && c <= 0xFB36;
- }
- } else { // c >= 0xFB38
- if (c < 0xFB40) {
- return c >= 0xFB38 && c <= 0xFB3C || c == 0xFB3E;
- } else { // c >= 0xFB40
- return c >= 0xFB40 && c <= 0xFB41 || c >= 0xFB43 && c <= 0xFB44;
- }
- }
- }
- } else { // c >= 0xFB46
- if (c < 0xFF21) {
- if (c < 0xFDF0) {
- if (c < 0xFD50) {
- return c >= 0xFB46 && c <= 0xFBB1 || c >= 0xFBD3 && c <= 0xFD3D;
- } else { // c >= 0xFD50
- return c >= 0xFD50 && c <= 0xFD8F || c >= 0xFD92 && c <= 0xFDC7;
- }
- } else { // c >= 0xFDF0
- if (c < 0xFE76) {
- return c >= 0xFDF0 && c <= 0xFDFB || c >= 0xFE70 && c <= 0xFE74;
- } else { // c >= 0xFE76
- return c >= 0xFE76 && c <= 0xFEFC || c >= 0xFF10 && c <= 0xFF19;
- }
- }
- } else { // c >= 0xFF21
- if (c < 0xFFCA) {
- if (c < 0xFF66) {
- return c >= 0xFF21 && c <= 0xFF3A || c >= 0xFF41 && c <= 0xFF5A;
- } else { // c >= 0xFF66
- return c >= 0xFF66 && c <= 0xFFBE || c >= 0xFFC2 && c <= 0xFFC7;
- }
- } else { // c >= 0xFFCA
- if (c < 0xFFDA) {
- return c >= 0xFFCA && c <= 0xFFCF || c >= 0xFFD2 && c <= 0xFFD7;
- } else { // c >= 0xFFDA
- return c >= 0xFFDA && c <= 0xFFDC;
- }
- }
- }
- }
- }
- }
- }
- }
-
- /**
- * Tells if a character can occur in an FTL identifier expression (without escaping) as other than the first
- * character.
- */
- public static boolean isNonEscapedIdentifierPart(final char c) {
- return isNonEscapedIdentifierStart(c) || (c >= '0' && c <= '9');
- }
-
- /**
- * Tells if a given character, for which {@link #isNonEscapedIdentifierStart(char)} and
- * {@link #isNonEscapedIdentifierPart(char)} is {@code false}, can occur in an identifier if it's preceded by a
- * backslash. Currently it return {@code true} for these: {@code '-'}, {@code '.'} and {@code ':'}.
- */
- public static boolean isEscapedIdentifierCharacter(final char c) {
- return c == '-' || c == '.' || c == ':';
- }
-
- /**
- * Escapes characters in the string that can only occur in FTL identifiers (variable names) escaped.
- * This means adding a backslash before any character for which {@link #isEscapedIdentifierCharacter(char)}
- * is {@code true}. Other characters will be left unescaped, even if they aren't valid in FTL identifiers.
- *
- * @param s The identifier to escape. If {@code null}, {@code null} is returned.
- */
- public static String escapeIdentifier(String s) {
- if (s == null) {
- return null;
- }
-
- int ln = s.length();
-
- // First we find out if we need to escape, and if so, what the length of the output will be:
- int firstEscIdx = -1;
- int lastEscIdx = 0;
- int plusOutLn = 0;
- for (int i = 0; i < ln; i++) {
- char c = s.charAt(i);
- if (isEscapedIdentifierCharacter(c)) {
- if (firstEscIdx == -1) {
- firstEscIdx = i;
- }
- lastEscIdx = i;
- plusOutLn++;
- } else if (i == 0 && !isNonEscapedIdentifierStart(c)
- || i > 0 && !isNonEscapedIdentifierPart(c)) {
- // TODO [FM3] But quoting is only allowed for target variables... that's a strange syntax anyway.
- return toStringLiteral(s);
- }
- }
-
- if (firstEscIdx == -1) {
- return s; // Nothing to escape
- } else {
- char[] esced = new char[ln + plusOutLn];
- if (firstEscIdx != 0) {
- s.getChars(0, firstEscIdx, esced, 0);
- }
- int dst = firstEscIdx;
- for (int i = firstEscIdx; i <= lastEscIdx; i++) {
- char c = s.charAt(i);
- if (isEscapedIdentifierCharacter(c)) {
- esced[dst++] = '\\';
- }
- esced[dst++] = c;
- }
- if (lastEscIdx != ln - 1) {
- s.getChars(lastEscIdx + 1, ln, esced, dst);
- }
-
- return String.valueOf(esced);
- }
- }
-
- /**
- * Returns the type description of a value with FTL terms (not plain class name), as it should be used in
- * type-related error messages and for debugging purposes. The exact format is not specified and might change over
- * time, but currently it's something like {@code "string (wrapper: f.t.SimpleScalar)"} or
- * {@code "sequence+hash+string (ArrayList wrapped into f.e.b.CollectionModel)"}.
- *
- * @param tm The value whose type we will describe. If {@code null}, then {@code "Null"} is returned (without the
- * quotation marks).
- */
- public static String getTypeDescription(TemplateModel tm) {
- if (tm == null) {
- return "Null";
- } else {
- Set typeNamesAppended = new HashSet();
-
- StringBuilder sb = new StringBuilder();
-
- Class primaryInterface = getPrimaryTemplateModelInterface(tm);
- if (primaryInterface != null) {
- appendTemplateModelTypeName(sb, typeNamesAppended, primaryInterface);
- }
-
- appendTemplateModelTypeName(sb, typeNamesAppended, tm.getClass());
-
- String javaClassName;
- Class unwrappedClass = getUnwrappedClass(tm);
- if (unwrappedClass != null) {
- javaClassName = _ClassUtils.getShortClassName(unwrappedClass, true);
- } else {
- javaClassName = null;
- }
-
- sb.append(" (");
- String modelClassName = _ClassUtils.getShortClassName(tm.getClass(), true);
- if (javaClassName == null) {
- sb.append("wrapper: ");
- sb.append(modelClassName);
- } else {
- sb.append(javaClassName);
- sb.append(" wrapped into ");
- sb.append(modelClassName);
- }
- sb.append(")");
-
- return sb.toString();
- }
- }
-
- /**
- * Return the template language type name of callable class, as it should be shown in error messages.
- *
- * @param callable
- * Can't be {@code null}.
- */
- public static String getCallableTypeName(TemplateCallableModel callable) {
- _NullArgumentException.check("callable", callable);
-
- String result = "callable-of-unknown-kind";
-
- String d = null;
- if (callable instanceof TemplateDirectiveModel) {
- d = _CoreAPI.isMacro(callable.getClass()) ? "macro" : "directive";
- result = d;
- }
-
- if (callable instanceof TemplateFunctionModel) {
- String f = callable instanceof JavaMethodModel ? "method" : "function";
- result = d == null ? f : d + "+" + f;
- }
-
- return result;
- }
-
- /**
- * Returns the {@link TemplateModel} interface that is the most characteristic of the object, or {@code null}.
- */
- private static Class getPrimaryTemplateModelInterface(TemplateModel tm) {
- if (tm instanceof BeanModel) {
- if (tm instanceof BeanAndStringModel) {
- Object wrapped = ((BeanModel) tm).getWrappedObject();
- return wrapped instanceof String
- ? TemplateScalarModel.class
- : (tm instanceof TemplateHashModelEx ? TemplateHashModelEx.class : null);
- } else {
- return null;
- }
- } else {
- return null;
- }
- }
-
- private static void appendTemplateModelTypeName(StringBuilder sb, Set typeNamesAppended, Class cl) {
- int initalLength = sb.length();
-
- if (TemplateNodeModelEx.class.isAssignableFrom(cl)) {
- appendTypeName(sb, typeNamesAppended, "extended node");
- } else if (TemplateNodeModel.class.isAssignableFrom(cl)) {
- appendTypeName(sb, typeNamesAppended, "node");
- }
-
- if (TemplateCallableModel.class.isAssignableFrom(cl)) {
- if (TemplateDirectiveModel.class.isAssignableFrom(cl)) {
- appendTypeName(sb, typeNamesAppended, _CoreAPI.isMacro(cl) ? "macro" : "directive");
- }
- if (TemplateFunctionModel.class.isAssignableFrom(cl)) {
- appendTypeName(sb, typeNamesAppended,
- JavaMethodModel.class.isAssignableFrom(cl) ? "method" : "function");
- }
- }
-
- if (TemplateSequenceModel.class.isAssignableFrom(cl)) {
- appendTypeName(sb, typeNamesAppended, "sequence");
- } else if (TemplateCollectionModel.class.isAssignableFrom(cl)) {
- appendTypeName(sb, typeNamesAppended,
- TemplateCollectionModelEx.class.isAssignableFrom(cl) ? "extended_collection" : "collection");
- } else if (TemplateModelIterator.class.isAssignableFrom(cl)) {
- appendTypeName(sb, typeNamesAppended, "iterator");
- }
-
- if (Environment.Namespace.class.isAssignableFrom(cl)) {
- appendTypeName(sb, typeNamesAppended, "namespace");
- } else if (TemplateHashModelEx.class.isAssignableFrom(cl)) {
- appendTypeName(sb, typeNamesAppended, "extendedHash");
- } else if (TemplateHashModel.class.isAssignableFrom(cl)) {
- appendTypeName(sb, typeNamesAppended, "hash");
- }
-
- if (TemplateNumberModel.class.isAssignableFrom(cl)) {
- appendTypeName(sb, typeNamesAppended, "number");
- }
-
- if (TemplateDateModel.class.isAssignableFrom(cl)) {
- appendTypeName(sb, typeNamesAppended, "date_or_time_or_dateTime");
- }
-
- if (TemplateBooleanModel.class.isAssignableFrom(cl)) {
- appendTypeName(sb, typeNamesAppended, "boolean");
- }
-
- if (TemplateScalarModel.class.isAssignableFrom(cl)) {
- appendTypeName(sb, typeNamesAppended, "string");
- }
-
- if (TemplateMarkupOutputModel.class.isAssignableFrom(cl)) {
- appendTypeName(sb, typeNamesAppended, "markupOutput");
- }
-
- if (sb.length() == initalLength) {
- appendTypeName(sb, typeNamesAppended, "miscTemplateModel");
- }
- }
-
- private static Class getUnwrappedClass(TemplateModel tm) {
- Object unwrapped;
- try {
- if (tm instanceof WrapperTemplateModel) {
- unwrapped = ((WrapperTemplateModel) tm).getWrappedObject();
- } else if (tm instanceof AdapterTemplateModel) {
- unwrapped = ((AdapterTemplateModel) tm).getAdaptedObject(Object.class);
- } else {
- unwrapped = null;
- }
- } catch (Throwable e) {
- unwrapped = null;
- }
- return unwrapped != null ? unwrapped.getClass() : null;
- }
-
- private static void appendTypeName(StringBuilder sb, Set typeNamesAppended, String name) {
- if (!typeNamesAppended.contains(name)) {
- if (sb.length() != 0) sb.append("+");
- sb.append(name);
- typeNamesAppended.add(name);
- }
- }
-}