Working on tools and tests.
This commit is contained in:
		
							parent
							
								
									f0b133bb22
								
							
						
					
					
						commit
						449c83975f
					
				| @ -157,6 +157,7 @@ def toolSpec = { String name, String mainClass -> | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| final List<ToolSpec> toolSpecs = [ | final List<ToolSpec> toolSpecs = [ | ||||||
|  |         toolSpec('astBuilder', 'AstBuilder'), | ||||||
|         toolSpec('astFileMaker', 'AstFileMakerCli'), // deprecated |         toolSpec('astFileMaker', 'AstFileMakerCli'), // deprecated | ||||||
|         toolSpec('convertToGroovy', 'ConvertToGroovy'), |         toolSpec('convertToGroovy', 'ConvertToGroovy'), | ||||||
|         toolSpec('groovyWvc', 'GroovyWvcCompiler'), |         toolSpec('groovyWvc', 'GroovyWvcCompiler'), | ||||||
|  | |||||||
							
								
								
									
										10
									
								
								web-view-components-compiler/makeAstTest
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										10
									
								
								web-view-components-compiler/makeAstTest
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,10 @@ | |||||||
|  | #!/usr/bin/env bash | ||||||
|  | 
 | ||||||
|  | ARGS="-v -d src/test/ast/ast-files -s _ast -e .txt" | ||||||
|  | 
 | ||||||
|  | if [ "$1" == "--debug" ]; then | ||||||
|  |     shift | ||||||
|  |     bin/astBuilder --debug $ARGS "$@" | ||||||
|  | else | ||||||
|  |     bin/astBuilder $ARGS "$@" | ||||||
|  | fi | ||||||
| @ -1,7 +1,7 @@ | |||||||
| lexer grammar LexerFragments; | lexer grammar LexerFragments; | ||||||
| 
 | 
 | ||||||
| fragment | fragment | ||||||
| NL : [\n\r] ; | NL : '\n' | '\r\n' ; | ||||||
| 
 | 
 | ||||||
| fragment | fragment | ||||||
| WS : [ \t] ; | WS : [ \t] ; | ||||||
|  | |||||||
| @ -331,7 +331,7 @@ TagError | |||||||
| mode GROOVY_CODE; | mode GROOVY_CODE; | ||||||
| 
 | 
 | ||||||
| PreambleClose | PreambleClose | ||||||
|     :   THREE_DASH { this.inPreamble() && this.getCharPositionInLine() == 3 }? { this.onPreambleClose(); } |     :   THREE_DASH { this.inPreamble() && this.getCharPositionInLine() == 3 }? WS* NL? { this.onPreambleClose(); } | ||||||
|     ; |     ; | ||||||
| 
 | 
 | ||||||
| ScriptletClose | ScriptletClose | ||||||
|  | |||||||
| @ -50,7 +50,7 @@ private fun doCheck(tree: ParseTree, destination: MutableList<MismatchedComponen | |||||||
| 
 | 
 | ||||||
| data class MismatchedComponentTypeError(val component: ComponentWithChildrenContext, val message: String) | data class MismatchedComponentTypeError(val component: ComponentWithChildrenContext, val message: String) | ||||||
| 
 | 
 | ||||||
| fun check(tree: ParseTree): List<MismatchedComponentTypeError> { | fun checkForMismatchedComponentTypeErrors(tree: ParseTree): List<MismatchedComponentTypeError> { | ||||||
|     val result: MutableList<MismatchedComponentTypeError> = ArrayList() |     val result: MutableList<MismatchedComponentTypeError> = ArrayList() | ||||||
|     doCheck(tree, result) |     doCheck(tree, result) | ||||||
|     return result |     return result | ||||||
|  | |||||||
| @ -97,7 +97,7 @@ public final class CompilerPipeline { | |||||||
| 
 | 
 | ||||||
|         // check for mismatched type errors |         // check for mismatched type errors | ||||||
|         final List<MismatchedComponentTypeError> mismatchedComponentTypeErrors = |         final List<MismatchedComponentTypeError> mismatchedComponentTypeErrors = | ||||||
|                 MismatchedComponentTypeAnalysis.check(parseResult.getCompilationUnitContext()); |                 MismatchedComponentTypeAnalysis.checkForMismatchedComponentTypeErrors(parseResult.getCompilationUnitContext()); | ||||||
| 
 | 
 | ||||||
|         if (!mismatchedComponentTypeErrors.isEmpty()) { |         if (!mismatchedComponentTypeErrors.isEmpty()) { | ||||||
|             if (mismatchedComponentTypeErrors.size() == 1) { |             if (mismatchedComponentTypeErrors.size() == 1) { | ||||||
|  | |||||||
| @ -0,0 +1,72 @@ | |||||||
|  | CompilationUnitNode(1,1..21,1) | ||||||
|  |   PreambleNode(1,1..6,1) | ||||||
|  |     PreambleBreak[1,1](---\n) | ||||||
|  |     GroovyCode[2,1](import some.Thing // a comment...rld!'\n) | ||||||
|  |     PreambleBreak[5,1](---\n) | ||||||
|  |   BodyNode(6,1..20,8) | ||||||
|  |     BodyTextNode(6,1..7,1) | ||||||
|  |       TextNode(6,1..7,1) | ||||||
|  |         RawText[6,1](<!DOCTYPE html>\n) | ||||||
|  |     TypedComponentNode(7,1..20,7) | ||||||
|  |       ComponentArgsNode(7,2..7,6) | ||||||
|  |         StringComponentTypeNode(7,2..7,6) | ||||||
|  |           StringIdentifier[7,2](html) | ||||||
|  |       BodyNode(7,7..19,12) | ||||||
|  |         TypedComponentNode(8,5..8,17) | ||||||
|  |           ComponentArgsNode(8,6..8,10) | ||||||
|  |             StringComponentTypeNode(8,6..8,10) | ||||||
|  |               StringIdentifier[8,6](head) | ||||||
|  |         TypedComponentNode(9,5..19,11) | ||||||
|  |           ComponentArgsNode(9,6..9,10) | ||||||
|  |             StringComponentTypeNode(9,6..9,10) | ||||||
|  |               StringIdentifier[9,6](body) | ||||||
|  |           BodyNode(9,11..19,5) | ||||||
|  |             TypedComponentNode(10,9..10,28) | ||||||
|  |               ComponentArgsNode(10,10..10,12) | ||||||
|  |                 StringComponentTypeNode(10,10..10,12) | ||||||
|  |                   StringIdentifier[10,10](h1) | ||||||
|  |               BodyNode(10,13..10,23) | ||||||
|  |                 BodyTextNode(10,13..10,23) | ||||||
|  |                   DollarScriptletNode(10,13..10,23) | ||||||
|  |                     DollarScriptletOpen[10,13](${) | ||||||
|  |                     GroovyCode[10,15](greeting) | ||||||
|  |                     DollarScriptletClose[10,23](}) | ||||||
|  |             TypedComponentNode(11,9..18,33) | ||||||
|  |               ComponentArgsNode(11,10..11,32) | ||||||
|  |                 ClassComponentTypeNode(11,10..11,32) | ||||||
|  |                   TypedIdentifier[11,10](groowt.view.web.Select) | ||||||
|  |               BodyNode(11,33..18,9) | ||||||
|  |                 TypedComponentNode(12,13..14,19) | ||||||
|  |                   ComponentArgsNode(12,14..12,35) | ||||||
|  |                     ClassComponentTypeNode(12,14..12,18) | ||||||
|  |                       TypedIdentifier[12,14](Case) | ||||||
|  |                     KeyValueAttrNode(12,19..12,35) | ||||||
|  |                       KeyNode(12,19..12,23) | ||||||
|  |                         AttributeIdentifier[12,19](cond) | ||||||
|  |                         Equals[12,23](=) | ||||||
|  |                       ClosureValueNode(12,24..12,35) | ||||||
|  |                         ClosureAttrValueStart[12,24]({) | ||||||
|  |                         GroovyCode[12,25](isItTrue()) | ||||||
|  |                         ClosureAttrValueEnd[12,35](}) | ||||||
|  |                   BodyNode(12,37..14,13) | ||||||
|  |                     TypedComponentNode(13,17..13,36) | ||||||
|  |                       ComponentArgsNode(13,18..13,18) | ||||||
|  |                         StringComponentTypeNode(13,18..13,18) | ||||||
|  |                           StringIdentifier[13,18](p) | ||||||
|  |                       BodyNode(13,20..13,33) | ||||||
|  |                         BodyTextNode(13,20..13,33) | ||||||
|  |                           TextNode(13,20..13,33) | ||||||
|  |                             RawText[13,20](It's true! :)) | ||||||
|  |                 TypedComponentNode(15,13..17,22) | ||||||
|  |                   ComponentArgsNode(15,14..15,21) | ||||||
|  |                     ClassComponentTypeNode(15,14..15,21) | ||||||
|  |                       TypedIdentifier[15,14](Default) | ||||||
|  |                   BodyNode(15,22..17,13) | ||||||
|  |                     TypedComponentNode(16,17..16,39) | ||||||
|  |                       ComponentArgsNode(16,18..16,18) | ||||||
|  |                         StringComponentTypeNode(16,18..16,18) | ||||||
|  |                           StringIdentifier[16,18](p) | ||||||
|  |                       BodyNode(16,20..16,36) | ||||||
|  |                         BodyTextNode(16,20..16,36) | ||||||
|  |                           TextNode(16,20..16,36) | ||||||
|  |                             RawText[16,20](It's false... :() | ||||||
| @ -0,0 +1,10 @@ | |||||||
|  | CompilationUnitNode(1,1..2,1) | ||||||
|  |   BodyNode(1,1..2,1) | ||||||
|  |     BodyTextNode(1,1..2,1) | ||||||
|  |       TextNode(1,1..1,8) | ||||||
|  |         RawText[1,1](Hello, ) | ||||||
|  |       DollarReferenceNode(1,8..1,15) | ||||||
|  |         DollarReferenceStart[1,8]($) | ||||||
|  |         GroovyCode[1,9](target) | ||||||
|  |       TextNode(1,15..2,1) | ||||||
|  |         RawText[1,15](!\n) | ||||||
| @ -0,0 +1,5 @@ | |||||||
|  | CompilationUnitNode(1,1..2,1) | ||||||
|  |   BodyNode(1,1..2,1) | ||||||
|  |     BodyTextNode(1,1..2,1) | ||||||
|  |       TextNode(1,1..2,1) | ||||||
|  |         RawText[1,1](Hello, World!\n) | ||||||
| @ -0,0 +1,10 @@ | |||||||
|  | CompilationUnitNode(1,1..2,1) | ||||||
|  |   BodyNode(1,1..1,35) | ||||||
|  |     TypedComponentNode(1,1..1,34) | ||||||
|  |       ComponentArgsNode(1,2..1,10) | ||||||
|  |         ClassComponentTypeNode(1,2..1,10) | ||||||
|  |           TypedIdentifier[1,2](Greeting) | ||||||
|  |       BodyNode(1,11..1,24) | ||||||
|  |         BodyTextNode(1,11..1,24) | ||||||
|  |           TextNode(1,11..1,24) | ||||||
|  |             RawText[1,11](to the world!) | ||||||
							
								
								
									
										1
									
								
								web-view-components-compiler/src/test/ast/helloWorld.wvc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								web-view-components-compiler/src/test/ast/helloWorld.wvc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | |||||||
|  | Hello, World! | ||||||
| @ -10,7 +10,6 @@ import org.junit.jupiter.api.Test | |||||||
| import static groowt.view.component.web.antlr.TokenUtil.getTokenName | import static groowt.view.component.web.antlr.TokenUtil.getTokenName | ||||||
| import static groowt.view.component.web.antlr.WebViewComponentsLexer.GroovyCode | import static groowt.view.component.web.antlr.WebViewComponentsLexer.GroovyCode | ||||||
| import static groowt.view.component.web.antlr.WebViewComponentsLexer.PreambleBreak | import static groowt.view.component.web.antlr.WebViewComponentsLexer.PreambleBreak | ||||||
| import static groowt.view.component.web.antlr.WebViewComponentsLexerBase.RawText |  | ||||||
| import static org.antlr.v4.runtime.Recognizer.EOF | import static org.antlr.v4.runtime.Recognizer.EOF | ||||||
| import static org.junit.jupiter.api.Assertions.* | import static org.junit.jupiter.api.Assertions.* | ||||||
| 
 | 
 | ||||||
| @ -51,11 +50,11 @@ class WebViewComponentsTokenStreamTests { | |||||||
|         def lexer = new WebViewComponentsLexer(input) |         def lexer = new WebViewComponentsLexer(input) | ||||||
|         def tokenStream = new WebViewComponentsTokenStream(lexer) |         def tokenStream = new WebViewComponentsTokenStream(lexer) | ||||||
|         def tokens = tokenStream.allTokens |         def tokens = tokenStream.allTokens | ||||||
|         assertTypes([PreambleBreak, GroovyCode, PreambleBreak, RawText, EOF], tokens) |         assertTypes([PreambleBreak, GroovyCode, PreambleBreak, EOF], tokens) | ||||||
|         assertMergedGroovyCodeToken(tokens[1]) { |         assertMergedGroovyCodeToken(tokens[1]) { | ||||||
|             assertEquals('println \'Hello, World!\' // comment\n', it.text) |             assertEquals('println \'Hello, World!\' // comment\n', it.text) | ||||||
|         } |         } | ||||||
|         assertIterableEquals(0..4, tokens*.tokenIndex) |         assertIterableEquals(0..3, tokens*.tokenIndex) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -8,6 +8,7 @@ import groowt.view.component.web.antlr.WebViewComponentsParser | |||||||
| import groowt.view.component.web.antlr.WebViewComponentsTokenStream | import groowt.view.component.web.antlr.WebViewComponentsTokenStream | ||||||
| import groowt.view.component.web.ast.node.* | import groowt.view.component.web.ast.node.* | ||||||
| import org.antlr.v4.runtime.CharStreams | import org.antlr.v4.runtime.CharStreams | ||||||
|  | import org.junit.jupiter.api.Disabled | ||||||
| import org.junit.jupiter.api.Test | import org.junit.jupiter.api.Test | ||||||
| 
 | 
 | ||||||
| import static groowt.view.component.web.antlr.WebViewComponentsParser.CompilationUnitContext | import static groowt.view.component.web.antlr.WebViewComponentsParser.CompilationUnitContext | ||||||
| @ -52,6 +53,7 @@ class DefaultAstBuilderVisitorTests { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Test |     @Test | ||||||
|  |     @Disabled('Move to file tests.') | ||||||
|     void helloTarget() { |     void helloTarget() { | ||||||
|         def (node, tokenList) = this.doBuild('Hello, $target!') |         def (node, tokenList) = this.doBuild('Hello, $target!') | ||||||
|         assertNodeWith(CompilationUnitNode, node) { |         assertNodeWith(CompilationUnitNode, node) { | ||||||
|  | |||||||
| @ -19,7 +19,7 @@ public class DefaultAstBuilderTests extends AstBuilderTests { | |||||||
|         super( |         super( | ||||||
|                 Path.of("src", "test", "ast"), |                 Path.of("src", "test", "ast"), | ||||||
|                 "*.wvc", |                 "*.wvc", | ||||||
|                 Path.of("src", "test", "ast", "trees"), |                 Path.of("src", "test", "ast", "ast-files"), | ||||||
|                 "_ast.txt" |                 "_ast.txt" | ||||||
|         ); |         ); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| 0: PreambleBreak[1,1](---\n) | 0: PreambleBreak[1,1](---\n) | ||||||
| 1: GroovyCode[2,1](import some.Thing // a comment...rld!'\n) | 1: GroovyCode[2,1](import some.Thing // a comment...rld!'\n) | ||||||
| 2: PreambleBreak[5,1](---) | 2: PreambleBreak[5,1](---\n) | ||||||
| 3: RawText[5,4](\n<!DOCTYPE html>\n) | 3: RawText[6,1](<!DOCTYPE html>\n) | ||||||
| 4: ComponentOpen[7,1](<) | 4: ComponentOpen[7,1](<) | ||||||
| 5: StringIdentifier[7,2](html) | 5: StringIdentifier[7,2](html) | ||||||
| 6: ComponentClose[7,6](>) | 6: ComponentClose[7,6](>) | ||||||
|  | |||||||
| @ -1,4 +1,3 @@ | |||||||
| 0: PreambleBreak[1,1](---) | 0: PreambleBreak[1,1](---) | ||||||
| 1: GroovyCode[1,4](-\n) | 1: GroovyCode[1,4](-\n) | ||||||
| 2: PreambleBreak[2,1](---) | 2: PreambleBreak[2,1](---\n) | ||||||
| 3: RawText[2,4](\n) |  | ||||||
| @ -1,4 +1,3 @@ | |||||||
| 0: PreambleBreak[1,1](---\n) | 0: PreambleBreak[1,1](---\n) | ||||||
| 1: GroovyCode[2,1](// ---\n) | 1: GroovyCode[2,1](// ---\n) | ||||||
| 2: PreambleBreak[3,1](---) | 2: PreambleBreak[3,1](---\n) | ||||||
| 3: RawText[3,4](\n) |  | ||||||
| @ -1,4 +1,3 @@ | |||||||
| 0: PreambleBreak[1,1](---\n) | 0: PreambleBreak[1,1](---\n) | ||||||
| 1: GroovyCode[2,1](def regex = $/match --- me $ $... / /$\n) | 1: GroovyCode[2,1](def regex = $/match --- me $ $... / /$\n) | ||||||
| 2: PreambleBreak[3,1](---) | 2: PreambleBreak[3,1](---\n) | ||||||
| 3: RawText[3,4](\n) |  | ||||||
| @ -1,4 +1,3 @@ | |||||||
| 0: PreambleBreak[1,1](---\n) | 0: PreambleBreak[1,1](---\n) | ||||||
| 1: GroovyCode[2,1](def test = "---$test${test('---')}"\n) | 1: GroovyCode[2,1](def test = "---$test${test('---')}"\n) | ||||||
| 2: PreambleBreak[3,1](---) | 2: PreambleBreak[3,1](---\n) | ||||||
| 3: RawText[3,4](\n) |  | ||||||
| @ -1,4 +1,3 @@ | |||||||
| 0: PreambleBreak[1,1](---\n) | 0: PreambleBreak[1,1](---\n) | ||||||
| 1: GroovyCode[2,1](def test = '---'\n) | 1: GroovyCode[2,1](def test = '---'\n) | ||||||
| 2: PreambleBreak[3,1](---) | 2: PreambleBreak[3,1](---\n) | ||||||
| 3: RawText[3,4](\n) |  | ||||||
| @ -1,4 +1,3 @@ | |||||||
| 0: PreambleBreak[1,1](---\n) | 0: PreambleBreak[1,1](---\n) | ||||||
| 1: GroovyCode[2,1](def regex = (/match --- \/ me/)\n) | 1: GroovyCode[2,1](def regex = (/match --- \/ me/)\n) | ||||||
| 2: PreambleBreak[3,1](---) | 2: PreambleBreak[3,1](---\n) | ||||||
| 3: RawText[3,4](\n) |  | ||||||
| @ -1,4 +1,3 @@ | |||||||
| 0: PreambleBreak[1,1](---\n) | 0: PreambleBreak[1,1](---\n) | ||||||
| 1: GroovyCode[2,1](def test = """\n--- $test ${te...\n"""\n) | 1: GroovyCode[2,1](def test = """\n--- $test ${te...\n"""\n) | ||||||
| 2: PreambleBreak[5,1](---) | 2: PreambleBreak[5,1](---\n) | ||||||
| 3: RawText[5,4](\n) |  | ||||||
| @ -1,4 +1,3 @@ | |||||||
| 0: PreambleBreak[1,1](---\n) | 0: PreambleBreak[1,1](---\n) | ||||||
| 1: GroovyCode[2,1](def test = '''\n---\n'''\n) | 1: GroovyCode[2,1](def test = '''\n---\n'''\n) | ||||||
| 2: PreambleBreak[5,1](---) | 2: PreambleBreak[5,1](---\n) | ||||||
| 3: RawText[5,4](\n) |  | ||||||
| @ -1,4 +1,3 @@ | |||||||
| 0: PreambleBreak[1,1](---\n) | 0: PreambleBreak[1,1](---\n) | ||||||
| 1: GroovyCode[2,1](package test\n) | 1: GroovyCode[2,1](package test\n) | ||||||
| 2: PreambleBreak[3,1](---) | 2: PreambleBreak[3,1](---\n) | ||||||
| 3: RawText[3,4](\n) |  | ||||||
| @ -1,12 +1,12 @@ | |||||||
| compilationUnit[1,1..21,1] | compilationUnit[1,1..21,1] | ||||||
|   preamble[1,1..5,4] |   preamble[1,1..6,1] | ||||||
|     PreambleBreak[1,1](---\n) |     PreambleBreak[1,1](---\n) | ||||||
|     GroovyCode[2,1](import some.Thing // a comment\n\ndef greeting = 'Hello, World!'\n) |     GroovyCode[2,1](import some.Thing // a comment\n\ndef greeting = 'Hello, World!'\n) | ||||||
|     PreambleBreak[5,1](---) |     PreambleBreak[5,1](---\n) | ||||||
|   body[5,4..20,8] |   body[6,1..20,8] | ||||||
|     bodyText[5,4..7,1] |     bodyText[6,1..7,1] | ||||||
|       text[5,4..7,1] |       text[6,1..7,1] | ||||||
|         RawText[5,4](\n<!DOCTYPE html>\n) |         RawText[6,1](<!DOCTYPE html>\n) | ||||||
|     component[7,1..20,7] |     component[7,1..20,7] | ||||||
|       componentWithChildren[7,1..20,7] |       componentWithChildren[7,1..20,7] | ||||||
|         openComponent[7,1..7,6] |         openComponent[7,1..7,6] | ||||||
|  | |||||||
| @ -80,7 +80,7 @@ final class AstFileMaker extends AbstractOutputFileMaker { | |||||||
|                 ) |                 ) | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             def mismatchedTypeErrors = MismatchedComponentTypeAnalysis.check(cuContext) |             def mismatchedTypeErrors = MismatchedComponentTypeAnalysis.checkForMismatchedComponentTypeErrors(cuContext) | ||||||
| 
 | 
 | ||||||
|             if (!mismatchedTypeErrors.isEmpty()) { |             if (!mismatchedTypeErrors.isEmpty()) { | ||||||
|                 def message = 'There were mismatched type errors: \n' + mismatchedTypeErrors.collect { |                 def message = 'There were mismatched type errors: \n' + mismatchedTypeErrors.collect { | ||||||
|  | |||||||
| @ -0,0 +1,193 @@ | |||||||
|  | package groowt.view.component.web.tools | ||||||
|  | 
 | ||||||
|  | import groowt.view.component.web.analysis.MismatchedComponentTypeError | ||||||
|  | import groowt.view.component.web.analysis.checkForMismatchedComponentTypeErrors | ||||||
|  | import groowt.view.component.web.antlr.* | ||||||
|  | import groowt.view.component.web.antlr.WebViewComponentsLexerBase.ERROR | ||||||
|  | import groowt.view.component.web.antlr.WebViewComponentsLexerBase.HIDDEN | ||||||
|  | import groowt.view.component.web.antlr.WebViewComponentsParser.CompilationUnitContext | ||||||
|  | import groowt.view.component.web.ast.DefaultAstBuilder | ||||||
|  | import groowt.view.component.web.ast.DefaultNodeFactory | ||||||
|  | import groowt.view.component.web.ast.formatAst | ||||||
|  | import groowt.view.component.web.ast.node.CompilationUnitNode | ||||||
|  | import org.antlr.v4.runtime.CharStreams | ||||||
|  | import org.antlr.v4.runtime.ConsoleErrorListener | ||||||
|  | import picocli.CommandLine | ||||||
|  | import picocli.CommandLine.Command | ||||||
|  | import picocli.CommandLine.Option | ||||||
|  | import java.nio.file.Path | ||||||
|  | import kotlin.io.path.nameWithoutExtension | ||||||
|  | import kotlin.system.exitProcess | ||||||
|  | 
 | ||||||
|  | @Command( | ||||||
|  |     name = "astBuilder", | ||||||
|  |     description = ["Create an AST from a .wvc file."], | ||||||
|  |     mixinStandardHelpOptions = true, | ||||||
|  |     version = ["0.1.0"] | ||||||
|  | ) | ||||||
|  | open class AstBuilder : AbstractSourceTransformerCli() { | ||||||
|  | 
 | ||||||
|  |     companion object { | ||||||
|  | 
 | ||||||
|  |         @JvmStatic | ||||||
|  |         fun main(args: Array<String>) { | ||||||
|  |             exitProcess(CommandLine(AstBuilder()).execute(*args)) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Option( | ||||||
|  |         names = ["-s", "--suffix"], | ||||||
|  |         description = ["The suffix (not extension!) to append to the output file."] | ||||||
|  |     ) | ||||||
|  |     protected var suffix: String? = null | ||||||
|  | 
 | ||||||
|  |     @Option( | ||||||
|  |         names = ["-e", "--extension"], | ||||||
|  |         description = ["The extension for output files."], | ||||||
|  |         defaultValue = ".txt" | ||||||
|  |     ) | ||||||
|  |     protected lateinit var extension: String | ||||||
|  | 
 | ||||||
|  |     @Option( | ||||||
|  |         names = ["-d", "--output-dir"], | ||||||
|  |         description = ["The output directory."], | ||||||
|  |         defaultValue = ".", | ||||||
|  |         paramLabel = "outputDir" | ||||||
|  |     ) | ||||||
|  |     protected lateinit var myOutputDir: Path | ||||||
|  | 
 | ||||||
|  |     @Option( | ||||||
|  |         names = ["--strict"], | ||||||
|  |         description = ["If true, do not recover from syntax errors during parsing."], | ||||||
|  |         negatable = true | ||||||
|  |     ) | ||||||
|  |     protected var strict = true | ||||||
|  | 
 | ||||||
|  |     protected open fun onLexerErrors(errors: List<LexerError>): Boolean { | ||||||
|  |         System.err.println("There were lexer errors.") | ||||||
|  |         errors.forEach { System.err.println(formatLexerError(it)) } | ||||||
|  |         return this.getYesNo("Do you wish to try again?", false) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     protected open fun onParserErrors(errors: List<ParserError>): Boolean { | ||||||
|  |         System.err.println("There were parser errors.") | ||||||
|  |         errors.forEach { System.err.println(formatParserError(it)) } | ||||||
|  |         return this.getYesNo("Do you wish to try again?", false) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     protected open fun onMismatchedErrors(errors: List<MismatchedComponentTypeError>): Boolean { | ||||||
|  |         System.err.println("There were mismatched component type errors.") | ||||||
|  |         errors.forEach { System.err.println(it.message) } | ||||||
|  |         return getYesNo("Do you wish to try again?", false) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     protected open fun onException(phase: String, e: Exception): Boolean { | ||||||
|  |         System.err.println("There was an exception during $phase: $e") | ||||||
|  |         if (this.verbose) { | ||||||
|  |             e.printStackTrace(System.err) | ||||||
|  |         } | ||||||
|  |         return this.getYesNo("Do you wish to try again?", false) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     protected open fun getFullTargetPath(target: Path): Path = | ||||||
|  |         Path.of(target.nameWithoutExtension + (suffix ?: "") + extension) | ||||||
|  | 
 | ||||||
|  |     protected open fun onSuccess(target: Path, tokenList: TokenList, cuNode: CompilationUnitNode): Boolean { | ||||||
|  |         val formatted = formatAst(cuNode, tokenList) | ||||||
|  |         if (interactive) { | ||||||
|  |             println("Please review the following ast:\n$formatted") | ||||||
|  |         } else { | ||||||
|  |             println(formatted) | ||||||
|  |         } | ||||||
|  |         if (getYesNo("Do you wish to write to disk?", true)) { | ||||||
|  |             writeToDisk(getFullTargetPath(target), formatted) | ||||||
|  |             return false | ||||||
|  |         } else { | ||||||
|  |             return getYesNo("Do you wish to redo this file?", false) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override fun getOutputDir() = myOutputDir | ||||||
|  | 
 | ||||||
|  |     override fun transform(target: Path): Int { | ||||||
|  |         if (interactive) { | ||||||
|  |             println("Building ast for $target") | ||||||
|  |         } | ||||||
|  |         while (true) { | ||||||
|  |             val parseResult: Pair<TokenList, CompilationUnitContext> = try { | ||||||
|  |                 val input = CharStreams.fromPath(target) | ||||||
|  | 
 | ||||||
|  |                 val lexer = WebViewComponentsLexer(input) | ||||||
|  |                 lexer.removeErrorListener(ConsoleErrorListener.INSTANCE) | ||||||
|  |                 val lexerErrorListener = LexerErrorListener() | ||||||
|  |                 lexer.addErrorListener(lexerErrorListener) | ||||||
|  | 
 | ||||||
|  |                 val tokenStream = if (strict) { | ||||||
|  |                     WebViewComponentsTokenStream(lexer) // only ignore hidden (default) | ||||||
|  |                 } else { | ||||||
|  |                     WebViewComponentsTokenStream(lexer, setOf(HIDDEN, ERROR)) // ignore hidden and error | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 val parser = WebViewComponentsParser(tokenStream) | ||||||
|  |                 parser.removeErrorListener(ConsoleErrorListener.INSTANCE) | ||||||
|  |                 val parserErrorListener = ParserErrorListener() | ||||||
|  |                 parser.addErrorListener(parserErrorListener) | ||||||
|  | 
 | ||||||
|  |                 val cuContext = parser.compilationUnit() | ||||||
|  | 
 | ||||||
|  |                 val lexerErrors = lexerErrorListener.getErrors() + parserErrorListener.getLexerErrors() | ||||||
|  |                 val parserErrors = parserErrorListener.getParserErrors() | ||||||
|  | 
 | ||||||
|  |                 if (lexerErrors.isNotEmpty()) { | ||||||
|  |                     val recover = this.onLexerErrors(lexerErrors) | ||||||
|  |                     if (!recover) { | ||||||
|  |                         return 1 | ||||||
|  |                     } | ||||||
|  |                 } else if (parserErrors.isNotEmpty()) { | ||||||
|  |                     val recover = this.onParserErrors(parserErrors) | ||||||
|  |                     if (!recover) { | ||||||
|  |                         return 1 | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 Pair(TokenList(tokenStream), cuContext) | ||||||
|  |             } catch (e: Exception) { | ||||||
|  |                 val recover = this.onException("parsing", e) | ||||||
|  |                 if (!recover) { | ||||||
|  |                     return 1 | ||||||
|  |                 } else { | ||||||
|  |                     continue | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             val mismatchedErrors = checkForMismatchedComponentTypeErrors(parseResult.second) | ||||||
|  |             if (mismatchedErrors.isNotEmpty()) { | ||||||
|  |                 val tryAgain = this.onMismatchedErrors(mismatchedErrors) | ||||||
|  |                 if (!tryAgain) { | ||||||
|  |                     return 1 | ||||||
|  |                 } else { | ||||||
|  |                     continue | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             val nodeFactory = DefaultNodeFactory(parseResult.first) | ||||||
|  |             val astBuilder = DefaultAstBuilder(nodeFactory) | ||||||
|  |             val cuNode: CompilationUnitNode = try { | ||||||
|  |                 astBuilder.buildCompilationUnit(parseResult.second) | ||||||
|  |             } catch (e: Exception) { | ||||||
|  |                 val recover = this.onException("ast building", e) | ||||||
|  |                 if (!recover) { | ||||||
|  |                     return 1 | ||||||
|  |                 } else { | ||||||
|  |                     continue | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             val redo = this.onSuccess(target, parseResult.first, cuNode) | ||||||
|  |             if (!redo) { | ||||||
|  |                 return 0 | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
| @ -7,11 +7,18 @@ import groowt.view.component.web.antlr.WebViewComponentsParser.CompilationUnitCo | |||||||
| import org.antlr.v4.runtime.CharStreams | import org.antlr.v4.runtime.CharStreams | ||||||
| import org.antlr.v4.runtime.ConsoleErrorListener | import org.antlr.v4.runtime.ConsoleErrorListener | ||||||
| import picocli.CommandLine | import picocli.CommandLine | ||||||
|  | import picocli.CommandLine.Command | ||||||
| import picocli.CommandLine.Option | import picocli.CommandLine.Option | ||||||
| import java.nio.file.Path | import java.nio.file.Path | ||||||
| import kotlin.io.path.nameWithoutExtension | import kotlin.io.path.nameWithoutExtension | ||||||
| import kotlin.system.exitProcess | import kotlin.system.exitProcess | ||||||
| 
 | 
 | ||||||
|  | @Command( | ||||||
|  |     name = "parseWvc", | ||||||
|  |     description = ["Parse a .wvc file and output an antlr4 parse tree."], | ||||||
|  |     mixinStandardHelpOptions = true, | ||||||
|  |     version = ["0.1.0"] | ||||||
|  | ) | ||||||
| open class ParseWvc : AbstractSourceTransformerCli() { | open class ParseWvc : AbstractSourceTransformerCli() { | ||||||
| 
 | 
 | ||||||
|     companion object { |     companion object { | ||||||
| @ -103,7 +110,6 @@ open class ParseWvc : AbstractSourceTransformerCli() { | |||||||
|         if (interactive) { |         if (interactive) { | ||||||
|             println("Parsing $target") |             println("Parsing $target") | ||||||
|         } |         } | ||||||
|         var code = 0 |  | ||||||
|         while (true) { |         while (true) { | ||||||
|             try { |             try { | ||||||
|                 val input = CharStreams.fromPath(target) |                 val input = CharStreams.fromPath(target) | ||||||
| @ -132,30 +138,26 @@ open class ParseWvc : AbstractSourceTransformerCli() { | |||||||
|                 if (lexerErrors.isNotEmpty()) { |                 if (lexerErrors.isNotEmpty()) { | ||||||
|                     val recover = this.onLexerErrors(lexerErrors) |                     val recover = this.onLexerErrors(lexerErrors) | ||||||
|                     if (!recover) { |                     if (!recover) { | ||||||
|                         code = 1 |                         return 1 | ||||||
|                         break |  | ||||||
|                     } |                     } | ||||||
|                 } else if (parserErrors.isNotEmpty()) { |                 } else if (parserErrors.isNotEmpty()) { | ||||||
|                     val recover = this.onParserErrors(parserErrors) |                     val recover = this.onParserErrors(parserErrors) | ||||||
|                     if (!recover) { |                     if (!recover) { | ||||||
|                         code = 1 |                         return 1 | ||||||
|                         break |  | ||||||
|                     } |                     } | ||||||
|                 } else { |                 } else { | ||||||
|                     val redo = this.onSuccess(target, parser, cuContext) |                     val redo = this.onSuccess(target, parser, cuContext) | ||||||
|                     if (!redo) { |                     if (!redo) { | ||||||
|                         break |                         return 0 | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } catch (e: Exception) { |             } catch (e: Exception) { | ||||||
|                 val recover = this.onException(e) |                 val recover = this.onException(e) | ||||||
|                 if (!recover) { |                 if (!recover) { | ||||||
|                     code = 1 |                     return 1 | ||||||
|                     break |  | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         return code |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -87,7 +87,6 @@ open class TokenizeWvc : AbstractSourceTransformerCli() { | |||||||
|         if (interactive) { |         if (interactive) { | ||||||
|             println("Tokenizing $target") |             println("Tokenizing $target") | ||||||
|         } |         } | ||||||
|         var code = 0 |  | ||||||
|         while (true) { |         while (true) { | ||||||
|             try { |             try { | ||||||
|                 val input = CharStreams.fromPath(target) |                 val input = CharStreams.fromPath(target) | ||||||
| @ -104,24 +103,21 @@ open class TokenizeWvc : AbstractSourceTransformerCli() { | |||||||
|                 if (errors.isNotEmpty()) { |                 if (errors.isNotEmpty()) { | ||||||
|                     val recover = this.onErrors(errors) |                     val recover = this.onErrors(errors) | ||||||
|                     if (!recover) { |                     if (!recover) { | ||||||
|                         code = 1 |                         return 1 | ||||||
|                         break |  | ||||||
|                     } |                     } | ||||||
|                 } else { |                 } else { | ||||||
|                     val redo = this.onSuccess(target, allTokens) |                     val redo = this.onSuccess(target, allTokens) | ||||||
|                     if (!redo) { |                     if (!redo) { | ||||||
|                         break |                         return 0 | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } catch (e: Exception) { |             } catch (e: Exception) { | ||||||
|                 val recover = this.onException(e) |                 val recover = this.onException(e) | ||||||
|                 if (!recover) { |                 if (!recover) { | ||||||
|                     code = 1 |                     return 1 | ||||||
|                     break |  | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         return code |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 JesseBrault0709
						JesseBrault0709