Groovyc can now accept .wvc files.
This commit is contained in:
parent
9212d128c3
commit
63720693a3
@ -23,14 +23,14 @@ public class ComponentTemplateCompileException extends Exception {
|
|||||||
@Override
|
@Override
|
||||||
public String getMessage() {
|
public String getMessage() {
|
||||||
final var sb = new StringBuilder("Error in ").append(compileUnit.getSource().getDescription());
|
final var sb = new StringBuilder("Error in ").append(compileUnit.getSource().getDescription());
|
||||||
final @Nullable String position = this.getPosition();
|
final @Nullable String position = this.formatPosition();
|
||||||
if (position != null) {
|
if (position != null) {
|
||||||
sb.append(" at ").append(position);
|
sb.append(" at ").append(position);
|
||||||
}
|
}
|
||||||
return sb.append(": ").append(super.getMessage()).toString();
|
return sb.append(": ").append(super.getMessage()).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected @Nullable String getPosition() {
|
protected @Nullable String formatPosition() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,6 +133,16 @@ tasks.register('toolsJar', Jar) {
|
|||||||
dependsOn tasks.named('jar')
|
dependsOn tasks.named('jar')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks.register('uberJar', Jar) {
|
||||||
|
group = 'build'
|
||||||
|
archiveBaseName = 'web-views-uber'
|
||||||
|
from sourceSets.main.output
|
||||||
|
from sourceSets.main.runtimeClasspath.filter(File.&exists).collect {
|
||||||
|
it.isDirectory() ? it : zipTree(it)
|
||||||
|
}
|
||||||
|
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||||
|
}
|
||||||
|
|
||||||
@NullCheck
|
@NullCheck
|
||||||
class ToolSpec {
|
class ToolSpec {
|
||||||
|
|
||||||
|
17
web-views/groovycTest
Executable file
17
web-views/groovycTest
Executable file
@ -0,0 +1,17 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
if [ "$1" == "--debug" ]; then
|
||||||
|
gradle -q uberJar && \
|
||||||
|
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:8192 \
|
||||||
|
-cp build/libs/web-views-uber-0.1.0.jar \
|
||||||
|
org.codehaus.groovy.tools.FileSystemCompiler \
|
||||||
|
--configscript src/main/resources/groowt/view/web/groovyc/GroovycConfigurationScript.groovy \
|
||||||
|
-d groovyc-out \
|
||||||
|
sketching/helloTarget.wvc
|
||||||
|
else
|
||||||
|
gradle -q uberJar && \
|
||||||
|
groovyc -cp build/libs/web-views-uber-0.1.0.jar \
|
||||||
|
--configscript src/main/resources/groowt/view/web/groovyc/GroovycConfigurationScript.groovy \
|
||||||
|
-d groovyc-out \
|
||||||
|
sketching/helloTarget.wvc
|
||||||
|
fi
|
@ -2,8 +2,8 @@ package groowt.view.web.compiler;
|
|||||||
|
|
||||||
import groowt.view.component.compiler.ComponentTemplateCompileException;
|
import groowt.view.component.compiler.ComponentTemplateCompileException;
|
||||||
import groowt.view.component.compiler.ComponentTemplateCompileUnit;
|
import groowt.view.component.compiler.ComponentTemplateCompileUnit;
|
||||||
import groowt.view.web.antlr.TokenUtil;
|
|
||||||
import groowt.view.web.ast.node.Node;
|
import groowt.view.web.ast.node.Node;
|
||||||
|
import groowt.view.web.util.SourcePosition;
|
||||||
import org.antlr.v4.runtime.ParserRuleContext;
|
import org.antlr.v4.runtime.ParserRuleContext;
|
||||||
import org.antlr.v4.runtime.tree.TerminalNode;
|
import org.antlr.v4.runtime.tree.TerminalNode;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
@ -60,14 +60,25 @@ public class WebViewComponentTemplateCompileException extends ComponentTemplateC
|
|||||||
this.node = node;
|
this.node = node;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public @Nullable SourcePosition getSourcePosition() {
|
||||||
protected @Nullable String getPosition() {
|
|
||||||
if (this.node != null) {
|
if (this.node != null) {
|
||||||
return this.node.getTokenRange().getStartPosition().toStringLong();
|
return this.node.getTokenRange().getStartPosition();
|
||||||
} else if (this.parserRuleContext != null) {
|
} else if (this.parserRuleContext != null) {
|
||||||
return TokenUtil.formatTokenPosition(this.parserRuleContext.start);
|
final var start = this.parserRuleContext.start;
|
||||||
|
return new SourcePosition(start.getLine(), start.getCharPositionInLine() + 1);
|
||||||
} else if (this.terminalNode != null) {
|
} else if (this.terminalNode != null) {
|
||||||
return TokenUtil.formatTokenPosition(terminalNode.getSymbol());
|
final var symbol = terminalNode.getSymbol();
|
||||||
|
return new SourcePosition(symbol.getLine(), symbol.getCharPositionInLine() + 1);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected @Nullable String formatPosition() {
|
||||||
|
final SourcePosition sourcePosition = this.getSourcePosition();
|
||||||
|
if (sourcePosition != null) {
|
||||||
|
return sourcePosition.toStringLong();
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,184 @@
|
|||||||
|
package groowt.view.web.groovyc;
|
||||||
|
|
||||||
|
import groowt.view.component.compiler.ComponentTemplateCompileException;
|
||||||
|
import groowt.view.component.compiler.DefaultComponentTemplateCompilerConfiguration;
|
||||||
|
import groowt.view.component.compiler.source.ComponentTemplateSource;
|
||||||
|
import groowt.view.web.analysis.MismatchedComponentTypeAnalysis;
|
||||||
|
import groowt.view.web.analysis.MismatchedComponentTypeError;
|
||||||
|
import groowt.view.web.antlr.*;
|
||||||
|
import groowt.view.web.ast.DefaultAstBuilder;
|
||||||
|
import groowt.view.web.ast.DefaultNodeFactory;
|
||||||
|
import groowt.view.web.ast.node.CompilationUnitNode;
|
||||||
|
import groowt.view.web.compiler.AnonymousWebViewComponent;
|
||||||
|
import groowt.view.web.compiler.MultipleWebViewComponentCompileErrorsException;
|
||||||
|
import groowt.view.web.compiler.WebViewComponentTemplateCompileException;
|
||||||
|
import groowt.view.web.compiler.WebViewComponentTemplateCompileUnit;
|
||||||
|
import groowt.view.web.transpile.DefaultGroovyTranspiler;
|
||||||
|
import groowt.view.web.util.SourcePosition;
|
||||||
|
import org.antlr.v4.runtime.ParserRuleContext;
|
||||||
|
import org.antlr.v4.runtime.Token;
|
||||||
|
import org.antlr.v4.runtime.tree.TerminalNode;
|
||||||
|
import org.antlr.v4.runtime.tree.Tree;
|
||||||
|
import org.apache.groovy.parser.antlr4.Antlr4ParserPlugin;
|
||||||
|
import org.codehaus.groovy.ast.ModuleNode;
|
||||||
|
import org.codehaus.groovy.control.CompilationFailedException;
|
||||||
|
import org.codehaus.groovy.control.ParserPlugin;
|
||||||
|
import org.codehaus.groovy.control.SourceUnit;
|
||||||
|
import org.codehaus.groovy.syntax.ParserException;
|
||||||
|
import org.codehaus.groovy.syntax.Reduction;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Reader;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class DelegatingWvcParserPlugin implements ParserPlugin {
|
||||||
|
|
||||||
|
private final Antlr4ParserPlugin groovyParserPlugin;
|
||||||
|
|
||||||
|
public DelegatingWvcParserPlugin(Antlr4ParserPlugin groovyParserPlugin) {
|
||||||
|
this.groovyParserPlugin = groovyParserPlugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Reduction parseCST(SourceUnit sourceUnit, Reader reader) throws CompilationFailedException {
|
||||||
|
return this.groovyParserPlugin.parseCST(sourceUnit, reader); // returns null
|
||||||
|
}
|
||||||
|
|
||||||
|
protected WebViewComponentTemplateCompileException getException(
|
||||||
|
WebViewComponentTemplateCompileUnit compileUnit,
|
||||||
|
TerminalNode terminalNode
|
||||||
|
) {
|
||||||
|
final Token offending = terminalNode.getSymbol();
|
||||||
|
final var exception = new WebViewComponentTemplateCompileException(
|
||||||
|
compileUnit, "Invalid token '" + TokenUtil.excerptToken(offending) + "'."
|
||||||
|
);
|
||||||
|
exception.setTerminalNode(terminalNode);
|
||||||
|
return exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected WebViewComponentTemplateCompileException getException(
|
||||||
|
WebViewComponentTemplateCompileUnit compileUnit,
|
||||||
|
ParserRuleContext parserRuleContext
|
||||||
|
) {
|
||||||
|
final var exception = new WebViewComponentTemplateCompileException(
|
||||||
|
compileUnit,
|
||||||
|
"Parser error: " + parserRuleContext.exception.getMessage(),
|
||||||
|
parserRuleContext.exception
|
||||||
|
);
|
||||||
|
exception.setParserRuleContext(parserRuleContext);
|
||||||
|
return exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected WebViewComponentTemplateCompileException getException(
|
||||||
|
WebViewComponentTemplateCompileUnit compileUnit,
|
||||||
|
Tree tree
|
||||||
|
) {
|
||||||
|
if (tree instanceof ParserRuleContext parserRuleContext) {
|
||||||
|
return getException(compileUnit, parserRuleContext);
|
||||||
|
} else if (tree instanceof TerminalNode terminalNode) {
|
||||||
|
return getException(compileUnit, terminalNode);
|
||||||
|
} else {
|
||||||
|
return new WebViewComponentTemplateCompileException(
|
||||||
|
compileUnit,
|
||||||
|
"Error at parser/lexer node " + tree.toString()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected WebViewComponentTemplateCompileException getException(
|
||||||
|
WebViewComponentTemplateCompileUnit compileUnit,
|
||||||
|
MismatchedComponentTypeError error
|
||||||
|
) {
|
||||||
|
final var exception = new WebViewComponentTemplateCompileException(
|
||||||
|
compileUnit,
|
||||||
|
error.getMessage()
|
||||||
|
);
|
||||||
|
exception.setParserRuleContext(error.getComponent());
|
||||||
|
return exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ParserException translateException(ComponentTemplateCompileException e) {
|
||||||
|
final var actual = (WebViewComponentTemplateCompileException) e;
|
||||||
|
final SourcePosition sourcePosition = actual.getSourcePosition();
|
||||||
|
if (sourcePosition != null) {
|
||||||
|
return new ParserException(e.getMessage(), e, sourcePosition.line(), sourcePosition.column());
|
||||||
|
} else {
|
||||||
|
return new ParserException(e.getMessage(), e, -1, -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ModuleNode buildAST(SourceUnit sourceUnit, ClassLoader classLoader, Reduction cst) throws ParserException {
|
||||||
|
final String sourceUnitName = sourceUnit.getName();
|
||||||
|
if (sourceUnitName.endsWith(".wvc")) {
|
||||||
|
final var compileUnit = new WebViewComponentTemplateCompileUnit(
|
||||||
|
AnonymousWebViewComponent.class,
|
||||||
|
ComponentTemplateSource.of(sourceUnit.getSource().getURI()),
|
||||||
|
"groowt.view.web.groovyc"
|
||||||
|
);
|
||||||
|
|
||||||
|
final CompilationUnitParseResult parseResult;
|
||||||
|
try {
|
||||||
|
parseResult = ParserUtil.parseCompilationUnit(sourceUnit.getSource().getReader());
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for parser/lexer errors
|
||||||
|
final var parseErrors = AntlrUtil.findErrorNodes(parseResult.getCompilationUnitContext());
|
||||||
|
if (!parseErrors.isEmpty()) {
|
||||||
|
if (parseErrors.getErrorCount() == 1) {
|
||||||
|
final var errorNode = parseErrors.getAll().getFirst();
|
||||||
|
throw this.translateException(getException(compileUnit, errorNode));
|
||||||
|
} else {
|
||||||
|
final var errorExceptions = parseErrors.getAll().stream()
|
||||||
|
.map(errorNode -> getException(compileUnit, errorNode))
|
||||||
|
.toList();
|
||||||
|
throw this.translateException(new MultipleWebViewComponentCompileErrorsException(
|
||||||
|
compileUnit,
|
||||||
|
errorExceptions
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for mismatched type errors
|
||||||
|
final List<MismatchedComponentTypeError> mismatchedComponentTypeErrors =
|
||||||
|
MismatchedComponentTypeAnalysis.check(parseResult.getCompilationUnitContext());
|
||||||
|
|
||||||
|
if (!mismatchedComponentTypeErrors.isEmpty()) {
|
||||||
|
if (mismatchedComponentTypeErrors.size() == 1) {
|
||||||
|
throw new RuntimeException(getException(compileUnit, mismatchedComponentTypeErrors.getFirst()));
|
||||||
|
} else {
|
||||||
|
final var errorExceptions = mismatchedComponentTypeErrors.stream()
|
||||||
|
.map(error -> getException(compileUnit, error))
|
||||||
|
.toList();
|
||||||
|
throw this.translateException(new MultipleWebViewComponentCompileErrorsException(
|
||||||
|
compileUnit,
|
||||||
|
errorExceptions
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// build ast
|
||||||
|
final var tokenList = new TokenList(parseResult.getTokenStream());
|
||||||
|
final var astBuilder = new DefaultAstBuilder(new DefaultNodeFactory(tokenList));
|
||||||
|
final var cuNode = (CompilationUnitNode) astBuilder.build(parseResult.getCompilationUnitContext());
|
||||||
|
|
||||||
|
final var groovyTranspiler = new DefaultGroovyTranspiler();
|
||||||
|
try {
|
||||||
|
final SourceUnit transpiledSourceUnit = groovyTranspiler.transpile(
|
||||||
|
new DefaultComponentTemplateCompilerConfiguration(),
|
||||||
|
compileUnit,
|
||||||
|
cuNode,
|
||||||
|
sourceUnitName.substring(0, sourceUnitName.length() - 4)
|
||||||
|
);
|
||||||
|
return transpiledSourceUnit.getAST();
|
||||||
|
} catch (ComponentTemplateCompileException e) {
|
||||||
|
throw this.translateException(e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return this.groovyParserPlugin.buildAST(sourceUnit, classLoader, cst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package groowt.view.web.groovyc;
|
||||||
|
|
||||||
|
import org.apache.groovy.parser.antlr4.Antlr4ParserPlugin;
|
||||||
|
import org.codehaus.groovy.control.ParserPlugin;
|
||||||
|
import org.codehaus.groovy.control.ParserPluginFactory;
|
||||||
|
|
||||||
|
public class WvcParserPluginFactory extends ParserPluginFactory {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ParserPlugin createParserPlugin() {
|
||||||
|
return new DelegatingWvcParserPlugin(new Antlr4ParserPlugin());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
.wvc
|
@ -0,0 +1 @@
|
|||||||
|
configuration.pluginFactory = new groowt.view.web.groovyc.WvcParserPluginFactory()
|
Loading…
Reference in New Issue
Block a user