Skip to content

Commit

Permalink
Qualify pegged/peg.d as @safe and when possible pure nothrow @nogc (#311
Browse files Browse the repository at this point in the history
)

* Qualify as @safe and when possible pure nothrow @nogc

* Add TODO about how to make stringify nothrow

* Fix compilation for @System AA.keys
  • Loading branch information
nordlow authored May 10, 2022
1 parent e81ac46 commit 5c5b9e9
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 90 deletions.
8 changes: 5 additions & 3 deletions pegged/dynamic/grammar.d
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@ import pegged.peg;
import pegged.parser;
import pegged.dynamic.peg;

@safe:

struct ParameterizedRule
{
size_t numArgs;
Dynamic delegate(Dynamic[]) code;
Dynamic delegate(Dynamic[]) @safe code;

Dynamic opCall(D...)(D rules)
{
Expand Down Expand Up @@ -64,7 +66,7 @@ struct ParameterizedRule
}
}

ParameterizedRule parameterizedRule(size_t n, Dynamic delegate(Dynamic[] d) code)
ParameterizedRule parameterizedRule(size_t n, Dynamic delegate(Dynamic[] d) @safe code)
{
ParameterizedRule pr;
pr.numArgs = n;
Expand Down Expand Up @@ -182,7 +184,7 @@ Dynamic makeRule(ParseTree def, Dynamic[string] context)
throw new Exception("Unknown name: " ~ name);
}

Dynamic ruleFromTree(ParseTree p)
Dynamic ruleFromTree(ParseTree p) @safe
{
//writeln("rfT: ", p.name, " ", p.matches);
//Dynamic result;
Expand Down
16 changes: 9 additions & 7 deletions pegged/dynamic/peg.d
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ import std.stdio;

import pegged.peg;

alias ParseTree delegate(ParseTree) Dynamic;
alias ParseTree delegate(ParseTree) @safe Dynamic;

@safe:

string getName(D)(D rule)
{
Expand All @@ -17,9 +19,9 @@ string getName(D)(D rule)

ParseTree callDynamic(D)(D d, string s)
{
static if (is(typeof(d) : ParseTree delegate(ParseTree)) || is(typeof(d) : ParseTree function(ParseTree)))
static if (is(typeof(d) : ParseTree delegate(ParseTree) @safe) || is(typeof(d) : ParseTree function(ParseTree) @safe))
return d(ParseTree("",false,[], s));
else static if (is(typeof(d) : ParseTree delegate(ParseTree) delegate()) || is(typeof(d) : ParseTree function(ParseTree) delegate()))
else static if (is(typeof(d) : ParseTree delegate(ParseTree) @safe delegate()) || is(typeof(d) : ParseTree function(ParseTree) @safe delegate()))
return d()(ParseTree("",false,[], s));
else static if (is(typeof(d) : ParseTree delegate(string)) || is(typeof(d) : ParseTree function(string)))
return d(s);
Expand All @@ -31,9 +33,9 @@ ParseTree callDynamic(D)(D d, string s)

ParseTree callDynamic(D)(D d, ParseTree p)
{
static if (is(typeof(d) : ParseTree delegate(ParseTree)) || is(typeof(d) : ParseTree function(ParseTree)))
static if (is(typeof(d) : ParseTree delegate(ParseTree) @safe) || is(typeof(d) : ParseTree function(ParseTree) @safe))
return d(p);
else static if (is(typeof(d) : ParseTree delegate(ParseTree) delegate()) || is(typeof(d) : ParseTree function(ParseTree) delegate()))
else static if (is(typeof(d) : ParseTree delegate(ParseTree) @safe delegate()) || is(typeof(d) : ParseTree function(ParseTree) @safe delegate()))
return d()(p);
else static if (is(typeof(d) : ParseTree delegate(string)) || is(typeof(d) : ParseTree function(string)))
return d(p.input[p.end..$]);
Expand Down Expand Up @@ -245,7 +247,7 @@ Dynamic and(T...)(T rules) if (T.length)

Dynamic or(T...)(T rules)
{
return (ParseTree p)
return (ParseTree p) @safe
{
// error-management
ParseTree longestFail = ParseTree("or", false, [], p.input, p.end, 0);
Expand Down Expand Up @@ -309,7 +311,7 @@ Dynamic or(T...)(T rules)
start += len + names[i].length + 4;
}
}
orErrorString = cast(string)(errString[0..$-4]);
() @trusted { orErrorString = cast(string)(errString[0..$-4]); } ();

longestFail.matches = longestFail.matches[0..$-1] // discarding longestFail error message
~ [orErrorString]; // and replacing it by the new, concatenated one.
Expand Down
26 changes: 13 additions & 13 deletions pegged/grammar.d
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import std.stdio;
public import pegged.peg;
import pegged.parser;


@safe:

/**
Option enum to get internal memoization (parse results storing).
Expand Down Expand Up @@ -204,16 +204,16 @@ string grammar(Memoization withMemo = Memoization.yes)(ParseTree defAsParseTree)
string firstRuleName = generateCode(p.children[1].children[0]);

result =
"struct Generic" ~ shortGrammarName ~ "(TParseTree)
"@safe struct Generic" ~ shortGrammarName ~ "(TParseTree)
{
import std.functional : toDelegate;
import pegged.dynamic.grammar;
static import pegged.peg;
struct " ~ grammarName ~ "\n {
enum name = \"" ~ shortGrammarName ~ "\";
static ParseTree delegate(ParseTree)[string] before;
static ParseTree delegate(ParseTree)[string] after;
static ParseTree delegate(ParseTree)[string] rules;";
static ParseTree delegate(ParseTree) @safe [string] before;
static ParseTree delegate(ParseTree) @safe [string] after;
static ParseTree delegate(ParseTree) @safe [string] rules;";

if (withMemo == Memoization.yes) {
result ~= "
Expand All @@ -226,7 +226,7 @@ string grammar(Memoization withMemo = Memoization.yes)(ParseTree defAsParseTree)
}

result ~= "
static this()\n {\n";
static this() @trusted\n {\n";

ParseTree[] definitions = p.children[1 .. $];
bool userDefinedSpacing;
Expand All @@ -248,7 +248,7 @@ string grammar(Memoization withMemo = Memoization.yes)(ParseTree defAsParseTree)
template hooked(alias r, string name)
{
static ParseTree hooked(ParseTree p)
static ParseTree hooked(ParseTree p) @safe
{
ParseTree result;
Expand All @@ -267,13 +267,13 @@ string grammar(Memoization withMemo = Memoization.yes)(ParseTree defAsParseTree)
return result;
}
static ParseTree hooked(string input)
static ParseTree hooked(string input) @safe
{
return hooked!(r, name)(ParseTree(\"\",false,[],input));
}
}
static void addRuleBefore(string parentRule, string ruleSyntax)
static void addRuleBefore(string parentRule, string ruleSyntax) @safe
{
// enum name is the current grammar name
DynamicGrammar dg = pegged.dynamic.grammar.grammar(name ~ \": \" ~ ruleSyntax, rules);
Expand All @@ -283,7 +283,7 @@ string grammar(Memoization withMemo = Memoization.yes)(ParseTree defAsParseTree)
before[parentRule] = rules[dg.startingRule];
}
static void addRuleAfter(string parentRule, string ruleSyntax)
static void addRuleAfter(string parentRule, string ruleSyntax) @safe
{
// enum name is the current grammar named
DynamicGrammar dg = pegged.dynamic.grammar.grammar(name ~ \": \" ~ ruleSyntax, rules);
Expand All @@ -295,7 +295,7 @@ string grammar(Memoization withMemo = Memoization.yes)(ParseTree defAsParseTree)
after[parentRule] = rules[dg.startingRule];
}
static bool isRule(string s)
static bool isRule(string s) pure nothrow @nogc
{
import std.algorithm : startsWith;
return s.startsWith(\"" ~ shortGrammarName ~ ".\");
Expand Down Expand Up @@ -2437,12 +2437,12 @@ version(unittest)
{
P foo(P)(P p) { return p;} // for testing actions

void badGrammar(string s)()
void badGrammar(string s)() @safe
{
assert(!__traits(compiles, {mixin(grammar(s));}), "This should fail: " ~ s);
}

void goodGrammar(string s)()
void goodGrammar(string s)() @safe
{
assert(__traits(compiles, {mixin(grammar(s));}), "This should work: " ~ s);
}
Expand Down
42 changes: 31 additions & 11 deletions pegged/introspection.d
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import std.typecons;

import pegged.parser;

@safe:

/**
The different kinds of recursion for a rule.
'direct' means the rule name appears in its own definition. 'indirect' means the rule calls itself through another rule (the call chain can be long).
Expand Down Expand Up @@ -109,17 +111,24 @@ pure GrammarInfo grammarInfo(ParseTree p)
also appear in the call graph when the rule has a name: hence, calls to predefined rules like 'identifier' or
'digit' will appear, but not a call to '[0-9]+', considered here as an anonymous rule.
*/
bool[string][string] callGraph(ParseTree p)
bool[string][string] callGraph(ParseTree p) @safe
{
bool[string] findIdentifiers(ParseTree p)
bool[string] findIdentifiers(ParseTree p) @safe
{
bool[string] idList;
if (p.name == "Pegged.Identifier")
idList[p.matches[0]] = true;
else
foreach(child; p.children)
foreach(name; findIdentifiers(child).keys)
{
auto ids = findIdentifiers(child);
static if (hasSystemAAKeys)
auto keys = () @trusted { return ids.keys; } ();
else
auto keys = ids.keys;
foreach(name; keys)
idList[name] = true;
}

return idList;
}
Expand All @@ -144,7 +153,7 @@ pure GrammarInfo grammarInfo(ParseTree p)
It will propagate the calls to find all rules called by a given rule,
directly (already in the call graph) or indirectly (through another rule).
*/
bool[string][string] closure(bool[string][string] graph)
bool[string][string] closure(bool[string][string] graph) @safe
{
bool[string][string] path;
foreach(rule, children; graph) // deep-dupping, to avoid children aliasing
Expand All @@ -155,10 +164,14 @@ pure GrammarInfo grammarInfo(ParseTree p)
while(changed)
{
changed = false;
foreach(rule1; graph.keys)
foreach(rule2; graph.keys)
static if (hasSystemAAKeys)
auto keys = () @trusted { return graph.keys; } ();
else
auto keys = graph.keys;
foreach(rule1; keys)
foreach(rule2; keys)
if (rule2 in path[rule1])
foreach(rule3; graph.keys)
foreach(rule3; keys)
if (rule3 in path[rule2] && rule3 !in path[rule1])
{
path[rule1][rule3] = true;
Expand All @@ -169,7 +182,7 @@ pure GrammarInfo grammarInfo(ParseTree p)
return path;
}

Recursive[string] recursions(bool[string][string] graph)
Recursive[string] recursions(bool[string][string] graph) @safe
{
bool[string][string] path = closure(graph);

Expand All @@ -189,7 +202,7 @@ pure GrammarInfo grammarInfo(ParseTree p)
return result;
}

NullMatch nullMatching(ParseTree p)
NullMatch nullMatching(ParseTree p) @safe
{
switch (p.name)
{
Expand Down Expand Up @@ -250,7 +263,7 @@ pure GrammarInfo grammarInfo(ParseTree p)
}
}

InfiniteLoop infiniteLooping(ParseTree p)
InfiniteLoop infiniteLooping(ParseTree p) @safe
{
switch (p.name)
{
Expand Down Expand Up @@ -292,7 +305,7 @@ pure GrammarInfo grammarInfo(ParseTree p)
}
}

LeftRecursive leftRecursion(ParseTree p, ref string[] cycle)
LeftRecursive leftRecursion(ParseTree p, ref string[] cycle) @safe
{
import std.algorithm.searching: countUntil;
switch (p.name)
Expand Down Expand Up @@ -598,3 +611,10 @@ ParseTree replaceInto(ParseTree parent, ParseTree child)
branch = replaceInto(branch, child);
return parent;
}

/* .keys is @safe after compiler version >= 2.098.0.
*
* See:
* https://dlang.org/changelog/2.098.0.html#bugfix-list and
* https://issues.dlang.org/show_bug.cgi?id=14439 */
enum bool hasSystemAAKeys = __VERSION__ < 2098;
12 changes: 7 additions & 5 deletions pegged/parser.d
Original file line number Diff line number Diff line change
Expand Up @@ -137,18 +137,20 @@ public import pegged.peg;
import std.algorithm: startsWith;
import std.functional: toDelegate;

@safe:

struct GenericPegged(TParseTree)
{
import std.functional : toDelegate;
import pegged.dynamic.grammar;
static import pegged.peg;
struct Pegged
@safe struct Pegged
{
enum name = "Pegged";
static ParseTree delegate(ParseTree)[string] before;
static ParseTree delegate(ParseTree)[string] after;
static ParseTree delegate(ParseTree)[string] rules;
static this()
static ParseTree delegate(ParseTree) @safe [string] before;
static ParseTree delegate(ParseTree) @safe [string] after;
static ParseTree delegate(ParseTree) @safe [string] rules;
static this() @trusted
{
rules["Grammar"] = toDelegate(&Grammar);
rules["Definition"] = toDelegate(&Definition);
Expand Down
Loading

0 comments on commit 5c5b9e9

Please sign in to comment.