From e112d81ea8ba77e8649bed486b905578f26c5f48 Mon Sep 17 00:00:00 2001 From: JesseBrault0709 <62299747+JesseBrault0709@users.noreply.github.com> Date: Mon, 27 May 2024 09:02:53 +0200 Subject: [PATCH] Transpiler refactoring finished. --- .../web/ast/DefaultAstBuilderVisitor.java | 17 +- .../component/web/ast/DefaultNodeFactory.java | 8 +- .../view/component/web/ast/NodeFactory.java | 4 +- .../extension/GroovyCodeNodeExtension.java | 1 + .../web/ast/node/ClosureValueNode.java | 2 +- .../web/ast/node/GStringBodyTextNode.java | 35 --- .../web/ast/node/JStringBodyTextNode.java | 27 --- .../AppendOrAddStatementFactory.java | 22 -- .../web/transpile/BodyTranspiler.java | 16 +- .../DefaultAppendOrAddStatementFactory.java | 79 ------- .../transpile/DefaultBodyTextTranspiler.java | 18 +- .../web/transpile/DefaultBodyTranspiler.java | 6 +- .../transpile/DefaultComponentTranspiler.java | 62 ++---- .../transpile/DefaultGStringTranspiler.java | 204 ------------------ .../DefaultGroovyBodyNodeTranspiler.java | 18 +- .../transpile/DefaultGroovyTranspiler.java | 33 +-- .../transpile/DefaultJStringTranspiler.java | 47 ---- .../transpile/DefaultLeftShiftFactory.java | 28 +++ .../DefaultTranspilerConfiguration.java | 85 -------- .../transpile/DefaultValueNodeTranspiler.java | 68 +++--- .../web/transpile/GStringTranspiler.java | 9 - .../web/transpile/JStringTranspiler.java | 12 -- .../web/transpile/LeftShiftFactory.java | 2 +- .../SimpleTranspilerConfiguration.java | 150 +++++++++++++ .../transpile/TranspilerConfiguration.java | 1 - .../ast/DefaultAstBuilderVisitorTests.groovy | 33 +-- .../DefaultBodyTranspilerTests.java | 6 +- .../DefaultGStringTranspilerTests.java | 16 -- .../component/web/ast/NodeFactoryTests.java | 4 +- .../web/transpiler/BodyTranspilerTests.java | 53 +---- .../transpiler/GStringTranspilerTests.java | 82 ------- 31 files changed, 287 insertions(+), 861 deletions(-) delete mode 100644 web-view-components-compiler/src/main/java/groowt/view/component/web/ast/node/GStringBodyTextNode.java delete mode 100644 web-view-components-compiler/src/main/java/groowt/view/component/web/ast/node/JStringBodyTextNode.java delete mode 100644 web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/AppendOrAddStatementFactory.java delete mode 100644 web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/DefaultAppendOrAddStatementFactory.java delete mode 100644 web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/DefaultGStringTranspiler.java delete mode 100644 web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/DefaultJStringTranspiler.java create mode 100644 web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/DefaultLeftShiftFactory.java delete mode 100644 web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/DefaultTranspilerConfiguration.java delete mode 100644 web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/GStringTranspiler.java delete mode 100644 web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/JStringTranspiler.java create mode 100644 web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/SimpleTranspilerConfiguration.java delete mode 100644 web-view-components-compiler/src/test/java/groowt/view/component/web/transpiler/DefaultGStringTranspilerTests.java delete mode 100644 web-view-components-compiler/src/testFixtures/java/groowt/view/component/web/transpiler/GStringTranspilerTests.java diff --git a/web-view-components-compiler/src/main/java/groowt/view/component/web/ast/DefaultAstBuilderVisitor.java b/web-view-components-compiler/src/main/java/groowt/view/component/web/ast/DefaultAstBuilderVisitor.java index c406e98..5bc7ae1 100644 --- a/web-view-components-compiler/src/main/java/groowt/view/component/web/ast/DefaultAstBuilderVisitor.java +++ b/web-view-components-compiler/src/main/java/groowt/view/component/web/ast/DefaultAstBuilderVisitor.java @@ -361,7 +361,7 @@ public class DefaultAstBuilderVisitor extends WebViewComponentsParserBaseVisitor public @Nullable Node visitPlainScriptlet(WebViewComponentsParser.PlainScriptletContext ctx) { final TerminalNode groovyCode = ctx.GroovyCode(); if (groovyCode != null) { - return this.nodeFactory.plainScriptletNode(this.getTokenRange(ctx), groovyCode.getSymbol().getTokenIndex()); + return this.nodeFactory.plainScriptletNode(this.getTokenRange(ctx), groovyCode.getSymbol().getText()); } else { return null; } @@ -381,16 +381,15 @@ public class DefaultAstBuilderVisitor extends WebViewComponentsParserBaseVisitor } @Override - public @Nullable Node visitDollarReference(WebViewComponentsParser.DollarReferenceContext ctx) { - final TerminalNode groovyCode = ctx.GroovyCode(); - if (groovyCode != null) { - return this.nodeFactory.dollarReferenceNode( - this.getTokenRange(ctx), - groovyCode.getSymbol().getTokenIndex() - ); + public Node visitDollarReference(WebViewComponentsParser.DollarReferenceContext ctx) { + final String groovyCode = ctx.GroovyCode().getText(); + final List parts = new ArrayList<>(); + if (groovyCode.contains(".")) { + parts.addAll(List.of(groovyCode.split("\\."))); } else { - return null; + parts.add(groovyCode); } + return this.nodeFactory.dollarReferenceNode(this.getTokenRange(ctx), parts); } @Override diff --git a/web-view-components-compiler/src/main/java/groowt/view/component/web/ast/DefaultNodeFactory.java b/web-view-components-compiler/src/main/java/groowt/view/component/web/ast/DefaultNodeFactory.java index b7f8d9e..73d7e1d 100644 --- a/web-view-components-compiler/src/main/java/groowt/view/component/web/ast/DefaultNodeFactory.java +++ b/web-view-components-compiler/src/main/java/groowt/view/component/web/ast/DefaultNodeFactory.java @@ -225,8 +225,8 @@ public class DefaultNodeFactory implements NodeFactory { } @Override - public PlainScriptletNode plainScriptletNode(TokenRange tokenRange, int groovyIndex) { - return this.objectFactory.get(PlainScriptletNode.class, tokenRange, groovyIndex); + public PlainScriptletNode plainScriptletNode(TokenRange tokenRange, String groovyCode) { + return this.objectFactory.get(PlainScriptletNode.class, tokenRange, groovyCode); } @Override @@ -235,8 +235,8 @@ public class DefaultNodeFactory implements NodeFactory { } @Override - public DollarReferenceNode dollarReferenceNode(TokenRange tokenRange, int groovyIndex) { - return this.objectFactory.get(DollarReferenceNode.class, tokenRange, groovyIndex); + public DollarReferenceNode dollarReferenceNode(TokenRange tokenRange, List parts) { + return this.objectFactory.get(DollarReferenceNode.class, tokenRange, parts); } } diff --git a/web-view-components-compiler/src/main/java/groowt/view/component/web/ast/NodeFactory.java b/web-view-components-compiler/src/main/java/groowt/view/component/web/ast/NodeFactory.java index 7e1942b..f7cf88f 100644 --- a/web-view-components-compiler/src/main/java/groowt/view/component/web/ast/NodeFactory.java +++ b/web-view-components-compiler/src/main/java/groowt/view/component/web/ast/NodeFactory.java @@ -76,10 +76,10 @@ public interface NodeFactory { EqualsScriptletNode equalsScriptletNode(TokenRange tokenRange, String groovyCode); - PlainScriptletNode plainScriptletNode(TokenRange tokenRange, int groovyIndex); + PlainScriptletNode plainScriptletNode(TokenRange tokenRange, String groovyCode); DollarScriptletNode dollarScriptletNode(TokenRange tokenRange, String groovyCode); - DollarReferenceNode dollarReferenceNode(TokenRange tokenRange, int groovyIndex); + DollarReferenceNode dollarReferenceNode(TokenRange tokenRange, List parts); } diff --git a/web-view-components-compiler/src/main/java/groowt/view/component/web/ast/extension/GroovyCodeNodeExtension.java b/web-view-components-compiler/src/main/java/groowt/view/component/web/ast/extension/GroovyCodeNodeExtension.java index 2513c78..1d70680 100644 --- a/web-view-components-compiler/src/main/java/groowt/view/component/web/ast/extension/GroovyCodeNodeExtension.java +++ b/web-view-components-compiler/src/main/java/groowt/view/component/web/ast/extension/GroovyCodeNodeExtension.java @@ -11,6 +11,7 @@ import java.util.ArrayList; import java.util.List; import java.util.function.Function; +@Deprecated public class GroovyCodeNodeExtension implements NodeExtension { private final Node self; diff --git a/web-view-components-compiler/src/main/java/groowt/view/component/web/ast/node/ClosureValueNode.java b/web-view-components-compiler/src/main/java/groowt/view/component/web/ast/node/ClosureValueNode.java index db16918..194c7b5 100644 --- a/web-view-components-compiler/src/main/java/groowt/view/component/web/ast/node/ClosureValueNode.java +++ b/web-view-components-compiler/src/main/java/groowt/view/component/web/ast/node/ClosureValueNode.java @@ -38,7 +38,7 @@ public class ClosureValueNode extends AbstractLeafNode implements ValueNode { } protected String toValidGroovyCode(List groovyTokens) { - return "def c = { " + groovyTokens.stream().map(Token::getText).collect(Collectors.joining()) + "\n}"; + return "def cl = {" + groovyTokens.stream().map(Token::getText).collect(Collectors.joining()) + "}"; } public GroovyCodeNodeExtension getGroovyCode() { diff --git a/web-view-components-compiler/src/main/java/groowt/view/component/web/ast/node/GStringBodyTextNode.java b/web-view-components-compiler/src/main/java/groowt/view/component/web/ast/node/GStringBodyTextNode.java deleted file mode 100644 index a6779a7..0000000 --- a/web-view-components-compiler/src/main/java/groowt/view/component/web/ast/node/GStringBodyTextNode.java +++ /dev/null @@ -1,35 +0,0 @@ -package groowt.view.component.web.ast.node; - -import groowt.util.di.annotation.Given; -import groowt.view.component.web.ast.extension.GStringNodeExtension; -import groowt.view.component.web.ast.extension.NodeExtensionContainer; -import groowt.view.component.web.util.TokenRange; -import jakarta.inject.Inject; - -import java.util.List; - -@Deprecated -public class GStringBodyTextNode extends AbstractTreeNode implements BodyChildNode { - - protected static List checkChildren(List children) { - for (final var child : children) { - if (!(child instanceof JStringBodyTextNode || child.hasExtension(GStringNodeExtension.class))) { - throw new IllegalArgumentException( - "Children of GStringBodyTextNode must be either a JStringBodyTextNode, " + - "or have a GStringNodeExtension." - ); - } - } - return children; - } - - @Inject - public GStringBodyTextNode( - NodeExtensionContainer extensionContainer, - @Given TokenRange tokenRange, - @Given List children - ) { - super(tokenRange, extensionContainer, checkChildren(children)); - } - -} diff --git a/web-view-components-compiler/src/main/java/groowt/view/component/web/ast/node/JStringBodyTextNode.java b/web-view-components-compiler/src/main/java/groowt/view/component/web/ast/node/JStringBodyTextNode.java deleted file mode 100644 index 9e1100f..0000000 --- a/web-view-components-compiler/src/main/java/groowt/view/component/web/ast/node/JStringBodyTextNode.java +++ /dev/null @@ -1,27 +0,0 @@ -package groowt.view.component.web.ast.node; - -import groowt.util.di.annotation.Given; -import groowt.view.component.web.ast.extension.NodeExtensionContainer; -import groowt.view.component.web.util.TokenRange; -import jakarta.inject.Inject; - -@Deprecated -public class JStringBodyTextNode extends AbstractLeafNode implements BodyChildNode { - - private final String content; - - @Inject - public JStringBodyTextNode( - NodeExtensionContainer extensionContainer, - @Given TokenRange tokenRange, - @Given String content - ) { - super(tokenRange, extensionContainer); - this.content = content; - } - - public String getContent() { - return this.content; - } - -} diff --git a/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/AppendOrAddStatementFactory.java b/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/AppendOrAddStatementFactory.java deleted file mode 100644 index 65ae3d1..0000000 --- a/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/AppendOrAddStatementFactory.java +++ /dev/null @@ -1,22 +0,0 @@ -package groowt.view.component.web.transpile; - -import groowt.view.component.web.ast.node.BodyChildNode; -import org.codehaus.groovy.ast.expr.Expression; -import org.codehaus.groovy.ast.stmt.Statement; - -import java.util.function.Function; - -@Deprecated -public interface AppendOrAddStatementFactory { - - enum Action { - ADD, APPEND - } - - Statement addOrAppend(BodyChildNode sourceNode, TranspilerState state, Function getRightSide); - - default Statement addOrAppend(BodyChildNode sourceNode, TranspilerState state, Expression rightSide) { - return this.addOrAppend(sourceNode, state, ignored -> rightSide); - } - -} diff --git a/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/BodyTranspiler.java b/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/BodyTranspiler.java index 51e7d8c..f1b3b34 100644 --- a/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/BodyTranspiler.java +++ b/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/BodyTranspiler.java @@ -1,22 +1,8 @@ package groowt.view.component.web.transpile; -import groowt.view.component.web.ast.node.BodyChildNode; import groowt.view.component.web.ast.node.BodyNode; -import org.codehaus.groovy.ast.expr.Expression; import org.codehaus.groovy.ast.stmt.BlockStatement; -import org.codehaus.groovy.ast.stmt.Statement; public interface BodyTranspiler { - - @FunctionalInterface - interface AddOrAppendCallback { - Statement createStatement(BodyChildNode source, Expression expression); - } - - BlockStatement transpileBody( - BodyNode bodyNode, - AddOrAppendCallback addOrAppendCallback, - TranspilerState state - ); - + BlockStatement transpileBody(BodyNode bodyNode, TranspilerState state); } diff --git a/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/DefaultAppendOrAddStatementFactory.java b/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/DefaultAppendOrAddStatementFactory.java deleted file mode 100644 index fe90a74..0000000 --- a/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/DefaultAppendOrAddStatementFactory.java +++ /dev/null @@ -1,79 +0,0 @@ -package groowt.view.component.web.transpile; - -import groovy.lang.Tuple2; -import groowt.view.component.web.ast.node.BodyChildNode; -import org.codehaus.groovy.ast.expr.*; -import org.codehaus.groovy.ast.stmt.ExpressionStatement; -import org.codehaus.groovy.ast.stmt.Statement; - -import java.util.function.Function; - -public class DefaultAppendOrAddStatementFactory implements AppendOrAddStatementFactory { - - private void addLineAndColumn( - BodyChildNode bodyChildNode, - TupleExpression args - ) { - final Tuple2 lineAndColumn = TranspilerUtil.lineAndColumn( - bodyChildNode.asNode().getTokenRange().getStartPosition() - ); - args.addExpression(lineAndColumn.getV1()); - args.addExpression(lineAndColumn.getV2()); - } - - private Statement doCreate( - BodyChildNode bodyChildNode, - Expression rightSide, - VariableExpression target, - String methodName // , - // boolean addLineAndColumn - ) { - final ArgumentListExpression args; - if (rightSide instanceof ArgumentListExpression argumentListExpression) { - args = argumentListExpression; - } else { - args = new ArgumentListExpression(); - args.addExpression(rightSide); - } -// if (addLineAndColumn && -// NodeUtil.isAnyOfType(bodyChildNode.asNode(), GStringBodyTextNode.class, ComponentNode.class)) { -// this.addLineAndColumn(bodyChildNode, args); -// } - final MethodCallExpression outExpression = new MethodCallExpression(target, methodName, args); - return new ExpressionStatement(outExpression); - } - - protected Statement addOnly(BodyChildNode bodyChildNode, TranspilerState state, Expression rightSide) { - return this.doCreate( - bodyChildNode, - rightSide, - state.getCurrentChildList(), - TranspilerUtil.ADD //, - // false - ); - } - - protected Statement appendOnly(BodyChildNode bodyChildNode, TranspilerState state, Expression rightSide) { - return this.doCreate( - bodyChildNode, - rightSide, - state.getWriter(), - TranspilerUtil.APPEND //, - // false - ); - } - - @Override - public Statement addOrAppend( - BodyChildNode bodyChildNode, - TranspilerState state, - Function getRightSide - ) { - if (state.hasCurrentChildList()) { - return this.addOnly(bodyChildNode, state, getRightSide.apply(Action.ADD)); - } else { - return this.appendOnly(bodyChildNode, state, getRightSide.apply(Action.APPEND)); - } - } - -} diff --git a/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/DefaultBodyTextTranspiler.java b/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/DefaultBodyTextTranspiler.java index 970c5a7..0c11a63 100644 --- a/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/DefaultBodyTextTranspiler.java +++ b/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/DefaultBodyTextTranspiler.java @@ -33,16 +33,16 @@ public class DefaultBodyTextTranspiler implements BodyTextTranspiler { this.includeComments = includeComments; } - protected Statement handleStringLiteral(Token source) { + protected Statement handleStringLiteral(TranspilerState state, Token source) { final ConstantExpression literal = getStringLiteral(source.getText()); this.positionSetter.setPosition(literal, source); - return this.leftShiftFactory.create(literal); + return this.leftShiftFactory.create(state, literal); } - protected Statement handleStringLiteral(Node source, String content) { + protected Statement handleStringLiteral(TranspilerState state, Node source, String content) { final ConstantExpression literal = getStringLiteral(content); this.positionSetter.setPosition(literal, source); - return this.leftShiftFactory.create(literal); + return this.leftShiftFactory.create(state, literal); } protected List handleHtmlCommentChild(HtmlCommentChild child, TranspilerState state) { @@ -67,23 +67,23 @@ public class DefaultBodyTextTranspiler implements BodyTextTranspiler { final List result = new ArrayList<>(); switch (child) { case QuestionNode questionNode -> { - result.add(this.handleStringLiteral(questionNode.getOpenToken())); + result.add(this.handleStringLiteral(state, questionNode.getOpenToken())); questionNode.getChildrenAsQuestionTagChildren().stream() .map(questionChild -> this.handleQuestionTagChild(questionChild, state)) .forEach(result::addAll); - result.add(this.handleStringLiteral(questionNode.getCloseToken())); + result.add(this.handleStringLiteral(state, questionNode.getCloseToken())); } case HtmlCommentNode commentNode -> { if (this.includeComments) { - result.add(this.handleStringLiteral(commentNode.getOpenToken())); + result.add(this.handleStringLiteral(state, commentNode.getOpenToken())); commentNode.getChildrenAsHtmlCommentChildren().stream() .map(commentChild -> this.handleHtmlCommentChild(commentChild, state)) .forEach(result::addAll); - result.add(this.handleStringLiteral(commentNode.getCloseToken())); + result.add(this.handleStringLiteral(state, commentNode.getCloseToken())); } } case TextNode textNode -> { - result.add(this.handleStringLiteral(textNode, textNode.getContent())); + result.add(this.handleStringLiteral(state, textNode, textNode.getContent())); } case GroovyBodyNode groovyBodyNode -> { result.add(this.groovyBodyNodeTranspiler.createGroovyBodyNodeStatements(groovyBodyNode, state)); diff --git a/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/DefaultBodyTranspiler.java b/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/DefaultBodyTranspiler.java index 1d35006..e589cc2 100644 --- a/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/DefaultBodyTranspiler.java +++ b/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/DefaultBodyTranspiler.java @@ -18,11 +18,7 @@ public class DefaultBodyTranspiler implements BodyTranspiler { } @Override - public BlockStatement transpileBody( - BodyNode bodyNode, - AddOrAppendCallback addOrAppendCallback, - TranspilerState state - ) { + public BlockStatement transpileBody(BodyNode bodyNode, TranspilerState state) { final BlockStatement block = new BlockStatement(); block.setVariableScope(state.pushScope()); for (final Node child : bodyNode.getChildren()) { diff --git a/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/DefaultComponentTranspiler.java b/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/DefaultComponentTranspiler.java index eaac1ce..cd27904 100644 --- a/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/DefaultComponentTranspiler.java +++ b/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/DefaultComponentTranspiler.java @@ -1,6 +1,5 @@ package groowt.view.component.web.transpile; -import groowt.util.fp.provider.Provider; import groowt.view.component.context.ComponentResolveException; import groowt.view.component.runtime.ComponentCreateException; import groowt.view.component.web.WebViewComponentBugError; @@ -29,37 +28,25 @@ public class DefaultComponentTranspiler implements ComponentTranspiler { private static final Pattern isFqn = Pattern.compile("^(\\p{Ll}.+\\.)+\\p{Lu}.+$"); private static final Pattern isWithPackage = Pattern.compile("^\\p{Ll}.+\\."); - private final Provider appendOrAddStatementFactoryProvider; - private final Provider componentClassNodeResolverProvider; - private final Provider valueNodeTranspilerProvider; - private final Provider bodyTranspilerProvider; + private LeftShiftFactory leftShiftFactory; + private ValueNodeTranspiler valueNodeTranspiler; + private BodyTranspiler bodyTranspiler; + private ComponentClassNodeResolver componentClassNodeResolver; - public DefaultComponentTranspiler( - Provider appendOrAddStatementFactoryProvider, - Provider componentClassNodeResolverProvider, - Provider valueNodeTranspilerProvider, - Provider bodyTranspilerProvider - ) { - this.appendOrAddStatementFactoryProvider = appendOrAddStatementFactoryProvider; - this.componentClassNodeResolverProvider = componentClassNodeResolverProvider; - this.valueNodeTranspilerProvider = valueNodeTranspilerProvider; - this.bodyTranspilerProvider = bodyTranspilerProvider; + public void setLeftShiftFactory(LeftShiftFactory leftShiftFactory) { + this.leftShiftFactory = leftShiftFactory; } - protected ValueNodeTranspiler getValueNodeTranspiler() { - return this.valueNodeTranspilerProvider.get(); + public void setValueNodeTranspiler(ValueNodeTranspiler valueNodeTranspiler) { + this.valueNodeTranspiler = valueNodeTranspiler; } - protected BodyTranspiler getBodyTranspiler() { - return this.bodyTranspilerProvider.get(); + public void setBodyTranspiler(BodyTranspiler bodyTranspiler) { + this.bodyTranspiler = bodyTranspiler; } - protected AppendOrAddStatementFactory getAppendOrAddStatementFactory() { - return this.appendOrAddStatementFactoryProvider.get(); - } - - protected ComponentClassNodeResolver getComponentClassNodeResolver() { - return this.componentClassNodeResolverProvider.get(); + public void setComponentClassNodeResolver(ComponentClassNodeResolver componentClassNodeResolver) { + this.componentClassNodeResolver = componentClassNodeResolver; } /* UTIL */ @@ -104,7 +91,7 @@ public class DefaultComponentTranspiler implements ComponentTranspiler { // we need to resolve it final var isWithPackageMatcher = isWithPackage.matcher(identifier); if (isWithPackageMatcher.matches()) { - final var resolveResult = this.getComponentClassNodeResolver().getClassForFqn(identifier); + final var resolveResult = this.componentClassNodeResolver.getClassForFqn(identifier); if (resolveResult.isLeft()) { final var error = resolveResult.getLeft(); error.setNode(componentNode.getArgs().getType()); @@ -117,7 +104,7 @@ public class DefaultComponentTranspiler implements ComponentTranspiler { } } else { final var resolveResult = - this.getComponentClassNodeResolver().getClassForNameWithoutPackage(identifier); + this.componentClassNodeResolver.getClassForNameWithoutPackage(identifier); if (resolveResult.isLeft()) { final var error = resolveResult.getLeft(); error.setNode(componentNode.getArgs().getType()); @@ -260,7 +247,7 @@ public class DefaultComponentTranspiler implements ComponentTranspiler { final Expression valueExpr = switch (attrNode) { case BooleanValueAttrNode ignored -> ConstantExpression.PRIM_TRUE; case KeyValueAttrNode keyValueAttrNode -> - this.getValueNodeTranspiler().createExpression(keyValueAttrNode.getValueNode(), state); + this.valueNodeTranspiler.createExpression(keyValueAttrNode.getValueNode(), state); }; return new MapEntryExpression(keyExpr, valueExpr); } @@ -328,11 +315,7 @@ public class DefaultComponentTranspiler implements ComponentTranspiler { scope.putDeclaredVariable(childListParam); state.pushChildList(childListParam); - final BlockStatement bodyStatements = this.getBodyTranspiler().transpileBody( - bodyNode, - (sourceNode, expr) -> this.getChildListAdd(childListParam, expr), - state - ); + final BlockStatement bodyStatements = this.bodyTranspiler.transpileBody(bodyNode, state); // clean up state.popChildList(); @@ -491,11 +474,7 @@ public class DefaultComponentTranspiler implements ComponentTranspiler { // Create final List createStatements = this.getTypedCreateStatements(typedComponentNode, state); // Append/Add - final Statement addOrAppend = this.getAppendOrAddStatementFactory().addOrAppend( - componentNode, - state, - (VariableExpression) state.getCurrentComponent() - ); + final Statement leftShift = this.leftShiftFactory.create(state, state.getCurrentComponent()); // cleanup state.popResolved(); @@ -504,17 +483,16 @@ public class DefaultComponentTranspiler implements ComponentTranspiler { final List allStatements = new ArrayList<>(); allStatements.addAll(resolveStatements); allStatements.addAll(createStatements); - allStatements.add(addOrAppend); + allStatements.add(leftShift); return allStatements; } else if (componentNode instanceof FragmentComponentNode fragmentComponentNode) { // Create and add all at once - final Statement addOrAppend = this.getAppendOrAddStatementFactory().addOrAppend( - componentNode, + final Statement leftShift = this.leftShiftFactory.create( state, this.getFragmentCreateExpression(fragmentComponentNode, state) ); - return List.of(addOrAppend); + return List.of(leftShift); } else { throw new WebViewComponentBugError(new IllegalArgumentException( "Cannot handle a ComponentNode not of type TypedComponentNode or FragmentComponentNode." diff --git a/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/DefaultGStringTranspiler.java b/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/DefaultGStringTranspiler.java deleted file mode 100644 index 44adfac..0000000 --- a/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/DefaultGStringTranspiler.java +++ /dev/null @@ -1,204 +0,0 @@ -package groowt.view.component.web.transpile; - -import groowt.util.fp.option.Option; -import groowt.view.component.web.antlr.MergedGroovyCodeToken; -import groowt.view.component.web.antlr.WebViewComponentsLexer; -import groowt.view.component.web.ast.extension.GStringNodeExtension; -import groowt.view.component.web.ast.extension.GStringPathExtension; -import groowt.view.component.web.ast.extension.GStringScriptletExtension; -import groowt.view.component.web.ast.node.GStringBodyTextNode; -import groowt.view.component.web.ast.node.JStringBodyTextNode; -import groowt.view.component.web.ast.node.Node; -import groowt.view.component.web.transpile.groovy.GroovyUtil; -import groowt.view.component.web.util.FilteringIterable; -import groowt.view.component.web.util.TokenRange; -import org.antlr.v4.runtime.Token; -import org.codehaus.groovy.ast.expr.*; -import org.codehaus.groovy.ast.stmt.BlockStatement; -import org.codehaus.groovy.ast.stmt.ExpressionStatement; -import org.codehaus.groovy.ast.stmt.Statement; -import org.jetbrains.annotations.Nullable; - -import java.util.ArrayList; -import java.util.List; -import java.util.ListIterator; -import java.util.stream.Collectors; - -@Deprecated -public class DefaultGStringTranspiler implements GStringTranspiler { - - private final PositionSetter positionSetter; - private final JStringTranspiler jStringTranspiler; - - public DefaultGStringTranspiler(PositionSetter positionSetter, JStringTranspiler jStringTranspiler) { - this.positionSetter = positionSetter; - this.jStringTranspiler = jStringTranspiler; - } - - protected Option checkPrevBeforeDollar(@Nullable Node prev, Node current) { - if (!(prev instanceof JStringBodyTextNode)) { - return Option.liftLazy(() -> { - final ConstantExpression expression = this.jStringTranspiler.createEmptyStringLiteral(); - this.positionSetter.setToStartOf(expression, current); - return expression; - }); - } else { - return Option.empty(); - } - } - - protected Option checkNextAfterDollar(@Nullable Node next) { - if (next != null && next.hasExtension(GStringNodeExtension.class)) { - return Option.liftLazy(() -> { - final ConstantExpression expression = this.jStringTranspiler.createEmptyStringLiteral(); - this.positionSetter.setToStartOf(expression, next); - return expression; - }); - } else { - return Option.empty(); - } - } - - protected ConstantExpression handleText(JStringBodyTextNode jStringBodyTextNode, @Nullable Node prev) { - if (prev instanceof JStringBodyTextNode) { - throw new IllegalStateException("Cannot have two texts in a row"); - } - return this.jStringTranspiler.createStringLiteral(jStringBodyTextNode); - } - - protected record PathResult( - Expression result, - Option before, - Option after - ) {} - - protected PathResult handlePath(Node current, GStringPathExtension path, @Nullable Node prev, @Nullable Node next) { - final List groowtTokens = path.getRawTokens(); - - VariableExpression begin = null; - PropertyExpression propertyExpression = null; - - for (final Token groowtToken : groowtTokens) { - if (groowtToken instanceof MergedGroovyCodeToken groovyCodeToken) { - final Iterable identifierTokenIterable = FilteringIterable.continuingUntilSuccess( - groovyCodeToken.getOriginals(), - token -> token.getType() == WebViewComponentsLexer.GStringIdentifier - ); - for (final Token identifierToken : identifierTokenIterable) { - final String identifier = identifierToken.getText(); - final TokenRange identifierTokenRange = TokenRange.of(identifierToken); - if (begin == null) { - begin = new VariableExpression(identifier); - this.positionSetter.setPosition(begin, identifierTokenRange); - } else if (propertyExpression == null) { - propertyExpression = new PropertyExpression(begin, identifier); - this.positionSetter.setPosition(propertyExpression, identifierTokenRange); - } else { - propertyExpression = new PropertyExpression(propertyExpression, identifier); - this.positionSetter.setPosition(propertyExpression, identifierTokenRange); - } - } - } else { - throw new IllegalStateException("Received a non-MergedGroovyToken from a GStringExtension"); - } - } - - if (begin == null) { - throw new IllegalStateException("begin is null!"); - } - - if (propertyExpression != null) { - return new PathResult( - propertyExpression, - this.checkPrevBeforeDollar(prev, current), - this.checkNextAfterDollar(next) - ); - } else { - return new PathResult( - begin, - this.checkPrevBeforeDollar(prev, current), - this.checkNextAfterDollar(next) - ); - } - } - - protected ClosureExpression handleScriptlet(GStringScriptletExtension gStringScriptletExtension) { - final GroovyUtil.ConvertResult convertResult = GroovyUtil.convert( - "def cl = {" + gStringScriptletExtension.getAsValidEmbeddableCode() + "}" - ); - final BlockStatement convertBlock = convertResult.blockStatement(); - if (convertBlock == null) { - throw new NullPointerException("Did not except convertBlock to be null"); - } - final List convertStatements = convertBlock.getStatements(); - if (convertStatements.size() != 1) { - throw new IllegalStateException("Did not expect convertStatements.size() to not equal 1"); - } - final ExpressionStatement convertExpressionStatement = (ExpressionStatement) convertStatements.getFirst(); - final BinaryExpression assignment = (BinaryExpression) convertExpressionStatement.getExpression(); - return (ClosureExpression) assignment.getRightExpression(); - } - - @Override - public GStringExpression createGStringExpression(GStringBodyTextNode gStringBodyTextNode) { - final var children = gStringBodyTextNode.getChildren(); - if (children.isEmpty()) { - throw new IllegalArgumentException("Cannot make a gStringOutStatement from zero GStringParts"); - } - - final String verbatimText = children.stream().map(node -> { - if (node instanceof JStringBodyTextNode jStringBodyTextNode) { - return jStringBodyTextNode.getContent(); - } else if (node.hasExtension(GStringNodeExtension.class)) { - final var gString = node.getExtension(GStringNodeExtension.class); - return switch (gString) { - case GStringPathExtension ignored -> gString.getAsValidEmbeddableCode(); - case GStringScriptletExtension ignored -> "${" + gString.getAsValidEmbeddableCode() + "}"; - }; - } else { - throw new IllegalArgumentException( - "Cannot get verbatim text when one of the given parts has " - + "neither a JStringNodeExtension nor a GStringNodeExtension" - ); - } - }).collect(Collectors.joining()); - - final List texts = new ArrayList<>(); - final List values = new ArrayList<>(); - final ListIterator iter = children.listIterator(); - - while (iter.hasNext()) { - final var prev = iter.previousIndex() > -1 ? children.get(iter.previousIndex()) : null; - final var current = iter.next(); - final var next = iter.nextIndex() < children.size() ? children.get(iter.nextIndex()) : null; - if (current instanceof JStringBodyTextNode jStringBodyTextNode) { - texts.add(this.handleText(jStringBodyTextNode, prev)); - } else { - switch (current.getExtension(GStringNodeExtension.class)) { - case GStringPathExtension path -> { - final var pathResult = this.handlePath(current, path, prev, next); - pathResult.before().ifPresent(texts::add); - values.add(pathResult.result()); - pathResult.after().ifPresent(texts::add); - } - case GStringScriptletExtension scriptlet -> { - checkPrevBeforeDollar(prev, current).ifPresent(texts::add); - values.add(this.handleScriptlet(scriptlet)); - checkNextAfterDollar(next).ifPresent(texts::add); - } - } - } - } - - if (!(texts.size() == values.size() || texts.size() == values.size() + 1)) { - throw new IllegalStateException( - "incorrect amount of texts vs. values: " + texts.size() + " " + values.size() - ); - } - - final var gString = new GStringExpression(verbatimText, texts, values); - this.positionSetter.setPosition(gString, gStringBodyTextNode); - return gString; - } - -} diff --git a/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/DefaultGroovyBodyNodeTranspiler.java b/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/DefaultGroovyBodyNodeTranspiler.java index 18f8843..d25bc6a 100644 --- a/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/DefaultGroovyBodyNodeTranspiler.java +++ b/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/DefaultGroovyBodyNodeTranspiler.java @@ -3,7 +3,6 @@ package groowt.view.component.web.transpile; import groowt.view.component.web.WebViewComponentBugError; import groowt.view.component.web.ast.node.*; import groowt.view.component.web.transpile.groovy.GroovyUtil; -import jakarta.inject.Inject; import org.codehaus.groovy.ast.expr.*; import org.codehaus.groovy.ast.stmt.BlockStatement; import org.codehaus.groovy.ast.stmt.ExpressionStatement; @@ -16,7 +15,6 @@ public class DefaultGroovyBodyNodeTranspiler implements GroovyBodyNodeTranspiler private final PositionSetter positionSetter; private final LeftShiftFactory leftShiftFactory; - @Inject public DefaultGroovyBodyNodeTranspiler(PositionSetter positionSetter, LeftShiftFactory leftShiftFactory) { this.positionSetter = positionSetter; this.leftShiftFactory = leftShiftFactory; @@ -58,7 +56,7 @@ public class DefaultGroovyBodyNodeTranspiler implements GroovyBodyNodeTranspiler ); callExpr = new MethodCallExpression(cl, "call", argsList); } - return this.leftShiftFactory.create(callExpr); + return this.leftShiftFactory.create(state, callExpr); } protected Statement handlePlainScriptlet(PlainScriptletNode plainScriptletNode, TranspilerState state) { @@ -76,7 +74,7 @@ public class DefaultGroovyBodyNodeTranspiler implements GroovyBodyNodeTranspiler return new ExpressionStatement(callExpr); } - protected Statement handleDollarScriptlet(DollarScriptletNode dollarScriptletNode) { + protected Statement handleDollarScriptlet(DollarScriptletNode dollarScriptletNode, TranspilerState state) { final ClosureExpression cl = this.convertToClosure(dollarScriptletNode, dollarScriptletNode.getGroovyCode()); final Expression toLeftShift; if (cl.getParameters() == null) { @@ -89,10 +87,10 @@ public class DefaultGroovyBodyNodeTranspiler implements GroovyBodyNodeTranspiler toLeftShift = cl; } } - return this.leftShiftFactory.create(toLeftShift); + return this.leftShiftFactory.create(state, toLeftShift); } - protected Statement handleDollarReference(DollarReferenceNode dollarReferenceNode) { + protected Statement handleDollarReference(DollarReferenceNode dollarReferenceNode, TranspilerState state) { VariableExpression root = null; PropertyExpression propertyExpr = null; for (final String part : dollarReferenceNode.getParts()) { @@ -107,10 +105,10 @@ public class DefaultGroovyBodyNodeTranspiler implements GroovyBodyNodeTranspiler final var positionVisitor = new PositionVisitor(this.positionSetter, dollarReferenceNode); if (propertyExpr != null) { propertyExpr.visit(positionVisitor); - return this.leftShiftFactory.create(propertyExpr); + return this.leftShiftFactory.create(state, propertyExpr); } else if (root != null) { root.visit(positionVisitor); - return this.leftShiftFactory.create(root); + return this.leftShiftFactory.create(state, root); } else { throw new WebViewComponentBugError("Did not expect root to be null."); } @@ -121,8 +119,8 @@ public class DefaultGroovyBodyNodeTranspiler implements GroovyBodyNodeTranspiler return switch (groovyBodyNode) { case EqualsScriptletNode equalsScriptletNode -> this.handleEqualsScriptlet(equalsScriptletNode, state); case PlainScriptletNode plainScriptletNode -> this.handlePlainScriptlet(plainScriptletNode, state); - case DollarScriptletNode dollarScriptletNode -> this.handleDollarScriptlet(dollarScriptletNode); - case DollarReferenceNode dollarReferenceNode -> this.handleDollarReference(dollarReferenceNode); + case DollarScriptletNode dollarScriptletNode -> this.handleDollarScriptlet(dollarScriptletNode, state); + case DollarReferenceNode dollarReferenceNode -> this.handleDollarReference(dollarReferenceNode, state); default -> throw new WebViewComponentBugError(new UnsupportedOperationException( "GroovyBodyNode of type " + groovyBodyNode.getClass().getName() + " is not supported." )); diff --git a/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/DefaultGroovyTranspiler.java b/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/DefaultGroovyTranspiler.java index 127158b..83a7ddd 100644 --- a/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/DefaultGroovyTranspiler.java +++ b/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/DefaultGroovyTranspiler.java @@ -4,14 +4,12 @@ import groovy.transform.Field; import groowt.view.component.compiler.ComponentTemplateCompileException; import groowt.view.component.compiler.ComponentTemplateCompileUnit; import groowt.view.component.compiler.ComponentTemplateCompilerConfiguration; -import groowt.view.component.web.WebViewComponentBugError; import groowt.view.component.web.ast.node.BodyNode; import groowt.view.component.web.ast.node.CompilationUnitNode; import groowt.view.component.web.ast.node.PreambleNode; import groowt.view.component.web.compiler.MultipleWebViewComponentCompileErrorsException; import groowt.view.component.web.compiler.WebViewComponentTemplateCompileException; import groowt.view.component.web.compiler.WebViewComponentTemplateCompileUnit; -import groowt.view.component.web.transpile.BodyTranspiler.AddOrAppendCallback; import groowt.view.component.web.transpile.groovy.GroovyUtil; import groowt.view.component.web.transpile.resolve.ClassLoaderComponentClassNodeResolver; import org.codehaus.groovy.ast.*; @@ -37,10 +35,9 @@ public class DefaultGroovyTranspiler implements GroovyTranspiler { private static final ClassNode FIELD_ANNOTATION = ClassHelper.make(Field.class); protected TranspilerConfiguration getConfiguration( - WebViewComponentTemplateCompileUnit compileUnit, - ClassLoader classLoader + ClassLoaderComponentClassNodeResolver classLoaderComponentClassNodeResolver ) { - return new DefaultTranspilerConfiguration(new ClassLoaderComponentClassNodeResolver(compileUnit, classLoader)); + return SimpleTranspilerConfiguration.withDefaults(classLoaderComponentClassNodeResolver); } protected void addAutomaticImports(WebViewComponentModuleNode moduleNode, TranspilerConfiguration configuration) { @@ -235,20 +232,7 @@ public class DefaultGroovyTranspiler implements GroovyTranspiler { TranspilerConfiguration transpilerConfiguration, TranspilerState state ) { - final var appendOrAddStatementFactory = transpilerConfiguration.getAppendOrAddStatementFactory(); - final AddOrAppendCallback callback = (source, expr) -> appendOrAddStatementFactory.addOrAppend( - source, - state, - action -> { - if (action == AppendOrAddStatementFactory.Action.ADD) { - throw new WebViewComponentBugError(new IllegalStateException( - "Should not be adding from document root, only appending!" - )); - } - return expr; - } - ); - return transpilerConfiguration.getBodyTranspiler().transpileBody(bodyNode, callback, state); + return transpilerConfiguration.getBodyTranspiler().transpileBody(bodyNode, state); } @Override @@ -258,10 +242,12 @@ public class DefaultGroovyTranspiler implements GroovyTranspiler { CompilationUnitNode compilationUnitNode, String templateClassSimpleName ) throws ComponentTemplateCompileException { - // transpilerConfiguration and positionSetter - final var transpilerConfiguration = this.getConfiguration( - compileUnit, compileUnit.getGroovyCompilationUnit().getClassLoader() + // resolver, transpilerConfiguration, and positionSetter + final ClassLoaderComponentClassNodeResolver resolver = new ClassLoaderComponentClassNodeResolver( + compileUnit, + compileUnit.getGroovyCompilationUnit().getClassLoader() ); + final var transpilerConfiguration = this.getConfiguration(resolver); final PositionSetter positionSetter = transpilerConfiguration.getPositionSetter(); // prepare sourceUnit @@ -280,6 +266,9 @@ public class DefaultGroovyTranspiler implements GroovyTranspiler { compileUnit, sourceUnit, transpilerConfiguration ); + // set resolver's moduleNode + resolver.setModuleNode(moduleNode); + // prepare mainClassNode final ClassNode mainClassNode = this.initMainClassNode(compileUnit, templateClassSimpleName, moduleNode); diff --git a/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/DefaultJStringTranspiler.java b/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/DefaultJStringTranspiler.java deleted file mode 100644 index f33a718..0000000 --- a/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/DefaultJStringTranspiler.java +++ /dev/null @@ -1,47 +0,0 @@ -package groowt.view.component.web.transpile; - -import groowt.view.component.web.ast.node.JStringBodyTextNode; -import groowt.view.component.web.ast.node.JStringValueNode; -import jakarta.inject.Inject; -import org.codehaus.groovy.ast.expr.ConstantExpression; - -import static org.apache.groovy.parser.antlr4.util.StringUtils.*; - -@Deprecated -public class DefaultJStringTranspiler implements JStringTranspiler { - - private final PositionSetter positionSetter; - - @Inject - public DefaultJStringTranspiler(PositionSetter positionSetter) { - this.positionSetter = positionSetter; - } - - @Override - public ConstantExpression createStringLiteral(JStringBodyTextNode jStringBodyTextNode) { - final var withoutCR = removeCR(jStringBodyTextNode.getContent()); - final var escaped = replaceEscapes(withoutCR, NONE_SLASHY); - final var expression = new ConstantExpression(escaped); - expression.setNodeMetaData("_IS_STRING", true); - this.positionSetter.setPosition(expression, jStringBodyTextNode); - return expression; - } - - @Override - public ConstantExpression createStringLiteral(JStringValueNode jStringValueNode) { - final var content = jStringValueNode.getContent(); - final var escaped = replaceEscapes(content, NONE_SLASHY); - final var expression = new ConstantExpression(escaped); - expression.setNodeMetaData("_IS_STRING", true); - this.positionSetter.setPosition(expression, jStringValueNode); - return expression; - } - - @Override - public ConstantExpression createEmptyStringLiteral() { - final var expression = new ConstantExpression(""); - expression.setNodeMetaData("_IS_STRING", true); - return expression; - } - -} diff --git a/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/DefaultLeftShiftFactory.java b/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/DefaultLeftShiftFactory.java new file mode 100644 index 0000000..ff1a811 --- /dev/null +++ b/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/DefaultLeftShiftFactory.java @@ -0,0 +1,28 @@ +package groowt.view.component.web.transpile; + +import org.codehaus.groovy.ast.expr.BinaryExpression; +import org.codehaus.groovy.ast.expr.Expression; +import org.codehaus.groovy.ast.stmt.ExpressionStatement; +import org.codehaus.groovy.ast.stmt.Statement; +import org.codehaus.groovy.syntax.Token; +import org.codehaus.groovy.syntax.Types; + +public class DefaultLeftShiftFactory implements LeftShiftFactory { + + @Override + public Statement create(TranspilerState state, Expression rightSide) { + final Expression left; + if (state.hasCurrentChildList()) { + left = state.getCurrentChildList(); + } else { + left = state.getWriter(); + } + final BinaryExpression leftShift = new BinaryExpression( + left, + new Token(Types.LEFT_SHIFT, "<<", -1, -1), + rightSide + ); + return new ExpressionStatement(leftShift); + } + +} diff --git a/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/DefaultTranspilerConfiguration.java b/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/DefaultTranspilerConfiguration.java deleted file mode 100644 index a72ace7..0000000 --- a/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/DefaultTranspilerConfiguration.java +++ /dev/null @@ -1,85 +0,0 @@ -package groowt.view.component.web.transpile; - -import groovy.lang.Tuple3; -import groowt.util.fp.provider.DefaultProvider; -import groowt.view.component.web.transpile.resolve.ComponentClassNodeResolver; -import org.codehaus.groovy.ast.ClassNode; - -import java.util.Map; -import java.util.Set; - -import static groowt.view.component.web.transpile.TranspilerUtil.*; - -public class DefaultTranspilerConfiguration implements TranspilerConfiguration { - - private final PositionSetter positionSetter; - private final AppendOrAddStatementFactory appendOrAddStatementFactory = new DefaultAppendOrAddStatementFactory(); - private final BodyTranspiler bodyTranspiler; - private final ValueNodeTranspiler valueNodeTranspiler; - - public DefaultTranspilerConfiguration(ComponentClassNodeResolver classNodeResolver) { - this.positionSetter = new SimplePositionSetter(); - final var jStringTranspiler = new DefaultJStringTranspiler(this.positionSetter); - final var gStringTranspiler = new DefaultGStringTranspiler(this.positionSetter, jStringTranspiler); - final var componentTranspiler = new DefaultComponentTranspiler( - DefaultProvider.of(this.appendOrAddStatementFactory), - DefaultProvider.of(classNodeResolver), - DefaultProvider.ofLazy(ValueNodeTranspiler.class, this::getValueNodeTranspiler), - DefaultProvider.ofLazy(BodyTranspiler.class, this::getBodyTranspiler) - ); - this.valueNodeTranspiler = new DefaultValueNodeTranspiler(componentTranspiler); - this.bodyTranspiler = new DefaultBodyTranspiler(componentTranspiler, null); // TODO - } - - @Override - public PositionSetter getPositionSetter() { - return this.positionSetter; - } - - @Override - public BodyTranspiler getBodyTranspiler() { - return this.bodyTranspiler; - } - - @Override - public AppendOrAddStatementFactory getAppendOrAddStatementFactory() { - return this.appendOrAddStatementFactory; - } - - protected ValueNodeTranspiler getValueNodeTranspiler() { - return this.valueNodeTranspiler; - } - - @Override - public Map getImports() { - return Map.of( - COMPONENT_TEMPLATE.getNameWithoutPackage(), COMPONENT_TEMPLATE, - COMPONENT_CONTEXT_TYPE.getNameWithoutPackage(), COMPONENT_CONTEXT_TYPE - ); - } - - @Override - public Set getStarImports() { - return Set.of( - GROOWT_VIEW_COMPONENT_WEB + ".lib", - "groowt.view.component.runtime", - GROOWT_VIEW_COMPONENT_WEB + ".runtime" - ); - } - - @Override - public Set> getStaticImports() { - return Set.of(); - } - - @Override - public Map getStaticStarImports() { - return Map.of(); - } - - @Override - public ClassNode getRenderContextImplementation() { - return DEFAULT_RENDER_CONTEXT_IMPLEMENTATION; - } - -} diff --git a/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/DefaultValueNodeTranspiler.java b/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/DefaultValueNodeTranspiler.java index 25b346f..a1fedf4 100644 --- a/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/DefaultValueNodeTranspiler.java +++ b/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/DefaultValueNodeTranspiler.java @@ -1,6 +1,5 @@ package groowt.view.component.web.transpile; -import groowt.view.component.web.WebViewComponentBugError; import groowt.view.component.web.ast.node.*; import groowt.view.component.web.transpile.groovy.GroovyUtil; import groowt.view.component.web.transpile.groovy.GroovyUtil.ConvertResult; @@ -12,49 +11,39 @@ import org.codehaus.groovy.ast.stmt.ExpressionStatement; import org.codehaus.groovy.ast.stmt.Statement; import org.jetbrains.annotations.Nullable; -import java.util.List; - import static groowt.view.component.web.transpile.TranspilerUtil.getStringLiteral; -// TODO: set positions public class DefaultValueNodeTranspiler implements ValueNodeTranspiler { private final ComponentTranspiler componentTranspiler; + private final PositionSetter positionSetter; - public DefaultValueNodeTranspiler(ComponentTranspiler componentTranspiler) { + public DefaultValueNodeTranspiler(ComponentTranspiler componentTranspiler, PositionSetter positionSetter) { this.componentTranspiler = componentTranspiler; + this.positionSetter = positionSetter; } - // TODO: positions protected Expression handleClosureNode(ClosureValueNode closureValueNode) { final var rawCode = closureValueNode.getGroovyCode().getAsValidGroovyCode(); final ClosureExpression convertedClosure = GroovyUtil.getClosure(rawCode); + + final PositionVisitor positionVisitor = new PositionVisitor( + this.positionSetter.withOffset(0, -10), + closureValueNode + ); + convertedClosure.visit(positionVisitor); + final Statement closureCode = convertedClosure.getCode(); - if (closureCode instanceof BlockStatement blockStatement) { - final List statements = blockStatement.getStatements(); - if (statements.isEmpty()) { - throw new WebViewComponentBugError(new IllegalArgumentException( - "Did not expect ClosureValueNode to produce no statements." - )); - } else if (statements.size() == 1) { - final Statement statement = statements.getFirst(); - if (statement instanceof ExpressionStatement expressionStatement) { - final Expression expression = expressionStatement.getExpression(); - return switch (expression) { - case ConstantExpression ignored -> expression; - case VariableExpression ignored -> expression; - case PropertyExpression ignored -> expression; - default -> convertedClosure; - }; - } else { - throw new IllegalArgumentException("A component closure value must produce a value."); - } - } else { - return convertedClosure; - } - } else { - return convertedClosure; + if (closureCode instanceof ExpressionStatement expressionStatement) { + final Expression expression = expressionStatement.getExpression(); + return switch (expression) { + case ConstantExpression ignored -> expression; + case VariableExpression ignored -> expression; + case PropertyExpression ignored -> expression; + default -> convertedClosure; + }; } + return convertedClosure; } private Expression gStringValue(GStringValueNode gStringValueNode) { @@ -65,16 +54,27 @@ public class DefaultValueNodeTranspiler implements ValueNodeTranspiler { throw new IllegalStateException("block statement is null or empty"); } final ExpressionStatement exprStmt = (ExpressionStatement) blockStatement.getStatements().getFirst(); - // TODO: set pos + + final PositionVisitor positionVisitor = new PositionVisitor( + this.positionSetter.withOffset(0, -1), + gStringValueNode + ); + exprStmt.visit(positionVisitor); + return exprStmt.getExpression(); } private ConstantExpression jStringValue(JStringValueNode jStringValueNode) { - return getStringLiteral(jStringValueNode.getContent()); // TODO: set pos + final ConstantExpression literal = getStringLiteral(jStringValueNode.getContent()); + this.positionSetter.setPosition(literal, jStringValueNode); + return literal; } private ClosureExpression emptyClosureValue(EmptyClosureValueNode emptyClosureValueNode) { - return new ClosureExpression(Parameter.EMPTY_ARRAY, EmptyStatement.INSTANCE); // TODO: set pos + final ClosureExpression cl = new ClosureExpression(Parameter.EMPTY_ARRAY, EmptyStatement.INSTANCE); + final PositionVisitor positionVisitor = new PositionVisitor(this.positionSetter, emptyClosureValueNode); + cl.visit(positionVisitor); + return cl; } private ClosureExpression componentValue(ComponentValueNode componentValueNode, TranspilerState state) { @@ -84,7 +84,7 @@ public class DefaultValueNodeTranspiler implements ValueNodeTranspiler { componentValueNode.getComponentNode(), state ), state.getCurrentScope()) - ); // TODO: set pos + ); } @Override diff --git a/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/GStringTranspiler.java b/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/GStringTranspiler.java deleted file mode 100644 index fbdcb1e..0000000 --- a/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/GStringTranspiler.java +++ /dev/null @@ -1,9 +0,0 @@ -package groowt.view.component.web.transpile; - -import groowt.view.component.web.ast.node.GStringBodyTextNode; -import org.codehaus.groovy.ast.expr.GStringExpression; - -@Deprecated -public interface GStringTranspiler { - GStringExpression createGStringExpression(GStringBodyTextNode parent); -} diff --git a/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/JStringTranspiler.java b/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/JStringTranspiler.java deleted file mode 100644 index 41de8d7..0000000 --- a/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/JStringTranspiler.java +++ /dev/null @@ -1,12 +0,0 @@ -package groowt.view.component.web.transpile; - -import groowt.view.component.web.ast.node.JStringBodyTextNode; -import groowt.view.component.web.ast.node.JStringValueNode; -import org.codehaus.groovy.ast.expr.ConstantExpression; - -@Deprecated -public interface JStringTranspiler { - ConstantExpression createStringLiteral(JStringBodyTextNode bodyTextNode); - ConstantExpression createStringLiteral(JStringValueNode jStringValueNode); - ConstantExpression createEmptyStringLiteral(); -} diff --git a/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/LeftShiftFactory.java b/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/LeftShiftFactory.java index 3b75e57..c72731c 100644 --- a/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/LeftShiftFactory.java +++ b/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/LeftShiftFactory.java @@ -4,5 +4,5 @@ import org.codehaus.groovy.ast.expr.Expression; import org.codehaus.groovy.ast.stmt.Statement; public interface LeftShiftFactory { - Statement create(Expression rightSide); + Statement create(TranspilerState state, Expression rightSide); } diff --git a/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/SimpleTranspilerConfiguration.java b/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/SimpleTranspilerConfiguration.java new file mode 100644 index 0000000..20457ad --- /dev/null +++ b/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/SimpleTranspilerConfiguration.java @@ -0,0 +1,150 @@ +package groowt.view.component.web.transpile; + +import groovy.lang.Tuple3; +import groowt.view.component.web.transpile.resolve.ComponentClassNodeResolver; +import org.codehaus.groovy.ast.ClassNode; + +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +import static groowt.view.component.web.transpile.TranspilerUtil.*; + +public class SimpleTranspilerConfiguration implements TranspilerConfiguration { + + public static TranspilerConfiguration withDefaults(ComponentClassNodeResolver componentClassNodeResolver) { + final var c = new SimpleTranspilerConfiguration(); + c.setComponentClassNodeResolver(componentClassNodeResolver); + + final var ct = new DefaultComponentTranspiler(); + final PositionSetter ps = new SimplePositionSetter(); + final LeftShiftFactory lsf = new DefaultLeftShiftFactory(); + final var gbnt = new DefaultGroovyBodyNodeTranspiler(ps, lsf); + final var btt = new DefaultBodyTextTranspiler(gbnt, ps, lsf, true); + final var bt = new DefaultBodyTranspiler(ct, btt); + final var vnt = new DefaultValueNodeTranspiler(ct, ps); + + ct.setLeftShiftFactory(lsf); + ct.setBodyTranspiler(bt); + ct.setValueNodeTranspiler(vnt); + ct.setComponentClassNodeResolver(componentClassNodeResolver); + + c.setComponentTranspiler(ct); + c.setPositionSetter(ps); + c.setLeftShiftFactory(lsf); + c.setGroovyBodyNodeTranspiler(gbnt); + c.setBodyTextTranspiler(btt); + c.setBodyTranspiler(bt); + c.setValueNodeTranspiler(vnt); + + return c; + } + + private ComponentClassNodeResolver componentClassNodeResolver; + private ComponentTranspiler componentTranspiler; + private PositionSetter positionSetter; + private LeftShiftFactory leftShiftFactory; + private GroovyBodyNodeTranspiler groovyBodyNodeTranspiler; + private BodyTextTranspiler bodyTextTranspiler; + private BodyTranspiler bodyTranspiler; + private ValueNodeTranspiler valueNodeTranspiler; + + public ComponentClassNodeResolver getComponentClassNodeResolver() { + return Objects.requireNonNull(this.componentClassNodeResolver); + } + + public void setComponentClassNodeResolver(ComponentClassNodeResolver componentClassNodeResolver) { + this.componentClassNodeResolver = componentClassNodeResolver; + } + + public ComponentTranspiler getComponentTranspiler() { + return Objects.requireNonNull(this.componentTranspiler); + } + + public void setComponentTranspiler(ComponentTranspiler componentTranspiler) { + this.componentTranspiler = componentTranspiler; + } + + @Override + public PositionSetter getPositionSetter() { + return Objects.requireNonNull(this.positionSetter); + } + + public void setPositionSetter(PositionSetter positionSetter) { + this.positionSetter = positionSetter; + } + + public LeftShiftFactory getLeftShiftFactory() { + return this.leftShiftFactory; + } + + public void setLeftShiftFactory(LeftShiftFactory leftShiftFactory) { + this.leftShiftFactory = leftShiftFactory; + } + + public GroovyBodyNodeTranspiler getGroovyBodyNodeTranspiler() { + return this.groovyBodyNodeTranspiler; + } + + public void setGroovyBodyNodeTranspiler(GroovyBodyNodeTranspiler groovyBodyNodeTranspiler) { + this.groovyBodyNodeTranspiler = groovyBodyNodeTranspiler; + } + + public BodyTextTranspiler getBodyTextTranspiler() { + return this.bodyTextTranspiler; + } + + public void setBodyTextTranspiler(BodyTextTranspiler bodyTextTranspiler) { + this.bodyTextTranspiler = bodyTextTranspiler; + } + + @Override + public BodyTranspiler getBodyTranspiler() { + return Objects.requireNonNull(this.bodyTranspiler); + } + + public void setBodyTranspiler(BodyTranspiler bodyTranspiler) { + this.bodyTranspiler = bodyTranspiler; + } + + public ValueNodeTranspiler getValueNodeTranspiler() { + return Objects.requireNonNull(this.valueNodeTranspiler); + } + + public void setValueNodeTranspiler(ValueNodeTranspiler valueNodeTranspiler) { + this.valueNodeTranspiler = valueNodeTranspiler; + } + + @Override + public Map getImports() { + return Map.of( + COMPONENT_TEMPLATE.getNameWithoutPackage(), COMPONENT_TEMPLATE, + COMPONENT_CONTEXT_TYPE.getNameWithoutPackage(), COMPONENT_CONTEXT_TYPE + ); + } + + @Override + public Set getStarImports() { + return Set.of( + GROOWT_VIEW_COMPONENT_WEB + ".lib", + "groowt.view.component.runtime", + GROOWT_VIEW_COMPONENT_WEB + ".runtime" + ); + } + + @Override + public Set> getStaticImports() { + return Set.of(); + } + + @Override + public Map getStaticStarImports() { + return Map.of(); + } + + @Override + public ClassNode getRenderContextImplementation() { + return DEFAULT_RENDER_CONTEXT_IMPLEMENTATION; + } + +} diff --git a/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/TranspilerConfiguration.java b/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/TranspilerConfiguration.java index dc09cb6..81f6999 100644 --- a/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/TranspilerConfiguration.java +++ b/web-view-components-compiler/src/main/java/groowt/view/component/web/transpile/TranspilerConfiguration.java @@ -9,7 +9,6 @@ import java.util.Set; public interface TranspilerConfiguration { PositionSetter getPositionSetter(); BodyTranspiler getBodyTranspiler(); - AppendOrAddStatementFactory getAppendOrAddStatementFactory(); Map getImports(); Set getStarImports(); Set> getStaticImports(); diff --git a/web-view-components-compiler/src/test/groovy/groowt/view/component/web/ast/DefaultAstBuilderVisitorTests.groovy b/web-view-components-compiler/src/test/groovy/groowt/view/component/web/ast/DefaultAstBuilderVisitorTests.groovy index f65f7ee..6874d35 100644 --- a/web-view-components-compiler/src/test/groovy/groowt/view/component/web/ast/DefaultAstBuilderVisitorTests.groovy +++ b/web-view-components-compiler/src/test/groovy/groowt/view/component/web/ast/DefaultAstBuilderVisitorTests.groovy @@ -6,13 +6,12 @@ import groowt.view.component.web.antlr.TokenList import groowt.view.component.web.antlr.WebViewComponentsLexer import groowt.view.component.web.antlr.WebViewComponentsParser import groowt.view.component.web.antlr.WebViewComponentsTokenStream -import groowt.view.component.web.ast.node.* +import groowt.view.component.web.ast.node.Node import org.antlr.v4.runtime.CharStreams -import org.junit.jupiter.api.Disabled -import org.junit.jupiter.api.Test import static groowt.view.component.web.antlr.WebViewComponentsParser.CompilationUnitContext -import static org.junit.jupiter.api.Assertions.* +import static org.junit.jupiter.api.Assertions.assertInstanceOf +import static org.junit.jupiter.api.Assertions.assertNotNull class DefaultAstBuilderVisitorTests { @@ -52,30 +51,4 @@ class DefaultAstBuilderVisitorTests { return new Tuple2<>(cu.accept(visitor), tokenList) } - @Test - @Disabled('Move to file tests.') - void helloTarget() { - def (node, tokenList) = this.doBuild('Hello, $target!') - assertNodeWith(CompilationUnitNode, node) { - assertNull(preambleNode) - bodyNode.with { - assertEquals(1, childrenSize) - assertNodeWith(GStringBodyTextNode, children.first) { - assertEquals(3, childrenSize) - assertNodeWith(JStringBodyTextNode, it[0]) { - assertEquals('Hello, ', it.getText(tokenList)) - assertEquals('Hello, ', it.content) - } - assertNodeWith(DollarReferenceNode, it[1]) { - assertEquals('$target', it.getText(tokenList)) - assertEquals('$target', it.GStringPath.asValidEmbeddableCode) - } - assertNodeWith(JStringBodyTextNode, it[2]) { - assertEquals('!', it.content) - } - } - } - } - } - } diff --git a/web-view-components-compiler/src/test/java/groowt/view/component/web/transpiler/DefaultBodyTranspilerTests.java b/web-view-components-compiler/src/test/java/groowt/view/component/web/transpiler/DefaultBodyTranspilerTests.java index 647bea4..b950208 100644 --- a/web-view-components-compiler/src/test/java/groowt/view/component/web/transpiler/DefaultBodyTranspilerTests.java +++ b/web-view-components-compiler/src/test/java/groowt/view/component/web/transpiler/DefaultBodyTranspilerTests.java @@ -1,7 +1,7 @@ package groowt.view.component.web.transpiler; import groowt.view.component.web.compiler.WebViewComponentTemplateCompileUnit; -import groowt.view.component.web.transpile.DefaultTranspilerConfiguration; +import groowt.view.component.web.transpile.SimpleTranspilerConfiguration; import groowt.view.component.web.transpile.TranspilerConfiguration; import groowt.view.component.web.transpile.resolve.CachingComponentClassNodeResolver; import org.codehaus.groovy.ast.ModuleNode; @@ -13,9 +13,7 @@ public class DefaultBodyTranspilerTests extends BodyTranspilerTests { WebViewComponentTemplateCompileUnit compileUnit, ModuleNode moduleNode ) { - return new DefaultTranspilerConfiguration( - new CachingComponentClassNodeResolver(compileUnit) - ); + return SimpleTranspilerConfiguration.withDefaults(new CachingComponentClassNodeResolver(compileUnit)); } } diff --git a/web-view-components-compiler/src/test/java/groowt/view/component/web/transpiler/DefaultGStringTranspilerTests.java b/web-view-components-compiler/src/test/java/groowt/view/component/web/transpiler/DefaultGStringTranspilerTests.java deleted file mode 100644 index c719454..0000000 --- a/web-view-components-compiler/src/test/java/groowt/view/component/web/transpiler/DefaultGStringTranspilerTests.java +++ /dev/null @@ -1,16 +0,0 @@ -package groowt.view.component.web.transpiler; - -import groowt.view.component.web.transpile.DefaultGStringTranspiler; -import groowt.view.component.web.transpile.DefaultJStringTranspiler; -import groowt.view.component.web.transpile.GStringTranspiler; -import groowt.view.component.web.transpile.SimplePositionSetter; - -public class DefaultGStringTranspilerTests extends GStringTranspilerTests { - - @Override - protected GStringTranspiler getGStringTranspiler() { - final var positionSetter = new SimplePositionSetter(); - return new DefaultGStringTranspiler(positionSetter, new DefaultJStringTranspiler(positionSetter)); - } - -} diff --git a/web-view-components-compiler/src/testFixtures/java/groowt/view/component/web/ast/NodeFactoryTests.java b/web-view-components-compiler/src/testFixtures/java/groowt/view/component/web/ast/NodeFactoryTests.java index ac0c1d4..94547e6 100644 --- a/web-view-components-compiler/src/testFixtures/java/groowt/view/component/web/ast/NodeFactoryTests.java +++ b/web-view-components-compiler/src/testFixtures/java/groowt/view/component/web/ast/NodeFactoryTests.java @@ -223,7 +223,7 @@ public abstract class NodeFactoryTests { @Test public void plainScriptletNode() { - assertNotNull(this.nodeFactory.plainScriptletNode(this.getTokenRange(), 0)); + assertNotNull(this.nodeFactory.plainScriptletNode(this.getTokenRange(), "")); } @Test @@ -233,7 +233,7 @@ public abstract class NodeFactoryTests { @Test public void dollarReferenceNode() { - assertNotNull(this.nodeFactory.dollarReferenceNode(this.getTokenRange(), 0)); + assertNotNull(this.nodeFactory.dollarReferenceNode(this.getTokenRange(), List.of("test"))); } } diff --git a/web-view-components-compiler/src/testFixtures/java/groowt/view/component/web/transpiler/BodyTranspilerTests.java b/web-view-components-compiler/src/testFixtures/java/groowt/view/component/web/transpiler/BodyTranspilerTests.java index 4c33682..47132a0 100644 --- a/web-view-components-compiler/src/testFixtures/java/groowt/view/component/web/transpiler/BodyTranspilerTests.java +++ b/web-view-components-compiler/src/testFixtures/java/groowt/view/component/web/transpiler/BodyTranspilerTests.java @@ -8,13 +8,7 @@ import groowt.view.component.web.ast.node.BodyNode; import groowt.view.component.web.compiler.WebViewComponentTemplateCompileUnit; import groowt.view.component.web.transpile.BodyTranspiler; import groowt.view.component.web.transpile.TranspilerConfiguration; -import groowt.view.component.web.transpile.TranspilerState; import org.codehaus.groovy.ast.ModuleNode; -import org.codehaus.groovy.ast.expr.ConstantExpression; -import org.codehaus.groovy.ast.expr.MethodCallExpression; -import org.codehaus.groovy.ast.expr.TupleExpression; -import org.codehaus.groovy.ast.stmt.BlockStatement; -import org.codehaus.groovy.ast.stmt.ExpressionStatement; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; @@ -30,9 +24,7 @@ public abstract class BodyTranspilerTests { ModuleNode moduleNode ); - protected record BuildResult(BodyNode bodyNode, TokenList tokenList) { - - } + protected record BuildResult(BodyNode bodyNode, TokenList tokenList) {} protected BuildResult build(String source) { final var parseResult = ParserUtil.parseCompilationUnit(source); @@ -58,47 +50,4 @@ public abstract class BodyTranspilerTests { }); } - @Test - public void simpleGStringOutStatement( - @Mock WebViewComponentTemplateCompileUnit compileUnit, - @Mock ModuleNode moduleNode - ) { - final var source = "Hello, $target!"; - final var buildResult = this.build(source); - final var configuration = this.getConfiguration(compileUnit, moduleNode); - final var transpiler = this.getBodyTranspiler(configuration); - final var state = TranspilerState.withDefaultRootScope(); - final var addOrAppend = configuration.getAppendOrAddStatementFactory(); - final BlockStatement blockStatement = transpiler.transpileBody( - buildResult.bodyNode(), - (node, expression) -> addOrAppend.addOrAppend(node, state, ignored -> expression), - TranspilerState.withDefaultRootScope() - ); - assertEquals(1, blockStatement.getStatements().size()); - } - - @Test - public void simpleJStringOutStatement( - @Mock WebViewComponentTemplateCompileUnit compileUnit, - @Mock ModuleNode moduleNode - ) { - final var source = "Hello, World!"; - final var buildResult = this.build(source); - final var configuration = this.getConfiguration(compileUnit, moduleNode); - final var transpiler = this.getBodyTranspiler(configuration); - final var state = TranspilerState.withDefaultRootScope(); - final var addOrAppend = configuration.getAppendOrAddStatementFactory(); - final BlockStatement blockStatement = transpiler.transpileBody( - buildResult.bodyNode(), - (node, expression) -> addOrAppend.addOrAppend(node, state, ignored -> expression), - TranspilerState.withDefaultRootScope() - ); - assertEquals(1, blockStatement.getStatements().size()); - final var s0 = (ExpressionStatement) blockStatement.getStatements().getFirst(); - final var binaryExpression = (MethodCallExpression) s0.getExpression(); - final var args = (TupleExpression) binaryExpression.getArguments(); - final var first = (ConstantExpression) args.getExpression(0); - assertEquals("Hello, World!", first.getValue()); - } - } diff --git a/web-view-components-compiler/src/testFixtures/java/groowt/view/component/web/transpiler/GStringTranspilerTests.java b/web-view-components-compiler/src/testFixtures/java/groowt/view/component/web/transpiler/GStringTranspilerTests.java deleted file mode 100644 index da156ef..0000000 --- a/web-view-components-compiler/src/testFixtures/java/groowt/view/component/web/transpiler/GStringTranspilerTests.java +++ /dev/null @@ -1,82 +0,0 @@ -package groowt.view.component.web.transpiler; - -import groowt.view.component.web.antlr.ParserUtil; -import groowt.view.component.web.antlr.TokenList; -import groowt.view.component.web.ast.DefaultAstBuilder; -import groowt.view.component.web.ast.DefaultNodeFactory; -import groowt.view.component.web.ast.node.BodyNode; -import groowt.view.component.web.ast.node.GStringBodyTextNode; -import groowt.view.component.web.transpile.GStringTranspiler; -import org.codehaus.groovy.ast.expr.ClosureExpression; -import org.codehaus.groovy.ast.expr.GStringExpression; -import org.codehaus.groovy.ast.expr.VariableExpression; -import org.junit.jupiter.api.Test; - -import java.util.Objects; -import java.util.function.Consumer; - -import static org.junit.jupiter.api.Assertions.*; - -public abstract class GStringTranspilerTests { - - protected abstract GStringTranspiler getGStringTranspiler(); - - @Test - public void smokeScreen() { - assertDoesNotThrow(() -> { - getGStringTranspiler(); - }); - } - - protected BodyNode getBodyNode(String source) { - final var parseResult = ParserUtil.parseCompilationUnit(source); - final var tokenList = new TokenList(parseResult.getTokenStream()); - final var nodeFactory = new DefaultNodeFactory(tokenList); - final var astBuilder = new DefaultAstBuilder(nodeFactory); - final var cuNode = astBuilder.buildCompilationUnit(parseResult.getCompilationUnitContext()); - return Objects.requireNonNull(cuNode.getBodyNode()); - } - - protected void doTest(String source, Consumer further) { - final var gStringBodyTextNode = this.getBodyNode(source).getAt(0, GStringBodyTextNode.class); - final var transpiler = this.getGStringTranspiler(); - final GStringExpression gStringExpression = transpiler.createGStringExpression(gStringBodyTextNode); - assertEquals(source, gStringExpression.getText()); - further.accept(gStringExpression); - } - - @Test - public void gStringExpressionWithDollarReference() { - this.doTest("Hello, $target!", gStringExpression -> { - assertEquals(2, gStringExpression.getStrings().size()); - assertEquals(1, gStringExpression.getValues().size()); - }); - } - - @Test - public void multiplePathValues() { - this.doTest("$greeting, $target!", gStringExpression -> { - assertEquals(3, gStringExpression.getStrings().size()); - assertEquals(2, gStringExpression.getValues().size()); - final var firstValue = gStringExpression.getValue(0); - assertInstanceOf(VariableExpression.class, firstValue); - assertEquals("greeting", firstValue.getText()); - final var secondValue = gStringExpression.getValue(1); - assertInstanceOf(VariableExpression.class, secondValue); - assertEquals("target", secondValue.getText()); - }); - } - - @Test - public void pathAndClosure() { - this.doTest("$greeting, ${consume(out)}!", gStringExpression -> { - assertEquals(3, gStringExpression.getStrings().size()); - assertEquals(2, gStringExpression.getValues().size()); - final var firstValue = gStringExpression.getValue(0); - assertInstanceOf(VariableExpression.class, firstValue); - assertEquals("greeting", firstValue.getText()); - assertInstanceOf(ClosureExpression.class, gStringExpression.getValue(1)); - }); - } - -}