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
|
||||
public String getMessage() {
|
||||
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) {
|
||||
sb.append(" at ").append(position);
|
||||
}
|
||||
return sb.append(": ").append(super.getMessage()).toString();
|
||||
}
|
||||
|
||||
protected @Nullable String getPosition() {
|
||||
protected @Nullable String formatPosition() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -133,6 +133,16 @@ tasks.register('toolsJar', 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
|
||||
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.ComponentTemplateCompileUnit;
|
||||
import groowt.view.web.antlr.TokenUtil;
|
||||
import groowt.view.web.ast.node.Node;
|
||||
import groowt.view.web.util.SourcePosition;
|
||||
import org.antlr.v4.runtime.ParserRuleContext;
|
||||
import org.antlr.v4.runtime.tree.TerminalNode;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@ -60,14 +60,25 @@ public class WebViewComponentTemplateCompileException extends ComponentTemplateC
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable String getPosition() {
|
||||
public @Nullable SourcePosition getSourcePosition() {
|
||||
if (this.node != null) {
|
||||
return this.node.getTokenRange().getStartPosition().toStringLong();
|
||||
return this.node.getTokenRange().getStartPosition();
|
||||
} 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) {
|
||||
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 {
|
||||
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