Repository: incubator-freemarker Updated Branches: refs/heads/3 2548f5cdc -> c5feb6328
Continued work on the FM2 to FM3 converter Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/c5feb632 Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/c5feb632 Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/c5feb632 Branch: refs/heads/3 Commit: c5feb6328a6f6dc027c52eda5bfe62ad0d967a87 Parents: 2548f5c Author: ddekany <ddek...@apache.org> Authored: Fri Jun 30 01:19:05 2017 +0200 Committer: ddekany <ddek...@apache.org> Committed: Fri Jun 30 01:19:05 2017 +0200 ---------------------------------------------------------------------- .../core/FM2ASTToFM3SourceConverter.java | 115 ++++++++++++++++++- .../converter/FM2ToFM3ConverterTest.java | 18 +++ 2 files changed, 129 insertions(+), 4 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/c5feb632/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 7f8a2da..13a80ac 100644 --- a/freemarker-converter/src/main/java/freemarker/core/FM2ASTToFM3SourceConverter.java +++ b/freemarker-converter/src/main/java/freemarker/core/FM2ASTToFM3SourceConverter.java @@ -20,7 +20,9 @@ package freemarker.core; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Set; import org.apache.freemarker.converter.ConverterException; @@ -382,11 +384,101 @@ public class FM2ASTToFM3SourceConverter { printExpBuiltinVariable((BuiltinVariable) node); } else if (node instanceof Dot) { printExpDot((Dot) node); + } else if (node instanceof ComparisonExpression) { + printExpComparison((ComparisonExpression) node); + } else if (node instanceof AndExpression) { + printExpAnd((AndExpression) node); + } else if (node instanceof OrExpression) { + printExpOr((OrExpression) node); + } else if (node instanceof NotExpression) { + printExpNot((NotExpression) node); } else { - throw new ConverterException("Unhandled AST node class: " + node.getClass().getName()); + throw new ConverterException("Unhandled AST node expression class: " + node.getClass().getName()); } } + private void printExpNot(NotExpression node) throws ConverterException { + printWithParamsLeadingSkippedTokens("!", node); + printNode(getOnlyParam(node, ParameterRole.RIGHT_HAND_OPERAND, Expression.class)); + } + + private static final Map<String, String> COMPARATOR_OP_MAP; + static { + COMPARATOR_OP_MAP = new HashMap<String, String>(); + // For now we leave FM2 ops as is, but later in many cases they will be replaced. + COMPARATOR_OP_MAP.put("==", "=="); + COMPARATOR_OP_MAP.put("=", "="); + COMPARATOR_OP_MAP.put("!=", "!="); + COMPARATOR_OP_MAP.put("<", "<"); + COMPARATOR_OP_MAP.put("lt", "lt"); + COMPARATOR_OP_MAP.put("\\lt", "\\lt"); + COMPARATOR_OP_MAP.put("<", "<"); + COMPARATOR_OP_MAP.put("<=", "<="); + COMPARATOR_OP_MAP.put("lte", "lte"); + COMPARATOR_OP_MAP.put("\\lte", "\\lte"); + COMPARATOR_OP_MAP.put("<=", "<="); + COMPARATOR_OP_MAP.put(">", ">"); + COMPARATOR_OP_MAP.put("gt", "gt"); + COMPARATOR_OP_MAP.put("\\gt", "\\gt"); + COMPARATOR_OP_MAP.put(">", ">"); + COMPARATOR_OP_MAP.put(">=", ">="); + COMPARATOR_OP_MAP.put("gte", "gte"); + COMPARATOR_OP_MAP.put("\\gte", "\\gte"); + COMPARATOR_OP_MAP.put(">=", ">="); + } + + private void printExpComparison(ComparisonExpression node) throws ConverterException { + printExpBinaryWithMappedOperator(node, COMPARATOR_OP_MAP); + } + + private static final Map<String, String> AND_OP_MAP; + static { + AND_OP_MAP = new HashMap<String, String>(); + // For now we leave FM2 ops as is, but later in many cases they will be replaced. + AND_OP_MAP.put("&&", "&&"); + AND_OP_MAP.put("&", "&"); + AND_OP_MAP.put("\\and", "\\and"); + AND_OP_MAP.put("&&", "&&"); + } + + private void printExpAnd(AndExpression node) throws ConverterException { + printExpBinaryWithMappedOperator(node, AND_OP_MAP); + } + + private static final Map<String, String> OR_OP_MAP; + static { + OR_OP_MAP = new HashMap<String, String>(); + // For now we leave FM2 ops as is, but later in many cases they will be replaced. + OR_OP_MAP.put("||", "||"); + OR_OP_MAP.put("|", "|"); + } + + private void printExpOr(OrExpression node) throws ConverterException { + printExpBinaryWithMappedOperator(node, OR_OP_MAP); + } + + private void printExpBinaryWithMappedOperator(Expression node, Map<String, String> operatorMapper) throws + ConverterException { + assertParamCount(node, 2); + Expression lho = getParam(node, 0, ParameterRole.LEFT_HAND_OPERAND, Expression.class); + Expression rho = getParam(node, 1, ParameterRole.RIGHT_HAND_OPERAND, Expression.class); + + printExp(lho); + + int lhoEndExcl = getEndPositionExclusive(lho); + int opStart = getPositionAfterWSAndExpComments(lhoEndExcl); + printWithConvertedExpComments(src.substring(lhoEndExcl, opStart)); + final String fm2Op = readUntilWSOrComment(opStart); + String fm3Op = operatorMapper.get(fm2Op); + if (fm3Op == null) { + throw new UnexpectedNodeContentException(node, "Unhandled operator: {}", fm2Op); + } + print(fm3Op); + printWithConvertedExpComments(src.substring(opStart + fm2Op.length(), getStartPosition(rho))); + + printExp(rho); + } + private void printExpBuiltinVariable(BuiltinVariable node) throws ConverterException { int startPos = getStartPosition(node); String sep = readExpWSAndSeparator(startPos, '.', false); @@ -933,9 +1025,8 @@ public class FM2ASTToFM3SourceConverter { private int getPositionAfterWSAndExpComments(int pos) throws ConverterException { scanForNoWSNoComment: while (pos < src.length()) { char c = src.charAt(pos); - if ((c == '<' || c == '[') - && (src.startsWith("!--", pos + 1) || src.startsWith("#--", pos + 1))) { - pos += 4; + if (isExpCommentStart(pos)) { + pos += 4; // length of "<#--" scanForCommentEnd: while (pos < src.length()) { if (src.startsWith("-->", pos) || src.startsWith("--]", pos)) { @@ -994,4 +1085,20 @@ public class FM2ASTToFM3SourceConverter { return src.substring(startPos, pos); } + private String readUntilWSOrComment(int startPos) throws ConverterException { + int pos = startPos; + while (pos < src.length() && !Character.isWhitespace(src.charAt(pos)) && !isExpCommentStart(pos)) { + pos++; + } + return src.substring(startPos, pos); + } + + private boolean isExpCommentStart(int pos) { + char c = src.charAt(pos); + return (c == '<' || c == '[') + && (pos + 1 < src.length() + && src.startsWith("!--", pos + 1) || src.startsWith("#--", pos + 1)); + + } + } http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/c5feb632/freemarker-converter/src/test/java/org/freemarker/converter/FM2ToFM3ConverterTest.java ---------------------------------------------------------------------- diff --git a/freemarker-converter/src/test/java/org/freemarker/converter/FM2ToFM3ConverterTest.java b/freemarker-converter/src/test/java/org/freemarker/converter/FM2ToFM3ConverterTest.java index 936c516..54abfd2 100644 --- a/freemarker-converter/src/test/java/org/freemarker/converter/FM2ToFM3ConverterTest.java +++ b/freemarker-converter/src/test/java/org/freemarker/converter/FM2ToFM3ConverterTest.java @@ -106,6 +106,24 @@ public class FM2ToFM3ConverterTest extends ConverterTest { assertConvertedSame("${.outputFormat}"); assertConvertedSame("${. <#-- C --> outputFormat}"); assertConverted("${.outputFormat}","${.output_format}"); + + assertConvertedSame("${a < b}${a <= b}${(a > b)}${(a >= b)}${a == b}${a != b}"); + assertConvertedSame("${a<#-- C1 --><<#-- C2 -->b}${a<#-- C3 --><=<#-- C4 -->b}" + + "${(a<#-- C7 -->><#-- C8 -->b)}${(a<#-- C9 -->>=<#-- CA -->b)}" + + "${a<#-- CB -->==<#-- CC -->b}${a<#-- CD -->!=<#-- CE -->b}"); + // "Same" for now, will be different later. + assertConvertedSame("${a = b}${a == b}"); + assertConvertedSame("${a < b}${a lt b}${a \\lt b}"); + assertConvertedSame("${a <= b}${a lte b}${a \\lte b}"); + assertConvertedSame("${a > b}${a gt b}${a \\gt b}"); + assertConvertedSame("${a >= b}${a gte b}${a \\gte b}"); + + // [FM3] Add \and and && tests when 2.3.27 is released + assertConvertedSame("${a && b}${a & b}${a || b}${a | b}"); + assertConvertedSame("${a<#-- C1 -->&&<#-- C2 -->b}${a<#-- C3 -->&<#-- C4 -->b}" + + "${a<#-- C5 -->||<#-- C6 -->b}${a<#-- C7 -->|<#-- C8 -->b}"); + + assertConvertedSame("${!a}${! foo}${! <#-- C1 --> bar}${!!c}"); } @Test