Skip to content

Commit 545d786

Browse files
committed
Fix #272 by moving template code around
A lot of template bloat was being generated by having map, filter and countUntil inside the 'and' and 'or' templates. By simply moving them outside compilation speed and memory is back to normal again.
1 parent 8b55a8f commit 545d786

File tree

1 file changed

+55
-30
lines changed

1 file changed

+55
-30
lines changed

pegged/peg.d

+55-30
Original file line numberDiff line numberDiff line change
@@ -1332,7 +1332,7 @@ template and(rules...) if (rules.length > 0)
13321332
}
13331333
else
13341334
{
1335-
auto firstLongestFailedMatch = result.children.countUntil!(c => c.failEnd > temp.end);
1335+
auto firstLongestFailedMatch = result.children.firstLongestFailedMatch(temp.end);
13361336
if (firstLongestFailedMatch == -1) {
13371337
result.children ~= temp;// add the failed node, to indicate which failed
13381338
if (temp.matches.length > 0)
@@ -1345,8 +1345,8 @@ template and(rules...) if (rules.length > 0)
13451345
// so that it is no longer successful and we want to move its failedChild into its children.
13461346
failedChildFixup(result.children[firstLongestFailedMatch], result.children[firstLongestFailedMatch].failEnd);
13471347
}
1348-
result.end = result.children.map!(c => c.end).maxElement;
1349-
result.failEnd = result.children.map!(c => c.failEnd).maxElement;
1348+
result.end = result.children.maxEnd();
1349+
result.failEnd = result.children.maxFailEnd();
13501350
version (tracer)
13511351
{
13521352
if (shouldTrace(getName!(r)(), p))
@@ -1380,33 +1380,54 @@ template and(rules...) if (rules.length > 0)
13801380
return name;
13811381
}
13821382
1383-
// A child ParseTree has kept track of an alternate ParseTree (in failedChild) that matches longer.
1384-
// whenever the 'and' rule fails we want to rewrite that child so that the failedChild is
1385-
// moved into its children, the successful is set to false, the end is set the its failEnd,
1386-
// the failEnd is reset, and all that info is propagated upwards the tree so intermediate
1387-
// nodes reflect the proper state.
1388-
bool failedChildFixup(ref ParseTree p, size_t failEnd) {
1389-
if (p.failedChild.length > 0) {
1390-
p.children ~= p.failedChild[0];
1391-
p.failedChild = [];
1392-
p.successful = false;
1393-
p.end = p.failEnd;
1394-
p.failEnd = p.children.map!(c => c.failEnd).maxElement();
1395-
return true;
1396-
} else {
1397-
bool result = false;
1398-
foreach(ref c; p.children) {
1399-
if (c.failEnd != failEnd)
1400-
continue;
1401-
if (failedChildFixup(c, failEnd)) {
1402-
p.end = c.end;
1403-
p.successful = false;
1404-
p.failEnd = p.children.map!(c => c.failEnd).maxElement();
1405-
result = true;
1406-
}
1383+
}
1384+
1385+
auto firstLongestFailedMatch(ParseTree[] children, size_t threshold) {
1386+
return children.countUntil!(c => c.failEnd > threshold);
1387+
}
1388+
1389+
auto maxFailEnd(ParseTree[] children)
1390+
{
1391+
return children.map!(c => c.failEnd).maxElement;
1392+
}
1393+
1394+
auto maxEnd(ParseTree[] children)
1395+
{
1396+
return children.map!(c => c.end).maxElement;
1397+
}
1398+
1399+
// A child ParseTree has kept track of an alternate ParseTree (in failedChild) that matches longer.
1400+
// whenever the 'and' rule fails we want to rewrite that child so that the failedChild is
1401+
// moved into its children, the successful is set to false, the end is set the its failEnd,
1402+
// the failEnd is reset, and all that info is propagated upwards the tree so intermediate
1403+
// nodes reflect the proper state.
1404+
bool failedChildFixup(ref ParseTree p, size_t failEnd)
1405+
{
1406+
if (p.failedChild.length > 0)
1407+
{
1408+
p.children ~= p.failedChild[0];
1409+
p.failedChild = [];
1410+
p.successful = false;
1411+
p.end = p.failEnd;
1412+
p.failEnd = p.children.map!(c => c.failEnd).maxElement();
1413+
return true;
1414+
}
1415+
else
1416+
{
1417+
bool result = false;
1418+
foreach (ref c; p.children)
1419+
{
1420+
if (c.failEnd != failEnd)
1421+
continue;
1422+
if (failedChildFixup(c, failEnd))
1423+
{
1424+
p.end = c.end;
1425+
p.successful = false;
1426+
p.failEnd = p.children.map!(c => c.failEnd).maxElement();
1427+
result = true;
14071428
}
1408-
return result;
14091429
}
1430+
return result;
14101431
}
14111432
}
14121433
@@ -1725,8 +1746,8 @@ template or(rules...) if (rules.length > 0)
17251746
longestFail.matches = longestFail.matches.length == 0 ? [orErrorString] :
17261747
longestFail.matches[0..$-1] // discarding longestFail error message
17271748
~ [orErrorString]; // and replacing it by the new, concatenated one.
1728-
auto children = results[].filter!(r => max(r.end, r.failEnd) >= maxFailedLength).array();
1729-
return ParseTree(name, false, longestFail.matches, p.input, p.end, longestFail.end, children, children.map!(c => c.failEnd).maxElement);
1749+
auto children = results[].getUpto(maxFailedLength);
1750+
return ParseTree(name, false, longestFail.matches, p.input, p.end, longestFail.end, children, children.maxFailEnd);
17301751
}
17311752
17321753
ParseTree or(string input)
@@ -1740,6 +1761,10 @@ template or(rules...) if (rules.length > 0)
17401761
}
17411762
}
17421763
1764+
auto getUpto(ParseTree[] children, size_t minFailedLength) {
1765+
return children.filter!(r => max(r.end, r.failEnd) >= minFailedLength).array();
1766+
}
1767+
17431768
unittest // 'or' unit test
17441769
{
17451770
alias charRange!('a','b') ab;

0 commit comments

Comments
 (0)