@@ -113,35 +113,9 @@ string grammar(Memoization withMemo = Memoization.yes)(string definition)
113113 import pegged.introspection;
114114 import std.algorithm : canFind;
115115 GrammarInfo grammarInfo = grammarInfo(defAsParseTree.children[0 ]);
116- string [][string ] stoppers; // Keys are the rules that stop left-recursion and the
117- // values are arrays of strings containing the corresponding
118- // rules for which memoization needs to be blocked.
119-
120- // Prints comment showing detected left-recursive cycles.
121- string printLeftRecursiveCycles ()
122- {
123- string result;
124- foreach (cycle; grammarInfo.leftRecursiveCycles)
125- {
126- result ~= cycle[0 ];
127- foreach (rule; cycle[1 .. $])
128- result ~= " <- " ~ rule;
129- result ~= " \n " ;
130- }
131- return result.length > 0 ? " /** Left-recursive cycles:\n " ~ result ~ " */\n\n " : " " ;
132- }
133-
134- // Prints comment showing rules that stop left-recursive cycles and rules for which memoization is blocked during recursion.
135- string printLeftRecursionStoppers ()
136- {
137- import std.array : join;
138- string result;
139- foreach (stopper, rules; stoppers)
140- result ~= stopper ~ " : " ~ rules.join(" , " ) ~ " \n " ;
141- return result.length > 0 ?
142- " /** Rules that stop left-recursive cycles, followed by rules for which\n "
143- ~ " * memoization is blocked during recursion:\n " ~ result ~ " */\n\n " : " " ;
144- }
116+ string [] stoppers; // Keys are the rules that stop left-recursion and the
117+ // values are arrays of strings containing the corresponding
118+ // rules for which memoization needs to be blocked.
145119
146120 /*
147121 I once considered that if two left-recursive cycles intersect, unbounded left-recursion
@@ -159,48 +133,34 @@ string grammar(Memoization withMemo = Memoization.yes)(string definition)
159133 if (! canFind(allLeftRecursiveRules, rule))
160134 allLeftRecursiveRules ~= rule;
161135 foreach (cycle; grammarInfo.leftRecursiveCycles)
162- stoppers[cycle[0 ]] = allLeftRecursiveRules;
163- // Analysis completed.
136+ stoppers ~= cycle[0 ];
164137
165- // / Returns code to prevent memoization of incomplete matches during left-recursion through this rule .
166- string blockMemoForLeftRecursion ( string stopper )
138+ // Prints comment showing detected left-recursive cycles .
139+ string printLeftRecursiveCycles ( )
167140 {
168141 string result;
169- foreach (rule; stoppers[stopper])
170- result ~= " blockMemo_" ~ rule ~ " _atPos ~= p.end;\n " ;
171- return result;
142+ foreach (cycle; grammarInfo.leftRecursiveCycles)
143+ {
144+ result ~= cycle[0 ];
145+ foreach (rule; cycle[1 .. $])
146+ result ~= " <- " ~ rule;
147+ result ~= " \n " ;
148+ }
149+ return result.length > 0 ? " /** Left-recursive cycles:\n " ~ result ~ " */\n\n " : " " ;
172150 }
173151
174- // / Returns code that enables memoization when left-recursion has completed .
175- string unblockMemoForLeftRecursion ( string stopper )
152+ // Prints comment showing rules that stop left-recursive cycles and rules for which memoization is blocked during recursion .
153+ string printLeftRecursionStoppers ( )
176154 {
155+ import std.array : join;
177156 string result;
178- foreach (rule; stoppers[stopper])
179- // TODO investigate if p.end is always the last element.
180- result ~= " assert(blockMemo_" ~ rule ~ " _atPos.canFind(p.end));\n "
181- ~ " blockMemo_" ~ rule ~ " _atPos = remove(blockMemo_" ~ rule ~ " _atPos, countUntil(blockMemo_" ~ rule ~ " _atPos, p.end));\n " ;
182- return result;
183- }
184-
185- // / If $(D_PARAM name) is part of a left-recursive cycle and not a stopping rule, code is
186- // inserted to test for blocking and if blocked return with "$(D_PARAM code)(p)".
187- string maybeBlockedMemo (string name, string code)
188- {
189- assert (name ! in stoppers);
190- foreach (cycle; stoppers)
191- foreach (rule; cycle)
192- if (rule == name)
193- return
194- " if (blockMemo_" ~ name ~ " _atPos.canFind(p.end))\n "
195- ~ " return " ~ code ~ " (p);\n " ;
196- return " " ;
197- }
198-
199- // / Returns a Boolean expression whether $(D_PARAM rule) is not blocked.
200- string shouldMemoLeftRecursion (string rule)
201- {
202- return " !blockMemo_" ~ rule ~ " _atPos.canFind(p.end)" ;
157+ foreach (stopper; stoppers)
158+ result ~= stopper ~ " : " ~ allLeftRecursiveRules.join(" , " ) ~ " \n " ;
159+ return result.length > 0 ?
160+ " /** Rules that stop left-recursive cycles, followed by rules for which\n "
161+ ~ " * memoization is blocked during recursion:\n " ~ result ~ " */\n\n " : " " ;
203162 }
163+ // Analysis completed.
204164
205165 string generateForgetMemo ()
206166 {
@@ -227,25 +187,6 @@ string grammar(Memoization withMemo = Memoization.yes)(string definition)
227187 {
228188 string result;
229189
230- // Variables holding the block-state.
231- string generateBlockers ()
232- {
233- string result;
234- string [] visited = [];
235- foreach (cycle; grammarInfo.leftRecursiveCycles)
236- foreach (rule; cycle)
237- if (! visited.canFind(rule))
238- {
239- visited ~= rule;
240- result ~= "
241- static size_t[] blockMemo_" ~ rule ~ " _atPos;" ;
242- }
243- if (result.length > 0 )
244- return "
245- import std.algorithm: canFind, countUntil, remove;" ~ result;
246- return result;
247- }
248-
249190 switch (p.name)
250191 {
251192 case " Pegged" :
@@ -273,7 +214,10 @@ string grammar(Memoization withMemo = Memoization.yes)(string definition)
273214 result ~= "
274215 import std.typecons:Tuple, tuple;
275216 static TParseTree[Tuple!(string, size_t)] memo;" ;
276- result ~= generateBlockers();
217+ if (grammarInfo.leftRecursiveCycles.length > 0 )
218+ result ~= "
219+ import std.algorithm: canFind, countUntil, remove;
220+ static size_t[] blockMemoAtPos;" ;
277221 }
278222
279223 result ~= "
@@ -517,7 +461,7 @@ string grammar(Memoization withMemo = Memoization.yes)(string definition)
517461 ~ " {\n "
518462 ~ " if(__ctfe)\n "
519463 ~ " {\n "
520- ~ (shortName in stoppers ?
464+ ~ (stoppers.canFind(shortName) ?
521465 " assert(false, \" " ~ shortName ~ " is left-recursive, which is not supported "
522466 ~ " at compile-time. Consider using asModule().\" );\n "
523467 :
@@ -526,7 +470,7 @@ string grammar(Memoization withMemo = Memoization.yes)(string definition)
526470 ~ " }\n "
527471 ~ " else\n "
528472 ~ " {\n "
529- ~ (shortName in stoppers ?
473+ ~ (stoppers.canFind(shortName) ?
530474 // This rule needs to prevent infinite left-recursion.
531475 " static TParseTree[size_t /*position*/] seed;\n "
532476 ~ " if (auto s = p.end in seed)\n "
@@ -571,7 +515,7 @@ string grammar(Memoization withMemo = Memoization.yes)(string definition)
571515 ~ " {\n "
572516 ~ " if(__ctfe)\n "
573517 ~ " {\n "
574- ~ (shortName in stoppers ?
518+ ~ (stoppers.canFind(shortName) ?
575519 " assert(false, \" " ~ shortName ~ " is left-recursive, which is not supported "
576520 ~ " at compile-time. Consider using asModule().\" );\n "
577521 :
@@ -580,17 +524,17 @@ string grammar(Memoization withMemo = Memoization.yes)(string definition)
580524 ~ " }\n "
581525 ~ " else\n "
582526 ~ " {\n "
583- ~ (shortName in stoppers ?
527+ ~ (stoppers.canFind(shortName) ?
584528 // This rule needs to prevent infinite left-recursion.
585529 " static TParseTree[size_t /*position*/] seed;\n "
586530 ~ " if (auto s = p.end in seed)\n "
587531 ~ " return *s;\n "
588- ~ " if (" ~ shouldMemoLeftRecursion(shortName) ~ " )\n "
532+ ~ " if (!blockMemoAtPos.canFind(p.end) )\n "
589533 ~ " if (auto m = tuple(" ~ innerName ~ " , p.end) in memo)\n "
590534 ~ " return *m;\n "
591535 ~ " auto current = fail(p);\n "
592536 ~ " seed[p.end] = current;\n "
593- ~ blockMemoForLeftRecursion(shortName)
537+ ~ " blockMemoAtPos ~= p.end; \n "
594538 ~ " while (true)\n "
595539 ~ " {\n "
596540 ~ " auto result = " ~ code ~ " (p);\n "
@@ -612,14 +556,20 @@ string grammar(Memoization withMemo = Memoization.yes)(string definition)
612556 // care of by memo. Note that p.end remains constant for the course of recursion,
613557 // and the length of seed only grows when nested recursion occurs.
614558 ~ " seed.remove(p.end);\n "
615- ~ unblockMemoForLeftRecursion(shortName)
559+ // TODO investigate if p.end is always the last element of blockMemoAtPos.
560+ ~ " assert(blockMemoAtPos.canFind(p.end));\n "
561+ ~ " blockMemoAtPos = blockMemoAtPos.remove(countUntil(blockMemoAtPos, p.end));\n "
616562 ~ " memo[tuple(" ~ innerName ~ " , p.end)] = current;\n "
617563 ~ " return current;\n "
618564 ~ " }\n "
619565 ~ " }\n "
620566 :
621567 // Possibly left-recursive rule, but infinite recursion is already prevented by another rule in the same cycle.
622- maybeBlockedMemo(shortName, code)
568+ (allLeftRecursiveRules.canFind(shortName) ?
569+ " if (blockMemoAtPos.canFind(p.end))\n "
570+ ~ " return " ~ code ~ " (p);\n "
571+ : " "
572+ )
623573 ~ " if (auto m = tuple(" ~ innerName ~ " , p.end) in memo)\n "
624574 ~ " return *m;\n "
625575 ~ " else\n "
0 commit comments