Transpiler refactoring finished.
This commit is contained in:
parent
2bac0f55dc
commit
e112d81ea8
@ -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<String> 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
|
||||
|
@ -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<String> parts) {
|
||||
return this.objectFactory.get(DollarReferenceNode.class, tokenRange, parts);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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<String> parts);
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -38,7 +38,7 @@ public class ClosureValueNode extends AbstractLeafNode implements ValueNode {
|
||||
}
|
||||
|
||||
protected String toValidGroovyCode(List<Token> 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() {
|
||||
|
@ -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<? extends Node> checkChildren(List<? extends Node> 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<? extends Node> children
|
||||
) {
|
||||
super(tokenRange, extensionContainer, checkChildren(children));
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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<Action, Expression> getRightSide);
|
||||
|
||||
default Statement addOrAppend(BodyChildNode sourceNode, TranspilerState state, Expression rightSide) {
|
||||
return this.addOrAppend(sourceNode, state, ignored -> rightSide);
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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<ConstantExpression, ConstantExpression> 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<Action, Expression> getRightSide
|
||||
) {
|
||||
if (state.hasCurrentChildList()) {
|
||||
return this.addOnly(bodyChildNode, state, getRightSide.apply(Action.ADD));
|
||||
} else {
|
||||
return this.appendOnly(bodyChildNode, state, getRightSide.apply(Action.APPEND));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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<Statement> handleHtmlCommentChild(HtmlCommentChild child, TranspilerState state) {
|
||||
@ -67,23 +67,23 @@ public class DefaultBodyTextTranspiler implements BodyTextTranspiler {
|
||||
final List<Statement> 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));
|
||||
|
@ -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()) {
|
||||
|
@ -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<AppendOrAddStatementFactory> appendOrAddStatementFactoryProvider;
|
||||
private final Provider<ComponentClassNodeResolver> componentClassNodeResolverProvider;
|
||||
private final Provider<ValueNodeTranspiler> valueNodeTranspilerProvider;
|
||||
private final Provider<BodyTranspiler> bodyTranspilerProvider;
|
||||
private LeftShiftFactory leftShiftFactory;
|
||||
private ValueNodeTranspiler valueNodeTranspiler;
|
||||
private BodyTranspiler bodyTranspiler;
|
||||
private ComponentClassNodeResolver componentClassNodeResolver;
|
||||
|
||||
public DefaultComponentTranspiler(
|
||||
Provider<AppendOrAddStatementFactory> appendOrAddStatementFactoryProvider,
|
||||
Provider<ComponentClassNodeResolver> componentClassNodeResolverProvider,
|
||||
Provider<ValueNodeTranspiler> valueNodeTranspilerProvider,
|
||||
Provider<BodyTranspiler> 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<Statement> 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<Statement> 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."
|
||||
|
@ -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<ConstantExpression> 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<ConstantExpression> 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<ConstantExpression> before,
|
||||
Option<ConstantExpression> after
|
||||
) {}
|
||||
|
||||
protected PathResult handlePath(Node current, GStringPathExtension path, @Nullable Node prev, @Nullable Node next) {
|
||||
final List<Token> groowtTokens = path.getRawTokens();
|
||||
|
||||
VariableExpression begin = null;
|
||||
PropertyExpression propertyExpression = null;
|
||||
|
||||
for (final Token groowtToken : groowtTokens) {
|
||||
if (groowtToken instanceof MergedGroovyCodeToken groovyCodeToken) {
|
||||
final Iterable<Token> 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<Statement> 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<ConstantExpression> texts = new ArrayList<>();
|
||||
final List<Expression> values = new ArrayList<>();
|
||||
final ListIterator<Node> 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;
|
||||
}
|
||||
|
||||
}
|
@ -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."
|
||||
));
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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<String, ClassNode> getImports() {
|
||||
return Map.of(
|
||||
COMPONENT_TEMPLATE.getNameWithoutPackage(), COMPONENT_TEMPLATE,
|
||||
COMPONENT_CONTEXT_TYPE.getNameWithoutPackage(), COMPONENT_CONTEXT_TYPE
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getStarImports() {
|
||||
return Set.of(
|
||||
GROOWT_VIEW_COMPONENT_WEB + ".lib",
|
||||
"groowt.view.component.runtime",
|
||||
GROOWT_VIEW_COMPONENT_WEB + ".runtime"
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Tuple3<ClassNode, String, String>> getStaticImports() {
|
||||
return Set.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, ClassNode> getStaticStarImports() {
|
||||
return Map.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassNode getRenderContextImplementation() {
|
||||
return DEFAULT_RENDER_CONTEXT_IMPLEMENTATION;
|
||||
}
|
||||
|
||||
}
|
@ -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<Statement> 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
|
||||
|
@ -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);
|
||||
}
|
@ -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();
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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<String, ClassNode> getImports() {
|
||||
return Map.of(
|
||||
COMPONENT_TEMPLATE.getNameWithoutPackage(), COMPONENT_TEMPLATE,
|
||||
COMPONENT_CONTEXT_TYPE.getNameWithoutPackage(), COMPONENT_CONTEXT_TYPE
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getStarImports() {
|
||||
return Set.of(
|
||||
GROOWT_VIEW_COMPONENT_WEB + ".lib",
|
||||
"groowt.view.component.runtime",
|
||||
GROOWT_VIEW_COMPONENT_WEB + ".runtime"
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Tuple3<ClassNode, String, String>> getStaticImports() {
|
||||
return Set.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, ClassNode> getStaticStarImports() {
|
||||
return Map.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassNode getRenderContextImplementation() {
|
||||
return DEFAULT_RENDER_CONTEXT_IMPLEMENTATION;
|
||||
}
|
||||
|
||||
}
|
@ -9,7 +9,6 @@ import java.util.Set;
|
||||
public interface TranspilerConfiguration {
|
||||
PositionSetter getPositionSetter();
|
||||
BodyTranspiler getBodyTranspiler();
|
||||
AppendOrAddStatementFactory getAppendOrAddStatementFactory();
|
||||
Map<String, ClassNode> getImports();
|
||||
Set<String> getStarImports();
|
||||
Set<Tuple3<ClassNode, String, String>> getStaticImports();
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
@ -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")));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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<GStringExpression> 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));
|
||||
});
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user