@@ -10,13 +10,14 @@ import scala.collection.mutable
10
10
import parsley .XAssert
11
11
import parsley .debug .ParseAttempt
12
12
import parsley .internal .deepembedding .frontend .LazyParsley
13
- import parsley .internal . deepembedding . frontend . debug .RemoteBreak
14
- import parsley .debug .*
13
+ import parsley .debug .DebugView
14
+ import parsley .debug .RefCodec . CodedRef
15
15
16
16
// Class used to hold details about a parser being debugged.
17
17
// This is normally held as a value inside an implicit variable.
18
18
// Anything caught by the toStringRules will have a parse result of that type toString-ed for memory
19
19
// efficiency.
20
+
20
21
private [parsley] class DebugContext (private val toStringRules : PartialFunction [Any , Boolean ], private val view : DebugView ) {
21
22
// Create a new dummy root of the tree that will act as filler for the rest of the tree to build
22
23
// off of (as there is no "nil" representation for the tree... other than null, which should be
@@ -45,7 +46,7 @@ private [parsley] class DebugContext(private val toStringRules: PartialFunction[
45
46
XAssert .assert(! (ch.size > 1 ), s " The root tree has somehow gained multiple children. ( ${ch.size}) " )
46
47
47
48
// This should never fail.
48
- ch.head
49
+ ch.head.withoutBreakpoints().withoutNewlyGeneratedFlags()
49
50
}
50
51
51
52
// Add an attempt of parsing at the current stack point.
@@ -83,48 +84,73 @@ private [parsley] class DebugContext(private val toStringRules: PartialFunction[
83
84
*/
84
85
private var breakpointSkips : Int = 0
85
86
86
- /** Handle a breakpoint.
87
+ /** True if associated DebugView extends the Manageable trait */
88
+ def manageableView : Boolean = view match {
89
+ case _ : DebugView .Manageable => true
90
+ case _ => false
91
+ }
92
+
93
+ private var firstBreakpoint : Boolean = true
94
+
95
+ /** Trigger a breakpoint.
87
96
*
88
- * @param tree The debug tree that has been created thus far.
89
97
* @param fullInput The full parser input.
90
- * @param view The DebugView instance. This must extend DebugView.Pauseable to work .
98
+ * @param refs References managed by this breakpoint .
91
99
*/
92
- private def handleBreak (tree : TransientDebugTree , fullInput : String ): Unit = view match {
93
- case view : DebugView .Pauseable => {
94
- if (breakpointSkips > 0 ) {
95
- breakpointSkips -= 1
96
- } else {
97
- breakpointSkips = view.renderWait(fullInput, tree)
100
+ def triggerBreak (fullInput : String , isAfter : Boolean , codedRefs : Option [Seq [CodedRef ]]): Option [Seq [CodedRef ]] = {
101
+ if (firstBreakpoint) {
102
+ builderStack.head.resetNewlyGeneratedFlags()
103
+ firstBreakpoint = false
104
+ }
105
+
106
+ val debugTree : TransientDebugTree = (if (isAfter) builderStack.head else {
107
+ // FIXME: Instead of `init`, this should take(n) where n is the number of children the next node would have.
108
+ // This can only be known after the next parser runs, and needs to be passed in after saving/restoring the builderStack
109
+ builderStack.head.copy(children = builderStack.tail.init)
110
+ }).copy(parse = Some (new ParseAttempt (" " , 0 , 0 , (0 ,0 ), (0 ,0 ), Some (()))))
111
+
112
+
113
+ val newRefs : Option [Seq [CodedRef ]] = view match {
114
+ case view : DebugView .Pauseable => {
115
+ if (breakpointSkips > 0 ) { // Skip to next breakpoint
116
+ breakpointSkips -= 1
117
+ None
118
+ } else if (breakpointSkips != - 1 ) { // Breakpoint exit
119
+ view match {
120
+ case view : DebugView .Manageable => {
121
+
122
+ // Wait for RemoteView to return breakpoint skips and updated state
123
+ val (newSkips, newRefs): (Int , Seq [CodedRef ]) = view.renderManage(fullInput, debugTree, codedRefs.get* )
124
+
125
+ // Update breakpoint skips
126
+ breakpointSkips = newSkips
127
+ Some (newRefs)
128
+ }
129
+
130
+ // Update breakpoint using Pausable render call
131
+ case _ => {
132
+ breakpointSkips = view.renderWait(fullInput, debugTree)
133
+ None
134
+ }
135
+ }
136
+ } else None
98
137
}
138
+
139
+ case _ => None
99
140
}
100
- case _ =>
141
+
142
+ debugTree.resetNewlyGeneratedFlags()
143
+ newRefs
101
144
}
102
145
103
146
// Push a new parser onto the parser callstack.
104
147
def push (fullInput : String , parser : LazyParsley [_], isIterative : Boolean , userAssignedName : Option [String ]): Unit = {
105
- // Send the debug tree here if EntryBreak
106
- parser match {
107
- case break : RemoteBreak [_] => break.break match {
108
- case EntryBreak | FullBreak => handleBreak(builderStack.head, fullInput)
109
- case _ =>
110
- }
111
- case _ =>
112
- }
113
148
114
149
val newTree = new TransientDebugTree (fullInput = fullInput)
115
150
newTree.name = Renamer .nameOf(userAssignedName, parser)
116
151
newTree.internal = Renamer .internalName(parser)
117
152
newTree.iterative = isIterative
118
153
119
- // Send the debug tree here if ExitBreak
120
- parser match {
121
- case break : RemoteBreak [_] => break.break match {
122
- case ExitBreak | FullBreak => handleBreak(newTree, fullInput)
123
- case _ =>
124
- }
125
- case _ =>
126
- }
127
-
128
154
// val uid = nextUid()
129
155
// builderStack.head.children(s"${newTree.name}-#$uid") = newTree
130
156
builderStack.head.children += newTree
0 commit comments