Skip to content

Commit dbffa0a

Browse files
Document simplifyAndAppend function with detailed explanation of behavior, parameters, and invariants in Parser.kt.
1 parent c0a7cef commit dbffa0a

File tree

1 file changed

+31
-4
lines changed
  • core/common/src/internal/format/parser

1 file changed

+31
-4
lines changed

core/common/src/internal/format/parser/Parser.kt

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,12 +91,32 @@ internal fun <T> List<ParserStructure<T>>.concat(): ParserStructure<T> {
9191
return ParserStructure(mergedOperations, simplifiedParserStructure.followedBy)
9292
}
9393

94+
/**
95+
* Simplifies this parser structure and appends [other] to all execution paths.
96+
*
97+
* Simplification includes:
98+
* - Merging consecutive number spans into single operations
99+
* - Collecting unconditional modifications and applying them before regular operations or at branch ends
100+
* - Flattening nested alternatives
101+
*
102+
* Number span handling at branch ends:
103+
* - If no alternative starts with a number span, the pending number span is added as a separate operation
104+
* - If any alternative starts with a number span, the pending number span is distributed to all alternatives
105+
* via [mergeOperations] for proper merging
106+
*
107+
* Invariant: [mergeOperations] is only called when the target structure has non-empty
108+
* operations, ensuring correct merging and unconditional modification placement.
109+
*
110+
* @param other The simplified parser structure to append
111+
* @return A new parser structure representing the simplified concatenation
112+
*/
94113
fun ParserStructure<T>.simplifyAndAppend(other: ParserStructure<T>): ParserStructure<T> {
95114
val newOperations = mutableListOf<ParserOperation<T>>()
96115
var currentNumberSpan: MutableList<NumberConsumer<T>>? = null
97116
val unconditionalModifications = mutableListOf<UnconditionalModification<T>>()
98-
// joining together the number consumers in this parser before the first alternative;
99-
// collecting the unconditional modifications.
117+
118+
// Joining together the number consumers in this parser before the first alternative.
119+
// Collecting the unconditional modifications.
100120
for (op in operations) {
101121
if (op is NumberSpanParserOperation) {
102122
if (currentNumberSpan != null) {
@@ -107,6 +127,7 @@ internal fun <T> List<ParserStructure<T>>.concat(): ParserStructure<T> {
107127
} else if (op is UnconditionalModification) {
108128
unconditionalModifications.add(op)
109129
} else {
130+
// Flush pending number span and unconditional modifications before regular operations
110131
if (currentNumberSpan != null) {
111132
newOperations.add(NumberSpanParserOperation(currentNumberSpan))
112133
currentNumberSpan = null
@@ -117,6 +138,7 @@ internal fun <T> List<ParserStructure<T>>.concat(): ParserStructure<T> {
117138
}
118139
}
119140

141+
// Recursively process alternatives, appending [other] and flattening nested structures
120142
val mergedTails = followedBy.flatMap {
121143
val simplified = it.simplifyAndAppend(other)
122144
// parser `ParserStructure(emptyList(), p)` is equivalent to `p`,
@@ -129,21 +151,26 @@ internal fun <T> List<ParserStructure<T>>.concat(): ParserStructure<T> {
129151
listOf(simplified)
130152
}.ifEmpty {
131153
if (other.operations.isNotEmpty()) {
154+
// Safe to call mergeOperations: target has operations
132155
return mergeOperations(newOperations, currentNumberSpan, unconditionalModifications, other)
133156
}
157+
// [other] has no operations, just alternatives; use them as our tails
134158
other.followedBy
135159
}
136160

137161
return if (currentNumberSpan == null) {
138-
// the last operation was not a number span, or it was a number span that we are allowed to interrupt
162+
// The last operation was not a number span, or it was a number span that we are allowed to interrupt
139163
newOperations.addAll(unconditionalModifications)
140164
ParserStructure(newOperations, mergedTails)
141165
} else if (mergedTails.none { it.operations.firstOrNull() is NumberSpanParserOperation }) {
142-
// the last operation was a number span, but there are no alternatives that start with a number span.
166+
// The last operation was a number span, but there are no alternatives that start with a number span.
143167
newOperations.add(NumberSpanParserOperation(currentNumberSpan))
144168
newOperations.addAll(unconditionalModifications)
145169
ParserStructure(newOperations, mergedTails)
146170
} else {
171+
// The last operation was a number span, and some alternatives start with one: distribute for merging.
172+
// [mergeOperations] is safe here because each alternative in [mergedTails] has operations
173+
// (verified by the structure coming from the recursive [simplifyAndAppend] calls).
147174
val newTails = mergedTails.map {
148175
mergeOperations(emptyList(), currentNumberSpan, unconditionalModifications, it)
149176
}

0 commit comments

Comments
 (0)