Skip to content

Commit 5875c72

Browse files
Refactor concat function in Parser.kt, simplifying comments
1 parent 394e7c0 commit 5875c72

File tree

1 file changed

+10
-61
lines changed
  • core/common/src/internal/format/parser

1 file changed

+10
-61
lines changed

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

Lines changed: 10 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -42,29 +42,11 @@ internal class ParserStructure<in Output>(
4242
}
4343

4444
/**
45-
* Concatenates a list of parser structures into a single structure.
46-
*
47-
* Processes parsers in reverse order, batching operations from parsers without alternatives
48-
* and simplifying the resulting structure (merging number spans, handling unconditional modifications).
49-
*
50-
* @return A single parser structure representing the composition of all parsers in the list
45+
* Concatenates a list of parser structures into a single structure, processing them in reverse order.
46+
* Simplifies the result by merging number spans and handling unconditional modifications.
5147
*/
5248
internal fun <T> List<ParserStructure<T>>.concat(): ParserStructure<T> {
53-
/**
54-
* Merges pending operations (base operations, number span, and unconditional modifications)
55-
* with a simplified parser structure.
56-
*
57-
* Invariant: this function should only be called when [simplifiedParserStructure.operations]
58-
* is non-empty. If the structure consists only of alternatives (empty operations with
59-
* non-empty followedBy), this function should NOT be called.
60-
*
61-
* @param baseOperations Operations to prepend (already processed operations from this parser)
62-
* @param numberSpan Pending number consumers that need to be merged or added (`null` if none pending)
63-
* @param unconditionalModifications Operations that must execute after all others
64-
* @param simplifiedParserStructure The simplified parser structure to merge with (must have operations)
65-
*
66-
* @return A new parser structure with all operations merged and the alternatives from [simplifiedParserStructure]
67-
*/
49+
// Invariant: only called when simplifiedParserStructure.operations is non-empty
6850
fun mergeOperations(
6951
baseOperations: List<ParserOperation<T>>,
7052
numberSpan: List<NumberConsumer<T>>?,
@@ -77,55 +59,32 @@ internal fun <T> List<ParserStructure<T>>.concat(): ParserStructure<T> {
7759
val mergedOperations = buildList {
7860
addAll(baseOperations)
7961
when {
80-
// No pending number span: just append all operations
8162
numberSpan == null -> {
8263
addAll(operationsToMerge)
8364
}
84-
// Merge the pending number span with the first operation if it's also a number span
8565
firstOperation is NumberSpanParserOperation -> {
8666
add(NumberSpanParserOperation(numberSpan + firstOperation.consumers))
8767
for (i in 1..operationsToMerge.lastIndex) {
8868
add(operationsToMerge[i])
8969
}
9070
}
91-
// Add the pending number span as a separate operation before the others
9271
else -> {
9372
add(NumberSpanParserOperation(numberSpan))
9473
addAll(operationsToMerge)
9574
}
9675
}
97-
// Unconditional modifications always go at the end of the branch
9876
addAll(unconditionalModifications)
9977
}
10078
return ParserStructure(mergedOperations, simplifiedParserStructure.followedBy)
10179
}
10280

103-
/**
104-
* Simplifies this parser structure and appends [other] to all execution paths.
105-
*
106-
* Simplification includes:
107-
* - Merging consecutive number spans into single operations
108-
* - Collecting unconditional modifications and applying them before regular operations or at branch ends
109-
* - Flattening nested alternatives
110-
*
111-
* Number span handling at branch ends:
112-
* - If no alternative starts with a number span, the pending number span is added as a separate operation
113-
* - If any alternative starts with a number span, the pending number span is distributed to all alternatives
114-
* via [mergeOperations] for proper merging
115-
*
116-
* Invariant: [mergeOperations] is only called when the target structure has non-empty
117-
* operations, ensuring correct merging and unconditional modification placement.
118-
*
119-
* @param other The simplified parser structure to append
120-
* @return A new parser structure representing the simplified concatenation
121-
*/
81+
// Simplifies this parser and appends [other] to all execution paths.
82+
// Merges number spans, collects unconditional modifications, and flattens alternatives.
12283
fun ParserStructure<T>.simplifyAndAppend(other: ParserStructure<T>): ParserStructure<T> {
12384
val newOperations = mutableListOf<ParserOperation<T>>()
12485
var currentNumberSpan: MutableList<NumberConsumer<T>>? = null
12586
val unconditionalModifications = mutableListOf<UnconditionalModification<T>>()
12687

127-
// Joining together the number consumers in this parser before the first alternative.
128-
// Collecting the unconditional modifications.
12988
for (op in operations) {
13089
if (op is NumberSpanParserOperation) {
13190
if (currentNumberSpan != null) {
@@ -136,7 +95,6 @@ internal fun <T> List<ParserStructure<T>>.concat(): ParserStructure<T> {
13695
} else if (op is UnconditionalModification) {
13796
unconditionalModifications.add(op)
13897
} else {
139-
// Flush pending number span and unconditional modifications before regular operations
14098
if (currentNumberSpan != null) {
14199
newOperations.add(NumberSpanParserOperation(currentNumberSpan))
142100
currentNumberSpan = null
@@ -147,7 +105,6 @@ internal fun <T> List<ParserStructure<T>>.concat(): ParserStructure<T> {
147105
}
148106
}
149107

150-
// Recursively process alternatives, appending [other] and flattening nested structures
151108
val mergedTails = followedBy.flatMap {
152109
val simplified = it.simplifyAndAppend(other)
153110
// Parser `ParserStructure(emptyList(), p)` is equivalent to `p`,
@@ -160,40 +117,35 @@ internal fun <T> List<ParserStructure<T>>.concat(): ParserStructure<T> {
160117
listOf(simplified)
161118
}.ifEmpty {
162119
if (other.operations.isNotEmpty()) {
163-
// Safe to call mergeOperations: target has operations
120+
// The invariant is preserved: other.operations is non-empty
164121
return mergeOperations(newOperations, currentNumberSpan, unconditionalModifications, other)
165122
}
166123
// [other] has no operations, just alternatives; use them as our tails
167124
other.followedBy
168125
}
169126

170127
return if (currentNumberSpan == null) {
171-
// The last operation was not a number span, or it was a number span that we are allowed to interrupt
172128
newOperations.addAll(unconditionalModifications)
173129
ParserStructure(newOperations, mergedTails)
174130
} else if (mergedTails.none { it.operations.firstOrNull() is NumberSpanParserOperation }) {
175-
// The last operation was a number span, but there are no alternatives that start with a number span.
176131
newOperations.add(NumberSpanParserOperation(currentNumberSpan))
177132
newOperations.addAll(unconditionalModifications)
178133
ParserStructure(newOperations, mergedTails)
179134
} else {
180-
// The last operation was a number span, and some alternatives start with one: distribute for merging.
181-
// [mergeOperations] is safe here because each alternative in [mergedTails] has operations
182-
// (verified by the structure coming from the recursive [simplifyAndAppend] calls).
183-
val newTails = mergedTails.map {
184-
mergeOperations(emptyList(), currentNumberSpan, unconditionalModifications, it)
135+
// Distribute number span across alternatives that start with number spans
136+
// The invariant is preserved: the structure coming from the recursive [simplifyAndAppend] calls
137+
val newTails = mergedTails.map { structure ->
138+
mergeOperations(emptyList(), currentNumberSpan, unconditionalModifications, structure)
185139
}
186140
ParserStructure(newOperations, newTails)
187141
}
188142
}
189143

190-
// Combine parsers in reverse order, batching operations from parsers without followedBy.
191144
var result = ParserStructure<T>(emptyList(), emptyList())
192145
val accumulatedOperations = mutableListOf<List<ParserOperation<T>>>()
193146

194147
fun flushAccumulatedOperations() {
195148
if (accumulatedOperations.isNotEmpty()) {
196-
// Reverse to restore the original order (since parsers are processed in reverse).
197149
val operations = buildList {
198150
for (parserOperations in accumulatedOperations.asReversed()) {
199151
addAll(parserOperations)
@@ -206,16 +158,13 @@ internal fun <T> List<ParserStructure<T>>.concat(): ParserStructure<T> {
206158

207159
for (parser in this.asReversed()) {
208160
if (parser.followedBy.isEmpty()) {
209-
// No followedBy: accumulate for batch processing.
210161
accumulatedOperations.add(parser.operations)
211162
} else {
212-
// Has followedBy: flush accumulated operations, then process individually.
213163
flushAccumulatedOperations()
214164
result = parser.simplifyAndAppend(result)
215165
}
216166
}
217167

218-
// Flush remaining accumulated operations.
219168
flushAccumulatedOperations()
220169
return result
221170
}

0 commit comments

Comments
 (0)