Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
// Copyright 2017-present Strumenta and contributors, licensed under Apache 2.0.
// Copyright 2024-present Strumenta and contributors, licensed under BSD 3-Clause.
package org.antlr.v4.kotlinruntime.atn
import com.strumenta.antlrkotlin.runtime.IdentityHashMap
import com.strumenta.antlrkotlin.runtime.System
import com.strumenta.antlrkotlin.runtime.assert
import org.antlr.v4.kotlinruntime.ParserRuleContext
import org.antlr.v4.kotlinruntime.Recognizer
import org.antlr.v4.kotlinruntime.RuleContext
import org.antlr.v4.kotlinruntime.misc.DoubleKeyMap
import org.antlr.v4.kotlinruntime.misc.MurmurHash
import kotlin.jvm.JvmField
@Suppress("EqualsOrHashCode", "MemberVisibilityCanBePrivate")
public abstract class PredictionContext protected constructor(
/**
* Stores the computed hash code of this [PredictionContext].
*
* The hash code is computed in parts to match the following reference algorithm.
*
* ```
* private fun referenceHashCode(): Int {
* val hash = MurmurHash.initialize(INITIAL_HASH)
*
* for (i in 0.., returnStates: IntArray): Int {
var hash = MurmurHash.initialize(INITIAL_HASH)
for (parent in parents) {
hash = MurmurHash.update(hash, parent)
}
for (returnState in returnStates) {
hash = MurmurHash.update(hash, returnState)
}
hash = MurmurHash.finish(hash, 2 * parents.size)
return hash
}
// Dispatch
public fun merge(
a: PredictionContext?,
b: PredictionContext?,
rootIsWildcard: Boolean,
mergeCache: DoubleKeyMap?,
): PredictionContext {
var aa = a
var bb = b
// Must be empty context, never null
assert(aa != null && bb != null)
// Share same graph if both same
if (a === b || aa == bb) {
return aa
}
if (aa is SingletonPredictionContext && bb is SingletonPredictionContext) {
return mergeSingletons(aa, bb, rootIsWildcard, mergeCache)
}
// At least one of a or b is array
// If one is $ and rootIsWildcard, return $ as * wildcard
if (rootIsWildcard) {
if (aa is EmptyPredictionContext) {
return aa
}
if (bb is EmptyPredictionContext) {
return bb
}
}
// Convert singleton so both are arrays to normalize
if (aa is SingletonPredictionContext) {
aa = ArrayPredictionContext(aa)
}
if (bb is SingletonPredictionContext) {
bb = ArrayPredictionContext(bb)
}
return mergeArrays(
aa as ArrayPredictionContext,
bb as ArrayPredictionContext,
rootIsWildcard,
mergeCache,
)
}
/**
* Merge two [SingletonPredictionContext] instances.
*
* Stack tops equal, parents merge is same; return left graph.
*
*
*
* Same stack top, parents differ; merge parents giving array node, then
* remainders of those graphs. A new root node is created to point to the
* merged parents.
*
*
*
* Different stack tops pointing to same parent. Make array node for the
* root where both element in the root point to the same (original)
* parent.
*
*
*
* Different stack tops pointing to different parents. Make array node for
* the root where each element points to the corresponding original
* parent.
*
*
*
* @param a The first [SingletonPredictionContext]
* @param b The second [SingletonPredictionContext]
* @param rootIsWildcard `true` if this is a local-context merge,
* otherwise `false` to indicate a full-context merge
* @param mergeCache
*/
public fun mergeSingletons(
a: SingletonPredictionContext,
b: SingletonPredictionContext,
rootIsWildcard: Boolean,
mergeCache: DoubleKeyMap?,
): PredictionContext {
if (mergeCache != null) {
var previous = mergeCache[a, b]
if (previous != null) {
return previous
}
previous = mergeCache[b, a]
if (previous != null) {
return previous
}
}
val rootMerge = mergeRoot(a, b, rootIsWildcard)
if (rootMerge != null) {
mergeCache?.put(a, b, rootMerge)
return rootMerge
}
// a == b
if (a.returnState == b.returnState) {
val parent = merge(a.parent, b.parent, rootIsWildcard, mergeCache)
// If parent is same as existing a or b parent or reduced to a parent, return it
// ax + bx = ax, if a=b
if (parent === a.parent) {
return a
}
// ax + bx = bx, if a=b
if (parent === b.parent) {
return b
}
// Else: ax + ay = a'[x,y]
// merge parents x and y, giving array node with x,y then remainders
// of those graphs. dup a, a' points at merged array
// new joined parent so create new singleton pointing to it, a'
@Suppress("LocalVariableName")
val a_ = SingletonPredictionContext.create(parent, a.returnState)
mergeCache?.put(a, b, a_)
return a_
}
// a != b payloads differ
// see if we can collapse parents due to $+x parents if local ctx
var singleParent: PredictionContext? = null
// ax + bx = [a,b]x
if (a === b || a.parent != null && a.parent == b.parent) {
singleParent = a.parent
}
if (singleParent != null) {
// Parents are same.
// Sort payloads and use same parent
val payloads = intArrayOf(a.returnState, b.returnState)
if (a.returnState > b.returnState) {
payloads[0] = b.returnState
payloads[1] = a.returnState
}
val parents: Array = arrayOf(singleParent, singleParent)
@Suppress("LocalVariableName")
val a_ = ArrayPredictionContext(parents, payloads)
mergeCache?.put(a, b, a_)
return a_
}
// Parents differ and can't merge them. Just pack together
// into array; can't merge.
// ax + by = [ax,by]
val payloads = intArrayOf(a.returnState, b.returnState)
var parents = arrayOf(a.parent, b.parent)
// Sort by payload
if (a.returnState > b.returnState) {
payloads[0] = b.returnState
payloads[1] = a.returnState
parents = arrayOf(b.parent, a.parent)
}
@Suppress("LocalVariableName")
val a_ = ArrayPredictionContext(parents, payloads)
mergeCache?.put(a, b, a_)
return a_
}
/**
* Handle case where at least one of [a] or [b] is [EmptyPredictionContext].
*
* In the following diagrams, the symbol `$` is used to represent [EmptyPredictionContext].
*
* ### Local-Context Merges
*
* These local-context merge operations are used when [rootIsWildcard] is true.
*
* [EmptyPredictionContext] is superset of any graph; return [EmptyPredictionContext].
*
*
*
* [EmptyPredictionContext] and anything is `#EMPTY`, so merged parent is `#EMPTY`; return left graph.
*
*
*
* Special case of last merge if local context.
*
*
*
* ### Full-Context Merges
*
* These full-context merge operations are used when [rootIsWildcard] is false.
*
*
*
* Must keep all contexts; [EmptyPredictionContext] in array is a special value (and `null` parent).
*
*
*
*
*
* @param a The first [SingletonPredictionContext]
* @param b The second [SingletonPredictionContext]
* @param rootIsWildcard `true` if this is a local-context merge,
* otherwise false to indicate a full-context merge
*/
public fun mergeRoot(
a: SingletonPredictionContext,
b: SingletonPredictionContext,
rootIsWildcard: Boolean,
): PredictionContext? {
if (rootIsWildcard) {
if (a === EmptyPredictionContext) {
// * + b = *
return EmptyPredictionContext
}
if (b === EmptyPredictionContext) {
// a + * = *
return EmptyPredictionContext
}
} else {
if (a === EmptyPredictionContext && b === EmptyPredictionContext) {
// $ + $ = $
return EmptyPredictionContext
}
if (a === EmptyPredictionContext) {
// $ + x = [x,$]
val payloads = intArrayOf(b.returnState, EMPTY_RETURN_STATE)
val parents = arrayOf(b.parent, null)
return ArrayPredictionContext(parents, payloads)
}
if (b === EmptyPredictionContext) {
// x + $ = [x,$] ($ is always last if present)
val payloads = intArrayOf(a.returnState, EMPTY_RETURN_STATE)
val parents = arrayOf(a.parent, null)
return ArrayPredictionContext(parents, payloads)
}
}
return null
}
/**
* Merge two [ArrayPredictionContext] instances.
*
* Different tops, different parents.
*
*
*
* Shared top, same parents.
*
*
*
* Shared top, different parents.
*
*
*
* Shared top, all shared parents.
*
*
*
* Equal tops, merge parents and reduce top to [SingletonPredictionContext].
*
*
*/
public fun mergeArrays(
a: ArrayPredictionContext,
b: ArrayPredictionContext,
rootIsWildcard: Boolean,
mergeCache: DoubleKeyMap?,
): PredictionContext {
if (mergeCache != null) {
var previous = mergeCache[a, b]
if (previous != null) {
if (ParserATNSimulator.trace_atn_sim) {
System.out.println("mergeArrays a=$a,b=$b -> previous")
}
return previous
}
previous = mergeCache[b, a]
if (previous != null) {
if (ParserATNSimulator.trace_atn_sim) {
System.out.println("mergeArrays a=$a,b=$b -> previous")
}
return previous
}
}
// Merge sorted payloads a + b => M
var i = 0 // Walks a
var j = 0 // Walks b
var k = 0 // Walks target M array
var mergedReturnStates = IntArray(a.returnStates.size + b.returnStates.size)
var mergedParents = arrayOfNulls(a.returnStates.size + b.returnStates.size)
// Walk and merge to yield mergedParents, mergedReturnStates
while (i < a.returnStates.size && j < b.returnStates.size) {
val aParent = a.parents[i]
val bParent = b.parents[j]
if (a.returnStates[i] == b.returnStates[j]) {
// Same payload (stack tops are equal), must yield merged singleton
val payload = a.returnStates[i]
// $+$ = $
val both = payload == EMPTY_RETURN_STATE && aParent == null && bParent == null
// ax+ax -> ax
@Suppress("LocalVariableName")
val ax_ax = aParent != null && bParent != null && aParent == bParent
if (both || ax_ax) {
mergedParents[k] = aParent // choose left
mergedReturnStates[k] = payload
} else {
// ax+ay -> a'[x,y]
val mergedParent = merge(aParent, bParent, rootIsWildcard, mergeCache)
mergedParents[k] = mergedParent
mergedReturnStates[k] = payload
}
i++ // Hop over left one as usual
j++ // But also skip one in right side since we merge
} else if (a.returnStates[i] < b.returnStates[j]) {
// copy a[i] to M
mergedParents[k] = aParent
mergedReturnStates[k] = a.returnStates[i]
i++
} else {
// b > a, copy b[j] to M
mergedParents[k] = bParent
mergedReturnStates[k] = b.returnStates[j]
j++
}
k++
}
// Copy over any payloads remaining in either array
if (i < a.returnStates.size) {
for (p in i.. a")
}
return a
}
if (M == b) {
mergeCache?.put(a, b, b)
if (ParserATNSimulator.trace_atn_sim) {
System.out.println("mergeArrays a=$a,b=$b -> b")
}
return b
}
combineCommonParents(mergedParents)
mergeCache?.put(a, b, M)
if (ParserATNSimulator.trace_atn_sim) {
System.out.println("mergeArrays a=$a,b=$b -> $M")
}
return M
}
/**
* Make pass over all *M* [parents].
*
* Merge any `equals()` ones.
*/
protected fun combineCommonParents(parents: Array) {
val uniqueParents = HashMap()
for (p in parents.indices) {
val parent = parents[p]
// Don't replace
if (!uniqueParents.containsKey(parent)) {
uniqueParents[parent] = parent
}
}
for (p in parents.indices) {
parents[p] = uniqueParents[parents[p]]
}
}
public fun toDOTString(context: PredictionContext?): String {
if (context == null) {
return ""
}
val buf = StringBuilder(1024)
buf.append("digraph G {\n")
buf.append("rankdir=LR;\n")
val nodes = getAllContextNodes(context).sortedBy(PredictionContext::id)
for (current in nodes) {
if (current is SingletonPredictionContext) {
buf.append(" s")
buf.append(current.id)
val returnState = if (current is EmptyPredictionContext) {
"$"
} else {
current.getReturnState(0).toString()
}
buf.append(" [label=\"")
buf.append(returnState)
buf.append("\"];\n")
continue
}
val arr = current as ArrayPredictionContext
buf.append(" s")
buf.append(arr.id)
buf.append(" [shape=box, label=\"")
buf.append("[")
var first = true
for (inv in arr.returnStates) {
if (!first) {
buf.append(", ")
}
if (inv == EMPTY_RETURN_STATE) {
buf.append("$")
} else {
buf.append(inv)
}
first = false
}
buf.append("]")
buf.append("\"];\n")
}
for (current in nodes) {
if (current === EmptyPredictionContext) {
continue
}
val size = current.size()
for (i in 0..")
buf.append("s")
buf.append(parent.id)
if (size > 1) {
buf.append(" [label=\"parent[$i]\"];\n")
} else {
buf.append(";\n")
}
}
}
buf.append("}\n")
return buf.toString()
}
// From Sam
public fun getCachedContext(
context: PredictionContext,
contextCache: PredictionContextCache,
visited: MutableMap,
): PredictionContext {
if (context.isEmpty) {
return context
}
var existing = visited[context]
if (existing != null) {
return existing
}
existing = contextCache[context]
if (existing != null) {
visited[context] = existing
return existing
}
var changed = false
var parents = arrayOfNulls(context.size())
for (i in parents.indices) {
val parent = getCachedContext(context.getParent(i)!!, contextCache, visited)
if (changed || parent !== context.getParent(i)) {
if (!changed) {
parents = arrayOfNulls(context.size())
for (j in 0.. {
val nodes = ArrayList()
val visited = IdentityHashMap()
getAllContextNodes_(context, nodes, visited)
return nodes
}
@Suppress("FunctionName")
public fun getAllContextNodes_(
context: PredictionContext?,
nodes: MutableList,
visited: MutableMap,
) {
if (context == null || visited.containsKey(context)) {
return
}
visited[context] = context
nodes.add(context)
for (i in 0..): String =
toString()
public open fun toStrings(recognizer: Recognizer<*, *>, currentState: Int): Array =
toStrings(recognizer, EmptyPredictionContext, currentState)
// From Sam
public open fun toStrings(recognizer: Recognizer<*, *>?, stop: PredictionContext, currentState: Int): Array {
val result = ArrayList()
var perm = 0
outer@ while (true) {
var offset = 0
var last = true
var p: PredictionContext? = this
var stateNumber = currentState
val localBuffer = StringBuilder()
localBuffer.append("[")
while (!p!!.isEmpty && p !== stop) {
var index = 0
if (p.size() > 0) {
var bits = 1
while (1 shl bits < p.size()) {
bits++
}
val mask = (1 shl bits) - 1
index = (perm shr offset) and mask
last = last and (index >= p.size() - 1)
if (index >= p.size()) {
perm++
continue@outer
}
offset += bits
}
if (recognizer != null) {
if (localBuffer.length > 1) {
// First char is '[', if more than that this isn't the first rule
localBuffer.append(" ")
}
val atn = recognizer.atn
val s = atn.states[stateNumber]
val ruleName = recognizer.ruleNames[s!!.ruleIndex]
localBuffer.append(ruleName)
} else if (p.getReturnState(index) != EMPTY_RETURN_STATE) {
if (!p.isEmpty) {
if (localBuffer.length > 1) {
// First char is '[', if more than that this isn't the first rule
localBuffer.append(" ")
}
localBuffer.append(p.getReturnState(index))
}
}
stateNumber = p.getReturnState(index)
p = p.getParent(index)
}
localBuffer.append("]")
result.add(localBuffer.toString())
if (last) {
break
}
perm++
}
return result.toTypedArray()
}
override fun hashCode(): Int =
cachedHashCode
}