Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cleanup the ParseTree hierarchy and open its functions #194

Merged
merged 2 commits into from
Sep 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ public class MySQLErrorListener : BaseErrorListener() {
// Walk up from generic rules to reach something that gives us more context, if needed.
var context = parser.context

while (context?.parent != null && simpleRules.contains(context.ruleIndex)) {
context = context.parent as ParserRuleContext?
while (context?.getParent() != null && simpleRules.contains(context.ruleIndex)) {
context = context.getParent()
}

// Try to find the expected input by examining the current parser context and
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public class BailErrorStrategy : DefaultErrorStrategy() {

while (context != null) {
context.exception = e
context = context.readParent()
context = context.getParent()
}

throw ParseCancellationException(e)
Expand All @@ -63,7 +63,7 @@ public class BailErrorStrategy : DefaultErrorStrategy() {

while (context != null) {
context.exception = e
context = context.readParent()
context = context.getParent()
}

throw ParseCancellationException(e)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -735,7 +735,7 @@ public open class DefaultErrorStrategy : ANTLRErrorStrategy {
val rt = invokingState!!.transition(0) as RuleTransition
val follow = atn.nextTokens(rt.followState)
recoverSet.addAll(follow)
ctx = ctx.readParent()
ctx = ctx.getParent()
}

recoverSet.remove(Token.EPSILON)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,10 @@ public abstract class Parser(input: TokenStream) : Recognizer<Token, ParserATNSi
}

override fun exitEveryRule(ctx: ParserRuleContext) {
if (ctx.children is ArrayList<*>) {
(ctx.children as ArrayList<*>).trimToSize()
val children = ctx.children

if (children is ArrayList<*>) {
children.trimToSize()
}
}
}
Expand Down Expand Up @@ -584,7 +586,7 @@ public abstract class Parser(input: TokenStream) : Recognizer<Token, ParserATNSi
ErrorNodeImpl(t)

protected open fun addContextToParseTree() {
val parent = context!!.readParent()
val parent = context!!.getParent()

// Add current context to parent if we have a parent
parent?.addChild(context!!)
Expand Down Expand Up @@ -620,7 +622,7 @@ public abstract class Parser(input: TokenStream) : Recognizer<Token, ParserATNSi
// Trigger event on context, before it reverts to parent
triggerExitRuleEvent()
state = context!!.invokingState
context = context!!.readParent()
context = context!!.getParent()
}

public fun enterOuterAlt(localctx: ParserRuleContext, altNum: Int) {
Expand All @@ -629,7 +631,7 @@ public abstract class Parser(input: TokenStream) : Recognizer<Token, ParserATNSi
// If we have new localctx, make sure we replace existing ctx
// that is previous child of parse tree
if (buildParseTree && context !== localctx) {
val parent = context!!.readParent()
val parent = context!!.getParent()

if (parent != null) {
parent.removeLastChild()
Expand Down Expand Up @@ -657,7 +659,7 @@ public abstract class Parser(input: TokenStream) : Recognizer<Token, ParserATNSi
*/
public open fun pushNewRecursionContext(localctx: ParserRuleContext, state: Int, ruleIndex: Int) {
val previous = context
previous!!.assignParent(localctx)
previous!!.setParent(localctx)
previous.invokingState = state
previous.stop = _input.LT(-1)

Expand All @@ -683,14 +685,14 @@ public abstract class Parser(input: TokenStream) : Recognizer<Token, ParserATNSi
if (parseListeners.isNotEmpty()) {
while (context !== _parentctx) {
triggerExitRuleEvent()
context = context!!.readParent()
context = context!!.getParent()
}
} else {
context = _parentctx
}

// Hook into tree
retCtx!!.assignParent(_parentctx)
retCtx!!.setParent(_parentctx)

if (buildParseTree && _parentctx != null) {
// Add return ctx into invoking rule's tree
Expand All @@ -706,7 +708,7 @@ public abstract class Parser(input: TokenStream) : Recognizer<Token, ParserATNSi
return p
}

p = p.readParent()
p = p.getParent()
}

return null
Expand Down Expand Up @@ -757,7 +759,7 @@ public abstract class Parser(input: TokenStream) : Recognizer<Token, ParserATNSi
return true
}

ctx = ctx.readParent()
ctx = ctx.getParent()
}

return following.contains(Token.EPSILON) && symbol == Token.EOF
Expand Down Expand Up @@ -795,7 +797,7 @@ public abstract class Parser(input: TokenStream) : Recognizer<Token, ParserATNSi
stack.add(ruleNames[ruleIndex])
}

p = p.readParent()
p = p.getParent()
}

return stack
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,23 +41,33 @@ public open class ParserRuleContext : RuleContext {
public val EMPTY: ParserRuleContext = ParserRuleContext()
}

// This does not exist in the Java runtime
public val position: Position?
get() {
val start = this.start
val stop = this.stop

if (start != null && stop != null) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps we could write this as `if (start != null && stop?.endPoint() != null) {

Copy link
Contributor Author

@lppedd lppedd Aug 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, because you'd have to assign the result of stop?.endPoint() to a variable x anyway, to assert x != null to be able to pass it to Position(start.startPoint(), x). So stop?.endPoint() != null is a redundant call to endPoint().

Another argument for calling startPoint() and endPoint() only once is they're functions, and the result may vary between invocations.

val endPoint = stop.endPoint()

if (endPoint != null) {
return Position(start.startPoint(), endPoint)
}
}

return null
}

/**
* If we are debugging or building a parse tree for a visitor,
* we need to track all the tokens and rule invocations associated
* with this rule's context. This is empty for parsing w/o tree constr.
* operation because we don't have the need to track the details about
* how we parse this rule.
*/
@JvmField
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to make this a JvmField? Do we want the outside world to be able to set the field directly?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, the outside world was able to set that property anyway, even without @JvmField. The difference is without the annotation a getter, a setter, and a backing private field would be generated. With the annotation we only have the public backing field.

Applying @JvmField aligns the code with the Java runtime.

public var children: MutableList<ParseTree>? = null

// This does not exist in the Java runtime
public val position: Position?
get() = if (start != null && stop?.endPoint() != null) {
Position(start!!.startPoint(), stop!!.endPoint()!!)
} else {
null
}

/**
* The initial token in this context.
*
Expand All @@ -81,6 +91,7 @@ public open class ParserRuleContext : RuleContext {
*
* If the rule successfully completed, this is `null`.
*/
@JvmField
public var exception: RecognitionException? = null

override val childCount: Int
Expand All @@ -98,11 +109,26 @@ public open class ParserRuleContext : RuleContext {
}
}

// Override to make the type more specific
override val ruleContext: ParserRuleContext
get() = this

// Override to make the type more specific
override val payload: ParserRuleContext
get() = this

public constructor()
public constructor(parent: ParserRuleContext?, invokingStateNumber: Int) : super(parent, invokingStateNumber)

override fun readParent(): ParserRuleContext? =
super.readParent() as ParserRuleContext?
// Override to make the type more specific
override fun getParent(): ParserRuleContext? =
parent as ParserRuleContext?

override fun setParent(value: RuleContext?) {
// Although we could assign 'value' straight away, we cast it
// to ensure we are dealing with a compatible type
parent = value as ParserRuleContext?
}

/**
* Copy a context (I'm deliberately not using copy constructor) to avoid
Expand Down Expand Up @@ -153,12 +179,12 @@ public open class ParserRuleContext : RuleContext {
* Other [addChild] methods call this.
*
* We cannot set the parent pointer of the incoming node
* because the existing interfaces do not have a [assignParent]
* because the existing interfaces do not have a [setParent]
* method and I don't want to break backward compatibility for this.
*
* @since 4.7
*/
public fun <T : ParseTree> addAnyChild(t: T): T {
public open fun <T : ParseTree> addAnyChild(t: T): T {
var childrenTemp = children

if (childrenTemp == null) {
Expand All @@ -170,14 +196,14 @@ public open class ParserRuleContext : RuleContext {
return t
}

public fun addChild(ruleInvocation: RuleContext): RuleContext =
public open fun addChild(ruleInvocation: RuleContext): RuleContext =
addAnyChild(ruleInvocation)

/**
* Add a token leaf node child and force its parent to be this node.
*/
public fun addChild(t: TerminalNode): TerminalNode {
t.assignParent(this)
public open fun addChild(t: TerminalNode): TerminalNode {
t.setParent(this)
return addAnyChild(t)
}

Expand All @@ -186,8 +212,8 @@ public open class ParserRuleContext : RuleContext {
*
* @since 4.7
*/
public fun addErrorNode(errorNode: ErrorNode): ErrorNode {
errorNode.assignParent(this)
public open fun addErrorNode(errorNode: ErrorNode): ErrorNode {
errorNode.setParent(this)
return addAnyChild(errorNode)
}

Expand All @@ -197,7 +223,7 @@ public open class ParserRuleContext : RuleContext {
*
* If we have `# label`, we will need to remove generic `ruleContext` object.
*/
public fun removeLastChild() {
public open fun removeLastChild() {
val tempChildren = children
tempChildren?.removeAt(tempChildren.size - 1)
}
Expand All @@ -211,7 +237,7 @@ public open class ParserRuleContext : RuleContext {
}
}

public fun <T : ParseTree> getChild(ctxType: KClass<T>, i: Int): T? {
public open fun <T : ParseTree> getChild(ctxType: KClass<T>, i: Int): T? {
val tempChildren = children

if (tempChildren == null || i < 0 || i >= tempChildren.size) {
Expand All @@ -235,7 +261,7 @@ public open class ParserRuleContext : RuleContext {
return null
}

public fun getToken(ttype: Int, i: Int): TerminalNode? {
public open fun getToken(ttype: Int, i: Int): TerminalNode? {
val tempChildren = children

if (tempChildren == null || i < 0 || i >= tempChildren.size) {
Expand All @@ -262,7 +288,7 @@ public open class ParserRuleContext : RuleContext {
return null
}

public fun getTokens(ttype: Int): List<TerminalNode> {
public open fun getTokens(ttype: Int): List<TerminalNode> {
val tempChildren = children ?: return emptyList()
val tokens = ArrayList<TerminalNode>()

Expand All @@ -279,10 +305,10 @@ public open class ParserRuleContext : RuleContext {
return tokens
}

public fun <T : ParserRuleContext> getRuleContext(ctxType: KClass<T>, i: Int): T? =
public open fun <T : ParserRuleContext> getRuleContext(ctxType: KClass<T>, i: Int): T? =
getChild(ctxType, i)

public fun <T : ParserRuleContext> getRuleContexts(ctxType: KClass<T>): List<T> {
public open fun <T : ParserRuleContext> getRuleContexts(ctxType: KClass<T>): List<T> {
val tempChildren = children ?: return emptyList()
val contexts = ArrayList<T>()

Expand All @@ -299,7 +325,7 @@ public open class ParserRuleContext : RuleContext {
/**
* Used for rule context info debugging during parse-time, not so much for ATN debugging.
*/
public fun toInfoString(recognizer: Parser): String {
public open fun toInfoString(recognizer: Parser): String {
val rules = recognizer.getRuleInvocationStack(this).toMutableList()
rules.reverse()
return "ParserRuleContext$rules{start=$start, stop=$stop}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import org.antlr.v4.kotlinruntime.tree.ParseTree
import org.antlr.v4.kotlinruntime.tree.ParseTreeVisitor
import org.antlr.v4.kotlinruntime.tree.RuleNode
import org.antlr.v4.kotlinruntime.tree.Trees
import kotlin.jvm.JvmField

/**
* A rule context is a record of a single rule invocation.
Expand Down Expand Up @@ -68,7 +69,8 @@ public open class RuleContext : RuleNode {
/**
* What context invoked this rule?
*/
public var parent: RuleContext? = null
@JvmField
protected var parent: RuleContext? = null

/**
* What state invoked the rule associated with this context?
Expand All @@ -77,6 +79,7 @@ public open class RuleContext : RuleNode {
* If [parent] is `null`, this should be `-1` as this context
* object represents the start rule.
*/
@JvmField
public var invokingState: Int = -1

/**
Expand Down Expand Up @@ -151,14 +154,14 @@ public open class RuleContext : RuleNode {
this.invokingState = invokingState
}

override fun readParent(): RuleContext? =
override fun getParent(): RuleContext? =
parent

override fun assignParent(value: RuleContext?) {
override fun setParent(value: RuleContext?) {
parent = value
}

public fun depth(): Int {
public open fun depth(): Int {
var n = 0
var p: RuleContext? = this

Expand Down Expand Up @@ -191,7 +194,7 @@ public open class RuleContext : RuleNode {
*
* Print just a node if this is a leaf.
*/
public fun toStringTree(ruleNames: List<String>?): String =
public open fun toStringTree(ruleNames: List<String>?): String =
Trees.toStringTree(this, ruleNames)

override fun toStringTree(): String =
Expand All @@ -201,7 +204,7 @@ public open class RuleContext : RuleNode {
toString(ruleNames = null, stop = null)

// recog null unless ParserRuleContext, in which case we use subclass toString(...)
public fun toString(recog: Recognizer<*, *>?, stop: RuleContext = ParserRuleContext.EMPTY): String {
public open fun toString(recog: Recognizer<*, *>?, stop: RuleContext = ParserRuleContext.EMPTY): String {
val ruleNames = recog?.ruleNames
val ruleNamesList = if (ruleNames != null) {
listOf(*ruleNames)
Expand All @@ -212,7 +215,7 @@ public open class RuleContext : RuleNode {
return toString(ruleNamesList, stop)
}

public fun toString(ruleNames: List<String>?, stop: RuleContext? = null): String {
public open fun toString(ruleNames: List<String>?, stop: RuleContext? = null): String {
val buf = StringBuilder()
var p: RuleContext? = this
buf.append("[")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,8 @@ public interface Token {
public fun startPoint(): Point =
Point(line, charPositionInLine)

public fun endPoint(): Point? =
if (text == null) {
null
} else {
Point(line, charPositionInLine).advance(text!!)
}
public fun endPoint(): Point? {
val text = this.text ?: return null
return Point(line, charPositionInLine).advance(text)
}
}
Loading
Loading