Major work on lexer/parser to help intellij plugin.
This commit is contained in:
parent
1b6344dbf2
commit
bfa2ec6cd7
@ -10,6 +10,7 @@ plugins {
|
|||||||
id 'groovy'
|
id 'groovy'
|
||||||
id 'org.jetbrains.kotlin.jvm'
|
id 'org.jetbrains.kotlin.jvm'
|
||||||
id 'java-test-fixtures'
|
id 'java-test-fixtures'
|
||||||
|
id 'distribution'
|
||||||
}
|
}
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
@ -104,6 +105,12 @@ tasks.named('generateWebViewComponentsLexerBase', GroowtAntlrExecTask) { task ->
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks.named({ String name ->
|
||||||
|
name in ['compileJava', 'compileGroovy', 'compileKotlin']
|
||||||
|
} as Spec<String>).configureEach {
|
||||||
|
dependsOn 'generateAllAntlr'
|
||||||
|
}
|
||||||
|
|
||||||
tasks.register('groovyConsole', JavaExec) {
|
tasks.register('groovyConsole', JavaExec) {
|
||||||
group = 'groovy'
|
group = 'groovy'
|
||||||
classpath += sourceSets.main.runtimeClasspath + configurations.groovyConsole
|
classpath += sourceSets.main.runtimeClasspath + configurations.groovyConsole
|
||||||
@ -112,14 +119,13 @@ tasks.register('groovyConsole', JavaExec) {
|
|||||||
|
|
||||||
tasks.register('toolsJar', Jar) {
|
tasks.register('toolsJar', Jar) {
|
||||||
group 'tools'
|
group 'tools'
|
||||||
archiveBaseName = 'web-tools'
|
archiveBaseName = 'web-view-components-compiler-tools'
|
||||||
exclude { FileTreeElement element ->
|
exclude { FileTreeElement element ->
|
||||||
element.file in sourceSets.main.output
|
element.file in sourceSets.main.output
|
||||||
}
|
}
|
||||||
from sourceSets.tools.output
|
from sourceSets.tools.output
|
||||||
from sourceSets.tools.runtimeClasspath.filter(File.&exists).collect { it.isDirectory() ? it : zipTree(it) }
|
from sourceSets.tools.runtimeClasspath.filter(File.&exists).collect { it.isDirectory() ? it : zipTree(it) }
|
||||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||||
dependsOn tasks.named('jar')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NullCheck
|
@NullCheck
|
||||||
@ -161,9 +167,9 @@ toolSpecs.each { spec ->
|
|||||||
group = 'tools'
|
group = 'tools'
|
||||||
outputDir = file('bin')
|
outputDir = file('bin')
|
||||||
applicationName = spec.name
|
applicationName = spec.name
|
||||||
|
classpath = sourceSets.tools.runtimeClasspath
|
||||||
mainClass = spec.fullMainClass
|
mainClass = spec.fullMainClass
|
||||||
unixStartScriptGenerator.template = resources.text.fromFile('src/tools/binTemplate.gst')
|
unixStartScriptGenerator.template = resources.text.fromFile('src/tools/binTemplate.gst')
|
||||||
dependsOn tasks.named('toolsJar')
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,6 +204,12 @@ java {
|
|||||||
withSourcesJar()
|
withSourcesJar()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks.named('sourcesJar', Jar) {
|
||||||
|
from fileTree('src/main/antlr')
|
||||||
|
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||||
|
dependsOn 'generateAllAntlr'
|
||||||
|
}
|
||||||
|
|
||||||
publishing {
|
publishing {
|
||||||
publications {
|
publications {
|
||||||
create('webViewComponentsCompiler', MavenPublication) {
|
create('webViewComponentsCompiler', MavenPublication) {
|
||||||
@ -206,4 +218,3 @@ publishing {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ options {
|
|||||||
|
|
||||||
tokens {
|
tokens {
|
||||||
PreambleBreak,
|
PreambleBreak,
|
||||||
|
ComponentNlws,
|
||||||
GroovyCode,
|
GroovyCode,
|
||||||
GStringAttrValueEnd,
|
GStringAttrValueEnd,
|
||||||
JStringAttrValueEnd,
|
JStringAttrValueEnd,
|
||||||
@ -15,6 +16,10 @@ tokens {
|
|||||||
DollarScriptletClose
|
DollarScriptletClose
|
||||||
}
|
}
|
||||||
|
|
||||||
|
channels {
|
||||||
|
ERROR
|
||||||
|
}
|
||||||
|
|
||||||
@header {
|
@header {
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import static groowt.view.component.web.antlr.LexerSemanticPredicates.*;
|
import static groowt.view.component.web.antlr.LexerSemanticPredicates.*;
|
||||||
@ -83,6 +88,10 @@ tokens {
|
|||||||
DollarSlashyStringClosureStart
|
DollarSlashyStringClosureStart
|
||||||
);
|
);
|
||||||
|
|
||||||
|
public WebViewComponentsLexerBase() {
|
||||||
|
_interp = new LexerATNSimulator(this,_ATN,_decisionToDFA,_sharedContextCache);
|
||||||
|
}
|
||||||
|
|
||||||
private void onPreambleClose() {
|
private void onPreambleClose() {
|
||||||
this.setType(PreambleBreak);
|
this.setType(PreambleBreak);
|
||||||
this.exitPreamble();
|
this.exitPreamble();
|
||||||
@ -112,11 +121,19 @@ PreambleOpen
|
|||||||
;
|
;
|
||||||
|
|
||||||
ComponentOpen
|
ComponentOpen
|
||||||
: LT -> pushMode(TAG_START)
|
: LT { !isAnyOf(this.getNextChar(), '/', '>') }? -> pushMode(TAG_START)
|
||||||
;
|
;
|
||||||
|
|
||||||
ClosingComponentOpen
|
ClosingComponentOpen
|
||||||
: LT FS -> pushMode(TAG_START)
|
: LT FS { !this.isNext('>') }? -> pushMode(TAG_START)
|
||||||
|
;
|
||||||
|
|
||||||
|
FragmentOpen
|
||||||
|
: LT GT
|
||||||
|
;
|
||||||
|
|
||||||
|
FragmentClose
|
||||||
|
: LT FS GT
|
||||||
;
|
;
|
||||||
|
|
||||||
EqualsScriptletOpen
|
EqualsScriptletOpen
|
||||||
@ -161,10 +178,6 @@ RawText
|
|||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
mode TAG_START;
|
mode TAG_START;
|
||||||
|
|
||||||
FragmentClose
|
|
||||||
: GT -> popMode
|
|
||||||
;
|
|
||||||
|
|
||||||
TypedIdentifier
|
TypedIdentifier
|
||||||
: ( PackageIdentifier DOT )* ClassIdentifier ( DOT ClassIdentifier )* -> mode(IN_TAG)
|
: ( PackageIdentifier DOT )* ClassIdentifier ( DOT ClassIdentifier )* -> mode(IN_TAG)
|
||||||
;
|
;
|
||||||
@ -213,6 +226,14 @@ StringIdentifierChar
|
|||||||
: [-_0-9\p{L}]
|
: [-_0-9\p{L}]
|
||||||
;
|
;
|
||||||
|
|
||||||
|
TagStartNlws
|
||||||
|
: NLWS+ -> type(ComponentNlws), channel(HIDDEN)
|
||||||
|
;
|
||||||
|
|
||||||
|
TagStartError
|
||||||
|
: . -> channel(ERROR)
|
||||||
|
;
|
||||||
|
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
mode IN_TAG;
|
mode IN_TAG;
|
||||||
|
|
||||||
@ -255,7 +276,7 @@ JStringAttrValueStart
|
|||||||
;
|
;
|
||||||
|
|
||||||
ClosureAttrValueStart
|
ClosureAttrValueStart
|
||||||
: LEFT_CURLY ComponentNlws? { !this.isNext('<') }?
|
: LEFT_CURLY InTagNlws? { !this.isNext('<') }?
|
||||||
{
|
{
|
||||||
this.curlies.push(() -> {
|
this.curlies.push(() -> {
|
||||||
this.setType(ClosureAttrValueEnd);
|
this.setType(ClosureAttrValueEnd);
|
||||||
@ -267,15 +288,19 @@ ClosureAttrValueStart
|
|||||||
;
|
;
|
||||||
|
|
||||||
ComponentAttrValueStart
|
ComponentAttrValueStart
|
||||||
: LEFT_CURLY ComponentNlws? { this.isNext('<') }?
|
: LEFT_CURLY InTagNlws? { this.isNext('<') }?
|
||||||
;
|
;
|
||||||
|
|
||||||
ComponentAttrValueEnd
|
ComponentAttrValueEnd
|
||||||
: GT RIGHT_CURLY
|
: GT RIGHT_CURLY
|
||||||
;
|
;
|
||||||
|
|
||||||
ComponentNlws
|
InTagNlws
|
||||||
: NLWS+
|
: NLWS+ -> type(ComponentNlws), channel(HIDDEN)
|
||||||
|
;
|
||||||
|
|
||||||
|
TagError
|
||||||
|
: . -> channel(ERROR)
|
||||||
;
|
;
|
||||||
|
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
|
@ -49,21 +49,20 @@ openComponent
|
|||||||
;
|
;
|
||||||
|
|
||||||
closingComponent
|
closingComponent
|
||||||
: ClosingComponentOpen ComponentNlws?
|
: ClosingComponentOpen
|
||||||
componentType ComponentNlws?
|
componentType
|
||||||
ComponentClose
|
ComponentClose
|
||||||
;
|
;
|
||||||
|
|
||||||
fragmentComponent
|
fragmentComponent
|
||||||
: ComponentOpen ComponentClose
|
: FragmentOpen body FragmentClose
|
||||||
body
|
|
||||||
ClosingComponentOpen ComponentClose
|
|
||||||
;
|
;
|
||||||
|
|
||||||
componentArgs
|
componentArgs
|
||||||
: ComponentNlws? componentType
|
: componentType
|
||||||
ComponentNlws? componentConstructor?
|
( attr )*
|
||||||
ComponentNlws? ( attr ComponentNlws? )*
|
componentConstructor?
|
||||||
|
( attr )*
|
||||||
;
|
;
|
||||||
|
|
||||||
componentType
|
componentType
|
||||||
|
@ -45,8 +45,8 @@ public abstract class AbstractWebViewComponentsLexer extends Lexer {
|
|||||||
|
|
||||||
protected record StringClosingEndSpec(int type, int popCount) implements GStringPathEndSpec {}
|
protected record StringClosingEndSpec(int type, int popCount) implements GStringPathEndSpec {}
|
||||||
|
|
||||||
protected final PairCounter curlies = new SimplePairCounter(this);
|
protected PairCounter curlies = new SimplePairCounter();
|
||||||
protected final PairCounter parentheses = new SimplePairCounter(this);
|
protected PairCounter parentheses = new SimplePairCounter();
|
||||||
|
|
||||||
private final Logger logger;
|
private final Logger logger;
|
||||||
|
|
||||||
@ -57,6 +57,58 @@ public abstract class AbstractWebViewComponentsLexer extends Lexer {
|
|||||||
public AbstractWebViewComponentsLexer(CharStream input) {
|
public AbstractWebViewComponentsLexer(CharStream input) {
|
||||||
super(input);
|
super(input);
|
||||||
this.logger = LoggerFactory.getLogger(this.getClass());
|
this.logger = LoggerFactory.getLogger(this.getClass());
|
||||||
|
this.curlies.setLexer(this);
|
||||||
|
this.parentheses.setLexer(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AbstractWebViewComponentsLexer() {
|
||||||
|
this.logger = LoggerFactory.getLogger(this.getClass());
|
||||||
|
this.curlies.setLexer(this);
|
||||||
|
this.parentheses.setLexer(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PairCounter getCurlies() {
|
||||||
|
return this.curlies;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCurlies(PairCounter curlies) {
|
||||||
|
this.curlies = curlies;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PairCounter getParentheses() {
|
||||||
|
return this.parentheses;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setParentheses(PairCounter parentheses) {
|
||||||
|
this.parentheses = parentheses;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Logger getLogger() {
|
||||||
|
return this.logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCanPreamble() {
|
||||||
|
return this.canPreamble;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCanPreamble(boolean canPreamble) {
|
||||||
|
this.canPreamble = canPreamble;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInPreamble() {
|
||||||
|
return this.inPreamble;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInPreamble(boolean inPreamble) {
|
||||||
|
this.inPreamble = inPreamble;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInConstructor() {
|
||||||
|
return this.inConstructor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInConstructor(boolean inConstructor) {
|
||||||
|
this.inConstructor = inConstructor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -2,8 +2,15 @@ package groowt.view.component.web.antlr
|
|||||||
|
|
||||||
import groowt.view.component.web.util.SourcePosition
|
import groowt.view.component.web.util.SourcePosition
|
||||||
|
|
||||||
data class LexerError(val type: LexerErrorType, val sourcePosition: SourcePosition)
|
data class LexerError(
|
||||||
|
val type: LexerErrorType,
|
||||||
|
val sourcePosition: SourcePosition,
|
||||||
|
val badText: String,
|
||||||
|
val lexerMode: Int
|
||||||
|
)
|
||||||
|
|
||||||
fun format(lexerError: LexerError): String {
|
fun formatLexerError(lexerError: LexerError): String {
|
||||||
return "At ${lexerError.sourcePosition.toStringLong()}: ${lexerError.type.message}"
|
return "At ${lexerError.sourcePosition.toStringLong()}: ${lexerError.type.message} " +
|
||||||
|
"Bad input: '${escapeChars(lexerError.badText)}'. " +
|
||||||
|
"(mode: ${WebViewComponentsLexer.modeNames[lexerError.lexerMode]})."
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import groowt.view.component.web.util.SourcePosition
|
|||||||
import org.antlr.v4.runtime.*
|
import org.antlr.v4.runtime.*
|
||||||
import org.antlr.v4.runtime.atn.ATNConfigSet
|
import org.antlr.v4.runtime.atn.ATNConfigSet
|
||||||
import org.antlr.v4.runtime.dfa.DFA
|
import org.antlr.v4.runtime.dfa.DFA
|
||||||
|
import org.antlr.v4.runtime.misc.Interval
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class LexerErrorListener : ANTLRErrorListener {
|
class LexerErrorListener : ANTLRErrorListener {
|
||||||
@ -22,7 +23,12 @@ class LexerErrorListener : ANTLRErrorListener {
|
|||||||
) {
|
) {
|
||||||
if (e is LexerNoViableAltException) {
|
if (e is LexerNoViableAltException) {
|
||||||
val sourcePosition = SourcePosition(line, charPositionInLine + 1)
|
val sourcePosition = SourcePosition(line, charPositionInLine + 1)
|
||||||
val lexerError = LexerError(LexerErrorType.NO_VIABLE_ALTERNATIVE, sourcePosition)
|
val lexerError = LexerError(
|
||||||
|
LexerErrorType.NO_VIABLE_ALTERNATIVE,
|
||||||
|
sourcePosition,
|
||||||
|
e.inputStream.getText(Interval.of(e.startIndex, e.startIndex)),
|
||||||
|
(recognizer as WebViewComponentsLexer)._mode
|
||||||
|
)
|
||||||
errors.add(lexerError)
|
errors.add(lexerError)
|
||||||
} else {
|
} else {
|
||||||
throw e
|
throw e
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
package groowt.view.component.web.antlr
|
package groowt.view.component.web.antlr
|
||||||
|
|
||||||
enum class LexerErrorType(val message: String) {
|
enum class LexerErrorType(val message: String) {
|
||||||
NO_VIABLE_ALTERNATIVE("No viable alternative.")
|
NO_VIABLE_ALTERNATIVE("Lexer has no viable alternative.")
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,11 @@
|
|||||||
package groowt.view.component.web.antlr;
|
package groowt.view.component.web.antlr;
|
||||||
|
|
||||||
|
import org.antlr.v4.runtime.Lexer;
|
||||||
|
import org.antlr.v4.runtime.misc.IntegerStack;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.Deque;
|
||||||
|
|
||||||
public interface PairCounter {
|
public interface PairCounter {
|
||||||
|
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
@ -7,6 +13,17 @@ public interface PairCounter {
|
|||||||
void after();
|
void after();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface StackEntry {
|
||||||
|
IntegerStack getModes();
|
||||||
|
@Nullable OnPop getOnPop();
|
||||||
|
int get();
|
||||||
|
int increment();
|
||||||
|
int decrement();
|
||||||
|
}
|
||||||
|
|
||||||
|
Deque<StackEntry> getStack();
|
||||||
|
void setLexer(Lexer lexer);
|
||||||
|
|
||||||
void push();
|
void push();
|
||||||
void push(OnPop onPop);
|
void push(OnPop onPop);
|
||||||
void pop();
|
void pop();
|
||||||
|
@ -14,7 +14,7 @@ class MismatchedInputParserError(
|
|||||||
val expectedTokenTypes: Set<Int>
|
val expectedTokenTypes: Set<Int>
|
||||||
) : ParserError(type, offending, context)
|
) : ParserError(type, offending, context)
|
||||||
|
|
||||||
fun format(error: ParserError): String {
|
fun formatParserError(error: ParserError): String {
|
||||||
val sb = StringBuilder()
|
val sb = StringBuilder()
|
||||||
val sourcePosition = SourcePosition.fromStartOfToken(error.offending)
|
val sourcePosition = SourcePosition.fromStartOfToken(error.offending)
|
||||||
sb.append("At ")
|
sb.append("At ")
|
||||||
|
@ -1,12 +1,16 @@
|
|||||||
package groowt.view.component.web.antlr
|
package groowt.view.component.web.antlr
|
||||||
|
|
||||||
|
import groowt.view.component.web.util.SourcePosition
|
||||||
import org.antlr.v4.runtime.*
|
import org.antlr.v4.runtime.*
|
||||||
|
import org.antlr.v4.runtime.misc.Interval
|
||||||
|
|
||||||
class ParserErrorListener : BaseErrorListener() {
|
class ParserErrorListener : BaseErrorListener() {
|
||||||
|
|
||||||
private val errors: MutableList<ParserError> = ArrayList()
|
private val lexerErrors: MutableList<LexerError> = ArrayList()
|
||||||
|
private val parserErrors: MutableList<ParserError> = ArrayList()
|
||||||
|
|
||||||
fun getErrors(): List<ParserError> = this.errors
|
fun getLexerErrors(): List<LexerError> = this.lexerErrors
|
||||||
|
fun getParserErrors(): List<ParserError> = this.parserErrors
|
||||||
|
|
||||||
override fun syntaxError(
|
override fun syntaxError(
|
||||||
recognizer: Recognizer<*, *>,
|
recognizer: Recognizer<*, *>,
|
||||||
@ -18,9 +22,16 @@ class ParserErrorListener : BaseErrorListener() {
|
|||||||
) {
|
) {
|
||||||
val parser = recognizer as WebViewComponentsParser
|
val parser = recognizer as WebViewComponentsParser
|
||||||
when (e) {
|
when (e) {
|
||||||
|
is LexerNoViableAltException -> {
|
||||||
|
val lexer = e.recognizer as WebViewComponentsLexer
|
||||||
|
val sourcePosition = SourcePosition(line, charPositionInLine + 1)
|
||||||
|
val badText = lexer.inputStream.getText(Interval.of(e.startIndex, e.startIndex))
|
||||||
|
val error = LexerError(LexerErrorType.NO_VIABLE_ALTERNATIVE, sourcePosition, badText, lexer._mode)
|
||||||
|
this.lexerErrors.add(error)
|
||||||
|
}
|
||||||
is NoViableAltException -> {
|
is NoViableAltException -> {
|
||||||
val error = ParserError(ParserErrorType.NO_VIABLE_ALTERNATIVE, e.offendingToken, parser.context)
|
val error = ParserError(ParserErrorType.NO_VIABLE_ALTERNATIVE, e.offendingToken, parser.context)
|
||||||
errors.add(error)
|
parserErrors.add(error)
|
||||||
}
|
}
|
||||||
is InputMismatchException -> {
|
is InputMismatchException -> {
|
||||||
val error = MismatchedInputParserError(
|
val error = MismatchedInputParserError(
|
||||||
@ -29,11 +40,11 @@ class ParserErrorListener : BaseErrorListener() {
|
|||||||
parser.context,
|
parser.context,
|
||||||
e.expectedTokens.toSet()
|
e.expectedTokens.toSet()
|
||||||
)
|
)
|
||||||
errors.add(error)
|
parserErrors.add(error)
|
||||||
}
|
}
|
||||||
is FailedPredicateException -> {
|
is FailedPredicateException -> {
|
||||||
val error = ParserError(ParserErrorType.FAILED_PREDICATE, e.offendingToken, parser.context)
|
val error = ParserError(ParserErrorType.FAILED_PREDICATE, e.offendingToken, parser.context)
|
||||||
errors.add(error)
|
parserErrors.add(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package groowt.view.component.web.antlr
|
package groowt.view.component.web.antlr
|
||||||
|
|
||||||
enum class ParserErrorType(val message: String) {
|
enum class ParserErrorType(val message: String) {
|
||||||
NO_VIABLE_ALTERNATIVE("No viable alternative."),
|
NO_VIABLE_ALTERNATIVE("Parser has no viable alternative."),
|
||||||
INPUT_MISMATCH("Input mismatch."),
|
INPUT_MISMATCH("Parser input mismatch."),
|
||||||
FAILED_PREDICATE("Input failed predicate.")
|
FAILED_PREDICATE("Parser input failed predicate.")
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,8 @@ data class CompilationUnitParseResult(
|
|||||||
val lexer: WebViewComponentsLexer,
|
val lexer: WebViewComponentsLexer,
|
||||||
val tokenStream: WebViewComponentsTokenStream,
|
val tokenStream: WebViewComponentsTokenStream,
|
||||||
val parser: WebViewComponentsParser,
|
val parser: WebViewComponentsParser,
|
||||||
|
val lexerErrors: List<LexerError>,
|
||||||
|
val parserErrors: List<ParserError>,
|
||||||
val compilationUnitContext: CompilationUnitContext
|
val compilationUnitContext: CompilationUnitContext
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -33,9 +35,21 @@ fun parseCompilationUnit(reader: Reader): CompilationUnitParseResult =
|
|||||||
fun parseCompilationUnit(charStream: CharStream): CompilationUnitParseResult {
|
fun parseCompilationUnit(charStream: CharStream): CompilationUnitParseResult {
|
||||||
val lexer = WebViewComponentsLexer(charStream)
|
val lexer = WebViewComponentsLexer(charStream)
|
||||||
val tokenStream = WebViewComponentsTokenStream(lexer)
|
val tokenStream = WebViewComponentsTokenStream(lexer)
|
||||||
|
|
||||||
val parser = WebViewComponentsParser(tokenStream)
|
val parser = WebViewComponentsParser(tokenStream)
|
||||||
|
parser.removeErrorListener(ConsoleErrorListener.INSTANCE)
|
||||||
|
val parserErrorListener = ParserErrorListener()
|
||||||
|
parser.addErrorListener(parserErrorListener)
|
||||||
|
|
||||||
val cu = parser.compilationUnit()
|
val cu = parser.compilationUnit()
|
||||||
return CompilationUnitParseResult(lexer, tokenStream, parser, cu)
|
return CompilationUnitParseResult(
|
||||||
|
lexer,
|
||||||
|
tokenStream,
|
||||||
|
parser,
|
||||||
|
parserErrorListener.getLexerErrors(),
|
||||||
|
parserErrorListener.getParserErrors(),
|
||||||
|
cu
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun parseCompilationUnit(
|
fun parseCompilationUnit(
|
||||||
|
@ -1,48 +1,76 @@
|
|||||||
package groowt.view.component.web.antlr
|
package groowt.view.component.web.antlr
|
||||||
|
|
||||||
|
import groowt.view.component.web.antlr.PairCounter.StackEntry
|
||||||
import org.antlr.v4.runtime.Lexer
|
import org.antlr.v4.runtime.Lexer
|
||||||
import org.antlr.v4.runtime.misc.IntegerStack
|
import org.antlr.v4.runtime.misc.IntegerStack
|
||||||
import org.slf4j.Logger
|
import org.slf4j.Logger
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class SimplePairCounter(private val lexer: Lexer) : PairCounter {
|
class SimplePairCounter : PairCounter {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val logger: Logger = LoggerFactory.getLogger(SimplePairCounter::class.java)
|
private val logger: Logger = LoggerFactory.getLogger(SimplePairCounter::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
private class StackEntry(val modes: IntegerStack, val onPop: PairCounter.OnPop?) {
|
class SimpleStackEntry(private val modes: IntegerStack, private val onPop: PairCounter.OnPop?) : StackEntry {
|
||||||
|
|
||||||
private var count: Int = 0
|
private var count: Int = 0
|
||||||
fun get() = this.count
|
|
||||||
fun increment(): Int = ++this.count
|
override fun getModes() = modes
|
||||||
fun decrement(): Int = --this.count
|
override fun getOnPop() = onPop
|
||||||
|
override fun get() = this.count
|
||||||
|
override fun increment(): Int = ++this.count
|
||||||
|
override fun decrement(): Int = --this.count
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (other !is StackEntry) return false
|
||||||
|
return modes == other.modes
|
||||||
|
&& onPop == other.onPop
|
||||||
|
&& get() == other.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode() = Objects.hash(modes, onPop, count)
|
||||||
|
|
||||||
|
override fun toString() = "SimpleStackEntry($count)"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private val stack: Deque<StackEntry> = LinkedList()
|
private val stack: Deque<SimpleStackEntry> = LinkedList()
|
||||||
|
private var lexer: Lexer? = null
|
||||||
|
|
||||||
private fun currentEntry(): StackEntry {
|
override fun getStack(): Deque<StackEntry> = LinkedList(stack)
|
||||||
|
|
||||||
|
override fun setLexer(lexer: Lexer?) {
|
||||||
|
this.lexer = lexer
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun currentEntry(): SimpleStackEntry {
|
||||||
if (this.stack.isEmpty()) {
|
if (this.stack.isEmpty()) {
|
||||||
throw IllegalStateException("Cannot currentEntry() when stack is empty!")
|
throw IllegalStateException("Cannot currentEntry() when stack is empty!")
|
||||||
}
|
}
|
||||||
return this.stack.peek()
|
return this.stack.peek()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getLexerModes() = IntegerStack(this.lexer._modeStack).also { it.push(this.lexer._mode) }
|
private fun getLexerModes(): IntegerStack {
|
||||||
|
if (lexer == null) {
|
||||||
|
throw IllegalStateException("lexer is null")
|
||||||
|
}
|
||||||
|
return IntegerStack(lexer!!._modeStack).also { it.push(lexer!!._mode) }
|
||||||
|
}
|
||||||
|
|
||||||
override fun push() {
|
override fun push() {
|
||||||
this.stack.push(StackEntry(this.getLexerModes(), null))
|
this.stack.push(SimpleStackEntry(this.getLexerModes(), null))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun push(onPop: PairCounter.OnPop?) {
|
override fun push(onPop: PairCounter.OnPop?) {
|
||||||
this.stack.push(StackEntry(this.getLexerModes(), onPop))
|
this.stack.push(SimpleStackEntry(this.getLexerModes(), onPop))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun pop() {
|
override fun pop() {
|
||||||
val entry = this.stack.pop()
|
val entry = this.stack.pop()
|
||||||
if (entry.onPop != null) {
|
entry.onPop?.after()
|
||||||
entry.onPop.after()
|
|
||||||
}
|
|
||||||
if (logger.isWarnEnabled) {
|
if (logger.isWarnEnabled) {
|
||||||
val currentModes = this.getLexerModes()
|
val currentModes = this.getLexerModes()
|
||||||
if (entry.modes != currentModes) {
|
if (entry.modes != currentModes) {
|
||||||
@ -80,4 +108,12 @@ class SimplePairCounter(private val lexer: Lexer) : PairCounter {
|
|||||||
this.stack.clear()
|
this.stack.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (other !is PairCounter) return false
|
||||||
|
return stack == other.stack
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int = Objects.hash(stack)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,10 @@ public class WebViewComponentsLexer extends WebViewComponentsLexerBase {
|
|||||||
this._interp = new PositionAdjustingLexerATNSimulator(this, _ATN, _decisionToDFA, _sharedContextCache);
|
this._interp = new PositionAdjustingLexerATNSimulator(this, _ATN, _decisionToDFA, _sharedContextCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public WebViewComponentsLexer() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected PositionAdjustingLexerATNSimulator getPositionAdjustingInterpreter() {
|
protected PositionAdjustingLexerATNSimulator getPositionAdjustingInterpreter() {
|
||||||
return (PositionAdjustingLexerATNSimulator) this.getInterpreter();
|
return (PositionAdjustingLexerATNSimulator) this.getInterpreter();
|
||||||
|
@ -7,7 +7,15 @@ private operator fun Interval.component1(): Int = this.a
|
|||||||
|
|
||||||
private operator fun Interval.component2(): Int = this.b
|
private operator fun Interval.component2(): Int = this.b
|
||||||
|
|
||||||
class WebViewComponentsTokenStream(private val tokenSource: TokenSource) : TokenStream {
|
class WebViewComponentsTokenStream(
|
||||||
|
private val tokenSource: TokenSource,
|
||||||
|
private val ignoreChannels: Set<Int>
|
||||||
|
) : TokenStream {
|
||||||
|
|
||||||
|
constructor(lexer: WebViewComponentsLexer) : this(
|
||||||
|
lexer,
|
||||||
|
setOf(WebViewComponentsLexer.HIDDEN, WebViewComponentsLexer.ERROR)
|
||||||
|
)
|
||||||
|
|
||||||
private val tokens: MutableList<Token> = ArrayList()
|
private val tokens: MutableList<Token> = ArrayList()
|
||||||
|
|
||||||
@ -67,7 +75,7 @@ class WebViewComponentsTokenStream(private val tokenSource: TokenSource) : Token
|
|||||||
MergedGroovyCodeToken(groovyTokens, this.tokens.size, this.tokenSource, this.tokenSource.inputStream)
|
MergedGroovyCodeToken(groovyTokens, this.tokens.size, this.tokenSource, this.tokenSource.inputStream)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (followingToken != null) {
|
if (followingToken != null && followingToken.channel !in this.ignoreChannels) {
|
||||||
fetched++
|
fetched++
|
||||||
if (followingToken is WritableToken) {
|
if (followingToken is WritableToken) {
|
||||||
followingToken.tokenIndex = this.tokens.size
|
followingToken.tokenIndex = this.tokens.size
|
||||||
@ -191,8 +199,7 @@ class WebViewComponentsTokenStream(private val tokenSource: TokenSource) : Token
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getAllTokensSkipEOF(): List<Token> {
|
fun getAllTokensSkipEOF(): List<Token> {
|
||||||
this.fill()
|
return this.getAllTokens().filter { it.type != Token.EOF }
|
||||||
return this.tokens.filter { it.type != Token.EOF }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun fill() {
|
private fun fill() {
|
||||||
|
@ -13,6 +13,7 @@ import org.junit.jupiter.api.TestFactory;
|
|||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static groowt.view.component.web.antlr.WebViewComponentsLexer.*;
|
import static groowt.view.component.web.antlr.WebViewComponentsLexer.*;
|
||||||
@ -70,7 +71,10 @@ public class WebViewComponentsLexerTests {
|
|||||||
sourceFile -> {
|
sourceFile -> {
|
||||||
final CharStream input = CharStreams.fromString(FileUtil.readFile(sourceFile));
|
final CharStream input = CharStreams.fromString(FileUtil.readFile(sourceFile));
|
||||||
final WebViewComponentsLexer lexer = new WebViewComponentsLexer(input);
|
final WebViewComponentsLexer lexer = new WebViewComponentsLexer(input);
|
||||||
final WebViewComponentsTokenStream tokenStream = new WebViewComponentsTokenStream(lexer);
|
final WebViewComponentsTokenStream tokenStream = new WebViewComponentsTokenStream(
|
||||||
|
lexer,
|
||||||
|
Set.of(WebViewComponentsLexer.HIDDEN) // include bad tokens for testing
|
||||||
|
);
|
||||||
final List<Token> allTokens = tokenStream.getAllTokensSkipEOF();
|
final List<Token> allTokens = tokenStream.getAllTokensSkipEOF();
|
||||||
final var sb = new StringBuilder();
|
final var sb = new StringBuilder();
|
||||||
for (int i = 0; i < allTokens.size(); i++) {
|
for (int i = 0; i < allTokens.size(); i++) {
|
||||||
|
@ -5,6 +5,8 @@ import org.antlr.v4.runtime.CharStreams;
|
|||||||
import org.junit.jupiter.api.DynamicTest;
|
import org.junit.jupiter.api.DynamicTest;
|
||||||
import org.junit.jupiter.api.TestFactory;
|
import org.junit.jupiter.api.TestFactory;
|
||||||
import org.junit.jupiter.api.function.Executable;
|
import org.junit.jupiter.api.function.Executable;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
@ -22,6 +24,8 @@ import static org.junit.jupiter.api.Assertions.*;
|
|||||||
|
|
||||||
public final class WebViewComponentsParserTests {
|
public final class WebViewComponentsParserTests {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(WebViewComponentsParserTests.class);
|
||||||
|
|
||||||
private static final String parserFileBase = String.join(File.separator, "src", "test", "parser");
|
private static final String parserFileBase = String.join(File.separator, "src", "test", "parser");
|
||||||
private static final String parserTreeFileBase = String.join(File.separator, parserFileBase, "trees");
|
private static final String parserTreeFileBase = String.join(File.separator, parserFileBase, "trees");
|
||||||
private static final String parseTreeFileSuffix = "_parseTree";
|
private static final String parseTreeFileSuffix = "_parseTree";
|
||||||
|
@ -2,11 +2,19 @@ package groowt.view.component.web.ast;
|
|||||||
|
|
||||||
import groowt.view.component.web.antlr.ParserUtil;
|
import groowt.view.component.web.antlr.ParserUtil;
|
||||||
import groowt.view.component.web.antlr.TokenList;
|
import groowt.view.component.web.antlr.TokenList;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
import static groowt.view.component.web.antlr.LexerErrorKt.formatLexerError;
|
||||||
|
import static groowt.view.component.web.antlr.ParserErrorKt.formatParserError;
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
public class DefaultAstBuilderTests extends AstBuilderTests {
|
public class DefaultAstBuilderTests extends AstBuilderTests {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(DefaultAstBuilderTests.class);
|
||||||
|
|
||||||
public DefaultAstBuilderTests() {
|
public DefaultAstBuilderTests() {
|
||||||
super(
|
super(
|
||||||
Path.of("src", "test", "ast"),
|
Path.of("src", "test", "ast"),
|
||||||
@ -19,6 +27,20 @@ public class DefaultAstBuilderTests extends AstBuilderTests {
|
|||||||
@Override
|
@Override
|
||||||
protected BuildResult buildFromSource(String source) {
|
protected BuildResult buildFromSource(String source) {
|
||||||
final var parseResult = ParserUtil.parseCompilationUnit(source);
|
final var parseResult = ParserUtil.parseCompilationUnit(source);
|
||||||
|
|
||||||
|
if (!parseResult.getLexerErrors().isEmpty()) {
|
||||||
|
parseResult.getLexerErrors().forEach(error -> {
|
||||||
|
logger.error(formatLexerError(error));
|
||||||
|
});
|
||||||
|
fail("There were lexer errors. See log for more information.");
|
||||||
|
}
|
||||||
|
if (!parseResult.getParserErrors().isEmpty()) {
|
||||||
|
parseResult.getParserErrors().forEach(error -> {
|
||||||
|
logger.error(formatParserError(error));
|
||||||
|
});
|
||||||
|
fail("There were parser errors. See log for more information.");
|
||||||
|
}
|
||||||
|
|
||||||
final var tokenList = new TokenList(parseResult.getTokenStream());
|
final var tokenList = new TokenList(parseResult.getTokenStream());
|
||||||
final var b = new DefaultAstBuilder(new DefaultNodeFactory(tokenList));
|
final var b = new DefaultAstBuilder(new DefaultNodeFactory(tokenList));
|
||||||
return new BuildResult(b.build(parseResult.getCompilationUnitContext()), tokenList);
|
return new BuildResult(b.build(parseResult.getCompilationUnitContext()), tokenList);
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
<bad! />
|
1
web-view-components-compiler/src/test/lexer/fragment.wvc
Normal file
1
web-view-components-compiler/src/test/lexer/fragment.wvc
Normal file
@ -0,0 +1 @@
|
|||||||
|
<><p>Hello, World!</p></>
|
@ -0,0 +1 @@
|
|||||||
|
</
|
@ -0,0 +1,5 @@
|
|||||||
|
0: ComponentOpen[1,1](<)
|
||||||
|
1: StringIdentifier[1,2](bad)
|
||||||
|
2: TagError[1,5](!)
|
||||||
|
3: ComponentSelfClose[1,7](/>)
|
||||||
|
4: RawText[1,9](\n)
|
@ -33,51 +33,50 @@
|
|||||||
32: RawText[11,33](\n )
|
32: RawText[11,33](\n )
|
||||||
33: ComponentOpen[12,13](<)
|
33: ComponentOpen[12,13](<)
|
||||||
34: TypedIdentifier[12,14](Case)
|
34: TypedIdentifier[12,14](Case)
|
||||||
35: ComponentNlws[12,18]( )
|
35: AttributeIdentifier[12,19](cond)
|
||||||
36: AttributeIdentifier[12,19](cond)
|
36: Equals[12,23](=)
|
||||||
37: Equals[12,23](=)
|
37: ClosureAttrValueStart[12,24]({)
|
||||||
38: ClosureAttrValueStart[12,24]({)
|
38: GroovyCode[12,25](isItTrue())
|
||||||
39: GroovyCode[12,25](isItTrue())
|
39: ClosureAttrValueEnd[12,35](})
|
||||||
40: ClosureAttrValueEnd[12,35](})
|
40: ComponentClose[12,36](>)
|
||||||
41: ComponentClose[12,36](>)
|
41: RawText[12,37](\n )
|
||||||
42: RawText[12,37](\n )
|
42: ComponentOpen[13,17](<)
|
||||||
43: ComponentOpen[13,17](<)
|
43: StringIdentifier[13,18](p)
|
||||||
44: StringIdentifier[13,18](p)
|
44: ComponentClose[13,19](>)
|
||||||
45: ComponentClose[13,19](>)
|
45: RawText[13,20](It's true! :))
|
||||||
46: RawText[13,20](It's true! :))
|
46: ClosingComponentOpen[13,33](</)
|
||||||
47: ClosingComponentOpen[13,33](</)
|
47: StringIdentifier[13,35](p)
|
||||||
48: StringIdentifier[13,35](p)
|
48: ComponentClose[13,36](>)
|
||||||
49: ComponentClose[13,36](>)
|
49: RawText[13,37](\n )
|
||||||
50: RawText[13,37](\n )
|
50: ClosingComponentOpen[14,13](</)
|
||||||
51: ClosingComponentOpen[14,13](</)
|
51: TypedIdentifier[14,15](Case)
|
||||||
52: TypedIdentifier[14,15](Case)
|
52: ComponentClose[14,19](>)
|
||||||
53: ComponentClose[14,19](>)
|
53: RawText[14,20](\n )
|
||||||
54: RawText[14,20](\n )
|
54: ComponentOpen[15,13](<)
|
||||||
55: ComponentOpen[15,13](<)
|
55: TypedIdentifier[15,14](Default)
|
||||||
56: TypedIdentifier[15,14](Default)
|
56: ComponentClose[15,21](>)
|
||||||
57: ComponentClose[15,21](>)
|
57: RawText[15,22](\n )
|
||||||
58: RawText[15,22](\n )
|
58: ComponentOpen[16,17](<)
|
||||||
59: ComponentOpen[16,17](<)
|
59: StringIdentifier[16,18](p)
|
||||||
60: StringIdentifier[16,18](p)
|
60: ComponentClose[16,19](>)
|
||||||
61: ComponentClose[16,19](>)
|
61: RawText[16,20](It's false... :()
|
||||||
62: RawText[16,20](It's false... :()
|
62: ClosingComponentOpen[16,36](</)
|
||||||
63: ClosingComponentOpen[16,36](</)
|
63: StringIdentifier[16,38](p)
|
||||||
64: StringIdentifier[16,38](p)
|
64: ComponentClose[16,39](>)
|
||||||
65: ComponentClose[16,39](>)
|
65: RawText[16,40](\n )
|
||||||
66: RawText[16,40](\n )
|
66: ClosingComponentOpen[17,13](</)
|
||||||
67: ClosingComponentOpen[17,13](</)
|
67: TypedIdentifier[17,15](Default)
|
||||||
68: TypedIdentifier[17,15](Default)
|
68: ComponentClose[17,22](>)
|
||||||
69: ComponentClose[17,22](>)
|
69: RawText[17,23](\n )
|
||||||
70: RawText[17,23](\n )
|
70: ClosingComponentOpen[18,9](</)
|
||||||
71: ClosingComponentOpen[18,9](</)
|
71: TypedIdentifier[18,11](groowt.view.web.Select)
|
||||||
72: TypedIdentifier[18,11](groowt.view.web.Select)
|
72: ComponentClose[18,33](>)
|
||||||
73: ComponentClose[18,33](>)
|
73: RawText[18,34](\n )
|
||||||
74: RawText[18,34](\n )
|
74: ClosingComponentOpen[19,5](</)
|
||||||
75: ClosingComponentOpen[19,5](</)
|
75: StringIdentifier[19,7](body)
|
||||||
76: StringIdentifier[19,7](body)
|
76: ComponentClose[19,11](>)
|
||||||
77: ComponentClose[19,11](>)
|
77: RawText[19,12](\n)
|
||||||
78: RawText[19,12](\n)
|
78: ClosingComponentOpen[20,1](</)
|
||||||
79: ClosingComponentOpen[20,1](</)
|
79: StringIdentifier[20,3](html)
|
||||||
80: StringIdentifier[20,3](html)
|
80: ComponentClose[20,7](>)
|
||||||
81: ComponentClose[20,7](>)
|
81: RawText[20,8](\n)
|
||||||
82: RawText[20,8](\n)
|
|
@ -1,5 +1,4 @@
|
|||||||
0: ComponentOpen[1,1](<)
|
0: ComponentOpen[1,1](<)
|
||||||
1: StringIdentifier[1,2](data-test)
|
1: StringIdentifier[1,2](data-test)
|
||||||
2: ComponentNlws[1,11]( )
|
2: ComponentSelfClose[1,12](/>)
|
||||||
3: ComponentSelfClose[1,12](/>)
|
3: RawText[1,14](\n)
|
||||||
4: RawText[1,14](\n)
|
|
@ -0,0 +1,10 @@
|
|||||||
|
0: FragmentOpen[1,1](<>)
|
||||||
|
1: ComponentOpen[1,3](<)
|
||||||
|
2: StringIdentifier[1,4](p)
|
||||||
|
3: ComponentClose[1,5](>)
|
||||||
|
4: RawText[1,6](Hello, World!)
|
||||||
|
5: ClosingComponentOpen[1,19](</)
|
||||||
|
6: StringIdentifier[1,21](p)
|
||||||
|
7: ComponentClose[1,22](>)
|
||||||
|
8: FragmentClose[1,23](</>)
|
||||||
|
9: RawText[1,26](\n)
|
@ -0,0 +1 @@
|
|||||||
|
0: ClosingComponentOpen[1,1](</)
|
@ -0,0 +1 @@
|
|||||||
|
<><p>Hello, World!</p></>
|
@ -90,7 +90,6 @@ compilationUnit[1,1..21,1]
|
|||||||
componentArgs[12,14..12,35]
|
componentArgs[12,14..12,35]
|
||||||
componentType[12,14..12,14]
|
componentType[12,14..12,14]
|
||||||
TypedIdentifier[12,14](Case)
|
TypedIdentifier[12,14](Case)
|
||||||
ComponentNlws[12,18]( )
|
|
||||||
attr[12,19..12,35]
|
attr[12,19..12,35]
|
||||||
keyValueAttr[12,19..12,35]
|
keyValueAttr[12,19..12,35]
|
||||||
AttributeIdentifier[12,19](cond)
|
AttributeIdentifier[12,19](cond)
|
||||||
|
@ -0,0 +1,28 @@
|
|||||||
|
compilationUnit[1,1..2,1]
|
||||||
|
body[1,1..1,26]
|
||||||
|
component[1,1..1,23]
|
||||||
|
fragmentComponent[1,1..1,23]
|
||||||
|
FragmentOpen[1,1](<>)
|
||||||
|
body[1,3..1,22]
|
||||||
|
component[1,3..1,22]
|
||||||
|
componentWithChildren[1,3..1,22]
|
||||||
|
openComponent[1,3..1,5]
|
||||||
|
ComponentOpen[1,3](<)
|
||||||
|
componentArgs[1,4..1,4]
|
||||||
|
componentType[1,4..1,4]
|
||||||
|
StringIdentifier[1,4](p)
|
||||||
|
ComponentClose[1,5](>)
|
||||||
|
body[1,6..1,6]
|
||||||
|
bodyText[1,6..1,6]
|
||||||
|
jStringBodyText[1,6..1,6]
|
||||||
|
RawText[1,6](Hello, World!)
|
||||||
|
closingComponent[1,19..1,22]
|
||||||
|
ClosingComponentOpen[1,19](</)
|
||||||
|
componentType[1,21..1,21]
|
||||||
|
StringIdentifier[1,21](p)
|
||||||
|
ComponentClose[1,22](>)
|
||||||
|
FragmentClose[1,23](</>)
|
||||||
|
bodyText[1,26..1,26]
|
||||||
|
jStringBodyText[1,26..1,26]
|
||||||
|
RawText[1,26](\n)
|
||||||
|
EOF[2,1](<EOF>)
|
@ -17,12 +17,17 @@ import org.codehaus.groovy.control.CompilePhase;
|
|||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import static groowt.view.component.web.antlr.LexerErrorKt.formatLexerError;
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
@ExtendWith(MockitoExtension.class)
|
@ExtendWith(MockitoExtension.class)
|
||||||
public abstract class GroovyTranspilerTests {
|
public abstract class GroovyTranspilerTests {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(GroovyTranspilerTests.class);
|
||||||
|
|
||||||
protected final GroovyTranspiler transpiler;
|
protected final GroovyTranspiler transpiler;
|
||||||
private final CompilationUnit groovyCompilationUnit;
|
private final CompilationUnit groovyCompilationUnit;
|
||||||
|
|
||||||
@ -36,6 +41,15 @@ public abstract class GroovyTranspilerTests {
|
|||||||
|
|
||||||
private void doTranspile(String source) {
|
private void doTranspile(String source) {
|
||||||
final var parseResult = ParserUtil.parseCompilationUnit(source);
|
final var parseResult = ParserUtil.parseCompilationUnit(source);
|
||||||
|
|
||||||
|
if (!parseResult.getLexerErrors().isEmpty()) {
|
||||||
|
logger.error("There were lexer errors.");
|
||||||
|
parseResult.getLexerErrors().forEach(error -> {
|
||||||
|
logger.error(formatLexerError(error));
|
||||||
|
});
|
||||||
|
fail("There were lexer errors. See log for more information.");
|
||||||
|
}
|
||||||
|
|
||||||
final var tokenList = new TokenList(parseResult.getTokenStream());
|
final var tokenList = new TokenList(parseResult.getTokenStream());
|
||||||
final var astBuilder = new DefaultAstBuilder(new DefaultNodeFactory(tokenList));
|
final var astBuilder = new DefaultAstBuilder(new DefaultNodeFactory(tokenList));
|
||||||
final var cuNode = astBuilder.buildCompilationUnit(parseResult.getCompilationUnitContext());
|
final var cuNode = astBuilder.buildCompilationUnit(parseResult.getCompilationUnitContext());
|
||||||
|
@ -1,3 +1,8 @@
|
|||||||
#/usr/bin/env bash
|
#/usr/bin/env bash
|
||||||
|
|
||||||
../gradlew toolsJar && java -cp build/libs/web-tools-0.1.0.jar:build/libs/web-views-0.1.0.jar $mainClassName "\$@"
|
if [ "\$1" == "--debug" ]; then
|
||||||
|
shift
|
||||||
|
gradle -q toolsJar && java -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:8192 -cp build/libs/web-view-components-compiler-tools-0.1.0.jar $mainClassName "\$@"
|
||||||
|
else
|
||||||
|
gradle -q toolsJar && java -cp build/libs/web-view-components-compiler-tools-0.1.0.jar $mainClassName "\$@"
|
||||||
|
fi
|
||||||
|
@ -74,13 +74,13 @@ final class ParseTreeFileMaker extends AbstractOutputFileMaker {
|
|||||||
|
|
||||||
if (!lexerErrorListener.errors.isEmpty()) {
|
if (!lexerErrorListener.errors.isEmpty()) {
|
||||||
println 'There were lexer errors.'
|
println 'There were lexer errors.'
|
||||||
lexerErrorListener.errors.each { println LexerErrorKt.format(it) }
|
lexerErrorListener.errors.each { println LexerErrorKt.formatLexerError(it) }
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!parserErrorListener.errors.isEmpty()) {
|
if (!parserErrorListener.parserErrors.isEmpty()) {
|
||||||
println 'There were parser errors.'
|
println 'There were parser errors.'
|
||||||
parserErrorListener.errors.each { println ParserErrorKt.format(it) }
|
parserErrorListener.parserErrors.each { println ParserErrorKt.formatParserError(it) }
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ open class TokenizeWvc : AbstractSourceTransformerCli() {
|
|||||||
|
|
||||||
protected fun onErrors(errors: List<LexerError>): Boolean {
|
protected fun onErrors(errors: List<LexerError>): Boolean {
|
||||||
println("There were errors during tokenization.")
|
println("There were errors during tokenization.")
|
||||||
errors.forEach { println(format(it)) }
|
errors.forEach { println(formatLexerError(it)) }
|
||||||
return this.getYesNo("Do you wish to try again?", false)
|
return this.getYesNo("Do you wish to try again?", false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,7 +99,7 @@ open class TokenizeWvc : AbstractSourceTransformerCli() {
|
|||||||
val errorListener = LexerErrorListener()
|
val errorListener = LexerErrorListener()
|
||||||
lexer.addErrorListener(errorListener)
|
lexer.addErrorListener(errorListener)
|
||||||
|
|
||||||
val tokenStream = WebViewComponentsTokenStream(lexer)
|
val tokenStream = WebViewComponentsTokenStream(lexer, setOf(WebViewComponentsLexer.HIDDEN))
|
||||||
val allTokens = tokenStream.getAllTokensSkipEOF()
|
val allTokens = tokenStream.getAllTokensSkipEOF()
|
||||||
|
|
||||||
val errors = errorListener.getErrors()
|
val errors = errorListener.getErrors()
|
||||||
|
Loading…
Reference in New Issue
Block a user