diff --git a/solver/src/main/kotlin/org/ucfs/parser/Gll.kt b/solver/src/main/kotlin/org/ucfs/parser/Gll.kt index 5495d2b2a..c70c9b5fa 100644 --- a/solver/src/main/kotlin/org/ucfs/parser/Gll.kt +++ b/solver/src/main/kotlin/org/ucfs/parser/Gll.kt @@ -70,7 +70,7 @@ class Gll private constructor( private fun isParseResult(matchedRange: RangeSppfNode): Boolean { return matchedRange.inputRange!!.from in ctx.input.getInputStartVertices() && matchedRange.rsmRange!!.from == ctx.fictiveStartState - && matchedRange.rsmRange.to == ctx.fictiveFinalState + && matchedRange.rsmRange!!.to == ctx.fictiveFinalState } /** diff --git a/solver/src/main/kotlin/org/ucfs/parser/IGll.kt b/solver/src/main/kotlin/org/ucfs/parser/IGll.kt index 0796d5a52..cb0ad1384 100644 --- a/solver/src/main/kotlin/org/ucfs/parser/IGll.kt +++ b/solver/src/main/kotlin/org/ucfs/parser/IGll.kt @@ -86,7 +86,7 @@ interface IGll { //TODO why these parameters??? newDescriptor = Descriptor( - rangeToPop.inputRange.to, descriptor.gssNode, destinationRsmState, newSppfNode + rangeToPop.inputRange!!.to, descriptor.gssNode, destinationRsmState, newSppfNode ) ctx.descriptors.add(newDescriptor) } diff --git a/solver/src/main/kotlin/org/ucfs/sppf/SppfStorage.kt b/solver/src/main/kotlin/org/ucfs/sppf/SppfStorage.kt index 253b654ce..1a5c6749d 100644 --- a/solver/src/main/kotlin/org/ucfs/sppf/SppfStorage.kt +++ b/solver/src/main/kotlin/org/ucfs/sppf/SppfStorage.kt @@ -18,6 +18,16 @@ open class SppfStorage { return createdSppfNodes.getOrPut(node, { node }) } + private fun makeNode( + input: InputRange?, + rsm: RsmRange?, + type: RangeType + ): RangeSppfNode = when (type) { + is TerminalType<*>, is EpsilonNonterminalType, is EmptyType -> LeafSppfNode(input, rsm, type) + is IntermediateType<*> -> BinarySppfNode(input, rsm, type) + else -> VariadicSppfNode(input, rsm, type) // Range, NonterminalType + } + /** * Add nonterminal node after pop */ @@ -63,7 +73,7 @@ open class SppfStorage { ), RsmRange( leftSubtree.rsmRange!!.from, rightSubtree.rsmRange!!.to ), IntermediateType( - leftSubtree.rsmRange.to, leftSubtree.inputRange.to + leftSubtree.rsmRange!!.to, leftSubtree.inputRange!!.to ), listOf(leftSubtree, rightSubtree) ) } @@ -74,17 +84,18 @@ open class SppfStorage { rangeType: RangeType, children: List> = listOf() ): RangeSppfNode { - val rangeNode = addNode(RangeSppfNode(input, rsm, Range)) + val rangeNode = addNode(makeNode(input, rsm, Range)) val valueRsm = if (rangeType is TerminalType<*>) null else rsm - val valueNode = addNode(RangeSppfNode(input, valueRsm, rangeType)) - if (!rangeNode.children.contains(valueNode)) { - rangeNode.children.add(valueNode) + val valueNode = addNode(makeNode(input, valueRsm, rangeType)) + + if (!rangeNode.hasChild(valueNode)) { + rangeNode.addChild(valueNode) } for (child in children) { - if (!valueNode.children.contains(child)) { - valueNode.children.add(child) + if (!valueNode.hasChild(child)) { + valueNode.addChild(child) } } return rangeNode } -} \ No newline at end of file +} diff --git a/solver/src/main/kotlin/org/ucfs/sppf/buildStringFromSppf.kt b/solver/src/main/kotlin/org/ucfs/sppf/buildStringFromSppf.kt index 243923193..c25478eb2 100644 --- a/solver/src/main/kotlin/org/ucfs/sppf/buildStringFromSppf.kt +++ b/solver/src/main/kotlin/org/ucfs/sppf/buildStringFromSppf.kt @@ -29,7 +29,7 @@ fun buildTokenStreamFromSppf(sppfNode: RangeSppfNode): Mut } is NonterminalType -> { - if (curNode.children.isNotEmpty()) { + if (curNode.children.toList().isNotEmpty()) { curNode.children.findLast { !visited.contains( it @@ -50,4 +50,4 @@ fun buildTokenStreamFromSppf(sppfNode: RangeSppfNode): Mut */ fun buildStringFromSppf(sppfNode: RangeSppfNode): String { return buildTokenStreamFromSppf(sppfNode).joinToString(separator = "") -} \ No newline at end of file +} diff --git a/solver/src/main/kotlin/org/ucfs/sppf/node/RangeSppfNode.kt b/solver/src/main/kotlin/org/ucfs/sppf/node/RangeSppfNode.kt index 1ea12899c..260f02ffd 100644 --- a/solver/src/main/kotlin/org/ucfs/sppf/node/RangeSppfNode.kt +++ b/solver/src/main/kotlin/org/ucfs/sppf/node/RangeSppfNode.kt @@ -6,24 +6,103 @@ import org.ucfs.rsm.RsmState import org.ucfs.rsm.symbol.ITerminal /** + * Base class for SPPF range nodes. + * Represents all possible ways to derive a specific range. + * Contains two ranges: one in the RSM and one in the input graph. + * Nodes are deduplicated via [SppfStorage] and can be reused. + * + * Specialized into three subclasses based on the number of children: + * - [LeafSppfNode] — no children (terminal, epsilon, empty nodes) + * - [BinarySppfNode] — exactly two children (intermediate nodes) + * - [VariadicSppfNode] — variable number of children (range, nonterminal nodes) * - * A Range node which corresponds to a matched range. It - * represents all possible ways to get a specific range and can - * have arbitrary many children. A child node can be of any - * type, besides a Range node. Nodes of this type can be reused. - *

- * Contains two range: in RSM and in Input graph - *

- * May be used as extended packed sppfNode. * @param VertexType - type of vertex in input graph */ +sealed class RangeSppfNode { + abstract val inputRange: InputRange? + abstract val rsmRange: RsmRange? + abstract val type: RangeType + abstract fun hasChild(target: RangeSppfNode): Boolean + abstract fun addChild(child: RangeSppfNode) + abstract val children: Iterable> +} -data class RangeSppfNode( - val inputRange: InputRange?, - val rsmRange: RsmRange?, - val type: RangeType, -) { - val children = ArrayList>() +data class LeafSppfNode( + override val inputRange: InputRange?, + override val rsmRange: RsmRange?, + override val type: RangeType, +) : RangeSppfNode() { + override val children = emptyList>() + + override fun hasChild(target: RangeSppfNode) = false + + override fun addChild(child: RangeSppfNode) = throw UnsupportedOperationException() +} + +data class BinarySppfNode( + override val inputRange: InputRange?, + override val rsmRange: RsmRange?, + override val type: RangeType, +) : RangeSppfNode() { + var child0: RangeSppfNode? = null + var child1: RangeSppfNode? = null + + override val children: Iterable> get() = listOfNotNull(child0, child1) + + override fun hasChild(target: RangeSppfNode) = + child0 === target || child1 === target + + override fun addChild(child: RangeSppfNode) { + when { + child0 == null -> child0 = child + child1 == null -> child1 = child + else -> throw IllegalStateException("BinarySppfNode already has 2 children") + } + } +} + +data class VariadicSppfNode( + override val inputRange: InputRange?, + override val rsmRange: RsmRange?, + override val type: RangeType, +) : RangeSppfNode() { + private var _child0: RangeSppfNode? = null + private var _child1: RangeSppfNode? = null + private var _rest: ArrayList>? = null + private var _size = 0 + + override val children: Iterable> get() = object : Iterable> { + override fun iterator() = object : Iterator> { + var i = 0 + + override fun hasNext() = i < _size + + override fun next(): RangeSppfNode = when (i++) { + 0 -> _child0!! + 1 -> _child1!! + else -> _rest!![i - 3] + } + } + } + + override fun hasChild(target: RangeSppfNode): Boolean { + if (_child0 === target) return true + if (_child1 === target) return true + _rest?.forEach { if (it === target) return true } + return false + } + + override fun addChild(child: RangeSppfNode) { + when (_size) { + 0 -> _child0 = child + 1 -> _child1 = child + else -> { + if (_rest == null) _rest = ArrayList(2) + _rest!!.add(child) + } + } + _size++ + } } fun getEmptyRange( isStart: Boolean = false): RangeSppfNode { @@ -31,7 +110,7 @@ fun getEmptyRange( isStart: Boolean = false): RangeSppfNode( diff --git a/solver/src/main/kotlin/org/ucfs/sppf/writeSppfToDot.kt b/solver/src/main/kotlin/org/ucfs/sppf/writeSppfToDot.kt index d9391295e..89922051b 100644 --- a/solver/src/main/kotlin/org/ucfs/sppf/writeSppfToDot.kt +++ b/solver/src/main/kotlin/org/ucfs/sppf/writeSppfToDot.kt @@ -21,7 +21,7 @@ fun getSppfDot(sppfNodes: Set>, label: Stri sb.appendLine("labelloc=\"t\"") sb.appendLine("label=\"$label\"") var idx = 0 - val results = sppfNodes.sortedWith(compareBy { it.toString() }).map { sppf -> getSppfDot(sppf.children[0], idx++.toString()) } + val results = sppfNodes.sortedWith(compareBy { it.toString() }).map { sppf -> getSppfDot(sppf.children.first(), idx++.toString()) } for (sppf in results.sorted()) { sb.appendLine(sppf) }