Skip to content

Commit

Permalink
Fix #272 by moving template code around
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
skoppe committed Mar 25, 2020
1 parent 8b55a8f commit 545d786
Showing 1 changed file with 55 additions and 30 deletions.
85 changes: 55 additions & 30 deletions pegged/peg.d
Original file line number Diff line number Diff line change
Expand Up @@ -1332,7 +1332,7 @@ template and(rules...) if (rules.length > 0)
}
else
{
auto firstLongestFailedMatch = result.children.countUntil!(c => c.failEnd > temp.end);
auto firstLongestFailedMatch = result.children.firstLongestFailedMatch(temp.end);
if (firstLongestFailedMatch == -1) {
result.children ~= temp;// add the failed node, to indicate which failed
if (temp.matches.length > 0)
Expand All @@ -1345,8 +1345,8 @@ template and(rules...) if (rules.length > 0)
// so that it is no longer successful and we want to move its failedChild into its children.
failedChildFixup(result.children[firstLongestFailedMatch], result.children[firstLongestFailedMatch].failEnd);
}
result.end = result.children.map!(c => c.end).maxElement;
result.failEnd = result.children.map!(c => c.failEnd).maxElement;
result.end = result.children.maxEnd();
result.failEnd = result.children.maxFailEnd();
version (tracer)
{
if (shouldTrace(getName!(r)(), p))
Expand Down Expand Up @@ -1380,33 +1380,54 @@ template and(rules...) if (rules.length > 0)
return name;
}
// A child ParseTree has kept track of an alternate ParseTree (in failedChild) that matches longer.
// whenever the 'and' rule fails we want to rewrite that child so that the failedChild is
// moved into its children, the successful is set to false, the end is set the its failEnd,
// the failEnd is reset, and all that info is propagated upwards the tree so intermediate
// nodes reflect the proper state.
bool failedChildFixup(ref ParseTree p, size_t failEnd) {
if (p.failedChild.length > 0) {
p.children ~= p.failedChild[0];
p.failedChild = [];
p.successful = false;
p.end = p.failEnd;
p.failEnd = p.children.map!(c => c.failEnd).maxElement();
return true;
} else {
bool result = false;
foreach(ref c; p.children) {
if (c.failEnd != failEnd)
continue;
if (failedChildFixup(c, failEnd)) {
p.end = c.end;
p.successful = false;
p.failEnd = p.children.map!(c => c.failEnd).maxElement();
result = true;
}
}
auto firstLongestFailedMatch(ParseTree[] children, size_t threshold) {
return children.countUntil!(c => c.failEnd > threshold);
}
auto maxFailEnd(ParseTree[] children)
{
return children.map!(c => c.failEnd).maxElement;
}
auto maxEnd(ParseTree[] children)
{
return children.map!(c => c.end).maxElement;
}
// A child ParseTree has kept track of an alternate ParseTree (in failedChild) that matches longer.
// whenever the 'and' rule fails we want to rewrite that child so that the failedChild is
// moved into its children, the successful is set to false, the end is set the its failEnd,
// the failEnd is reset, and all that info is propagated upwards the tree so intermediate
// nodes reflect the proper state.
bool failedChildFixup(ref ParseTree p, size_t failEnd)
{
if (p.failedChild.length > 0)
{
p.children ~= p.failedChild[0];
p.failedChild = [];
p.successful = false;
p.end = p.failEnd;
p.failEnd = p.children.map!(c => c.failEnd).maxElement();
return true;
}
else
{
bool result = false;
foreach (ref c; p.children)
{
if (c.failEnd != failEnd)
continue;
if (failedChildFixup(c, failEnd))
{
p.end = c.end;
p.successful = false;
p.failEnd = p.children.map!(c => c.failEnd).maxElement();
result = true;
}
return result;
}
return result;
}
}
Expand Down Expand Up @@ -1725,8 +1746,8 @@ template or(rules...) if (rules.length > 0)
longestFail.matches = longestFail.matches.length == 0 ? [orErrorString] :
longestFail.matches[0..$-1] // discarding longestFail error message
~ [orErrorString]; // and replacing it by the new, concatenated one.
auto children = results[].filter!(r => max(r.end, r.failEnd) >= maxFailedLength).array();
return ParseTree(name, false, longestFail.matches, p.input, p.end, longestFail.end, children, children.map!(c => c.failEnd).maxElement);
auto children = results[].getUpto(maxFailedLength);
return ParseTree(name, false, longestFail.matches, p.input, p.end, longestFail.end, children, children.maxFailEnd);
}
ParseTree or(string input)
Expand All @@ -1740,6 +1761,10 @@ template or(rules...) if (rules.length > 0)
}
}
auto getUpto(ParseTree[] children, size_t minFailedLength) {
return children.filter!(r => max(r.end, r.failEnd) >= minFailedLength).array();
}
unittest // 'or' unit test
{
alias charRange!('a','b') ab;
Expand Down

0 comments on commit 545d786

Please sign in to comment.