Repository: incubator-freemarker Updated Branches: refs/heads/3 22d3ef2e0 -> d0a9c2bb5
Continued 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/d0a9c2bb Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/d0a9c2bb Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/d0a9c2bb Branch: refs/heads/3 Commit: d0a9c2bb57793d8b7504cec9563198cdc0ef6f96 Parents: 22d3ef2 Author: ddekany <[email protected]> Authored: Sun Jul 9 00:40:52 2017 +0200 Committer: ddekany <[email protected]> Committed: Sun Jul 9 00:40:52 2017 +0200 ---------------------------------------------------------------------- .../core/FM2ASTToFM3SourceConverter.java | 129 +++++++++++++++---- .../converter/FM2ToFM3ConverterTest.java | 9 ++ 2 files changed, 110 insertions(+), 28 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/d0a9c2bb/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 6ff6958..0e0ed11 100644 --- a/freemarker-converter/src/main/java/freemarker/core/FM2ASTToFM3SourceConverter.java +++ b/freemarker-converter/src/main/java/freemarker/core/FM2ASTToFM3SourceConverter.java @@ -406,11 +406,52 @@ public class FM2ASTToFM3SourceConverter { printDirRecurse((RecurseNode) node); } else if (node instanceof FallbackInstruction) { printDirFallback((FallbackInstruction) node); + } else if (node instanceof TransformBlock) { + printDirTransform((TransformBlock) node); } else { throw new ConverterException("Unhandled AST TemplateElement class: " + node.getClass().getName()); } } + private void printDirTransform(TransformBlock node) throws ConverterException { + Expression callee = getParam(node, 0, ParameterRole.CALLEE, Expression.class); + + print(tagBeginChar); + print('@'); + printExp(callee); + + int pos = printWSAndExpComments(getEndPositionExclusive(callee)); + if (src.charAt(pos) == ';') { + pos++; + pos = printWSAndExpComments(pos); + } + + int paramIdx = 1; + while (paramIdx < node.getParameterCount()) { + String paramName = getParam(node, paramIdx++, ParameterRole.ARGUMENT_NAME, String.class); + print(FTLUtil.escapeIdentifier(paramName)); + pos = getPositionAfterIdentifier(pos); + + pos = printSeparatorAndWSAndExpComments(pos, "="); + + Expression paramValue = getParam(node, paramIdx++, ParameterRole.ARGUMENT_VALUE, Expression.class); + printExp(paramValue); + + pos = printWSAndExpComments(getEndPositionExclusive(paramValue)); + } + + printStartTagEnd(node, pos, false); + + printChildElements(node); + + print(tagBeginChar); + print("/@"); + if (callee instanceof Identifier || (callee instanceof Dot && ((Dot) callee).onlyHasIdentifiers())) { + printExp(callee); + } + print(tagEndChar); + } + private void printDirFallback(FallbackInstruction node) throws ConverterException { printDirGenericNoParamsNoNested(node, "fallback"); } @@ -426,7 +467,7 @@ public class FM2ASTToFM3SourceConverter { private void printDirVisitLike(TemplateElement node, String tagName) throws ConverterException { assertParamCount(node, 2); - printStartTagPartBeforeParams(node, tagName); + printDirStartTagPartBeforeParams(node, tagName); Expression lastParam; @@ -457,7 +498,7 @@ public class FM2ASTToFM3SourceConverter { throw new UnexpectedNodeContentException(node, "Unsupported subtype {}", subtype); } - int pos = printStartTagPartBeforeParams(node, tagName); + int pos = printDirStartTagPartBeforeParams(node, tagName); Expression value = getParam(node, 0, ParameterRole.CONDITION, Expression.class); if (value != null) { @@ -475,7 +516,7 @@ public class FM2ASTToFM3SourceConverter { private void printDirSwitch(SwitchBlock node) throws ConverterException { assertParamCount(node, 1); - printStartTagPartBeforeParams(node, "switch"); + printDirStartTagPartBeforeParams(node, "switch"); Expression param = getOnlyParam(node, ParameterRole.VALUE, Expression.class); printExp(param); @@ -490,7 +531,7 @@ public class FM2ASTToFM3SourceConverter { private void printDirStop(StopInstruction node) throws ConverterException { assertParamCount(node, 1); - int pos = printStartTagPartBeforeParams(node, "stop"); + int pos = printDirStartTagPartBeforeParams(node, "stop"); Expression message = getParam(node, 0, ParameterRole.MESSAGE, Expression.class); if (message != null) { printExp(message); @@ -502,7 +543,7 @@ public class FM2ASTToFM3SourceConverter { private void printDirSetting(PropertySetting node) throws ConverterException { assertParamCount(node, 2); - int pos = printStartTagPartBeforeParams(node, "setting"); + int pos = printDirStartTagPartBeforeParams(node, "setting"); print(FTLUtil.escapeIdentifier(convertSettingName( getParam(node, 0, ParameterRole.ITEM_KEY, String.class), @@ -552,7 +593,7 @@ public class FM2ASTToFM3SourceConverter { } private void printDirNested(BodyInstruction node) throws ConverterException { - int pos = printStartTagPartBeforeParams(node, "nested"); + int pos = printDirStartTagPartBeforeParams(node, "nested"); int paramCnt = node.getParameterCount(); for (int paramIdx = 0; paramIdx < paramCnt; paramIdx++) { Expression passedValue = getParam(node, paramIdx, ParameterRole.PASSED_VALUE, Expression.class); @@ -570,7 +611,7 @@ public class FM2ASTToFM3SourceConverter { } private void printDirItems(Items node) throws ConverterException { - int pos = printStartTagPartBeforeParams(node, "items"); + int pos = printDirStartTagPartBeforeParams(node, "items"); pos = printSeparatorAndWSAndExpComments(pos, "as"); int paramCnt = node.getParameterCount(); @@ -616,7 +657,7 @@ public class FM2ASTToFM3SourceConverter { int paramCount = node.getParameterCount(); assertNodeContent(paramCount <= 3, node, "ParameterCount <= 3 was expected"); - int pos = printStartTagPartBeforeParams(node, "list"); + int pos = printDirStartTagPartBeforeParams(node, "list"); Expression listSource = getParam(node, 0, ParameterRole.LIST_SOURCE, Expression.class); // To be future proof, we don't assume that the parameter count of list don't include the null parameters. @@ -702,7 +743,7 @@ public class FM2ASTToFM3SourceConverter { private void printDirInclude(Include node) throws ConverterException { assertParamCount(node, 4); - printStartTagPartBeforeParams(node, "include"); + printDirStartTagPartBeforeParams(node, "include"); Expression templateName = getParam(node, 0, ParameterRole.TEMPLATE_NAME, Expression.class); int templateNameEndPos = getEndPositionExclusive(templateName); @@ -785,7 +826,7 @@ public class FM2ASTToFM3SourceConverter { private void printDirImport(LibraryLoad node) throws ConverterException { assertParamCount(node, 2); - printStartTagPartBeforeParams(node, "import"); + printDirStartTagPartBeforeParams(node, "import"); Expression templateName = getParam(node, 0, ParameterRole.TEMPLATE_NAME, Expression.class); printExp(templateName); @@ -799,7 +840,7 @@ public class FM2ASTToFM3SourceConverter { } private void printDirReturn(ReturnInstruction node) throws ConverterException { - printStartTagPartBeforeParams(node, "return"); + printDirStartTagPartBeforeParams(node, "return"); Expression value = getOnlyParam(node, ParameterRole.VALUE, Expression.class); printExp(value); @@ -819,7 +860,7 @@ public class FM2ASTToFM3SourceConverter { private void printDirEscape(EscapeBlock node) throws ConverterException { assertParamCount(node, 2); - int pos = printStartTagPartBeforeParams(node, "escape"); + int pos = printDirStartTagPartBeforeParams(node, "escape"); pos = getPositionAfterIdentifier(pos); print(FTLUtil.escapeIdentifier(getParam(node, 0, ParameterRole.PLACEHOLDER_VARIABLE, String.class))); @@ -955,7 +996,7 @@ public class FM2ASTToFM3SourceConverter { private int printDirAssignmentCommonTagTillAssignmentExp(TemplateElement node, int scopeParamIdx) throws ConverterException { - return printStartTagPartBeforeParams(node, getAssignmentDirTagName(node, scopeParamIdx)); + return printDirStartTagPartBeforeParams(node, getAssignmentDirTagName(node, scopeParamIdx)); } private String getAssignmentDirTagName(TemplateElement node, int scopeParamIdx) @@ -1011,7 +1052,7 @@ public class FM2ASTToFM3SourceConverter { throw new UnexpectedNodeContentException(node, "Unhandled node subtype: {}", subtype); } - int pos = printStartTagPartBeforeParams(node, tagName); + int pos = printDirStartTagPartBeforeParams(node, tagName); String assignedName = getParam(node, 0, ParameterRole.ASSIGNMENT_TARGET, String.class); print(FTLUtil.escapeIdentifier(assignedName)); @@ -1085,13 +1126,28 @@ public class FM2ASTToFM3SourceConverter { boolean ftlDirMode = printNextCustomDirAsFtlDir; printNextCustomDirAsFtlDir = false; + boolean legacyCallDirMode = src.startsWith("#call" , getStartPosition(node) + 1); + print(tagBeginChar); print(ftlDirMode ? '#' : '@'); Expression callee = getParam(node, 0, ParameterRole.CALLEE, Expression.class); printExp(callee); - Expression lastPrintedExp = callee; + int calleEnd = getEndPositionExclusive(callee); + int lastParamEnd = printWSAndExpComments(calleEnd); + boolean legacyCallDirWithParenthesis = false; + boolean legacyCallDirNeedsSeparatorSpace = false; + if (legacyCallDirMode) { + if (src.charAt(lastParamEnd) == '(') { + if (calleEnd == lastParamEnd) { + legacyCallDirNeedsSeparatorSpace = true; + } + lastParamEnd++; // skip '(' + legacyCallDirWithParenthesis = true; + } + } + int paramIdx = 1; int paramCount = node.getParameterCount(); @@ -1099,20 +1155,31 @@ public class FM2ASTToFM3SourceConverter { while (paramIdx < paramCount && node.getParameterRole(paramIdx) == ParameterRole.ARGUMENT_VALUE) { Expression argValue = getParam(node, paramIdx, ParameterRole.ARGUMENT_VALUE, Expression.class); - printParameterSeparatorSource(lastPrintedExp, argValue); + if (legacyCallDirNeedsSeparatorSpace) { + print(' '); + legacyCallDirNeedsSeparatorSpace = false; + } + printSeparatorAndWSAndExpComments(lastParamEnd, ",", true); printExp(argValue); - lastPrintedExp = argValue; + lastParamEnd = getEndPositionExclusive(argValue); paramIdx++; } + if (legacyCallDirWithParenthesis) { + lastParamEnd = printWSAndExpComments(lastParamEnd); + assertNodeContent(src.charAt(lastParamEnd) == ')', node, + "Can't find closing parenthesis of #call(...)"); + lastParamEnd++; // skip ')' + } + // Print named arguments: while (paramIdx < paramCount && node.getParameterRole(paramIdx) == ParameterRole.ARGUMENT_NAME) { String paramName = getParam(node, paramIdx, ParameterRole.ARGUMENT_NAME, String.class); Expression argValue = getParam(node, paramIdx + 1, ParameterRole.ARGUMENT_VALUE, Expression.class); - int pos = getEndPositionExclusive(lastPrintedExp); + int pos = lastParamEnd; pos = printOptionalSeparatorAndWSAndExpComments(pos, ","); pos = getPositionAfterIdentifier(pos); if (ftlDirMode) { @@ -1122,12 +1189,12 @@ public class FM2ASTToFM3SourceConverter { printSeparatorAndWSAndExpComments(pos, "="); printExp(argValue); - lastPrintedExp = argValue; + lastParamEnd = getEndPositionExclusive(argValue); paramIdx += 2; } // Print loop variables: - int pos = getEndPositionExclusive(lastPrintedExp); + int pos = lastParamEnd; boolean beforeFirstLoopVar = true; while (paramIdx < paramCount) { pos = printSeparatorAndWSAndExpComments(pos, beforeFirstLoopVar ? ";" : ","); @@ -1143,6 +1210,10 @@ public class FM2ASTToFM3SourceConverter { paramIdx++; } + pos = printWSAndExpComments(pos); + if (legacyCallDirMode) { + print('/'); + } int startTagEndPos = printStartTagEnd(node, pos, false); int elementEndPos = getEndPositionInclusive(node); @@ -1168,8 +1239,10 @@ public class FM2ASTToFM3SourceConverter { printWithConvertedExpComments(src.substring(nameStartPos, elementEndPos)); print(tagEndChar); } else { // We don't have end-tag - assertNodeContent(src.charAt(startTagEndPos - 1) == '/', node, - "Expected \"/\" at the end of the start tag"); + if (!legacyCallDirMode) { + assertNodeContent(src.charAt(startTagEndPos - 1) == '/', node, + "Expected \"/\" at the end of the start tag"); + } assertNodeContent(node.getChildCount() == 0, node, "Expected no children"); } @@ -1192,7 +1265,7 @@ public class FM2ASTToFM3SourceConverter { } if (conditionExp != null) { - printStartTagPartBeforeParams(node, tagName); + printDirStartTagPartBeforeParams(node, tagName); printNode(conditionExp); printStartTagEnd(node, conditionExp, true); } else { @@ -1370,7 +1443,7 @@ public class FM2ASTToFM3SourceConverter { int lhoEndExcl = getEndPositionExclusive(lho); int opStart = getPositionAfterWSAndExpComments(lhoEndExcl); printWithConvertedExpComments(src.substring(lhoEndExcl, opStart)); - final String fm2Op = readUntilWSOrComment(opStart); + final String fm2Op = readUntilWSOrComment(opStart, getStartPosition(rho)); String fm3Op = operatorMapper.get(fm2Op); if (fm3Op == null) { throw new UnexpectedNodeContentException(node, "Unhandled operator: {}", fm2Op); @@ -1684,7 +1757,7 @@ public class FM2ASTToFM3SourceConverter { * * @return The position in the source after the printed part */ - private int printStartTagPartBeforeParams(TemplateElement node, String fm3TagName) + private int printDirStartTagPartBeforeParams(TemplateElement node, String fm3TagName) throws ConverterException { print(tagBeginChar); print('#'); @@ -1704,7 +1777,7 @@ public class FM2ASTToFM3SourceConverter { private int printDirStartTagNoParams(TemplateElement node, String fm3TagName, boolean removeSlash) throws ConverterException { - int pos = printStartTagPartBeforeParams(node, fm3TagName); + int pos = printDirStartTagPartBeforeParams(node, fm3TagName); printStartTagEnd(node, pos, removeSlash); return pos + 1; } @@ -2166,9 +2239,9 @@ public class FM2ASTToFM3SourceConverter { return src.substring(startPos, getPositionAfterIdentifier(startPos)); } - private String readUntilWSOrComment(int startPos) throws ConverterException { + private String readUntilWSOrComment(int startPos, int endPosition) throws ConverterException { int pos = startPos; - while (pos < src.length() && !Character.isWhitespace(src.charAt(pos)) && !isExpCommentStart(pos)) { + while (pos < endPosition && !Character.isWhitespace(src.charAt(pos)) && !isExpCommentStart(pos)) { pos++; } return src.substring(startPos, pos); http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/d0a9c2bb/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 a76350c..980d833 100644 --- a/freemarker-converter/src/test/java/org/freemarker/converter/FM2ToFM3ConverterTest.java +++ b/freemarker-converter/src/test/java/org/freemarker/converter/FM2ToFM3ConverterTest.java @@ -367,6 +367,15 @@ public class FM2ToFM3ConverterTest extends ConverterTest { assertEquals(1, (Object) e.getRow()); assertEquals(2, (Object) e.getColumn()); } + + assertConverted("<@m 1, 2, 3/>", "<#call m(1, 2, 3)>"); + assertConverted("<@m/>", "<#call m()>"); + assertConverted("<@m/>", "<#call m>"); + assertConverted("<@m a=1 b=2/>", "<#call m a=1 b=2>"); + + assertConverted("<@t a=1 b=2>x</@t>", "<#transform t a=1 b=2>x</#transform>"); + assertConverted("<@n.t>x</@n.t>", "<#transform n.t>x</#transform>"); + assertConverted("<@f()>x</@>", "<#transform f()>x</#transform>"); } @Test
