Lexer identifier refactorings and basic lexer/parser error listeners.
This commit is contained in:
parent
e747ac3c32
commit
80b01ec27a
@ -112,11 +112,11 @@ PreambleOpen
|
||||
;
|
||||
|
||||
ComponentOpen
|
||||
: LT -> pushMode(IN_TAG)
|
||||
: LT -> pushMode(TAG_START)
|
||||
;
|
||||
|
||||
ClosingComponentOpen
|
||||
: LT FS -> pushMode(IN_TAG)
|
||||
: LT FS -> pushMode(TAG_START)
|
||||
;
|
||||
|
||||
EqualsScriptletOpen
|
||||
@ -159,34 +159,87 @@ RawText
|
||||
;
|
||||
|
||||
// ----------------------------------------
|
||||
mode IN_TAG;
|
||||
mode TAG_START;
|
||||
|
||||
ComponentSelfClose
|
||||
: FS GT -> popMode
|
||||
FragmentClose
|
||||
: GT -> popMode
|
||||
;
|
||||
|
||||
TypedIdentifier
|
||||
: ( PackageIdentifier DOT )* ClassIdentifier ( DOT ClassIdentifier )* -> mode(IN_TAG)
|
||||
;
|
||||
|
||||
fragment
|
||||
PackageIdentifier
|
||||
: PackageIdentifierStartChar PackageIdentifierChar*
|
||||
;
|
||||
|
||||
fragment
|
||||
PackageIdentifierStartChar
|
||||
: [\p{Ll}]
|
||||
;
|
||||
|
||||
fragment
|
||||
PackageIdentifierChar
|
||||
: [\p{L}_0-9]
|
||||
;
|
||||
|
||||
fragment
|
||||
ClassIdentifier
|
||||
: ClassIdentifierStartChar ClassIdentifierChar*
|
||||
;
|
||||
|
||||
fragment
|
||||
ClassIdentifierStartChar
|
||||
: [\p{Lu}]
|
||||
;
|
||||
|
||||
fragment
|
||||
ClassIdentifierChar
|
||||
: [\p{L}_0-9]
|
||||
;
|
||||
|
||||
StringIdentifier
|
||||
: StringIdentifierStartChar StringIdentifierChar* -> mode(IN_TAG)
|
||||
;
|
||||
|
||||
fragment
|
||||
StringIdentifierStartChar
|
||||
: [\p{Ll}]
|
||||
;
|
||||
|
||||
fragment
|
||||
StringIdentifierChar
|
||||
: [-_0-9\p{L}]
|
||||
;
|
||||
|
||||
// ----------------------------------------
|
||||
mode IN_TAG;
|
||||
|
||||
ComponentClose
|
||||
: GT -> popMode
|
||||
;
|
||||
|
||||
Identifier
|
||||
: IdentifierStartChar IdentifierChar*
|
||||
;
|
||||
|
||||
IdentifierStartChar
|
||||
: ~[.] { isIdentifierStartChar(this.getCurrentChar()) }?
|
||||
;
|
||||
|
||||
IdentifierChar
|
||||
: ~[.] { isIdentifierChar(this.getCurrentChar()) }?
|
||||
ComponentSelfClose
|
||||
: FS GT -> popMode
|
||||
;
|
||||
|
||||
ConstructorOpen
|
||||
: LP { this.enterConstructor(); }
|
||||
;
|
||||
|
||||
Dot
|
||||
: DOT
|
||||
AttributeIdentifier
|
||||
: AttributeIdentifierStartChar AttributeIdentifierChar*
|
||||
;
|
||||
|
||||
fragment
|
||||
AttributeIdentifierStartChar
|
||||
: [\p{L}_$]
|
||||
;
|
||||
|
||||
fragment
|
||||
AttributeIdentifierChar
|
||||
: [\p{L}_$0-9]
|
||||
;
|
||||
|
||||
Equals
|
||||
|
@ -67,7 +67,7 @@ componentArgs
|
||||
;
|
||||
|
||||
componentType
|
||||
: Identifier ( Dot Identifier )*
|
||||
: TypedIdentifier | StringIdentifier
|
||||
;
|
||||
|
||||
componentConstructor
|
||||
@ -79,11 +79,11 @@ attr
|
||||
;
|
||||
|
||||
keyValueAttr
|
||||
: Identifier Equals value
|
||||
: AttributeIdentifier Equals value
|
||||
;
|
||||
|
||||
booleanAttr
|
||||
: Identifier
|
||||
: AttributeIdentifier
|
||||
;
|
||||
|
||||
value
|
||||
|
@ -1,17 +1,25 @@
|
||||
@file:JvmName("MismatchedComponentTypeAnalysis")
|
||||
package groowt.view.component.web.analysis
|
||||
|
||||
import groowt.view.component.web.WebViewComponentBugError
|
||||
import groowt.view.component.web.antlr.WebViewComponentsParser.ComponentTypeContext
|
||||
import groowt.view.component.web.antlr.WebViewComponentsParser.ComponentWithChildrenContext
|
||||
import groowt.view.component.web.util.SourcePosition
|
||||
import org.antlr.v4.runtime.ParserRuleContext
|
||||
import org.antlr.v4.runtime.Token
|
||||
import org.antlr.v4.runtime.tree.ParseTree
|
||||
import org.antlr.v4.runtime.tree.TerminalNode
|
||||
|
||||
private fun getIdentifiers(
|
||||
componentTypeContext: ComponentTypeContext
|
||||
): List<Token> = componentTypeContext.Identifier().map(TerminalNode::getSymbol)
|
||||
private fun getIdentifiers(ctx: ComponentTypeContext): Token {
|
||||
val typedIdentifier = ctx.TypedIdentifier()
|
||||
if (typedIdentifier != null) {
|
||||
return typedIdentifier.symbol
|
||||
}
|
||||
val stringIdentifier = ctx.StringIdentifier()
|
||||
if (stringIdentifier != null) {
|
||||
return stringIdentifier.symbol
|
||||
}
|
||||
throw WebViewComponentBugError("Could not determine identifier type: $ctx")
|
||||
}
|
||||
|
||||
private fun getErrorMessage(
|
||||
openType: ComponentTypeContext,
|
||||
@ -20,20 +28,8 @@ private fun getErrorMessage(
|
||||
"Found '${openType.text}' at ${SourcePosition.formatStartOfTokenLong(openType.start)} " +
|
||||
"and '${closingType.text}' at ${SourcePosition.formatStartOfTokenLong(closingType.start)}."
|
||||
|
||||
private fun test(
|
||||
openIdentifiers: List<Token>,
|
||||
closingIdentifiers: List<Token>
|
||||
): Boolean {
|
||||
if (openIdentifiers.size != closingIdentifiers.size) {
|
||||
return false
|
||||
}
|
||||
openIdentifiers.zip(closingIdentifiers).forEach { (openIdentifier, closingIdentifier) ->
|
||||
if (!openIdentifier.text.equals(closingIdentifier.text)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
private fun test(openIdentifiers: Token, closingIdentifiers: Token): Boolean =
|
||||
openIdentifiers.text.equals(closingIdentifiers.text)
|
||||
|
||||
private fun doCheck(tree: ParseTree, destination: MutableList<MismatchedComponentTypeError>) {
|
||||
if (tree is ParserRuleContext) {
|
||||
@ -43,9 +39,9 @@ private fun doCheck(tree: ParseTree, destination: MutableList<MismatchedComponen
|
||||
if (tree is ComponentWithChildrenContext) {
|
||||
val openType: ComponentTypeContext = tree.openComponent().componentArgs().componentType()
|
||||
val closingType: ComponentTypeContext = tree.closingComponent().componentType()
|
||||
val openTypeIdentifiers = getIdentifiers(openType)
|
||||
val closingTypeIdentifiers = getIdentifiers(closingType)
|
||||
if (!test(openTypeIdentifiers, closingTypeIdentifiers)) {
|
||||
val openIdentifier = getIdentifiers(openType)
|
||||
val closingIdentifier = getIdentifiers(closingType)
|
||||
if (!test(openIdentifier, closingIdentifier)) {
|
||||
destination.add(MismatchedComponentTypeError(tree, getErrorMessage(openType, closingType)))
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,9 @@
|
||||
package groowt.view.component.web.antlr
|
||||
|
||||
import groowt.view.component.web.util.SourcePosition
|
||||
|
||||
data class LexerError(val type: LexerErrorType, val sourcePosition: SourcePosition)
|
||||
|
||||
fun format(lexerError: LexerError): String {
|
||||
return "At ${lexerError.sourcePosition.toStringLong()}: ${lexerError.type.message}"
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
package groowt.view.component.web.antlr
|
||||
|
||||
import groowt.view.component.web.util.SourcePosition
|
||||
import org.antlr.v4.runtime.*
|
||||
import org.antlr.v4.runtime.atn.ATNConfigSet
|
||||
import org.antlr.v4.runtime.dfa.DFA
|
||||
import java.util.*
|
||||
|
||||
class LexerErrorListener : ANTLRErrorListener {
|
||||
|
||||
private val errors: MutableList<LexerError> = ArrayList()
|
||||
|
||||
fun getErrors(): List<LexerError> = this.errors
|
||||
|
||||
override fun syntaxError(
|
||||
recognizer: Recognizer<*, *>,
|
||||
offendingSymbol: Any?,
|
||||
line: Int,
|
||||
charPositionInLine: Int,
|
||||
msg: String,
|
||||
e: RecognitionException
|
||||
) {
|
||||
if (e is LexerNoViableAltException) {
|
||||
val sourcePosition = SourcePosition(line, charPositionInLine + 1)
|
||||
val lexerError = LexerError(LexerErrorType.NO_VIABLE_ALTERNATIVE, sourcePosition)
|
||||
errors.add(lexerError)
|
||||
} else {
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
override fun reportAmbiguity(
|
||||
recognizer: Parser?,
|
||||
dfa: DFA?,
|
||||
startIndex: Int,
|
||||
stopIndex: Int,
|
||||
exact: Boolean,
|
||||
ambigAlts: BitSet?,
|
||||
configs: ATNConfigSet?
|
||||
) {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
override fun reportAttemptingFullContext(
|
||||
recognizer: Parser?,
|
||||
dfa: DFA?,
|
||||
startIndex: Int,
|
||||
stopIndex: Int,
|
||||
conflictingAlts: BitSet?,
|
||||
configs: ATNConfigSet?
|
||||
) {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
override fun reportContextSensitivity(
|
||||
recognizer: Parser?,
|
||||
dfa: DFA?,
|
||||
startIndex: Int,
|
||||
stopIndex: Int,
|
||||
prediction: Int,
|
||||
configs: ATNConfigSet?
|
||||
) {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
package groowt.view.component.web.antlr
|
||||
|
||||
enum class LexerErrorType(val message: String) {
|
||||
NO_VIABLE_ALTERNATIVE("No viable alternative.")
|
||||
}
|
@ -70,7 +70,7 @@ fun isIdentifierStartChar(c: Char): Boolean = Character.isJavaIdentifierStart(c)
|
||||
|
||||
fun isIdentifierStartChar(subject: Int) = isIdentifierStartChar(subject.toChar())
|
||||
|
||||
fun isIdentifierChar(c: Char): Boolean = Character.isJavaIdentifierPart(c)
|
||||
fun isIdentifierChar(c: Char): Boolean = Character.isJavaIdentifierPart(c) || c == '-'
|
||||
|
||||
fun isIdentifierChar(subject: Int) = isIdentifierChar(subject.toChar())
|
||||
|
||||
|
@ -4,4 +4,12 @@ package groowt.view.component.web.antlr
|
||||
import org.antlr.v4.runtime.CharStream
|
||||
import org.antlr.v4.runtime.Token
|
||||
|
||||
fun runLexerAllTokens(input: CharStream): List<Token> = WebViewComponentsLexer(input).allTokens
|
||||
fun runLexerAllTokensRaw(input: CharStream): List<Token> = WebViewComponentsLexer(input).allTokens
|
||||
|
||||
fun runLexerAllTokens(input: CharStream, withEOF: Boolean = false): List<Token> {
|
||||
val lexer = WebViewComponentsLexer(input)
|
||||
val stream = WebViewComponentsTokenStream(lexer)
|
||||
return if (withEOF) stream.getAllTokens() else stream.getAllTokens()
|
||||
}
|
||||
|
||||
fun runLexerAllTokens(input: CharStream) = runLexerAllTokens(input, withEOF = false)
|
||||
|
@ -0,0 +1,50 @@
|
||||
package groowt.view.component.web.antlr
|
||||
|
||||
import groowt.view.component.web.util.SourcePosition
|
||||
import groowt.view.component.web.util.excerpt
|
||||
import org.antlr.v4.runtime.ParserRuleContext
|
||||
import org.antlr.v4.runtime.Token
|
||||
|
||||
open class ParserError(val type: ParserErrorType, val offending: Token, val context: ParserRuleContext)
|
||||
|
||||
class MismatchedInputParserError(
|
||||
type: ParserErrorType,
|
||||
offending: Token,
|
||||
context: ParserRuleContext,
|
||||
val expectedTokenTypes: Set<Int>
|
||||
) : ParserError(type, offending, context)
|
||||
|
||||
fun format(error: ParserError): String {
|
||||
val sb = StringBuilder()
|
||||
val sourcePosition = SourcePosition.fromStartOfToken(error.offending)
|
||||
sb.append("At ")
|
||||
.append(sourcePosition.toStringLong())
|
||||
.append(": ")
|
||||
.append(error.type.message)
|
||||
.append(" Offending token: ")
|
||||
.append(formatTokenForError(error.offending))
|
||||
.append(". ")
|
||||
if (error is MismatchedInputParserError) {
|
||||
sb.append("Expected any of: ")
|
||||
.append(formatExpected(error.expectedTokenTypes))
|
||||
.append(". ")
|
||||
}
|
||||
sb.append("(" + formatContext(error.context) + ").")
|
||||
return sb.toString()
|
||||
}
|
||||
|
||||
private fun formatTokenForError(token: Token): String {
|
||||
return "'${token.text}' (${getTokenName(token)})"
|
||||
}
|
||||
|
||||
private fun formatContext(context: ParserRuleContext): String {
|
||||
val sb = StringBuilder()
|
||||
sb.append("context: ${context.javaClass.simpleName}")
|
||||
if (context.text.isNotEmpty()) {
|
||||
sb.append(", text: ")
|
||||
.append(escapeChars(excerpt(context.text)))
|
||||
}
|
||||
return sb.toString()
|
||||
}
|
||||
|
||||
private fun formatExpected(expectedTokenTypes: Set<Int>): String = expectedTokenTypes.joinToString { getTokenName(it) }
|
@ -0,0 +1,41 @@
|
||||
package groowt.view.component.web.antlr
|
||||
|
||||
import org.antlr.v4.runtime.*
|
||||
|
||||
class ParserErrorListener : BaseErrorListener() {
|
||||
|
||||
private val errors: MutableList<ParserError> = ArrayList()
|
||||
|
||||
fun getErrors(): List<ParserError> = this.errors
|
||||
|
||||
override fun syntaxError(
|
||||
recognizer: Recognizer<*, *>,
|
||||
offendingSymbol: Any,
|
||||
line: Int,
|
||||
charPositionInLine: Int,
|
||||
msg: String,
|
||||
e: RecognitionException
|
||||
) {
|
||||
val parser = recognizer as WebViewComponentsParser
|
||||
when (e) {
|
||||
is NoViableAltException -> {
|
||||
val error = ParserError(ParserErrorType.NO_VIABLE_ALTERNATIVE, e.offendingToken, parser.context)
|
||||
errors.add(error)
|
||||
}
|
||||
is InputMismatchException -> {
|
||||
val error = MismatchedInputParserError(
|
||||
ParserErrorType.INPUT_MISMATCH,
|
||||
e.offendingToken,
|
||||
parser.context,
|
||||
e.expectedTokens.toSet()
|
||||
)
|
||||
errors.add(error)
|
||||
}
|
||||
is FailedPredicateException -> {
|
||||
val error = ParserError(ParserErrorType.FAILED_PREDICATE, e.offendingToken, parser.context)
|
||||
errors.add(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package groowt.view.component.web.antlr
|
||||
|
||||
enum class ParserErrorType(val message: String) {
|
||||
NO_VIABLE_ALTERNATIVE("No viable alternative."),
|
||||
INPUT_MISMATCH("Input mismatch."),
|
||||
FAILED_PREDICATE("Input failed predicate.")
|
||||
}
|
@ -38,9 +38,6 @@ fun parseCompilationUnit(charStream: CharStream): CompilationUnitParseResult {
|
||||
return CompilationUnitParseResult(lexer, tokenStream, parser, cu)
|
||||
}
|
||||
|
||||
fun parseCompilationUnit(tokenStream: TokenStream): CompilationUnitContext =
|
||||
parse(tokenStream, WebViewComponentsParser::compilationUnit)
|
||||
|
||||
fun parseCompilationUnit(
|
||||
tokenStream: TokenStream,
|
||||
onResult: BiConsumer<CompilationUnitContext, WebViewComponentsParser>
|
||||
|
@ -3,17 +3,18 @@ package groowt.view.component.web.antlr
|
||||
|
||||
import groowt.view.component.web.antlr.WebViewComponentsLexer.GStringParts
|
||||
import groowt.view.component.web.antlr.WebViewComponentsLexer.GroovyTokens
|
||||
import groowt.view.component.web.util.SourcePosition
|
||||
import org.antlr.v4.runtime.Token
|
||||
|
||||
fun isGroovyTokenType(token: Token) = isGroovyTokenType(token.type)
|
||||
|
||||
fun isGroovyTokenType(type: Int): Boolean = type in GroovyTokens
|
||||
|
||||
fun isGStringPart (token: Token) = isGStringPart(token.type)
|
||||
fun isGStringPart(token: Token) = isGStringPart(token.type)
|
||||
|
||||
fun isGStringPart(type: Int): Boolean = type in GStringParts
|
||||
|
||||
fun getTokenName (token: Token) = getTokenName(token.type)
|
||||
fun getTokenName(token: Token) = getTokenName(token.type)
|
||||
|
||||
fun getTokenName(type: Int): String = WebViewComponentsLexer.VOCABULARY.getDisplayName(type)
|
||||
|
||||
@ -25,15 +26,17 @@ fun interface TokenTextFormatter {
|
||||
}
|
||||
|
||||
fun formatToken(token: Token, textFormatter: TokenTextFormatter): String =
|
||||
"${getTokenName(token)}[${token.line},${token.charPositionInLine}](${textFormatter.format(token.text)})"
|
||||
|
||||
fun shortFormatToken(token: Token): String =
|
||||
"${getTokenName(token)}[${token.line},${token.charPositionInLine},${token.text.length}]"
|
||||
getTokenName(token) + "[${formatTokenPositionShort(token)}](${textFormatter.format(token.text)})"
|
||||
|
||||
fun formatTokenText(text: String): String = excerptTokenParts(escapeTokenPartsToList(text))
|
||||
|
||||
fun formatTokenPosition(token: Token): String {
|
||||
return "line ${token.line}, column ${token.charPositionInLine + 1}"
|
||||
fun formatTokenPositionShort(token: Token): String {
|
||||
val sourcePosition = getTokenSourcePosition(token)
|
||||
return "${sourcePosition.line},${sourcePosition.column}"
|
||||
}
|
||||
|
||||
fun getTokenSourcePosition(token: Token): SourcePosition {
|
||||
return SourcePosition(token.line, token.charPositionInLine + 1)
|
||||
}
|
||||
|
||||
fun excerptToken(token: Token) = excerptToken(token, 30, 7, "...")
|
||||
@ -42,7 +45,7 @@ fun excerptToken(token: Token, startLength: Int = 30, endLength: Int = 7, separa
|
||||
return excerptTokenParts(escapeTokenPartsToList(token.text), startLength, endLength, separator)
|
||||
}
|
||||
|
||||
fun excerptTokenParts(
|
||||
private fun excerptTokenParts(
|
||||
parts: List<String>,
|
||||
startLength: Int = 30,
|
||||
endLength: Int = 7,
|
||||
|
@ -7,7 +7,7 @@ private operator fun Interval.component1(): Int = this.a
|
||||
|
||||
private operator fun Interval.component2(): Int = this.b
|
||||
|
||||
class WebViewComponentsTokenStream (private val tokenSource: TokenSource) : TokenStream {
|
||||
class WebViewComponentsTokenStream(private val tokenSource: TokenSource) : TokenStream {
|
||||
|
||||
private val tokens: MutableList<Token> = ArrayList()
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
package groowt.view.component.web.ast;
|
||||
|
||||
import groowt.view.component.web.WebViewComponentBugError;
|
||||
import groowt.view.component.web.antlr.MergedGroovyCodeToken;
|
||||
import groowt.view.component.web.antlr.TokenUtil;
|
||||
import groowt.view.component.web.antlr.WebViewComponentsParser;
|
||||
@ -219,16 +220,18 @@ public class DefaultAstBuilderVisitor extends WebViewComponentsParserBaseVisitor
|
||||
|
||||
@Override
|
||||
public Node visitComponentType(WebViewComponentsParser.ComponentTypeContext ctx) {
|
||||
final var identifiers = ctx.Identifier();
|
||||
if (identifiers.size() == 1) {
|
||||
final TerminalNode first = identifiers.getFirst();
|
||||
if (startsWithLowercaseLetter(first.getText())) {
|
||||
return this.nodeFactory.stringComponentTypeNode(
|
||||
this.getTokenRange(ctx), first.getSymbol().getTokenIndex()
|
||||
);
|
||||
}
|
||||
final var typedIdentifier = ctx.TypedIdentifier();
|
||||
if (typedIdentifier != null) {
|
||||
return this.nodeFactory.classComponentTypeNode(this.getTokenRange(ctx));
|
||||
}
|
||||
return this.nodeFactory.classComponentTypeNode(this.getTokenRange(ctx));
|
||||
final var stringIdentifier = ctx.StringIdentifier();
|
||||
if (stringIdentifier != null) {
|
||||
return this.nodeFactory.stringComponentTypeNode(
|
||||
this.getTokenRange(ctx),
|
||||
stringIdentifier.getSymbol().getTokenIndex()
|
||||
);
|
||||
}
|
||||
throw new WebViewComponentBugError("Could not determine type of " + ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -253,7 +256,7 @@ public class DefaultAstBuilderVisitor extends WebViewComponentsParserBaseVisitor
|
||||
|
||||
@Override
|
||||
public Node visitKeyValueAttr(WebViewComponentsParser.KeyValueAttrContext ctx) {
|
||||
final TerminalNode identifier = ctx.Identifier();
|
||||
final TerminalNode identifier = ctx.AttributeIdentifier();
|
||||
final KeyNode keyNode = this.nodeFactory.keyNode(TokenRange.of(
|
||||
identifier.getSymbol(),
|
||||
ctx.Equals().getSymbol()
|
||||
@ -264,7 +267,7 @@ public class DefaultAstBuilderVisitor extends WebViewComponentsParserBaseVisitor
|
||||
|
||||
@Override
|
||||
public Node visitBooleanAttr(WebViewComponentsParser.BooleanAttrContext ctx) {
|
||||
final Token identifierToken = ctx.Identifier().getSymbol();
|
||||
final Token identifierToken = ctx.AttributeIdentifier().getSymbol();
|
||||
final KeyNode keyNode = this.nodeFactory.keyNode(
|
||||
TokenRange.of(identifierToken),
|
||||
identifierToken.getTokenIndex()
|
||||
|
@ -116,7 +116,7 @@ public final class CompilerPipeline {
|
||||
// build ast
|
||||
final var tokenList = new TokenList(parseResult.getTokenStream());
|
||||
final var astBuilder = new DefaultAstBuilder(new DefaultNodeFactory(tokenList));
|
||||
return (CompilationUnitNode) astBuilder.build(parseResult.getCompilationUnitContext());
|
||||
return astBuilder.buildCompilationUnit(parseResult.getCompilationUnitContext());
|
||||
}
|
||||
|
||||
private CompilerPipeline() {}
|
||||
|
@ -0,0 +1,12 @@
|
||||
@file:JvmName("TextUtil")
|
||||
package groowt.view.component.web.util
|
||||
|
||||
fun excerpt(s: String, startLength: Int = 30, endLength: Int = 7, ellipsis: String = "..."): String {
|
||||
if (s.length > startLength + endLength + ellipsis.length) {
|
||||
val start = s.substring(0..<startLength)
|
||||
val end = s.substring((s.length - endLength)..<s.length)
|
||||
return start + ellipsis + end
|
||||
} else {
|
||||
return s
|
||||
}
|
||||
}
|
@ -1,75 +1,69 @@
|
||||
CompilationUnitNode(1,1..21,6)
|
||||
PreambleNode(1,1..6,1)
|
||||
PreambleBreak[1,0](---\n)
|
||||
GroovyCode[2,0](import some.Thing // a comment...World!')
|
||||
PreambleBreak[4,30](\n---\n)
|
||||
PreambleBreak[1,1](---\n)
|
||||
GroovyCode[2,1](import some.Thing // a comment...World!')
|
||||
PreambleBreak[4,31](\n---\n)
|
||||
BodyNode(6,1..21,1)
|
||||
JStringBodyTextNode(6,1..7,1)
|
||||
RawText[6,0](<!DOCTYPE html>\n)
|
||||
RawText[6,1](<!DOCTYPE html>\n)
|
||||
TypedComponentNode(7,1..20,8)
|
||||
ComponentArgsNode(7,2..7,6)
|
||||
StringComponentTypeNode(7,2..7,6)
|
||||
Identifier[7,1](html)
|
||||
StringIdentifier[7,2](html)
|
||||
BodyNode(7,7..20,1)
|
||||
TypedComponentNode(8,5..8,18)
|
||||
ComponentArgsNode(8,6..8,10)
|
||||
StringComponentTypeNode(8,6..8,10)
|
||||
Identifier[8,5](head)
|
||||
StringIdentifier[8,6](head)
|
||||
TypedComponentNode(9,5..19,12)
|
||||
ComponentArgsNode(9,6..9,10)
|
||||
StringComponentTypeNode(9,6..9,10)
|
||||
Identifier[9,5](body)
|
||||
StringIdentifier[9,6](body)
|
||||
BodyNode(9,11..19,5)
|
||||
TypedComponentNode(10,9..10,29)
|
||||
ComponentArgsNode(10,10..10,12)
|
||||
StringComponentTypeNode(10,10..10,12)
|
||||
Identifier[10,9](h1)
|
||||
StringIdentifier[10,10](h1)
|
||||
BodyNode(10,13..10,24)
|
||||
GStringBodyTextNode(10,13..10,24)
|
||||
DollarScriptletNode(10,13..10,24)
|
||||
DollarScriptletOpen[10,12](${)
|
||||
GroovyCode[10,14](greeting)
|
||||
DollarScriptletClose[10,22](})
|
||||
DollarScriptletOpen[10,13](${)
|
||||
GroovyCode[10,15](greeting)
|
||||
DollarScriptletClose[10,23](})
|
||||
TypedComponentNode(11,9..18,34)
|
||||
ComponentArgsNode(11,10..11,32)
|
||||
ClassComponentTypeNode(11,10..11,32)
|
||||
Identifier[11,9](groowt)
|
||||
Dot[11,15](.)
|
||||
Identifier[11,16](view)
|
||||
Dot[11,20](.)
|
||||
Identifier[11,21](web)
|
||||
Dot[11,24](.)
|
||||
Identifier[11,25](Select)
|
||||
TypedIdentifier[11,10](groowt.view.web.Select)
|
||||
BodyNode(11,33..18,9)
|
||||
TypedComponentNode(12,13..14,20)
|
||||
ComponentArgsNode(12,14..12,36)
|
||||
ClassComponentTypeNode(12,14..12,18)
|
||||
Identifier[12,13](Case)
|
||||
TypedIdentifier[12,14](Case)
|
||||
KeyValueAttrNode(12,19..12,36)
|
||||
KeyNode(12,19..12,24)
|
||||
Identifier[12,18](cond)
|
||||
Equals[12,22](=)
|
||||
AttributeIdentifier[12,19](cond)
|
||||
Equals[12,23](=)
|
||||
ClosureValueNode(12,24..12,36)
|
||||
ClosureAttrValueStart[12,23]({)
|
||||
GroovyCode[12,24](isItTrue())
|
||||
ClosureAttrValueEnd[12,34](})
|
||||
ClosureAttrValueStart[12,24]({)
|
||||
GroovyCode[12,25](isItTrue())
|
||||
ClosureAttrValueEnd[12,35](})
|
||||
BodyNode(12,37..14,13)
|
||||
TypedComponentNode(13,17..13,37)
|
||||
ComponentArgsNode(13,18..13,19)
|
||||
StringComponentTypeNode(13,18..13,19)
|
||||
Identifier[13,17](p)
|
||||
StringIdentifier[13,18](p)
|
||||
BodyNode(13,20..13,33)
|
||||
JStringBodyTextNode(13,20..13,33)
|
||||
RawText[13,19](It's true! :))
|
||||
RawText[13,20](It's true! :))
|
||||
TypedComponentNode(15,13..17,23)
|
||||
ComponentArgsNode(15,14..15,21)
|
||||
ClassComponentTypeNode(15,14..15,21)
|
||||
Identifier[15,13](Default)
|
||||
TypedIdentifier[15,14](Default)
|
||||
BodyNode(15,22..17,13)
|
||||
TypedComponentNode(16,17..16,40)
|
||||
ComponentArgsNode(16,18..16,19)
|
||||
StringComponentTypeNode(16,18..16,19)
|
||||
Identifier[16,17](p)
|
||||
StringIdentifier[16,18](p)
|
||||
BodyNode(16,20..16,36)
|
||||
JStringBodyTextNode(16,20..16,36)
|
||||
RawText[16,19](It's false... :()
|
||||
RawText[16,20](It's false... :()
|
||||
|
@ -2,9 +2,9 @@ CompilationUnitNode(1,1..2,6)
|
||||
BodyNode(1,1..2,1)
|
||||
GStringBodyTextNode(1,1..2,1)
|
||||
JStringBodyTextNode(1,1..1,8)
|
||||
RawText[1,0](Hello, )
|
||||
RawText[1,1](Hello, )
|
||||
DollarReferenceNode(1,8..1,15)
|
||||
DollarReferenceStart[1,7]($)
|
||||
GroovyCode[1,8](target)
|
||||
DollarReferenceStart[1,8]($)
|
||||
GroovyCode[1,9](target)
|
||||
JStringBodyTextNode(1,15..2,1)
|
||||
RawText[1,14](!\n)
|
||||
RawText[1,15](!\n)
|
||||
|
@ -3,7 +3,7 @@ CompilationUnitNode(1,1..2,6)
|
||||
TypedComponentNode(1,1..1,35)
|
||||
ComponentArgsNode(1,2..1,10)
|
||||
ClassComponentTypeNode(1,2..1,10)
|
||||
Identifier[1,1](Greeting)
|
||||
TypedIdentifier[1,2](Greeting)
|
||||
BodyNode(1,11..1,24)
|
||||
JStringBodyTextNode(1,11..1,24)
|
||||
RawText[1,10](to the world!)
|
||||
RawText[1,11](to the world!)
|
||||
|
20
web-view-components-compiler/src/test/lexer/complicated.wvc
Normal file
20
web-view-components-compiler/src/test/lexer/complicated.wvc
Normal file
@ -0,0 +1,20 @@
|
||||
---
|
||||
import some.Thing // a comment
|
||||
|
||||
def greeting = 'Hello, World!'
|
||||
---
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head></head>
|
||||
<body>
|
||||
<h1>${greeting}</h1>
|
||||
<groowt.view.web.Select>
|
||||
<Case cond={isItTrue()}>
|
||||
<p>It's true! :)</p>
|
||||
</Case>
|
||||
<Default>
|
||||
<p>It's false... :(</p>
|
||||
</Default>
|
||||
</groowt.view.web.Select>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1 @@
|
||||
<data-test />
|
@ -0,0 +1 @@
|
||||
<html></html>
|
@ -0,0 +1 @@
|
||||
<groowt.Test></groowt.Test>
|
@ -0,0 +1,83 @@
|
||||
PreambleBreak[1,1](---\n)
|
||||
GroovyCode[2,1](import some.Thing // a comment...World!')
|
||||
PreambleBreak[4,31](\n---\n)
|
||||
RawText[6,1](<!DOCTYPE html>\n)
|
||||
ComponentOpen[7,1](<)
|
||||
StringIdentifier[7,2](html)
|
||||
ComponentClose[7,6](>)
|
||||
RawText[7,7](\n )
|
||||
ComponentOpen[8,5](<)
|
||||
StringIdentifier[8,6](head)
|
||||
ComponentClose[8,10](>)
|
||||
ClosingComponentOpen[8,11](</)
|
||||
StringIdentifier[8,13](head)
|
||||
ComponentClose[8,17](>)
|
||||
RawText[8,18](\n )
|
||||
ComponentOpen[9,5](<)
|
||||
StringIdentifier[9,6](body)
|
||||
ComponentClose[9,10](>)
|
||||
RawText[9,11](\n )
|
||||
ComponentOpen[10,9](<)
|
||||
StringIdentifier[10,10](h1)
|
||||
ComponentClose[10,12](>)
|
||||
DollarScriptletOpen[10,13](${)
|
||||
GroovyCode[10,15](greeting)
|
||||
DollarScriptletClose[10,23](})
|
||||
ClosingComponentOpen[10,24](</)
|
||||
StringIdentifier[10,26](h1)
|
||||
ComponentClose[10,28](>)
|
||||
RawText[10,29](\n )
|
||||
ComponentOpen[11,9](<)
|
||||
TypedIdentifier[11,10](groowt.view.web.Select)
|
||||
ComponentClose[11,32](>)
|
||||
RawText[11,33](\n )
|
||||
ComponentOpen[12,13](<)
|
||||
TypedIdentifier[12,14](Case)
|
||||
ComponentNlws[12,18]( )
|
||||
AttributeIdentifier[12,19](cond)
|
||||
Equals[12,23](=)
|
||||
ClosureAttrValueStart[12,24]({)
|
||||
GroovyCode[12,25](isItTrue())
|
||||
ClosureAttrValueEnd[12,35](})
|
||||
ComponentClose[12,36](>)
|
||||
RawText[12,37](\n )
|
||||
ComponentOpen[13,17](<)
|
||||
StringIdentifier[13,18](p)
|
||||
ComponentClose[13,19](>)
|
||||
RawText[13,20](It's true! :))
|
||||
ClosingComponentOpen[13,33](</)
|
||||
StringIdentifier[13,35](p)
|
||||
ComponentClose[13,36](>)
|
||||
RawText[13,37](\n )
|
||||
ClosingComponentOpen[14,13](</)
|
||||
TypedIdentifier[14,15](Case)
|
||||
ComponentClose[14,19](>)
|
||||
RawText[14,20](\n )
|
||||
ComponentOpen[15,13](<)
|
||||
TypedIdentifier[15,14](Default)
|
||||
ComponentClose[15,21](>)
|
||||
RawText[15,22](\n )
|
||||
ComponentOpen[16,17](<)
|
||||
StringIdentifier[16,18](p)
|
||||
ComponentClose[16,19](>)
|
||||
RawText[16,20](It's false... :()
|
||||
ClosingComponentOpen[16,36](</)
|
||||
StringIdentifier[16,38](p)
|
||||
ComponentClose[16,39](>)
|
||||
RawText[16,40](\n )
|
||||
ClosingComponentOpen[17,13](</)
|
||||
TypedIdentifier[17,15](Default)
|
||||
ComponentClose[17,22](>)
|
||||
RawText[17,23](\n )
|
||||
ClosingComponentOpen[18,9](</)
|
||||
TypedIdentifier[18,11](groowt.view.web.Select)
|
||||
ComponentClose[18,33](>)
|
||||
RawText[18,34](\n )
|
||||
ClosingComponentOpen[19,5](</)
|
||||
StringIdentifier[19,7](body)
|
||||
ComponentClose[19,11](>)
|
||||
RawText[19,12](\n)
|
||||
ClosingComponentOpen[20,1](</)
|
||||
StringIdentifier[20,3](html)
|
||||
ComponentClose[20,7](>)
|
||||
RawText[20,8](\n)
|
@ -0,0 +1,5 @@
|
||||
ComponentOpen[1,1](<)
|
||||
StringIdentifier[1,2](data-test)
|
||||
ComponentNlws[1,11]( )
|
||||
ComponentSelfClose[1,12](/>)
|
||||
RawText[1,14](\n)
|
@ -0,0 +1,7 @@
|
||||
ComponentOpen[1,1](<)
|
||||
StringIdentifier[1,2](html)
|
||||
ComponentClose[1,6](>)
|
||||
ClosingComponentOpen[1,7](</)
|
||||
StringIdentifier[1,9](html)
|
||||
ComponentClose[1,13](>)
|
||||
RawText[1,14](\n)
|
@ -0,0 +1,7 @@
|
||||
ComponentOpen[1,1](<)
|
||||
TypedIdentifier[1,2](groowt.Test)
|
||||
ComponentClose[1,13](>)
|
||||
ClosingComponentOpen[1,14](</)
|
||||
TypedIdentifier[1,16](groowt.Test)
|
||||
ComponentClose[1,27](>)
|
||||
RawText[1,28](\n)
|
@ -1,4 +1,4 @@
|
||||
RawText[1,0](Hello, )
|
||||
DollarReferenceStart[1,7]($)
|
||||
GroovyCode[1,8](target)
|
||||
RawText[1,14](!\n)
|
||||
RawText[1,1](Hello, )
|
||||
DollarReferenceStart[1,8]($)
|
||||
GroovyCode[1,9](target)
|
||||
RawText[1,15](!\n)
|
@ -1 +1 @@
|
||||
RawText[1,0](Hello, World!\n)
|
||||
RawText[1,1](Hello, World!\n)
|
@ -0,0 +1 @@
|
||||
<html></html>
|
@ -13,7 +13,7 @@ compilationUnit[1,1..21,1]
|
||||
ComponentOpen[7,1](<)
|
||||
componentArgs[7,2..7,2]
|
||||
componentType[7,2..7,2]
|
||||
Identifier[7,2](html)
|
||||
StringIdentifier[7,2](html)
|
||||
ComponentClose[7,6](>)
|
||||
body[7,7..19,12]
|
||||
bodyText[7,7..7,7]
|
||||
@ -25,12 +25,12 @@ compilationUnit[1,1..21,1]
|
||||
ComponentOpen[8,5](<)
|
||||
componentArgs[8,6..8,6]
|
||||
componentType[8,6..8,6]
|
||||
Identifier[8,6](head)
|
||||
StringIdentifier[8,6](head)
|
||||
ComponentClose[8,10](>)
|
||||
closingComponent[8,11..8,17]
|
||||
ClosingComponentOpen[8,11](</)
|
||||
componentType[8,13..8,13]
|
||||
Identifier[8,13](head)
|
||||
StringIdentifier[8,13](head)
|
||||
ComponentClose[8,17](>)
|
||||
bodyText[8,18..8,18]
|
||||
jStringBodyText[8,18..8,18]
|
||||
@ -41,7 +41,7 @@ compilationUnit[1,1..21,1]
|
||||
ComponentOpen[9,5](<)
|
||||
componentArgs[9,6..9,6]
|
||||
componentType[9,6..9,6]
|
||||
Identifier[9,6](body)
|
||||
StringIdentifier[9,6](body)
|
||||
ComponentClose[9,10](>)
|
||||
body[9,11..18,34]
|
||||
bodyText[9,11..9,11]
|
||||
@ -53,7 +53,7 @@ compilationUnit[1,1..21,1]
|
||||
ComponentOpen[10,9](<)
|
||||
componentArgs[10,10..10,10]
|
||||
componentType[10,10..10,10]
|
||||
Identifier[10,10](h1)
|
||||
StringIdentifier[10,10](h1)
|
||||
ComponentClose[10,12](>)
|
||||
body[10,13..10,23]
|
||||
bodyText[10,13..10,23]
|
||||
@ -66,7 +66,7 @@ compilationUnit[1,1..21,1]
|
||||
closingComponent[10,24..10,28]
|
||||
ClosingComponentOpen[10,24](</)
|
||||
componentType[10,26..10,26]
|
||||
Identifier[10,26](h1)
|
||||
StringIdentifier[10,26](h1)
|
||||
ComponentClose[10,28](>)
|
||||
bodyText[10,29..10,29]
|
||||
jStringBodyText[10,29..10,29]
|
||||
@ -75,15 +75,9 @@ compilationUnit[1,1..21,1]
|
||||
componentWithChildren[11,9..18,33]
|
||||
openComponent[11,9..11,32]
|
||||
ComponentOpen[11,9](<)
|
||||
componentArgs[11,10..11,26]
|
||||
componentType[11,10..11,26]
|
||||
Identifier[11,10](groowt)
|
||||
Dot[11,16](.)
|
||||
Identifier[11,17](view)
|
||||
Dot[11,21](.)
|
||||
Identifier[11,22](web)
|
||||
Dot[11,25](.)
|
||||
Identifier[11,26](Select)
|
||||
componentArgs[11,10..11,10]
|
||||
componentType[11,10..11,10]
|
||||
TypedIdentifier[11,10](groowt.view.web.Select)
|
||||
ComponentClose[11,32](>)
|
||||
body[11,33..17,23]
|
||||
bodyText[11,33..11,33]
|
||||
@ -95,11 +89,11 @@ compilationUnit[1,1..21,1]
|
||||
ComponentOpen[12,13](<)
|
||||
componentArgs[12,14..12,35]
|
||||
componentType[12,14..12,14]
|
||||
Identifier[12,14](Case)
|
||||
TypedIdentifier[12,14](Case)
|
||||
ComponentNlws[12,18]( )
|
||||
attr[12,19..12,35]
|
||||
keyValueAttr[12,19..12,35]
|
||||
Identifier[12,19](cond)
|
||||
AttributeIdentifier[12,19](cond)
|
||||
Equals[12,23](=)
|
||||
value[12,24..12,35]
|
||||
closureAttrValue[12,24..12,35]
|
||||
@ -117,7 +111,7 @@ compilationUnit[1,1..21,1]
|
||||
ComponentOpen[13,17](<)
|
||||
componentArgs[13,18..13,18]
|
||||
componentType[13,18..13,18]
|
||||
Identifier[13,18](p)
|
||||
StringIdentifier[13,18](p)
|
||||
ComponentClose[13,19](>)
|
||||
body[13,20..13,20]
|
||||
bodyText[13,20..13,20]
|
||||
@ -126,7 +120,7 @@ compilationUnit[1,1..21,1]
|
||||
closingComponent[13,33..13,36]
|
||||
ClosingComponentOpen[13,33](</)
|
||||
componentType[13,35..13,35]
|
||||
Identifier[13,35](p)
|
||||
StringIdentifier[13,35](p)
|
||||
ComponentClose[13,36](>)
|
||||
bodyText[13,37..13,37]
|
||||
jStringBodyText[13,37..13,37]
|
||||
@ -134,7 +128,7 @@ compilationUnit[1,1..21,1]
|
||||
closingComponent[14,13..14,19]
|
||||
ClosingComponentOpen[14,13](</)
|
||||
componentType[14,15..14,15]
|
||||
Identifier[14,15](Case)
|
||||
TypedIdentifier[14,15](Case)
|
||||
ComponentClose[14,19](>)
|
||||
bodyText[14,20..14,20]
|
||||
jStringBodyText[14,20..14,20]
|
||||
@ -145,7 +139,7 @@ compilationUnit[1,1..21,1]
|
||||
ComponentOpen[15,13](<)
|
||||
componentArgs[15,14..15,14]
|
||||
componentType[15,14..15,14]
|
||||
Identifier[15,14](Default)
|
||||
TypedIdentifier[15,14](Default)
|
||||
ComponentClose[15,21](>)
|
||||
body[15,22..16,40]
|
||||
bodyText[15,22..15,22]
|
||||
@ -157,7 +151,7 @@ compilationUnit[1,1..21,1]
|
||||
ComponentOpen[16,17](<)
|
||||
componentArgs[16,18..16,18]
|
||||
componentType[16,18..16,18]
|
||||
Identifier[16,18](p)
|
||||
StringIdentifier[16,18](p)
|
||||
ComponentClose[16,19](>)
|
||||
body[16,20..16,20]
|
||||
bodyText[16,20..16,20]
|
||||
@ -166,7 +160,7 @@ compilationUnit[1,1..21,1]
|
||||
closingComponent[16,36..16,39]
|
||||
ClosingComponentOpen[16,36](</)
|
||||
componentType[16,38..16,38]
|
||||
Identifier[16,38](p)
|
||||
StringIdentifier[16,38](p)
|
||||
ComponentClose[16,39](>)
|
||||
bodyText[16,40..16,40]
|
||||
jStringBodyText[16,40..16,40]
|
||||
@ -174,21 +168,15 @@ compilationUnit[1,1..21,1]
|
||||
closingComponent[17,13..17,22]
|
||||
ClosingComponentOpen[17,13](</)
|
||||
componentType[17,15..17,15]
|
||||
Identifier[17,15](Default)
|
||||
TypedIdentifier[17,15](Default)
|
||||
ComponentClose[17,22](>)
|
||||
bodyText[17,23..17,23]
|
||||
jStringBodyText[17,23..17,23]
|
||||
RawText[17,23](\n )
|
||||
closingComponent[18,9..18,33]
|
||||
ClosingComponentOpen[18,9](</)
|
||||
componentType[18,11..18,27]
|
||||
Identifier[18,11](groowt)
|
||||
Dot[18,17](.)
|
||||
Identifier[18,18](view)
|
||||
Dot[18,22](.)
|
||||
Identifier[18,23](web)
|
||||
Dot[18,26](.)
|
||||
Identifier[18,27](Select)
|
||||
componentType[18,11..18,11]
|
||||
TypedIdentifier[18,11](groowt.view.web.Select)
|
||||
ComponentClose[18,33](>)
|
||||
bodyText[18,34..18,34]
|
||||
jStringBodyText[18,34..18,34]
|
||||
@ -196,7 +184,7 @@ compilationUnit[1,1..21,1]
|
||||
closingComponent[19,5..19,11]
|
||||
ClosingComponentOpen[19,5](</)
|
||||
componentType[19,7..19,7]
|
||||
Identifier[19,7](body)
|
||||
StringIdentifier[19,7](body)
|
||||
ComponentClose[19,11](>)
|
||||
bodyText[19,12..19,12]
|
||||
jStringBodyText[19,12..19,12]
|
||||
@ -204,7 +192,7 @@ compilationUnit[1,1..21,1]
|
||||
closingComponent[20,1..20,7]
|
||||
ClosingComponentOpen[20,1](</)
|
||||
componentType[20,3..20,3]
|
||||
Identifier[20,3](html)
|
||||
StringIdentifier[20,3](html)
|
||||
ComponentClose[20,7](>)
|
||||
bodyText[20,8..20,8]
|
||||
jStringBodyText[20,8..20,8]
|
||||
|
@ -0,0 +1,19 @@
|
||||
compilationUnit[1,1..2,1]
|
||||
body[1,1..1,14]
|
||||
component[1,1..1,13]
|
||||
componentWithChildren[1,1..1,13]
|
||||
openComponent[1,1..1,6]
|
||||
ComponentOpen[1,1](<)
|
||||
componentArgs[1,2..1,2]
|
||||
componentType[1,2..1,2]
|
||||
StringIdentifier[1,2](html)
|
||||
ComponentClose[1,6](>)
|
||||
closingComponent[1,7..1,13]
|
||||
ClosingComponentOpen[1,7](</)
|
||||
componentType[1,9..1,9]
|
||||
StringIdentifier[1,9](html)
|
||||
ComponentClose[1,13](>)
|
||||
bodyText[1,14..1,14]
|
||||
jStringBodyText[1,14..1,14]
|
||||
RawText[1,14](\n)
|
||||
EOF[2,1](<EOF>)
|
@ -5,7 +5,6 @@ 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.CompilationUnitNode;
|
||||
import groowt.view.component.web.compiler.WebViewComponentTemplateCompileUnit;
|
||||
import groowt.view.component.web.transpile.BodyTranspiler;
|
||||
import groowt.view.component.web.transpile.TranspilerConfiguration;
|
||||
@ -39,7 +38,7 @@ public abstract class BodyTranspilerTests {
|
||||
final var parseResult = ParserUtil.parseCompilationUnit(source);
|
||||
final var tokenList = new TokenList(parseResult.getTokenStream());
|
||||
final var b = new DefaultAstBuilder(new DefaultNodeFactory(tokenList));
|
||||
final var cuNode = (CompilationUnitNode) b.build(parseResult.getCompilationUnitContext());
|
||||
final var cuNode = b.buildCompilationUnit(parseResult.getCompilationUnitContext());
|
||||
final var bodyNode = cuNode.getBodyNode();
|
||||
if (bodyNode == null) {
|
||||
fail("No BodyNode was built for source: " + source);
|
||||
|
@ -5,7 +5,6 @@ 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.CompilationUnitNode;
|
||||
import groowt.view.component.web.ast.node.GStringBodyTextNode;
|
||||
import groowt.view.component.web.transpile.GStringTranspiler;
|
||||
import org.codehaus.groovy.ast.expr.ClosureExpression;
|
||||
@ -34,7 +33,7 @@ public abstract class GStringTranspilerTests {
|
||||
final var tokenList = new TokenList(parseResult.getTokenStream());
|
||||
final var nodeFactory = new DefaultNodeFactory(tokenList);
|
||||
final var astBuilder = new DefaultAstBuilder(nodeFactory);
|
||||
final var cuNode = (CompilationUnitNode) astBuilder.build(parseResult.getCompilationUnitContext());
|
||||
final var cuNode = astBuilder.buildCompilationUnit(parseResult.getCompilationUnitContext());
|
||||
return Objects.requireNonNull(cuNode.getBodyNode());
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,6 @@ 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.CompilationUnitNode;
|
||||
import groowt.view.component.web.compiler.AnonymousWebViewComponent;
|
||||
import groowt.view.component.web.compiler.DefaultWebViewComponentTemplateCompileUnit;
|
||||
import groowt.view.component.web.transpile.GroovyTranspiler;
|
||||
@ -39,7 +38,7 @@ public abstract class GroovyTranspilerTests {
|
||||
final var parseResult = ParserUtil.parseCompilationUnit(source);
|
||||
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 cuNode = astBuilder.buildCompilationUnit(parseResult.getCompilationUnitContext());
|
||||
try {
|
||||
this.transpiler.transpile(
|
||||
new DefaultComponentTemplateCompilerConfiguration(),
|
||||
|
@ -3,8 +3,10 @@ package groowt.view.component.web.tools
|
||||
import groovy.transform.InheritConstructors
|
||||
import groowt.view.component.web.antlr.*
|
||||
import groowt.view.component.web.antlr.AntlrUtil.ParseErrorCollector
|
||||
import groowt.view.component.web.antlr.WebViewComponentsParser.CompilationUnitContext
|
||||
import groowt.view.component.web.util.ExtensionUtil
|
||||
import org.antlr.v4.runtime.CharStreams
|
||||
import org.antlr.v4.runtime.ConsoleErrorListener
|
||||
|
||||
@InheritConstructors
|
||||
final class ParseTreeFileMaker extends AbstractOutputFileMaker {
|
||||
@ -36,7 +38,7 @@ final class ParseTreeFileMaker extends AbstractOutputFileMaker {
|
||||
private boolean onErrors(
|
||||
String name,
|
||||
WebViewComponentsParser parser,
|
||||
WebViewComponentsParser.CompilationUnitContext cu,
|
||||
CompilationUnitContext cu,
|
||||
ParseErrorCollector errors
|
||||
) {
|
||||
def errorCount = errors.errorCount
|
||||
@ -53,14 +55,35 @@ final class ParseTreeFileMaker extends AbstractOutputFileMaker {
|
||||
}
|
||||
}
|
||||
|
||||
private Tuple3<WebViewComponentsParser, WebViewComponentsParser.CompilationUnitContext, ParseErrorCollector> parse(
|
||||
File sourceFile
|
||||
) {
|
||||
private Tuple3<WebViewComponentsParser, CompilationUnitContext, ParseErrorCollector> parse(File sourceFile) {
|
||||
def input = CharStreams.fromFileName(sourceFile.toString())
|
||||
|
||||
def lexer = new WebViewComponentsLexer(input)
|
||||
def lexerErrorListener = new LexerErrorListener()
|
||||
lexer.removeErrorListener(ConsoleErrorListener.INSTANCE)
|
||||
lexer.addErrorListener(lexerErrorListener)
|
||||
|
||||
def tokenStream = new WebViewComponentsTokenStream(lexer)
|
||||
|
||||
def parser = new WebViewComponentsParser(tokenStream)
|
||||
def parserErrorListener = new ParserErrorListener()
|
||||
parser.removeErrorListener(ConsoleErrorListener.INSTANCE)
|
||||
parser.addErrorListener(parserErrorListener)
|
||||
|
||||
def cu = parser.compilationUnit()
|
||||
|
||||
if (!lexerErrorListener.errors.isEmpty()) {
|
||||
println 'There were lexer errors.'
|
||||
lexerErrorListener.errors.each { println LexerErrorKt.format(it) }
|
||||
return null
|
||||
}
|
||||
|
||||
if (!parserErrorListener.errors.isEmpty()) {
|
||||
println 'There were parser errors.'
|
||||
parserErrorListener.errors.each { println ParserErrorKt.format(it) }
|
||||
return null
|
||||
}
|
||||
|
||||
def errors = AntlrUtil.findErrorNodes(cu)
|
||||
new Tuple3<>(parser, cu, errors)
|
||||
}
|
||||
@ -71,11 +94,27 @@ final class ParseTreeFileMaker extends AbstractOutputFileMaker {
|
||||
println "Processing: $name"
|
||||
boolean doneYet = false
|
||||
while (!doneYet) {
|
||||
def (parser, cu, errors) = this.parse(sourceFile)
|
||||
if (errors.isEmpty()) {
|
||||
doneYet = this.onSuccess(name, parser, cu)
|
||||
} else {
|
||||
doneYet = this.onErrors(name, parser, cu, errors)
|
||||
final WebViewComponentsParser parser
|
||||
final CompilationUnitContext cu
|
||||
final ParseErrorCollector errors
|
||||
try {
|
||||
def result = this.parse(sourceFile)
|
||||
if (result != null) {
|
||||
(parser, cu, errors) = result
|
||||
if (errors.isEmpty()) {
|
||||
doneYet = this.onSuccess(name, parser, cu)
|
||||
} else {
|
||||
doneYet = this.onErrors(name, parser, cu, errors)
|
||||
}
|
||||
} else {
|
||||
doneYet = !this.getYesNoInput('Would you like to try again? (y/n)', true)
|
||||
}
|
||||
} catch (Exception e) {
|
||||
println "There was an exception: $e"
|
||||
if (this.verbose) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
doneYet = !this.getYesNoInput('Would you like to try again? (y/n)', true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,10 @@
|
||||
package groowt.view.component.web.tools
|
||||
|
||||
import groovy.transform.InheritConstructors
|
||||
import groowt.view.component.web.antlr.TokenUtil
|
||||
import groowt.view.component.web.antlr.WebViewComponentsLexer
|
||||
import groowt.view.component.web.antlr.WebViewComponentsTokenStream
|
||||
import groowt.view.component.web.antlr.*
|
||||
import groowt.view.component.web.util.ExtensionUtil
|
||||
import org.antlr.v4.runtime.CharStreams
|
||||
import org.antlr.v4.runtime.ConsoleErrorListener
|
||||
import org.antlr.v4.runtime.Token
|
||||
|
||||
@InheritConstructors
|
||||
@ -25,6 +24,18 @@ class TokensFileMaker extends AbstractOutputFileMaker {
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean onLexerErrors(String name, List<LexerError> errors) {
|
||||
println "There were lexer errors in $name."
|
||||
errors.each { println LexerError.format(it) }
|
||||
if (this.getYesNoInput('Do you wish to try again? (y/n)', true)) {
|
||||
println "Trying $name again..."
|
||||
return false
|
||||
} else {
|
||||
println "Skipping $name..."
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean onException(String name, Exception e) {
|
||||
println "There was an exception while tokenizing $name: $e.message"
|
||||
e.printStackTrace()
|
||||
@ -46,8 +57,16 @@ class TokensFileMaker extends AbstractOutputFileMaker {
|
||||
try {
|
||||
def input = CharStreams.fromString(sourceFile.getText())
|
||||
def lexer = new WebViewComponentsLexer(input)
|
||||
lexer.removeErrorListener(ConsoleErrorListener.INSTANCE)
|
||||
def lexerErrorListener = new LexerErrorListener()
|
||||
lexer.addErrorListener(lexerErrorListener)
|
||||
def tokenStream = new WebViewComponentsTokenStream(lexer)
|
||||
doneYet = this.onSuccess(name, tokenStream.getAllTokensSkipEOF())
|
||||
def allTokens = tokenStream.getAllTokensSkipEOF()
|
||||
if (!lexerErrorListener.errors.isEmpty()) {
|
||||
|
||||
} else {
|
||||
doneYet = this.onSuccess(name, allTokens)
|
||||
}
|
||||
} catch (Exception e) {
|
||||
doneYet = this.onException(name, e)
|
||||
}
|
||||
|
@ -2,11 +2,11 @@
|
||||
package groowt.view.component.web.tools
|
||||
|
||||
import groowt.view.component.web.antlr.formatToken
|
||||
import groowt.view.component.web.antlr.runLexerAllTokens
|
||||
import groowt.view.component.web.antlr.runLexerAllTokensRaw
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val options = processArgs(args)
|
||||
configureLog(options.logLevel)
|
||||
val input = getInput(options.source)
|
||||
runLexerAllTokens(input).forEachIndexed { i, t -> println("$i: ${formatToken(t)}") }
|
||||
runLexerAllTokensRaw(input).forEachIndexed { i, t -> println("$i: ${formatToken(t)}") }
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user