From f84c4e5e6cedb59e841a1610e3eb369d97bbac62 Mon Sep 17 00:00:00 2001 From: Edoardo Luppi Date: Tue, 9 Jan 2024 18:51:10 +0100 Subject: [PATCH 1/4] refactor: make TerminalNode.symbol not null and adjust references --- .../org/antlr/v4/kotlinruntime/ParserRuleContext.kt | 4 ++-- .../org/antlr/v4/kotlinruntime/tree/TerminalNode.kt | 2 +- .../antlr/v4/kotlinruntime/tree/TerminalNodeImpl.kt | 13 ++++++------- .../kotlin/org/antlr/v4/kotlinruntime/tree/Trees.kt | 7 ++----- .../tree/pattern/ParseTreePatternMatcher.kt | 2 +- .../kotlinruntime/tree/xpath/XPathTokenElement.kt | 2 +- 6 files changed, 13 insertions(+), 17 deletions(-) diff --git a/antlr-kotlin-runtime/src/commonMain/kotlin/org/antlr/v4/kotlinruntime/ParserRuleContext.kt b/antlr-kotlin-runtime/src/commonMain/kotlin/org/antlr/v4/kotlinruntime/ParserRuleContext.kt index ce58dc66..46082885 100644 --- a/antlr-kotlin-runtime/src/commonMain/kotlin/org/antlr/v4/kotlinruntime/ParserRuleContext.kt +++ b/antlr-kotlin-runtime/src/commonMain/kotlin/org/antlr/v4/kotlinruntime/ParserRuleContext.kt @@ -252,7 +252,7 @@ public open class ParserRuleContext : RuleContext { if (o is TerminalNode) { val symbol = o.symbol - if (symbol!!.type == ttype) { + if (symbol.type == ttype) { j++ if (j == i) { @@ -273,7 +273,7 @@ public open class ParserRuleContext : RuleContext { if (o is TerminalNode) { val symbol = o.symbol - if (symbol!!.type == ttype) { + if (symbol.type == ttype) { tokens.add(o) } } diff --git a/antlr-kotlin-runtime/src/commonMain/kotlin/org/antlr/v4/kotlinruntime/tree/TerminalNode.kt b/antlr-kotlin-runtime/src/commonMain/kotlin/org/antlr/v4/kotlinruntime/tree/TerminalNode.kt index 0b796b41..2b6b9024 100644 --- a/antlr-kotlin-runtime/src/commonMain/kotlin/org/antlr/v4/kotlinruntime/tree/TerminalNode.kt +++ b/antlr-kotlin-runtime/src/commonMain/kotlin/org/antlr/v4/kotlinruntime/tree/TerminalNode.kt @@ -9,5 +9,5 @@ package org.antlr.v4.kotlinruntime.tree import org.antlr.v4.kotlinruntime.Token public interface TerminalNode : ParseTree { - public val symbol: Token? + public val symbol: Token } diff --git a/antlr-kotlin-runtime/src/commonMain/kotlin/org/antlr/v4/kotlinruntime/tree/TerminalNodeImpl.kt b/antlr-kotlin-runtime/src/commonMain/kotlin/org/antlr/v4/kotlinruntime/tree/TerminalNodeImpl.kt index 86982ce8..f84b2156 100644 --- a/antlr-kotlin-runtime/src/commonMain/kotlin/org/antlr/v4/kotlinruntime/tree/TerminalNodeImpl.kt +++ b/antlr-kotlin-runtime/src/commonMain/kotlin/org/antlr/v4/kotlinruntime/tree/TerminalNodeImpl.kt @@ -11,21 +11,20 @@ import org.antlr.v4.kotlinruntime.RuleContext import org.antlr.v4.kotlinruntime.Token import org.antlr.v4.kotlinruntime.misc.Interval -public open class TerminalNodeImpl(override var symbol: Token?) : TerminalNode { +public open class TerminalNodeImpl(override var symbol: Token) : TerminalNode { private var parent: ParseTree? = null override val childCount: Int = 0 override val text: String - get() = symbol!!.text!! + get() = symbol.text!! - override val payload: Token? + override val payload: Token get() = symbol override val sourceInterval: Interval get() { - val tempSymbol = symbol ?: return Interval.INVALID - val tokenIndex = tempSymbol.tokenIndex + val tokenIndex = symbol.tokenIndex return Interval(tokenIndex, tokenIndex) } @@ -46,10 +45,10 @@ public open class TerminalNodeImpl(override var symbol: Token?) : TerminalNode { toString() override fun toString(): String = - if (symbol!!.type == Token.EOF) { + if (symbol.type == Token.EOF) { "" } else { - symbol!!.text!! + symbol.text!! } override fun toStringTree(): String = diff --git a/antlr-kotlin-runtime/src/commonMain/kotlin/org/antlr/v4/kotlinruntime/tree/Trees.kt b/antlr-kotlin-runtime/src/commonMain/kotlin/org/antlr/v4/kotlinruntime/tree/Trees.kt index e11fd84f..92fd2329 100644 --- a/antlr-kotlin-runtime/src/commonMain/kotlin/org/antlr/v4/kotlinruntime/tree/Trees.kt +++ b/antlr-kotlin-runtime/src/commonMain/kotlin/org/antlr/v4/kotlinruntime/tree/Trees.kt @@ -90,10 +90,7 @@ public object Trees { return t.toString() } else if (t is TerminalNode) { val symbol = t.symbol - - if (symbol != null) { - return symbol.text!! - } + return symbol.text!! } } @@ -189,7 +186,7 @@ public object Trees { ) { // Check this node (the root) first if (findTokens && t is TerminalNode) { - if (t.symbol!!.type == index) { + if (t.symbol.type == index) { nodes.add(t) } } else if (!findTokens && t is ParserRuleContext) { diff --git a/antlr-kotlin-runtime/src/commonMain/kotlin/org/antlr/v4/kotlinruntime/tree/pattern/ParseTreePatternMatcher.kt b/antlr-kotlin-runtime/src/commonMain/kotlin/org/antlr/v4/kotlinruntime/tree/pattern/ParseTreePatternMatcher.kt index 40dddcba..acd23c04 100644 --- a/antlr-kotlin-runtime/src/commonMain/kotlin/org/antlr/v4/kotlinruntime/tree/pattern/ParseTreePatternMatcher.kt +++ b/antlr-kotlin-runtime/src/commonMain/kotlin/org/antlr/v4/kotlinruntime/tree/pattern/ParseTreePatternMatcher.kt @@ -209,7 +209,7 @@ public open class ParseTreePatternMatcher(public val lexer: Lexer, public val pa var mismatchedNode: ParseTree? = null // Both are tokens and they have same type - if (tree.symbol?.type == patternTree.symbol?.type) { + if (tree.symbol.type == patternTree.symbol.type) { if (patternTree.symbol is TokenTagToken) { // x and val tokenTagToken = patternTree.symbol as TokenTagToken diff --git a/antlr-kotlin-runtime/src/commonMain/kotlin/org/antlr/v4/kotlinruntime/tree/xpath/XPathTokenElement.kt b/antlr-kotlin-runtime/src/commonMain/kotlin/org/antlr/v4/kotlinruntime/tree/xpath/XPathTokenElement.kt index 518f2e41..43876b7e 100644 --- a/antlr-kotlin-runtime/src/commonMain/kotlin/org/antlr/v4/kotlinruntime/tree/xpath/XPathTokenElement.kt +++ b/antlr-kotlin-runtime/src/commonMain/kotlin/org/antlr/v4/kotlinruntime/tree/xpath/XPathTokenElement.kt @@ -18,7 +18,7 @@ public open class XPathTokenElement(tokenName: String, protected var tokenType: for (c in Trees.getChildren(t)) { if (c is TerminalNode) { - if (c.symbol!!.type == tokenType && !invert || c.symbol!!.type != tokenType && invert) { + if (c.symbol.type == tokenType && !invert || c.symbol.type != tokenType && invert) { nodes.add(c) } } From b41c85a86c5ee7397805c4bf58448f684d46535f Mon Sep 17 00:00:00 2001 From: Edoardo Luppi Date: Tue, 9 Jan 2024 18:53:59 +0100 Subject: [PATCH 2/4] refactor: cleanup Trees --- .../org/antlr/v4/kotlinruntime/tree/Trees.kt | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/antlr-kotlin-runtime/src/commonMain/kotlin/org/antlr/v4/kotlinruntime/tree/Trees.kt b/antlr-kotlin-runtime/src/commonMain/kotlin/org/antlr/v4/kotlinruntime/tree/Trees.kt index 92fd2329..4109a6c4 100644 --- a/antlr-kotlin-runtime/src/commonMain/kotlin/org/antlr/v4/kotlinruntime/tree/Trees.kt +++ b/antlr-kotlin-runtime/src/commonMain/kotlin/org/antlr/v4/kotlinruntime/tree/Trees.kt @@ -76,21 +76,19 @@ public object Trees { public fun getNodeText(t: Tree, ruleNames: List?): String { if (ruleNames != null) { - if (t is RuleContext) { - val ruleIndex = t.ruleContext.ruleIndex - val ruleName = ruleNames[ruleIndex] - val altNumber = t.altNumber - - return if (altNumber != ATN.INVALID_ALT_NUMBER) { - "$ruleName:$altNumber" - } else { - ruleName + when (t) { + is RuleContext -> { + val ruleIndex = t.ruleContext.ruleIndex + val ruleName = ruleNames[ruleIndex] + val altNumber = t.altNumber + return if (altNumber != ATN.INVALID_ALT_NUMBER) { + "$ruleName:$altNumber" + } else { + ruleName + } } - } else if (t is ErrorNode) { - return t.toString() - } else if (t is TerminalNode) { - val symbol = t.symbol - return symbol.text!! + is ErrorNode -> return t.toString() + is TerminalNode -> return t.symbol.text!! } } From 6214b44dac28af472e47b97b9a0172945ab25f78 Mon Sep 17 00:00:00 2001 From: Edoardo Luppi Date: Tue, 9 Jan 2024 19:53:33 +0100 Subject: [PATCH 3/4] chore: improve nullability support for generated parsers --- .../v4/tool/templates/codegen/Kotlin/Kotlin.stg | 8 ++++---- .../test/minicalc/MiniCalcParserTest.kt | 14 +++++++------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/antlr-kotlin-target/src/main/resources/org/antlr/v4/tool/templates/codegen/Kotlin/Kotlin.stg b/antlr-kotlin-target/src/main/resources/org/antlr/v4/tool/templates/codegen/Kotlin/Kotlin.stg index 30b4ff39..68f31dc9 100644 --- a/antlr-kotlin-target/src/main/resources/org/antlr/v4/tool/templates/codegen/Kotlin/Kotlin.stg +++ b/antlr-kotlin-target/src/main/resources/org/antlr/v4/tool/templates/codegen/Kotlin/Kotlin.stg @@ -741,7 +741,7 @@ TokenTypeDecl(t) ::= "var : Int" TokenListDecl(t) ::= ": MutableList\ = ArrayList\()" RuleContextDecl(r) ::= ": ? = null" RuleContextListDecl(rdecl) ::= ": MutableList\<> = ArrayList\<>()" -ContextTokenGetterDecl(t) ::= "public fun (): TerminalNode? = getToken(Tokens..id, 0)" +ContextTokenGetterDecl(t) ::= "public fun (): TerminalNode? = getToken(Tokens..id, 0)!!" ContextTokenListGetterDecl(t) ::= "public fun (): List\ = getTokens(Tokens..id)" ContextTokenListIndexedGetterDecl(t) ::= << @@ -749,15 +749,15 @@ public fun (i: Int): TerminalNode = getToken(Tokens..id, i)!! >> ContextRuleGetterDecl(r) ::= << -public fun find(): ? = getRuleContext(::class, 0) +public fun get(): ? = getRuleContext(::class, 0)!! >> ContextRuleListGetterDecl(r) ::= << -public fun find(): List\<\> = getRuleContexts(::class) +public fun get(): List\<\> = getRuleContexts(::class) >> ContextRuleListIndexedGetterDecl(r) ::= << -public fun find(i: Int): ? = getRuleContext(::class, i) +public fun get(i: Int): ? = getRuleContext(::class, i) >> LexerRuleContext() ::= "RuleContext" diff --git a/antlr-kotlin-tests/src/commonTest/kotlin/com/strumenta/antlrkotlin/test/minicalc/MiniCalcParserTest.kt b/antlr-kotlin-tests/src/commonTest/kotlin/com/strumenta/antlrkotlin/test/minicalc/MiniCalcParserTest.kt index 77a48b99..59e386d3 100644 --- a/antlr-kotlin-tests/src/commonTest/kotlin/com/strumenta/antlrkotlin/test/minicalc/MiniCalcParserTest.kt +++ b/antlr-kotlin-tests/src/commonTest/kotlin/com/strumenta/antlrkotlin/test/minicalc/MiniCalcParserTest.kt @@ -64,21 +64,21 @@ class MiniCalcParserTest { val lexer = MiniCalcLexer(input) val parser = MiniCalcParser(CommonTokenStream(lexer)) val root = parser.miniCalcFile() - val line = root.findLine(0)!! - val statement = line.findStatement()!! + val line = root.getLine(0)!! + val statement = line.getStatement() @Suppress("UNUSED_VARIABLE") val inputDeclStmt = statement as MiniCalcParser.InputDeclarationStatementContext - val inputDecl = statement.findInputDeclaration()!! + val inputDecl = statement.getInputDeclaration() val inputKw = inputDecl.INPUT() - assertEquals("input", inputKw!!.text) + assertEquals("input", inputKw.text) - val type = inputDecl.findType()!! + val type = inputDecl.getType() val intKw = (type as MiniCalcParser.IntegerContext).INT() - assertEquals("Int", intKw!!.text) + assertEquals("Int", intKw.text) - val id = inputDecl.ID()!! + val id = inputDecl.ID() assertEquals("width", id.text) val newline = line.NEWLINE()!! From 4d5c21196d985f3c3f446208c775969de98bc36c Mon Sep 17 00:00:00 2001 From: Edoardo Luppi Date: Wed, 10 Jan 2024 14:24:10 +0100 Subject: [PATCH 4/4] refactor: throw a proper exception when the symbol's text is null --- .../kotlin/org/antlr/v4/kotlinruntime/tree/Trees.kt | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/antlr-kotlin-runtime/src/commonMain/kotlin/org/antlr/v4/kotlinruntime/tree/Trees.kt b/antlr-kotlin-runtime/src/commonMain/kotlin/org/antlr/v4/kotlinruntime/tree/Trees.kt index 4109a6c4..a52850fc 100644 --- a/antlr-kotlin-runtime/src/commonMain/kotlin/org/antlr/v4/kotlinruntime/tree/Trees.kt +++ b/antlr-kotlin-runtime/src/commonMain/kotlin/org/antlr/v4/kotlinruntime/tree/Trees.kt @@ -87,8 +87,13 @@ public object Trees { ruleName } } - is ErrorNode -> return t.toString() - is TerminalNode -> return t.symbol.text!! + is ErrorNode -> { + return t.toString() + } + is TerminalNode -> { + val text = t.symbol.text + return text ?: throw IllegalStateException("Symbol text should not be null") + } } }