Skip to content

Commit 3ba3284

Browse files
committed
Refactor GLL algorithm. Add base correctness tests
1 parent 7316694 commit 3ba3284

File tree

29 files changed

+475
-267
lines changed

29 files changed

+475
-267
lines changed

solver/src/main/kotlin/org/ucfs/grammar/combinator/Grammar.kt

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -45,22 +45,4 @@ open class Grammar {
4545
//if nonterminal not initialized -- it will be checked in buildRsmBox()
4646
return startNt.nonterm.startState
4747
}
48-
49-
/**
50-
* Get all terminals used in RSM from current state (recursive)
51-
*/
52-
fun getTerminals(): Iterable<ITerminal> {
53-
val terms : HashSet<ITerminal> = incrementalDfs(
54-
rsm,
55-
{ state: RsmState ->
56-
state.nonterminalEdgesStorage.map { it.destinationState.nonterminal.startState } +
57-
state.nonterminalEdgesStorage.map { (it.symbol as Nonterminal).startState }
58-
},
59-
hashSetOf(),
60-
{ state, set -> set.addAll(state.terminalEdgesStorage.map { it.symbol as ITerminal }) }
61-
)
62-
val comparator = terms.firstOrNull()?.getComparator() ?: return emptyList()
63-
return terms.toSortedSet(comparator).toList()
64-
}
65-
6648
}

solver/src/main/kotlin/org/ucfs/gss/GraphStructuredStack.kt

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,20 @@ class GraphStructuredStack<InputNode> {
99

1010
fun getOrCreateNode(input: InputNode, rsm: RsmState): GssNode<InputNode> {
1111
val node = findNode(input, rsm)
12-
return if(node == null) GssNode(rsm, input) else node
12+
return if (node == null) GssNode(rsm, input) else node
1313
}
1414

15-
fun findNode(input: InputNode, rsm: RsmState): GssNode<InputNode>?{
16-
return nodes.find{ node -> node.inputPosition == input && node.rsm == rsm}
15+
fun findNode(input: InputNode, rsm: RsmState): GssNode<InputNode>? {
16+
return nodes.find { node -> node.inputPosition == input && node.rsm == rsm }
1717
}
1818

19-
fun addEdge(gssNode: GssNode<InputNode>,
20-
rsmStateToReturn: RsmState,
21-
inputToContinue: InputNode,
22-
rsmStateToContinue: RsmState,
23-
matcherRange: RangeSppfNode<InputNode>): GssResult<InputNode> {
19+
fun addEdge(
20+
gssNode: GssNode<InputNode>,
21+
rsmStateToReturn: RsmState,
22+
inputToContinue: InputNode,
23+
rsmStateToContinue: RsmState,
24+
matcherRange: RangeSppfNode<InputNode>
25+
): GssResult<InputNode> {
2426
val addedNode = getOrCreateNode(inputToContinue, rsmStateToContinue)
2527
val edge = GssEdge(gssNode, rsmStateToReturn, matcherRange)
2628

@@ -37,8 +39,9 @@ class GraphStructuredStack<InputNode> {
3739
/**
3840
* return outgoing edges
3941
*/
40-
fun pop(descriptor: Descriptor<InputNode>, range: RangeSppfNode<InputNode>):
41-
ArrayList<GssEdge<InputNode>> {
42+
fun pop(
43+
descriptor: Descriptor<InputNode>, range: RangeSppfNode<InputNode>
44+
): ArrayList<GssEdge<InputNode>> {
4245
val gssNode = descriptor.gssNode
4346
gssNode.popped.add(range)
4447
return gssNode.outgoingEdges
@@ -47,8 +50,7 @@ class GraphStructuredStack<InputNode> {
4750
}
4851

4952
data class GssResult<InputNodeType>(
50-
val gssNode: GssNode<InputNodeType>,
51-
val popped: ArrayList<RangeSppfNode<InputNodeType>>
53+
val gssNode: GssNode<InputNodeType>, val popped: ArrayList<RangeSppfNode<InputNodeType>>
5254
)
5355

5456

solver/src/main/kotlin/org/ucfs/gss/GssNode.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import kotlin.collections.ArrayList
1010
* Node in Graph Structured Stack
1111
* @param InputNodeType - type of vertex in input graph
1212
*/
13+
var lastId = 0
14+
1315
data class GssNode<InputNodeType>(
1416
/**
1517
* RSM corresponding to grammar slot
@@ -18,7 +20,7 @@ data class GssNode<InputNodeType>(
1820
/**
1921
* Pointer to vertex in input graph
2022
*/
21-
val inputPosition: InputNodeType
23+
val inputPosition: InputNodeType, val id: Int = lastId++
2224

2325
) {
2426
val popped = ArrayList<RangeSppfNode<InputNodeType>>()
@@ -28,7 +30,7 @@ data class GssNode<InputNodeType>(
2830
/**
2931
* Add edge and return popped
3032
*/
31-
fun addEdge(edge: GssEdge<InputNodeType>): ArrayList<RangeSppfNode<InputNodeType>>{
33+
fun addEdge(edge: GssEdge<InputNodeType>): ArrayList<RangeSppfNode<InputNodeType>> {
3234
outgoingEdges.add(edge)
3335
//TODO
3436
return popped

solver/src/main/kotlin/org/ucfs/input/DotParser.kt

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ import org.antlr.v4.runtime.CommonTokenStream
55
import org.ucfs.input.utils.dot.DotLexer
66
import org.ucfs.input.utils.dot.DotParser
77
import org.ucfs.input.utils.dot.GraphFromDotVisitor
8-
import org.ucfs.parser.ParsingException
9-
import org.ucfs.rsm.symbol.ITerminal
108
import java.io.File
119
import java.io.IOException
1210

@@ -32,24 +30,4 @@ class DotParser {
3230
)
3331
return GraphFromDotVisitor().visitGraph(realParser.graph())
3432
}
35-
36-
37-
class StringTerminal(val value: String) : ITerminal {
38-
override fun getComparator(): Comparator<ITerminal> {
39-
return object : Comparator<ITerminal> {
40-
override fun compare(a: ITerminal, b: ITerminal): Int {
41-
if (a !is StringTerminal || b !is StringTerminal) {
42-
throw ParsingException(
43-
"used comparator for $javaClass, " + "but got elements of ${a.javaClass}$ and ${b.javaClass}\$"
44-
)
45-
}
46-
return a.value.compareTo(b.value)
47-
}
48-
}
49-
}
50-
51-
override fun toString(): String {
52-
return value
53-
}
54-
}
5533
}

solver/src/main/kotlin/org/ucfs/input/utils/dot/GraphFromDotVisitor.kt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
package org.ucfs.input.utils.dot
22

3-
import org.ucfs.input.DotParser.StringTerminal
43
import org.ucfs.input.InputGraph
54
import org.ucfs.input.TerminalInputLabel
5+
import org.ucfs.rsm.symbol.Term
66

7-
class GraphFromDotVisitor: DotBaseVisitor<InputGraph<Int, TerminalInputLabel>>() {
7+
class GraphFromDotVisitor : DotBaseVisitor<InputGraph<Int, TerminalInputLabel>>() {
88
lateinit var graph: InputGraph<Int, TerminalInputLabel>
99

1010
override fun visitGraph(ctx: DotParser.GraphContext?): InputGraph<Int, TerminalInputLabel> {
@@ -20,7 +20,8 @@ class GraphFromDotVisitor: DotBaseVisitor<InputGraph<Int, TerminalInputLabel>>()
2020
}
2121

2222
private fun parseSimpleEdge(edgeView: String): TerminalInputLabel {
23-
return TerminalInputLabel(StringTerminal(edgeView))
23+
val viewWithoutQuotes = edgeView.substring(1, edgeView.length - 1)
24+
return TerminalInputLabel(Term(viewWithoutQuotes))
2425
}
2526

2627
override fun visitEdge_stmt(ctx: DotParser.Edge_stmtContext?): InputGraph<Int, TerminalInputLabel> {
@@ -49,7 +50,7 @@ class GraphFromDotVisitor: DotBaseVisitor<InputGraph<Int, TerminalInputLabel>>()
4950
}
5051

5152
override fun visitNode_stmt(ctx: DotParser.Node_stmtContext?): InputGraph<Int, TerminalInputLabel> {
52-
if(ctx?.node_id()?.text == "start"){
53+
if (ctx?.node_id()?.text == "start") {
5354
return super.visitNode_stmt(ctx)
5455

5556
}

solver/src/main/kotlin/org/ucfs/intersection/IntersectionEngine.kt

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import org.ucfs.rsm.symbol.Nonterminal
88

99
object IntersectionEngine : IIntersectionEngine {
1010

11+
1112
/**
1213
* Process outgoing edges from input position in given descriptor, according to processing logic, represented as
1314
* separate functions for both outgoing terminal and nonterminal edges from rsmState in descriptor
@@ -21,18 +22,20 @@ object IntersectionEngine : IIntersectionEngine {
2122

2223
for (inputEdge in gll.ctx.input.getEdges(descriptor.inputPosition)) {
2324
val inputTerminal = inputEdge.label.terminal
24-
descriptor.rsmState.terminalEdgesStorage.find { rsmEdge -> rsmEdge.symbol == inputTerminal }?. let {
25-
rsmEdge -> gll.handleTerminalEdge(
26-
descriptor,
27-
inputEdge,
28-
rsmEdge.destinationState,
29-
rsmEdge.symbol as ITerminal
30-
)
25+
val rsmEdge = descriptor.rsmState.terminalEdgesStorage.find {
26+
it.symbol == inputTerminal
27+
}
28+
if (rsmEdge != null) {
29+
gll.handleTerminalEdge(
30+
descriptor, inputEdge, rsmEdge.destinationState, rsmEdge.symbol as ITerminal
31+
)
3132
}
3233
}
3334

3435
for (nonterminalEdge in descriptor.rsmState.nonterminalEdgesStorage) {
35-
gll.handleNonterminalEdge(descriptor, nonterminalEdge.destinationState, nonterminalEdge.symbol as Nonterminal)
36+
gll.handleNonterminalEdge(
37+
descriptor, nonterminalEdge.destinationState, nonterminalEdge.symbol as Nonterminal
38+
)
3639
}
3740
}
3841
}

solver/src/main/kotlin/org/ucfs/parser/Gll.kt

Lines changed: 36 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -34,58 +34,60 @@ class Gll<VertexType, LabelType : ILabel> private constructor(
3434
}
3535

3636
private fun getEpsilonRange(descriptor: Descriptor<VertexType>): RangeSppfNode<VertexType> {
37-
return RangeSppfNode(
38-
InputRange(
39-
descriptor.inputPosition,
40-
descriptor.inputPosition,
41-
),
42-
RsmRange(
43-
descriptor.rsmState,
44-
descriptor.rsmState,
45-
),
46-
EpsilonNonterminalType(descriptor.gssNode.rsm)
37+
val input = InputRange(
38+
descriptor.inputPosition,
39+
descriptor.inputPosition,
40+
)
41+
val rsm = RsmRange(
42+
descriptor.rsmState,
43+
descriptor.rsmState,
44+
)
45+
val range = ctx.sppfStorage.addNode(RangeSppfNode(input, rsm, Range))
46+
val epsilon = ctx.sppfStorage.addNode(
47+
RangeSppfNode(input, rsm, EpsilonNonterminalType(descriptor.gssNode.rsm))
4748
)
49+
range.children.add(epsilon)
50+
return range
4851
}
4952

50-
private fun handlePoppedGssEdge(poppedGssEdge: GssEdge<VertexType>, descriptor: Descriptor<VertexType>){
53+
private fun handlePoppedGssEdge(
54+
poppedGssEdge: GssEdge<VertexType>, descriptor: Descriptor<VertexType>, childSppf: RangeSppfNode<VertexType>
55+
) {
5156
val leftRange = poppedGssEdge.matchedRange
52-
val startRsmState =
53-
if (poppedGssEdge.matchedRange.type == EmptyType)
54-
poppedGssEdge.gssNode.rsm
55-
else
56-
poppedGssEdge.matchedRange.rsmRange!!.rsmTo
57-
val rightEdge = RangeSppfNode(
57+
val startRsmState = if (poppedGssEdge.matchedRange.type == EmptyType) poppedGssEdge.gssNode.rsm
58+
else poppedGssEdge.matchedRange.rsmRange!!.to
59+
val rightRange = ctx.sppfStorage.addNode(
5860
InputRange(
59-
descriptor.gssNode.inputPosition,
60-
descriptor.inputPosition
61-
),
62-
RsmRange(
61+
descriptor.gssNode.inputPosition, descriptor.inputPosition
62+
), RsmRange(
6363
startRsmState,
6464
poppedGssEdge.state,
65-
),
66-
NonterminalType(descriptor.gssNode.rsm)
65+
), descriptor.gssNode.rsm, childSppf
6766
)
68-
ctx.sppfStorage.addNode(rightEdge)
69-
val newRange = ctx.sppfStorage.addNode(leftRange, rightEdge)
67+
ctx.sppfStorage.addNode(rightRange)
68+
val newRange = ctx.sppfStorage.addNode(leftRange, rightRange)
7069
val newDescriptor = Descriptor(
71-
descriptor.inputPosition,
72-
poppedGssEdge.gssNode,
73-
poppedGssEdge.state,
74-
newRange
70+
descriptor.inputPosition, poppedGssEdge.gssNode, poppedGssEdge.state, newRange
7571
)
7672
ctx.descriptors.add(newDescriptor)
7773
}
74+
7875
/**
7976
* Processes descriptor
8077
* @param descriptor - descriptor to process
8178
*/
8279
override fun handleDescriptor(descriptor: Descriptor<VertexType>) {
8380
ctx.descriptors.addToHandled(descriptor)
84-
if(descriptor.rsmState.isFinal){
85-
val matchedRange = if(descriptor.sppfNode.type == EmptyType) getEpsilonRange(descriptor) else descriptor.sppfNode
86-
val gssEdges = ctx.gss.pop(descriptor, matchedRange)
87-
gssEdges.map{::handlePoppedGssEdge}
88-
if(descriptor.rsmState == ctx.startState){
81+
if (descriptor.rsmState.isFinal) {
82+
val matchedRange = if (descriptor.sppfNode.type == EmptyType) {
83+
getEpsilonRange(descriptor)
84+
} else {
85+
descriptor.sppfNode
86+
}
87+
for (poppedEdge in ctx.gss.pop(descriptor, matchedRange)) {
88+
handlePoppedGssEdge(poppedEdge, descriptor, matchedRange)
89+
}
90+
if (descriptor.gssNode.outgoingEdges.isEmpty() && descriptor.gssNode.rsm.isStart) {
8991
ctx.parseResult = matchedRange
9092
}
9193
}

solver/src/main/kotlin/org/ucfs/parser/IGll.kt

Lines changed: 22 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -54,54 +54,40 @@ interface IGll<InputNodeType, LabelType : ILabel> {
5454

5555
val gssNode = ctx.gss.getOrCreateNode(startVertex, ctx.startState)
5656
val startDescriptor = Descriptor(
57-
startVertex,
58-
gssNode,
59-
ctx.startState,
60-
getEmptyRange()
57+
startVertex, gssNode, ctx.startState, getEmptyRange()
6158
)
6259
ctx.descriptors.add(startDescriptor)
6360
}
6461
}
6562

6663
fun handleNonterminalEdge(
67-
descriptor: Descriptor<InputNodeType>,
68-
destinationRsmState: RsmState,
69-
edgeNonterminal: Nonterminal
64+
descriptor: Descriptor<InputNodeType>, destinationRsmState: RsmState, edgeNonterminal: Nonterminal
7065
) {
7166
val rsmStartState = edgeNonterminal.startState
7267
val (newGssNode, positionToPops) = ctx.gss.addEdge(
73-
descriptor.gssNode,
74-
destinationRsmState,
75-
descriptor.inputPosition,
76-
rsmStartState,
77-
descriptor.sppfNode
68+
descriptor.gssNode, destinationRsmState, descriptor.inputPosition, rsmStartState, descriptor.sppfNode
7869
)
7970

8071
var newDescriptor = Descriptor(
81-
descriptor.inputPosition,
82-
newGssNode,
83-
rsmStartState,
84-
getEmptyRange())
72+
descriptor.inputPosition, newGssNode, rsmStartState, getEmptyRange()
73+
)
8574
ctx.descriptors.add(newDescriptor)
8675

87-
for(rangeToPop in positionToPops){
76+
for (rangeToPop in positionToPops) {
8877
val leftSubRange = descriptor.sppfNode
89-
val rightSubRange = ctx.sppfStorage.addNode(RangeSppfNode(
90-
rangeToPop.inputRange,
91-
RsmRange(
92-
descriptor.rsmState,
93-
destinationRsmState
94-
),
95-
NonterminalType(rsmStartState)
96-
))
78+
val rightSubRange = ctx.sppfStorage.addNode(
79+
RangeSppfNode(
80+
rangeToPop.inputRange, RsmRange(
81+
descriptor.rsmState, destinationRsmState
82+
), NonterminalType(rsmStartState)
83+
)
84+
)
9785
val newSppfNode = ctx.sppfStorage.addNode(leftSubRange, rightSubRange)
9886

9987
//TODO why these parameters???
10088
newDescriptor = Descriptor(
101-
rangeToPop.inputRange!!.to,
102-
descriptor.gssNode,
103-
destinationRsmState,
104-
newSppfNode)
89+
rangeToPop.inputRange!!.to, descriptor.gssNode, destinationRsmState, newSppfNode
90+
)
10591
ctx.descriptors.add(newDescriptor)
10692
}
10793
}
@@ -113,23 +99,19 @@ interface IGll<InputNodeType, LabelType : ILabel> {
11399
destinationRsmState: RsmState,
114100
terminal: ITerminal
115101
) {
116-
val terminalNode = RangeSppfNode(
102+
var terminalSppfNode = ctx.sppfStorage.addNode(
117103
InputRange(
118104
descriptor.inputPosition,
119105
inputEdge.targetVertex,
120-
),
121-
RsmRange(
106+
), RsmRange(
122107
descriptor.rsmState,
123108
destinationRsmState,
124-
),
125-
TerminalType(terminal)
126-
)
109+
), terminal
110+
)
111+
val intermediateOrTerminalSppf = ctx.sppfStorage.addNode(descriptor.sppfNode, terminalSppfNode)
127112
val descriptorForTerminal = Descriptor(
128-
inputEdge.targetVertex,
129-
descriptor.gssNode,
130-
destinationRsmState,
131-
terminalNode
132-
)
113+
inputEdge.targetVertex, descriptor.gssNode, destinationRsmState, intermediateOrTerminalSppf
114+
)
133115
ctx.descriptors.add(descriptorForTerminal)
134116
}
135117
}

0 commit comments

Comments
 (0)