@@ -49,78 +49,81 @@ internal fun <T> List<ParserStructure<T>>.concat(): ParserStructure<T> {
4949 ParserStructure (operations, followedBy.map { it.append(other) })
5050 }
5151
52- fun <T > ParserStructure<T>.simplify (unconditionalModifications : List <UnconditionalModification <T >>): ParserStructure <T > {
53- val newOperations = mutableListOf<ParserOperation <T >>()
54- var currentNumberSpan: MutableList <NumberConsumer <T >>? = null
55- val unconditionalModificationsForTails = unconditionalModifications.toMutableList()
56- // joining together the number consumers in this parser before the first alternative;
57- // collecting the unconditional modifications to push them to the end of all the parser's branches.
58- for (op in operations) {
59- if (op is NumberSpanParserOperation ) {
60- if (currentNumberSpan != null ) {
61- currentNumberSpan.addAll(op.consumers)
52+ val cache = hashMapOf<Pair <ParserStructure <T >, List <UnconditionalModification <T >>>, ParserStructure <T >>()
53+
54+ fun ParserStructure<T>.simplify (unconditionalModifications : List <UnconditionalModification <T >>): ParserStructure <T > =
55+ cache.getOrPut(this to unconditionalModifications) {
56+ val newOperations = mutableListOf<ParserOperation <T >>()
57+ var currentNumberSpan: MutableList <NumberConsumer <T >>? = null
58+ val unconditionalModificationsForTails = unconditionalModifications.toMutableList()
59+ // joining together the number consumers in this parser before the first alternative;
60+ // collecting the unconditional modifications to push them to the end of all the parser's branches.
61+ for (op in operations) {
62+ if (op is NumberSpanParserOperation ) {
63+ if (currentNumberSpan != null ) {
64+ currentNumberSpan.addAll(op.consumers)
65+ } else {
66+ currentNumberSpan = op.consumers.toMutableList()
67+ }
68+ } else if (op is UnconditionalModification ) {
69+ unconditionalModificationsForTails.add(op)
6270 } else {
63- currentNumberSpan = op.consumers.toMutableList()
64- }
65- } else if (op is UnconditionalModification ) {
66- unconditionalModificationsForTails.add(op)
67- } else {
68- if (currentNumberSpan != null ) {
69- newOperations.add(NumberSpanParserOperation (currentNumberSpan))
70- currentNumberSpan = null
71+ if (currentNumberSpan != null ) {
72+ newOperations.add(NumberSpanParserOperation (currentNumberSpan))
73+ currentNumberSpan = null
74+ }
75+ newOperations.add(op)
7176 }
72- newOperations.add(op)
7377 }
74- }
75- val mergedTails = followedBy.flatMap {
76- val simplified = it.simplify(unconditionalModificationsForTails)
77- // parser `ParserStructure(emptyList(), p)` is equivalent to `p`,
78- // unless `p` is empty. For example, ((a|b)|(c|d)) is equivalent to (a|b|c|d).
79- // As a special case, `ParserStructure(emptyList(), emptyList())` represents a parser that recognizes an empty
80- // string. For example, (|a|b) is not equivalent to (a|b).
81- if (simplified.operations.isEmpty())
82- simplified.followedBy.ifEmpty { listOf (simplified) }
83- else
84- listOf (simplified)
85- }.ifEmpty {
86- // preserving the invariant that `mergedTails` contains all unconditional modifications
87- listOf (ParserStructure (unconditionalModificationsForTails, emptyList()))
88- }
89- return if (currentNumberSpan == null ) {
90- // the last operation was not a number span, or it was a number span that we are allowed to interrupt
91- ParserStructure (newOperations, mergedTails)
92- } else if (mergedTails.none {
93- it.operations.firstOrNull()?.let { it is NumberSpanParserOperation } == true
94- }) {
95- // the last operation was a number span, but there are no alternatives that start with a number span.
96- newOperations.add(NumberSpanParserOperation (currentNumberSpan))
97- ParserStructure (newOperations, mergedTails)
98- } else {
99- val newTails = mergedTails.map {
100- when (val firstOperation = it.operations.firstOrNull()) {
101- is NumberSpanParserOperation -> {
102- ParserStructure (
103- listOf (NumberSpanParserOperation (currentNumberSpan + firstOperation.consumers)) + it.operations.drop(
104- 1
105- ),
78+ val mergedTails = followedBy.flatMap {
79+ val simplified = it.simplify(unconditionalModificationsForTails)
80+ // parser `ParserStructure(emptyList(), p)` is equivalent to `p`,
81+ // unless `p` is empty. For example, ((a|b)|(c|d)) is equivalent to (a|b|c|d).
82+ // As a special case, `ParserStructure(emptyList(), emptyList())` represents a parser that recognizes an empty
83+ // string. For example, (|a|b) is not equivalent to (a|b).
84+ if (simplified.operations.isEmpty())
85+ simplified.followedBy.ifEmpty { listOf (simplified) }
86+ else
87+ listOf (simplified)
88+ }.ifEmpty {
89+ // preserving the invariant that `mergedTails` contains all unconditional modifications
90+ listOf (ParserStructure (unconditionalModificationsForTails, emptyList()))
91+ }
92+ if (currentNumberSpan == null ) {
93+ // the last operation was not a number span, or it was a number span that we are allowed to interrupt
94+ ParserStructure (newOperations, mergedTails)
95+ } else if (mergedTails.none {
96+ it.operations.firstOrNull()?.let { it is NumberSpanParserOperation } == true
97+ }) {
98+ // the last operation was a number span, but there are no alternatives that start with a number span.
99+ newOperations.add(NumberSpanParserOperation (currentNumberSpan))
100+ ParserStructure (newOperations, mergedTails)
101+ } else {
102+ val newTails = mergedTails.map {
103+ when (val firstOperation = it.operations.firstOrNull()) {
104+ is NumberSpanParserOperation -> {
105+ ParserStructure (
106+ listOf (NumberSpanParserOperation (currentNumberSpan + firstOperation.consumers)) + it.operations.drop(
107+ 1
108+ ),
109+ it.followedBy
110+ )
111+ }
112+
113+ null -> ParserStructure (
114+ listOf (NumberSpanParserOperation (currentNumberSpan)),
106115 it.followedBy
107116 )
108- }
109-
110- null -> ParserStructure (
111- listOf (NumberSpanParserOperation (currentNumberSpan)),
112- it.followedBy
113- )
114117
115- else -> ParserStructure (
116- listOf (NumberSpanParserOperation (currentNumberSpan)) + it.operations,
117- it.followedBy
118- )
118+ else -> ParserStructure (
119+ listOf (NumberSpanParserOperation (currentNumberSpan)) + it.operations,
120+ it.followedBy
121+ )
122+ }
119123 }
124+ ParserStructure (newOperations, newTails)
120125 }
121- ParserStructure (newOperations, newTails)
122126 }
123- }
124127 val naiveParser = foldRight(ParserStructure <T >(emptyList(), emptyList())) { parser, acc -> parser.append(acc) }
125128 return naiveParser.simplify(emptyList())
126129}
0 commit comments