From ac5be365dc60b665da6b31506e9555360fdd8bbe Mon Sep 17 00:00:00 2001 From: cbleser Date: Sat, 29 May 2021 12:35:38 +0300 Subject: [PATCH 01/29] Inside peg.d the ParseTree change to a mixin template This enables 'overloading' of the ParseTree --- pegged/peg.d | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pegged/peg.d b/pegged/peg.d index 33ce886..9e057a3 100644 --- a/pegged/peg.d +++ b/pegged/peg.d @@ -49,7 +49,7 @@ package string stringified(string inp) @safe "\t" : `"\t"`, `"` : `"\""`, - "`" : q"("`")", + "`" : q{("`")}, "'" : `"'"`, "42" : `"42"`, @@ -237,7 +237,7 @@ enum KEYWORDS = IFCHAIN; The basic parse tree, as used throughout the project. You can define your own parse tree node, but respect the basic layout. */ -struct ParseTree +mixin template ParseTreeT() { string name; /// The node name bool successful; /// Indicates whether a parsing was successful or not @@ -362,6 +362,10 @@ struct ParseTree } } +struct ParseTree +{ + mixin ParseTreeT; +} /** * Default fail message formating function */ From 510d8941a744d3667992be734bca90f2a31ba300 Mon Sep 17 00:00:00 2001 From: cbleser Date: Mon, 31 May 2021 13:25:56 +0300 Subject: [PATCH 02/29] WIP: Working on changing the peg grammers to use costume ParseTree datatypes --- pegged/dynamic/grammar.d | 9 +- pegged/dynamic/peg.d | 1 + pegged/grammar.d | 3 +- pegged/introspection.d | 6 +- pegged/parser.d | 856 +++++----- pegged/peg.d | 3447 ++++++++++++++++++++------------------ 6 files changed, 2229 insertions(+), 2093 deletions(-) diff --git a/pegged/dynamic/grammar.d b/pegged/dynamic/grammar.d index a40d1bb..f5c51d1 100644 --- a/pegged/dynamic/grammar.d +++ b/pegged/dynamic/grammar.d @@ -19,6 +19,8 @@ import pegged.peg; import pegged.parser; import pegged.dynamic.peg; +private alias ParseTree=DefaultParseTree; + struct ParameterizedRule { size_t numArgs; @@ -78,6 +80,7 @@ struct DynamicGrammar string startingRule; Dynamic[string] rules; ParameterizedRule[string] paramRules; + private alias ParseTree=DefaultParseTree; ParseTree decimateTree(ParseTree p) { @@ -142,7 +145,7 @@ struct DynamicGrammar } // Helper to insert 'Spacing' before and after Primaries -ParseTree spaceArrow(ParseTree input) +ParseTree spaceArrow(ParseTree)(ParseTree input) if (isParseTree!ParseTree) { ParseTree wrapInSpaces(ParseTree p) { @@ -160,7 +163,7 @@ ParseTree spaceArrow(ParseTree input) result.children = spacer ~ result.children ~ spacer; return result; } - return modify!( p => p.name == "Pegged.Primary", + return modify!(ParseTree, p => p.name == "Pegged.Primary", wrapInSpaces)(input); } @@ -170,7 +173,7 @@ Dynamic makeRule(string def, Dynamic[string] context) return makeRule(p, context); } -Dynamic makeRule(ParseTree def, Dynamic[string] context) +Dynamic makeRule(ParseTree)(ParseTree def, Dynamic[string] context) if (isParseTree!ParseTree) { Dynamic code; diff --git a/pegged/dynamic/peg.d b/pegged/dynamic/peg.d index 9e929f8..fcd27bb 100644 --- a/pegged/dynamic/peg.d +++ b/pegged/dynamic/peg.d @@ -8,6 +8,7 @@ import std.stdio; import pegged.peg; +private alias ParseTree=DefaultParseTree; alias ParseTree delegate(ParseTree) Dynamic; string getName(D)(D rule) diff --git a/pegged/grammar.d b/pegged/grammar.d index 67acc82..eee189d 100644 --- a/pegged/grammar.d +++ b/pegged/grammar.d @@ -57,7 +57,7 @@ void asModule(Memoization withMemo = Memoization.yes)(string moduleName, File fi } // Helper to insert 'Spacing' before and after Primaries -ParseTree spaceArrow(ParseTree input) +ParseTree spaceArrow(ParseTree)(ParseTree input) { ParseTree wrapInSpaces(ParseTree p) { @@ -209,6 +209,7 @@ string grammar(Memoization withMemo = Memoization.yes)(ParseTree defAsParseTree) import std.functional : toDelegate; import pegged.dynamic.grammar; static import pegged.peg; + alias PEG=pegged.peg; struct " ~ grammarName ~ "\n { enum name = \"" ~ shortGrammarName ~ "\"; static ParseTree delegate(ParseTree)[string] before; diff --git a/pegged/introspection.d b/pegged/introspection.d index 22bd5c7..5a62fea 100644 --- a/pegged/introspection.d +++ b/pegged/introspection.d @@ -89,7 +89,7 @@ Returns for all grammar rules: This kind of potential problem can be detected statically and should be transmitted to the grammar designer. */ -pure GrammarInfo grammarInfo(ParseTree p) +pure GrammarInfo grammarInfo(ParseTree)(ParseTree p) { if (p.name == "Pegged") return grammarInfo(p.children[0]); @@ -428,7 +428,7 @@ Returns for all grammar rules: This kind of potential problem can be detected statically and should be transmitted to the grammar designer. */ -pure RuleInfo[string] ruleInfo(ParseTree p) +pure RuleInfo[string] ruleInfo(ParseTree)(ParseTree p) { return grammarInfo(p).ruleInfo; } @@ -587,7 +587,7 @@ unittest // Left-recursive null-matching Act on rules parse tree as produced by pegged.parser. Replace every occurence of child in parent by child's parse tree */ -ParseTree replaceInto(ParseTree parent, ParseTree child) +ParseTree replaceInto(ParseTree)(ParseTree parent, ParseTree child) { if (parent.name == "Pegged.RhsName" && parent.matches[0] == child.matches[0]) return ParseTree("Pegged.Named", true, child.matches[0..1], "",0,0, diff --git a/pegged/parser.d b/pegged/parser.d index b1d976c..0f82f5f 100644 --- a/pegged/parser.d +++ b/pegged/parser.d @@ -137,8 +137,11 @@ public import pegged.peg; import std.algorithm: startsWith; import std.functional: toDelegate; -struct GenericPegged(TParseTree) +struct GenericPegged(ParseTree) { +// mixin ParseCollections!ParseTree; + alias PEG=PeggedT!ParseTree; + mixin DefaultParsePatterns!PEG; import std.functional : toDelegate; import pegged.dynamic.grammar; static import pegged.peg; @@ -261,25 +264,25 @@ struct GenericPegged(TParseTree) } mixin decimateTree; - static TParseTree Grammar(TParseTree p) + static ParseTree Grammar(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(Spacing, GrammarName, pegged.peg.oneOrMore!(Definition), pegged.peg.discard!(eoi)), "Pegged.Grammar")(p); + return PEG.defined!(PEG.and!(Spacing, GrammarName, PEG.oneOrMore!(Definition), PEG.discard!(eoi)), "Pegged.Grammar")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(Spacing, GrammarName, pegged.peg.oneOrMore!(Definition), pegged.peg.discard!(eoi)), "Pegged.Grammar"), "Grammar")(p); + return hooked!(PEG.defined!(PEG.and!(Spacing, GrammarName, PEG.oneOrMore!(Definition), PEG.discard!(eoi)), "Pegged.Grammar"), "Grammar")(p); } } - static TParseTree Grammar(string s) + static ParseTree Grammar(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(Spacing, GrammarName, pegged.peg.oneOrMore!(Definition), pegged.peg.discard!(eoi)), "Pegged.Grammar")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(Spacing, GrammarName, PEG.oneOrMore!(Definition), PEG.discard!(eoi)), "Pegged.Grammar")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(Spacing, GrammarName, pegged.peg.oneOrMore!(Definition), pegged.peg.discard!(eoi)), "Pegged.Grammar"), "Grammar")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(Spacing, GrammarName, PEG.oneOrMore!(Definition), PEG.discard!(eoi)), "Pegged.Grammar"), "Grammar")(ParseTree("", false,[], s)); } } static string Grammar(GetName g) @@ -287,25 +290,25 @@ struct GenericPegged(TParseTree) return "Pegged.Grammar"; } - static TParseTree Definition(TParseTree p) + static ParseTree Definition(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(LhsName, Arrow, Expression), "Pegged.Definition")(p); + return PEG.defined!(PEG.and!(LhsName, Arrow, Expression), "Pegged.Definition")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(LhsName, Arrow, Expression), "Pegged.Definition"), "Definition")(p); + return hooked!(PEG.defined!(PEG.and!(LhsName, Arrow, Expression), "Pegged.Definition"), "Definition")(p); } } - static TParseTree Definition(string s) + static ParseTree Definition(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(LhsName, Arrow, Expression), "Pegged.Definition")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(LhsName, Arrow, Expression), "Pegged.Definition")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(LhsName, Arrow, Expression), "Pegged.Definition"), "Definition")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(LhsName, Arrow, Expression), "Pegged.Definition"), "Definition")(ParseTree("", false,[], s)); } } static string Definition(GetName g) @@ -313,25 +316,25 @@ struct GenericPegged(TParseTree) return "Pegged.Definition"; } - static TParseTree Expression(TParseTree p) + static ParseTree Expression(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.or!(FirstExpression, LongestExpression), "Pegged.Expression")(p); + return PEG.defined!(PEG.or!(FirstExpression, LongestExpression), "Pegged.Expression")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.or!(FirstExpression, LongestExpression), "Pegged.Expression"), "Expression")(p); + return hooked!(PEG.defined!(PEG.or!(FirstExpression, LongestExpression), "Pegged.Expression"), "Expression")(p); } } - static TParseTree Expression(string s) + static ParseTree Expression(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.or!(FirstExpression, LongestExpression), "Pegged.Expression")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.or!(FirstExpression, LongestExpression), "Pegged.Expression")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.or!(FirstExpression, LongestExpression), "Pegged.Expression"), "Expression")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.or!(FirstExpression, LongestExpression), "Pegged.Expression"), "Expression")(ParseTree("", false,[], s)); } } static string Expression(GetName g) @@ -339,25 +342,25 @@ struct GenericPegged(TParseTree) return "Pegged.Expression"; } - static TParseTree FirstExpression(TParseTree p) + static ParseTree FirstExpression(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.discard!(pegged.peg.option!(OR)), Sequence, pegged.peg.oneOrMore!(pegged.peg.and!(pegged.peg.discard!(OR), Sequence))), "Pegged.FirstExpression")(p); + return PEG.defined!(PEG.and!(PEG.discard!(PEG.option!(OR)), Sequence, PEG.oneOrMore!(PEG.and!(PEG.discard!(OR), Sequence))), "Pegged.FirstExpression")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.discard!(pegged.peg.option!(OR)), Sequence, pegged.peg.oneOrMore!(pegged.peg.and!(pegged.peg.discard!(OR), Sequence))), "Pegged.FirstExpression"), "FirstExpression")(p); + return hooked!(PEG.defined!(PEG.and!(PEG.discard!(PEG.option!(OR)), Sequence, PEG.oneOrMore!(PEG.and!(PEG.discard!(OR), Sequence))), "Pegged.FirstExpression"), "FirstExpression")(p); } } - static TParseTree FirstExpression(string s) + static ParseTree FirstExpression(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.discard!(pegged.peg.option!(OR)), Sequence, pegged.peg.oneOrMore!(pegged.peg.and!(pegged.peg.discard!(OR), Sequence))), "Pegged.FirstExpression")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(PEG.discard!(PEG.option!(OR)), Sequence, PEG.oneOrMore!(PEG.and!(PEG.discard!(OR), Sequence))), "Pegged.FirstExpression")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.discard!(pegged.peg.option!(OR)), Sequence, pegged.peg.oneOrMore!(pegged.peg.and!(pegged.peg.discard!(OR), Sequence))), "Pegged.FirstExpression"), "FirstExpression")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(PEG.discard!(PEG.option!(OR)), Sequence, PEG.oneOrMore!(PEG.and!(PEG.discard!(OR), Sequence))), "Pegged.FirstExpression"), "FirstExpression")(ParseTree("", false,[], s)); } } static string FirstExpression(GetName g) @@ -365,25 +368,25 @@ struct GenericPegged(TParseTree) return "Pegged.FirstExpression"; } - static TParseTree LongestExpression(TParseTree p) + static ParseTree LongestExpression(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.discard!(pegged.peg.option!(pegged.peg.or!(OR, LONGEST_OR))), Sequence, pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.discard!(LONGEST_OR), Sequence))), "Pegged.LongestExpression")(p); + return PEG.defined!(PEG.and!(PEG.discard!(PEG.option!(PEG.or!(OR, LONGEST_OR))), Sequence, PEG.zeroOrMore!(PEG.and!(PEG.discard!(LONGEST_OR), Sequence))), "Pegged.LongestExpression")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.discard!(pegged.peg.option!(pegged.peg.or!(OR, LONGEST_OR))), Sequence, pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.discard!(LONGEST_OR), Sequence))), "Pegged.LongestExpression"), "LongestExpression")(p); + return hooked!(PEG.defined!(PEG.and!(PEG.discard!(PEG.option!(PEG.or!(OR, LONGEST_OR))), Sequence, PEG.zeroOrMore!(PEG.and!(PEG.discard!(LONGEST_OR), Sequence))), "Pegged.LongestExpression"), "LongestExpression")(p); } } - static TParseTree LongestExpression(string s) + static ParseTree LongestExpression(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.discard!(pegged.peg.option!(pegged.peg.or!(OR, LONGEST_OR))), Sequence, pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.discard!(LONGEST_OR), Sequence))), "Pegged.LongestExpression")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(PEG.discard!(PEG.option!(PEG.or!(OR, LONGEST_OR))), Sequence, PEG.zeroOrMore!(PEG.and!(PEG.discard!(LONGEST_OR), Sequence))), "Pegged.LongestExpression")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.discard!(pegged.peg.option!(pegged.peg.or!(OR, LONGEST_OR))), Sequence, pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.discard!(LONGEST_OR), Sequence))), "Pegged.LongestExpression"), "LongestExpression")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(PEG.discard!(PEG.option!(PEG.or!(OR, LONGEST_OR))), Sequence, PEG.zeroOrMore!(PEG.and!(PEG.discard!(LONGEST_OR), Sequence))), "Pegged.LongestExpression"), "LongestExpression")(ParseTree("", false,[], s)); } } static string LongestExpression(GetName g) @@ -391,25 +394,25 @@ struct GenericPegged(TParseTree) return "Pegged.LongestExpression"; } - static TParseTree Sequence(TParseTree p) + static ParseTree Sequence(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.oneOrMore!(Prefix), "Pegged.Sequence")(p); + return PEG.defined!(PEG.oneOrMore!(Prefix), "Pegged.Sequence")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.oneOrMore!(Prefix), "Pegged.Sequence"), "Sequence")(p); + return hooked!(PEG.defined!(PEG.oneOrMore!(Prefix), "Pegged.Sequence"), "Sequence")(p); } } - static TParseTree Sequence(string s) + static ParseTree Sequence(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.oneOrMore!(Prefix), "Pegged.Sequence")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.oneOrMore!(Prefix), "Pegged.Sequence")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.oneOrMore!(Prefix), "Pegged.Sequence"), "Sequence")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.oneOrMore!(Prefix), "Pegged.Sequence"), "Sequence")(ParseTree("", false,[], s)); } } static string Sequence(GetName g) @@ -417,25 +420,25 @@ struct GenericPegged(TParseTree) return "Pegged.Sequence"; } - static TParseTree Prefix(TParseTree p) + static ParseTree Prefix(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.zeroOrMore!(pegged.peg.or!(POS, NEG, FUSE, DISCARD, KEEP, DROP, PROPAGATE)), Suffix), "Pegged.Prefix")(p); + return PEG.defined!(PEG.and!(PEG.zeroOrMore!(PEG.or!(POS, NEG, FUSE, DISCARD, KEEP, DROP, PROPAGATE)), Suffix), "Pegged.Prefix")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.zeroOrMore!(pegged.peg.or!(POS, NEG, FUSE, DISCARD, KEEP, DROP, PROPAGATE)), Suffix), "Pegged.Prefix"), "Prefix")(p); + return hooked!(PEG.defined!(PEG.and!(PEG.zeroOrMore!(PEG.or!(POS, NEG, FUSE, DISCARD, KEEP, DROP, PROPAGATE)), Suffix), "Pegged.Prefix"), "Prefix")(p); } } - static TParseTree Prefix(string s) + static ParseTree Prefix(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.zeroOrMore!(pegged.peg.or!(POS, NEG, FUSE, DISCARD, KEEP, DROP, PROPAGATE)), Suffix), "Pegged.Prefix")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(PEG.zeroOrMore!(PEG.or!(POS, NEG, FUSE, DISCARD, KEEP, DROP, PROPAGATE)), Suffix), "Pegged.Prefix")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.zeroOrMore!(pegged.peg.or!(POS, NEG, FUSE, DISCARD, KEEP, DROP, PROPAGATE)), Suffix), "Pegged.Prefix"), "Prefix")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(PEG.zeroOrMore!(PEG.or!(POS, NEG, FUSE, DISCARD, KEEP, DROP, PROPAGATE)), Suffix), "Pegged.Prefix"), "Prefix")(ParseTree("", false,[], s)); } } static string Prefix(GetName g) @@ -443,25 +446,25 @@ struct GenericPegged(TParseTree) return "Pegged.Prefix"; } - static TParseTree Suffix(TParseTree p) + static ParseTree Suffix(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(Primary, pegged.peg.zeroOrMore!(pegged.peg.or!(OPTION, ZEROORMORE, ONEORMORE, Action))), "Pegged.Suffix")(p); + return PEG.defined!(PEG.and!(Primary, PEG.zeroOrMore!(PEG.or!(OPTION, ZEROORMORE, ONEORMORE, Action))), "Pegged.Suffix")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(Primary, pegged.peg.zeroOrMore!(pegged.peg.or!(OPTION, ZEROORMORE, ONEORMORE, Action))), "Pegged.Suffix"), "Suffix")(p); + return hooked!(PEG.defined!(PEG.and!(Primary, PEG.zeroOrMore!(PEG.or!(OPTION, ZEROORMORE, ONEORMORE, Action))), "Pegged.Suffix"), "Suffix")(p); } } - static TParseTree Suffix(string s) + static ParseTree Suffix(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(Primary, pegged.peg.zeroOrMore!(pegged.peg.or!(OPTION, ZEROORMORE, ONEORMORE, Action))), "Pegged.Suffix")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(Primary, PEG.zeroOrMore!(PEG.or!(OPTION, ZEROORMORE, ONEORMORE, Action))), "Pegged.Suffix")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(Primary, pegged.peg.zeroOrMore!(pegged.peg.or!(OPTION, ZEROORMORE, ONEORMORE, Action))), "Pegged.Suffix"), "Suffix")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(Primary, PEG.zeroOrMore!(PEG.or!(OPTION, ZEROORMORE, ONEORMORE, Action))), "Pegged.Suffix"), "Suffix")(ParseTree("", false,[], s)); } } static string Suffix(GetName g) @@ -469,25 +472,25 @@ struct GenericPegged(TParseTree) return "Pegged.Suffix"; } - static TParseTree Primary(TParseTree p) + static ParseTree Primary(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.negLookahead!(pegged.peg.and!(LhsName, Arrow)), pegged.peg.or!(RhsName, pegged.peg.and!(pegged.peg.discard!(OPEN), Expression, pegged.peg.discard!(CLOSE)), Literal, CILiteral, CharClass, ANY)), "Pegged.Primary")(p); + return PEG.defined!(PEG.and!(PEG.negLookahead!(PEG.and!(LhsName, Arrow)), PEG.or!(RhsName, PEG.and!(PEG.discard!(OPEN), Expression, PEG.discard!(CLOSE)), Literal, CILiteral, CharClass, ANY)), "Pegged.Primary")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.negLookahead!(pegged.peg.and!(LhsName, Arrow)), pegged.peg.or!(RhsName, pegged.peg.and!(pegged.peg.discard!(OPEN), Expression, pegged.peg.discard!(CLOSE)), Literal, CILiteral, CharClass, ANY)), "Pegged.Primary"), "Primary")(p); + return hooked!(PEG.defined!(PEG.and!(PEG.negLookahead!(PEG.and!(LhsName, Arrow)), PEG.or!(RhsName, PEG.and!(PEG.discard!(OPEN), Expression, PEG.discard!(CLOSE)), Literal, CILiteral, CharClass, ANY)), "Pegged.Primary"), "Primary")(p); } } - static TParseTree Primary(string s) + static ParseTree Primary(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.negLookahead!(pegged.peg.and!(LhsName, Arrow)), pegged.peg.or!(RhsName, pegged.peg.and!(pegged.peg.discard!(OPEN), Expression, pegged.peg.discard!(CLOSE)), Literal, CILiteral, CharClass, ANY)), "Pegged.Primary")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(PEG.negLookahead!(PEG.and!(LhsName, Arrow)), PEG.or!(RhsName, PEG.and!(PEG.discard!(OPEN), Expression, PEG.discard!(CLOSE)), Literal, CILiteral, CharClass, ANY)), "Pegged.Primary")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.negLookahead!(pegged.peg.and!(LhsName, Arrow)), pegged.peg.or!(RhsName, pegged.peg.and!(pegged.peg.discard!(OPEN), Expression, pegged.peg.discard!(CLOSE)), Literal, CILiteral, CharClass, ANY)), "Pegged.Primary"), "Primary")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(PEG.negLookahead!(PEG.and!(LhsName, Arrow)), PEG.or!(RhsName, PEG.and!(PEG.discard!(OPEN), Expression, PEG.discard!(CLOSE)), Literal, CILiteral, CharClass, ANY)), "Pegged.Primary"), "Primary")(ParseTree("", false,[], s)); } } static string Primary(GetName g) @@ -495,25 +498,25 @@ struct GenericPegged(TParseTree) return "Pegged.Primary"; } - static TParseTree Identifier(TParseTree p) + static ParseTree Identifier(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(identifier, "Pegged.Identifier")(p); + return PEG.defined!(identifier, "Pegged.Identifier")(p); } else { - return hooked!(pegged.peg.defined!(identifier, "Pegged.Identifier"), "Identifier")(p); + return hooked!(PEG.defined!(identifier, "Pegged.Identifier"), "Identifier")(p); } } - static TParseTree Identifier(string s) + static ParseTree Identifier(string s) { if(__ctfe) - return pegged.peg.defined!(identifier, "Pegged.Identifier")(TParseTree("", false,[], s)); + return PEG.defined!(identifier, "Pegged.Identifier")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(identifier, "Pegged.Identifier"), "Identifier")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(identifier, "Pegged.Identifier"), "Identifier")(ParseTree("", false,[], s)); } } static string Identifier(GetName g) @@ -521,25 +524,25 @@ struct GenericPegged(TParseTree) return "Pegged.Identifier"; } - static TParseTree GrammarName(TParseTree p) + static ParseTree GrammarName(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(Identifier, pegged.peg.option!(ParamList), Spacing, pegged.peg.discard!(pegged.peg.literal!(":")), Spacing), "Pegged.GrammarName")(p); + return PEG.defined!(PEG.and!(Identifier, PEG.option!(ParamList), Spacing, PEG.discard!(PEG.literal!(":")), Spacing), "Pegged.GrammarName")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(Identifier, pegged.peg.option!(ParamList), Spacing, pegged.peg.discard!(pegged.peg.literal!(":")), Spacing), "Pegged.GrammarName"), "GrammarName")(p); + return hooked!(PEG.defined!(PEG.and!(Identifier, PEG.option!(ParamList), Spacing, PEG.discard!(PEG.literal!(":")), Spacing), "Pegged.GrammarName"), "GrammarName")(p); } } - static TParseTree GrammarName(string s) + static ParseTree GrammarName(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(Identifier, pegged.peg.option!(ParamList), Spacing, pegged.peg.discard!(pegged.peg.literal!(":")), Spacing), "Pegged.GrammarName")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(Identifier, PEG.option!(ParamList), Spacing, PEG.discard!(PEG.literal!(":")), Spacing), "Pegged.GrammarName")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(Identifier, pegged.peg.option!(ParamList), Spacing, pegged.peg.discard!(pegged.peg.literal!(":")), Spacing), "Pegged.GrammarName"), "GrammarName")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(Identifier, PEG.option!(ParamList), Spacing, PEG.discard!(PEG.literal!(":")), Spacing), "Pegged.GrammarName"), "GrammarName")(ParseTree("", false,[], s)); } } static string GrammarName(GetName g) @@ -547,25 +550,25 @@ struct GenericPegged(TParseTree) return "Pegged.GrammarName"; } - static TParseTree LhsName(TParseTree p) + static ParseTree LhsName(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(Identifier, pegged.peg.option!(ParamList), Spacing), "Pegged.LhsName")(p); + return PEG.defined!(PEG.and!(Identifier, PEG.option!(ParamList), Spacing), "Pegged.LhsName")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(Identifier, pegged.peg.option!(ParamList), Spacing), "Pegged.LhsName"), "LhsName")(p); + return hooked!(PEG.defined!(PEG.and!(Identifier, PEG.option!(ParamList), Spacing), "Pegged.LhsName"), "LhsName")(p); } } - static TParseTree LhsName(string s) + static ParseTree LhsName(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(Identifier, pegged.peg.option!(ParamList), Spacing), "Pegged.LhsName")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(Identifier, PEG.option!(ParamList), Spacing), "Pegged.LhsName")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(Identifier, pegged.peg.option!(ParamList), Spacing), "Pegged.LhsName"), "LhsName")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(Identifier, PEG.option!(ParamList), Spacing), "Pegged.LhsName"), "LhsName")(ParseTree("", false,[], s)); } } static string LhsName(GetName g) @@ -573,25 +576,25 @@ struct GenericPegged(TParseTree) return "Pegged.LhsName"; } - static TParseTree RhsName(TParseTree p) + static ParseTree RhsName(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(Identifier, pegged.peg.option!(ArgList), pegged.peg.zeroOrMore!(pegged.peg.and!(NAMESEP, Identifier, pegged.peg.option!(ArgList))), Spacing), "Pegged.RhsName")(p); + return PEG.defined!(PEG.and!(Identifier, PEG.option!(ArgList), PEG.zeroOrMore!(PEG.and!(NAMESEP, Identifier, PEG.option!(ArgList))), Spacing), "Pegged.RhsName")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(Identifier, pegged.peg.option!(ArgList), pegged.peg.zeroOrMore!(pegged.peg.and!(NAMESEP, Identifier, pegged.peg.option!(ArgList))), Spacing), "Pegged.RhsName"), "RhsName")(p); + return hooked!(PEG.defined!(PEG.and!(Identifier, PEG.option!(ArgList), PEG.zeroOrMore!(PEG.and!(NAMESEP, Identifier, PEG.option!(ArgList))), Spacing), "Pegged.RhsName"), "RhsName")(p); } } - static TParseTree RhsName(string s) + static ParseTree RhsName(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(Identifier, pegged.peg.option!(ArgList), pegged.peg.zeroOrMore!(pegged.peg.and!(NAMESEP, Identifier, pegged.peg.option!(ArgList))), Spacing), "Pegged.RhsName")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(Identifier, PEG.option!(ArgList), PEG.zeroOrMore!(PEG.and!(NAMESEP, Identifier, PEG.option!(ArgList))), Spacing), "Pegged.RhsName")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(Identifier, pegged.peg.option!(ArgList), pegged.peg.zeroOrMore!(pegged.peg.and!(NAMESEP, Identifier, pegged.peg.option!(ArgList))), Spacing), "Pegged.RhsName"), "RhsName")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(Identifier, PEG.option!(ArgList), PEG.zeroOrMore!(PEG.and!(NAMESEP, Identifier, PEG.option!(ArgList))), Spacing), "Pegged.RhsName"), "RhsName")(ParseTree("", false,[], s)); } } static string RhsName(GetName g) @@ -599,25 +602,25 @@ struct GenericPegged(TParseTree) return "Pegged.RhsName"; } - static TParseTree ParamList(TParseTree p) + static ParseTree ParamList(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.discard!(OPEN), Param, pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.discard!(SEPARATOR), Param)), pegged.peg.discard!(CLOSE)), "Pegged.ParamList")(p); + return PEG.defined!(PEG.and!(PEG.discard!(OPEN), Param, PEG.zeroOrMore!(PEG.and!(PEG.discard!(SEPARATOR), Param)), PEG.discard!(CLOSE)), "Pegged.ParamList")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.discard!(OPEN), Param, pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.discard!(SEPARATOR), Param)), pegged.peg.discard!(CLOSE)), "Pegged.ParamList"), "ParamList")(p); + return hooked!(PEG.defined!(PEG.and!(PEG.discard!(OPEN), Param, PEG.zeroOrMore!(PEG.and!(PEG.discard!(SEPARATOR), Param)), PEG.discard!(CLOSE)), "Pegged.ParamList"), "ParamList")(p); } } - static TParseTree ParamList(string s) + static ParseTree ParamList(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.discard!(OPEN), Param, pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.discard!(SEPARATOR), Param)), pegged.peg.discard!(CLOSE)), "Pegged.ParamList")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(PEG.discard!(OPEN), Param, PEG.zeroOrMore!(PEG.and!(PEG.discard!(SEPARATOR), Param)), PEG.discard!(CLOSE)), "Pegged.ParamList")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.discard!(OPEN), Param, pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.discard!(SEPARATOR), Param)), pegged.peg.discard!(CLOSE)), "Pegged.ParamList"), "ParamList")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(PEG.discard!(OPEN), Param, PEG.zeroOrMore!(PEG.and!(PEG.discard!(SEPARATOR), Param)), PEG.discard!(CLOSE)), "Pegged.ParamList"), "ParamList")(ParseTree("", false,[], s)); } } static string ParamList(GetName g) @@ -625,25 +628,25 @@ struct GenericPegged(TParseTree) return "Pegged.ParamList"; } - static TParseTree Param(TParseTree p) + static ParseTree Param(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.or!(DefaultParam, SingleParam), "Pegged.Param")(p); + return PEG.defined!(PEG.or!(DefaultParam, SingleParam), "Pegged.Param")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.or!(DefaultParam, SingleParam), "Pegged.Param"), "Param")(p); + return hooked!(PEG.defined!(PEG.or!(DefaultParam, SingleParam), "Pegged.Param"), "Param")(p); } } - static TParseTree Param(string s) + static ParseTree Param(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.or!(DefaultParam, SingleParam), "Pegged.Param")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.or!(DefaultParam, SingleParam), "Pegged.Param")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.or!(DefaultParam, SingleParam), "Pegged.Param"), "Param")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.or!(DefaultParam, SingleParam), "Pegged.Param"), "Param")(ParseTree("", false,[], s)); } } static string Param(GetName g) @@ -651,25 +654,25 @@ struct GenericPegged(TParseTree) return "Pegged.Param"; } - static TParseTree DefaultParam(TParseTree p) + static ParseTree DefaultParam(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(Identifier, Spacing, pegged.peg.discard!(ASSIGN), Expression), "Pegged.DefaultParam")(p); + return PEG.defined!(PEG.and!(Identifier, Spacing, PEG.discard!(ASSIGN), Expression), "Pegged.DefaultParam")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(Identifier, Spacing, pegged.peg.discard!(ASSIGN), Expression), "Pegged.DefaultParam"), "DefaultParam")(p); + return hooked!(PEG.defined!(PEG.and!(Identifier, Spacing, PEG.discard!(ASSIGN), Expression), "Pegged.DefaultParam"), "DefaultParam")(p); } } - static TParseTree DefaultParam(string s) + static ParseTree DefaultParam(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(Identifier, Spacing, pegged.peg.discard!(ASSIGN), Expression), "Pegged.DefaultParam")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(Identifier, Spacing, PEG.discard!(ASSIGN), Expression), "Pegged.DefaultParam")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(Identifier, Spacing, pegged.peg.discard!(ASSIGN), Expression), "Pegged.DefaultParam"), "DefaultParam")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(Identifier, Spacing, PEG.discard!(ASSIGN), Expression), "Pegged.DefaultParam"), "DefaultParam")(ParseTree("", false,[], s)); } } static string DefaultParam(GetName g) @@ -677,25 +680,25 @@ struct GenericPegged(TParseTree) return "Pegged.DefaultParam"; } - static TParseTree SingleParam(TParseTree p) + static ParseTree SingleParam(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(Identifier, Spacing), "Pegged.SingleParam")(p); + return PEG.defined!(PEG.and!(Identifier, Spacing), "Pegged.SingleParam")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(Identifier, Spacing), "Pegged.SingleParam"), "SingleParam")(p); + return hooked!(PEG.defined!(PEG.and!(Identifier, Spacing), "Pegged.SingleParam"), "SingleParam")(p); } } - static TParseTree SingleParam(string s) + static ParseTree SingleParam(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(Identifier, Spacing), "Pegged.SingleParam")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(Identifier, Spacing), "Pegged.SingleParam")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(Identifier, Spacing), "Pegged.SingleParam"), "SingleParam")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(Identifier, Spacing), "Pegged.SingleParam"), "SingleParam")(ParseTree("", false,[], s)); } } static string SingleParam(GetName g) @@ -703,25 +706,25 @@ struct GenericPegged(TParseTree) return "Pegged.SingleParam"; } - static TParseTree ArgList(TParseTree p) + static ParseTree ArgList(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.discard!(OPEN), Expression, pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.discard!(SEPARATOR), Expression)), pegged.peg.discard!(CLOSE)), "Pegged.ArgList")(p); + return PEG.defined!(PEG.and!(PEG.discard!(OPEN), Expression, PEG.zeroOrMore!(PEG.and!(PEG.discard!(SEPARATOR), Expression)), PEG.discard!(CLOSE)), "Pegged.ArgList")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.discard!(OPEN), Expression, pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.discard!(SEPARATOR), Expression)), pegged.peg.discard!(CLOSE)), "Pegged.ArgList"), "ArgList")(p); + return hooked!(PEG.defined!(PEG.and!(PEG.discard!(OPEN), Expression, PEG.zeroOrMore!(PEG.and!(PEG.discard!(SEPARATOR), Expression)), PEG.discard!(CLOSE)), "Pegged.ArgList"), "ArgList")(p); } } - static TParseTree ArgList(string s) + static ParseTree ArgList(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.discard!(OPEN), Expression, pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.discard!(SEPARATOR), Expression)), pegged.peg.discard!(CLOSE)), "Pegged.ArgList")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(PEG.discard!(OPEN), Expression, PEG.zeroOrMore!(PEG.and!(PEG.discard!(SEPARATOR), Expression)), PEG.discard!(CLOSE)), "Pegged.ArgList")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.discard!(OPEN), Expression, pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.discard!(SEPARATOR), Expression)), pegged.peg.discard!(CLOSE)), "Pegged.ArgList"), "ArgList")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(PEG.discard!(OPEN), Expression, PEG.zeroOrMore!(PEG.and!(PEG.discard!(SEPARATOR), Expression)), PEG.discard!(CLOSE)), "Pegged.ArgList"), "ArgList")(ParseTree("", false,[], s)); } } static string ArgList(GetName g) @@ -729,25 +732,25 @@ struct GenericPegged(TParseTree) return "Pegged.ArgList"; } - static TParseTree Literal(TParseTree p) + static ParseTree Literal(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.or!(pegged.peg.and!(quote, pegged.peg.fuse!(pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(quote), Char))), quote, pegged.peg.negLookahead!(pegged.peg.literal!("i")), Spacing), pegged.peg.and!(doublequote, pegged.peg.fuse!(pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(doublequote), Char))), doublequote, pegged.peg.negLookahead!(pegged.peg.literal!("i")), Spacing)), "Pegged.Literal")(p); + return PEG.defined!(PEG.or!(PEG.and!(quote, PEG.fuse!(PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(quote), Char))), quote, PEG.negLookahead!(PEG.literal!("i")), Spacing), PEG.and!(doublequote, PEG.fuse!(PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(doublequote), Char))), doublequote, PEG.negLookahead!(PEG.literal!("i")), Spacing)), "Pegged.Literal")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.or!(pegged.peg.and!(quote, pegged.peg.fuse!(pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(quote), Char))), quote, pegged.peg.negLookahead!(pegged.peg.literal!("i")), Spacing), pegged.peg.and!(doublequote, pegged.peg.fuse!(pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(doublequote), Char))), doublequote, pegged.peg.negLookahead!(pegged.peg.literal!("i")), Spacing)), "Pegged.Literal"), "Literal")(p); + return hooked!(PEG.defined!(PEG.or!(PEG.and!(quote, PEG.fuse!(PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(quote), Char))), quote, PEG.negLookahead!(PEG.literal!("i")), Spacing), PEG.and!(doublequote, PEG.fuse!(PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(doublequote), Char))), doublequote, PEG.negLookahead!(PEG.literal!("i")), Spacing)), "Pegged.Literal"), "Literal")(p); } } - static TParseTree Literal(string s) + static ParseTree Literal(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.or!(pegged.peg.and!(quote, pegged.peg.fuse!(pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(quote), Char))), quote, pegged.peg.negLookahead!(pegged.peg.literal!("i")), Spacing), pegged.peg.and!(doublequote, pegged.peg.fuse!(pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(doublequote), Char))), doublequote, pegged.peg.negLookahead!(pegged.peg.literal!("i")), Spacing)), "Pegged.Literal")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.or!(PEG.and!(quote, PEG.fuse!(PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(quote), Char))), quote, PEG.negLookahead!(PEG.literal!("i")), Spacing), PEG.and!(doublequote, PEG.fuse!(PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(doublequote), Char))), doublequote, PEG.negLookahead!(PEG.literal!("i")), Spacing)), "Pegged.Literal")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.or!(pegged.peg.and!(quote, pegged.peg.fuse!(pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(quote), Char))), quote, pegged.peg.negLookahead!(pegged.peg.literal!("i")), Spacing), pegged.peg.and!(doublequote, pegged.peg.fuse!(pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(doublequote), Char))), doublequote, pegged.peg.negLookahead!(pegged.peg.literal!("i")), Spacing)), "Pegged.Literal"), "Literal")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.or!(PEG.and!(quote, PEG.fuse!(PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(quote), Char))), quote, PEG.negLookahead!(PEG.literal!("i")), Spacing), PEG.and!(doublequote, PEG.fuse!(PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(doublequote), Char))), doublequote, PEG.negLookahead!(PEG.literal!("i")), Spacing)), "Pegged.Literal"), "Literal")(ParseTree("", false,[], s)); } } static string Literal(GetName g) @@ -755,25 +758,25 @@ struct GenericPegged(TParseTree) return "Pegged.Literal"; } - static TParseTree CILiteral(TParseTree p) + static ParseTree CILiteral(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.or!(pegged.peg.and!(quote, pegged.peg.fuse!(pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(quote), Char))), quote, pegged.peg.discard!(pegged.peg.literal!("i")), Spacing), pegged.peg.and!(doublequote, pegged.peg.fuse!(pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(doublequote), Char))), doublequote, pegged.peg.discard!(pegged.peg.literal!("i")), Spacing)), "Pegged.CILiteral")(p); + return PEG.defined!(PEG.or!(PEG.and!(quote, PEG.fuse!(PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(quote), Char))), quote, PEG.discard!(PEG.literal!("i")), Spacing), PEG.and!(doublequote, PEG.fuse!(PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(doublequote), Char))), doublequote, PEG.discard!(PEG.literal!("i")), Spacing)), "Pegged.CILiteral")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.or!(pegged.peg.and!(quote, pegged.peg.fuse!(pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(quote), Char))), quote, pegged.peg.discard!(pegged.peg.literal!("i")), Spacing), pegged.peg.and!(doublequote, pegged.peg.fuse!(pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(doublequote), Char))), doublequote, pegged.peg.discard!(pegged.peg.literal!("i")), Spacing)), "Pegged.CILiteral"), "CILiteral")(p); + return hooked!(PEG.defined!(PEG.or!(PEG.and!(quote, PEG.fuse!(PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(quote), Char))), quote, PEG.discard!(PEG.literal!("i")), Spacing), PEG.and!(doublequote, PEG.fuse!(PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(doublequote), Char))), doublequote, PEG.discard!(PEG.literal!("i")), Spacing)), "Pegged.CILiteral"), "CILiteral")(p); } } - static TParseTree CILiteral(string s) + static ParseTree CILiteral(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.or!(pegged.peg.and!(quote, pegged.peg.fuse!(pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(quote), Char))), quote, pegged.peg.discard!(pegged.peg.literal!("i")), Spacing), pegged.peg.and!(doublequote, pegged.peg.fuse!(pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(doublequote), Char))), doublequote, pegged.peg.discard!(pegged.peg.literal!("i")), Spacing)), "Pegged.CILiteral")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.or!(PEG.and!(quote, PEG.fuse!(PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(quote), Char))), quote, PEG.discard!(PEG.literal!("i")), Spacing), PEG.and!(doublequote, PEG.fuse!(PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(doublequote), Char))), doublequote, PEG.discard!(PEG.literal!("i")), Spacing)), "Pegged.CILiteral")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.or!(pegged.peg.and!(quote, pegged.peg.fuse!(pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(quote), Char))), quote, pegged.peg.discard!(pegged.peg.literal!("i")), Spacing), pegged.peg.and!(doublequote, pegged.peg.fuse!(pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(doublequote), Char))), doublequote, pegged.peg.discard!(pegged.peg.literal!("i")), Spacing)), "Pegged.CILiteral"), "CILiteral")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.or!(PEG.and!(quote, PEG.fuse!(PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(quote), Char))), quote, PEG.discard!(PEG.literal!("i")), Spacing), PEG.and!(doublequote, PEG.fuse!(PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(doublequote), Char))), doublequote, PEG.discard!(PEG.literal!("i")), Spacing)), "Pegged.CILiteral"), "CILiteral")(ParseTree("", false,[], s)); } } static string CILiteral(GetName g) @@ -781,25 +784,25 @@ struct GenericPegged(TParseTree) return "Pegged.CILiteral"; } - static TParseTree CharClass(TParseTree p) + static ParseTree CharClass(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.discard!(pegged.peg.literal!("[")), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(pegged.peg.literal!("]")), CharRange)), pegged.peg.discard!(pegged.peg.literal!("]")), Spacing), "Pegged.CharClass")(p); + return PEG.defined!(PEG.and!(PEG.discard!(PEG.literal!("[")), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.literal!("]")), CharRange)), PEG.discard!(PEG.literal!("]")), Spacing), "Pegged.CharClass")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.discard!(pegged.peg.literal!("[")), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(pegged.peg.literal!("]")), CharRange)), pegged.peg.discard!(pegged.peg.literal!("]")), Spacing), "Pegged.CharClass"), "CharClass")(p); + return hooked!(PEG.defined!(PEG.and!(PEG.discard!(PEG.literal!("[")), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.literal!("]")), CharRange)), PEG.discard!(PEG.literal!("]")), Spacing), "Pegged.CharClass"), "CharClass")(p); } } - static TParseTree CharClass(string s) + static ParseTree CharClass(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.discard!(pegged.peg.literal!("[")), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(pegged.peg.literal!("]")), CharRange)), pegged.peg.discard!(pegged.peg.literal!("]")), Spacing), "Pegged.CharClass")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(PEG.discard!(PEG.literal!("[")), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.literal!("]")), CharRange)), PEG.discard!(PEG.literal!("]")), Spacing), "Pegged.CharClass")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.discard!(pegged.peg.literal!("[")), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(pegged.peg.literal!("]")), CharRange)), pegged.peg.discard!(pegged.peg.literal!("]")), Spacing), "Pegged.CharClass"), "CharClass")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(PEG.discard!(PEG.literal!("[")), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.literal!("]")), CharRange)), PEG.discard!(PEG.literal!("]")), Spacing), "Pegged.CharClass"), "CharClass")(ParseTree("", false,[], s)); } } static string CharClass(GetName g) @@ -807,25 +810,25 @@ struct GenericPegged(TParseTree) return "Pegged.CharClass"; } - static TParseTree CharRange(TParseTree p) + static ParseTree CharRange(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.or!(pegged.peg.and!(Char, pegged.peg.literal!("-"), Char), Char), "Pegged.CharRange")(p); + return PEG.defined!(PEG.or!(PEG.and!(Char, PEG.literal!("-"), Char), Char), "Pegged.CharRange")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.or!(pegged.peg.and!(Char, pegged.peg.literal!("-"), Char), Char), "Pegged.CharRange"), "CharRange")(p); + return hooked!(PEG.defined!(PEG.or!(PEG.and!(Char, PEG.literal!("-"), Char), Char), "Pegged.CharRange"), "CharRange")(p); } } - static TParseTree CharRange(string s) + static ParseTree CharRange(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.or!(pegged.peg.and!(Char, pegged.peg.literal!("-"), Char), Char), "Pegged.CharRange")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.or!(PEG.and!(Char, PEG.literal!("-"), Char), Char), "Pegged.CharRange")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.or!(pegged.peg.and!(Char, pegged.peg.literal!("-"), Char), Char), "Pegged.CharRange"), "CharRange")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.or!(PEG.and!(Char, PEG.literal!("-"), Char), Char), "Pegged.CharRange"), "CharRange")(ParseTree("", false,[], s)); } } static string CharRange(GetName g) @@ -833,25 +836,25 @@ struct GenericPegged(TParseTree) return "Pegged.CharRange"; } - static TParseTree Char(TParseTree p) + static ParseTree Char(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.fuse!(pegged.peg.or!(pegged.peg.and!(backslash, pegged.peg.or!(quote, doublequote, backquote, backslash, pegged.peg.literal!("-"), pegged.peg.literal!("["), pegged.peg.literal!("]"), pegged.peg.or!(pegged.peg.literal!("n"), pegged.peg.literal!("r"), pegged.peg.literal!("t")), pegged.peg.and!(pegged.peg.charRange!('0', '2'), pegged.peg.charRange!('0', '7'), pegged.peg.charRange!('0', '7')), pegged.peg.and!(pegged.peg.charRange!('0', '7'), pegged.peg.option!(pegged.peg.charRange!('0', '7'))), pegged.peg.and!(pegged.peg.literal!("x"), hexDigit, hexDigit), pegged.peg.and!(pegged.peg.literal!("u"), hexDigit, hexDigit, hexDigit, hexDigit), pegged.peg.and!(pegged.peg.literal!("U"), hexDigit, hexDigit, hexDigit, hexDigit, hexDigit, hexDigit, hexDigit, hexDigit))), pegged.peg.any)), "Pegged.Char")(p); + return PEG.defined!(PEG.fuse!(PEG.or!(PEG.and!(backslash, PEG.or!(quote, doublequote, backquote, backslash, PEG.literal!("-"), PEG.literal!("["), PEG.literal!("]"), PEG.or!(PEG.literal!("n"), PEG.literal!("r"), PEG.literal!("t")), PEG.and!(PEG.charRange!('0', '2'), PEG.charRange!('0', '7'), PEG.charRange!('0', '7')), PEG.and!(PEG.charRange!('0', '7'), PEG.option!(PEG.charRange!('0', '7'))), PEG.and!(PEG.literal!("x"), hexDigit, hexDigit), PEG.and!(PEG.literal!("u"), hexDigit, hexDigit, hexDigit, hexDigit), PEG.and!(PEG.literal!("U"), hexDigit, hexDigit, hexDigit, hexDigit, hexDigit, hexDigit, hexDigit, hexDigit))), PEG.any)), "Pegged.Char")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.fuse!(pegged.peg.or!(pegged.peg.and!(backslash, pegged.peg.or!(quote, doublequote, backquote, backslash, pegged.peg.literal!("-"), pegged.peg.literal!("["), pegged.peg.literal!("]"), pegged.peg.or!(pegged.peg.literal!("n"), pegged.peg.literal!("r"), pegged.peg.literal!("t")), pegged.peg.and!(pegged.peg.charRange!('0', '2'), pegged.peg.charRange!('0', '7'), pegged.peg.charRange!('0', '7')), pegged.peg.and!(pegged.peg.charRange!('0', '7'), pegged.peg.option!(pegged.peg.charRange!('0', '7'))), pegged.peg.and!(pegged.peg.literal!("x"), hexDigit, hexDigit), pegged.peg.and!(pegged.peg.literal!("u"), hexDigit, hexDigit, hexDigit, hexDigit), pegged.peg.and!(pegged.peg.literal!("U"), hexDigit, hexDigit, hexDigit, hexDigit, hexDigit, hexDigit, hexDigit, hexDigit))), pegged.peg.any)), "Pegged.Char"), "Char")(p); + return hooked!(PEG.defined!(PEG.fuse!(PEG.or!(PEG.and!(backslash, PEG.or!(quote, doublequote, backquote, backslash, PEG.literal!("-"), PEG.literal!("["), PEG.literal!("]"), PEG.or!(PEG.literal!("n"), PEG.literal!("r"), PEG.literal!("t")), PEG.and!(PEG.charRange!('0', '2'), PEG.charRange!('0', '7'), PEG.charRange!('0', '7')), PEG.and!(PEG.charRange!('0', '7'), PEG.option!(PEG.charRange!('0', '7'))), PEG.and!(PEG.literal!("x"), hexDigit, hexDigit), PEG.and!(PEG.literal!("u"), hexDigit, hexDigit, hexDigit, hexDigit), PEG.and!(PEG.literal!("U"), hexDigit, hexDigit, hexDigit, hexDigit, hexDigit, hexDigit, hexDigit, hexDigit))), PEG.any)), "Pegged.Char"), "Char")(p); } } - static TParseTree Char(string s) + static ParseTree Char(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.fuse!(pegged.peg.or!(pegged.peg.and!(backslash, pegged.peg.or!(quote, doublequote, backquote, backslash, pegged.peg.literal!("-"), pegged.peg.literal!("["), pegged.peg.literal!("]"), pegged.peg.or!(pegged.peg.literal!("n"), pegged.peg.literal!("r"), pegged.peg.literal!("t")), pegged.peg.and!(pegged.peg.charRange!('0', '2'), pegged.peg.charRange!('0', '7'), pegged.peg.charRange!('0', '7')), pegged.peg.and!(pegged.peg.charRange!('0', '7'), pegged.peg.option!(pegged.peg.charRange!('0', '7'))), pegged.peg.and!(pegged.peg.literal!("x"), hexDigit, hexDigit), pegged.peg.and!(pegged.peg.literal!("u"), hexDigit, hexDigit, hexDigit, hexDigit), pegged.peg.and!(pegged.peg.literal!("U"), hexDigit, hexDigit, hexDigit, hexDigit, hexDigit, hexDigit, hexDigit, hexDigit))), pegged.peg.any)), "Pegged.Char")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.fuse!(PEG.or!(PEG.and!(backslash, PEG.or!(quote, doublequote, backquote, backslash, PEG.literal!("-"), PEG.literal!("["), PEG.literal!("]"), PEG.or!(PEG.literal!("n"), PEG.literal!("r"), PEG.literal!("t")), PEG.and!(PEG.charRange!('0', '2'), PEG.charRange!('0', '7'), PEG.charRange!('0', '7')), PEG.and!(PEG.charRange!('0', '7'), PEG.option!(PEG.charRange!('0', '7'))), PEG.and!(PEG.literal!("x"), hexDigit, hexDigit), PEG.and!(PEG.literal!("u"), hexDigit, hexDigit, hexDigit, hexDigit), PEG.and!(PEG.literal!("U"), hexDigit, hexDigit, hexDigit, hexDigit, hexDigit, hexDigit, hexDigit, hexDigit))), PEG.any)), "Pegged.Char")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.fuse!(pegged.peg.or!(pegged.peg.and!(backslash, pegged.peg.or!(quote, doublequote, backquote, backslash, pegged.peg.literal!("-"), pegged.peg.literal!("["), pegged.peg.literal!("]"), pegged.peg.or!(pegged.peg.literal!("n"), pegged.peg.literal!("r"), pegged.peg.literal!("t")), pegged.peg.and!(pegged.peg.charRange!('0', '2'), pegged.peg.charRange!('0', '7'), pegged.peg.charRange!('0', '7')), pegged.peg.and!(pegged.peg.charRange!('0', '7'), pegged.peg.option!(pegged.peg.charRange!('0', '7'))), pegged.peg.and!(pegged.peg.literal!("x"), hexDigit, hexDigit), pegged.peg.and!(pegged.peg.literal!("u"), hexDigit, hexDigit, hexDigit, hexDigit), pegged.peg.and!(pegged.peg.literal!("U"), hexDigit, hexDigit, hexDigit, hexDigit, hexDigit, hexDigit, hexDigit, hexDigit))), pegged.peg.any)), "Pegged.Char"), "Char")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.fuse!(PEG.or!(PEG.and!(backslash, PEG.or!(quote, doublequote, backquote, backslash, PEG.literal!("-"), PEG.literal!("["), PEG.literal!("]"), PEG.or!(PEG.literal!("n"), PEG.literal!("r"), PEG.literal!("t")), PEG.and!(PEG.charRange!('0', '2'), PEG.charRange!('0', '7'), PEG.charRange!('0', '7')), PEG.and!(PEG.charRange!('0', '7'), PEG.option!(PEG.charRange!('0', '7'))), PEG.and!(PEG.literal!("x"), hexDigit, hexDigit), PEG.and!(PEG.literal!("u"), hexDigit, hexDigit, hexDigit, hexDigit), PEG.and!(PEG.literal!("U"), hexDigit, hexDigit, hexDigit, hexDigit, hexDigit, hexDigit, hexDigit, hexDigit))), PEG.any)), "Pegged.Char"), "Char")(ParseTree("", false,[], s)); } } static string Char(GetName g) @@ -859,25 +862,25 @@ struct GenericPegged(TParseTree) return "Pegged.Char"; } - static TParseTree Arrow(TParseTree p) + static ParseTree Arrow(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.or!(LEFTARROW, FUSEARROW, DISCARDARROW, KEEPARROW, DROPARROW, PROPAGATEARROW, ACTIONARROW, SPACEARROW), "Pegged.Arrow")(p); + return PEG.defined!(PEG.or!(LEFTARROW, FUSEARROW, DISCARDARROW, KEEPARROW, DROPARROW, PROPAGATEARROW, ACTIONARROW, SPACEARROW), "Pegged.Arrow")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.or!(LEFTARROW, FUSEARROW, DISCARDARROW, KEEPARROW, DROPARROW, PROPAGATEARROW, ACTIONARROW, SPACEARROW), "Pegged.Arrow"), "Arrow")(p); + return hooked!(PEG.defined!(PEG.or!(LEFTARROW, FUSEARROW, DISCARDARROW, KEEPARROW, DROPARROW, PROPAGATEARROW, ACTIONARROW, SPACEARROW), "Pegged.Arrow"), "Arrow")(p); } } - static TParseTree Arrow(string s) + static ParseTree Arrow(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.or!(LEFTARROW, FUSEARROW, DISCARDARROW, KEEPARROW, DROPARROW, PROPAGATEARROW, ACTIONARROW, SPACEARROW), "Pegged.Arrow")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.or!(LEFTARROW, FUSEARROW, DISCARDARROW, KEEPARROW, DROPARROW, PROPAGATEARROW, ACTIONARROW, SPACEARROW), "Pegged.Arrow")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.or!(LEFTARROW, FUSEARROW, DISCARDARROW, KEEPARROW, DROPARROW, PROPAGATEARROW, ACTIONARROW, SPACEARROW), "Pegged.Arrow"), "Arrow")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.or!(LEFTARROW, FUSEARROW, DISCARDARROW, KEEPARROW, DROPARROW, PROPAGATEARROW, ACTIONARROW, SPACEARROW), "Pegged.Arrow"), "Arrow")(ParseTree("", false,[], s)); } } static string Arrow(GetName g) @@ -885,25 +888,25 @@ struct GenericPegged(TParseTree) return "Pegged.Arrow"; } - static TParseTree LEFTARROW(TParseTree p) + static ParseTree LEFTARROW(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("<-"), Spacing), "Pegged.LEFTARROW")(p); + return PEG.defined!(PEG.and!(PEG.literal!("<-"), Spacing), "Pegged.LEFTARROW")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("<-"), Spacing), "Pegged.LEFTARROW"), "LEFTARROW")(p); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("<-"), Spacing), "Pegged.LEFTARROW"), "LEFTARROW")(p); } } - static TParseTree LEFTARROW(string s) + static ParseTree LEFTARROW(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("<-"), Spacing), "Pegged.LEFTARROW")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(PEG.literal!("<-"), Spacing), "Pegged.LEFTARROW")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("<-"), Spacing), "Pegged.LEFTARROW"), "LEFTARROW")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("<-"), Spacing), "Pegged.LEFTARROW"), "LEFTARROW")(ParseTree("", false,[], s)); } } static string LEFTARROW(GetName g) @@ -911,25 +914,25 @@ struct GenericPegged(TParseTree) return "Pegged.LEFTARROW"; } - static TParseTree FUSEARROW(TParseTree p) + static ParseTree FUSEARROW(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("<~"), Spacing), "Pegged.FUSEARROW")(p); + return PEG.defined!(PEG.and!(PEG.literal!("<~"), Spacing), "Pegged.FUSEARROW")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("<~"), Spacing), "Pegged.FUSEARROW"), "FUSEARROW")(p); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("<~"), Spacing), "Pegged.FUSEARROW"), "FUSEARROW")(p); } } - static TParseTree FUSEARROW(string s) + static ParseTree FUSEARROW(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("<~"), Spacing), "Pegged.FUSEARROW")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(PEG.literal!("<~"), Spacing), "Pegged.FUSEARROW")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("<~"), Spacing), "Pegged.FUSEARROW"), "FUSEARROW")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("<~"), Spacing), "Pegged.FUSEARROW"), "FUSEARROW")(ParseTree("", false,[], s)); } } static string FUSEARROW(GetName g) @@ -937,25 +940,25 @@ struct GenericPegged(TParseTree) return "Pegged.FUSEARROW"; } - static TParseTree DISCARDARROW(TParseTree p) + static ParseTree DISCARDARROW(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("<:"), Spacing), "Pegged.DISCARDARROW")(p); + return PEG.defined!(PEG.and!(PEG.literal!("<:"), Spacing), "Pegged.DISCARDARROW")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("<:"), Spacing), "Pegged.DISCARDARROW"), "DISCARDARROW")(p); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("<:"), Spacing), "Pegged.DISCARDARROW"), "DISCARDARROW")(p); } } - static TParseTree DISCARDARROW(string s) + static ParseTree DISCARDARROW(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("<:"), Spacing), "Pegged.DISCARDARROW")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(PEG.literal!("<:"), Spacing), "Pegged.DISCARDARROW")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("<:"), Spacing), "Pegged.DISCARDARROW"), "DISCARDARROW")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("<:"), Spacing), "Pegged.DISCARDARROW"), "DISCARDARROW")(ParseTree("", false,[], s)); } } static string DISCARDARROW(GetName g) @@ -963,25 +966,25 @@ struct GenericPegged(TParseTree) return "Pegged.DISCARDARROW"; } - static TParseTree KEEPARROW(TParseTree p) + static ParseTree KEEPARROW(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("<^"), Spacing), "Pegged.KEEPARROW")(p); + return PEG.defined!(PEG.and!(PEG.literal!("<^"), Spacing), "Pegged.KEEPARROW")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("<^"), Spacing), "Pegged.KEEPARROW"), "KEEPARROW")(p); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("<^"), Spacing), "Pegged.KEEPARROW"), "KEEPARROW")(p); } } - static TParseTree KEEPARROW(string s) + static ParseTree KEEPARROW(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("<^"), Spacing), "Pegged.KEEPARROW")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(PEG.literal!("<^"), Spacing), "Pegged.KEEPARROW")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("<^"), Spacing), "Pegged.KEEPARROW"), "KEEPARROW")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("<^"), Spacing), "Pegged.KEEPARROW"), "KEEPARROW")(ParseTree("", false,[], s)); } } static string KEEPARROW(GetName g) @@ -989,25 +992,25 @@ struct GenericPegged(TParseTree) return "Pegged.KEEPARROW"; } - static TParseTree DROPARROW(TParseTree p) + static ParseTree DROPARROW(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("<;"), Spacing), "Pegged.DROPARROW")(p); + return PEG.defined!(PEG.and!(PEG.literal!("<;"), Spacing), "Pegged.DROPARROW")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("<;"), Spacing), "Pegged.DROPARROW"), "DROPARROW")(p); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("<;"), Spacing), "Pegged.DROPARROW"), "DROPARROW")(p); } } - static TParseTree DROPARROW(string s) + static ParseTree DROPARROW(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("<;"), Spacing), "Pegged.DROPARROW")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(PEG.literal!("<;"), Spacing), "Pegged.DROPARROW")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("<;"), Spacing), "Pegged.DROPARROW"), "DROPARROW")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("<;"), Spacing), "Pegged.DROPARROW"), "DROPARROW")(ParseTree("", false,[], s)); } } static string DROPARROW(GetName g) @@ -1015,25 +1018,25 @@ struct GenericPegged(TParseTree) return "Pegged.DROPARROW"; } - static TParseTree PROPAGATEARROW(TParseTree p) + static ParseTree PROPAGATEARROW(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("<%"), Spacing), "Pegged.PROPAGATEARROW")(p); + return PEG.defined!(PEG.and!(PEG.literal!("<%"), Spacing), "Pegged.PROPAGATEARROW")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("<%"), Spacing), "Pegged.PROPAGATEARROW"), "PROPAGATEARROW")(p); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("<%"), Spacing), "Pegged.PROPAGATEARROW"), "PROPAGATEARROW")(p); } } - static TParseTree PROPAGATEARROW(string s) + static ParseTree PROPAGATEARROW(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("<%"), Spacing), "Pegged.PROPAGATEARROW")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(PEG.literal!("<%"), Spacing), "Pegged.PROPAGATEARROW")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("<%"), Spacing), "Pegged.PROPAGATEARROW"), "PROPAGATEARROW")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("<%"), Spacing), "Pegged.PROPAGATEARROW"), "PROPAGATEARROW")(ParseTree("", false,[], s)); } } static string PROPAGATEARROW(GetName g) @@ -1041,25 +1044,25 @@ struct GenericPegged(TParseTree) return "Pegged.PROPAGATEARROW"; } - static TParseTree SPACEARROW(TParseTree p) + static ParseTree SPACEARROW(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("<"), Spacing), "Pegged.SPACEARROW")(p); + return PEG.defined!(PEG.and!(PEG.literal!("<"), Spacing), "Pegged.SPACEARROW")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("<"), Spacing), "Pegged.SPACEARROW"), "SPACEARROW")(p); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("<"), Spacing), "Pegged.SPACEARROW"), "SPACEARROW")(p); } } - static TParseTree SPACEARROW(string s) + static ParseTree SPACEARROW(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("<"), Spacing), "Pegged.SPACEARROW")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(PEG.literal!("<"), Spacing), "Pegged.SPACEARROW")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("<"), Spacing), "Pegged.SPACEARROW"), "SPACEARROW")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("<"), Spacing), "Pegged.SPACEARROW"), "SPACEARROW")(ParseTree("", false,[], s)); } } static string SPACEARROW(GetName g) @@ -1067,25 +1070,25 @@ struct GenericPegged(TParseTree) return "Pegged.SPACEARROW"; } - static TParseTree ACTIONARROW(TParseTree p) + static ParseTree ACTIONARROW(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("<"), Action, Spacing), "Pegged.ACTIONARROW")(p); + return PEG.defined!(PEG.and!(PEG.literal!("<"), Action, Spacing), "Pegged.ACTIONARROW")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("<"), Action, Spacing), "Pegged.ACTIONARROW"), "ACTIONARROW")(p); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("<"), Action, Spacing), "Pegged.ACTIONARROW"), "ACTIONARROW")(p); } } - static TParseTree ACTIONARROW(string s) + static ParseTree ACTIONARROW(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("<"), Action, Spacing), "Pegged.ACTIONARROW")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(PEG.literal!("<"), Action, Spacing), "Pegged.ACTIONARROW")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("<"), Action, Spacing), "Pegged.ACTIONARROW"), "ACTIONARROW")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("<"), Action, Spacing), "Pegged.ACTIONARROW"), "ACTIONARROW")(ParseTree("", false,[], s)); } } static string ACTIONARROW(GetName g) @@ -1093,25 +1096,25 @@ struct GenericPegged(TParseTree) return "Pegged.ACTIONARROW"; } - static TParseTree OR(TParseTree p) + static ParseTree OR(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("/"), Spacing), "Pegged.OR")(p); + return PEG.defined!(PEG.and!(PEG.literal!("/"), Spacing), "Pegged.OR")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("/"), Spacing), "Pegged.OR"), "OR")(p); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("/"), Spacing), "Pegged.OR"), "OR")(p); } } - static TParseTree OR(string s) + static ParseTree OR(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("/"), Spacing), "Pegged.OR")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(PEG.literal!("/"), Spacing), "Pegged.OR")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("/"), Spacing), "Pegged.OR"), "OR")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("/"), Spacing), "Pegged.OR"), "OR")(ParseTree("", false,[], s)); } } static string OR(GetName g) @@ -1119,25 +1122,25 @@ struct GenericPegged(TParseTree) return "Pegged.OR"; } - static TParseTree LONGEST_OR(TParseTree p) + static ParseTree LONGEST_OR(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("|"), Spacing), "Pegged.LONGEST_OR")(p); + return PEG.defined!(PEG.and!(PEG.literal!("|"), Spacing), "Pegged.LONGEST_OR")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("|"), Spacing), "Pegged.LONGEST_OR"), "LONGEST_OR")(p); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("|"), Spacing), "Pegged.LONGEST_OR"), "LONGEST_OR")(p); } } - static TParseTree LONGEST_OR(string s) + static ParseTree LONGEST_OR(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("|"), Spacing), "Pegged.LONGEST_OR")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(PEG.literal!("|"), Spacing), "Pegged.LONGEST_OR")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("|"), Spacing), "Pegged.LONGEST_OR"), "LONGEST_OR")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("|"), Spacing), "Pegged.LONGEST_OR"), "LONGEST_OR")(ParseTree("", false,[], s)); } } static string LONGEST_OR(GetName g) @@ -1145,25 +1148,25 @@ struct GenericPegged(TParseTree) return "Pegged.LONGEST_OR"; } - static TParseTree POS(TParseTree p) + static ParseTree POS(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("&"), Spacing), "Pegged.POS")(p); + return PEG.defined!(PEG.and!(PEG.literal!("&"), Spacing), "Pegged.POS")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("&"), Spacing), "Pegged.POS"), "POS")(p); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("&"), Spacing), "Pegged.POS"), "POS")(p); } } - static TParseTree POS(string s) + static ParseTree POS(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("&"), Spacing), "Pegged.POS")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(PEG.literal!("&"), Spacing), "Pegged.POS")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("&"), Spacing), "Pegged.POS"), "POS")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("&"), Spacing), "Pegged.POS"), "POS")(ParseTree("", false,[], s)); } } static string POS(GetName g) @@ -1171,25 +1174,25 @@ struct GenericPegged(TParseTree) return "Pegged.POS"; } - static TParseTree NEG(TParseTree p) + static ParseTree NEG(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("!"), Spacing), "Pegged.NEG")(p); + return PEG.defined!(PEG.and!(PEG.literal!("!"), Spacing), "Pegged.NEG")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("!"), Spacing), "Pegged.NEG"), "NEG")(p); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("!"), Spacing), "Pegged.NEG"), "NEG")(p); } } - static TParseTree NEG(string s) + static ParseTree NEG(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("!"), Spacing), "Pegged.NEG")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(PEG.literal!("!"), Spacing), "Pegged.NEG")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("!"), Spacing), "Pegged.NEG"), "NEG")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("!"), Spacing), "Pegged.NEG"), "NEG")(ParseTree("", false,[], s)); } } static string NEG(GetName g) @@ -1197,25 +1200,25 @@ struct GenericPegged(TParseTree) return "Pegged.NEG"; } - static TParseTree FUSE(TParseTree p) + static ParseTree FUSE(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("~"), Spacing), "Pegged.FUSE")(p); + return PEG.defined!(PEG.and!(PEG.literal!("~"), Spacing), "Pegged.FUSE")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("~"), Spacing), "Pegged.FUSE"), "FUSE")(p); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("~"), Spacing), "Pegged.FUSE"), "FUSE")(p); } } - static TParseTree FUSE(string s) + static ParseTree FUSE(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("~"), Spacing), "Pegged.FUSE")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(PEG.literal!("~"), Spacing), "Pegged.FUSE")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("~"), Spacing), "Pegged.FUSE"), "FUSE")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("~"), Spacing), "Pegged.FUSE"), "FUSE")(ParseTree("", false,[], s)); } } static string FUSE(GetName g) @@ -1223,25 +1226,25 @@ struct GenericPegged(TParseTree) return "Pegged.FUSE"; } - static TParseTree DISCARD(TParseTree p) + static ParseTree DISCARD(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!(":"), Spacing), "Pegged.DISCARD")(p); + return PEG.defined!(PEG.and!(PEG.literal!(":"), Spacing), "Pegged.DISCARD")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!(":"), Spacing), "Pegged.DISCARD"), "DISCARD")(p); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!(":"), Spacing), "Pegged.DISCARD"), "DISCARD")(p); } } - static TParseTree DISCARD(string s) + static ParseTree DISCARD(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!(":"), Spacing), "Pegged.DISCARD")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(PEG.literal!(":"), Spacing), "Pegged.DISCARD")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!(":"), Spacing), "Pegged.DISCARD"), "DISCARD")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!(":"), Spacing), "Pegged.DISCARD"), "DISCARD")(ParseTree("", false,[], s)); } } static string DISCARD(GetName g) @@ -1249,25 +1252,25 @@ struct GenericPegged(TParseTree) return "Pegged.DISCARD"; } - static TParseTree KEEP(TParseTree p) + static ParseTree KEEP(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("^"), Spacing), "Pegged.KEEP")(p); + return PEG.defined!(PEG.and!(PEG.literal!("^"), Spacing), "Pegged.KEEP")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("^"), Spacing), "Pegged.KEEP"), "KEEP")(p); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("^"), Spacing), "Pegged.KEEP"), "KEEP")(p); } } - static TParseTree KEEP(string s) + static ParseTree KEEP(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("^"), Spacing), "Pegged.KEEP")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(PEG.literal!("^"), Spacing), "Pegged.KEEP")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("^"), Spacing), "Pegged.KEEP"), "KEEP")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("^"), Spacing), "Pegged.KEEP"), "KEEP")(ParseTree("", false,[], s)); } } static string KEEP(GetName g) @@ -1275,25 +1278,25 @@ struct GenericPegged(TParseTree) return "Pegged.KEEP"; } - static TParseTree DROP(TParseTree p) + static ParseTree DROP(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!(";"), Spacing), "Pegged.DROP")(p); + return PEG.defined!(PEG.and!(PEG.literal!(";"), Spacing), "Pegged.DROP")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!(";"), Spacing), "Pegged.DROP"), "DROP")(p); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!(";"), Spacing), "Pegged.DROP"), "DROP")(p); } } - static TParseTree DROP(string s) + static ParseTree DROP(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!(";"), Spacing), "Pegged.DROP")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(PEG.literal!(";"), Spacing), "Pegged.DROP")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!(";"), Spacing), "Pegged.DROP"), "DROP")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!(";"), Spacing), "Pegged.DROP"), "DROP")(ParseTree("", false,[], s)); } } static string DROP(GetName g) @@ -1301,25 +1304,25 @@ struct GenericPegged(TParseTree) return "Pegged.DROP"; } - static TParseTree PROPAGATE(TParseTree p) + static ParseTree PROPAGATE(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("%"), Spacing), "Pegged.PROPAGATE")(p); + return PEG.defined!(PEG.and!(PEG.literal!("%"), Spacing), "Pegged.PROPAGATE")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("%"), Spacing), "Pegged.PROPAGATE"), "PROPAGATE")(p); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("%"), Spacing), "Pegged.PROPAGATE"), "PROPAGATE")(p); } } - static TParseTree PROPAGATE(string s) + static ParseTree PROPAGATE(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("%"), Spacing), "Pegged.PROPAGATE")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(PEG.literal!("%"), Spacing), "Pegged.PROPAGATE")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("%"), Spacing), "Pegged.PROPAGATE"), "PROPAGATE")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("%"), Spacing), "Pegged.PROPAGATE"), "PROPAGATE")(ParseTree("", false,[], s)); } } static string PROPAGATE(GetName g) @@ -1327,25 +1330,25 @@ struct GenericPegged(TParseTree) return "Pegged.PROPAGATE"; } - static TParseTree OPTION(TParseTree p) + static ParseTree OPTION(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("?"), Spacing), "Pegged.OPTION")(p); + return PEG.defined!(PEG.and!(PEG.literal!("?"), Spacing), "Pegged.OPTION")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("?"), Spacing), "Pegged.OPTION"), "OPTION")(p); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("?"), Spacing), "Pegged.OPTION"), "OPTION")(p); } } - static TParseTree OPTION(string s) + static ParseTree OPTION(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("?"), Spacing), "Pegged.OPTION")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(PEG.literal!("?"), Spacing), "Pegged.OPTION")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("?"), Spacing), "Pegged.OPTION"), "OPTION")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("?"), Spacing), "Pegged.OPTION"), "OPTION")(ParseTree("", false,[], s)); } } static string OPTION(GetName g) @@ -1353,25 +1356,25 @@ struct GenericPegged(TParseTree) return "Pegged.OPTION"; } - static TParseTree ZEROORMORE(TParseTree p) + static ParseTree ZEROORMORE(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("*"), Spacing), "Pegged.ZEROORMORE")(p); + return PEG.defined!(PEG.and!(PEG.literal!("*"), Spacing), "Pegged.ZEROORMORE")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("*"), Spacing), "Pegged.ZEROORMORE"), "ZEROORMORE")(p); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("*"), Spacing), "Pegged.ZEROORMORE"), "ZEROORMORE")(p); } } - static TParseTree ZEROORMORE(string s) + static ParseTree ZEROORMORE(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("*"), Spacing), "Pegged.ZEROORMORE")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(PEG.literal!("*"), Spacing), "Pegged.ZEROORMORE")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("*"), Spacing), "Pegged.ZEROORMORE"), "ZEROORMORE")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("*"), Spacing), "Pegged.ZEROORMORE"), "ZEROORMORE")(ParseTree("", false,[], s)); } } static string ZEROORMORE(GetName g) @@ -1379,25 +1382,25 @@ struct GenericPegged(TParseTree) return "Pegged.ZEROORMORE"; } - static TParseTree ONEORMORE(TParseTree p) + static ParseTree ONEORMORE(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("+"), Spacing), "Pegged.ONEORMORE")(p); + return PEG.defined!(PEG.and!(PEG.literal!("+"), Spacing), "Pegged.ONEORMORE")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("+"), Spacing), "Pegged.ONEORMORE"), "ONEORMORE")(p); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("+"), Spacing), "Pegged.ONEORMORE"), "ONEORMORE")(p); } } - static TParseTree ONEORMORE(string s) + static ParseTree ONEORMORE(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("+"), Spacing), "Pegged.ONEORMORE")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(PEG.literal!("+"), Spacing), "Pegged.ONEORMORE")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("+"), Spacing), "Pegged.ONEORMORE"), "ONEORMORE")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("+"), Spacing), "Pegged.ONEORMORE"), "ONEORMORE")(ParseTree("", false,[], s)); } } static string ONEORMORE(GetName g) @@ -1405,25 +1408,25 @@ struct GenericPegged(TParseTree) return "Pegged.ONEORMORE"; } - static TParseTree ACTIONOPEN(TParseTree p) + static ParseTree ACTIONOPEN(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("{"), Spacing), "Pegged.ACTIONOPEN")(p); + return PEG.defined!(PEG.and!(PEG.literal!("{"), Spacing), "Pegged.ACTIONOPEN")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("{"), Spacing), "Pegged.ACTIONOPEN"), "ACTIONOPEN")(p); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("{"), Spacing), "Pegged.ACTIONOPEN"), "ACTIONOPEN")(p); } } - static TParseTree ACTIONOPEN(string s) + static ParseTree ACTIONOPEN(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("{"), Spacing), "Pegged.ACTIONOPEN")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(PEG.literal!("{"), Spacing), "Pegged.ACTIONOPEN")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("{"), Spacing), "Pegged.ACTIONOPEN"), "ACTIONOPEN")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("{"), Spacing), "Pegged.ACTIONOPEN"), "ACTIONOPEN")(ParseTree("", false,[], s)); } } static string ACTIONOPEN(GetName g) @@ -1431,25 +1434,25 @@ struct GenericPegged(TParseTree) return "Pegged.ACTIONOPEN"; } - static TParseTree ACTIONCLOSE(TParseTree p) + static ParseTree ACTIONCLOSE(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("}"), Spacing), "Pegged.ACTIONCLOSE")(p); + return PEG.defined!(PEG.and!(PEG.literal!("}"), Spacing), "Pegged.ACTIONCLOSE")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("}"), Spacing), "Pegged.ACTIONCLOSE"), "ACTIONCLOSE")(p); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("}"), Spacing), "Pegged.ACTIONCLOSE"), "ACTIONCLOSE")(p); } } - static TParseTree ACTIONCLOSE(string s) + static ParseTree ACTIONCLOSE(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("}"), Spacing), "Pegged.ACTIONCLOSE")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(PEG.literal!("}"), Spacing), "Pegged.ACTIONCLOSE")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("}"), Spacing), "Pegged.ACTIONCLOSE"), "ACTIONCLOSE")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("}"), Spacing), "Pegged.ACTIONCLOSE"), "ACTIONCLOSE")(ParseTree("", false,[], s)); } } static string ACTIONCLOSE(GetName g) @@ -1457,25 +1460,25 @@ struct GenericPegged(TParseTree) return "Pegged.ACTIONCLOSE"; } - static TParseTree SEPARATOR(TParseTree p) + static ParseTree SEPARATOR(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!(","), Spacing), "Pegged.SEPARATOR")(p); + return PEG.defined!(PEG.and!(PEG.literal!(","), Spacing), "Pegged.SEPARATOR")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!(","), Spacing), "Pegged.SEPARATOR"), "SEPARATOR")(p); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!(","), Spacing), "Pegged.SEPARATOR"), "SEPARATOR")(p); } } - static TParseTree SEPARATOR(string s) + static ParseTree SEPARATOR(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!(","), Spacing), "Pegged.SEPARATOR")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(PEG.literal!(","), Spacing), "Pegged.SEPARATOR")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!(","), Spacing), "Pegged.SEPARATOR"), "SEPARATOR")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!(","), Spacing), "Pegged.SEPARATOR"), "SEPARATOR")(ParseTree("", false,[], s)); } } static string SEPARATOR(GetName g) @@ -1483,25 +1486,25 @@ struct GenericPegged(TParseTree) return "Pegged.SEPARATOR"; } - static TParseTree ASSIGN(TParseTree p) + static ParseTree ASSIGN(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("="), Spacing), "Pegged.ASSIGN")(p); + return PEG.defined!(PEG.and!(PEG.literal!("="), Spacing), "Pegged.ASSIGN")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("="), Spacing), "Pegged.ASSIGN"), "ASSIGN")(p); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("="), Spacing), "Pegged.ASSIGN"), "ASSIGN")(p); } } - static TParseTree ASSIGN(string s) + static ParseTree ASSIGN(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("="), Spacing), "Pegged.ASSIGN")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(PEG.literal!("="), Spacing), "Pegged.ASSIGN")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("="), Spacing), "Pegged.ASSIGN"), "ASSIGN")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("="), Spacing), "Pegged.ASSIGN"), "ASSIGN")(ParseTree("", false,[], s)); } } static string ASSIGN(GetName g) @@ -1509,25 +1512,25 @@ struct GenericPegged(TParseTree) return "Pegged.ASSIGN"; } - static TParseTree NAMESEP(TParseTree p) + static ParseTree NAMESEP(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.literal!("."), "Pegged.NAMESEP")(p); + return PEG.defined!(PEG.literal!("."), "Pegged.NAMESEP")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.literal!("."), "Pegged.NAMESEP"), "NAMESEP")(p); + return hooked!(PEG.defined!(PEG.literal!("."), "Pegged.NAMESEP"), "NAMESEP")(p); } } - static TParseTree NAMESEP(string s) + static ParseTree NAMESEP(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.literal!("."), "Pegged.NAMESEP")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.literal!("."), "Pegged.NAMESEP")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.literal!("."), "Pegged.NAMESEP"), "NAMESEP")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.literal!("."), "Pegged.NAMESEP"), "NAMESEP")(ParseTree("", false,[], s)); } } static string NAMESEP(GetName g) @@ -1535,25 +1538,25 @@ struct GenericPegged(TParseTree) return "Pegged.NAMESEP"; } - static TParseTree OPEN(TParseTree p) + static ParseTree OPEN(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("("), Spacing), "Pegged.OPEN")(p); + return PEG.defined!(PEG.and!(PEG.literal!("("), Spacing), "Pegged.OPEN")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("("), Spacing), "Pegged.OPEN"), "OPEN")(p); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("("), Spacing), "Pegged.OPEN"), "OPEN")(p); } } - static TParseTree OPEN(string s) + static ParseTree OPEN(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("("), Spacing), "Pegged.OPEN")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(PEG.literal!("("), Spacing), "Pegged.OPEN")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("("), Spacing), "Pegged.OPEN"), "OPEN")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("("), Spacing), "Pegged.OPEN"), "OPEN")(ParseTree("", false,[], s)); } } static string OPEN(GetName g) @@ -1561,25 +1564,25 @@ struct GenericPegged(TParseTree) return "Pegged.OPEN"; } - static TParseTree CLOSE(TParseTree p) + static ParseTree CLOSE(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!(")"), Spacing), "Pegged.CLOSE")(p); + return PEG.defined!(PEG.and!(PEG.literal!(")"), Spacing), "Pegged.CLOSE")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!(")"), Spacing), "Pegged.CLOSE"), "CLOSE")(p); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!(")"), Spacing), "Pegged.CLOSE"), "CLOSE")(p); } } - static TParseTree CLOSE(string s) + static ParseTree CLOSE(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!(")"), Spacing), "Pegged.CLOSE")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(PEG.literal!(")"), Spacing), "Pegged.CLOSE")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!(")"), Spacing), "Pegged.CLOSE"), "CLOSE")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!(")"), Spacing), "Pegged.CLOSE"), "CLOSE")(ParseTree("", false,[], s)); } } static string CLOSE(GetName g) @@ -1587,25 +1590,25 @@ struct GenericPegged(TParseTree) return "Pegged.CLOSE"; } - static TParseTree ANY(TParseTree p) + static ParseTree ANY(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("."), Spacing), "Pegged.ANY")(p); + return PEG.defined!(PEG.and!(PEG.literal!("."), Spacing), "Pegged.ANY")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("."), Spacing), "Pegged.ANY"), "ANY")(p); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("."), Spacing), "Pegged.ANY"), "ANY")(p); } } - static TParseTree ANY(string s) + static ParseTree ANY(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("."), Spacing), "Pegged.ANY")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(PEG.literal!("."), Spacing), "Pegged.ANY")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("."), Spacing), "Pegged.ANY"), "ANY")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("."), Spacing), "Pegged.ANY"), "ANY")(ParseTree("", false,[], s)); } } static string ANY(GetName g) @@ -1613,25 +1616,25 @@ struct GenericPegged(TParseTree) return "Pegged.ANY"; } - static TParseTree Spacing(TParseTree p) + static ParseTree Spacing(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.discard!(pegged.peg.zeroOrMore!(pegged.peg.or!(blank, Comment))), "Pegged.Spacing")(p); + return PEG.defined!(PEG.discard!(PEG.zeroOrMore!(PEG.or!(blank, Comment))), "Pegged.Spacing")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.discard!(pegged.peg.zeroOrMore!(pegged.peg.or!(blank, Comment))), "Pegged.Spacing"), "Spacing")(p); + return hooked!(PEG.defined!(PEG.discard!(PEG.zeroOrMore!(PEG.or!(blank, Comment))), "Pegged.Spacing"), "Spacing")(p); } } - static TParseTree Spacing(string s) + static ParseTree Spacing(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.discard!(pegged.peg.zeroOrMore!(pegged.peg.or!(blank, Comment))), "Pegged.Spacing")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.discard!(PEG.zeroOrMore!(PEG.or!(blank, Comment))), "Pegged.Spacing")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.discard!(pegged.peg.zeroOrMore!(pegged.peg.or!(blank, Comment))), "Pegged.Spacing"), "Spacing")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.discard!(PEG.zeroOrMore!(PEG.or!(blank, Comment))), "Pegged.Spacing"), "Spacing")(ParseTree("", false,[], s)); } } static string Spacing(GetName g) @@ -1639,25 +1642,25 @@ struct GenericPegged(TParseTree) return "Pegged.Spacing"; } - static TParseTree Comment(TParseTree p) + static ParseTree Comment(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("#"), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(eol), pegged.peg.any)), pegged.peg.discard!(eol)), "Pegged.Comment")(p); + return PEG.defined!(PEG.and!(PEG.literal!("#"), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(eol), PEG.any)), PEG.discard!(eol)), "Pegged.Comment")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("#"), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(eol), pegged.peg.any)), pegged.peg.discard!(eol)), "Pegged.Comment"), "Comment")(p); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("#"), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(eol), PEG.any)), PEG.discard!(eol)), "Pegged.Comment"), "Comment")(p); } } - static TParseTree Comment(string s) + static ParseTree Comment(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("#"), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(eol), pegged.peg.any)), pegged.peg.discard!(eol)), "Pegged.Comment")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(PEG.literal!("#"), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(eol), PEG.any)), PEG.discard!(eol)), "Pegged.Comment")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("#"), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(eol), pegged.peg.any)), pegged.peg.discard!(eol)), "Pegged.Comment"), "Comment")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("#"), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(eol), PEG.any)), PEG.discard!(eol)), "Pegged.Comment"), "Comment")(ParseTree("", false,[], s)); } } static string Comment(GetName g) @@ -1665,25 +1668,25 @@ struct GenericPegged(TParseTree) return "Pegged.Comment"; } - static TParseTree Space(TParseTree p) + static ParseTree Space(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.or!(spacing, pegged.peg.literal!("\\t"), pegged.peg.literal!("\\n"), pegged.peg.literal!("\\r")), "Pegged.Space")(p); + return PEG.defined!(PEG.or!(spacing, PEG.literal!("\\t"), PEG.literal!("\\n"), PEG.literal!("\\r")), "Pegged.Space")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.or!(spacing, pegged.peg.literal!("\\t"), pegged.peg.literal!("\\n"), pegged.peg.literal!("\\r")), "Pegged.Space"), "Space")(p); + return hooked!(PEG.defined!(PEG.or!(spacing, PEG.literal!("\\t"), PEG.literal!("\\n"), PEG.literal!("\\r")), "Pegged.Space"), "Space")(p); } } - static TParseTree Space(string s) + static ParseTree Space(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.or!(spacing, pegged.peg.literal!("\\t"), pegged.peg.literal!("\\n"), pegged.peg.literal!("\\r")), "Pegged.Space")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.or!(spacing, PEG.literal!("\\t"), PEG.literal!("\\n"), PEG.literal!("\\r")), "Pegged.Space")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.or!(spacing, pegged.peg.literal!("\\t"), pegged.peg.literal!("\\n"), pegged.peg.literal!("\\r")), "Pegged.Space"), "Space")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.or!(spacing, PEG.literal!("\\t"), PEG.literal!("\\n"), PEG.literal!("\\r")), "Pegged.Space"), "Space")(ParseTree("", false,[], s)); } } static string Space(GetName g) @@ -1691,25 +1694,25 @@ struct GenericPegged(TParseTree) return "Pegged.Space"; } - static TParseTree Action(TParseTree p) + static ParseTree Action(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.discard!(ACTIONOPEN), Spacing, pegged.peg.and!(pegged.peg.or!(Lambda, qualifiedIdentifier), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.discard!(SEPARATOR), pegged.peg.or!(Lambda, qualifiedIdentifier)))), Spacing, pegged.peg.discard!(ACTIONCLOSE)), "Pegged.Action")(p); + return PEG.defined!(PEG.and!(PEG.discard!(ACTIONOPEN), Spacing, PEG.and!(PEG.or!(Lambda, qualifiedIdentifier), PEG.zeroOrMore!(PEG.and!(PEG.discard!(SEPARATOR), PEG.or!(Lambda, qualifiedIdentifier)))), Spacing, PEG.discard!(ACTIONCLOSE)), "Pegged.Action")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.discard!(ACTIONOPEN), Spacing, pegged.peg.and!(pegged.peg.or!(Lambda, qualifiedIdentifier), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.discard!(SEPARATOR), pegged.peg.or!(Lambda, qualifiedIdentifier)))), Spacing, pegged.peg.discard!(ACTIONCLOSE)), "Pegged.Action"), "Action")(p); + return hooked!(PEG.defined!(PEG.and!(PEG.discard!(ACTIONOPEN), Spacing, PEG.and!(PEG.or!(Lambda, qualifiedIdentifier), PEG.zeroOrMore!(PEG.and!(PEG.discard!(SEPARATOR), PEG.or!(Lambda, qualifiedIdentifier)))), Spacing, PEG.discard!(ACTIONCLOSE)), "Pegged.Action"), "Action")(p); } } - static TParseTree Action(string s) + static ParseTree Action(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.discard!(ACTIONOPEN), Spacing, pegged.peg.and!(pegged.peg.or!(Lambda, qualifiedIdentifier), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.discard!(SEPARATOR), pegged.peg.or!(Lambda, qualifiedIdentifier)))), Spacing, pegged.peg.discard!(ACTIONCLOSE)), "Pegged.Action")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(PEG.discard!(ACTIONOPEN), Spacing, PEG.and!(PEG.or!(Lambda, qualifiedIdentifier), PEG.zeroOrMore!(PEG.and!(PEG.discard!(SEPARATOR), PEG.or!(Lambda, qualifiedIdentifier)))), Spacing, PEG.discard!(ACTIONCLOSE)), "Pegged.Action")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.discard!(ACTIONOPEN), Spacing, pegged.peg.and!(pegged.peg.or!(Lambda, qualifiedIdentifier), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.discard!(SEPARATOR), pegged.peg.or!(Lambda, qualifiedIdentifier)))), Spacing, pegged.peg.discard!(ACTIONCLOSE)), "Pegged.Action"), "Action")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(PEG.discard!(ACTIONOPEN), Spacing, PEG.and!(PEG.or!(Lambda, qualifiedIdentifier), PEG.zeroOrMore!(PEG.and!(PEG.discard!(SEPARATOR), PEG.or!(Lambda, qualifiedIdentifier)))), Spacing, PEG.discard!(ACTIONCLOSE)), "Pegged.Action"), "Action")(ParseTree("", false,[], s)); } } static string Action(GetName g) @@ -1717,25 +1720,25 @@ struct GenericPegged(TParseTree) return "Pegged.Action"; } - static TParseTree Lambda(TParseTree p) + static ParseTree Lambda(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.fuse!(pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(pegged.peg.or!(ACTIONCLOSE, SEPARATOR)), pegged.peg.or!(LambdaItems, NestedList!(pegged.peg.literal!("{"), LambdaItems, pegged.peg.literal!("}")), pegged.peg.any)))), "Pegged.Lambda")(p); + return PEG.defined!(PEG.fuse!(PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(ACTIONCLOSE, SEPARATOR)), PEG.or!(LambdaItems, NestedList!(PEG.literal!("{"), LambdaItems, PEG.literal!("}")), PEG.any)))), "Pegged.Lambda")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.fuse!(pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(pegged.peg.or!(ACTIONCLOSE, SEPARATOR)), pegged.peg.or!(LambdaItems, NestedList!(pegged.peg.literal!("{"), LambdaItems, pegged.peg.literal!("}")), pegged.peg.any)))), "Pegged.Lambda"), "Lambda")(p); + return hooked!(PEG.defined!(PEG.fuse!(PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(ACTIONCLOSE, SEPARATOR)), PEG.or!(LambdaItems, NestedList!(PEG.literal!("{"), LambdaItems, PEG.literal!("}")), PEG.any)))), "Pegged.Lambda"), "Lambda")(p); } } - static TParseTree Lambda(string s) + static ParseTree Lambda(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.fuse!(pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(pegged.peg.or!(ACTIONCLOSE, SEPARATOR)), pegged.peg.or!(LambdaItems, NestedList!(pegged.peg.literal!("{"), LambdaItems, pegged.peg.literal!("}")), pegged.peg.any)))), "Pegged.Lambda")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.fuse!(PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(ACTIONCLOSE, SEPARATOR)), PEG.or!(LambdaItems, NestedList!(PEG.literal!("{"), LambdaItems, PEG.literal!("}")), PEG.any)))), "Pegged.Lambda")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.fuse!(pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(pegged.peg.or!(ACTIONCLOSE, SEPARATOR)), pegged.peg.or!(LambdaItems, NestedList!(pegged.peg.literal!("{"), LambdaItems, pegged.peg.literal!("}")), pegged.peg.any)))), "Pegged.Lambda"), "Lambda")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.fuse!(PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(ACTIONCLOSE, SEPARATOR)), PEG.or!(LambdaItems, NestedList!(PEG.literal!("{"), LambdaItems, PEG.literal!("}")), PEG.any)))), "Pegged.Lambda"), "Lambda")(ParseTree("", false,[], s)); } } static string Lambda(GetName g) @@ -1743,25 +1746,25 @@ struct GenericPegged(TParseTree) return "Pegged.Lambda"; } - static TParseTree LambdaItems(TParseTree p) + static ParseTree LambdaItems(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.or!(pegged.peg.fuse!(DComment), pegged.peg.fuse!(DString), pegged.peg.fuse!(DParamList)), "Pegged.LambdaItems")(p); + return PEG.defined!(PEG.or!(PEG.fuse!(DComment), PEG.fuse!(DString), PEG.fuse!(DParamList)), "Pegged.LambdaItems")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.or!(pegged.peg.fuse!(DComment), pegged.peg.fuse!(DString), pegged.peg.fuse!(DParamList)), "Pegged.LambdaItems"), "LambdaItems")(p); + return hooked!(PEG.defined!(PEG.or!(PEG.fuse!(DComment), PEG.fuse!(DString), PEG.fuse!(DParamList)), "Pegged.LambdaItems"), "LambdaItems")(p); } } - static TParseTree LambdaItems(string s) + static ParseTree LambdaItems(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.or!(pegged.peg.fuse!(DComment), pegged.peg.fuse!(DString), pegged.peg.fuse!(DParamList)), "Pegged.LambdaItems")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.or!(PEG.fuse!(DComment), PEG.fuse!(DString), PEG.fuse!(DParamList)), "Pegged.LambdaItems")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.or!(pegged.peg.fuse!(DComment), pegged.peg.fuse!(DString), pegged.peg.fuse!(DParamList)), "Pegged.LambdaItems"), "LambdaItems")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.or!(PEG.fuse!(DComment), PEG.fuse!(DString), PEG.fuse!(DParamList)), "Pegged.LambdaItems"), "LambdaItems")(ParseTree("", false,[], s)); } } static string LambdaItems(GetName g) @@ -1769,25 +1772,25 @@ struct GenericPegged(TParseTree) return "Pegged.LambdaItems"; } - static TParseTree DString(TParseTree p) + static ParseTree DString(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.or!(WYSString, DBQString, TKNString, DLMString), "Pegged.DString")(p); + return PEG.defined!(PEG.or!(WYSString, DBQString, TKNString, DLMString), "Pegged.DString")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.or!(WYSString, DBQString, TKNString, DLMString), "Pegged.DString"), "DString")(p); + return hooked!(PEG.defined!(PEG.or!(WYSString, DBQString, TKNString, DLMString), "Pegged.DString"), "DString")(p); } } - static TParseTree DString(string s) + static ParseTree DString(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.or!(WYSString, DBQString, TKNString, DLMString), "Pegged.DString")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.or!(WYSString, DBQString, TKNString, DLMString), "Pegged.DString")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.or!(WYSString, DBQString, TKNString, DLMString), "Pegged.DString"), "DString")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.or!(WYSString, DBQString, TKNString, DLMString), "Pegged.DString"), "DString")(ParseTree("", false,[], s)); } } static string DString(GetName g) @@ -1795,25 +1798,25 @@ struct GenericPegged(TParseTree) return "Pegged.DString"; } - static TParseTree WYSString(TParseTree p) + static ParseTree WYSString(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.or!(pegged.peg.and!(pegged.peg.literal!("r"), doublequote, pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(doublequote), pegged.peg.any)), doublequote), pegged.peg.and!(backquote, pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(backquote), pegged.peg.any)), backquote)), "Pegged.WYSString")(p); + return PEG.defined!(PEG.or!(PEG.and!(PEG.literal!("r"), doublequote, PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(doublequote), PEG.any)), doublequote), PEG.and!(backquote, PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(backquote), PEG.any)), backquote)), "Pegged.WYSString")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.or!(pegged.peg.and!(pegged.peg.literal!("r"), doublequote, pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(doublequote), pegged.peg.any)), doublequote), pegged.peg.and!(backquote, pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(backquote), pegged.peg.any)), backquote)), "Pegged.WYSString"), "WYSString")(p); + return hooked!(PEG.defined!(PEG.or!(PEG.and!(PEG.literal!("r"), doublequote, PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(doublequote), PEG.any)), doublequote), PEG.and!(backquote, PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(backquote), PEG.any)), backquote)), "Pegged.WYSString"), "WYSString")(p); } } - static TParseTree WYSString(string s) + static ParseTree WYSString(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.or!(pegged.peg.and!(pegged.peg.literal!("r"), doublequote, pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(doublequote), pegged.peg.any)), doublequote), pegged.peg.and!(backquote, pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(backquote), pegged.peg.any)), backquote)), "Pegged.WYSString")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.or!(PEG.and!(PEG.literal!("r"), doublequote, PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(doublequote), PEG.any)), doublequote), PEG.and!(backquote, PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(backquote), PEG.any)), backquote)), "Pegged.WYSString")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.or!(pegged.peg.and!(pegged.peg.literal!("r"), doublequote, pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(doublequote), pegged.peg.any)), doublequote), pegged.peg.and!(backquote, pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(backquote), pegged.peg.any)), backquote)), "Pegged.WYSString"), "WYSString")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.or!(PEG.and!(PEG.literal!("r"), doublequote, PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(doublequote), PEG.any)), doublequote), PEG.and!(backquote, PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(backquote), PEG.any)), backquote)), "Pegged.WYSString"), "WYSString")(ParseTree("", false,[], s)); } } static string WYSString(GetName g) @@ -1821,25 +1824,25 @@ struct GenericPegged(TParseTree) return "Pegged.WYSString"; } - static TParseTree DBQString(TParseTree p) + static ParseTree DBQString(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(doublequote, pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(doublequote), Char)), doublequote), "Pegged.DBQString")(p); + return PEG.defined!(PEG.and!(doublequote, PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(doublequote), Char)), doublequote), "Pegged.DBQString")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(doublequote, pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(doublequote), Char)), doublequote), "Pegged.DBQString"), "DBQString")(p); + return hooked!(PEG.defined!(PEG.and!(doublequote, PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(doublequote), Char)), doublequote), "Pegged.DBQString"), "DBQString")(p); } } - static TParseTree DBQString(string s) + static ParseTree DBQString(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(doublequote, pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(doublequote), Char)), doublequote), "Pegged.DBQString")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(doublequote, PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(doublequote), Char)), doublequote), "Pegged.DBQString")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(doublequote, pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(doublequote), Char)), doublequote), "Pegged.DBQString"), "DBQString")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(doublequote, PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(doublequote), Char)), doublequote), "Pegged.DBQString"), "DBQString")(ParseTree("", false,[], s)); } } static string DBQString(GetName g) @@ -1847,25 +1850,25 @@ struct GenericPegged(TParseTree) return "Pegged.DBQString"; } - static TParseTree TKNString(TParseTree p) + static ParseTree TKNString(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.posLookahead!(pegged.peg.literal!("q{")), pegged.peg.and!(pegged.peg.literal!("q"), NestedList!(pegged.peg.literal!("{"), DString, pegged.peg.literal!("}")))), "Pegged.TKNString")(p); + return PEG.defined!(PEG.and!(PEG.posLookahead!(PEG.literal!("q{")), PEG.and!(PEG.literal!("q"), NestedList!(PEG.literal!("{"), DString, PEG.literal!("}")))), "Pegged.TKNString")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.posLookahead!(pegged.peg.literal!("q{")), pegged.peg.and!(pegged.peg.literal!("q"), NestedList!(pegged.peg.literal!("{"), DString, pegged.peg.literal!("}")))), "Pegged.TKNString"), "TKNString")(p); + return hooked!(PEG.defined!(PEG.and!(PEG.posLookahead!(PEG.literal!("q{")), PEG.and!(PEG.literal!("q"), NestedList!(PEG.literal!("{"), DString, PEG.literal!("}")))), "Pegged.TKNString"), "TKNString")(p); } } - static TParseTree TKNString(string s) + static ParseTree TKNString(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.posLookahead!(pegged.peg.literal!("q{")), pegged.peg.and!(pegged.peg.literal!("q"), NestedList!(pegged.peg.literal!("{"), DString, pegged.peg.literal!("}")))), "Pegged.TKNString")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(PEG.posLookahead!(PEG.literal!("q{")), PEG.and!(PEG.literal!("q"), NestedList!(PEG.literal!("{"), DString, PEG.literal!("}")))), "Pegged.TKNString")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.posLookahead!(pegged.peg.literal!("q{")), pegged.peg.and!(pegged.peg.literal!("q"), NestedList!(pegged.peg.literal!("{"), DString, pegged.peg.literal!("}")))), "Pegged.TKNString"), "TKNString")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(PEG.posLookahead!(PEG.literal!("q{")), PEG.and!(PEG.literal!("q"), NestedList!(PEG.literal!("{"), DString, PEG.literal!("}")))), "Pegged.TKNString"), "TKNString")(ParseTree("", false,[], s)); } } static string TKNString(GetName g) @@ -1873,25 +1876,25 @@ struct GenericPegged(TParseTree) return "Pegged.TKNString"; } - static TParseTree DLMString(TParseTree p) + static ParseTree DLMString(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.and!(pegged.peg.literal!("q"), doublequote), pegged.peg.or!(pegged.peg.and!(pegged.peg.posLookahead!(pegged.peg.literal!("{")), NestedList!(pegged.peg.literal!("{"), DString, pegged.peg.literal!("}"))), pegged.peg.and!(pegged.peg.posLookahead!(pegged.peg.literal!("[")), NestedList!(pegged.peg.literal!("["), DString, pegged.peg.literal!("]"))), pegged.peg.and!(pegged.peg.posLookahead!(pegged.peg.literal!("(")), NestedList!(pegged.peg.literal!("("), DString, pegged.peg.literal!(")"))), pegged.peg.and!(pegged.peg.posLookahead!(pegged.peg.literal!("<")), NestedList!(pegged.peg.literal!("<"), DString, pegged.peg.literal!(">")))), doublequote), "Pegged.DLMString")(p); + return PEG.defined!(PEG.and!(PEG.and!(PEG.literal!("q"), doublequote), PEG.or!(PEG.and!(PEG.posLookahead!(PEG.literal!("{")), NestedList!(PEG.literal!("{"), DString, PEG.literal!("}"))), PEG.and!(PEG.posLookahead!(PEG.literal!("[")), NestedList!(PEG.literal!("["), DString, PEG.literal!("]"))), PEG.and!(PEG.posLookahead!(PEG.literal!("(")), NestedList!(PEG.literal!("("), DString, PEG.literal!(")"))), PEG.and!(PEG.posLookahead!(PEG.literal!("<")), NestedList!(PEG.literal!("<"), DString, PEG.literal!(">")))), doublequote), "Pegged.DLMString")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.and!(pegged.peg.literal!("q"), doublequote), pegged.peg.or!(pegged.peg.and!(pegged.peg.posLookahead!(pegged.peg.literal!("{")), NestedList!(pegged.peg.literal!("{"), DString, pegged.peg.literal!("}"))), pegged.peg.and!(pegged.peg.posLookahead!(pegged.peg.literal!("[")), NestedList!(pegged.peg.literal!("["), DString, pegged.peg.literal!("]"))), pegged.peg.and!(pegged.peg.posLookahead!(pegged.peg.literal!("(")), NestedList!(pegged.peg.literal!("("), DString, pegged.peg.literal!(")"))), pegged.peg.and!(pegged.peg.posLookahead!(pegged.peg.literal!("<")), NestedList!(pegged.peg.literal!("<"), DString, pegged.peg.literal!(">")))), doublequote), "Pegged.DLMString"), "DLMString")(p); + return hooked!(PEG.defined!(PEG.and!(PEG.and!(PEG.literal!("q"), doublequote), PEG.or!(PEG.and!(PEG.posLookahead!(PEG.literal!("{")), NestedList!(PEG.literal!("{"), DString, PEG.literal!("}"))), PEG.and!(PEG.posLookahead!(PEG.literal!("[")), NestedList!(PEG.literal!("["), DString, PEG.literal!("]"))), PEG.and!(PEG.posLookahead!(PEG.literal!("(")), NestedList!(PEG.literal!("("), DString, PEG.literal!(")"))), PEG.and!(PEG.posLookahead!(PEG.literal!("<")), NestedList!(PEG.literal!("<"), DString, PEG.literal!(">")))), doublequote), "Pegged.DLMString"), "DLMString")(p); } } - static TParseTree DLMString(string s) + static ParseTree DLMString(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.and!(pegged.peg.literal!("q"), doublequote), pegged.peg.or!(pegged.peg.and!(pegged.peg.posLookahead!(pegged.peg.literal!("{")), NestedList!(pegged.peg.literal!("{"), DString, pegged.peg.literal!("}"))), pegged.peg.and!(pegged.peg.posLookahead!(pegged.peg.literal!("[")), NestedList!(pegged.peg.literal!("["), DString, pegged.peg.literal!("]"))), pegged.peg.and!(pegged.peg.posLookahead!(pegged.peg.literal!("(")), NestedList!(pegged.peg.literal!("("), DString, pegged.peg.literal!(")"))), pegged.peg.and!(pegged.peg.posLookahead!(pegged.peg.literal!("<")), NestedList!(pegged.peg.literal!("<"), DString, pegged.peg.literal!(">")))), doublequote), "Pegged.DLMString")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(PEG.and!(PEG.literal!("q"), doublequote), PEG.or!(PEG.and!(PEG.posLookahead!(PEG.literal!("{")), NestedList!(PEG.literal!("{"), DString, PEG.literal!("}"))), PEG.and!(PEG.posLookahead!(PEG.literal!("[")), NestedList!(PEG.literal!("["), DString, PEG.literal!("]"))), PEG.and!(PEG.posLookahead!(PEG.literal!("(")), NestedList!(PEG.literal!("("), DString, PEG.literal!(")"))), PEG.and!(PEG.posLookahead!(PEG.literal!("<")), NestedList!(PEG.literal!("<"), DString, PEG.literal!(">")))), doublequote), "Pegged.DLMString")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.and!(pegged.peg.literal!("q"), doublequote), pegged.peg.or!(pegged.peg.and!(pegged.peg.posLookahead!(pegged.peg.literal!("{")), NestedList!(pegged.peg.literal!("{"), DString, pegged.peg.literal!("}"))), pegged.peg.and!(pegged.peg.posLookahead!(pegged.peg.literal!("[")), NestedList!(pegged.peg.literal!("["), DString, pegged.peg.literal!("]"))), pegged.peg.and!(pegged.peg.posLookahead!(pegged.peg.literal!("(")), NestedList!(pegged.peg.literal!("("), DString, pegged.peg.literal!(")"))), pegged.peg.and!(pegged.peg.posLookahead!(pegged.peg.literal!("<")), NestedList!(pegged.peg.literal!("<"), DString, pegged.peg.literal!(">")))), doublequote), "Pegged.DLMString"), "DLMString")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(PEG.and!(PEG.literal!("q"), doublequote), PEG.or!(PEG.and!(PEG.posLookahead!(PEG.literal!("{")), NestedList!(PEG.literal!("{"), DString, PEG.literal!("}"))), PEG.and!(PEG.posLookahead!(PEG.literal!("[")), NestedList!(PEG.literal!("["), DString, PEG.literal!("]"))), PEG.and!(PEG.posLookahead!(PEG.literal!("(")), NestedList!(PEG.literal!("("), DString, PEG.literal!(")"))), PEG.and!(PEG.posLookahead!(PEG.literal!("<")), NestedList!(PEG.literal!("<"), DString, PEG.literal!(">")))), doublequote), "Pegged.DLMString"), "DLMString")(ParseTree("", false,[], s)); } } static string DLMString(GetName g) @@ -1899,25 +1902,25 @@ struct GenericPegged(TParseTree) return "Pegged.DLMString"; } - static TParseTree DComment(TParseTree p) + static ParseTree DComment(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.or!(DLineComment, DBlockComment, DNestingBlockComment), "Pegged.DComment")(p); + return PEG.defined!(PEG.or!(DLineComment, DBlockComment, DNestingBlockComment), "Pegged.DComment")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.or!(DLineComment, DBlockComment, DNestingBlockComment), "Pegged.DComment"), "DComment")(p); + return hooked!(PEG.defined!(PEG.or!(DLineComment, DBlockComment, DNestingBlockComment), "Pegged.DComment"), "DComment")(p); } } - static TParseTree DComment(string s) + static ParseTree DComment(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.or!(DLineComment, DBlockComment, DNestingBlockComment), "Pegged.DComment")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.or!(DLineComment, DBlockComment, DNestingBlockComment), "Pegged.DComment")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.or!(DLineComment, DBlockComment, DNestingBlockComment), "Pegged.DComment"), "DComment")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.or!(DLineComment, DBlockComment, DNestingBlockComment), "Pegged.DComment"), "DComment")(ParseTree("", false,[], s)); } } static string DComment(GetName g) @@ -1925,25 +1928,25 @@ struct GenericPegged(TParseTree) return "Pegged.DComment"; } - static TParseTree DLineComment(TParseTree p) + static ParseTree DLineComment(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("//"), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(endOfLine), pegged.peg.any)), endOfLine), "Pegged.DLineComment")(p); + return PEG.defined!(PEG.and!(PEG.literal!("//"), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(endOfLine), PEG.any)), endOfLine), "Pegged.DLineComment")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("//"), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(endOfLine), pegged.peg.any)), endOfLine), "Pegged.DLineComment"), "DLineComment")(p); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("//"), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(endOfLine), PEG.any)), endOfLine), "Pegged.DLineComment"), "DLineComment")(p); } } - static TParseTree DLineComment(string s) + static ParseTree DLineComment(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("//"), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(endOfLine), pegged.peg.any)), endOfLine), "Pegged.DLineComment")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(PEG.literal!("//"), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(endOfLine), PEG.any)), endOfLine), "Pegged.DLineComment")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("//"), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(endOfLine), pegged.peg.any)), endOfLine), "Pegged.DLineComment"), "DLineComment")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("//"), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(endOfLine), PEG.any)), endOfLine), "Pegged.DLineComment"), "DLineComment")(ParseTree("", false,[], s)); } } static string DLineComment(GetName g) @@ -1951,25 +1954,25 @@ struct GenericPegged(TParseTree) return "Pegged.DLineComment"; } - static TParseTree DBlockComment(TParseTree p) + static ParseTree DBlockComment(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("/*"), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(pegged.peg.literal!("*/")), pegged.peg.any)), pegged.peg.literal!("*/")), "Pegged.DBlockComment")(p); + return PEG.defined!(PEG.and!(PEG.literal!("/*"), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.literal!("*/")), PEG.any)), PEG.literal!("*/")), "Pegged.DBlockComment")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("/*"), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(pegged.peg.literal!("*/")), pegged.peg.any)), pegged.peg.literal!("*/")), "Pegged.DBlockComment"), "DBlockComment")(p); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("/*"), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.literal!("*/")), PEG.any)), PEG.literal!("*/")), "Pegged.DBlockComment"), "DBlockComment")(p); } } - static TParseTree DBlockComment(string s) + static ParseTree DBlockComment(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("/*"), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(pegged.peg.literal!("*/")), pegged.peg.any)), pegged.peg.literal!("*/")), "Pegged.DBlockComment")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(PEG.literal!("/*"), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.literal!("*/")), PEG.any)), PEG.literal!("*/")), "Pegged.DBlockComment")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.literal!("/*"), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(pegged.peg.literal!("*/")), pegged.peg.any)), pegged.peg.literal!("*/")), "Pegged.DBlockComment"), "DBlockComment")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(PEG.literal!("/*"), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.literal!("*/")), PEG.any)), PEG.literal!("*/")), "Pegged.DBlockComment"), "DBlockComment")(ParseTree("", false,[], s)); } } static string DBlockComment(GetName g) @@ -1977,25 +1980,25 @@ struct GenericPegged(TParseTree) return "Pegged.DBlockComment"; } - static TParseTree DNestingBlockComment(TParseTree p) + static ParseTree DNestingBlockComment(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(NestedList!(pegged.peg.literal!("/+"), pegged.peg.literal!("+/")), "Pegged.DNestingBlockComment")(p); + return PEG.defined!(NestedList!(PEG.literal!("/+"), PEG.literal!("+/")), "Pegged.DNestingBlockComment")(p); } else { - return hooked!(pegged.peg.defined!(NestedList!(pegged.peg.literal!("/+"), pegged.peg.literal!("+/")), "Pegged.DNestingBlockComment"), "DNestingBlockComment")(p); + return hooked!(PEG.defined!(NestedList!(PEG.literal!("/+"), PEG.literal!("+/")), "Pegged.DNestingBlockComment"), "DNestingBlockComment")(p); } } - static TParseTree DNestingBlockComment(string s) + static ParseTree DNestingBlockComment(string s) { if(__ctfe) - return pegged.peg.defined!(NestedList!(pegged.peg.literal!("/+"), pegged.peg.literal!("+/")), "Pegged.DNestingBlockComment")(TParseTree("", false,[], s)); + return PEG.defined!(NestedList!(PEG.literal!("/+"), PEG.literal!("+/")), "Pegged.DNestingBlockComment")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(NestedList!(pegged.peg.literal!("/+"), pegged.peg.literal!("+/")), "Pegged.DNestingBlockComment"), "DNestingBlockComment")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(NestedList!(PEG.literal!("/+"), PEG.literal!("+/")), "Pegged.DNestingBlockComment"), "DNestingBlockComment")(ParseTree("", false,[], s)); } } static string DNestingBlockComment(GetName g) @@ -2003,25 +2006,25 @@ struct GenericPegged(TParseTree) return "Pegged.DNestingBlockComment"; } - static TParseTree DParamList(TParseTree p) + static ParseTree DParamList(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(NestedList!(pegged.peg.literal!("("), pegged.peg.literal!(")")), "Pegged.DParamList")(p); + return PEG.defined!(NestedList!(PEG.literal!("("), PEG.literal!(")")), "Pegged.DParamList")(p); } else { - return hooked!(pegged.peg.defined!(NestedList!(pegged.peg.literal!("("), pegged.peg.literal!(")")), "Pegged.DParamList"), "DParamList")(p); + return hooked!(PEG.defined!(NestedList!(PEG.literal!("("), PEG.literal!(")")), "Pegged.DParamList"), "DParamList")(p); } } - static TParseTree DParamList(string s) + static ParseTree DParamList(string s) { if(__ctfe) - return pegged.peg.defined!(NestedList!(pegged.peg.literal!("("), pegged.peg.literal!(")")), "Pegged.DParamList")(TParseTree("", false,[], s)); + return PEG.defined!(NestedList!(PEG.literal!("("), PEG.literal!(")")), "Pegged.DParamList")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(NestedList!(pegged.peg.literal!("("), pegged.peg.literal!(")")), "Pegged.DParamList"), "DParamList")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(NestedList!(PEG.literal!("("), PEG.literal!(")")), "Pegged.DParamList"), "DParamList")(ParseTree("", false,[], s)); } } static string DParamList(GetName g) @@ -2031,25 +2034,25 @@ struct GenericPegged(TParseTree) template NestedList(alias L, alias Items, alias R) { - static TParseTree NestedList(TParseTree p) + static ParseTree NestedList(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.keep!(L), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(pegged.peg.or!(L, R, Items)), pegged.peg.any)), pegged.peg.zeroOrMore!(pegged.peg.or!(Items, NestedList!(L, Items, R), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(pegged.peg.or!(L, R, Items)), pegged.peg.any)))), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(pegged.peg.or!(L, R, Items)), pegged.peg.any)), pegged.peg.keep!(R)), "Pegged.NestedList!(" ~ pegged.peg.getName!(L)() ~ ", " ~ pegged.peg.getName!(Items)() ~ ", " ~ pegged.peg.getName!(R) ~ ")")(p); + return PEG.defined!(PEG.and!(PEG.keep!(L), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)), PEG.zeroOrMore!(PEG.or!(Items, NestedList!(L, Items, R), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)))), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)), PEG.keep!(R)), "Pegged.NestedList!(" ~ pegged.peg.getName!(L)() ~ ", " ~ pegged.peg.getName!(Items)() ~ ", " ~ pegged.peg.getName!(R) ~ ")")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.keep!(L), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(pegged.peg.or!(L, R, Items)), pegged.peg.any)), pegged.peg.zeroOrMore!(pegged.peg.or!(Items, NestedList!(L, Items, R), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(pegged.peg.or!(L, R, Items)), pegged.peg.any)))), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(pegged.peg.or!(L, R, Items)), pegged.peg.any)), pegged.peg.keep!(R)), "Pegged.NestedList!(" ~ pegged.peg.getName!(L)() ~ ", " ~ pegged.peg.getName!(Items)() ~ ", " ~ pegged.peg.getName!(R) ~ ")"), "NestedList_3")(p); + return hooked!(PEG.defined!(PEG.and!(PEG.keep!(L), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)), PEG.zeroOrMore!(PEG.or!(Items, NestedList!(L, Items, R), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)))), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)), PEG.keep!(R)), "Pegged.NestedList!(" ~ pegged.peg.getName!(L)() ~ ", " ~ pegged.peg.getName!(Items)() ~ ", " ~ pegged.peg.getName!(R) ~ ")"), "NestedList_3")(p); } } - static TParseTree NestedList(string s) + static ParseTree NestedList(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.keep!(L), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(pegged.peg.or!(L, R, Items)), pegged.peg.any)), pegged.peg.zeroOrMore!(pegged.peg.or!(Items, NestedList!(L, Items, R), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(pegged.peg.or!(L, R, Items)), pegged.peg.any)))), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(pegged.peg.or!(L, R, Items)), pegged.peg.any)), pegged.peg.keep!(R)), "Pegged.NestedList!(" ~ pegged.peg.getName!(L)() ~ ", " ~ pegged.peg.getName!(Items)() ~ ", " ~ pegged.peg.getName!(R) ~ ")")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(PEG.keep!(L), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)), PEG.zeroOrMore!(PEG.or!(Items, NestedList!(L, Items, R), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)))), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)), PEG.keep!(R)), "Pegged.NestedList!(" ~ pegged.peg.getName!(L)() ~ ", " ~ pegged.peg.getName!(Items)() ~ ", " ~ pegged.peg.getName!(R) ~ ")")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.keep!(L), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(pegged.peg.or!(L, R, Items)), pegged.peg.any)), pegged.peg.zeroOrMore!(pegged.peg.or!(Items, NestedList!(L, Items, R), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(pegged.peg.or!(L, R, Items)), pegged.peg.any)))), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(pegged.peg.or!(L, R, Items)), pegged.peg.any)), pegged.peg.keep!(R)), "Pegged.NestedList!(" ~ pegged.peg.getName!(L)() ~ ", " ~ pegged.peg.getName!(Items)() ~ ", " ~ pegged.peg.getName!(R) ~ ")"), "NestedList_3")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(PEG.keep!(L), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)), PEG.zeroOrMore!(PEG.or!(Items, NestedList!(L, Items, R), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)))), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)), PEG.keep!(R)), "Pegged.NestedList!(" ~ pegged.peg.getName!(L)() ~ ", " ~ pegged.peg.getName!(Items)() ~ ", " ~ pegged.peg.getName!(R) ~ ")"), "NestedList_3")(ParseTree("", false,[], s)); } } static string NestedList(GetName g) @@ -2060,25 +2063,25 @@ struct GenericPegged(TParseTree) } template NestedList(alias L, alias R) { - static TParseTree NestedList(TParseTree p) + static ParseTree NestedList(ParseTree p) { if(__ctfe) { - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.keep!(L), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(pegged.peg.or!(L, R)), pegged.peg.any)), pegged.peg.zeroOrMore!(pegged.peg.or!(NestedList!(L, R), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(pegged.peg.or!(L, R)), pegged.peg.any)))), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(pegged.peg.or!(L, R)), pegged.peg.any)), pegged.peg.keep!(R)), "Pegged.NestedList!(" ~ pegged.peg.getName!(L)() ~ ", " ~ pegged.peg.getName!(R) ~ ")")(p); + return PEG.defined!(PEG.and!(PEG.keep!(L), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)), PEG.zeroOrMore!(PEG.or!(NestedList!(L, R), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)))), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)), PEG.keep!(R)), "Pegged.NestedList!(" ~ pegged.peg.getName!(L)() ~ ", " ~ pegged.peg.getName!(R) ~ ")")(p); } else { - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.keep!(L), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(pegged.peg.or!(L, R)), pegged.peg.any)), pegged.peg.zeroOrMore!(pegged.peg.or!(NestedList!(L, R), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(pegged.peg.or!(L, R)), pegged.peg.any)))), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(pegged.peg.or!(L, R)), pegged.peg.any)), pegged.peg.keep!(R)), "Pegged.NestedList!(" ~ pegged.peg.getName!(L)() ~ ", " ~ pegged.peg.getName!(R) ~ ")"), "NestedList_2")(p); + return hooked!(PEG.defined!(PEG.and!(PEG.keep!(L), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)), PEG.zeroOrMore!(PEG.or!(NestedList!(L, R), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)))), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)), PEG.keep!(R)), "Pegged.NestedList!(" ~ pegged.peg.getName!(L)() ~ ", " ~ pegged.peg.getName!(R) ~ ")"), "NestedList_2")(p); } } - static TParseTree NestedList(string s) + static ParseTree NestedList(string s) { if(__ctfe) - return pegged.peg.defined!(pegged.peg.and!(pegged.peg.keep!(L), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(pegged.peg.or!(L, R)), pegged.peg.any)), pegged.peg.zeroOrMore!(pegged.peg.or!(NestedList!(L, R), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(pegged.peg.or!(L, R)), pegged.peg.any)))), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(pegged.peg.or!(L, R)), pegged.peg.any)), pegged.peg.keep!(R)), "Pegged.NestedList!(" ~ pegged.peg.getName!(L)() ~ ", " ~ pegged.peg.getName!(R) ~ ")")(TParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(PEG.keep!(L), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)), PEG.zeroOrMore!(PEG.or!(NestedList!(L, R), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)))), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)), PEG.keep!(R)), "Pegged.NestedList!(" ~ pegged.peg.getName!(L)() ~ ", " ~ pegged.peg.getName!(R) ~ ")")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(pegged.peg.defined!(pegged.peg.and!(pegged.peg.keep!(L), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(pegged.peg.or!(L, R)), pegged.peg.any)), pegged.peg.zeroOrMore!(pegged.peg.or!(NestedList!(L, R), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(pegged.peg.or!(L, R)), pegged.peg.any)))), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(pegged.peg.or!(L, R)), pegged.peg.any)), pegged.peg.keep!(R)), "Pegged.NestedList!(" ~ pegged.peg.getName!(L)() ~ ", " ~ pegged.peg.getName!(R) ~ ")"), "NestedList_2")(TParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(PEG.keep!(L), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)), PEG.zeroOrMore!(PEG.or!(NestedList!(L, R), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)))), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)), PEG.keep!(R)), "Pegged.NestedList!(" ~ pegged.peg.getName!(L)() ~ ", " ~ pegged.peg.getName!(R) ~ ")"), "NestedList_2")(ParseTree("", false,[], s)); } } static string NestedList(GetName g) @@ -2087,18 +2090,18 @@ struct GenericPegged(TParseTree) } } - static TParseTree opCall(TParseTree p) + static ParseTree opCall(ParseTree p) { - TParseTree result = decimateTree(Grammar(p)); + ParseTree result = decimateTree(Grammar(p)); result.children = [result]; result.name = "Pegged"; return result; } - static TParseTree opCall(string input) + static ParseTree opCall(string input) { forgetMemo(); - return Pegged(TParseTree(``, false, [], input, 0, 0)); + return Pegged(ParseTree(``, false, [], input, 0, 0)); } static string opCall(GetName g) { @@ -2112,5 +2115,4 @@ struct GenericPegged(TParseTree) } } -alias GenericPegged!(ParseTree).Pegged Pegged; - +alias GenericPegged!(DefaultParseTree).Pegged Pegged; diff --git a/pegged/peg.d b/pegged/peg.d index 9e057a3..ab131f1 100644 --- a/pegged/peg.d +++ b/pegged/peg.d @@ -1,21 +1,21 @@ /** -This module contains the engine behind Pegged, the expression templates building blocks to create a top-down -recursive-descent parser. + This module contains the engine behind Pegged, the expression templates building blocks to create a top-down + recursive-descent parser. -The terminals and non-terminals described here are meant to be used inside a Pegged grammar. -As such, they are a bit less user-friendly than what's output by pegged.grammar. -For example they take a ParseTree as input, not a string. + The terminals and non-terminals described here are meant to be used inside a Pegged grammar. + As such, they are a bit less user-friendly than what's output by pegged.grammar. + For example they take a ParseTree as input, not a string. -See the /docs directory for the full documentation as markdown files. + See the /docs directory for the full documentation as markdown files. */ module pegged.peg; /* -NOTE: -Do not use the GrammarTester for unittesting in this module. This module needs -to be able to pass its unittests before the GrammarTester is even trustable. -Writing tests the long way is preferred here, as it will avoid the circular -dependency. + NOTE: + Do not use the GrammarTester for unittesting in this module. This module needs + to be able to pass its unittests before the GrammarTester is even trustable. + Writing tests the long way is preferred here, as it will avoid the circular + dependency. */ import std.algorithm: equal, map, startsWith, max, countUntil, maxElement, filter; @@ -54,7 +54,7 @@ package string stringified(string inp) @safe "42" : `"42"`, "\"some text\"\n" : `"\"some text\"\n"` - ]; + ]; const caseSuit2 = [cast(string)null : `"end of input"`]; @@ -79,166 +79,76 @@ package string stringified(string inp) @safe doTest; // Run-time. } -version (tracer) -{ - import std.experimental.logger; - import std.algorithm.comparison : min; - - // Function pointers. - private static bool function(string ruleName, const ref ParseTree p) traceConditionFunction; - private static bool delegate(string ruleName, const ref ParseTree p) traceConditionDelegate; - private static int traceLevel; - private static bool traceBlocked; - private static bool logTraceLevel = false; - - private void incTraceLevel() - { - if (!__ctfe) - traceLevel++; - } - - private void decTraceLevel() - { - if (!__ctfe) - traceLevel--; - } - - private bool shouldTrace(string ruleName, const ref ParseTree p) - { - if (__ctfe || traceBlocked) - return false; - if (traceConditionDelegate != null) - return traceConditionDelegate(ruleName, p); - if (traceConditionFunction != null) - return traceConditionFunction(ruleName, p); - return false; - } +struct GetName {} - static this() - { - traceLevel = 0; - traceNothing(); - traceBlocked = false; - } +string getName(alias expr)() @property +{ + static if (is(typeof( { expr(GetName()); }))) + return expr(GetName()); + else + return __traits(identifier, expr); +} - /++ Supply a function to dynamically switch tracing on and off based on the rule name. - + - + Example: - + --- - + /* Exclude build-in parsers, only trace parsers generated from MyGrammar. */ - + setTraceConditionFunction(ruleName => ruleName.startsWith("MyGrammar")); - + --- - +/ - void setTraceConditionFunction(bool delegate(string ruleName, const ref ParseTree p) condition) - { - traceConditionDelegate = condition; - traceConditionFunction = null; - } +string fail(GetName g) +{ + return "fail"; +} - /// ditto - void setTraceConditionFunction(bool function(string ruleName, const ref ParseTree p) condition) - { - traceConditionFunction = condition; - traceConditionDelegate = null; - } +string eoi(GetName g) +{ + return "eoi"; +} - /** Trace all rules. - * - * This can produce a lot of output. - */ - void traceAll() - { - setTraceConditionFunction(function(string ruleName, const ref ParseTree p) {return true;}); - } +string any(GetName g) +{ + return "any"; +} - /** Do not trace any rules. */ - void traceNothing() - { - traceConditionFunction = null; - traceConditionDelegate = null; +import std.traits : isType, ReturnType, ForeachType, isCallable, Unqual; +template Returns(alias M) { + static if (isType!M) { + alias U = M; } - - private string traceMsg(ParseTree p, string expression, string name) - { - import std.format; - Position pos = position(p); - enum inputLength = 15; - string result; - for (auto i = 1; i <= traceLevel; i++) - result ~= format("%d|", i); - result ~= format(" (l:%d, c:%d, i:%d)\t", pos.line + 1, pos.col + 1, pos.index) ~ - expression.stringified ~ " considering rule " ~ name.stringified ~ " on " ~ - p.input[p.end .. min(p.input.length, p.end + inputLength)].stringified ~ - (p.end + inputLength > p.input.length ? "" : "..."); - return result; + else { + alias U = typeof(M); } - - private string traceResultMsg(ParseTree p, string name) - { - import std.format; - import std.range: chain; - import std.algorithm.iteration: joiner; - Position pos = position(p); - enum inputLength = 15; - string result; - for (auto i = 1; i <= traceLevel; i++) - result ~= format("%d|", i); - if (p.successful) - { - string consumed; - foreach (match; p.matches) - consumed ~= match; - result ~= format(" (l:%d, c:%d, i:%d)\t", pos.line + 1, pos.col + 1, pos.index) ~ name.stringified ~ " SUCCEEDED on " ~ - consumed.stringified; - } - else - result ~= format(" (l:%d, c:%d, i:%d)\t", pos.line + 1, pos.col + 1, pos.index) ~ name.stringified ~ " FAILED on " ~ - p.input[p.end .. min(p.input.length, p.end + inputLength)].stringified ~ - (p.end + inputLength > p.input.length ? "" : "..."); - return result; + static if (isCallable!U) { + alias Returns = Unqual!(ReturnType!U); } - - /** - Overrides FileLogger to remove the time stamp. - - Example: - --- - sharedLog = new TraceLogger("TraceLog.txt"); - --- - */ - class TraceLogger : FileLogger - { - this(in string fn) @safe - { - super(fn); - } - import std.concurrency : Tid; - import std.datetime : SysTime; - override protected void beginLogMsg(string file, int line, string funcName, - string prettyFuncName, string moduleName, LogLevel logLevel, - Tid threadId, SysTime timestamp, Logger logger) - @safe - { - } + else { + alias Returns = Unqual!(U); } } +pragma(msg, Returns!(DefaultParseTree.name)); +pragma(msg, ": ", ForeachType!(Returns!(DefaultParseTree.matches))); +pragma(msg, ": ", ForeachType!(Returns!(DefaultParseTree.children))); +//import +enum isParseTree(T) = + is(Returns!(T.name) == string) && + is(Returns!(T.successful) == bool) && + is(Returns!(T.input) == string) && + is(Returns!(T.begin) == size_t) && + is(Returns!(T.end) == size_t) && + is(Returns!(T.failEnd) == size_t) && + is(ForeachType!(Returns!(T.matches)) == string) && + is(ForeachType!(Returns!(T.children)) == T) && + is(ForeachType!(Returns!(T.failedChild)) == T); + /** -CT Switch for testing 'keywords' implementations + Matches the end of input. Fails if there is any character left. */ -enum -{ - IFCHAIN, - TRIE +ParseTree eoi(ParseTree)(const ParseTree p) if (isParseTree!ParseTree) { + if (p.end == p.input.length) + return ParseTree("eoi", true, [], p.input, p.end, p.end); + else + return ParseTree("eoi", false, ["end of input"], p.input, p.end, p.end); } -enum KEYWORDS = IFCHAIN; -/** -The basic parse tree, as used throughout the project. -You can define your own parse tree node, but respect the basic layout. -*/ -mixin template ParseTreeT() -{ + +mixin template ParseTreeM() { + import std.functional : toDelegate; + alias ParseTree = typeof(this); string name; /// The node name bool successful; /// Indicates whether a parsing was successful or not string[] matches; /// The matched input's parts. Some expressions match at more than one place, hence matches is an array. @@ -252,41 +162,41 @@ mixin template ParseTreeT() ParseTree[] failedChild; /// The !successful child that could still be partially parsed. /** - Basic toString for easy pretty-printing. + Basic toString for easy pretty-printing. */ string toString(string tabs = "") const - { - string result = name; + { + string result = name; - string childrenString; - bool allChildrenSuccessful = true; + string childrenString; + bool allChildrenSuccessful = true; - foreach(i,child; children) - { - childrenString ~= tabs ~ " +-" ~ child.toString(tabs ~ ((i < children.length -1 ) ? " | " : " ")); - if (!child.successful) { - allChildrenSuccessful = false; + foreach(i,child; children) + { + childrenString ~= tabs ~ " +-" ~ child.toString(tabs ~ ((i < children.length -1 ) ? " | " : " ")); + if (!child.successful) { + allChildrenSuccessful = false; + } } + result ~= this.toStringThisNode(allChildrenSuccessful); + return result ~ childrenString; } - result ~= this.toStringThisNode(allChildrenSuccessful); - return result ~ childrenString; - } /** * Basic toString of only this node, without the children */ private string toStringThisNode(bool allChildrenSuccessful) const - { - if (successful) { - return to!string([begin, end]) ~ to!string(matches) ~ "\n"; - } else { // some failure info is needed - if (allChildrenSuccessful) { // no one calculated the position yet - return " " ~ this.failMsg ~ "\n"; - } else { - return " (failure)\n"; + { + if (successful) { + return to!string([begin, end]) ~ to!string(matches) ~ "\n"; + } else { // some failure info is needed + if (allChildrenSuccessful) { // no one calculated the position yet + return " " ~ this.failMsg ~ "\n"; + } else { + return " (failure)\n"; + } } } - } /** * Generates a generic error when a node fails @@ -294,58 +204,58 @@ mixin template ParseTreeT() * @param successMsg String returned when there isn't an error * @param formatFailMsg Formating delegate function that generates the error message. */ - string failMsg(string delegate(Position, string, string, const ParseTree) formatFailMsg = defaultFormatFailMsg, + string failMsg(string delegate(Position, string, string, const ParseTree) formatFailMsg = toDelegate(&defaultFormatFailMsg!ParseTree), string successMsg = "Sucess") const @property - { - foreach(i, child; children) { - if (!child.successful) { - return child.failMsg(formatFailMsg, successMsg); + { + foreach(i, child; children) { + if (!child.successful) { + return child.failMsg(formatFailMsg, successMsg); + } } - } - if (!successful) { - Position pos = position(this); - string left, right; + if (!successful) { + Position pos = position(this); + string left, right; - if (pos.index < 10) { - left = input[0 .. pos.index]; - } else { - left = input[pos.index - 10 .. pos.index]; - } - if (pos.index + 10 < input.length) { - right = input[pos.index .. pos.index + 10]; - } else { - right = input[pos.index .. $]; + if (pos.index < 10) { + left = input[0 .. pos.index]; + } else { + left = input[pos.index - 10 .. pos.index]; + } + if (pos.index + 10 < input.length) { + right = input[pos.index .. pos.index + 10]; + } else { + right = input[pos.index .. $]; + } + return formatFailMsg(pos, left, right, this); } - return formatFailMsg(pos, left, right, this); - } - return successMsg; - } + return successMsg; + } ParseTree dup() const @property - { - ParseTree result; - result.name = name; - result.successful = successful; - result.matches = matches.dup; - result.input = input; - result.begin = begin; - result.end = end; - result.failEnd = failEnd; - result.failedChild = map!(p => p.dup)(failedChild).array(); - result.children = map!(p => p.dup)(children).array(); - return result; - } + { + ParseTree result; + result.name = name; + result.successful = successful; + result.matches = matches.dup; + result.input = input; + result.begin = begin; + result.end = end; + result.failEnd = failEnd; + result.failedChild = map!(p => p.dup)(failedChild).array(); + result.children = map!(p => p.dup)(children).array(); + return result; + } immutable(ParseTree) idup() const @property - { - return cast(immutable)dup(); - } + { + return cast(immutable)dup(); + } // Override opIndex operators ref ParseTree opIndex(size_t index) { - return children[index]; + return children[index]; } ref ParseTree[] opIndex() return { @@ -353,111 +263,34 @@ mixin template ParseTreeT() } size_t opDollar(size_t pos)() const - { - return children.length; - } + { + return children.length; + } ParseTree[] opSlice(size_t i, size_t j) { return children[i..j]; } } -struct ParseTree -{ - mixin ParseTreeT; -} /** - * Default fail message formating function - */ -immutable defaultFormatFailMsg = delegate (Position pos, string left, string right, const ParseTree pt) -{ - return "Failure at line " ~ to!string(pos.line) ~ ", col " ~ to!string(pos.col) ~ ", " - ~ (left.length > 0 ? "after " ~ left.stringified ~ " " : "") - ~ "expected " ~ (pt.matches.length > 0 ? pt.matches[$ - 1].stringified : "NO MATCH") - ~ `, but got ` ~ right.stringified; -}; - - -unittest // ParseTree testing -{ - ParseTree p; - assert(p == p, "Self-identity on null tree."); - - p = ParseTree("Name", true, ["abc", "", "def"], "input", 0, 1, null); - assert(p == p, "Self identity on non-null tree."); - - ParseTree child = ParseTree("Child", true, ["abc", "", "def"], "input", 0, 1, null); - p.children = [child, child]; - - assert(p.children[0] == p[0], "override opIndex allows to write less verbose code to navigate the tree"); - assert(p.children == p[] ); - assert(p.children[0..1] == p[0..1] ); - assert(p.children[0..$] == p[0..$] ); - - ParseTree q = p; - assert(p == q, "Copying creates equal trees."); - - assert(p.children == q.children); - p.children = [child, child, child]; - assert(q.children != p.children, "Disconnecting children."); - - p = ParseTree("Name", true, ["abc", "", "def"], "input", 0, 1, null); - p.children = [child, child]; - - q = p.dup; - assert(p == q, "Dupping creates equal trees."); - - assert(p.children == q.children, "Equal children for dupped trees."); - p.children = null; - assert(q.children != p.children); - - immutable iq = p.idup; - q = iq.dup; - assert(p == q, "Dupping to/from immutable creates equal trees."); - - q.children = [p,p]; - assert(p != q, "Tree with different children are not equal."); - - p.children = [p,p]; - assert(p == q, "Adding equivalent children is OK."); - - p.matches = null; - assert(p != q, "Nulling matches makes trees unequal."); - - p.matches = q.matches; - assert(p == q, "Copying matches makes equal trees."); - - p.children[0].successful = false; - assert(p.children[0].failMsg == `Failure at line 0, col 1, after "i" expected "def", but got "nput"`); - assert(p.children[1].failMsg == "Sucess"); - assert(p.failMsg == `Failure at line 0, col 1, after "i" expected "def", but got "nput"`); -} - -/// To compare two trees for content (not bothering with node names) -/// That's useful to compare the results from two different grammars. -bool softCompare(const ParseTree p1, const ParseTree p2) + The basic parse tree, as used throughout the project. + You can define your own parse tree node, but respect the basic layout. +*/ +struct DefaultParseTree { - return p1.successful == p2.successful - && p1.matches == p2.matches - && p1.begin == p2.begin - && p1.end == p2.end - && equal!(softCompare)(p1.children, p2.children); // the same for children + mixin ParseTreeM; } -unittest // softCompare +static assert(isParseTree!DefaultParseTree); +/** + CT Switch for testing 'keywords' implementations +*/ +enum { - ParseTree p = ParseTree("Name", true, ["abc", "", "def"], "input", 0, 1, null); - ParseTree child = ParseTree("Child", true, ["abc", "", "def"], "input", 0, 1, null); - p.children = [child, child]; - - ParseTree q = p; - assert(p == q, "Copy => Equal trees."); - assert(softCompare(p,q), "Copy => Trees equal for softCompare."); - - q.name = "Another One"; - assert(p != q, "Name change => non-equal trees."); - assert(softCompare(p,q), "Name change => Trees equal for softCompare."); + IFCHAIN, + TRIE } +enum KEYWORDS = IFCHAIN; /// To record a position in a text struct Position @@ -468,17 +301,17 @@ struct Position } /** -Given an input string, returns the position corresponding to the end of the string. + Given an input string, returns the position corresponding to the end of the string. -For example: ---- -assert(position("abc") == Position(0,3,3)); -assert(position("abc -") == Position(1,0,4)); -assert(position("abc + For example: + --- + assert(position("abc") == Position(0,3,3)); + assert(position("abc + ") == Position(1,0,4)); + assert(position("abc - ") == Position(2,4,8)); ---- + ") == Position(2,4,8)); + --- */ Position position(string s) { @@ -487,7 +320,7 @@ Position position(string s) foreach(i,c; s) { if ((c == '\n' && !(i == prev_i + 1 && prev_c == '\r')) || // new line except when directly following a carriage return. - c == '\r') + c == '\r') { col = 0; ++line; @@ -506,10 +339,11 @@ Position position(string s) return Position(line,col,index); } + /** -Same as previous overload, but from the begin of P.input to p.end + Same as previous overload, but from the begin of P.input to p.end */ -Position position(const ParseTree p) +Position position(ParseTree)(const ParseTree p) { return position(p.input[0..p.end]); } @@ -533,249 +367,501 @@ unittest assert(position("one\r\ntwo\r\nthree") == Position(2, 5, 15), "Three lines, DOS line endings"); } -string getName(alias expr)() @property -{ - static if (is(typeof( { expr(GetName()); }))) - return expr(GetName()); - else - return __traits(identifier, expr); -} -struct GetName {} +struct PeggedT(ParseTree) { + import pegged.peg; + mixin ParseCollections!ParseTree; + version (tracer) + { + import std.experimental.logger; + import std.algorithm.comparison : min; -/** -Basic rule, that always fail without consuming. -*/ -ParseTree fail(ParseTree p) -{ - return ParseTree("fail", false, [], p.input, p.end, p.end, null); -} + // Function pointers. + private static bool function(string ruleName, const ref ParseTree p) traceConditionFunction; + private static bool delegate(string ruleName, const ref ParseTree p) traceConditionDelegate; + private static int traceLevel; + private static bool traceBlocked; + private static bool logTraceLevel = false; -/// ditto -ParseTree fail(string input) -{ - return fail(ParseTree("", false, [], input)); -} + private void incTraceLevel() + { + if (!__ctfe) + traceLevel++; + } -string fail(GetName g) -{ - return "fail"; -} + private void decTraceLevel() + { + if (!__ctfe) + traceLevel--; + } -unittest // 'fail' unit test -{ - ParseTree input = ParseTree("input", true, [], "This is the input string.", 0,0, null); - ParseTree result = fail(input); - assert(result.name == "fail"); - assert(!result.successful, "'fail' fails."); - assert(result.matches is null, "'fail' makes no match."); - assert(result.input == input.input, "'fail' does not change the input."); - assert(result.end == input.end, "'fail' puts the index after the previous parse."); - assert(result.children is null, "'fail' has no children."); + private bool shouldTrace(string ruleName, const ref ParseTree p) + { + if (__ctfe || traceBlocked) + return false; + if (traceConditionDelegate != null) + return traceConditionDelegate(ruleName, p); + if (traceConditionFunction != null) + return traceConditionFunction(ruleName, p); + return false; + } - result = fail("This is the input string."); - assert(!result.successful, "'fail' fails."); -} + static this() + { + traceLevel = 0; + traceNothing(); + traceBlocked = false; + } -/** -Matches the end of input. Fails if there is any character left. -*/ -ParseTree eoi(ParseTree p) -{ - if (p.end == p.input.length) - return ParseTree("eoi", true, [], p.input, p.end, p.end); - else - return ParseTree("eoi", false, ["end of input"], p.input, p.end, p.end); -} + /++ Supply a function to dynamically switch tracing on and off based on the rule name. + + + + Example: + + --- + + /* Exclude build-in parsers, only trace parsers generated from MyGrammar. */ + + setTraceConditionFunction(ruleName => ruleName.startsWith("MyGrammar")); + + --- + +/ + void setTraceConditionFunction(bool delegate(string ruleName, const ref ParseTree p) condition) + { + traceConditionDelegate = condition; + traceConditionFunction = null; + } -/// ditto -ParseTree eoi(string input) -{ - return eoi(ParseTree("", false, [], input)); -} + /// ditto + void setTraceConditionFunction(bool function(string ruleName, const ref ParseTree p) condition) + { + traceConditionFunction = condition; + traceConditionDelegate = null; + } -string eoi(GetName g) -{ - return "eoi"; -} + /** Trace all rules. + * + * This can produce a lot of output. + */ + void traceAll() + { + setTraceConditionFunction(function(string ruleName, const ref ParseTree p) {return true;}); + } -alias eoi endOfInput; /// helper alias. + /** Do not trace any rules. */ + void traceNothing() + { + traceConditionFunction = null; + traceConditionDelegate = null; + } -unittest // 'eoi' unit test -{ - ParseTree input = ParseTree("input", true, [], "This is the input string.", 0,0, null); - ParseTree result = eoi(input); - assert(result.name == "eoi"); - assert(!result.successful, "'eoi' fails on non-null string."); - assert(result.matches == ["end of input"], "'eoi' error message."); - assert(result.input == input.input, "'eoi' does not change the input."); - assert(result.end == input.end, "'eoi' puts the index after the previous parse."); - assert(result.children is null, "'eoi' has no children."); + private string traceMsg(ParseTree p, string expression, string name) + { + import std.format; + Position pos = position(p); + enum inputLength = 15; + string result; + for (auto i = 1; i <= traceLevel; i++) + result ~= format("%d|", i); + result ~= format(" (l:%d, c:%d, i:%d)\t", pos.line + 1, pos.col + 1, pos.index) ~ + expression.stringified ~ " considering rule " ~ name.stringified ~ " on " ~ + p.input[p.end .. min(p.input.length, p.end + inputLength)].stringified ~ + (p.end + inputLength > p.input.length ? "" : "..."); + return result; + } - input = ParseTree("input", true, [], "", 0,0, null); - result = eoi(input); - assert(result.successful, "'eoi' succeeds on strings of length 0."); - result = eoi(""); - assert(result.successful, "'eoi' succeeds on strings of length 0."); - result = eoi(null); - assert(result.successful, "'eoi' succeeds on null strings"); -} + private string traceResultMsg(ParseTree p, string name) + { + import std.format; + import std.range: chain; + import std.algorithm.iteration: joiner; + Position pos = position(p); + enum inputLength = 15; + string result; + for (auto i = 1; i <= traceLevel; i++) + result ~= format("%d|", i); + if (p.successful) + { + string consumed; + foreach (match; p.matches) + consumed ~= match; + result ~= format(" (l:%d, c:%d, i:%d)\t", pos.line + 1, pos.col + 1, pos.index) ~ name.stringified ~ " SUCCEEDED on " ~ + consumed.stringified; + } + else + result ~= format(" (l:%d, c:%d, i:%d)\t", pos.line + 1, pos.col + 1, pos.index) ~ name.stringified ~ " FAILED on " ~ + p.input[p.end .. min(p.input.length, p.end + inputLength)].stringified ~ + (p.end + inputLength > p.input.length ? "" : "..."); + return result; + } + + /** + Overrides FileLogger to remove the time stamp. + + Example: + --- + sharedLog = new TraceLogger("TraceLog.txt"); + --- + */ + static class TraceLogger : FileLogger + { + this(in string fn) @safe + { + super(fn); + } + import std.concurrency : Tid; + import std.datetime : SysTime; + override protected void beginLogMsg(string file, int line, string funcName, + string prettyFuncName, string moduleName, LogLevel logLevel, + Tid threadId, SysTime timestamp, Logger logger) + @safe + { + } + } + } + + unittest // ParseTree testing + { + ParseTree p; + assert(p == p, "Self-identity on null tree."); + + p = ParseTree("Name", true, ["abc", "", "def"], "input", 0, 1, null); + assert(p == p, "Self identity on non-null tree."); + + ParseTree child = ParseTree("Child", true, ["abc", "", "def"], "input", 0, 1, null); + p.children = [child, child]; + + assert(p.children[0] == p[0], "override opIndex allows to write less verbose code to navigate the tree"); + assert(p.children == p[] ); + assert(p.children[0..1] == p[0..1] ); + assert(p.children[0..$] == p[0..$] ); + + ParseTree q = p; + assert(p == q, "Copying creates equal trees."); + + assert(p.children == q.children); + p.children = [child, child, child]; + assert(q.children != p.children, "Disconnecting children."); + + p = ParseTree("Name", true, ["abc", "", "def"], "input", 0, 1, null); + p.children = [child, child]; + + q = p.dup; + assert(p == q, "Dupping creates equal trees."); + + assert(p.children == q.children, "Equal children for dupped trees."); + p.children = null; + assert(q.children != p.children); + + immutable iq = p.idup; + q = iq.dup; + assert(p == q, "Dupping to/from immutable creates equal trees."); + + q.children = [p,p]; + assert(p != q, "Tree with different children are not equal."); + + p.children = [p,p]; + assert(p == q, "Adding equivalent children is OK."); + + p.matches = null; + assert(p != q, "Nulling matches makes trees unequal."); + + p.matches = q.matches; + assert(p == q, "Copying matches makes equal trees."); + + p.children[0].successful = false; + assert(p.children[0].failMsg == `Failure at line 0, col 1, after "i" expected "def", but got "nput"`); + assert(p.children[1].failMsg == "Sucess"); + assert(p.failMsg == `Failure at line 0, col 1, after "i" expected "def", but got "nput"`); + } + +/// To compare two trees for content (not bothering with node names) +/// That's useful to compare the results from two different grammars. + static bool softCompare(const ParseTree p1, const ParseTree p2) + { + return p1.successful == p2.successful + && p1.matches == p2.matches + && p1.begin == p2.begin + && p1.end == p2.end + && equal!(softCompare)(p1.children, p2.children); // the same for children + } + + unittest // softCompare + { + ParseTree p = ParseTree("Name", true, ["abc", "", "def"], "input", 0, 1, null); + ParseTree child = ParseTree("Child", true, ["abc", "", "def"], "input", 0, 1, null); + p.children = [child, child]; + + ParseTree q = p; + assert(p == q, "Copy => Equal trees."); + assert(softCompare(p,q), "Copy => Trees equal for softCompare."); + + q.name = "Another One"; + assert(p != q, "Name change => non-equal trees."); + assert(softCompare(p,q), "Name change => Trees equal for softCompare."); + } /** -Match any character. As long as there is at least a character left in the input, it succeeds. -Conversely, it fails only if called at the end of the input. + Basic rule, that always fail without consuming. */ -ParseTree any(ParseTree p) -{ - if (p.end < p.input.length) - return ParseTree("any", true, [p.input[p.end..p.end+1]], p.input, p.end, p.end+1); - else - return ParseTree("any", false, ["any char"], p.input, p.end, p.end); -} + ParseTree fail(ParseTree p) + { + return ParseTree("fail", false, [], p.input, p.end, p.end, null); + } /// ditto -ParseTree any(string input) -{ - return any(ParseTree("", false, [], input)); -} - -string any(GetName g) -{ - return "any"; -} + ParseTree fail(string input) + { + return fail(ParseTree("", false, [], input)); + } -unittest // 'any' unit test -{ - ParseTree input = ParseTree("input", true, [], "This is the input string.", 0,0, null); - ParseTree result = any(input); + unittest // 'fail' unit test + { + ParseTree input = ParseTree("input", true, [], "This is the input string.", 0,0, null); + ParseTree result = fail(input); + assert(result.name == "fail"); + assert(!result.successful, "'fail' fails."); + assert(result.matches is null, "'fail' makes no match."); + assert(result.input == input.input, "'fail' does not change the input."); + assert(result.end == input.end, "'fail' puts the index after the previous parse."); + assert(result.children is null, "'fail' has no children."); + + result = fail("This is the input string."); + assert(!result.successful, "'fail' fails."); + } - assert(result.name == "any"); - assert(result.successful, "'any' succeeds on non-null strings."); - assert(result.matches == ["T"], "'any' matches the first char in an input."); - assert(result.input == input.input, "'any' does not change the input."); - assert(result.end == input.end+1, "'any' advances the index by one position."); - assert(result.children is null, "'any' has no children."); +/// ditto + static ParseTree eoi(string input) + { + return .eoi(ParseTree("", false, [], input)); + } - result = any("a"); - assert(result.successful, "'any' matches on strings of length one."); - assert(result.matches == ["a"], "'any' matches the first char in an input."); - assert(result.input == "a", "'any' does not change the input."); - assert(result.end == 1, "'any' advances the index by one position."); - assert(result.children is null, "'any' has no children."); + alias eoi endOfInput; /// helper alias. - input = ParseTree("input", true, [], "", 0,0, null); + unittest // 'eoi' unit test + { + ParseTree input = ParseTree("input", true, [], "This is the input string.", 0,0, null); + ParseTree result = eoi(input); + assert(result.name == "eoi"); + assert(!result.successful, "'eoi' fails on non-null string."); + assert(result.matches == ["end of input"], "'eoi' error message."); + assert(result.input == input.input, "'eoi' does not change the input."); + assert(result.end == input.end, "'eoi' puts the index after the previous parse."); + assert(result.children is null, "'eoi' has no children."); + + input = ParseTree("input", true, [], "", 0,0, null); + result = eoi(input); + assert(result.successful, "'eoi' succeeds on strings of length 0."); + result = eoi(""); + assert(result.successful, "'eoi' succeeds on strings of length 0."); + result = eoi(null); + assert(result.successful, "'eoi' succeeds on null strings"); + } - result = any(input); - assert(!result.successful, "'any' fails on strings of length 0."); - assert(result.matches == ["any char"], "'any' error message on strings of length 0."); - assert(result.end == 0, "'any' does not advance the index."); +/** + Match any character. As long as there is at least a character left in the input, it succeeds. + Conversely, it fails only if called at the end of the input. +*/ + static ParseTree any(ParseTree p) + { + if (p.end < p.input.length) + return ParseTree("any", true, [p.input[p.end..p.end+1]], p.input, p.end, p.end+1); + else + return ParseTree("any", false, ["any char"], p.input, p.end, p.end); + } - result = any(""); - assert(!result.successful, "'any' fails on strings of length 0."); - assert(result.matches == ["any char"], "'any' error message on strings of length 0."); - assert(result.end == 0, "'any' does not advance the index."); +/// ditto + static ParseTree any(string input) + { + return any(ParseTree("", false, [], input)); + } - result = any(null); - assert(!result.successful, "'any' fails on null strings."); - assert(result.matches == ["any char"], "'any' error message on strings of length 0."); - assert(result.end == 0, "'any' does not advance the index."); -} + unittest // 'any' unit test + { + ParseTree input = ParseTree("input", true, [], "This is the input string.", 0,0, null); + ParseTree result = any(input); + + assert(result.name == "any"); + assert(result.successful, "'any' succeeds on non-null strings."); + assert(result.matches == ["T"], "'any' matches the first char in an input."); + assert(result.input == input.input, "'any' does not change the input."); + assert(result.end == input.end+1, "'any' advances the index by one position."); + assert(result.children is null, "'any' has no children."); + + result = any("a"); + assert(result.successful, "'any' matches on strings of length one."); + assert(result.matches == ["a"], "'any' matches the first char in an input."); + assert(result.input == "a", "'any' does not change the input."); + assert(result.end == 1, "'any' advances the index by one position."); + assert(result.children is null, "'any' has no children."); + + input = ParseTree("input", true, [], "", 0,0, null); + + result = any(input); + assert(!result.successful, "'any' fails on strings of length 0."); + assert(result.matches == ["any char"], "'any' error message on strings of length 0."); + assert(result.end == 0, "'any' does not advance the index."); + + result = any(""); + assert(!result.successful, "'any' fails on strings of length 0."); + assert(result.matches == ["any char"], "'any' error message on strings of length 0."); + assert(result.end == 0, "'any' does not advance the index."); + + result = any(null); + assert(!result.successful, "'any' fails on null strings."); + assert(result.matches == ["any char"], "'any' error message on strings of length 0."); + assert(result.end == 0, "'any' does not advance the index."); + } /** -Predefined parser: matches word boundaries, as \b for regexes. + Predefined parser: matches word boundaries, as \b for regexes. */ -ParseTree wordBoundary(ParseTree p) -{ - // TODO: I added more indexing guards and now this could probably use - // some simplification. Too tired to write it better. --Chad - bool matched = (p.end == 0 && isAlpha(p.input.front())) - || (p.end == p.input.length && isAlpha(p.input.back())) - || (p.end > 0 && isAlpha(p.input[p.end-1]) && p.end < p.input.length && !isAlpha(p.input[p.end])) - || (p.end > 0 && !isAlpha(p.input[p.end-1]) && p.end < p.input.length && isAlpha(p.input[p.end])); - if (matched) - return ParseTree("wordBoundary", matched, [], p.input, p.end, p.end, null); - else - return ParseTree("wordBoundary", matched, ["word boundary"], p.input, p.end, p.end, null); -} + static ParseTree wordBoundary(ParseTree p) + { + // TODO: I added more indexing guards and now this could probably use + // some simplification. Too tired to write it better. --Chad + bool matched = (p.end == 0 && isAlpha(p.input.front())) + || (p.end == p.input.length && isAlpha(p.input.back())) + || (p.end > 0 && isAlpha(p.input[p.end-1]) && p.end < p.input.length && !isAlpha(p.input[p.end])) + || (p.end > 0 && !isAlpha(p.input[p.end-1]) && p.end < p.input.length && isAlpha(p.input[p.end])); + if (matched) + return ParseTree("wordBoundary", matched, [], p.input, p.end, p.end, null); + else + return ParseTree("wordBoundary", matched, ["word boundary"], p.input, p.end, p.end, null); + } /// ditto -ParseTree wordBoundary(string input) -{ - return ParseTree("wordBoundary", isAlpha(input.front()), [], input, 0,0, null); -} + static ParseTree wordBoundary(string input) + { + return ParseTree("wordBoundary", isAlpha(input.front()), [], input, 0,0, null); + } -string wordBoundary(GetName g) -{ - return "wordBoundary"; + static string wordBoundary(GetName g) + { + return "wordBoundary"; + } + + unittest // word boundary + { + ParseTree input = ParseTree("", false, [], "This is a word."); + auto wb = [// "This" + cast(size_t)(0):true, 1:false, 2:false, 3:false, 4: true, + // "is" + 5: true, 6:false, 7: true, + // "a" + 8: true, 9:true, + // "word" + 10:true, 11:false, 12:false, 13:false, 14:true, + // "." + 15:false + ]; + + foreach(size_t index; 0 .. input.input.length) + { + input.end = index; + ParseTree result = wordBoundary(input); + + assert(result.name == "wordBoundary"); + assert(result.successful == wb[index]); // true, false, ... + // for errors, there is an error message + assert(result.successful && result.matches is null || !result.successful); + assert(result.begin == input.end); + assert(result.end == input.end); + assert(result.children is null); + } + } +/** + eps matches the empty string (usually denoted by the Greek letter 'epsilon') and always succeeds. + It's equivalent to literal!"" (for example, it creates a match of [""]: one match, the empty string). +*/ + ParseTree eps(ParseTree p) + { + return ParseTree("eps", true, [""], p.input, p.end, p.end); + } + + ParseTree eps(string input) + { + return eps(ParseTree("",false,[], input)); + } + + string eps(GetName g) + { + return "eps"; + } + + unittest // 'eps' unit test + { + ParseTree input = ParseTree("input", true, [], "abcdef", 0,0, null); + + ParseTree result = eps(input); + + assert(result.name == "eps"); + assert(result.successful, "'eps' succeeds on non-null inputs."); + assert(result.matches == [""], "'eps' matches '' at the beginning."); + assert(result.input == input.input, "'eps' does not change the input."); + assert(result.end == input.end+0, "'eps' does not advance the index."); + assert(result.children is null, "'eps' has no children."); + + input.input = ""; + + result = eps(input); + assert(result.name == "eps"); + assert(result.successful, "'eps' succeeds on empty strings."); + assert(result.matches == [""], "'eps' matches '' at the beginning, even on empty strings."); + assert(result.input == input.input, "'eps' does not change the input."); + assert(result.end == input.end+0, "'eps' does not advance the index."); + assert(result.children is null, "'eps' has no children."); + } } -unittest // word boundary +/** + * Default fail message formating function + */ +static defaultFormatFailMsg(ParseTree)(Position pos, string left, string right, const ParseTree pt) { - ParseTree input = ParseTree("", false, [], "This is a word."); - auto wb = [// "This" - cast(size_t)(0):true, 1:false, 2:false, 3:false, 4: true, - // "is" - 5: true, 6:false, 7: true, - // "a" - 8: true, 9:true, - // "word" - 10:true, 11:false, 12:false, 13:false, 14:true, - // "." - 15:false - ]; + return "Failure at line " ~ to!string(pos.line) ~ ", col " ~ to!string(pos.col) ~ ", " + ~ (left.length > 0 ? "after " ~ left.stringified ~ " " : "") + ~ "expected " ~ (pt.matches.length > 0 ? pt.matches[$ - 1].stringified : "NO MATCH") + ~ `, but got ` ~ right.stringified; +}; + - foreach(size_t index; 0 .. input.input.length) - { - input.end = index; - ParseTree result = wordBoundary(input); - - assert(result.name == "wordBoundary"); - assert(result.successful == wb[index]); // true, false, ... - // for errors, there is an error message - assert(result.successful && result.matches is null || !result.successful); - assert(result.begin == input.end); - assert(result.end == input.end); - assert(result.children is null); - } -} /** -Represents a literal in a PEG, like "abc" or 'abc' (or even ''). -It succeeds if a prefix of the input is equal to its template parameter and fails otherwise. + Represents a literal in a PEG, like "abc" or 'abc' (or even ''). + It succeeds if a prefix of the input is equal to its template parameter and fails otherwise. */ -template literal(string s) +template literalT(ParseTree, string s) { enum name = "literal!(\""~s~"\")"; - ParseTree literal(ParseTree p) - { - enum lit = "\"" ~ s ~ "\""; - - if (p.end+s.length <= p.input.length && p.input[p.end..p.end+s.length] == s) - return ParseTree(name, true, [s], p.input, p.end, p.end+s.length); - else { - import std.algorithm : commonPrefix; - import std.utf : byCodeUnit; - auto prefix = p.input[p.end..$].byCodeUnit.commonPrefix(s.byCodeUnit); - return ParseTree(name, false, [lit], p.input, p.end, p.end, null, p.end + prefix.length); + ParseTree literalT(ParseTree p) + { + enum lit = "\"" ~ s ~ "\""; + + if (p.end+s.length <= p.input.length && p.input[p.end..p.end+s.length] == s) + return ParseTree(name, true, [s], p.input, p.end, p.end+s.length); + else { + import std.algorithm : commonPrefix; + import std.utf : byCodeUnit; + auto prefix = p.input[p.end..$].byCodeUnit.commonPrefix(s.byCodeUnit); + return ParseTree(name, false, [lit], p.input, p.end, p.end, null, p.end + prefix.length); + } } - } - ParseTree literal(string input) - { - return .literal!(s)(ParseTree("", false, [], input)); - } + ParseTree literalT(string input) + { + return .literalT!(ParseTree, s)(ParseTree("", false, [], input)); + } - string literal(GetName g) - { - return name; - } + string literalT(GetName g) + { + return name; + } } unittest // 'literal' unit test { + alias ParseTree = DefaultParseTree; + mixin ParseCollections!ParseTree; + ParseTree input = ParseTree("input", true, [], "abcdef", 0,0, null); alias literal!"a" a; @@ -887,38 +973,40 @@ unittest // 'literal' unit test } /** -Represents a case insensitive literal in a PEG, like "abc"i or 'abc'i (or even ''i). -It succeeds if a case insensitive comparison of a prefix of the input and its template -parameter yields no difference and fails otherwise. + Represents a case insensitive literal in a PEG, like "abc"i or 'abc'i (or even ''i). + It succeeds if a case insensitive comparison of a prefix of the input and its template + parameter yields no difference and fails otherwise. */ -template caseInsensitiveLiteral(string s) +template caseInsensitiveLiteralT(ParseTreeT, string s) { enum name = "caseInsensitiveLiteral!(\""~s~"\")"; - ParseTree caseInsensitiveLiteral(ParseTree p) - { - enum lit = "\"" ~ s ~ "\""; - if (p.end+s.length <= p.input.length && icmp(p.input[p.end..p.end+s.length], s) == 0) - return ParseTree(name, true, [s], p.input, p.end, p.end+s.length); - else - return ParseTree(name, false, [lit], p.input, p.end, p.end); - } + ParseTreeT caseInsensitiveLiteral(ParseTree p) + { + enum lit = "\"" ~ s ~ "\""; + if (p.end+s.length <= p.input.length && icmp(p.input[p.end..p.end+s.length], s) == 0) + return ParseTree(name, true, [s], p.input, p.end, p.end+s.length); + else + return ParseTree(name, false, [lit], p.input, p.end, p.end); + } - ParseTree caseInsensitiveLiteral(string input) - { - return .caseInsensitiveLiteral!(s)(ParseTree("", false, [], input)); - } + ParseTreeT caseInsensitiveLiteral(string input) + { + return .caseInsensitiveLiteral!(s)(ParseTree("", false, [], input)); + } string caseInsensitiveLiteral(GetName g) - { - return name; - } + { + return name; + } } unittest // 'caseInsensitiveLiteral' unit test { + alias ParseTree = DefaultParseTree; + mixin ParseCollections!ParseTree; ParseTree input = ParseTree("input", true, [], "AbCdEf", 0,0, null); alias caseInsensitiveLiteral!"a" a; @@ -1035,40 +1123,43 @@ unittest // 'caseInsensitiveLiteral' unit test } /** -Represents a range of chars, from begin to end, included. So charRange!('a','z') matches -all English lowercase letters. If fails if the input is empty or does not begin with a character -between begin and end. + Represents a range of chars, from begin to end, included. So charRange!('a','z') matches + all English lowercase letters. If fails if the input is empty or does not begin with a character + between begin and end. -If begin == end, it will match one char (begin... or end). + If begin == end, it will match one char (begin... or end). -begin > end is non-legal. + begin > end is non-legal. */ -template charRange(dchar begin, dchar end) if (begin <= end) +template charRangeT(ParseTree, dchar begin, dchar end) if (begin <= end) { enum name = "charRange!('"~to!string(begin)~"','" ~ to!string(end) ~ "')"; - ParseTree charRange(ParseTree p) - { - enum longname = "a char between '"~to!string(begin)~"' and '"~to!string(end)~"'"; - if (p.end < p.input.length && p.input[p.end] >= begin && p.input[p.end] <= end) - return ParseTree(name, true, [p.input[p.end..p.end+1]], p.input, p.end, p.end+1); - else - return ParseTree(name, false, [longname], p.input, p.end, p.end); - } + ParseTree charRangeT(ParseTree p) + { + enum longname = "a char between '"~to!string(begin)~"' and '"~to!string(end)~"'"; + if (p.end < p.input.length && p.input[p.end] >= begin && p.input[p.end] <= end) + return ParseTree(name, true, [p.input[p.end..p.end+1]], p.input, p.end, p.end+1); + else + return ParseTree(name, false, [longname], p.input, p.end, p.end); + } - ParseTree charRange(string input) - { - return .charRange!(begin,end)(ParseTree("",false,[],input)); - } + ParseTree charRangeT(string input) + { + return .charRangeT!(ParseTree, begin, end)(ParseTree("",false,[],input)); + } - string charRange(GetName g) - { - return name; - } + string charRangeT(GetName g) + { + return name; + } } unittest // 'charRange' unit test { + alias ParseTree = DefaultParseTree; + mixin ParseCollections!ParseTree; + ParseTree input = ParseTree("input", true, [], "abcdef", 0,0, null); alias charRange!('a','a') aa; @@ -1192,210 +1283,166 @@ unittest // 'charRange' unit test } /** -eps matches the empty string (usually denoted by the Greek letter 'epsilon') and always succeeds. -It's equivalent to literal!"" (for example, it creates a match of [""]: one match, the empty string). + Basic operator: it matches if all its subrules (stored in the rules template parameter tuple) match + the input successively. Its subrules parse trees are stored as its children and its matches field + will contain all its subrules matches, in order. + + ---- + alias and!(literal!"abc", charRange!('a','z')) rule; // abc followed by any letter between a and z. + ParseTree input = ParseTree("",false,[],"abcd"); // low-level plumbing, + // the rules described here act on ParseTree's not strings. + // It's equivalent to "abcd" as input + auto result = rule(input); + + assert(result.successful); // OK, 'abc' followed by 'd' + assert(result.matches == ["abc", "d"]); // stores the matches + assert(result.children.length == 2); // two children, the result of "abc" on "abcd" and the result of [a-z] on "d" + + input.input = "abc"; // changing the input string; + assert(!rule(input)).successful); // NOK, abc alone + input.input = "ab"; + assert(!rule(input)).successful); // NOK, does not begin by abc + ---- + + If it fails, the last children will contain the failed node. That way, when printing, as sort of diagnostic is given: + + ---- + alias and!(literal!"abc", charRange!('a','z')) rule; // 'abc[a-z]', aka 'abc' followed by any letter between 'a' and 'z'. + ParseTree input = ParseTree("",false,[],"abc1"); // equivalent to "abc1" + + auto failure = rule(input); + writeln(failure); + /+ + writes: + and (failure) + +-literal(abc) [0, 3]["abc"] + +-charRange(a,z) failure at line 0, col 3, after "abc" a char between 'a' and 'z', but got "1" + +/ + ---- + + So we know the global 'and' failed, that the first sub-rule ('abc') succeeded on input[0..3] with "abc" + and that the second subrule ('[a-z]') failed at position 3 (so, on '1'). */ -ParseTree eps(ParseTree p) -{ - return ParseTree("eps", true, [""], p.input, p.end, p.end); -} - -ParseTree eps(string input) -{ - return eps(ParseTree("",false,[], input)); -} - -string eps(GetName g) -{ - return "eps"; -} - -unittest // 'eps' unit test -{ - ParseTree input = ParseTree("input", true, [], "abcdef", 0,0, null); - - ParseTree result = eps(input); - - assert(result.name == "eps"); - assert(result.successful, "'eps' succeeds on non-null inputs."); - assert(result.matches == [""], "'eps' matches '' at the beginning."); - assert(result.input == input.input, "'eps' does not change the input."); - assert(result.end == input.end+0, "'eps' does not advance the index."); - assert(result.children is null, "'eps' has no children."); - - input.input = ""; - - result = eps(input); - assert(result.name == "eps"); - assert(result.successful, "'eps' succeeds on empty strings."); - assert(result.matches == [""], "'eps' matches '' at the beginning, even on empty strings."); - assert(result.input == input.input, "'eps' does not change the input."); - assert(result.end == input.end+0, "'eps' does not advance the index."); - assert(result.children is null, "'eps' has no children."); -} - - -/** -Basic operator: it matches if all its subrules (stored in the rules template parameter tuple) match -the input successively. Its subrules parse trees are stored as its children and its matches field -will contain all its subrules matches, in order. - ----- -alias and!(literal!"abc", charRange!('a','z')) rule; // abc followed by any letter between a and z. -ParseTree input = ParseTree("",false,[],"abcd"); // low-level plumbing, - // the rules described here act on ParseTree's not strings. - // It's equivalent to "abcd" as input -auto result = rule(input); - -assert(result.successful); // OK, 'abc' followed by 'd' -assert(result.matches == ["abc", "d"]); // stores the matches -assert(result.children.length == 2); // two children, the result of "abc" on "abcd" and the result of [a-z] on "d" - -input.input = "abc"; // changing the input string; -assert(!rule(input)).successful); // NOK, abc alone -input.input = "ab"; -assert(!rule(input)).successful); // NOK, does not begin by abc ----- - -If it fails, the last children will contain the failed node. That way, when printing, as sort of diagnostic is given: - ----- -alias and!(literal!"abc", charRange!('a','z')) rule; // 'abc[a-z]', aka 'abc' followed by any letter between 'a' and 'z'. -ParseTree input = ParseTree("",false,[],"abc1"); // equivalent to "abc1" - -auto failure = rule(input); -writeln(failure); -/+ -writes: -and (failure) - +-literal(abc) [0, 3]["abc"] - +-charRange(a,z) failure at line 0, col 3, after "abc" a char between 'a' and 'z', but got "1" -+/ ----- - -So we know the global 'and' failed, that the first sub-rule ('abc') succeeded on input[0..3] with "abc" -and that the second subrule ('[a-z]') failed at position 3 (so, on '1'). -*/ -template and(rules...) if (rules.length > 0) +template andT(ParseTree, rules...) if (rules.length > 0) { string ctfeGetNameAnd() - { - string name = "and!("; - foreach(i,rule; rules) - name ~= __traits(identifier, rule) // because using getName!(rule) causes an infinite loop during compilation - // for recursive rules + { + string name = "and!("; + foreach(i,rule; rules) + name ~= __traits(identifier, rule) // because using getName!(rule) causes an infinite loop during compilation + // for recursive rules ~ (i < rules.length -1 ? ", " : ""); - name ~= ")"; - return name; - } + name ~= ")"; + return name; + } enum name = ctfeGetNameAnd(); - ParseTree and(ParseTree p) - { - bool keepNode(ParseTree node) - { - return node.name.startsWith("keep!(") - || ( !node.name.startsWith("discard!(") - //&& !node.name.startsWith("drop!(") - && (node.matches !is null - || node.failEnd >= node.end) - //&& node.begin != node.end - ); - } - - version (tracer) + ParseTree andT(ParseTree p) { - incTraceLevel(); - } - - ParseTree result = ParseTree(name, false, [], p.input, p.end, p.end, []); + bool keepNode(ParseTree node) + { + return node.name.startsWith("keep!(") + || ( !node.name.startsWith("discard!(") + //&& !node.name.startsWith("drop!(") + && (node.matches !is null + || node.failEnd >= node.end) + //&& node.begin != node.end + ); + } - foreach(i,r; rules) - { version (tracer) { - if (shouldTrace(getName!(r)(), p)) - trace(traceMsg(result, name, getName!(r)())); + incTraceLevel(); } - ParseTree temp = r(result); - result.end = temp.end; - result.failEnd = max(result.failEnd, temp.failEnd); - if (temp.successful) + + ParseTree result = ParseTree(name, false, [], p.input, p.end, p.end, []); + + foreach(i,r; rules) { - if (keepNode(temp)) + version (tracer) { - result.matches ~= temp.matches; - if (temp.name.startsWith("drop!(")) - {} - else if (temp.name.startsWith("propagate!(")) - result.children ~= temp.children; - else - result.children ~= temp; + if (shouldTrace(getName!(r)(), p)) + trace(traceMsg(result, name, getName!(r)())); } - } - else - { - 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) - result.matches ~= temp.matches[$-1]; - } else { - // don't add the failed node because a previous one already failed further back - result.children = result.children[0 .. firstLongestFailedMatch+1]; // discard any intermediate correct nodes - // This current 'and' rule has failed parsing and there is a successful child - // that had a longer failing match. We now want to revisit that child and modify it - // 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); + ParseTree temp = r(result); + result.end = temp.end; + result.failEnd = max(result.failEnd, temp.failEnd); + if (temp.successful) + { + if (keepNode(temp)) + { + result.matches ~= temp.matches; + if (temp.name.startsWith("drop!(")) + {} + else if (temp.name.startsWith("propagate!(")) + result.children ~= temp.children; + else + result.children ~= temp; + } } - result.end = result.children.maxEnd(); - result.failEnd = result.children.maxFailEnd(); - version (tracer) + else { - if (shouldTrace(getName!(r)(), p)) - trace(traceResultMsg(result, getName!(r)())); - decTraceLevel(); + 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) + result.matches ~= temp.matches[$-1]; + } else { + // don't add the failed node because a previous one already failed further back + result.children = result.children[0 .. firstLongestFailedMatch+1]; // discard any intermediate correct nodes + // This current 'and' rule has failed parsing and there is a successful child + // that had a longer failing match. We now want to revisit that child and modify it + // 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.maxEnd(); + result.failEnd = result.children.maxFailEnd(); + version (tracer) + { + if (shouldTrace(getName!(r)(), p)) + trace(traceResultMsg(result, getName!(r)())); + decTraceLevel(); + } + return result; // and end the parsing attempt right there } - return result; // and end the parsing attempt right there } + result.successful = true; + version (tracer) + { + foreach(i, r; rules) + if (shouldTrace(getName!(r)(), p)) + { + trace(traceResultMsg(result, name)); + break; + } + decTraceLevel(); + } + return result; } - result.successful = true; - version (tracer) + + ParseTree andT(string input) { - foreach(i, r; rules) - if (shouldTrace(getName!(r)(), p)) - { - trace(traceResultMsg(result, name)); - break; - } - decTraceLevel(); + return .andT!(ParseTree, rules)(ParseTree("",false,[],input)); } - return result; - } - ParseTree and(string input) - { - return .and!(rules)(ParseTree("",false,[],input)); - } - - string and(GetName g) - { - return name; - } + string andT(GetName g) + { + return name; + } } -auto firstLongestFailedMatch(ParseTree[] children, size_t threshold) { +auto firstLongestFailedMatch(ParseTreeT)(ParseTreeT[] children, size_t threshold) { return children.countUntil!(c => c.failEnd > threshold); } -auto maxFailEnd(ParseTree[] children) +auto maxFailEnd(ParseTreeT)(ParseTreeT[] children) { return children.map!(c => c.failEnd).maxElement; } -auto maxEnd(ParseTree[] children) +auto maxEnd(ParseTreeT)(ParseTreeT[] children) { return children.map!(c => c.end).maxElement; } @@ -1405,7 +1452,7 @@ auto maxEnd(ParseTree[] children) // 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) +bool failedChildFixup(ParseTreeT)(ref ParseTreeT p, size_t failEnd) { if (p.failedChild.length > 0) { @@ -1437,6 +1484,8 @@ bool failedChildFixup(ref ParseTree p, size_t failEnd) unittest // 'and' unit test { + alias ParseTree = DefaultParseTree; + mixin ParseCollections!ParseTree; alias literal!"abc" abc; alias literal!"de" de; alias literal!"f" f; @@ -1463,27 +1512,27 @@ unittest // 'and' unit test assert(result.successful, "and!('abc','de') parses 'abcdefghi'"); assert(result.matches == ["abc","de"], - "and!('abc','de') matches 'abc' and 'de' at the beginning of 'abcdefghi'"); + "and!('abc','de') matches 'abc' and 'de' at the beginning of 'abcdefghi'"); assert(result.end == input.end+5, "and!('abc','de') advances the index by 3+2 positions."); assert(result.children == [abc(input), de(abc(input))], - "and!('abc','de') has two children, created by 'abc' and 'de'."); + "and!('abc','de') has two children, created by 'abc' and 'de'."); result = abcdef(input); assert(result.successful, "and!('abc','de','f') parses 'abcdefghi'"); assert(result.matches == ["abc","de","f"], - "and!('abc','de','f') matches 'abcdef' at the beginning of 'abcdefghi'"); + "and!('abc','de','f') matches 'abcdef' at the beginning of 'abcdefghi'"); assert(result.end == input.end+6, "and!('abc','de','f') advances the index by 3+2+1 positions."); assert(result.children == [abc(input), de(abc(input)), f(de(abc(input)))] - , "and!('abc','de') has two children, created by 'abc' and 'de'."); + , "and!('abc','de') has two children, created by 'abc' and 'de'."); result = withEps(input); assert(result.successful, "and!('','abc','','de','','f','') parses 'abcdefghi'"); assert(result.matches == ["","abc","","de","","f",""], - "and!('','abc','','de','','f','') matches 'abcdef' at the beginning of 'abcdefghi'"); + "and!('','abc','','de','','f','') matches 'abcdef' at the beginning of 'abcdefghi'"); assert(result.end == input.end+6, - "and!('','abc','','de','','f','') advances the index by 0+3+0+2+0+1+0 positions."); + "and!('','abc','','de','','f','') advances the index by 0+3+0+2+0+1+0 positions."); input.input = "bcdefghi"; @@ -1502,7 +1551,7 @@ unittest // 'and' unit test //assert(result.matches == ["abc"], "Only the first match, from 'abc'."); assert(result.end == input.end+3, "Advances by 3 positions, due to 'abc'"); assert(result.children == [abc(input), de(abc(input))] - , "'abc' 'de' 'f' has two child on 'abc_efghi', the one from 'abc' (success) and the one from 'de' (failure)."); + , "'abc' 'de' 'f' has two child on 'abc_efghi', the one from 'abc' (success) and the one from 'de' (failure)."); } version (unittest) { @@ -1515,6 +1564,9 @@ version (unittest) { unittest // 'and' unit test with zeroOrMore and longest failing match { + alias ParseTree = DefaultParseTree; + mixin ParseCollections!ParseTree; + alias literal!"abc" A; alias literal!"def" B; alias literal!"ghi" C; @@ -1531,6 +1583,9 @@ unittest // 'and' unit test with zeroOrMore and longest failing match unittest // 'and' unit test with option and longest failing match { + alias ParseTree = DefaultParseTree; + mixin ParseCollections!ParseTree; + alias literal!"abc" A; alias literal!"def" B; alias literal!"ghi" C; @@ -1547,6 +1602,9 @@ unittest // 'and' unit test with option and longest failing match unittest // 'and' unit test with oneOrMore and longest failing match { + alias ParseTree = DefaultParseTree; + mixin ParseCollections!ParseTree; + alias literal!"abc" A; alias literal!"def" B; alias literal!"ghi" C; @@ -1561,216 +1619,219 @@ unittest // 'and' unit test with oneOrMore and longest failing match assert(result.matches == ["abc", "def"]); } -template wrapAround(alias before, alias target, alias after) +template wrapAroundT(ParseTree, alias before, alias target, alias after) { ParseTree wrapAround(ParseTree p) - { - ParseTree temp = before(p); - if (!temp.successful) - return temp; + { + ParseTree temp = before(p); + if (!temp.successful) + return temp; - ParseTree result = target(temp); - if (!result.successful) - return result; - result.begin = temp.begin; + ParseTree result = target(temp); + if (!result.successful) + return result; + result.begin = temp.begin; - temp = after(result); - if (!temp.successful) - return temp; + temp = after(result); + if (!temp.successful) + return temp; - result.end = temp.end; - return result; - } + result.end = temp.end; + return result; + } ParseTree wrapAround(string input) - { - return .wrapAround!(before, target, after)(ParseTree("",false,[],input)); - } + { + return .wrapAround!(before, target, after)(ParseTree("",false,[],input)); + } string wrapAround(GetName g) - { - return "wrapAround!(" ~ getName!(before)() ~ - ", " ~ getName!(target)() ~ - ", " ~ getName!(after)() ~ ")"; - } -} - -/** -Basic operator: it matches if one of its subrules (stored in the rules template parameter tuple) match -the input. The subrules are tested in order, from rules[0] to rules[$-1]. - -The matching subrule parse trees is stored as its only child and its matches field -will contain all the subrule matches, in order. - ----- -alias or!(literal!"abc", charRange!('a','z')) rule; // abc or, failing that, any letter between a and z. -ParseTree input = ParseTree("",false,[],"defg"); // low-level plumbing, the rules described here act on ParseTree's not strings. - // It's equivalent to "defg" as input -auto result = rule(input); - -assert(result.successful); // OK -assert(result.matches == ["d"]); // stores the (in this case) only match -assert(result.children.length == 1); // one child, the result of "abc" or [a-z], depending on which rule succeeded. - -input.input = "abc"; // changing the input string; -assert(rule(input)).successful); // Still OK -input.input = "1abc"; -assert(!rule(input)).successful); // NOK, does not begin by abc nor by [a-z] ----- - -If it fails, the last children will contain the failed node that matched furthest (longes match). -That way, when printing, as sort of diagnostic is given: - ----- -alias or!(literal!"abc", and!(literal!"ab", charRange!('0','9'))) rule; // 'abc' or 'ab[0-9]' -ParseTree input = ParseTree("",false,[],"abd"); // equivalent to "abd" - -auto failure = rule(input); -writeln(failure); -/+ -or (failure) - +-and (failure) - +-literal(ab) [0, 2]["ab"] - +-charRange(0,9) failure at line 0, col 2, after "ab" expected a char between '0' and '9', but got "d" -+/ ----- + { + return "wrapAround!(" ~ getName!(before)() ~ + ", " ~ getName!(target)() ~ + ", " ~ getName!(after)() ~ ")"; + } +} -So we know 'or' failed, that the 'and' sub-rule had the longest match, matching 'ab' and failing for [0-9] on index 2. +/** + Basic operator: it matches if one of its subrules (stored in the rules template parameter tuple) match + the input. The subrules are tested in order, from rules[0] to rules[$-1]. + + The matching subrule parse trees is stored as its only child and its matches field + will contain all the subrule matches, in order. + + ---- + alias or!(literal!"abc", charRange!('a','z')) rule; // abc or, failing that, any letter between a and z. + ParseTree input = ParseTree("",false,[],"defg"); // low-level plumbing, the rules described here act on ParseTree's not strings. + // It's equivalent to "defg" as input + auto result = rule(input); + + assert(result.successful); // OK + assert(result.matches == ["d"]); // stores the (in this case) only match + assert(result.children.length == 1); // one child, the result of "abc" or [a-z], depending on which rule succeeded. + + input.input = "abc"; // changing the input string; + assert(rule(input)).successful); // Still OK + input.input = "1abc"; + assert(!rule(input)).successful); // NOK, does not begin by abc nor by [a-z] + ---- + + If it fails, the last children will contain the failed node that matched furthest (longes match). + That way, when printing, as sort of diagnostic is given: + + ---- + alias or!(literal!"abc", and!(literal!"ab", charRange!('0','9'))) rule; // 'abc' or 'ab[0-9]' + ParseTree input = ParseTree("",false,[],"abd"); // equivalent to "abd" + + auto failure = rule(input); + writeln(failure); + /+ + or (failure) + +-and (failure) + +-literal(ab) [0, 2]["ab"] + +-charRange(0,9) failure at line 0, col 2, after "ab" expected a char between '0' and '9', but got "d" + +/ + ---- + + So we know 'or' failed, that the 'and' sub-rule had the longest match, matching 'ab' and failing for [0-9] on index 2. */ -template or(rules...) if (rules.length > 0) +template orT(ParseTree, rules...) if (rules.length > 0) { string ctfeGetNameOr() - { - string name = "or!("; - foreach(i,rule; rules) - name ~= getName!(rule) + { + string name = "or!("; + foreach(i,rule; rules) + name ~= getName!(rule) ~ (i < rules.length -1 ? ", " : ""); - name ~= ")"; - return name; - } + name ~= ")"; + return name; + } enum name = ctfeGetNameOr(); - ParseTree or(ParseTree p) - { - // error-management - ParseTree longestFail = ParseTree(name, false, [], p.input, p.end, 0); - string[] errorStrings; - size_t errorStringChars; - string orErrorString; - - ParseTree[rules.length] results; - string[rules.length] names; - size_t[rules.length] failedLength; - size_t maxFailedLength; - - version (tracer) + ParseTree orT(ParseTree p) { - incTraceLevel(); - } + // error-management + ParseTree longestFail = ParseTree(name, false, [], p.input, p.end, 0); + string[] errorStrings; + size_t errorStringChars; + string orErrorString; + + ParseTree[rules.length] results; + string[rules.length] names; + size_t[rules.length] failedLength; + size_t maxFailedLength; - // Real 'or' loop - foreach(i,r; rules) - { version (tracer) { - if (shouldTrace(getName!(r)(), p)) - trace(traceMsg(p, name, getName!(r)())); + incTraceLevel(); } - ParseTree temp = r(p); - if (temp.successful) + + // Real 'or' loop + foreach(i,r; rules) { - temp.children = [temp]; - temp.name = name; - // if there is a child that failed but parsed more - if (longestFail.failEnd > temp.end) { - temp.failEnd = longestFail.failEnd; - temp.failedChild = [longestFail]; - } version (tracer) { if (shouldTrace(getName!(r)(), p)) - trace(traceResultMsg(temp, getName!(r)())); - decTraceLevel(); + trace(traceMsg(p, name, getName!(r)())); } - return temp; - } - else - { - version (tracer) + ParseTree temp = r(p); + if (temp.successful) { - if (shouldTrace(getName!(r)(), p)) - trace(traceResultMsg(temp, getName!(r)())); + temp.children = [temp]; + temp.name = name; + // if there is a child that failed but parsed more + if (longestFail.failEnd > temp.end) { + temp.failEnd = longestFail.failEnd; + temp.failedChild = [longestFail]; + } + version (tracer) + { + if (shouldTrace(getName!(r)(), p)) + trace(traceResultMsg(temp, getName!(r)())); + decTraceLevel(); + } + return temp; } - enum errName = " (" ~ getName!(r)() ~")"; - failedLength[i] = temp.end; - if (temp.end >= longestFail.end) + else { - if (temp.end == longestFail.end) - errorStringChars += (temp.matches.length > 0 ? temp.matches[$-1].length : 0) + errName.length + 4; - else - errorStringChars = (temp.matches.length > 0 ? temp.matches[$-1].length : 0) + errName.length + 4; - maxFailedLength = temp.end; - longestFail = temp; - names[i] = errName; - results[i] = temp; - + version (tracer) + { + if (shouldTrace(getName!(r)(), p)) + trace(traceResultMsg(temp, getName!(r)())); + } + enum errName = " (" ~ getName!(r)() ~")"; + failedLength[i] = temp.end; + if (temp.end >= longestFail.end) + { + if (temp.end == longestFail.end) + errorStringChars += (temp.matches.length > 0 ? temp.matches[$-1].length : 0) + errName.length + 4; + else + errorStringChars = (temp.matches.length > 0 ? temp.matches[$-1].length : 0) + errName.length + 4; + maxFailedLength = temp.end; + longestFail = temp; + names[i] = errName; + results[i] = temp; + + } + // Else, this error parsed less input than another one: we discard it. } - // Else, this error parsed less input than another one: we discard it. } - } - version (tracer) - { - decTraceLevel(); - } + version (tracer) + { + decTraceLevel(); + } - // All subrules failed, we will take the longest match as the result - // If more than one node failed at the same (farthest) position, we concatenate their error messages + // All subrules failed, we will take the longest match as the result + // If more than one node failed at the same (farthest) position, we concatenate their error messages - char[] errString;// = new char[](errorStringChars); - errString.length = errorStringChars; - uint start = 0; - foreach(i; 0..rules.length) - { - if (failedLength[i] == maxFailedLength && results[i].matches.length > 0) + char[] errString;// = new char[](errorStringChars); + errString.length = errorStringChars; + uint start = 0; + foreach(i; 0..rules.length) { - auto temp = results[i]; - auto len = temp.matches[$-1].length; - auto nlen = names[i].length; - errString[start .. start+len] = temp.matches[$-1][]; - errString[start+len .. start+len+names[i].length] = names[i][]; - errString[start+len+nlen .. start+len+nlen+4] = " or "; - start += len + names[i].length + 4; + if (failedLength[i] == maxFailedLength && results[i].matches.length > 0) + { + auto temp = results[i]; + auto len = temp.matches[$-1].length; + auto nlen = names[i].length; + errString[start .. start+len] = temp.matches[$-1][]; + errString[start+len .. start+len+names[i].length] = names[i][]; + errString[start+len+nlen .. start+len+nlen+4] = " or "; + start += len + names[i].length + 4; + } } - } - orErrorString = cast(string)(errString[0..$-4]); + orErrorString = cast(string)(errString[0..$-4]); - 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[].getUpto(maxFailedLength); - return ParseTree(name, false, longestFail.matches, p.input, p.end, longestFail.end, children, children.maxFailEnd); - } + 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[].getUpto(maxFailedLength); + return ParseTree(name, false, longestFail.matches, p.input, p.end, longestFail.end, children, children.maxFailEnd); + } - ParseTree or(string input) - { - return .or!(rules)(ParseTree("",false,[],input)); - } + ParseTree orT(string input) + { + return orT!(ParseTree,rules)(ParseTree("",false,[],input)); + } - string or(GetName g) - { - return name; - } + string orT(GetName g) + { + return name; + } } -auto getUpto(ParseTree[] children, size_t minFailedLength) { +auto getUpto(ParseTreeT)(ParseTreeT[] children, size_t minFailedLength) { return children.filter!(r => max(r.end, r.failEnd) >= minFailedLength).array(); } unittest // 'or' unit test { + alias ParseTree = DefaultParseTree; + mixin ParseCollections!ParseTree; + alias charRange!('a','b') ab; alias charRange!('c','d') cd; @@ -1817,8 +1878,8 @@ unittest // 'or' unit test assert(!result.successful, "or!([a-b],[c-d]) fails on '_abcdefghi'"); assert(result.end == input.end+0, "or!([a-b],[c-d]) does not advance the index."); assert(result.matches == - [ "a char between 'a' and 'b' (charRange!('a','b')) or a char between 'c' and 'd' (charRange!('c','d'))"] - , "or!([a-b],[c-d]) error message. |" ~ result.matches[0]~ "|"); + [ "a char between 'a' and 'b' (charRange!('a','b')) or a char between 'c' and 'd' (charRange!('c','d'))"] + , "or!([a-b],[c-d]) error message. |" ~ result.matches[0]~ "|"); input.input = ""; @@ -1827,142 +1888,145 @@ unittest // 'or' unit test assert(!result.successful, "or!([a-b],[c-d]) fails on and empty input"); assert(result.end == input.end+0, "or!([a-b],[c-d]) does not advance the index."); assert(result.matches == - [ "a char between 'a' and 'b' (charRange!('a','b')) or a char between 'c' and 'd' (charRange!('c','d'))"] - , "or!([a-b],[c-d]) error message."); + [ "a char between 'a' and 'b' (charRange!('a','b')) or a char between 'c' and 'd' (charRange!('c','d'))"] + , "or!([a-b],[c-d]) error message."); } /** -Basic operator: it matches if one of its subrules (stored in the rules template parameter tuple) match -the input. All subrules are tested and the one producing the longest match is taken. + Basic operator: it matches if one of its subrules (stored in the rules template parameter tuple) match + the input. All subrules are tested and the one producing the longest match is taken. -The longest matching subrule's parse tree is stored as its only child and its matches field -will contain all the subrule matches, in order. + The longest matching subrule's parse tree is stored as its only child and its matches field + will contain all the subrule matches, in order. */ -template longest_match(rules...) if (rules.length > 0) +template longest_matchT(ParseTreeT, rules...) if (rules.length > 0) { string ctfeGetNameOr() - { - string name = "longest_match!("; - foreach(i,rule; rules) - name ~= getName!(rule) + { + string name = "longest_match!("; + foreach(i,rule; rules) + name ~= getName!(rule) ~ (i < rules.length -1 ? ", " : ""); - name ~= ")"; - return name; - } + name ~= ")"; + return name; + } enum name = ctfeGetNameOr(); - ParseTree longest_match(ParseTree p) - { - // error-management - ParseTree longest, longestFail = ParseTree(name, false, [], p.input, p.end, 0); - string[] errorStrings; - size_t errorStringChars; - string orErrorString; - - ParseTree[rules.length] results; - string[rules.length] names; - size_t[rules.length] failedLength; - size_t maxFailedLength; - - version (tracer) + ParseTreeT longest_match(ParseTreeT p) { - incTraceLevel(); - } + // error-management + ParseTreeT longest, longestFail = ParseTreeT(name, false, [], p.input, p.end, 0); + string[] errorStrings; + size_t errorStringChars; + string orErrorString; + + ParseTreeT[rules.length] results; + string[rules.length] names; + size_t[rules.length] failedLength; + size_t maxFailedLength; - // Real 'longest_match' loop - foreach(i,r; rules) - { version (tracer) { - if (shouldTrace(getName!(r)(), p)) - trace(traceMsg(p, name, getName!(r)())); + incTraceLevel(); + } + + // Real 'longest_match' loop + foreach(i,r; rules) + { + version (tracer) + { + if (shouldTrace(getName!(r)(), p)) + trace(traceMsg(p, name, getName!(r)())); + } + ParseTreeT temp = r(p); + version (tracer) + { + if (shouldTrace(getName!(r)(), p)) + trace(traceResultMsg(temp, getName!(r)())); + } + + if (temp.successful) + { + if (temp.end > longest.end) + longest = temp; + // Else, this rule parsed less input than another one: we discard it. + } + else + { + enum errName = " (" ~ getName!(r)() ~")"; + failedLength[i] = temp.end; + if (temp.end >= longestFail.end) + { + maxFailedLength = temp.end; + longestFail = temp; + names[i] = errName; + results[i] = temp; + + if (temp.end == longestFail.end) + errorStringChars += (temp.matches.length > 0 ? temp.matches[$-1].length : 0) + errName.length + 4; + else + errorStringChars = (temp.matches.length > 0 ? temp.matches[$-1].length : 0) + errName.length + 4; + } + // Else, this error parsed less input than another one: we discard it. + } } - ParseTree temp = r(p); version (tracer) { - if (shouldTrace(getName!(r)(), p)) - trace(traceResultMsg(temp, getName!(r)())); + decTraceLevel(); } - - if (temp.successful) + if (longest.successful) { - if (temp.end > longest.end) - longest = temp; - // Else, this rule parsed less input than another one: we discard it. + longest.children = [longest]; + longest.name = name; + return longest; } - else + + // All subrules failed, we will take the longest match as the result + // If more than one node failed at the same (farthest) position, we concatenate their error messages + + char[] errString;// = new char[](errorStringChars); + errString.length = errorStringChars; + uint start = 0; + foreach(i; 0..rules.length) { - enum errName = " (" ~ getName!(r)() ~")"; - failedLength[i] = temp.end; - if (temp.end >= longestFail.end) + if (failedLength[i] == maxFailedLength && results[i].matches.length > 0) { - maxFailedLength = temp.end; - longestFail = temp; - names[i] = errName; - results[i] = temp; - - if (temp.end == longestFail.end) - errorStringChars += (temp.matches.length > 0 ? temp.matches[$-1].length : 0) + errName.length + 4; - else - errorStringChars = (temp.matches.length > 0 ? temp.matches[$-1].length : 0) + errName.length + 4; + auto temp = results[i]; + auto len = temp.matches[$-1].length; + auto nlen = names[i].length; + errString[start .. start+len] = temp.matches[$-1][]; + errString[start+len .. start+len+names[i].length] = names[i][]; + errString[start+len+nlen .. start+len+nlen+4] = " or "; + start += len + names[i].length + 4; } - // Else, this error parsed less input than another one: we discard it. } + orErrorString = cast(string)(errString[0..$-4]); + + longestFail.matches = longestFail.matches.length == 0 ? [orErrorString] : + longestFail.matches[0..$-1] // discarding longestFail error message + ~ [orErrorString]; // and replacing it by the new, concatenated one. + longestFail.name = name; + longestFail.begin = p.end; + return longestFail; } - version (tracer) - { - decTraceLevel(); - } - if (longest.successful) - { - longest.children = [longest]; - longest.name = name; - return longest; - } - - // All subrules failed, we will take the longest match as the result - // If more than one node failed at the same (farthest) position, we concatenate their error messages - char[] errString;// = new char[](errorStringChars); - errString.length = errorStringChars; - uint start = 0; - foreach(i; 0..rules.length) + ParseTreeT longest_match(string input) { - if (failedLength[i] == maxFailedLength && results[i].matches.length > 0) - { - auto temp = results[i]; - auto len = temp.matches[$-1].length; - auto nlen = names[i].length; - errString[start .. start+len] = temp.matches[$-1][]; - errString[start+len .. start+len+names[i].length] = names[i][]; - errString[start+len+nlen .. start+len+nlen+4] = " or "; - start += len + names[i].length + 4; - } + return .or!(rules)(ParseTreeT("",false,[],input)); } - orErrorString = cast(string)(errString[0..$-4]); - - longestFail.matches = longestFail.matches.length == 0 ? [orErrorString] : - longestFail.matches[0..$-1] // discarding longestFail error message - ~ [orErrorString]; // and replacing it by the new, concatenated one. - longestFail.name = name; - longestFail.begin = p.end; - return longestFail; - } - - ParseTree longest_match(string input) - { - return .or!(rules)(ParseTree("",false,[],input)); - } string longest_match(GetName g) - { - return name; - } + { + return name; + } } unittest // 'longest_match' unit test { + alias ParseTree = DefaultParseTree; + mixin ParseCollections!ParseTree; + alias charRange!('a','b') ab; alias charRange!('c','d') cd; @@ -2011,8 +2075,8 @@ unittest // 'longest_match' unit test assert(!result.successful, "longest_match!([a-b],[c-d]) fails on '_abcdefghi'"); assert(result.end == input.end+0, "longest_match!([a-b],[c-d]) does not advance the index."); assert(result.matches == - [ "a char between 'a' and 'b' (charRange!('a','b')) or a char between 'c' and 'd' (charRange!('c','d'))"] - , "longest_match!([a-b],[c-d]) error message. |" ~ result.matches[0]~ "|"); + [ "a char between 'a' and 'b' (charRange!('a','b')) or a char between 'c' and 'd' (charRange!('c','d'))"] + , "longest_match!([a-b],[c-d]) error message. |" ~ result.matches[0]~ "|"); input.input = ""; @@ -2021,8 +2085,8 @@ unittest // 'longest_match' unit test assert(!result.successful, "longest_match!([a-b],[c-d]) fails on and empty input"); assert(result.end == input.end+0, "longest_match!([a-b],[c-d]) does not advance the index."); assert(result.matches == - [ "a char between 'a' and 'b' (charRange!('a','b')) or a char between 'c' and 'd' (charRange!('c','d'))"] - , "longest_match!([a-b],[c-d]) error message."); + [ "a char between 'a' and 'b' (charRange!('a','b')) or a char between 'c' and 'd' (charRange!('c','d'))"] + , "longest_match!([a-b],[c-d]) error message."); // Now test longest match behaviour: @@ -2035,7 +2099,7 @@ unittest // 'longest_match' unit test /** -Compile-time switch trie from Brian Schott + Compile-time switch trie from Brian Schott */ class Trie(V) : TrieNode!(V) { @@ -2082,11 +2146,11 @@ string printCaseStatements(V)(TrieNode!(V) node, string indentString) put("case '"); switch(k) { - case '\n': append("\\n"); break; - case '\t': append("\\t"); break; - case '\r': append("\\r"); break; - case 92: append("\\"); break; - default: append(to!string(k)); + case '\n': append("\\n"); break; + case '\t': append("\\t"); break; + case '\r': append("\\r"); break; + case 92: append("\\"); break; + default: append(to!string(k)); } append("':\n"); incIndent(); @@ -2147,86 +2211,89 @@ string generateCaseTrie(string[] args ...) } /** -or special case for literal list ("abstract"/"alias"/...) + or special case for literal list ("abstract"/"alias"/...) */ -template keywords(kws...) if (kws.length > 0) +template keywordsT(ParseTree,kws...) if (kws.length > 0) { string ctfeGetNameKeywords() - { - string name= "keywords!("; - foreach(i,kw;kws) - name ~= "\"" ~ kw ~ "\""~ (i < kws.length -1 ? ", " : ""); - name ~= ")"; - return name; - } + { + string name= "keywords!("; + foreach(i,kw;kws) + name ~= "\"" ~ kw ~ "\""~ (i < kws.length -1 ? ", " : ""); + name ~= ")"; + return name; + } string ctfeConcatKeywords() - { - string s = "["; - foreach(i, k; kws) { - s ~= "\"" ~ k ~ "\""; - if (i < kws.length - 1) - s ~= ", "; + string s = "["; + foreach(i, k; kws) + { + s ~= "\"" ~ k ~ "\""; + if (i < kws.length - 1) + s ~= ", "; + } + return s ~= "]"; } - return s ~= "]"; - } enum name = ctfeGetNameKeywords(); enum failString = "one among " ~ ctfeConcatKeywords(); ParseTree keywords(ParseTree p) - { - string keywordCode(string[] keywords) { - string result; - foreach(kw; keywords) - result ~= "if (p.end+"~to!string(kw.length) ~ " <= p.input.length " - ~" && p.input[p.end..p.end+"~to!string(kw.length)~"]==`" - ~kw~"`) return ParseTree(`" - ~name~"`,true,[`"~kw~"`],p.input,p.end,p.end+" - ~to!string(kw.length)~");\n"; + string keywordCode(string[] keywords) + { + string result; + foreach(kw; keywords) + result ~= "if (p.end+"~to!string(kw.length) ~ " <= p.input.length " + ~" && p.input[p.end..p.end+"~to!string(kw.length)~"]==`" + ~kw~"`) return ParseTree(`" + ~name~"`,true,[`"~kw~"`],p.input,p.end,p.end+" + ~to!string(kw.length)~");\n"; - result ~= "return ParseTree(`"~name~"`,false,[`" ~ failString ~ "`],p.input,p.end,p.end);"; + result ~= "return ParseTree(`"~name~"`,false,[`" ~ failString ~ "`],p.input,p.end,p.end);"; - return result; - } + return result; + } - static if (KEYWORDS == IFCHAIN) - { - mixin(keywordCode([kws])); - } - else static if (KEYWORDS == TRIE) - { - auto temp = p; - if (p.end < p.input.length) // is this conditional required? + static if (KEYWORDS == IFCHAIN) { - switch(p.input[p.end]) - { - mixin(generateCaseTrie([kws])); - mixin("default: return ParseTree(`"~name~"`,false,[`" ~ failString ~ "`],p.input,p.end,p.end);"); - } + mixin(keywordCode([kws])); } - else + else static if (KEYWORDS == TRIE) { - mixin("return ParseTree(`"~name~"`,false,[`" ~ failString ~ "`],p.input,p.end,p.end);"); + auto temp = p; + if (p.end < p.input.length) // is this conditional required? + { + switch(p.input[p.end]) + { + mixin(generateCaseTrie([kws])); + mixin("default: return ParseTree(`"~name~"`,false,[`" ~ failString ~ "`],p.input,p.end,p.end);"); + } + } + else + { + mixin("return ParseTree(`"~name~"`,false,[`" ~ failString ~ "`],p.input,p.end,p.end);"); + } } } - } ParseTree keywords(string input) - { - return .keywords!(kws)(ParseTree("",false,[],input)); - } + { + return .keywords!(kws)(ParseTree("",false,[],input)); + } string keywords(GetName g) - { - return name; - } + { + return name; + } } unittest { + alias ParseTree = DefaultParseTree; + mixin ParseCollections!ParseTree; + alias keywords!("abc","de","f") kw; assert(getName!(kw)() == `keywords!("abc", "de", "f")`); @@ -2272,102 +2339,105 @@ unittest /** -Tries to match subrule 'r' zero or more times. It always succeeds, since if 'r' fails -from the very beginning, it matched 'r' zero times... - -Its matches are those of its subrules (they might be different for each match) and its -children are all the parse trees returned by the successive application of 'r'. - ----- -alias zeroOrMore!(or!(literal!"abc", literal!"d")) rule; // in PEG-speak: '("abc" / "d")*' -ParseTree input = ParseTree("",false,[], "abcdabce"); - -ParseTree result = rule(input); - -assert(result.successful); -assert(result.matches == ["abc", "d", "abc"]); -assert(result.end == 7); // matched "abcdabce"[0..7] => "abcdabc". "e" at the end is not part of the parse tree. -assert(result.children.length == 3); -writeln(result); -/+ -writes: -zeroOrMore [0, 7]["abc", "d", "abc"] - +-or [0, 3]["abc"] - | +-literal(abc) [0, 3]["abc"] - +-or [3, 4]["d"] - | +-literal(d) [3, 4]["d"] - +-or [4, 7]["abc"] - +-literal(abc) [4, 7]["abc"] -+/ ----- - -So we know the first child used the 'literal!"abc"' sub-rule and matched input[0..3]. -The second matched input[3..4] and the third input[4..7]. - ----- -input = ParseTree("",false,[], "efgh"); -result = rule(input); -assert(result.successful); // succeed, even though all patterns failed. -assert(result.children.length == 0); ----- + Tries to match subrule 'r' zero or more times. It always succeeds, since if 'r' fails + from the very beginning, it matched 'r' zero times... + + Its matches are those of its subrules (they might be different for each match) and its + children are all the parse trees returned by the successive application of 'r'. + + ---- + alias zeroOrMore!(or!(literal!"abc", literal!"d")) rule; // in PEG-speak: '("abc" / "d")*' + ParseTree input = ParseTree("",false,[], "abcdabce"); + + ParseTree result = rule(input); + + assert(result.successful); + assert(result.matches == ["abc", "d", "abc"]); + assert(result.end == 7); // matched "abcdabce"[0..7] => "abcdabc". "e" at the end is not part of the parse tree. + assert(result.children.length == 3); + writeln(result); + /+ + writes: + zeroOrMore [0, 7]["abc", "d", "abc"] + +-or [0, 3]["abc"] + | +-literal(abc) [0, 3]["abc"] + +-or [3, 4]["d"] + | +-literal(d) [3, 4]["d"] + +-or [4, 7]["abc"] + +-literal(abc) [4, 7]["abc"] + +/ + ---- + + So we know the first child used the 'literal!"abc"' sub-rule and matched input[0..3]. + The second matched input[3..4] and the third input[4..7]. + + ---- + input = ParseTree("",false,[], "efgh"); + result = rule(input); + assert(result.successful); // succeed, even though all patterns failed. + assert(result.children.length == 0); + ---- */ -template zeroOrMore(alias r) +template zeroOrMoreT(ParseTree, alias r) { enum name = "zeroOrMore!(" ~ getName!(r) ~ ")"; - ParseTree zeroOrMore(ParseTree p) - { - auto result = ParseTree(name, true, [], p.input, p.end, p.end); - version (tracer) - { - incTraceLevel(); - if (shouldTrace(getName!(r)(), p)) - trace(traceMsg(result, name, getName!(r)())); - } - auto temp = r(result); - while(temp.successful - && (temp.begin < temp.end // To avoid infinite loops on epsilon-matching rules - || temp.name.startsWith("discard!("))) + ParseTree zeroOrMoreT(ParseTree p) { - result.matches ~= temp.matches; - result.children ~= temp; - result.end = temp.end; - result.failEnd = max(result.failEnd, temp.failEnd); + auto result = ParseTree(name, true, [], p.input, p.end, p.end); version (tracer) { + incTraceLevel(); if (shouldTrace(getName!(r)(), p)) trace(traceMsg(result, name, getName!(r)())); } - temp = r(result); - } - auto maxFail = max(temp.failEnd, temp.end); - if (maxFail > result.failEnd && maxFail > result.end) { - result.failedChild = [temp]; - result.failEnd = maxFail; + auto temp = r(result); + while(temp.successful + && (temp.begin < temp.end // To avoid infinite loops on epsilon-matching rules + || temp.name.startsWith("discard!("))) + { + result.matches ~= temp.matches; + result.children ~= temp; + result.end = temp.end; + result.failEnd = max(result.failEnd, temp.failEnd); + version (tracer) + { + if (shouldTrace(getName!(r)(), p)) + trace(traceMsg(result, name, getName!(r)())); + } + temp = r(result); + } + auto maxFail = max(temp.failEnd, temp.end); + if (maxFail > result.failEnd && maxFail > result.end) { + result.failedChild = [temp]; + result.failEnd = maxFail; + } + result.successful = true; + version (tracer) + { + if (shouldTrace(getName!(r)(), p)) + trace(traceResultMsg(result, getName!(r)())); + decTraceLevel(); + } + return result; } - result.successful = true; - version (tracer) + + ParseTree zeroOrMoreT(string input) { - if (shouldTrace(getName!(r)(), p)) - trace(traceResultMsg(result, getName!(r)())); - decTraceLevel(); + return zeroOrMoreT!(ParseTree, r)(ParseTree("",false,[],input)); } - return result; - } - - ParseTree zeroOrMore(string input) - { - return .zeroOrMore!(r)(ParseTree("",false,[],input)); - } - string zeroOrMore(GetName g) - { - return name; - } + string zeroOrMoreT(GetName g) + { + return name; + } } unittest // 'zeroOrMore' unit test { + alias ParseTree = DefaultParseTree; + mixin ParseCollections!ParseTree; + alias literal!"a" a; alias literal!"abc" abc; alias charRange!('a','z') az; @@ -2432,111 +2502,114 @@ unittest // 'zeroOrMore' unit test } /** -Tries to match subrule 'r' one or more times. If 'r' fails -from the very beginning, it fails and else succeeds. - -Its matches are those of its subrules (they might be different for each match) and its -children are all the parse trees returned by the successive application of 'r'. - ----- -alias oneOrMore!(or!(literal!"abc", literal!"d")) rule; // in PEG-speak: '("abc" / "d")*' -ParseTree input = ParseTree("",false,[], "abcdabce"); - -ParseTree result = rule(input); - -assert(result.successful); -assert(result.matches == ["abc", "d", "abc"]); -assert(result.end == 7); // matched "abcdabce"[0..7] => "abcdabc". "e" at the end is not part of the parse tree. -assert(result.children.length == 3); -writeln(result); -/+ -writes: -oneOrMore [0, 7]["abc", "d", "abc"] - +-or [0, 3]["abc"] - | +-literal(abc) [0, 3]["abc"] - +-or [3, 4]["d"] - | +-literal(d) [3, 4]["d"] - +-or [4, 7]["abc"] - +-literal(abc) [4, 7]["abc"] -+/ ----- - -So we know the first child used the 'literal!"abc"' sub-rule and matched input[0..3]. -The second matched input[3..4] and the third input[4..7]. - ----- -input = ParseTree("",false,[], "efgh"); -result = rule(input); -assert(!result.successful); // fails, since it failed on the first try. ----- + Tries to match subrule 'r' one or more times. If 'r' fails + from the very beginning, it fails and else succeeds. + + Its matches are those of its subrules (they might be different for each match) and its + children are all the parse trees returned by the successive application of 'r'. + + ---- + alias oneOrMore!(or!(literal!"abc", literal!"d")) rule; // in PEG-speak: '("abc" / "d")*' + ParseTree input = ParseTree("",false,[], "abcdabce"); + + ParseTree result = rule(input); + + assert(result.successful); + assert(result.matches == ["abc", "d", "abc"]); + assert(result.end == 7); // matched "abcdabce"[0..7] => "abcdabc". "e" at the end is not part of the parse tree. + assert(result.children.length == 3); + writeln(result); + /+ + writes: + oneOrMore [0, 7]["abc", "d", "abc"] + +-or [0, 3]["abc"] + | +-literal(abc) [0, 3]["abc"] + +-or [3, 4]["d"] + | +-literal(d) [3, 4]["d"] + +-or [4, 7]["abc"] + +-literal(abc) [4, 7]["abc"] + +/ + ---- + + So we know the first child used the 'literal!"abc"' sub-rule and matched input[0..3]. + The second matched input[3..4] and the third input[4..7]. + + ---- + input = ParseTree("",false,[], "efgh"); + result = rule(input); + assert(!result.successful); // fails, since it failed on the first try. + ---- */ -template oneOrMore(alias r) +template oneOrMoreT(ParseTree, alias r) { enum name = "oneOrMore!(" ~ getName!(r) ~ ")"; - ParseTree oneOrMore(ParseTree p) - { - auto result = ParseTree(name, false, [], p.input, p.end, p.end); - version (tracer) + ParseTree oneOrMoreT(ParseTree p) { - incTraceLevel(); - if (shouldTrace(getName!(r)(), p)) - trace(traceMsg(result, name, getName!(r)())); - } - auto temp = r(result); + auto result = ParseTree(name, false, [], p.input, p.end, p.end); + version (tracer) + { + incTraceLevel(); + if (shouldTrace(getName!(r)(), p)) + trace(traceMsg(result, name, getName!(r)())); + } + auto temp = r(result); - if (!temp.successful) - { - result.matches = temp.matches; - result.children = [temp]; - result.end = temp.end; - } - else - { - while( temp.successful - && (temp.begin < temp.end // To avoid infinite loops on epsilon-matching rules - || temp.name.startsWith("discard!("))) + if (!temp.successful) { - result.matches ~= temp.matches; - result.children ~= temp; + result.matches = temp.matches; + result.children = [temp]; result.end = temp.end; - result.failEnd = max(result.failEnd, temp.failEnd); - version (tracer) + } + else + { + while( temp.successful + && (temp.begin < temp.end // To avoid infinite loops on epsilon-matching rules + || temp.name.startsWith("discard!("))) { - if (shouldTrace(getName!(r)(), p)) - trace(traceMsg(result, name, getName!(r)())); + result.matches ~= temp.matches; + result.children ~= temp; + result.end = temp.end; + result.failEnd = max(result.failEnd, temp.failEnd); + version (tracer) + { + if (shouldTrace(getName!(r)(), p)) + trace(traceMsg(result, name, getName!(r)())); + } + temp = r(result); } - temp = r(result); + auto maxFail = max(temp.failEnd, temp.end); + if (maxFail > result.failEnd && maxFail > result.end) { + result.failedChild = [temp]; + result.failEnd = maxFail; + } + result.successful = true; } - auto maxFail = max(temp.failEnd, temp.end); - if (maxFail > result.failEnd && maxFail > result.end) { - result.failedChild = [temp]; - result.failEnd = maxFail; + version (tracer) + { + if (shouldTrace(getName!(r)(), p)) + trace(traceResultMsg(result, getName!(r)())); + decTraceLevel(); } - result.successful = true; + return result; } - version (tracer) + + ParseTree oneOrMoreT(string input) { - if (shouldTrace(getName!(r)(), p)) - trace(traceResultMsg(result, getName!(r)())); - decTraceLevel(); + return oneOrMoreT!(ParseTree, r)(ParseTree("",false,[],input)); } - return result; - } - - ParseTree oneOrMore(string input) - { - return .oneOrMore!(r)(ParseTree("",false,[],input)); - } - string oneOrMore(GetName g) - { - return name; - } + string oneOrMoreT(GetName g) + { + return name; + } } unittest // 'oneOrMore' unit test { + alias ParseTree = DefaultParseTree; + mixin ParseCollections!ParseTree; + alias literal!"a" a; alias literal!"abc" abc; alias charRange!('a','z') az; @@ -2602,51 +2675,54 @@ unittest // 'oneOrMore' unit test } /** -Given a subrule 'r', represents the expression 'r?'. It tries to match 'r' and if this matches -successfully, it returns this match. If 'r' failed, 'r?' is still a success, but without any child nor match. - ----- -alias option!(literal!"abc") rule; // Aka '"abc"?' -ParseTree input = ParseTree("",false,[],"abcd"); - -ParseTree result = rule(input); -assert(result.successful); -assert(result.matches == ["abc"]); -assert(result.children.length == 1); -assert(result.children[0] == literal!"abc"(input)); ----- + Given a subrule 'r', represents the expression 'r?'. It tries to match 'r' and if this matches + successfully, it returns this match. If 'r' failed, 'r?' is still a success, but without any child nor match. + + ---- + alias option!(literal!"abc") rule; // Aka '"abc"?' + ParseTree input = ParseTree("",false,[],"abcd"); + + ParseTree result = rule(input); + assert(result.successful); + assert(result.matches == ["abc"]); + assert(result.children.length == 1); + assert(result.children[0] == literal!"abc"(input)); + ---- */ -template option(alias r) +template optionT(ParseTree, alias r) { enum name = "option!(" ~ getName!(r) ~ ")"; - ParseTree option(ParseTree p) - { - version (tracer) + ParseTree optionT(ParseTree p) { - if (shouldTrace(getName!(r)(), p)) - trace(traceMsg(p, name, getName!(r)())); + version (tracer) + { + if (shouldTrace(getName!(r)(), p)) + trace(traceMsg(p, name, getName!(r)())); + } + ParseTree result = r(p); + if (result.successful) + return ParseTree(name, true, result.matches, result.input, result.begin, result.end, [result], result.failEnd); + else + return ParseTree(name, true, [], p.input, p.end, p.end, null, max(result.end,result.failEnd), [result]); } - ParseTree result = r(p); - if (result.successful) - return ParseTree(name, true, result.matches, result.input, result.begin, result.end, [result], result.failEnd); - else - return ParseTree(name, true, [], p.input, p.end, p.end, null, max(result.end,result.failEnd), [result]); - } - ParseTree option(string input) - { - return .option!(r)(ParseTree("",false,[],input)); - } + ParseTree optionT(string input) + { + return optionT!(ParseTree, r)(ParseTree("",false,[],input)); + } - string option(GetName g) - { - return name; - } + string optionT(GetName g) + { + return name; + } } unittest // 'option' unit test { + alias ParseTree = DefaultParseTree; + mixin ParseCollections!ParseTree; + alias literal!"a" a; alias literal!"abc" abc; @@ -2707,40 +2783,43 @@ unittest // 'option' unit test } /** -Tries 'r' on the input. If it succeeds, the rule also succeeds, without consuming any input. -If 'r' fails, then posLookahead!r also fails. Low-level implementation of '&r'. + Tries 'r' on the input. If it succeeds, the rule also succeeds, without consuming any input. + If 'r' fails, then posLookahead!r also fails. Low-level implementation of '&r'. */ -template posLookahead(alias r) +template posLookaheadT(ParseTree, alias r) { enum name = "posLookahead!(" ~ getName!(r) ~ ")"; - ParseTree posLookahead(ParseTree p) - { - version (tracer) + ParseTree posLookaheadT(ParseTree p) { - if (shouldTrace(getName!(r)(), p)) - trace(traceMsg(p, name, getName!(r)())); + version (tracer) + { + if (shouldTrace(getName!(r)(), p)) + trace(traceMsg(p, name, getName!(r)())); + } + ParseTree temp = r(p); + if (temp.successful) + return ParseTree(name, temp.successful, [], p.input, p.end, p.end); + else + return ParseTree(name, temp.successful, [temp.matches[$-1]], p.input, p.end, p.end); } - ParseTree temp = r(p); - if (temp.successful) - return ParseTree(name, temp.successful, [], p.input, p.end, p.end); - else - return ParseTree(name, temp.successful, [temp.matches[$-1]], p.input, p.end, p.end); - } - ParseTree posLookahead(string input) - { - return .posLookahead!(r)(ParseTree("",false,[],input)); - } + ParseTree posLookaheadT(string input) + { + return posLookaheadT!(ParseTree, r)(ParseTree("",false,[],input)); + } - string posLookahead(GetName g) - { - return name; - } + string posLookaheadT(GetName g) + { + return name; + } } unittest // 'posLookahead' unit test { + alias ParseTree = DefaultParseTree; + mixin ParseCollections!ParseTree; + alias literal!"a" a; alias literal!"abc" abc; @@ -2798,40 +2877,43 @@ unittest // 'posLookahead' unit test } /** -Tries 'r' on the input. If it fails, the rule succeeds, without consuming any input. -If 'r' succeeds, then negLookahead!r fails. Low-level implementation of '!r'. + Tries 'r' on the input. If it fails, the rule succeeds, without consuming any input. + If 'r' succeeds, then negLookahead!r fails. Low-level implementation of '!r'. */ -template negLookahead(alias r) +template negLookaheadT(ParseTree, alias r) { enum name = "negLookahead!(" ~ getName!(r) ~ ")"; - ParseTree negLookahead(ParseTree p) - { - version (tracer) + ParseTree negLookaheadT(ParseTree p) { - if (shouldTrace(getName!(r)(), p)) - trace(traceMsg(p, name, getName!(r)())); + version (tracer) + { + if (shouldTrace(getName!(r)(), p)) + trace(traceMsg(p, name, getName!(r)())); + } + ParseTree temp = r(p); + if (temp.successful) + return ParseTree(name, false, ["anything but \"" ~ p.input[temp.begin..temp.end] ~ "\""], p.input, p.end, p.end); + else + return ParseTree(name, true, [], p.input, p.end, p.end); } - ParseTree temp = r(p); - if (temp.successful) - return ParseTree(name, false, ["anything but \"" ~ p.input[temp.begin..temp.end] ~ "\""], p.input, p.end, p.end); - else - return ParseTree(name, true, [], p.input, p.end, p.end); - } - ParseTree negLookahead(string input) - { - return .negLookahead!(r)(ParseTree("",false,[],input)); - } + ParseTree negLookaheadT(string input) + { + return negLookaheadT!(ParseTree, r)(ParseTree("",false,[],input)); + } - string negLookahead(GetName g) - { - return name; - } + string negLookaheadT(GetName g) + { + return name; + } } unittest // 'negLookahead' unit test { + alias ParseTree = DefaultParseTree; + mixin ParseCollections!ParseTree; + alias literal!"a" a; alias literal!"abc" abc; @@ -2889,23 +2971,23 @@ unittest // 'negLookahead' unit test } /** -Internal helper template, to get a parse tree node with a name. For example, given: ----- -alias or!(literal!("abc"), charRange!('0','9')) myRule; ----- + Internal helper template, to get a parse tree node with a name. For example, given: + ---- + alias or!(literal!("abc"), charRange!('0','9')) myRule; + ---- -myRule gives nodes named "or", since its the parent rule. If you want nodes to be named "myRule", -use named. named just overwrites the original root node name, the children are left untouched. + myRule gives nodes named "or", since its the parent rule. If you want nodes to be named "myRule", + use named. named just overwrites the original root node name, the children are left untouched. -See_Also: defined. + See_Also: defined. ----- -alias or!(literal!("abc"), charRange!('0','9')) rule; -alias named!(rule, "myRule") myRule; + ---- + alias or!(literal!("abc"), charRange!('0','9')) rule; + alias named!(rule, "myRule") myRule; -auto input = "abc3"; -auto p1 = rule(input); -auto p2 = myRule(input); + auto input = "abc3"; + auto p1 = rule(input); + auto p2 = myRule(input); // They are both successful assert(p1.successful && p2.successful); @@ -2918,28 +3000,31 @@ assert(p2.children == p1.children); ---- */ -template named(alias r, string name) +template namedT(ParseTree, alias r, string name) { - ParseTree named(ParseTree p) - { - ParseTree result = r(p); - result.name = name; - return result; - } + ParseTree namedT(ParseTree p) + { + ParseTree result = r(p); + result.name = name; + return result; + } - ParseTree named(string input) - { - return .named!(r,name)(ParseTree("",false,[],input)); - } + ParseTree namedT(string input) + { + return namedT!(ParseTree, r, name)(ParseTree("",false,[],input)); + } - string named(GetName g) - { - return name; - } + string namedT(GetName g) + { + return name; + } } unittest // 'named' unit test { + alias ParseTree = DefaultParseTree; + mixin ParseCollections!ParseTree; + alias or!(literal!("abc"), charRange!('0','9')) rule; alias named!(rule, "myRule") myRule; @@ -2970,24 +3055,24 @@ unittest // 'named' unit test } /** -Internal helper template, to get a parse tree node with a name, while keeping the original node (see also named). -For example, given: ----- -alias or!(literal!("abc"), charRange!('0','9')) myRule; ----- + Internal helper template, to get a parse tree node with a name, while keeping the original node (see also named). + For example, given: + ---- + alias or!(literal!("abc"), charRange!('0','9')) myRule; + ---- -myRule gives nodes named "or", since its the parent rule. If you want nodes to be named "myRule", -use defined. Contrary to named (see before), the original node is pushed as the child. + myRule gives nodes named "or", since its the parent rule. If you want nodes to be named "myRule", + use defined. Contrary to named (see before), the original node is pushed as the child. -See_Also: named. + See_Also: named. ----- -alias or!(literal!("abc"), charRange!('0','9')) rule; -alias defined!(rule, "myRule") myRule; + ---- + alias or!(literal!("abc"), charRange!('0','9')) rule; + alias defined!(rule, "myRule") myRule; -auto input = "abc3"; -auto p1 = rule(input); -auto p2 = myRule(input); + auto input = "abc3"; + auto p1 = rule(input); + auto p2 = myRule(input); // They are both successful assert(p1.successful && p2.successful); @@ -2999,29 +3084,32 @@ assert(p2.name == `myRule`); assert(p2.children[0] == p1); ---- */ -template defined(alias r, string name) +template definedT(ParseTree, alias r, string name) { - ParseTree defined(ParseTree p) - { - ParseTree result = r(p); - result.children = [result]; - result.name = name; - return result; - } + ParseTree definedT(ParseTree p) + { + ParseTree result = r(p); + result.children = [result]; + result.name = name; + return result; + } - ParseTree defined(string input) - { - return .defined!(r,name)(ParseTree("",false,[],input)); - } + ParseTree definedT(string input) + { + return definedT!(ParseTree, r,name)(ParseTree("",false,[],input)); + } - string defined(GetName g) - { - return name; - } + string definedT(GetName g) + { + return name; + } } unittest // 'defined' unit test { + alias ParseTree = DefaultParseTree; + mixin ParseCollections!ParseTree; + alias or!(literal!("abc"), charRange!('0','9')) rule; alias defined!(rule, "myRule") myRule; @@ -3052,30 +3140,33 @@ unittest // 'defined' unit test } /** -Low-level representation for the expression 'r {act}'. That is, it applies rule 'r' -on the input and then calls 'act' on the resulting ParseTree. + Low-level representation for the expression 'r {act}'. That is, it applies rule 'r' + on the input and then calls 'act' on the resulting ParseTree. */ -template action(alias r, alias act) +template actionT(ParseTree, alias r, alias act) { ParseTree action(ParseTree p) - { - return act(r(p)); - } + { + return act(r(p)); + } ParseTree action(string input) - { - return .action!(r,act)(ParseTree("",false,[],input)); - } + { + return .action!(r,act)(ParseTree("",false,[],input)); + } string action(GetName g) - { - enum name = "action!("~ getName!(r)() ~ ", " ~ __traits(identifier, act) ~ ")"; - return name; - } + { + enum name = "action!("~ getName!(r)() ~ ", " ~ __traits(identifier, act) ~ ")"; + return name; + } } unittest // 'action' unit test { + alias ParseTree = DefaultParseTree; + mixin ParseCollections!ParseTree; + ParseTree foo(ParseTree p) { p.matches ~= p.matches; // doubling matches @@ -3111,37 +3202,40 @@ unittest // 'action' unit test } /** -Concatenates a ParseTree's matches as one match and discards its children. Equivalent to the expression '~r'. + Concatenates a ParseTree's matches as one match and discards its children. Equivalent to the expression '~r'. */ -template fuse(alias r) +template fuseT(ParseTree, alias r) { - ParseTree fuse(ParseTree p) - { - p = r(p); - if(p.successful) + ParseTree fuseT(ParseTree p) { - if (p.matches.length != 0) - p.matches = [std.array.join(p.matches)]; + p = r(p); + if(p.successful) + { + if (p.matches.length != 0) + p.matches = [std.array.join(p.matches)]; - p.children = null; // also discard children + p.children = null; // also discard children + } + return p; } - return p; - } - ParseTree fuse(string input) - { - return .fuse!(r)(ParseTree("",false,[],input)); - } + ParseTree fuseT(string input) + { + return fuseT!(ParseTree, r)(ParseTree("",false,[],input)); + } - string fuse(GetName g) - { - enum name = "fuse!(" ~ getName!(r)() ~ ")"; - return name; - } + string fuseT(GetName g) + { + enum name = "fuse!(" ~ getName!(r)() ~ ")"; + return name; + } } unittest // 'fuse' unit test { + alias ParseTree = DefaultParseTree; + mixin ParseCollections!ParseTree; + alias oneOrMore!(literal!("abc")) abcs; alias fuse!(abcs) f; @@ -3184,85 +3278,90 @@ unittest // 'fuse' unit test } /** -Calls 'r' on the input and then discards its children nodes. + Calls 'r' on the input and then discards its children nodes. */ -template discardChildren(alias r) +template discardChildrenT(ParseTree, alias r) { - ParseTree discardChildren(ParseTree p) - { - p = r(p); - p.children = null; - return p; - } + ParseTree discardChildrenT(ParseTree p) + { + p = r(p); + p.children = null; + return p; + } - ParseTree discardChildren(string input) - { - return .discardChildren!(r)(ParseTree("",false,[],input)); - } + ParseTree discardChildrenT(string input) + { + return .discardChildrenT!(ParseTree, r)(ParseTree("",false,[],input)); + } - string discardChildren(GetName g) - { - enum name = "discardChildren!(" ~ getName!(r)() ~ ")"; - return name; - } + string discardChildrenT(GetName g) + { + enum name = "discardChildren!(" ~ getName!(r)() ~ ")"; + return name; + } } /** -Calls 'r' on the input and then discards its matches. + Calls 'r' on the input and then discards its matches. */ -template discardMatches(alias r) +template discardMatchesT(ParseTree, alias r) { ParseTree discardMatches(ParseTree p) - { - p = r(p); - if (p.successful) - p.matches = null; - return p; - } + { + p = r(p); + if (p.successful) + p.matches = null; + return p; + } ParseTree discardMatches(string input) - { - return .discardMatches!(r)(ParseTree("",false,[],input)); - } + { + return .discardMatches!(r)(ParseTree("",false,[],input)); + } string discardMatches(GetName g) - { - enum name = "discardMatches!(" ~ getName!(r)() ~ ")"; - return name; - } + { + enum name = "discardMatches!(" ~ getName!(r)() ~ ")"; + return name; + } } /** -Calls 'r' on the input and then discard everything 'r' returned: no children, no match and index -put at the end of the match. It's the low-level engine behind ':r'. + Calls 'r' on the input and then discard everything 'r' returned: no children, no match and index + put at the end of the match. It's the low-level engine behind ':r'. */ -template discard(alias r) +template discardT(ParseTree, alias r) { - ParseTree discard(ParseTree p) - { - ParseTree result = r(p); - result.name = "discard!(" ~ getName!(r)() ~ ")"; - //result.begin = result.end; - result.children = null; - if (result.successful) - result.matches = null;//to keep error messages, if any + ParseTree discardT(ParseTree p) + { + pragma(msg, typeof(p)); + pragma(msg, typeof(r(p))); + ParseTree result = r(p); + result.name = "discard!(" ~ getName!(r)() ~ ")"; + //result.begin = result.end; + result.children = null; + if (result.successful) + result.matches = null;//to keep error messages, if any - return result; - } + return result; + } - ParseTree discard(string input) - { - return .discard!(r)(ParseTree("",false,[],input)); - } + ParseTree discardT(string input) + { + return discardT!(ParseTree, r)(ParseTree("",false,[],input)); + } - string discard(GetName g) - { - return "discard!(" ~ getName!(r)() ~ ")"; - } + string discardT(GetName g) + { + return "discard!(" ~ getName!(r)() ~ ")"; + } } unittest // 'discard' unit test { + alias ParseTree = DefaultParseTree; + mixin ParseCollections!ParseTree; + alias literal!"abc" abc; alias oneOrMore!abc abcs; alias discard!(literal!("abc")) dabc; @@ -3315,34 +3414,37 @@ unittest // 'discard' unit test } /** -Calls 'r' on the input and then discards everything 'r' did, except its matches (so that -they propagate upwards). Equivalent to ';r'. + Calls 'r' on the input and then discards everything 'r' did, except its matches (so that + they propagate upwards). Equivalent to ';r'. */ -template drop(alias r) +template dropT(ParseTree, alias r) { ParseTree drop(ParseTree p) - { - ParseTree result = r(p); - //result.begin = result.end; - result.children = null; - if (result.successful) - result.name = "drop!(" ~ getName!(r)() ~ ")"; - return result; - } + { + ParseTree result = r(p); + //result.begin = result.end; + result.children = null; + if (result.successful) + result.name = "drop!(" ~ getName!(r)() ~ ")"; + return result; + } ParseTree drop(string input) - { - return .drop!(r)(ParseTree("",false,[],input)); - } + { + return .drop!(r)(ParseTree("",false,[],input)); + } string drop(GetName g) - { - return "drop!(" ~ getName!(r)() ~ ")"; - } + { + return "drop!(" ~ getName!(r)() ~ ")"; + } } unittest // 'drop' unit test { + alias ParseTree = DefaultParseTree; + mixin ParseCollections!ParseTree; + alias literal!"abc" abc; alias oneOrMore!abc abcs; alias drop!(literal!("abc")) dabc; @@ -3395,86 +3497,89 @@ unittest // 'drop' unit test } /** -Makes r disappear in a sequence, letting its children take its place. It's equivalent -to the '%' operator. Given A <- B %C D and C <- E F, a successful parse for A will -generate a three with four children: B, E, F and D parse trees. + Makes r disappear in a sequence, letting its children take its place. It's equivalent + to the '%' operator. Given A <- B %C D and C <- E F, a successful parse for A will + generate a three with four children: B, E, F and D parse trees. */ -template propagate(alias r) +template propagateT(ParseTree, alias r) { ParseTree propagate(ParseTree p) - { - ParseTree result = r(p); - if (result.successful) - result.name = "propagate!(" ~ getName!(r)() ~ ")"; - return result; - } + { + ParseTree result = r(p); + if (result.successful) + result.name = "propagate!(" ~ getName!(r)() ~ ")"; + return result; + } ParseTree propagate(string input) - { - return .propagate!(r)(ParseTree("",false,[],input)); - } + { + return .propagate!(r)(ParseTree("",false,[],input)); + } string propagate(GetName g) - { - return "propagate!(" ~ getName!(r)() ~ ")"; - } + { + return "propagate!(" ~ getName!(r)() ~ ")"; + } } /** -Makes 'r's result be kept when it would be discarded by the tree-decimation done by a grammar. -Equivalent to '^r'. + Makes 'r's result be kept when it would be discarded by the tree-decimation done by a grammar. + Equivalent to '^r'. */ -template keep(alias r) +template keepT(ParseTree, alias r) { - ParseTree keep(ParseTree p) - { - ParseTree result = r(p); - if (result.successful) + ParseTree keepT(ParseTree p) { - result.children = [result]; - result.name = "keep!(" ~ getName!(r)() ~ ")"; + ParseTree result = r(p); + if (result.successful) + { + result.children = [result]; + result.name = "keep!(" ~ getName!(r)() ~ ")"; + } + return result; } - return result; - } - ParseTree keep(string input) - { - return .keep!(r)(ParseTree("",false,[],input)); - } + ParseTree keepT(string input) + { + return keepT!(ParseTree, r)(ParseTree("",false,[],input)); + } - string keep(GetName g) - { - return "keep!(" ~ getName!(r)() ~ ")"; - } + string keepT(GetName g) + { + return "keep!(" ~ getName!(r)() ~ ")"; + } } unittest // 'keep' unit test { + alias ParseTree = DefaultParseTree; + mixin ParseCollections!ParseTree; + // Grammar mimicry struct KeepTest { static bool isRule(string s) - { - if (s == "A" || s == "KA") - return true; - else - return false; - } + { + if (s == "A" || s == "KA") + return true; + else + return false; + } mixin decimateTree; // Equivalent to A <- 'a' 'b' static ParseTree A(string s) - { - return decimateTree(named!(and!(literal!"a", literal!"b"), "A")(s)); - } + { + return decimateTree(named!(and!(literal!"a", literal!"b"), "A")(s)); + } // Here we use keep to protect 'b' // Equivalent to KA <- 'a' ^'b' static ParseTree KA(string s) - { - return decimateTree(named!(and!(literal!"a", keep!(literal!"b")), "KA")(s)); - } + { + return decimateTree(named!(and!(literal!"a", keep!(literal!"b")), "KA")(s)); + } } ParseTree reference = KeepTest.A("abc"); @@ -3490,51 +3595,6 @@ unittest // 'keep' unit test assert(result.children == [literal!("b")(literal!("a")("abc"))], "'b' node was kept."); } -/* ****************** predefined rules ******************** */ - -alias named!(or!(literal!("\r\n"), literal!("\n"), literal!("\r")), "endOfLine") endOfLine; /// predefined end-of-line parser -alias endOfLine eol; /// helper alias. - -alias or!(literal!(" "), literal!("\t"), literal!("\v")) space; /// predefined space-recognizing parser (space or tabulation). -alias named!(literal!"\t", "tab") tab; /// A parser recognizing \t (tabulation) -alias named!(fuse!(discardChildren!(oneOrMore!space)), - "spaces") spaces; /// aka '~space+' -alias or!(space, endOfLine) blank; /// Any blank char (spaces or end of line). -alias named!(discard!(zeroOrMore!blank), - "spacing") spacing; /// The basic space-management parser: discard zero or more blank spaces. - -alias charRange!('0', '9') digit; /// Decimal digit: [0-9] -alias named!(fuse!(discardChildren!(oneOrMore!digit)), "digits") digits; /// [0-9]+ - -alias or!(charRange!('0','9'), charRange!('a','f'), charRange!('A', 'F')) hexDigit; /// Hexadecimal digit: [0-9a-fA-F] - -alias charRange!('a', 'z') alpha; /// [a-z] -alias charRange!('A', 'Z') Alpha; /// [A-Z] - -alias and!(oneOrMore!(or!(alpha, Alpha, literal!("_"))), zeroOrMore!(or!(digit, alpha, Alpha, literal!("_")))) ident; -alias named!(fuse!(discardChildren!ident), - "identifier") identifier; /// [a-zA-Z_][a-zA-Z_0-9]*, the basic C-family identifier -alias named!(fuse!(discardChildren!(and!(identifier, zeroOrMore!(and!(literal!".", identifier))))), - "qualifiedIdentifier") qualifiedIdentifier; /// qualified identifiers (ids separated by dots: abd.def.g). - -alias named!(literal!"/", "slash") slash; /// A parser recognizing '/' -alias named!(literal!"\\", "backslash") backslash; /// A parser recognizing '\' -alias named!(literal!"'", "quote") quote; /// A parser recognizing ' (single quote) -alias named!(literal!"\"", "doublequote") doublequote; /// A parser recognizing " (double quote) -alias named!(literal!"`", "backquote") backquote; /// A parser recognizing $(BACKTICK) (backquote) - -/// A list of elem's separated by sep's. One element minimum. -template list(alias elem, alias sep) -{ - alias named!(spaceAnd!(oneOrMore!blank, and!(elem, zeroOrMore!(spaceAnd!(discardMatches!(sep), elem)))), "list") list; -} - -/// A list of elem's separated by sep's. The empty list (no elem, no sep) is OK. -template list0(alias elem, alias sep) -{ - alias named!(spaceAnd!(oneOrMore!blank, option!(and!(elem, zeroOrMore!(spaceAnd!(discardMatches!(sep), elem))))), "list0") list0; -} - template AddSpace(alias sp) { template AddSpace(alias r) @@ -3544,53 +3604,52 @@ template AddSpace(alias sp) } /** -The engine formerly behind the '< ' Pegged rule: all sequence subelements of a rule are interspersed -with a space-consuming rule, given as the first template parameter. It's not used by Pegged anymore -but can be useful for low-level code. It might become deprecated, but it's not there yet. + The engine formerly behind the '< ' Pegged rule: all sequence subelements of a rule are interspersed + with a space-consuming rule, given as the first template parameter. It's not used by Pegged anymore + but can be useful for low-level code. It might become deprecated, but it's not there yet. ----- -alias and!(literal!"abc", literal!"def") rule1; // "abc" "def", equivalent to "abcdef" -alias spaceAnd!(oneOrMore!blank, literal!"abc", literal!"def") rule2; // "abc" "def", but with spaces in-between. + ---- + alias and!(literal!"abc", literal!"def") rule1; // "abc" "def", equivalent to "abcdef" + alias spaceAnd!(oneOrMore!blank, literal!"abc", literal!"def") rule2; // "abc" "def", but with spaces in-between. -string input1 = "abcdef"; -string input2 = " abc + string input1 = "abcdef"; + string input2 = " abc -def "; // with spaces and end of line markers. + def "; // with spaces and end of line markers. -assert(rule1(input1).successful); // OK -assert(!rule1(input2).successful); // NOK, couldn't find "def" after "abc" + assert(rule1(input1).successful); // OK + assert(!rule1(input2).successful); // NOK, couldn't find "def" after "abc" -assert(rule2(input1).successful); // OK -assert(rule2(input2).successful); // Still OK -assert(rule2(input2).matches == ["abc","def"]);// rule2 finds the literals among the spaces ----- + assert(rule2(input1).successful); // OK + assert(rule2(input2).successful); // Still OK + assert(rule2(input2).matches == ["abc","def"]);// rule2 finds the literals among the spaces + ---- -As you can see on the previous line, spaceAnd discards the matched spaces -and returns matches only for the 'real' subrules. + As you can see on the previous line, spaceAnd discards the matched spaces + and returns matches only for the 'real' subrules. -Note: by using a non-space rule as the first template argument, -you can use spaceAnd as a generic 'find these patterns, possibly separated by this pattern' rule. + Note: by using a non-space rule as the first template argument, + you can use spaceAnd as a generic 'find these patterns, possibly separated by this pattern' rule. -For example, using digits as separators: ----- -alias spaceAnd!(digit, literal!"abc", litera!"def") rule3; + For example, using digits as separators: + ---- + alias spaceAnd!(digit, literal!"abc", litera!"def") rule3; -ParseTree result = rule3("123abc45def67890"); -assert(rule3.successful); -assert(rule3.matches == ["abc", "def"]); -assert(rule3.children.length == 2); + ParseTree result = rule3("123abc45def67890"); + assert(rule3.successful); + assert(rule3.matches == ["abc", "def"]); + assert(rule3.children.length == 2); -assert(rule3.begin == 0;) -assert(rule3.end == "123abc45def67890".length); ----- + assert(rule3.begin == 0;) + assert(rule3.end == "123abc45def67890".length); + ---- */ -template spaceAnd(alias sp, rules...) -{ - alias and!(discard!(zeroOrMore!sp), staticMap!(AddSpace!(zeroOrMore!sp), rules)) spaceAnd; -} unittest // 'spaceAnd' unit test { + alias ParseTree = DefaultParseTree; + mixin ParseCollections!ParseTree; + alias literal!"a" a; alias literal!"b" b; @@ -3649,80 +3708,80 @@ unittest // 'spaceAnd' unit test mixin template decimateTree() { static ParseTree decimateTree(ParseTree p) - { - if(p.children.length == 0) return p; + { + if(p.children.length == 0) return p; - bool parseFailed = !p.successful; + bool parseFailed = !p.successful; - ParseTree[] filterChildren(ParseTree pt) - { - ParseTree[] result; - foreach(child; pt.children) + ParseTree[] filterChildren(ParseTree pt) { - import std.algorithm : startsWith; - - if ( (isRule(child.name) && (child.matches.length != 0 || parseFailed)) - || (!child.successful && child.children.length == 0) - || (!child.successful && child.name.startsWith("or!") && child.children.length > 1) - || (!pt.successful && child.successful && child.children.length == 0 && child.failedChild.length > 0)) - { - child.children = filterChildren(child); - result ~= child; - } - else if (child.name.startsWith("keep!(")) // 'keep' node are never discarded. - // They have only one child, the node to keep - { - result ~= child.children[0]; - } - else // discard this node, but see if its children contain nodes to keep + ParseTree[] result; + foreach(child; pt.children) { - result ~= filterChildren(child); + import std.algorithm : startsWith; + + if ( (isRule(child.name) && (child.matches.length != 0 || parseFailed)) + || (!child.successful && child.children.length == 0) + || (!child.successful && child.name.startsWith("or!") && child.children.length > 1) + || (!pt.successful && child.successful && child.children.length == 0 && child.failedChild.length > 0)) + { + child.children = filterChildren(child); + result ~= child; + } + else if (child.name.startsWith("keep!(")) // 'keep' node are never discarded. + // They have only one child, the node to keep + { + result ~= child.children[0]; + } + else // discard this node, but see if its children contain nodes to keep + { + result ~= filterChildren(child); + } } + return result; } - return result; - } - void filterFailedChildren(ref ParseTree pt) - { - foreach(ref child; pt.children) + void filterFailedChildren(ref ParseTree pt) { - filterFailedChildren(child); - import std.algorithm : startsWith; - - if ( (isRule(child.name) && (child.matches.length != 0 || parseFailed)) - || (!child.successful && child.children.length == 0) - || (!child.successful && child.name.startsWith("or!") && child.children.length > 1) - || (!pt.successful && child.successful && child.children.length == 0 && child.failedChild.length > 0)) - { - } - else if (child.name.startsWith("keep!(")) // 'keep' node are never discarded. - // They have only one child, the node to keep + foreach(ref child; pt.children) { + filterFailedChildren(child); + import std.algorithm : startsWith; + + if ( (isRule(child.name) && (child.matches.length != 0 || parseFailed)) + || (!child.successful && child.children.length == 0) + || (!child.successful && child.name.startsWith("or!") && child.children.length > 1) + || (!pt.successful && child.successful && child.children.length == 0 && child.failedChild.length > 0)) + { + } + else if (child.name.startsWith("keep!(")) // 'keep' node are never discarded. + // They have only one child, the node to keep + { + } + else if (child.failedChild.length > 0)// discard this node, but see if its children contain nodes to keep + { + pt.failedChild ~= child.failedChild; + child.failedChild = []; + } } - else if (child.failedChild.length > 0)// discard this node, but see if its children contain nodes to keep + foreach(ref child; pt.failedChild) { - pt.failedChild ~= child.failedChild; - child.failedChild = []; + filterFailedChildren(child); + child.children = filterChildren(child); } } - foreach(ref child; pt.failedChild) - { - filterFailedChildren(child); - child.children = filterChildren(child); - } + if (!p.successful) + filterFailedChildren(p); + p.children = filterChildren(p); + return p; } - if (!p.successful) - filterFailedChildren(p); - p.children = filterChildren(p); - return p; - } } /** -Discard one-child nodes and replace them with their children. -Most grammar tend to produce long one-child/one-child branches, -simplifyTree compacts these. + Discard one-child nodes and replace them with their children. + Most grammar tend to produce long one-child/one-child branches, + simplifyTree compacts these. */ -ParseTree simplifyTree(ParseTree p) +ParseTree simplifyTree(ParseTree)(ParseTree p) { foreach(ref child; p.children) child = simplifyTree(child); @@ -3734,31 +3793,101 @@ ParseTree simplifyTree(ParseTree p) } /** -Returns: the number of nodes in a parse tree. + Returns: the number of nodes in a parse tree. */ -size_t size(ParseTree p) +size_t size(ParseTree)(ParseTree p) { - size_t result = 1; - foreach(child; p.children) - result += size(child); - return result; + size_t result = 1; + foreach(child; p.children) + result += size(child); + return result; } /** -Generic ParseTree modifier: -predicate must be callable with a ParseTree and return a boolean. -modifier must be callable with a ParseTree and return a ParseTree. + Generic ParseTree modifier: + predicate must be callable with a ParseTree and return a boolean. + modifier must be callable with a ParseTree and return a ParseTree. -If predicate is true on input, modify calls modifier on input and return the result. -If not, it continues with the children. + If predicate is true on input, modify calls modifier on input and return the result. + If not, it continues with the children. */ -ParseTree modify(alias predicate, alias modifier)(ParseTree input) +ParseTree modify(ParseTree, alias predicate, alias modifier)(ParseTree input) if (isParseTree!ParseTree) { foreach(ref child; input.children) - child = modify!(predicate, modifier)(child); + child = modify!(ParseTree, predicate, modifier)(child); if (predicate(input)) input = modifier(input); return input; } + +mixin template ParseCollections(ParseTree) { + alias literal(string s) = literalT!(ParseTree, s); + alias caseInsensitiveLiteral(string s) = caseInsensitiveLiteralT!(ParseTree, s); + alias charRange(dchar begin, dchar end) = charRangeT!(ParseTree, begin, end); + + alias wrapAround(alias before, alias target, alias after) = wrapAroundT!(ParseTree, before, target, after); + alias and(rules...) = andT!(ParseTree, rules); + alias or(rules...) = orT!(ParseTree, rules); + alias longest_matchT(rules...) = longest_matchT!(ParseTree, rules); + alias keywords(kws...) = keywordsT!(ParseTree, kws); + alias zeroOrMore(alias r) = zeroOrMoreT!(ParseTree, r); + alias oneOrMore(alias r) = oneOrMoreT!(ParseTree, r); + alias option(alias r) = optionT!(ParseTree, r); + alias posLookahead(alias r) = posLookaheadT!(ParseTree, r); + alias negLookahead(alias r) = negLookaheadT!(ParseTree, r); + alias named(alias r, string name) = namedT!(ParseTree, r, name); + alias defined(alias r, string name)= definedT!(ParseTree, r, name); + alias action(alias r, alias act) = actionT!(ParseTree, r, act); + alias fuse(alias r) = fuseT!(ParseTree, r); + alias discardChildren(alias r) = discardChildrenT!(ParseTree, r); + alias discardMatches(alias r) = discardMatchesT!(ParseTree, r); + alias discard(alias r) = discardT!(ParseTree, r); + alias drop(alias r) = dropT!(ParseTree, r); + alias propagate(alias r) = propagateT!(ParseTree, r); + alias keep(alias r) = keepT!(ParseTree, r); + +} + +mixin template DefaultParsePatterns(alias PEG) { + /* ****************** predefined rules ******************** */ + + alias endOfLine = PEG.named!(PEG.or!(PEG.literal!("\r\n"), PEG.literal!("\n"), PEG.literal!("\r")), "endOfLine"); /// predefined end-of-line parser + alias eol = endOfLine; /// helper alias. + + alias space = PEG.or!(PEG.literal!(" "), PEG.literal!("\t"), PEG.literal!("\v")); /// predefined space-recognizing parser (space or tabulation). + alias tab = PEG.named!(PEG.literal!"\t", "tab"); /// A parser recognizing \t (tabulation) + alias spaces = PEG.named!(PEG.fuse!(PEG.discardChildren!(PEG.oneOrMore!space)), + "spaces"); /// aka '~space+' + alias blank = PEG.or!(space, endOfLine); /// Any blank char (spaces or end of line). + alias spacing = PEG.named!(PEG.discard!(PEG.zeroOrMore!blank), + "spacing"); /// The basic space-management parser: PEG.discard zero or more blank spaces. + + alias digit = PEG.charRange!('0', '9'); /// Decimal digit: [0-9] + alias digits = PEG.named!(PEG.fuse!(PEG.discardChildren!(PEG.oneOrMore!digit)), "digits"); /// [0-9]+ + + alias hexDigit = PEG.or!(PEG.charRange!('0','9'), PEG.charRange!('a','f'), PEG.charRange!('A', 'F')); /// Hexadecimal digit: [0-9a-fA-F] + + alias alpha = PEG.charRange!('a', 'z'); /// [a-z] + alias Alpha = PEG.charRange!('A', 'Z'); /// [A-Z] + + alias ident = PEG.and!(PEG.oneOrMore!(PEG.or!(alpha, Alpha, PEG.literal!("_"))), PEG.zeroOrMore!(PEG.or!(digit, alpha, Alpha, PEG.literal!("_")))); + alias identifier = PEG.named!(PEG.fuse!(PEG.discardChildren!ident), + "identifier"); /// [a-zA-Z_][a-zA-Z_0-9]*, the basic C-family identifier + alias qualifiedIdentifier = PEG.named!(PEG.fuse!(PEG.discardChildren!(PEG.and!(identifier, PEG.zeroOrMore!(PEG.and!(PEG.literal!".", identifier))))), + "qualifiedIdentifier"); /// qualified identifiers (ids separated by dots: abd.def.g). + + alias slash = PEG.named!(PEG.literal!"/", "slash"); /// A parser recognizing '/' + alias backslash = PEG.named!(PEG.literal!"\\", "backslash"); /// A parser recognizing '\' + alias quote = PEG.named!(PEG.literal!"'", "quote"); /// A parser recognizing ' (single quote) + alias doublequote = PEG.named!(PEG.literal!"\"", "doublequote"); /// A parser recognizing " (double quote) + alias backquote = PEG.named!(PEG.literal!"`", "backquote"); /// A parser recognizing $(BACKTICK) (backquote) + /// A list of elem's separated by sep's. One element minimum. + alias list(alias elem, alias sep) = PEG.named!(spaceAnd!(PEG.oneOrMore!blank, PEG.and!(elem, PEG.zeroOrMore!(spaceAnd!(PEG.discardMatches!(sep), elem)))), "list"); + +/// A list of elem's separated by sep's. The empty list (no elem, no sep) is OK. + alias list0(alias elem, alias sep) = PEG.named!(spaceAnd!(PEG.oneOrMore!blank, PEG.option!(PEG.and!(elem, PEG.zeroOrMore!(spaceAnd!(PEG.discardMatches!(sep), elem))))), "list0"); + + alias spaceAnd(alias sp, rules...) = PEG.and!(PEG.discard!(PEG.zeroOrMore!sp), staticMap!(AddSpace!(PEG.zeroOrMore!sp), rules)); +} From d89af29f7b07ebf6c5499fabadac2d6dce208169 Mon Sep 17 00:00:00 2001 From: cbleser Date: Mon, 31 May 2021 15:30:40 +0300 Subject: [PATCH 03/29] WIP: Correction error in the unittest --- pegged/grammar.d | 152 +++++++++++++++++++---------------- pegged/peg.d | 55 ++++++------- pegged/tester/testerparser.d | 72 +++++++++-------- 3 files changed, 148 insertions(+), 131 deletions(-) diff --git a/pegged/grammar.d b/pegged/grammar.d index eee189d..d99e276 100644 --- a/pegged/grammar.d +++ b/pegged/grammar.d @@ -75,7 +75,7 @@ ParseTree spaceArrow(ParseTree)(ParseTree input) result.children = spacer ~ result.children ~ spacer; return result; } - return modify!( p => p.name == "Pegged.Primary", + return modify!(ParseTree, p => p.name == "Pegged.Primary", wrapInSpaces)(input); } @@ -96,7 +96,7 @@ mixin(grammar(def)); ParseTree p = Gram("abcbccbcd"); ---- */ -string grammar(Memoization withMemo = Memoization.yes)(string definition) +string grammar(Memoization withMemo = Memoization.yes, ParseTree=DefaultParseTree)(string definition) { ParseTree defAsParseTree = Pegged(definition); @@ -106,10 +106,10 @@ string grammar(Memoization withMemo = Memoization.yes)(string definition) string result = "static assert(false, `" ~ defAsParseTree.toString("") ~ "`);"; return result; } - return grammar!(withMemo)(defAsParseTree); + return grammar!(ParseTree, withMemo)(defAsParseTree); } /// ditto -string grammar(Memoization withMemo = Memoization.yes)(ParseTree defAsParseTree) +string grammar(ParseTree, Memoization withMemo = Memoization.yes)(ParseTree defAsParseTree) if (isParseTree!ParseTree) { string[] composedGrammars; @@ -204,12 +204,15 @@ string grammar(Memoization withMemo = Memoization.yes)(ParseTree defAsParseTree) string firstRuleName = generateCode(p.children[1].children[0]); result = -"struct Generic" ~ shortGrammarName ~ "(TParseTree) +"struct Generic" ~ shortGrammarName ~ "(ParseTree) { import std.functional : toDelegate; import pegged.dynamic.grammar; static import pegged.peg; - alias PEG=pegged.peg; + mixin ParseCollections!ParseTree; + alias PEG=PeggedT!ParseTree; + mixin DefaultParsePatterns!PEG; + struct " ~ grammarName ~ "\n { enum name = \"" ~ shortGrammarName ~ "\"; static ParseTree delegate(ParseTree)[string] before; @@ -219,7 +222,7 @@ string grammar(Memoization withMemo = Memoization.yes)(ParseTree defAsParseTree) if (withMemo == Memoization.yes) { result ~= " import std.typecons:Tuple, tuple; - static TParseTree[Tuple!(string, size_t)] memo;"; + static ParseTree[Tuple!(string, size_t)] memo;"; if (grammarInfo.leftRecursiveCycles.length > 0) result ~= " import std.algorithm: canFind, countUntil, remove; @@ -358,29 +361,29 @@ string grammar(Memoization withMemo = Memoization.yes)(ParseTree defAsParseTree) if (p.children[1].children[0].children.length == 1) { // General calling interface - result ~= " static TParseTree opCall(TParseTree p)\n" + result ~= " static ParseTree opCall(ParseTree p)\n" ~ " {\n" - ~ " TParseTree result = decimateTree(" ~ firstRuleName ~ "(p));\n" + ~ " ParseTree result = decimateTree(" ~ firstRuleName ~ "(p));\n" ~ " result.children = [result];\n" ~ " result.name = \"" ~ shortGrammarName ~ "\";\n" ~ " return result;\n" ~ " }\n\n" - ~ " static TParseTree opCall(string input)\n" + ~ " static ParseTree opCall(string input)\n" ~ " {\n"; if (withMemo == Memoization.no) result ~= " forgetMemo();\n" - ~ " return " ~ shortGrammarName ~ "(TParseTree(``, false, [], input, 0, 0));\n" + ~ " return " ~ shortGrammarName ~ "(ParseTree(``, false, [], input, 0, 0));\n" ~ " }\n"; else result ~= " if(__ctfe)\n" ~ " {\n" - ~ " return " ~ shortGrammarName ~ "(TParseTree(``, false, [], input, 0, 0));\n" + ~ " return " ~ shortGrammarName ~ "(ParseTree(``, false, [], input, 0, 0));\n" ~ " }\n" ~ " else\n" ~ " {\n" ~ " forgetMemo();\n" - ~ " return " ~ shortGrammarName ~ "(TParseTree(``, false, [], input, 0, 0));\n" + ~ " return " ~ shortGrammarName ~ "(ParseTree(``, false, [], input, 0, 0));\n" ~ " }\n" ~ " }\n"; @@ -392,7 +395,7 @@ string grammar(Memoization withMemo = Memoization.yes)(ParseTree defAsParseTree) result ~= generateForgetMemo(); result ~= " }\n" // end of grammar struct definition ~ "}\n\n" // end of template definition - ~ "alias Generic" ~ shortGrammarName ~ "!(ParseTree)." + ~ "alias Generic" ~ shortGrammarName ~ "!(DefaultParseTree)." ~ shortGrammarName ~ " " ~ shortGrammarName ~ ";\n\n"; break; case "Pegged.Definition": @@ -408,19 +411,19 @@ string grammar(Memoization withMemo = Memoization.yes)(ParseTree defAsParseTree) code ~= generateCode(p.children[2]); break; case "Pegged.FUSEARROW": - code ~= "pegged.peg.fuse!(" ~ generateCode(p.children[2]) ~ ")"; + code ~= "PEG.fuse!(" ~ generateCode(p.children[2]) ~ ")"; break; case "Pegged.DISCARDARROW": - code ~= "pegged.peg.discard!(" ~ generateCode(p.children[2]) ~ ")"; + code ~= "PEG.discard!(" ~ generateCode(p.children[2]) ~ ")"; break; case "Pegged.KEEPARROW": - code ~= "pegged.peg.keep!("~ generateCode(p.children[2]) ~ ")"; + code ~= "PEG.keep!("~ generateCode(p.children[2]) ~ ")"; break; case "Pegged.DROPARROW": - code ~= "pegged.peg.drop!("~ generateCode(p.children[2]) ~ ")"; + code ~= "PEG.drop!("~ generateCode(p.children[2]) ~ ")"; break; case "Pegged.PROPAGATEARROW": - code ~= "pegged.peg.propagate!("~ generateCode(p.children[2]) ~ ")"; + code ~= "PEG.propagate!("~ generateCode(p.children[2]) ~ ")"; break; case "Pegged.SPACEARROW": ParseTree modified = spaceArrow(p.children[2]); @@ -429,7 +432,7 @@ string grammar(Memoization withMemo = Memoization.yes)(ParseTree defAsParseTree) case "Pegged.ACTIONARROW": auto actionResult = generateCode(p.children[2]); foreach(action; p.children[1].matches[1..$]) - actionResult = "pegged.peg.action!(" ~ actionResult ~ ", " ~ action ~ ")"; + actionResult = "PEG.action!(" ~ actionResult ~ ", " ~ action ~ ")"; code ~= actionResult; break; default: @@ -449,7 +452,7 @@ string grammar(Memoization withMemo = Memoization.yes)(ParseTree defAsParseTree) innerName ~= "\"" ~ shortName ~ "!(\" ~ "; hookedName ~= "_" ~ to!string(p.children[0].children[1].children.length); foreach(i,param; p.children[0].children[1].children) - innerName ~= "pegged.peg.getName!("~ param.children[0].matches[0] + innerName ~= "PEG.getName!("~ param.children[0].matches[0] ~ (i 1) // real sequence { - result = "pegged.peg.and!("; + result = "PEG.and!("; foreach(seq; p.children) { string elementCode = generateCode(seq); // flattening inner sequences - if (elementCode.length > 6 && elementCode[0..5] == "pegged.peg.and!(") + if (elementCode.length > 6 && elementCode[0..5] == "PEG.and!(") elementCode = elementCode[5..$-1]; // cutting 'and!(' and ')' result ~= elementCode ~ ", "; } @@ -710,17 +713,17 @@ string grammar(Memoization withMemo = Memoization.yes)(ParseTree defAsParseTree) switch (child.name) { case "Pegged.OPTION": - result = "pegged.peg.option!(" ~ result ~ ")"; + result = "PEG.option!(" ~ result ~ ")"; break; case "Pegged.ZEROORMORE": - result = "pegged.peg.zeroOrMore!(" ~ result ~ ")"; + result = "PEG.zeroOrMore!(" ~ result ~ ")"; break; case "Pegged.ONEORMORE": - result = "pegged.peg.oneOrMore!(" ~ result ~ ")"; + result = "PEG.oneOrMore!(" ~ result ~ ")"; break; case "Pegged.Action": foreach(action; child.matches) - result = "pegged.peg.action!(" ~ result ~ ", " ~ action ~ ")"; + result = "PEG.action!(" ~ result ~ ", " ~ action ~ ")"; break; default: break; @@ -756,20 +759,20 @@ string grammar(Memoization withMemo = Memoization.yes)(ParseTree defAsParseTree) break; case "Pegged.Literal": if(p.matches.length == 3) // standard case - result = "pegged.peg.literal!(\"" ~ p.matches[1] ~ "\")"; + result = "PEG.literal!(\"" ~ p.matches[1] ~ "\")"; else // only two children -> empty literal - result = "pegged.peg.literal!(``)"; + result = "PEG.literal!(``)"; break; case "Pegged.CILiteral": if(p.matches.length == 3) // standard case - result = "pegged.peg.caseInsensitiveLiteral!(\"" ~ p.matches[1] ~ "\")"; + result = "PEG.caseInsensitiveLiteral!(\"" ~ p.matches[1] ~ "\")"; else // only two children -> empty literal - result = "pegged.peg.caseInsensitiveLiteral!(``)"; + result = "PEG.caseInsensitiveLiteral!(``)"; break; case "Pegged.CharClass": if (p.children.length > 1) { - result = "pegged.peg.or!("; + result = "PEG.or!("; foreach(seq; p.children) result ~= generateCode(seq) ~ ", "; result = result[0..$-2] ~ ")"; @@ -783,14 +786,14 @@ string grammar(Memoization withMemo = Memoization.yes)(ParseTree defAsParseTree) /// Make the generation at the Char level: directly what is needed, be it `` or "" or whatever if (p.children.length > 1) // a-b range { - result = "pegged.peg.charRange!('" ~ generateCode(p.children[0]) + result = "PEG.charRange!('" ~ generateCode(p.children[0]) ~ "', '" ~ generateCode(p.children[1]) ~ "')"; } else // lone char { - result = "pegged.peg.literal!("; + result = "PEG.literal!("; string ch = p.matches[0]; switch (ch) { @@ -811,7 +814,7 @@ string grammar(Memoization withMemo = Memoization.yes)(ParseTree defAsParseTree) break; case "\"": case "\\\"": - result ~= "`\"`)"; + result ~= q{`"`)}; break; case "\n": case "\r": @@ -847,48 +850,48 @@ string grammar(Memoization withMemo = Memoization.yes)(ParseTree defAsParseTree) } break; case "Pegged.POS": - result = "pegged.peg.posLookahead!("; + result = "PEG.posLookahead!("; break; case "Pegged.NEG": - result = "pegged.peg.negLookahead!("; + result = "PEG.negLookahead!("; break; case "Pegged.FUSE": - result = "pegged.peg.fuse!("; + result = "PEG.fuse!("; break; case "Pegged.DISCARD": - result = "pegged.peg.discard!("; + result = "PEG.discard!("; break; //case "Pegged.CUT": // result = "discardChildren!("; // break; case "Pegged.KEEP": - result = "pegged.peg.keep!("; + result = "PEG.keep!("; break; case "Pegged.DROP": - result = "pegged.peg.drop!("; + result = "PEG.drop!("; break; case "Pegged.PROPAGATE": - result = "pegged.peg.propagate!("; + result = "PEG.propagate!("; break; case "Pegged.OPTION": - result = "pegged.peg.option!("; + result = "PEG.option!("; break; case "Pegged.ZEROORMORE": - result = "pegged.peg.zeroOrMore!("; + result = "PEG.zeroOrMore!("; break; case "Pegged.ONEORMORE": - result = "pegged.peg.oneOrMore!("; + result = "PEG.oneOrMore!("; break; case "Pegged.Action": result = generateCode(p.children[0]); foreach(action; p.matches[1..$]) - result = "pegged.peg.action!(" ~ result ~ ", " ~ action ~ ")"; + result = "PEG.action!(" ~ result ~ ", " ~ action ~ ")"; break; case "Pegged.ANY": - result = "pegged.peg.any"; + result = "PEG.any"; break; case "Pegged.WrapAround": - result = "pegged.peg.wrapAround!(" ~ generateCode(p.children[0]) ~ ", " + result = "PEG.wrapAround!(" ~ generateCode(p.children[0]) ~ ", " ~ generateCode(p.children[1]) ~ ", " ~ generateCode(p.children[2]) ~ ")"; break; @@ -979,6 +982,11 @@ mixin template expected() unittest // 'grammar' unit test: low-level functionalities { + alias ParseTree = DefaultParseTree; + mixin ParseCollections!ParseTree; + alias PEG=PeggedT!ParseTree; + mixin DefaultParsePatterns!PEG; + mixin(grammar(` Test1: Rule1 <- 'a' @@ -999,9 +1007,13 @@ unittest // 'grammar' unit test: low-level functionalities unittest // 'grammar' unit test: PEG syntax { - // Here we do not test pegged.peg.*, just the grammar transformations - // From a PEG to a Pegged expression template. + alias ParseTree = DefaultParseTree; + mixin ParseCollections!ParseTree; + alias PEG=PeggedT!ParseTree; + mixin DefaultParsePatterns!PEG; + // Here we do not test PEG.*, just the grammar transformations + // From a PEG to a Pegged expression template. mixin(grammar(` Terminals: Literal1 <- "abc" @@ -1359,6 +1371,8 @@ Rule4 <- 'f' Rule5 # Rule4 ends with 'f', then it's Rule5 unittest // Parsing at compile-time { + alias ParseTree = DefaultParseTree; + mixin(grammar(` Test: Rule1 <- 'a' Rule2('b') @@ -2137,7 +2151,7 @@ unittest // qualified names for rules Second: Rule1 <- First.Rule1 Rule2 <- First.Rule2 - Rule3 <- pegged.peg.list(pegged.peg.identifier, ',') + Rule3 <- PEG.list(PEG.identifier, ',') `)); // Equal on success @@ -2598,9 +2612,9 @@ unittest // Memoization testing assert(result3 == result4); //Directly comparing result1 and result3 is not possible, for the grammar names are different - assert(pegged.peg.softCompare(result1, result2)); - assert(pegged.peg.softCompare(result1, result3)); - assert(pegged.peg.softCompare(result1, result4)); + assert(PEG.softCompare(result1, result2)); + assert(PEG.softCompare(result1, result3)); + assert(PEG.softCompare(result1, result4)); } unittest // Memoization reset in composed grammars. Issue #162 diff --git a/pegged/peg.d b/pegged/peg.d index ab131f1..36f2171 100644 --- a/pegged/peg.d +++ b/pegged/peg.d @@ -145,6 +145,11 @@ ParseTree eoi(ParseTree)(const ParseTree p) if (isParseTree!ParseTree) { return ParseTree("eoi", false, ["end of input"], p.input, p.end, p.end); } +ParseTree eps(ParseTree)(const ParseTree p) if (isParseTree!ParseTree) { + return ParseTree("eps", true, [""], p.input, p.end, p.end); +} + + mixin template ParseTreeM() { import std.functional : toDelegate; @@ -769,11 +774,6 @@ struct PeggedT(ParseTree) { eps matches the empty string (usually denoted by the Greek letter 'epsilon') and always succeeds. It's equivalent to literal!"" (for example, it creates a match of [""]: one match, the empty string). */ - ParseTree eps(ParseTree p) - { - return ParseTree("eps", true, [""], p.input, p.end, p.end); - } - ParseTree eps(string input) { return eps(ParseTree("",false,[], input)); @@ -977,11 +977,11 @@ unittest // 'literal' unit test It succeeds if a case insensitive comparison of a prefix of the input and its template parameter yields no difference and fails otherwise. */ -template caseInsensitiveLiteralT(ParseTreeT, string s) +template caseInsensitiveLiteralT(ParseTree, string s) { enum name = "caseInsensitiveLiteral!(\""~s~"\")"; - ParseTreeT caseInsensitiveLiteral(ParseTree p) + ParseTree caseInsensitiveLiteralT(ParseTree p) { enum lit = "\"" ~ s ~ "\""; if (p.end+s.length <= p.input.length && icmp(p.input[p.end..p.end+s.length], s) == 0) @@ -990,13 +990,13 @@ template caseInsensitiveLiteralT(ParseTreeT, string s) return ParseTree(name, false, [lit], p.input, p.end, p.end); } - ParseTreeT caseInsensitiveLiteral(string input) + ParseTree caseInsensitiveLiteralT(string input) { - return .caseInsensitiveLiteral!(s)(ParseTree("", false, [], input)); + return caseInsensitiveLiteralT!(ParseTree, s)(ParseTree("", false, [], input)); } - string caseInsensitiveLiteral(GetName g) + string caseInsensitiveLiteralT(GetName g) { return name; } @@ -1007,6 +1007,7 @@ unittest // 'caseInsensitiveLiteral' unit test { alias ParseTree = DefaultParseTree; mixin ParseCollections!ParseTree; + ParseTree input = ParseTree("input", true, [], "AbCdEf", 0,0, null); alias caseInsensitiveLiteral!"a" a; @@ -1555,7 +1556,7 @@ unittest // 'and' unit test } version (unittest) { - static ParseTree getError(ref ParseTree p) { + static ParseTree getError(ParseTree)(ref ParseTree p) if (isParseTree!ParseTree) { if (p.children.length > 0) return getError(p.children[$-1]); return p; @@ -1621,7 +1622,7 @@ unittest // 'and' unit test with oneOrMore and longest failing match template wrapAroundT(ParseTree, alias before, alias target, alias after) { - ParseTree wrapAround(ParseTree p) + ParseTree wrapAroundT(ParseTree p) { ParseTree temp = before(p); if (!temp.successful) @@ -1640,12 +1641,12 @@ template wrapAroundT(ParseTree, alias before, alias target, alias after) return result; } - ParseTree wrapAround(string input) + ParseTree wrapAroundT(string input) { - return .wrapAround!(before, target, after)(ParseTree("",false,[],input)); + return wrapAroundT!(ParseTree, before, target, after)(ParseTree("",false,[],input)); } - string wrapAround(GetName g) + string wrapAroundT(GetName g) { return "wrapAround!(" ~ getName!(before)() ~ ", " ~ getName!(target)() ~ @@ -2239,7 +2240,7 @@ template keywordsT(ParseTree,kws...) if (kws.length > 0) enum name = ctfeGetNameKeywords(); enum failString = "one among " ~ ctfeConcatKeywords(); - ParseTree keywords(ParseTree p) + ParseTree keywordsT(ParseTree p) { string keywordCode(string[] keywords) { @@ -2278,12 +2279,12 @@ template keywordsT(ParseTree,kws...) if (kws.length > 0) } } - ParseTree keywords(string input) + ParseTree keywordsT(string input) { - return .keywords!(kws)(ParseTree("",false,[],input)); + return keywordsT!(ParseTree, kws)(ParseTree("",false,[],input)); } - string keywords(GetName g) + string keywordsT(GetName g) { return name; } @@ -3419,7 +3420,7 @@ unittest // 'discard' unit test */ template dropT(ParseTree, alias r) { - ParseTree drop(ParseTree p) + ParseTree dropT(ParseTree p) { ParseTree result = r(p); //result.begin = result.end; @@ -3429,12 +3430,12 @@ template dropT(ParseTree, alias r) return result; } - ParseTree drop(string input) + ParseTree dropT(string input) { - return .drop!(r)(ParseTree("",false,[],input)); + return dropT!(ParseTree, r)(ParseTree("",false,[],input)); } - string drop(GetName g) + string dropT(GetName g) { return "drop!(" ~ getName!(r)() ~ ")"; } @@ -3503,7 +3504,7 @@ unittest // 'drop' unit test */ template propagateT(ParseTree, alias r) { - ParseTree propagate(ParseTree p) + ParseTree propagateT(ParseTree p) { ParseTree result = r(p); if (result.successful) @@ -3511,12 +3512,12 @@ template propagateT(ParseTree, alias r) return result; } - ParseTree propagate(string input) + ParseTree propagateT(string input) { - return .propagate!(r)(ParseTree("",false,[],input)); + return propagateT!(ParseTree, r)(ParseTree("",false,[],input)); } - string propagate(GetName g) + string propagateT(GetName g) { return "propagate!(" ~ getName!(r)() ~ ")"; } diff --git a/pegged/tester/testerparser.d b/pegged/tester/testerparser.d index b91745d..2b193fc 100644 --- a/pegged/tester/testerparser.d +++ b/pegged/tester/testerparser.d @@ -24,7 +24,7 @@ UnorderedBranch < Spacing <: (blank / Comment)* -Comment <- +Comment <- / '//' (!eol .)* (eol) / '/*' (!'*/' .)* '*/' / NestedComment @@ -39,8 +39,11 @@ NestedCommentEnd <- '+/' module pegged.tester.testerparser; public import pegged.peg; -struct GenericTesterGrammar(TParseTree) +struct GenericTesterGrammar(ParseTree) { + alias PEG=PeggedT!ParseTree; + mixin DefaultParsePatterns!PEG; + struct TesterGrammar { enum name = "TesterGrammar"; @@ -63,134 +66,134 @@ struct GenericTesterGrammar(TParseTree) } } mixin decimateTree; - static TParseTree Root(TParseTree p) + static ParseTree Root(ParseTree p) { return pegged.peg.named!(pegged.peg.and!(pegged.peg.wrapAround!(Spacing, Node, Spacing), pegged.peg.wrapAround!(Spacing, eoi, Spacing)), "TesterGrammar.Root")(p); } - static TParseTree Root(string s) + static ParseTree Root(string s) { - return pegged.peg.named!(pegged.peg.and!(pegged.peg.wrapAround!(Spacing, Node, Spacing), pegged.peg.wrapAround!(Spacing, eoi, Spacing)), "TesterGrammar.Root")(TParseTree("", false,[], s)); + return pegged.peg.named!(pegged.peg.and!(pegged.peg.wrapAround!(Spacing, Node, Spacing), pegged.peg.wrapAround!(Spacing, eoi, Spacing)), "TesterGrammar.Root")(ParseTree("", false,[], s)); } static string Root(GetName g) { return "TesterGrammar.Root"; } - static TParseTree Node(TParseTree p) + static ParseTree Node(ParseTree p) { return pegged.peg.named!(pegged.peg.or!(pegged.peg.and!(pegged.peg.discard!(pegged.peg.wrapAround!(Spacing, pegged.peg.literal!("^"), Spacing)), pegged.peg.wrapAround!(Spacing, identifier, Spacing)), pegged.peg.and!(pegged.peg.wrapAround!(Spacing, identifier, Spacing), pegged.peg.zeroOrMore!(pegged.peg.wrapAround!(Spacing, pegged.peg.propagate!(pegged.peg.wrapAround!(Spacing, Branch, Spacing)), Spacing)))), "TesterGrammar.Node")(p); } - static TParseTree Node(string s) + static ParseTree Node(string s) { - return pegged.peg.named!(pegged.peg.or!(pegged.peg.and!(pegged.peg.discard!(pegged.peg.wrapAround!(Spacing, pegged.peg.literal!("^"), Spacing)), pegged.peg.wrapAround!(Spacing, identifier, Spacing)), pegged.peg.and!(pegged.peg.wrapAround!(Spacing, identifier, Spacing), pegged.peg.zeroOrMore!(pegged.peg.wrapAround!(Spacing, pegged.peg.propagate!(pegged.peg.wrapAround!(Spacing, Branch, Spacing)), Spacing)))), "TesterGrammar.Node")(TParseTree("", false,[], s)); + return pegged.peg.named!(pegged.peg.or!(pegged.peg.and!(pegged.peg.discard!(pegged.peg.wrapAround!(Spacing, pegged.peg.literal!("^"), Spacing)), pegged.peg.wrapAround!(Spacing, identifier, Spacing)), pegged.peg.and!(pegged.peg.wrapAround!(Spacing, identifier, Spacing), pegged.peg.zeroOrMore!(pegged.peg.wrapAround!(Spacing, pegged.peg.propagate!(pegged.peg.wrapAround!(Spacing, Branch, Spacing)), Spacing)))), "TesterGrammar.Node")(ParseTree("", false,[], s)); } static string Node(GetName g) { return "TesterGrammar.Node"; } - static TParseTree Branch(TParseTree p) + static ParseTree Branch(ParseTree p) { return pegged.peg.named!(pegged.peg.or!(pegged.peg.wrapAround!(Spacing, OrderedBranch, Spacing), pegged.peg.wrapAround!(Spacing, UnorderedBranch, Spacing)), "TesterGrammar.Branch")(p); } - static TParseTree Branch(string s) + static ParseTree Branch(string s) { - return pegged.peg.named!(pegged.peg.or!(pegged.peg.wrapAround!(Spacing, OrderedBranch, Spacing), pegged.peg.wrapAround!(Spacing, UnorderedBranch, Spacing)), "TesterGrammar.Branch")(TParseTree("", false,[], s)); + return pegged.peg.named!(pegged.peg.or!(pegged.peg.wrapAround!(Spacing, OrderedBranch, Spacing), pegged.peg.wrapAround!(Spacing, UnorderedBranch, Spacing)), "TesterGrammar.Branch")(ParseTree("", false,[], s)); } static string Branch(GetName g) { return "TesterGrammar.Branch"; } - static TParseTree OrderedBranch(TParseTree p) + static ParseTree OrderedBranch(ParseTree p) { return pegged.peg.named!(pegged.peg.or!(pegged.peg.and!(pegged.peg.discard!(pegged.peg.wrapAround!(Spacing, pegged.peg.literal!("->"), Spacing)), pegged.peg.discard!(pegged.peg.wrapAround!(Spacing, pegged.peg.literal!("{"), Spacing)), pegged.peg.oneOrMore!(pegged.peg.wrapAround!(Spacing, Node, Spacing)), pegged.peg.discard!(pegged.peg.wrapAround!(Spacing, pegged.peg.literal!("}"), Spacing))), pegged.peg.and!(pegged.peg.discard!(pegged.peg.wrapAround!(Spacing, pegged.peg.literal!("->"), Spacing)), pegged.peg.wrapAround!(Spacing, Node, Spacing))), "TesterGrammar.OrderedBranch")(p); } - static TParseTree OrderedBranch(string s) + static ParseTree OrderedBranch(string s) { - return pegged.peg.named!(pegged.peg.or!(pegged.peg.and!(pegged.peg.discard!(pegged.peg.wrapAround!(Spacing, pegged.peg.literal!("->"), Spacing)), pegged.peg.discard!(pegged.peg.wrapAround!(Spacing, pegged.peg.literal!("{"), Spacing)), pegged.peg.oneOrMore!(pegged.peg.wrapAround!(Spacing, Node, Spacing)), pegged.peg.discard!(pegged.peg.wrapAround!(Spacing, pegged.peg.literal!("}"), Spacing))), pegged.peg.and!(pegged.peg.discard!(pegged.peg.wrapAround!(Spacing, pegged.peg.literal!("->"), Spacing)), pegged.peg.wrapAround!(Spacing, Node, Spacing))), "TesterGrammar.OrderedBranch")(TParseTree("", false,[], s)); + return pegged.peg.named!(pegged.peg.or!(pegged.peg.and!(pegged.peg.discard!(pegged.peg.wrapAround!(Spacing, pegged.peg.literal!("->"), Spacing)), pegged.peg.discard!(pegged.peg.wrapAround!(Spacing, pegged.peg.literal!("{"), Spacing)), pegged.peg.oneOrMore!(pegged.peg.wrapAround!(Spacing, Node, Spacing)), pegged.peg.discard!(pegged.peg.wrapAround!(Spacing, pegged.peg.literal!("}"), Spacing))), pegged.peg.and!(pegged.peg.discard!(pegged.peg.wrapAround!(Spacing, pegged.peg.literal!("->"), Spacing)), pegged.peg.wrapAround!(Spacing, Node, Spacing))), "TesterGrammar.OrderedBranch")(ParseTree("", false,[], s)); } static string OrderedBranch(GetName g) { return "TesterGrammar.OrderedBranch"; } - static TParseTree UnorderedBranch(TParseTree p) + static ParseTree UnorderedBranch(ParseTree p) { return pegged.peg.named!(pegged.peg.or!(pegged.peg.and!(pegged.peg.discard!(pegged.peg.wrapAround!(Spacing, pegged.peg.literal!("~>"), Spacing)), pegged.peg.discard!(pegged.peg.wrapAround!(Spacing, pegged.peg.literal!("{"), Spacing)), pegged.peg.oneOrMore!(pegged.peg.wrapAround!(Spacing, Node, Spacing)), pegged.peg.discard!(pegged.peg.wrapAround!(Spacing, pegged.peg.literal!("}"), Spacing))), pegged.peg.and!(pegged.peg.discard!(pegged.peg.wrapAround!(Spacing, pegged.peg.literal!("~>"), Spacing)), pegged.peg.wrapAround!(Spacing, Node, Spacing))), "TesterGrammar.UnorderedBranch")(p); } - static TParseTree UnorderedBranch(string s) + static ParseTree UnorderedBranch(string s) { - return pegged.peg.named!(pegged.peg.or!(pegged.peg.and!(pegged.peg.discard!(pegged.peg.wrapAround!(Spacing, pegged.peg.literal!("~>"), Spacing)), pegged.peg.discard!(pegged.peg.wrapAround!(Spacing, pegged.peg.literal!("{"), Spacing)), pegged.peg.oneOrMore!(pegged.peg.wrapAround!(Spacing, Node, Spacing)), pegged.peg.discard!(pegged.peg.wrapAround!(Spacing, pegged.peg.literal!("}"), Spacing))), pegged.peg.and!(pegged.peg.discard!(pegged.peg.wrapAround!(Spacing, pegged.peg.literal!("~>"), Spacing)), pegged.peg.wrapAround!(Spacing, Node, Spacing))), "TesterGrammar.UnorderedBranch")(TParseTree("", false,[], s)); + return pegged.peg.named!(pegged.peg.or!(pegged.peg.and!(pegged.peg.discard!(pegged.peg.wrapAround!(Spacing, pegged.peg.literal!("~>"), Spacing)), pegged.peg.discard!(pegged.peg.wrapAround!(Spacing, pegged.peg.literal!("{"), Spacing)), pegged.peg.oneOrMore!(pegged.peg.wrapAround!(Spacing, Node, Spacing)), pegged.peg.discard!(pegged.peg.wrapAround!(Spacing, pegged.peg.literal!("}"), Spacing))), pegged.peg.and!(pegged.peg.discard!(pegged.peg.wrapAround!(Spacing, pegged.peg.literal!("~>"), Spacing)), pegged.peg.wrapAround!(Spacing, Node, Spacing))), "TesterGrammar.UnorderedBranch")(ParseTree("", false,[], s)); } static string UnorderedBranch(GetName g) { return "TesterGrammar.UnorderedBranch"; } - static TParseTree Spacing(TParseTree p) + static ParseTree Spacing(ParseTree p) { return pegged.peg.named!(pegged.peg.discard!(pegged.peg.zeroOrMore!(pegged.peg.or!(blank, Comment))), "TesterGrammar.Spacing")(p); } - static TParseTree Spacing(string s) + static ParseTree Spacing(string s) { - return pegged.peg.named!(pegged.peg.discard!(pegged.peg.zeroOrMore!(pegged.peg.or!(blank, Comment))), "TesterGrammar.Spacing")(TParseTree("", false,[], s)); + return pegged.peg.named!(pegged.peg.discard!(pegged.peg.zeroOrMore!(pegged.peg.or!(blank, Comment))), "TesterGrammar.Spacing")(ParseTree("", false,[], s)); } static string Spacing(GetName g) { return "TesterGrammar.Spacing"; } - static TParseTree Comment(TParseTree p) + static ParseTree Comment(ParseTree p) { return pegged.peg.named!(pegged.peg.or!(pegged.peg.and!(pegged.peg.literal!("//"), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(eol), pegged.peg.any)), eol), pegged.peg.and!(pegged.peg.literal!("/*"), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(pegged.peg.literal!("*/")), pegged.peg.any)), pegged.peg.literal!("*/")), NestedComment), "TesterGrammar.Comment")(p); } - static TParseTree Comment(string s) + static ParseTree Comment(string s) { - return pegged.peg.named!(pegged.peg.or!(pegged.peg.and!(pegged.peg.literal!("//"), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(eol), pegged.peg.any)), eol), pegged.peg.and!(pegged.peg.literal!("/*"), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(pegged.peg.literal!("*/")), pegged.peg.any)), pegged.peg.literal!("*/")), NestedComment), "TesterGrammar.Comment")(TParseTree("", false,[], s)); + return pegged.peg.named!(pegged.peg.or!(pegged.peg.and!(pegged.peg.literal!("//"), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(eol), pegged.peg.any)), eol), pegged.peg.and!(pegged.peg.literal!("/*"), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(pegged.peg.literal!("*/")), pegged.peg.any)), pegged.peg.literal!("*/")), NestedComment), "TesterGrammar.Comment")(ParseTree("", false,[], s)); } static string Comment(GetName g) { return "TesterGrammar.Comment"; } - static TParseTree NestedComment(TParseTree p) + static ParseTree NestedComment(ParseTree p) { return pegged.peg.named!(pegged.peg.and!(pegged.peg.literal!("/+"), pegged.peg.or!(pegged.peg.and!(pegged.peg.negLookahead!(NestedCommentEnd), pegged.peg.any), NestedComment), NestedCommentEnd), "TesterGrammar.NestedComment")(p); } - static TParseTree NestedComment(string s) + static ParseTree NestedComment(string s) { - return pegged.peg.named!(pegged.peg.and!(pegged.peg.literal!("/+"), pegged.peg.or!(pegged.peg.and!(pegged.peg.negLookahead!(NestedCommentEnd), pegged.peg.any), NestedComment), NestedCommentEnd), "TesterGrammar.NestedComment")(TParseTree("", false,[], s)); + return pegged.peg.named!(pegged.peg.and!(pegged.peg.literal!("/+"), pegged.peg.or!(pegged.peg.and!(pegged.peg.negLookahead!(NestedCommentEnd), pegged.peg.any), NestedComment), NestedCommentEnd), "TesterGrammar.NestedComment")(ParseTree("", false,[], s)); } static string NestedComment(GetName g) { return "TesterGrammar.NestedComment"; } - static TParseTree NestedCommentEnd(TParseTree p) + static ParseTree NestedCommentEnd(ParseTree p) { return pegged.peg.named!(pegged.peg.literal!("+/"), "TesterGrammar.NestedCommentEnd")(p); } - static TParseTree NestedCommentEnd(string s) + static ParseTree NestedCommentEnd(string s) { - return pegged.peg.named!(pegged.peg.literal!("+/"), "TesterGrammar.NestedCommentEnd")(TParseTree("", false,[], s)); + return pegged.peg.named!(pegged.peg.literal!("+/"), "TesterGrammar.NestedCommentEnd")(ParseTree("", false,[], s)); } static string NestedCommentEnd(GetName g) { return "TesterGrammar.NestedCommentEnd"; } - static TParseTree opCall(TParseTree p) + static ParseTree opCall(ParseTree p) { - TParseTree result = decimateTree(Root(p)); + ParseTree result = decimateTree(Root(p)); result.children = [result]; result.name = "TesterGrammar"; return result; } - static TParseTree opCall(string input) + static ParseTree opCall(string input) { - return TesterGrammar(TParseTree(``, false, [], input, 0, 0)); + return TesterGrammar(ParseTree(``, false, [], input, 0, 0)); } static string opCall(GetName g) { @@ -200,5 +203,4 @@ struct GenericTesterGrammar(TParseTree) } } -alias GenericTesterGrammar!(ParseTree).TesterGrammar TesterGrammar; - +alias GenericTesterGrammar!(DefaultParseTree).TesterGrammar TesterGrammar; From 838ee0b06e3e4534f3003eaa2d16d4ee653af653 Mon Sep 17 00:00:00 2001 From: cbleser Date: Mon, 31 May 2021 23:31:59 +0300 Subject: [PATCH 04/29] WIP: Unittest passed except for doTest --- pegged/grammar.d | 74 +++- pegged/peg.d | 680 ++++++++++++++++------------------- pegged/tester/testerparser.d | 36 +- 3 files changed, 395 insertions(+), 395 deletions(-) diff --git a/pegged/grammar.d b/pegged/grammar.d index d99e276..cde1d52 100644 --- a/pegged/grammar.d +++ b/pegged/grammar.d @@ -452,7 +452,7 @@ string grammar(ParseTree, Memoization withMemo = Memoization.yes)(ParseTree defA innerName ~= "\"" ~ shortName ~ "!(\" ~ "; hookedName ~= "_" ~ to!string(p.children[0].children[1].children.length); foreach(i,param; p.children[0].children[1].children) - innerName ~= "PEG.getName!("~ param.children[0].matches[0] + innerName ~= "pegged.peg.getName!("~ param.children[0].matches[0] ~ (i 0 && isAlpha(p.input[p.end-1]) && p.end < p.input.length && !isAlpha(p.input[p.end])) + || (p.end > 0 && !isAlpha(p.input[p.end-1]) && p.end < p.input.length && isAlpha(p.input[p.end])); + if (matched) + return ParseTree("wordBoundary", matched, [], p.input, p.end, p.end, null); + else + return ParseTree("wordBoundary", matched, ["word boundary"], p.input, p.end, p.end, null); +} + +/** + Basic rule, that always fail without consuming. +*/ +ParseTree fail(ParseTree)(const ParseTree p) @safe if (isParseTree!ParseTree) { + return ParseTree("fail", false, [], p.input, p.end, p.end, null); +} + + mixin template ParseTreeM() { + import pegged.peg; import std.functional : toDelegate; alias ParseTree = typeof(this); string name; /// The node name @@ -374,7 +406,7 @@ unittest struct PeggedT(ParseTree) { - import pegged.peg; + import pegged.peg : fail, eoi, wordBoundary, eps; mixin ParseCollections!ParseTree; version (tracer) { @@ -520,144 +552,20 @@ struct PeggedT(ParseTree) { } } - unittest // ParseTree testing - { - ParseTree p; - assert(p == p, "Self-identity on null tree."); - - p = ParseTree("Name", true, ["abc", "", "def"], "input", 0, 1, null); - assert(p == p, "Self identity on non-null tree."); - - ParseTree child = ParseTree("Child", true, ["abc", "", "def"], "input", 0, 1, null); - p.children = [child, child]; - - assert(p.children[0] == p[0], "override opIndex allows to write less verbose code to navigate the tree"); - assert(p.children == p[] ); - assert(p.children[0..1] == p[0..1] ); - assert(p.children[0..$] == p[0..$] ); - - ParseTree q = p; - assert(p == q, "Copying creates equal trees."); - - assert(p.children == q.children); - p.children = [child, child, child]; - assert(q.children != p.children, "Disconnecting children."); - - p = ParseTree("Name", true, ["abc", "", "def"], "input", 0, 1, null); - p.children = [child, child]; - - q = p.dup; - assert(p == q, "Dupping creates equal trees."); - - assert(p.children == q.children, "Equal children for dupped trees."); - p.children = null; - assert(q.children != p.children); - - immutable iq = p.idup; - q = iq.dup; - assert(p == q, "Dupping to/from immutable creates equal trees."); - - q.children = [p,p]; - assert(p != q, "Tree with different children are not equal."); - - p.children = [p,p]; - assert(p == q, "Adding equivalent children is OK."); - - p.matches = null; - assert(p != q, "Nulling matches makes trees unequal."); - - p.matches = q.matches; - assert(p == q, "Copying matches makes equal trees."); - - p.children[0].successful = false; - assert(p.children[0].failMsg == `Failure at line 0, col 1, after "i" expected "def", but got "nput"`); - assert(p.children[1].failMsg == "Sucess"); - assert(p.failMsg == `Failure at line 0, col 1, after "i" expected "def", but got "nput"`); - } - -/// To compare two trees for content (not bothering with node names) -/// That's useful to compare the results from two different grammars. - static bool softCompare(const ParseTree p1, const ParseTree p2) - { - return p1.successful == p2.successful - && p1.matches == p2.matches - && p1.begin == p2.begin - && p1.end == p2.end - && equal!(softCompare)(p1.children, p2.children); // the same for children - } - - unittest // softCompare - { - ParseTree p = ParseTree("Name", true, ["abc", "", "def"], "input", 0, 1, null); - ParseTree child = ParseTree("Child", true, ["abc", "", "def"], "input", 0, 1, null); - p.children = [child, child]; - - ParseTree q = p; - assert(p == q, "Copy => Equal trees."); - assert(softCompare(p,q), "Copy => Trees equal for softCompare."); - - q.name = "Another One"; - assert(p != q, "Name change => non-equal trees."); - assert(softCompare(p,q), "Name change => Trees equal for softCompare."); - } - -/** - Basic rule, that always fail without consuming. -*/ - ParseTree fail(ParseTree p) - { - return ParseTree("fail", false, [], p.input, p.end, p.end, null); - } - /// ditto - ParseTree fail(string input) + static ParseTree fail(string input) { return fail(ParseTree("", false, [], input)); } - unittest // 'fail' unit test - { - ParseTree input = ParseTree("input", true, [], "This is the input string.", 0,0, null); - ParseTree result = fail(input); - assert(result.name == "fail"); - assert(!result.successful, "'fail' fails."); - assert(result.matches is null, "'fail' makes no match."); - assert(result.input == input.input, "'fail' does not change the input."); - assert(result.end == input.end, "'fail' puts the index after the previous parse."); - assert(result.children is null, "'fail' has no children."); - - result = fail("This is the input string."); - assert(!result.successful, "'fail' fails."); - } - /// ditto static ParseTree eoi(string input) { - return .eoi(ParseTree("", false, [], input)); + return eoi(ParseTree("", false, [], input)); } alias eoi endOfInput; /// helper alias. - unittest // 'eoi' unit test - { - ParseTree input = ParseTree("input", true, [], "This is the input string.", 0,0, null); - ParseTree result = eoi(input); - assert(result.name == "eoi"); - assert(!result.successful, "'eoi' fails on non-null string."); - assert(result.matches == ["end of input"], "'eoi' error message."); - assert(result.input == input.input, "'eoi' does not change the input."); - assert(result.end == input.end, "'eoi' puts the index after the previous parse."); - assert(result.children is null, "'eoi' has no children."); - - input = ParseTree("input", true, [], "", 0,0, null); - result = eoi(input); - assert(result.successful, "'eoi' succeeds on strings of length 0."); - result = eoi(""); - assert(result.successful, "'eoi' succeeds on strings of length 0."); - result = eoi(null); - assert(result.successful, "'eoi' succeeds on null strings"); - } - /** Match any character. As long as there is at least a character left in the input, it succeeds. Conversely, it fails only if called at the end of the input. @@ -676,60 +584,6 @@ struct PeggedT(ParseTree) { return any(ParseTree("", false, [], input)); } - unittest // 'any' unit test - { - ParseTree input = ParseTree("input", true, [], "This is the input string.", 0,0, null); - ParseTree result = any(input); - - assert(result.name == "any"); - assert(result.successful, "'any' succeeds on non-null strings."); - assert(result.matches == ["T"], "'any' matches the first char in an input."); - assert(result.input == input.input, "'any' does not change the input."); - assert(result.end == input.end+1, "'any' advances the index by one position."); - assert(result.children is null, "'any' has no children."); - - result = any("a"); - assert(result.successful, "'any' matches on strings of length one."); - assert(result.matches == ["a"], "'any' matches the first char in an input."); - assert(result.input == "a", "'any' does not change the input."); - assert(result.end == 1, "'any' advances the index by one position."); - assert(result.children is null, "'any' has no children."); - - input = ParseTree("input", true, [], "", 0,0, null); - - result = any(input); - assert(!result.successful, "'any' fails on strings of length 0."); - assert(result.matches == ["any char"], "'any' error message on strings of length 0."); - assert(result.end == 0, "'any' does not advance the index."); - - result = any(""); - assert(!result.successful, "'any' fails on strings of length 0."); - assert(result.matches == ["any char"], "'any' error message on strings of length 0."); - assert(result.end == 0, "'any' does not advance the index."); - - result = any(null); - assert(!result.successful, "'any' fails on null strings."); - assert(result.matches == ["any char"], "'any' error message on strings of length 0."); - assert(result.end == 0, "'any' does not advance the index."); - } - -/** - Predefined parser: matches word boundaries, as \b for regexes. -*/ - static ParseTree wordBoundary(ParseTree p) - { - // TODO: I added more indexing guards and now this could probably use - // some simplification. Too tired to write it better. --Chad - bool matched = (p.end == 0 && isAlpha(p.input.front())) - || (p.end == p.input.length && isAlpha(p.input.back())) - || (p.end > 0 && isAlpha(p.input[p.end-1]) && p.end < p.input.length && !isAlpha(p.input[p.end])) - || (p.end > 0 && !isAlpha(p.input[p.end-1]) && p.end < p.input.length && isAlpha(p.input[p.end])); - if (matched) - return ParseTree("wordBoundary", matched, [], p.input, p.end, p.end, null); - else - return ParseTree("wordBoundary", matched, ["word boundary"], p.input, p.end, p.end, null); - } - /// ditto static ParseTree wordBoundary(string input) { @@ -741,35 +595,6 @@ struct PeggedT(ParseTree) { return "wordBoundary"; } - unittest // word boundary - { - ParseTree input = ParseTree("", false, [], "This is a word."); - auto wb = [// "This" - cast(size_t)(0):true, 1:false, 2:false, 3:false, 4: true, - // "is" - 5: true, 6:false, 7: true, - // "a" - 8: true, 9:true, - // "word" - 10:true, 11:false, 12:false, 13:false, 14:true, - // "." - 15:false - ]; - - foreach(size_t index; 0 .. input.input.length) - { - input.end = index; - ParseTree result = wordBoundary(input); - - assert(result.name == "wordBoundary"); - assert(result.successful == wb[index]); // true, false, ... - // for errors, there is an error message - assert(result.successful && result.matches is null || !result.successful); - assert(result.begin == input.end); - assert(result.end == input.end); - assert(result.children is null); - } - } /** eps matches the empty string (usually denoted by the Greek letter 'epsilon') and always succeeds. It's equivalent to literal!"" (for example, it creates a match of [""]: one match, the empty string). @@ -783,32 +608,220 @@ struct PeggedT(ParseTree) { { return "eps"; } +} - unittest // 'eps' unit test - { - ParseTree input = ParseTree("input", true, [], "abcdef", 0,0, null); +version(unittest) { + private { + alias ParseTree = DefaultParseTree; + mixin ParseCollections!ParseTree; + alias PEG=PeggedT!ParseTree; + mixin DefaultParsePatterns!PEG; + } +} + +unittest // ParseTree testing +{ + ParseTree p; + assert(p == p, "Self-identity on null tree."); - ParseTree result = eps(input); + p = ParseTree("Name", true, ["abc", "", "def"], "input", 0, 1, null); + assert(p == p, "Self identity on non-null tree."); - assert(result.name == "eps"); - assert(result.successful, "'eps' succeeds on non-null inputs."); - assert(result.matches == [""], "'eps' matches '' at the beginning."); - assert(result.input == input.input, "'eps' does not change the input."); - assert(result.end == input.end+0, "'eps' does not advance the index."); - assert(result.children is null, "'eps' has no children."); + ParseTree child = ParseTree("Child", true, ["abc", "", "def"], "input", 0, 1, null); + p.children = [child, child]; - input.input = ""; + assert(p.children[0] == p[0], "override opIndex allows to write less verbose code to navigate the tree"); + assert(p.children == p[] ); + assert(p.children[0..1] == p[0..1] ); + assert(p.children[0..$] == p[0..$] ); - result = eps(input); - assert(result.name == "eps"); - assert(result.successful, "'eps' succeeds on empty strings."); - assert(result.matches == [""], "'eps' matches '' at the beginning, even on empty strings."); - assert(result.input == input.input, "'eps' does not change the input."); - assert(result.end == input.end+0, "'eps' does not advance the index."); - assert(result.children is null, "'eps' has no children."); - } + ParseTree q = p; + assert(p == q, "Copying creates equal trees."); + + assert(p.children == q.children); + p.children = [child, child, child]; + assert(q.children != p.children, "Disconnecting children."); + + p = ParseTree("Name", true, ["abc", "", "def"], "input", 0, 1, null); + p.children = [child, child]; + + q = p.dup; + assert(p == q, "Dupping creates equal trees."); + + assert(p.children == q.children, "Equal children for dupped trees."); + p.children = null; + assert(q.children != p.children); + + immutable iq = p.idup; + q = iq.dup; + assert(p == q, "Dupping to/from immutable creates equal trees."); + + q.children = [p,p]; + assert(p != q, "Tree with different children are not equal."); + + p.children = [p,p]; + assert(p == q, "Adding equivalent children is OK."); + + p.matches = null; + assert(p != q, "Nulling matches makes trees unequal."); + + p.matches = q.matches; + assert(p == q, "Copying matches makes equal trees."); + + p.children[0].successful = false; + assert(p.children[0].failMsg == `Failure at line 0, col 1, after "i" expected "def", but got "nput"`); + assert(p.children[1].failMsg == "Sucess"); + assert(p.failMsg == `Failure at line 0, col 1, after "i" expected "def", but got "nput"`); } +unittest // softCompare +{ + ParseTree p = ParseTree("Name", true, ["abc", "", "def"], "input", 0, 1, null); + ParseTree child = ParseTree("Child", true, ["abc", "", "def"], "input", 0, 1, null); + p.children = [child, child]; + + ParseTree q = p; + assert(p == q, "Copy => Equal trees."); + assert(softCompare(p,q), "Copy => Trees equal for softCompare."); + + q.name = "Another One"; + assert(p != q, "Name change => non-equal trees."); + assert(softCompare(p,q), "Name change => Trees equal for softCompare."); +} + + +unittest // 'fail' unit test +{ + + ParseTree input = ParseTree("input", true, [], "This is the input string.", 0,0, null); + ParseTree result = fail(input); + assert(result.name == "fail"); + assert(!result.successful, "'fail' fails."); + assert(result.matches is null, "'fail' makes no match."); + assert(result.input == input.input, "'fail' does not change the input."); + assert(result.end == input.end, "'fail' puts the index after the previous parse."); + assert(result.children is null, "'fail' has no children."); + + result = PEG.fail("This is the input string."); + assert(!result.successful, "'fail' fails."); +} + + +unittest // 'eoi' unit test +{ + ParseTree input = ParseTree("input", true, [], "This is the input string.", 0,0, null); + ParseTree result = eoi(input); + assert(result.name == "eoi"); + assert(!result.successful, "'eoi' fails on non-null string."); + assert(result.matches == ["end of input"], "'eoi' error message."); + assert(result.input == input.input, "'eoi' does not change the input."); + assert(result.end == input.end, "'eoi' puts the index after the previous parse."); + assert(result.children is null, "'eoi' has no children."); + + input = ParseTree("input", true, [], "", 0,0, null); + result = eoi(input); + assert(result.successful, "'eoi' succeeds on strings of length 0."); + result = PEG.eoi(""); + assert(result.successful, "'eoi' succeeds on strings of length 0."); + result = PEG.eoi(null); + assert(result.successful, "'eoi' succeeds on null strings"); +} + + +unittest // 'any' unit test +{ + ParseTree input = ParseTree("input", true, [], "This is the input string.", 0,0, null); + ParseTree result = PEG.any(input); + + assert(result.name == "any"); + assert(result.successful, "'any' succeeds on non-null strings."); + assert(result.matches == ["T"], "'any' matches the first char in an input."); + assert(result.input == input.input, "'any' does not change the input."); + assert(result.end == input.end+1, "'any' advances the index by one position."); + assert(result.children is null, "'any' has no children."); + + result = PEG.any("a"); + assert(result.successful, "'any' matches on strings of length one."); + assert(result.matches == ["a"], "'any' matches the first char in an input."); + assert(result.input == "a", "'any' does not change the input."); + assert(result.end == 1, "'any' advances the index by one position."); + assert(result.children is null, "'any' has no children."); + + input = ParseTree("input", true, [], "", 0,0, null); + + result = PEG.any(input); + assert(!result.successful, "'any' fails on strings of length 0."); + assert(result.matches == ["any char"], "'any' error message on strings of length 0."); + assert(result.end == 0, "'any' does not advance the index."); + + result = PEG.any(""); + assert(!result.successful, "'any' fails on strings of length 0."); + assert(result.matches == ["any char"], "'any' error message on strings of length 0."); + assert(result.end == 0, "'any' does not advance the index."); + + result = PEG.any(null); + assert(!result.successful, "'any' fails on null strings."); + assert(result.matches == ["any char"], "'any' error message on strings of length 0."); + assert(result.end == 0, "'any' does not advance the index."); +} + + +unittest // word boundary +{ + ParseTree input = ParseTree("", false, [], "This is a word."); + auto wb = [// "This" + cast(size_t)(0):true, 1:false, 2:false, 3:false, 4: true, + // "is" + 5: true, 6:false, 7: true, + // "a" + 8: true, 9:true, + // "word" + 10:true, 11:false, 12:false, 13:false, 14:true, + // "." + 15:false + ]; + + foreach(size_t index; 0 .. input.input.length) + { + input.end = index; + ParseTree result = wordBoundary(input); + + assert(result.name == "wordBoundary"); + assert(result.successful == wb[index]); // true, false, ... + // for errors, there is an error message + assert(result.successful && result.matches is null || !result.successful); + assert(result.begin == input.end); + assert(result.end == input.end); + assert(result.children is null); + } +} + + +unittest // 'eps' unit test +{ + ParseTree input = ParseTree("input", true, [], "abcdef", 0,0, null); + + ParseTree result = eps(input); + + assert(result.name == "eps"); + assert(result.successful, "'eps' succeeds on non-null inputs."); + assert(result.matches == [""], "'eps' matches '' at the beginning."); + assert(result.input == input.input, "'eps' does not change the input."); + assert(result.end == input.end+0, "'eps' does not advance the index."); + assert(result.children is null, "'eps' has no children."); + + input.input = ""; + + result = eps(input); + assert(result.name == "eps"); + assert(result.successful, "'eps' succeeds on empty strings."); + assert(result.matches == [""], "'eps' matches '' at the beginning, even on empty strings."); + assert(result.input == input.input, "'eps' does not change the input."); + assert(result.end == input.end+0, "'eps' does not advance the index."); + assert(result.children is null, "'eps' has no children."); +} + + /** * Default fail message formating function */ @@ -846,7 +859,7 @@ template literalT(ParseTree, string s) ParseTree literalT(string input) { - return .literalT!(ParseTree, s)(ParseTree("", false, [], input)); + return literalT!(ParseTree, s)(ParseTree("", false, [], input)); } @@ -859,8 +872,6 @@ template literalT(ParseTree, string s) unittest // 'literal' unit test { - alias ParseTree = DefaultParseTree; - mixin ParseCollections!ParseTree; ParseTree input = ParseTree("input", true, [], "abcdef", 0,0, null); @@ -1005,9 +1016,6 @@ template caseInsensitiveLiteralT(ParseTree, string s) unittest // 'caseInsensitiveLiteral' unit test { - alias ParseTree = DefaultParseTree; - mixin ParseCollections!ParseTree; - ParseTree input = ParseTree("input", true, [], "AbCdEf", 0,0, null); alias caseInsensitiveLiteral!"a" a; @@ -1158,9 +1166,6 @@ template charRangeT(ParseTree, dchar begin, dchar end) if (begin <= end) unittest // 'charRange' unit test { - alias ParseTree = DefaultParseTree; - mixin ParseCollections!ParseTree; - ParseTree input = ParseTree("input", true, [], "abcdef", 0,0, null); alias charRange!('a','a') aa; @@ -1434,12 +1439,11 @@ template andT(ParseTree, rules...) if (rules.length > 0) } -auto firstLongestFailedMatch(ParseTreeT)(ParseTreeT[] children, size_t threshold) { +auto firstLongestFailedMatch(ParseTree)(ParseTree[] children, size_t threshold) if (isParseTree!ParseTree) { return children.countUntil!(c => c.failEnd > threshold); } -auto maxFailEnd(ParseTreeT)(ParseTreeT[] children) -{ +auto maxFailEnd(ParseTree)(ParseTree[] children) if (isParseTree!ParseTree) { return children.map!(c => c.failEnd).maxElement; } @@ -1485,8 +1489,6 @@ bool failedChildFixup(ParseTreeT)(ref ParseTreeT p, size_t failEnd) unittest // 'and' unit test { - alias ParseTree = DefaultParseTree; - mixin ParseCollections!ParseTree; alias literal!"abc" abc; alias literal!"de" de; alias literal!"f" f; @@ -1565,9 +1567,6 @@ version (unittest) { unittest // 'and' unit test with zeroOrMore and longest failing match { - alias ParseTree = DefaultParseTree; - mixin ParseCollections!ParseTree; - alias literal!"abc" A; alias literal!"def" B; alias literal!"ghi" C; @@ -1584,8 +1583,6 @@ unittest // 'and' unit test with zeroOrMore and longest failing match unittest // 'and' unit test with option and longest failing match { - alias ParseTree = DefaultParseTree; - mixin ParseCollections!ParseTree; alias literal!"abc" A; alias literal!"def" B; @@ -1603,8 +1600,6 @@ unittest // 'and' unit test with option and longest failing match unittest // 'and' unit test with oneOrMore and longest failing match { - alias ParseTree = DefaultParseTree; - mixin ParseCollections!ParseTree; alias literal!"abc" A; alias literal!"def" B; @@ -1830,8 +1825,6 @@ auto getUpto(ParseTreeT)(ParseTreeT[] children, size_t minFailedLength) { unittest // 'or' unit test { - alias ParseTree = DefaultParseTree; - mixin ParseCollections!ParseTree; alias charRange!('a','b') ab; alias charRange!('c','d') cd; @@ -1900,7 +1893,7 @@ unittest // 'or' unit test The longest matching subrule's parse tree is stored as its only child and its matches field will contain all the subrule matches, in order. */ -template longest_matchT(ParseTreeT, rules...) if (rules.length > 0) +template longest_matchT(ParseTree, rules...) if (rules.length > 0) { string ctfeGetNameOr() { @@ -1914,15 +1907,15 @@ template longest_matchT(ParseTreeT, rules...) if (rules.length > 0) enum name = ctfeGetNameOr(); - ParseTreeT longest_match(ParseTreeT p) + ParseTree longest_matchT(ParseTree p) { // error-management - ParseTreeT longest, longestFail = ParseTreeT(name, false, [], p.input, p.end, 0); + ParseTree longest, longestFail = ParseTree(name, false, [], p.input, p.end, 0); string[] errorStrings; size_t errorStringChars; string orErrorString; - ParseTreeT[rules.length] results; + ParseTree[rules.length] results; string[rules.length] names; size_t[rules.length] failedLength; size_t maxFailedLength; @@ -1940,7 +1933,7 @@ template longest_matchT(ParseTreeT, rules...) if (rules.length > 0) if (shouldTrace(getName!(r)(), p)) trace(traceMsg(p, name, getName!(r)())); } - ParseTreeT temp = r(p); + ParseTree temp = r(p); version (tracer) { if (shouldTrace(getName!(r)(), p)) @@ -2012,12 +2005,12 @@ template longest_matchT(ParseTreeT, rules...) if (rules.length > 0) return longestFail; } - ParseTreeT longest_match(string input) + ParseTree longest_matchT(string input) { - return .or!(rules)(ParseTreeT("",false,[],input)); + return orT!(ParseTree, rules)(ParseTree("",false,[],input)); } - string longest_match(GetName g) + string longest_matchT(GetName g) { return name; } @@ -2025,8 +2018,6 @@ template longest_matchT(ParseTreeT, rules...) if (rules.length > 0) unittest // 'longest_match' unit test { - alias ParseTree = DefaultParseTree; - mixin ParseCollections!ParseTree; alias charRange!('a','b') ab; alias charRange!('c','d') cd; @@ -2292,8 +2283,6 @@ template keywordsT(ParseTree,kws...) if (kws.length > 0) unittest { - alias ParseTree = DefaultParseTree; - mixin ParseCollections!ParseTree; alias keywords!("abc","de","f") kw; @@ -2436,9 +2425,6 @@ template zeroOrMoreT(ParseTree, alias r) unittest // 'zeroOrMore' unit test { - alias ParseTree = DefaultParseTree; - mixin ParseCollections!ParseTree; - alias literal!"a" a; alias literal!"abc" abc; alias charRange!('a','z') az; @@ -2608,9 +2594,6 @@ template oneOrMoreT(ParseTree, alias r) unittest // 'oneOrMore' unit test { - alias ParseTree = DefaultParseTree; - mixin ParseCollections!ParseTree; - alias literal!"a" a; alias literal!"abc" abc; alias charRange!('a','z') az; @@ -2721,9 +2704,6 @@ template optionT(ParseTree, alias r) unittest // 'option' unit test { - alias ParseTree = DefaultParseTree; - mixin ParseCollections!ParseTree; - alias literal!"a" a; alias literal!"abc" abc; @@ -2818,9 +2798,6 @@ template posLookaheadT(ParseTree, alias r) unittest // 'posLookahead' unit test { - alias ParseTree = DefaultParseTree; - mixin ParseCollections!ParseTree; - alias literal!"a" a; alias literal!"abc" abc; @@ -2912,9 +2889,6 @@ template negLookaheadT(ParseTree, alias r) unittest // 'negLookahead' unit test { - alias ParseTree = DefaultParseTree; - mixin ParseCollections!ParseTree; - alias literal!"a" a; alias literal!"abc" abc; @@ -3023,9 +2997,6 @@ template namedT(ParseTree, alias r, string name) unittest // 'named' unit test { - alias ParseTree = DefaultParseTree; - mixin ParseCollections!ParseTree; - alias or!(literal!("abc"), charRange!('0','9')) rule; alias named!(rule, "myRule") myRule; @@ -3108,9 +3079,6 @@ template definedT(ParseTree, alias r, string name) unittest // 'defined' unit test { - alias ParseTree = DefaultParseTree; - mixin ParseCollections!ParseTree; - alias or!(literal!("abc"), charRange!('0','9')) rule; alias defined!(rule, "myRule") myRule; @@ -3146,17 +3114,17 @@ unittest // 'defined' unit test */ template actionT(ParseTree, alias r, alias act) { - ParseTree action(ParseTree p) + ParseTree actionT(ParseTree p) { return act(r(p)); } - ParseTree action(string input) + ParseTree actionT(string input) { - return .action!(r,act)(ParseTree("",false,[],input)); + return actionT!(ParseTree, r,act)(ParseTree("",false,[],input)); } - string action(GetName g) + string actionT(GetName g) { enum name = "action!("~ getName!(r)() ~ ", " ~ __traits(identifier, act) ~ ")"; return name; @@ -3165,9 +3133,6 @@ template actionT(ParseTree, alias r, alias act) unittest // 'action' unit test { - alias ParseTree = DefaultParseTree; - mixin ParseCollections!ParseTree; - ParseTree foo(ParseTree p) { p.matches ~= p.matches; // doubling matches @@ -3234,9 +3199,6 @@ template fuseT(ParseTree, alias r) unittest // 'fuse' unit test { - alias ParseTree = DefaultParseTree; - mixin ParseCollections!ParseTree; - alias oneOrMore!(literal!("abc")) abcs; alias fuse!(abcs) f; @@ -3307,7 +3269,7 @@ template discardChildrenT(ParseTree, alias r) */ template discardMatchesT(ParseTree, alias r) { - ParseTree discardMatches(ParseTree p) + ParseTree discardMatchesT(ParseTree p) { p = r(p); if (p.successful) @@ -3315,12 +3277,12 @@ template discardMatchesT(ParseTree, alias r) return p; } - ParseTree discardMatches(string input) + ParseTree discardMatchesT(string input) { - return .discardMatches!(r)(ParseTree("",false,[],input)); + return discardMatchesT!(ParseTree, r)(ParseTree("",false,[],input)); } - string discardMatches(GetName g) + string discardMatchesT(GetName g) { enum name = "discardMatches!(" ~ getName!(r)() ~ ")"; return name; @@ -3360,9 +3322,6 @@ template discardT(ParseTree, alias r) unittest // 'discard' unit test { - alias ParseTree = DefaultParseTree; - mixin ParseCollections!ParseTree; - alias literal!"abc" abc; alias oneOrMore!abc abcs; alias discard!(literal!("abc")) dabc; @@ -3443,9 +3402,6 @@ template dropT(ParseTree, alias r) unittest // 'drop' unit test { - alias ParseTree = DefaultParseTree; - mixin ParseCollections!ParseTree; - alias literal!"abc" abc; alias oneOrMore!abc abcs; alias drop!(literal!("abc")) dabc; @@ -3553,9 +3509,6 @@ template keepT(ParseTree, alias r) unittest // 'keep' unit test { - alias ParseTree = DefaultParseTree; - mixin ParseCollections!ParseTree; - // Grammar mimicry struct KeepTest { @@ -3596,11 +3549,11 @@ unittest // 'keep' unit test assert(result.children == [literal!("b")(literal!("a")("abc"))], "'b' node was kept."); } -template AddSpace(alias sp) +template AddSpaceT(ParseTree, alias sp) { - template AddSpace(alias r) + template AddSpaceT(alias r) { - alias TypeTuple!(r, discard!sp) AddSpace; + alias AddSpaceT=TypeTuple!(r, discardT!(ParseTree,sp)); } } @@ -3648,61 +3601,60 @@ template AddSpace(alias sp) unittest // 'spaceAnd' unit test { - alias ParseTree = DefaultParseTree; - mixin ParseCollections!ParseTree; - - alias literal!"a" a; - alias literal!"b" b; + with(PEG) { + alias literal!"a" a; + alias literal!"b" b; - //Basic use - alias and!(a,b) ab; - alias spaceAnd!(oneOrMore!blank, a, b) a_b; + //Basic use + alias and!(a,b) ab; + alias spaceAnd!(oneOrMore!blank, a, b) a_b; - ParseTree reference = ab("ab"); - ParseTree result = a_b("ab"); + ParseTree reference = ab("ab"); + ParseTree result = a_b("ab"); - assert(reference.successful); - assert(result.successful); - assert(result.matches == reference.matches); - assert(result.begin == reference.begin); - assert(result.end == reference.end); - assert(result.children == reference.children); + assert(reference.successful); + assert(result.successful); + assert(result.matches == reference.matches); + assert(result.begin == reference.begin); + assert(result.end == reference.end); + assert(result.children == reference.children); - reference = ab(" a b "); - result = a_b( " a b "); + reference = ab(" a b "); + result = a_b( " a b "); - assert(!reference.successful); - assert(result.successful); - assert(result.matches == ["a","b"]); - assert(result.begin == 0); - assert(result.end == " a b ".length); - assert(result.children.length == 2); + assert(!reference.successful); + assert(result.successful); + assert(result.matches == ["a","b"]); + assert(result.begin == 0); + assert(result.end == " a b ".length); + assert(result.children.length == 2); - reference = ab("ac"); - result = a_b("ac"); + reference = ab("ac"); + result = a_b("ac"); - assert(!reference.successful); - assert(!result.successful); + assert(!reference.successful); + assert(!result.successful); - reference = ab(" a c "); - result = a_b(" a c "); + reference = ab(" a c "); + result = a_b(" a c "); - assert(!reference.successful); - assert(!result.successful); + assert(!reference.successful); + assert(!result.successful); - // With another separator than spaces - alias spaceAnd!(digit, a, b) a0b; + // With another separator than spaces + alias spaceAnd!(digit, a, b) a0b; - assert(a0b("ab").successful); - assert(!a0b(" a b ").successful); + assert(a0b("ab").successful); + assert(!a0b(" a b ").successful); - result = a0b("012a34b567"); + result = a0b("012a34b567"); - assert(result.successful); - assert(result.matches == ["a", "b"]); - assert(result.begin == 0); - assert(result.end == "012a34b567".length); - assert(result.children.length == 2); + assert(result.successful); + assert(result.matches == ["a", "b"]); + assert(result.begin == 0); + assert(result.end == "012a34b567".length); + assert(result.children.length == 2); + } } /// Mixin to simplify a parse tree inside a grammar @@ -3831,7 +3783,7 @@ mixin template ParseCollections(ParseTree) { alias wrapAround(alias before, alias target, alias after) = wrapAroundT!(ParseTree, before, target, after); alias and(rules...) = andT!(ParseTree, rules); alias or(rules...) = orT!(ParseTree, rules); - alias longest_matchT(rules...) = longest_matchT!(ParseTree, rules); + alias longest_match(rules...) = longest_matchT!(ParseTree, rules); alias keywords(kws...) = keywordsT!(ParseTree, kws); alias zeroOrMore(alias r) = zeroOrMoreT!(ParseTree, r); alias oneOrMore(alias r) = oneOrMoreT!(ParseTree, r); @@ -3848,10 +3800,12 @@ mixin template ParseCollections(ParseTree) { alias drop(alias r) = dropT!(ParseTree, r); alias propagate(alias r) = propagateT!(ParseTree, r); alias keep(alias r) = keepT!(ParseTree, r); + alias AddSpace(alias sp) = AddSpaceT!(ParseTree, sp); } mixin template DefaultParsePatterns(alias PEG) { + import std.meta : staticMap; /* ****************** predefined rules ******************** */ alias endOfLine = PEG.named!(PEG.or!(PEG.literal!("\r\n"), PEG.literal!("\n"), PEG.literal!("\r")), "endOfLine"); /// predefined end-of-line parser diff --git a/pegged/tester/testerparser.d b/pegged/tester/testerparser.d index 2b193fc..9267b2e 100644 --- a/pegged/tester/testerparser.d +++ b/pegged/tester/testerparser.d @@ -68,11 +68,11 @@ struct GenericTesterGrammar(ParseTree) mixin decimateTree; static ParseTree Root(ParseTree p) { - return pegged.peg.named!(pegged.peg.and!(pegged.peg.wrapAround!(Spacing, Node, Spacing), pegged.peg.wrapAround!(Spacing, eoi, Spacing)), "TesterGrammar.Root")(p); + return PEG.named!(PEG.and!(PEG.wrapAround!(Spacing, Node, Spacing), PEG.wrapAround!(Spacing, eoi, Spacing)), "TesterGrammar.Root")(p); } static ParseTree Root(string s) { - return pegged.peg.named!(pegged.peg.and!(pegged.peg.wrapAround!(Spacing, Node, Spacing), pegged.peg.wrapAround!(Spacing, eoi, Spacing)), "TesterGrammar.Root")(ParseTree("", false,[], s)); + return PEG.named!(PEG.and!(PEG.wrapAround!(Spacing, Node, Spacing), PEG.wrapAround!(Spacing, eoi, Spacing)), "TesterGrammar.Root")(ParseTree("", false,[], s)); } static string Root(GetName g) { @@ -81,11 +81,11 @@ struct GenericTesterGrammar(ParseTree) static ParseTree Node(ParseTree p) { - return pegged.peg.named!(pegged.peg.or!(pegged.peg.and!(pegged.peg.discard!(pegged.peg.wrapAround!(Spacing, pegged.peg.literal!("^"), Spacing)), pegged.peg.wrapAround!(Spacing, identifier, Spacing)), pegged.peg.and!(pegged.peg.wrapAround!(Spacing, identifier, Spacing), pegged.peg.zeroOrMore!(pegged.peg.wrapAround!(Spacing, pegged.peg.propagate!(pegged.peg.wrapAround!(Spacing, Branch, Spacing)), Spacing)))), "TesterGrammar.Node")(p); + return PEG.named!(PEG.or!(PEG.and!(PEG.discard!(PEG.wrapAround!(Spacing, PEG.literal!("^"), Spacing)), PEG.wrapAround!(Spacing, identifier, Spacing)), PEG.and!(PEG.wrapAround!(Spacing, identifier, Spacing), PEG.zeroOrMore!(PEG.wrapAround!(Spacing, PEG.propagate!(PEG.wrapAround!(Spacing, Branch, Spacing)), Spacing)))), "TesterGrammar.Node")(p); } static ParseTree Node(string s) { - return pegged.peg.named!(pegged.peg.or!(pegged.peg.and!(pegged.peg.discard!(pegged.peg.wrapAround!(Spacing, pegged.peg.literal!("^"), Spacing)), pegged.peg.wrapAround!(Spacing, identifier, Spacing)), pegged.peg.and!(pegged.peg.wrapAround!(Spacing, identifier, Spacing), pegged.peg.zeroOrMore!(pegged.peg.wrapAround!(Spacing, pegged.peg.propagate!(pegged.peg.wrapAround!(Spacing, Branch, Spacing)), Spacing)))), "TesterGrammar.Node")(ParseTree("", false,[], s)); + return PEG.named!(PEG.or!(PEG.and!(PEG.discard!(PEG.wrapAround!(Spacing, PEG.literal!("^"), Spacing)), PEG.wrapAround!(Spacing, identifier, Spacing)), PEG.and!(PEG.wrapAround!(Spacing, identifier, Spacing), PEG.zeroOrMore!(PEG.wrapAround!(Spacing, PEG.propagate!(PEG.wrapAround!(Spacing, Branch, Spacing)), Spacing)))), "TesterGrammar.Node")(ParseTree("", false,[], s)); } static string Node(GetName g) { @@ -94,11 +94,11 @@ struct GenericTesterGrammar(ParseTree) static ParseTree Branch(ParseTree p) { - return pegged.peg.named!(pegged.peg.or!(pegged.peg.wrapAround!(Spacing, OrderedBranch, Spacing), pegged.peg.wrapAround!(Spacing, UnorderedBranch, Spacing)), "TesterGrammar.Branch")(p); + return PEG.named!(PEG.or!(PEG.wrapAround!(Spacing, OrderedBranch, Spacing), PEG.wrapAround!(Spacing, UnorderedBranch, Spacing)), "TesterGrammar.Branch")(p); } static ParseTree Branch(string s) { - return pegged.peg.named!(pegged.peg.or!(pegged.peg.wrapAround!(Spacing, OrderedBranch, Spacing), pegged.peg.wrapAround!(Spacing, UnorderedBranch, Spacing)), "TesterGrammar.Branch")(ParseTree("", false,[], s)); + return PEG.named!(PEG.or!(PEG.wrapAround!(Spacing, OrderedBranch, Spacing), PEG.wrapAround!(Spacing, UnorderedBranch, Spacing)), "TesterGrammar.Branch")(ParseTree("", false,[], s)); } static string Branch(GetName g) { @@ -107,11 +107,11 @@ struct GenericTesterGrammar(ParseTree) static ParseTree OrderedBranch(ParseTree p) { - return pegged.peg.named!(pegged.peg.or!(pegged.peg.and!(pegged.peg.discard!(pegged.peg.wrapAround!(Spacing, pegged.peg.literal!("->"), Spacing)), pegged.peg.discard!(pegged.peg.wrapAround!(Spacing, pegged.peg.literal!("{"), Spacing)), pegged.peg.oneOrMore!(pegged.peg.wrapAround!(Spacing, Node, Spacing)), pegged.peg.discard!(pegged.peg.wrapAround!(Spacing, pegged.peg.literal!("}"), Spacing))), pegged.peg.and!(pegged.peg.discard!(pegged.peg.wrapAround!(Spacing, pegged.peg.literal!("->"), Spacing)), pegged.peg.wrapAround!(Spacing, Node, Spacing))), "TesterGrammar.OrderedBranch")(p); + return PEG.named!(PEG.or!(PEG.and!(PEG.discard!(PEG.wrapAround!(Spacing, PEG.literal!("->"), Spacing)), PEG.discard!(PEG.wrapAround!(Spacing, PEG.literal!("{"), Spacing)), PEG.oneOrMore!(PEG.wrapAround!(Spacing, Node, Spacing)), PEG.discard!(PEG.wrapAround!(Spacing, PEG.literal!("}"), Spacing))), PEG.and!(PEG.discard!(PEG.wrapAround!(Spacing, PEG.literal!("->"), Spacing)), PEG.wrapAround!(Spacing, Node, Spacing))), "TesterGrammar.OrderedBranch")(p); } static ParseTree OrderedBranch(string s) { - return pegged.peg.named!(pegged.peg.or!(pegged.peg.and!(pegged.peg.discard!(pegged.peg.wrapAround!(Spacing, pegged.peg.literal!("->"), Spacing)), pegged.peg.discard!(pegged.peg.wrapAround!(Spacing, pegged.peg.literal!("{"), Spacing)), pegged.peg.oneOrMore!(pegged.peg.wrapAround!(Spacing, Node, Spacing)), pegged.peg.discard!(pegged.peg.wrapAround!(Spacing, pegged.peg.literal!("}"), Spacing))), pegged.peg.and!(pegged.peg.discard!(pegged.peg.wrapAround!(Spacing, pegged.peg.literal!("->"), Spacing)), pegged.peg.wrapAround!(Spacing, Node, Spacing))), "TesterGrammar.OrderedBranch")(ParseTree("", false,[], s)); + return PEG.named!(PEG.or!(PEG.and!(PEG.discard!(PEG.wrapAround!(Spacing, PEG.literal!("->"), Spacing)), PEG.discard!(PEG.wrapAround!(Spacing, PEG.literal!("{"), Spacing)), PEG.oneOrMore!(PEG.wrapAround!(Spacing, Node, Spacing)), PEG.discard!(PEG.wrapAround!(Spacing, PEG.literal!("}"), Spacing))), PEG.and!(PEG.discard!(PEG.wrapAround!(Spacing, PEG.literal!("->"), Spacing)), PEG.wrapAround!(Spacing, Node, Spacing))), "TesterGrammar.OrderedBranch")(ParseTree("", false,[], s)); } static string OrderedBranch(GetName g) { @@ -120,11 +120,11 @@ struct GenericTesterGrammar(ParseTree) static ParseTree UnorderedBranch(ParseTree p) { - return pegged.peg.named!(pegged.peg.or!(pegged.peg.and!(pegged.peg.discard!(pegged.peg.wrapAround!(Spacing, pegged.peg.literal!("~>"), Spacing)), pegged.peg.discard!(pegged.peg.wrapAround!(Spacing, pegged.peg.literal!("{"), Spacing)), pegged.peg.oneOrMore!(pegged.peg.wrapAround!(Spacing, Node, Spacing)), pegged.peg.discard!(pegged.peg.wrapAround!(Spacing, pegged.peg.literal!("}"), Spacing))), pegged.peg.and!(pegged.peg.discard!(pegged.peg.wrapAround!(Spacing, pegged.peg.literal!("~>"), Spacing)), pegged.peg.wrapAround!(Spacing, Node, Spacing))), "TesterGrammar.UnorderedBranch")(p); + return PEG.named!(PEG.or!(PEG.and!(PEG.discard!(PEG.wrapAround!(Spacing, PEG.literal!("~>"), Spacing)), PEG.discard!(PEG.wrapAround!(Spacing, PEG.literal!("{"), Spacing)), PEG.oneOrMore!(PEG.wrapAround!(Spacing, Node, Spacing)), PEG.discard!(PEG.wrapAround!(Spacing, PEG.literal!("}"), Spacing))), PEG.and!(PEG.discard!(PEG.wrapAround!(Spacing, PEG.literal!("~>"), Spacing)), PEG.wrapAround!(Spacing, Node, Spacing))), "TesterGrammar.UnorderedBranch")(p); } static ParseTree UnorderedBranch(string s) { - return pegged.peg.named!(pegged.peg.or!(pegged.peg.and!(pegged.peg.discard!(pegged.peg.wrapAround!(Spacing, pegged.peg.literal!("~>"), Spacing)), pegged.peg.discard!(pegged.peg.wrapAround!(Spacing, pegged.peg.literal!("{"), Spacing)), pegged.peg.oneOrMore!(pegged.peg.wrapAround!(Spacing, Node, Spacing)), pegged.peg.discard!(pegged.peg.wrapAround!(Spacing, pegged.peg.literal!("}"), Spacing))), pegged.peg.and!(pegged.peg.discard!(pegged.peg.wrapAround!(Spacing, pegged.peg.literal!("~>"), Spacing)), pegged.peg.wrapAround!(Spacing, Node, Spacing))), "TesterGrammar.UnorderedBranch")(ParseTree("", false,[], s)); + return PEG.named!(PEG.or!(PEG.and!(PEG.discard!(PEG.wrapAround!(Spacing, PEG.literal!("~>"), Spacing)), PEG.discard!(PEG.wrapAround!(Spacing, PEG.literal!("{"), Spacing)), PEG.oneOrMore!(PEG.wrapAround!(Spacing, Node, Spacing)), PEG.discard!(PEG.wrapAround!(Spacing, PEG.literal!("}"), Spacing))), PEG.and!(PEG.discard!(PEG.wrapAround!(Spacing, PEG.literal!("~>"), Spacing)), PEG.wrapAround!(Spacing, Node, Spacing))), "TesterGrammar.UnorderedBranch")(ParseTree("", false,[], s)); } static string UnorderedBranch(GetName g) { @@ -133,11 +133,11 @@ struct GenericTesterGrammar(ParseTree) static ParseTree Spacing(ParseTree p) { - return pegged.peg.named!(pegged.peg.discard!(pegged.peg.zeroOrMore!(pegged.peg.or!(blank, Comment))), "TesterGrammar.Spacing")(p); + return PEG.named!(PEG.discard!(PEG.zeroOrMore!(PEG.or!(blank, Comment))), "TesterGrammar.Spacing")(p); } static ParseTree Spacing(string s) { - return pegged.peg.named!(pegged.peg.discard!(pegged.peg.zeroOrMore!(pegged.peg.or!(blank, Comment))), "TesterGrammar.Spacing")(ParseTree("", false,[], s)); + return PEG.named!(PEG.discard!(PEG.zeroOrMore!(PEG.or!(blank, Comment))), "TesterGrammar.Spacing")(ParseTree("", false,[], s)); } static string Spacing(GetName g) { @@ -146,11 +146,11 @@ struct GenericTesterGrammar(ParseTree) static ParseTree Comment(ParseTree p) { - return pegged.peg.named!(pegged.peg.or!(pegged.peg.and!(pegged.peg.literal!("//"), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(eol), pegged.peg.any)), eol), pegged.peg.and!(pegged.peg.literal!("/*"), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(pegged.peg.literal!("*/")), pegged.peg.any)), pegged.peg.literal!("*/")), NestedComment), "TesterGrammar.Comment")(p); + return PEG.named!(PEG.or!(PEG.and!(PEG.literal!("//"), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(eol), PEG.any)), eol), PEG.and!(PEG.literal!("/*"), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.literal!("*/")), PEG.any)), PEG.literal!("*/")), NestedComment), "TesterGrammar.Comment")(p); } static ParseTree Comment(string s) { - return pegged.peg.named!(pegged.peg.or!(pegged.peg.and!(pegged.peg.literal!("//"), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(eol), pegged.peg.any)), eol), pegged.peg.and!(pegged.peg.literal!("/*"), pegged.peg.zeroOrMore!(pegged.peg.and!(pegged.peg.negLookahead!(pegged.peg.literal!("*/")), pegged.peg.any)), pegged.peg.literal!("*/")), NestedComment), "TesterGrammar.Comment")(ParseTree("", false,[], s)); + return PEG.named!(PEG.or!(PEG.and!(PEG.literal!("//"), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(eol), PEG.any)), eol), PEG.and!(PEG.literal!("/*"), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.literal!("*/")), PEG.any)), PEG.literal!("*/")), NestedComment), "TesterGrammar.Comment")(ParseTree("", false,[], s)); } static string Comment(GetName g) { @@ -159,11 +159,11 @@ struct GenericTesterGrammar(ParseTree) static ParseTree NestedComment(ParseTree p) { - return pegged.peg.named!(pegged.peg.and!(pegged.peg.literal!("/+"), pegged.peg.or!(pegged.peg.and!(pegged.peg.negLookahead!(NestedCommentEnd), pegged.peg.any), NestedComment), NestedCommentEnd), "TesterGrammar.NestedComment")(p); + return PEG.named!(PEG.and!(PEG.literal!("/+"), PEG.or!(PEG.and!(PEG.negLookahead!(NestedCommentEnd), PEG.any), NestedComment), NestedCommentEnd), "TesterGrammar.NestedComment")(p); } static ParseTree NestedComment(string s) { - return pegged.peg.named!(pegged.peg.and!(pegged.peg.literal!("/+"), pegged.peg.or!(pegged.peg.and!(pegged.peg.negLookahead!(NestedCommentEnd), pegged.peg.any), NestedComment), NestedCommentEnd), "TesterGrammar.NestedComment")(ParseTree("", false,[], s)); + return PEG.named!(PEG.and!(PEG.literal!("/+"), PEG.or!(PEG.and!(PEG.negLookahead!(NestedCommentEnd), PEG.any), NestedComment), NestedCommentEnd), "TesterGrammar.NestedComment")(ParseTree("", false,[], s)); } static string NestedComment(GetName g) { @@ -172,11 +172,11 @@ struct GenericTesterGrammar(ParseTree) static ParseTree NestedCommentEnd(ParseTree p) { - return pegged.peg.named!(pegged.peg.literal!("+/"), "TesterGrammar.NestedCommentEnd")(p); + return PEG.named!(PEG.literal!("+/"), "TesterGrammar.NestedCommentEnd")(p); } static ParseTree NestedCommentEnd(string s) { - return pegged.peg.named!(pegged.peg.literal!("+/"), "TesterGrammar.NestedCommentEnd")(ParseTree("", false,[], s)); + return PEG.named!(PEG.literal!("+/"), "TesterGrammar.NestedCommentEnd")(ParseTree("", false,[], s)); } static string NestedCommentEnd(GetName g) { From b1ebfd21f0cec4714d9d53b200e64041119971cb Mon Sep 17 00:00:00 2001 From: cbleser Date: Mon, 31 May 2021 23:41:09 +0300 Subject: [PATCH 05/29] WIP: doTest compile time test passed --- pegged/peg.d | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pegged/peg.d b/pegged/peg.d index fe621d0..271285c 100644 --- a/pegged/peg.d +++ b/pegged/peg.d @@ -37,7 +37,6 @@ package string stringified(string inp) @safe return "%(%s%)".format(shell); } -version(none) @safe unittest // Run- & Compile-time. { static bool doTest() @@ -50,7 +49,7 @@ version(none) "\t" : `"\t"`, `"` : `"\""`, - "`" : q{("`")}, + "`" : q{"`"}, "'" : `"'"`, "42" : `"42"`, @@ -76,8 +75,8 @@ version(none) } // Result is always true, but here, we just force CTFE-mode. - static assert(doTest); // Compile-time. doTest; // Run-time. + static assert(doTest); // Compile-time. } struct GetName {} From 59a7b5b74ecf4281b2df1529ecd967affc48e859 Mon Sep 17 00:00:00 2001 From: cbleser Date: Mon, 31 May 2021 23:43:01 +0300 Subject: [PATCH 06/29] WIP: compile time debug printout removed --- pegged/grammar.d | 15 --------------- pegged/peg.d | 2 -- 2 files changed, 17 deletions(-) diff --git a/pegged/grammar.d b/pegged/grammar.d index cde1d52..429a395 100644 --- a/pegged/grammar.d +++ b/pegged/grammar.d @@ -2808,21 +2808,6 @@ unittest // Test lambda syntax in semantic actions unittest { // Higher-level word boundary test. - pragma(msg, grammar(` - TestGrammar: - - Foo < '{' 'X' '}' - Bar < 'A' 'B' - - Spacing <: - / blank+ - / blank* wordBoundary - / wordBoundary blank* - / ![a-zA-Z] - / !. - - `)); - mixin(grammar(` TestGrammar: diff --git a/pegged/peg.d b/pegged/peg.d index 271285c..464aed3 100644 --- a/pegged/peg.d +++ b/pegged/peg.d @@ -3296,8 +3296,6 @@ template discardT(ParseTree, alias r) { ParseTree discardT(ParseTree p) { - pragma(msg, typeof(p)); - pragma(msg, typeof(r(p))); ParseTree result = r(p); result.name = "discard!(" ~ getName!(r)() ~ ")"; //result.begin = result.end; From 7eadf443faa963abad8035c1bdb0577c014d974c Mon Sep 17 00:00:00 2001 From: cbleser Date: Tue, 1 Jun 2021 08:56:17 +0300 Subject: [PATCH 07/29] WIP: parses unittest --- pegged/peg.d | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/pegged/peg.d b/pegged/peg.d index 464aed3..fde5a7a 100644 --- a/pegged/peg.d +++ b/pegged/peg.d @@ -457,14 +457,14 @@ struct PeggedT(ParseTree) { + setTraceConditionFunction(ruleName => ruleName.startsWith("MyGrammar")); + --- +/ - void setTraceConditionFunction(bool delegate(string ruleName, const ref ParseTree p) condition) + static void setTraceConditionFunction(bool delegate(string ruleName, const ref ParseTree p) condition) { traceConditionDelegate = condition; traceConditionFunction = null; } /// ditto - void setTraceConditionFunction(bool function(string ruleName, const ref ParseTree p) condition) + static void setTraceConditionFunction(bool function(string ruleName, const ref ParseTree p) condition) { traceConditionFunction = condition; traceConditionDelegate = null; @@ -474,19 +474,19 @@ struct PeggedT(ParseTree) { * * This can produce a lot of output. */ - void traceAll() + static void traceAll() { setTraceConditionFunction(function(string ruleName, const ref ParseTree p) {return true;}); } /** Do not trace any rules. */ - void traceNothing() + static void traceNothing() { traceConditionFunction = null; traceConditionDelegate = null; } - private string traceMsg(ParseTree p, string expression, string name) + private static string traceMsg(const ParseTree p, string expression, string name) { import std.format; Position pos = position(p); @@ -501,7 +501,7 @@ struct PeggedT(ParseTree) { return result; } - private string traceResultMsg(ParseTree p, string name) + private static string traceResultMsg(const ParseTree p, string name) { import std.format; import std.range: chain; @@ -598,12 +598,12 @@ struct PeggedT(ParseTree) { eps matches the empty string (usually denoted by the Greek letter 'epsilon') and always succeeds. It's equivalent to literal!"" (for example, it creates a match of [""]: one match, the empty string). */ - ParseTree eps(string input) + static ParseTree eps(string input) { return eps(ParseTree("",false,[], input)); } - string eps(GetName g) + static string eps(GetName g) { return "eps"; } @@ -824,7 +824,7 @@ unittest // 'eps' unit test /** * Default fail message formating function */ -static defaultFormatFailMsg(ParseTree)(Position pos, string left, string right, const ParseTree pt) +static string defaultFormatFailMsg(ParseTree)(Position pos, string left, string right, const ParseTree pt) if (isParseTree!ParseTree) { return "Failure at line " ~ to!string(pos.line) ~ ", col " ~ to!string(pos.col) ~ ", " ~ (left.length > 0 ? "after " ~ left.stringified ~ " " : "") @@ -1446,8 +1446,7 @@ auto maxFailEnd(ParseTree)(ParseTree[] children) if (isParseTree!ParseTree) { return children.map!(c => c.failEnd).maxElement; } -auto maxEnd(ParseTreeT)(ParseTreeT[] children) -{ +auto maxEnd(ParseTreeT)(ParseTreeT[] children) if (isParseTree!ParseTree) { return children.map!(c => c.end).maxElement; } @@ -1456,8 +1455,7 @@ auto maxEnd(ParseTreeT)(ParseTreeT[] children) // 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(ParseTreeT)(ref ParseTreeT p, size_t failEnd) -{ +bool failedChildFixup(ParseTree)(ref ParseTree p, size_t failEnd) if (isParseTree!ParseTree) { if (p.failedChild.length > 0) { p.children ~= p.failedChild[0]; From 1568b5619e89531fe7fe4c79f9c12f37794e9f0a Mon Sep 17 00:00:00 2001 From: cbleser Date: Tue, 1 Jun 2021 09:31:34 +0300 Subject: [PATCH 08/29] WIP: ParseTree scaffold is now move to it's own module pegged.parsetree --- dub.json | 1 + pegged/dynamic/grammar.d | 1 + pegged/dynamic/peg.d | 2 + pegged/grammar.d | 900 +++++++++++++++++------------------ pegged/parser.d | 1 + pegged/peg.d | 173 +------ pegged/tester/testerparser.d | 1 + 7 files changed, 455 insertions(+), 624 deletions(-) diff --git a/dub.json b/dub.json index 630af66..cffeee7 100644 --- a/dub.json +++ b/dub.json @@ -8,6 +8,7 @@ "pegged/peg.d", "pegged/grammar.d", "pegged/parser.d", + "pegged/parsetree.d", "pegged/introspection.d", "pegged/tohtml.d", "pegged/dynamic/grammar.d", diff --git a/pegged/dynamic/grammar.d b/pegged/dynamic/grammar.d index f5c51d1..fb127ce 100644 --- a/pegged/dynamic/grammar.d +++ b/pegged/dynamic/grammar.d @@ -19,6 +19,7 @@ import pegged.peg; import pegged.parser; import pegged.dynamic.peg; +private import pegged.parsetree : DefaultParseTree, isParseTree; private alias ParseTree=DefaultParseTree; struct ParameterizedRule diff --git a/pegged/dynamic/peg.d b/pegged/dynamic/peg.d index fcd27bb..159c813 100644 --- a/pegged/dynamic/peg.d +++ b/pegged/dynamic/peg.d @@ -8,6 +8,8 @@ import std.stdio; import pegged.peg; + +private import pegged.parsetree : DefaultParseTree; private alias ParseTree=DefaultParseTree; alias ParseTree delegate(ParseTree) Dynamic; diff --git a/pegged/grammar.d b/pegged/grammar.d index 429a395..1f4de1f 100644 --- a/pegged/grammar.d +++ b/pegged/grammar.d @@ -1,8 +1,8 @@ /** -Parser generation module for Pegged. -The Pegged parser itself is in pegged.parser, generated from pegged.examples.peggedgrammar. + Parser generation module for Pegged. + The Pegged parser itself is in pegged.parser, generated from pegged.examples.peggedgrammar. -The documentation is in the /docs directory. + The documentation is in the /docs directory. */ module pegged.grammar; @@ -13,17 +13,18 @@ import std.stdio; public import pegged.peg; import pegged.parser; +import pegged.parsetree : DefaultParseTree, isParseTree; /** -Option enum to get internal memoization (parse results storing). + Option enum to get internal memoization (parse results storing). */ enum Memoization { no, yes } /** -This function takes a (future) module name, a (future) file name and a grammar as a string or a file. -It writes the corresponding parser inside a module with the given name. + This function takes a (future) module name, a (future) file name and a grammar as a string or a file. + It writes the corresponding parser inside a module with the given name. */ void asModule(Memoization withMemo = Memoization.yes)(string moduleName, string fileName, string grammarString, string optHeader = "") { @@ -62,39 +63,39 @@ ParseTree spaceArrow(ParseTree)(ParseTree input) ParseTree wrapInSpaces(ParseTree p) { ParseTree spacer = - ParseTree("Pegged.Prefix", true, null, null, 0,0, [ - ParseTree("Pegged.Suffix", true, null, null, 0, 0, [ - ParseTree("Pegged.Primary", true, null, null, 0, 0, [ - ParseTree("Pegged.RhsName", true, null, null, 0,0, [ - ParseTree("Pegged.Identifier", true, ["Spacing"]) - ]) - ]) - ]) - ]); + ParseTree("Pegged.Prefix", true, null, null, 0,0, [ + ParseTree("Pegged.Suffix", true, null, null, 0, 0, [ + ParseTree("Pegged.Primary", true, null, null, 0, 0, [ + ParseTree("Pegged.RhsName", true, null, null, 0,0, [ + ParseTree("Pegged.Identifier", true, ["Spacing"]) + ]) + ]) + ]) + ]); ParseTree result = ParseTree("Pegged.WrapAround", true, p.matches, p.input, p.begin, p.end, p.children); result.children = spacer ~ result.children ~ spacer; return result; } return modify!(ParseTree, p => p.name == "Pegged.Primary", - wrapInSpaces)(input); + wrapInSpaces)(input); } /** -Generate a parser from a PEG definition. -The parser is a string containing D code, to be mixed in or written in a file. - ----- -enum string def = " -Gram: - A <- 'a' B* - B <- 'b' / 'c' -"; + Generate a parser from a PEG definition. + The parser is a string containing D code, to be mixed in or written in a file. + + ---- + enum string def = " + Gram: + A <- 'a' B* + B <- 'b' / 'c' + "; -mixin(grammar(def)); + mixin(grammar(def)); -ParseTree p = Gram("abcbccbcd"); ----- + ParseTree p = Gram("abcbccbcd"); + ---- */ string grammar(Memoization withMemo = Memoization.yes, ParseTree=DefaultParseTree)(string definition) { @@ -122,14 +123,14 @@ string grammar(ParseTree, Memoization withMemo = Memoization.yes)(ParseTree defA // rules for which memoization needs to be blocked. /* - I once considered that if two left-recursive cycles intersect, unbounded left-recursion - would be prevented in both cycles if only the intersection rule would be a stopper. Although - true, it causes other problems, as documented in the "Mutual left-recursion" unittest below. - Therefore, we simply make the first rule in every left-recursive cycle a stopper. - Also, one might think that it suffices to prevent ordinary memoization in just the rules - that are part of the cycle. However, some larger input files for pegged/examples/extended_pascal - would fail to parse. So memoization for all left-recursive rules is disabled during - left-recursion. + I once considered that if two left-recursive cycles intersect, unbounded left-recursion + would be prevented in both cycles if only the intersection rule would be a stopper. Although + true, it causes other problems, as documented in the "Mutual left-recursion" unittest below. + Therefore, we simply make the first rule in every left-recursive cycle a stopper. + Also, one might think that it suffices to prevent ordinary memoization in just the rules + that are part of the cycle. However, some larger input files for pegged/examples/extended_pascal + would fail to parse. So memoization for all left-recursive rules is disabled during + left-recursion. */ string[] allLeftRecursiveRules; foreach (cycle; grammarInfo.leftRecursiveCycles) @@ -163,7 +164,7 @@ string grammar(ParseTree, Memoization withMemo = Memoization.yes)(ParseTree defA result ~= stopper ~ ": " ~ allLeftRecursiveRules.join(", ") ~ "\n"; return result.length > 0 ? "/** Rules that stop left-recursive cycles, followed by rules for which\n" - ~ " * memoization is blocked during recursion:\n" ~ result ~ "*/\n\n" : ""; + ~ " * memoization is blocked during recursion:\n" ~ result ~ "*/\n\n" : ""; } // Analysis completed. @@ -194,17 +195,18 @@ string grammar(ParseTree, Memoization withMemo = Memoization.yes)(ParseTree defA switch (p.name) { - case "Pegged": - result = generateCode(p.children[0]); - break; - case "Pegged.Grammar": - string grammarName = generateCode(p.children[0]); - string shortGrammarName = p.children[0].matches[0]; - //string invokedGrammarName = generateCode(transformName(p.children[0])); - string firstRuleName = generateCode(p.children[1].children[0]); - - result = -"struct Generic" ~ shortGrammarName ~ "(ParseTree) + case "Pegged": + result = generateCode(p.children[0]); + break; + case "Pegged.Grammar": + string grammarName = generateCode(p.children[0]); + string shortGrammarName = p.children[0].matches[0]; + //string invokedGrammarName = generateCode(transformName(p.children[0])); + string firstRuleName = generateCode(p.children[1].children[0]); + result = "import pegged.parsetree : DefaultParseTree;\n"; + + result ~= + "struct Generic" ~ shortGrammarName ~ "(ParseTree) { import std.functional : toDelegate; import pegged.dynamic.grammar; @@ -219,36 +221,36 @@ string grammar(ParseTree, Memoization withMemo = Memoization.yes)(ParseTree defA static ParseTree delegate(ParseTree)[string] after; static ParseTree delegate(ParseTree)[string] rules;"; - if (withMemo == Memoization.yes) { - result ~= " + if (withMemo == Memoization.yes) { + result ~= " import std.typecons:Tuple, tuple; static ParseTree[Tuple!(string, size_t)] memo;"; - if (grammarInfo.leftRecursiveCycles.length > 0) - result ~= " + if (grammarInfo.leftRecursiveCycles.length > 0) + result ~= " import std.algorithm: canFind, countUntil, remove; static size_t[] blockMemoAtPos;"; - } + } - result ~= " + result ~= " static this()\n {\n"; - ParseTree[] definitions = p.children[1 .. $]; - bool userDefinedSpacing; - foreach(i,def; definitions) + ParseTree[] definitions = p.children[1 .. $]; + bool userDefinedSpacing; + foreach(i,def; definitions) + { + if (def.children[0].children.length == 1) // Non-parameterized ruleName + result ~= " rules[\"" ~ def.matches[0] ~ "\"] = toDelegate(&" ~ def.matches[0] ~ ");\n"; + if (def.matches[0] == "Spacing") // user-defined spacing { - if (def.children[0].children.length == 1) // Non-parameterized ruleName - result ~= " rules[\"" ~ def.matches[0] ~ "\"] = toDelegate(&" ~ def.matches[0] ~ ");\n"; - if (def.matches[0] == "Spacing") // user-defined spacing - { - userDefinedSpacing = true; - break; - } + userDefinedSpacing = true; + break; } - if(!userDefinedSpacing) - result ~= " rules[\"Spacing\"] = toDelegate(&Spacing);\n"; + } + if(!userDefinedSpacing) + result ~= " rules[\"Spacing\"] = toDelegate(&Spacing);\n"; - result ~= -" } + result ~= + " } template hooked(alias r, string name) { @@ -307,181 +309,181 @@ string grammar(ParseTree, Memoization withMemo = Memoization.yes)(ParseTree defA "; - /+ - ~ " switch(s)\n" - ~ " {\n"; - - bool[string] ruleNames; // to avoid duplicates, when using parameterized rules - string parameterizedRulesSpecialCode; // because param rules need to be put in the 'default' part of the switch - - string paramRuleHandler(string target) - { - return "if (s.length >= "~to!string(shortGrammarName.length + target.length + 3) - ~" && s[0.."~to!string(shortGrammarName.length + target.length + 3)~"] == \"" - ~shortGrammarName ~ "." ~ target~"!(\") return true;"; - } - - foreach(i,def; definitions) - { - /* - if (def.matches[0] !in ruleNames) - { - ruleNames[def.matches[0]] = true; - - if (def.children[0].children.length > 1) // Parameterized rule - parameterizedRulesSpecialCode ~= " " ~ paramRuleHandler(def.matches[0])~ "\n"; - else - result ~= " case \"" ~ shortGrammarName ~ "." ~ def.matches[0] ~ "\":\n"; - } - */ - if (def.matches[0] == "Spacing") // user-defined spacing - { - userDefinedSpacing = true; - break; - } - } - result ~= " return true;\n" - ~ " default:\n" - ~ parameterizedRulesSpecialCode - ~ " return false;\n }\n }\n"; - +/ - result ~= " mixin decimateTree;\n\n"; - - // If the grammar provides a Spacing rule, then this will be used. - // else, the predefined 'spacing' rule is used. - result ~= userDefinedSpacing ? "" : " alias spacing Spacing;\n\n"; - - // Creating the inner functions, each corresponding to a grammar rule - foreach(def; definitions) - result ~= generateCode(def, shortGrammarName); - - // if the first rule is parameterized (a template), it's impossible to get an opCall - // because we don't know with which template arguments it should be called. - // So no opCall is generated in this case. - if (p.children[1].children[0].children.length == 1) - { - // General calling interface - result ~= " static ParseTree opCall(ParseTree p)\n" - ~ " {\n" - ~ " ParseTree result = decimateTree(" ~ firstRuleName ~ "(p));\n" - ~ " result.children = [result];\n" - ~ " result.name = \"" ~ shortGrammarName ~ "\";\n" - ~ " return result;\n" - ~ " }\n\n" - ~ " static ParseTree opCall(string input)\n" - ~ " {\n"; + /+ + ~ " switch(s)\n" + ~ " {\n"; + + bool[string] ruleNames; // to avoid duplicates, when using parameterized rules + string parameterizedRulesSpecialCode; // because param rules need to be put in the 'default' part of the switch + + string paramRuleHandler(string target) + { + return "if (s.length >= "~to!string(shortGrammarName.length + target.length + 3) + ~" && s[0.."~to!string(shortGrammarName.length + target.length + 3)~"] == \"" + ~shortGrammarName ~ "." ~ target~"!(\") return true;"; + } + + foreach(i,def; definitions) + { + /* + if (def.matches[0] !in ruleNames) + { + ruleNames[def.matches[0]] = true; + + if (def.children[0].children.length > 1) // Parameterized rule + parameterizedRulesSpecialCode ~= " " ~ paramRuleHandler(def.matches[0])~ "\n"; + else + result ~= " case \"" ~ shortGrammarName ~ "." ~ def.matches[0] ~ "\":\n"; + } + */ + if (def.matches[0] == "Spacing") // user-defined spacing + { + userDefinedSpacing = true; + break; + } + } + result ~= " return true;\n" + ~ " default:\n" + ~ parameterizedRulesSpecialCode + ~ " return false;\n }\n }\n"; + +/ + result ~= " mixin decimateTree;\n\n"; + + // If the grammar provides a Spacing rule, then this will be used. + // else, the predefined 'spacing' rule is used. + result ~= userDefinedSpacing ? "" : " alias spacing Spacing;\n\n"; + + // Creating the inner functions, each corresponding to a grammar rule + foreach(def; definitions) + result ~= generateCode(def, shortGrammarName); + + // if the first rule is parameterized (a template), it's impossible to get an opCall + // because we don't know with which template arguments it should be called. + // So no opCall is generated in this case. + if (p.children[1].children[0].children.length == 1) + { + // General calling interface + result ~= " static ParseTree opCall(ParseTree p)\n" + ~ " {\n" + ~ " ParseTree result = decimateTree(" ~ firstRuleName ~ "(p));\n" + ~ " result.children = [result];\n" + ~ " result.name = \"" ~ shortGrammarName ~ "\";\n" + ~ " return result;\n" + ~ " }\n\n" + ~ " static ParseTree opCall(string input)\n" + ~ " {\n"; - if (withMemo == Memoization.no) - result ~= " forgetMemo();\n" - ~ " return " ~ shortGrammarName ~ "(ParseTree(``, false, [], input, 0, 0));\n" - ~ " }\n"; - else - result ~= " if(__ctfe)\n" - ~ " {\n" - ~ " return " ~ shortGrammarName ~ "(ParseTree(``, false, [], input, 0, 0));\n" - ~ " }\n" - ~ " else\n" - ~ " {\n" - ~ " forgetMemo();\n" - ~ " return " ~ shortGrammarName ~ "(ParseTree(``, false, [], input, 0, 0));\n" - ~ " }\n" - ~ " }\n"; - - result ~= " static string opCall(GetName g)\n" - ~ " {\n" - ~ " return \"" ~ shortGrammarName ~ "\";\n" - ~ " }\n\n"; - } - result ~= generateForgetMemo(); - result ~= " }\n" // end of grammar struct definition - ~ "}\n\n" // end of template definition - ~ "alias Generic" ~ shortGrammarName ~ "!(DefaultParseTree)." - ~ shortGrammarName ~ " " ~ shortGrammarName ~ ";\n\n"; + if (withMemo == Memoization.no) + result ~= " forgetMemo();\n" + ~ " return " ~ shortGrammarName ~ "(ParseTree(``, false, [], input, 0, 0));\n" + ~ " }\n"; + else + result ~= " if(__ctfe)\n" + ~ " {\n" + ~ " return " ~ shortGrammarName ~ "(ParseTree(``, false, [], input, 0, 0));\n" + ~ " }\n" + ~ " else\n" + ~ " {\n" + ~ " forgetMemo();\n" + ~ " return " ~ shortGrammarName ~ "(ParseTree(``, false, [], input, 0, 0));\n" + ~ " }\n" + ~ " }\n"; + + result ~= " static string opCall(GetName g)\n" + ~ " {\n" + ~ " return \"" ~ shortGrammarName ~ "\";\n" + ~ " }\n\n"; + } + result ~= generateForgetMemo(); + result ~= " }\n" // end of grammar struct definition + ~ "}\n\n" // end of template definition + ~ "alias Generic" ~ shortGrammarName ~ "!(DefaultParseTree)." + ~ shortGrammarName ~ " " ~ shortGrammarName ~ ";\n\n"; + break; + case "Pegged.Definition": + // children[0]: name + // children[1]: arrow (arrow type as first child) + // children[2]: description + + string code; + + switch(p.children[1].children[0].name) + { + case "Pegged.LEFTARROW": + code ~= generateCode(p.children[2]); break; - case "Pegged.Definition": - // children[0]: name - // children[1]: arrow (arrow type as first child) - // children[2]: description - - string code; - - switch(p.children[1].children[0].name) - { - case "Pegged.LEFTARROW": - code ~= generateCode(p.children[2]); - break; - case "Pegged.FUSEARROW": - code ~= "PEG.fuse!(" ~ generateCode(p.children[2]) ~ ")"; - break; - case "Pegged.DISCARDARROW": - code ~= "PEG.discard!(" ~ generateCode(p.children[2]) ~ ")"; - break; - case "Pegged.KEEPARROW": - code ~= "PEG.keep!("~ generateCode(p.children[2]) ~ ")"; - break; - case "Pegged.DROPARROW": - code ~= "PEG.drop!("~ generateCode(p.children[2]) ~ ")"; - break; - case "Pegged.PROPAGATEARROW": - code ~= "PEG.propagate!("~ generateCode(p.children[2]) ~ ")"; - break; - case "Pegged.SPACEARROW": - ParseTree modified = spaceArrow(p.children[2]); - code ~= generateCode(modified); - break; - case "Pegged.ACTIONARROW": - auto actionResult = generateCode(p.children[2]); - foreach(action; p.children[1].matches[1..$]) - actionResult = "PEG.action!(" ~ actionResult ~ ", " ~ action ~ ")"; - code ~= actionResult; - break; - default: - break; - } - - bool parameterizedRule = p.children[0].children.length > 1; - string completeName = generateCode(p.children[0]); - string shortName = p.matches[0]; - string innerName; - string hookedName = p.matches[0]; + case "Pegged.FUSEARROW": + code ~= "PEG.fuse!(" ~ generateCode(p.children[2]) ~ ")"; + break; + case "Pegged.DISCARDARROW": + code ~= "PEG.discard!(" ~ generateCode(p.children[2]) ~ ")"; + break; + case "Pegged.KEEPARROW": + code ~= "PEG.keep!("~ generateCode(p.children[2]) ~ ")"; + break; + case "Pegged.DROPARROW": + code ~= "PEG.drop!("~ generateCode(p.children[2]) ~ ")"; + break; + case "Pegged.PROPAGATEARROW": + code ~= "PEG.propagate!("~ generateCode(p.children[2]) ~ ")"; + break; + case "Pegged.SPACEARROW": + ParseTree modified = spaceArrow(p.children[2]); + code ~= generateCode(modified); + break; + case "Pegged.ACTIONARROW": + auto actionResult = generateCode(p.children[2]); + foreach(action; p.children[1].matches[1..$]) + actionResult = "PEG.action!(" ~ actionResult ~ ", " ~ action ~ ")"; + code ~= actionResult; + break; + default: + break; + } - if (parameterizedRule) - { - result = " template " ~ completeName ~ "\n" - ~ " {\n"; - innerName ~= "\"" ~ shortName ~ "!(\" ~ "; - hookedName ~= "_" ~ to!string(p.children[0].children[1].children.length); - foreach(i,param; p.children[0].children[1].children) - innerName ~= "pegged.peg.getName!("~ param.children[0].matches[0] - ~ (i 1; + string completeName = generateCode(p.children[0]); + string shortName = p.matches[0]; + string innerName; + string hookedName = p.matches[0]; - string ctfeCode = " PEG.defined!(" ~ code ~ ", \"" ~ propagatedName ~ "." ~ innerName[1..$-1] ~ "\")"; - code = "hooked!(PEG.defined!(" ~ code ~ ", \"" ~ propagatedName ~ "." ~ innerName[1..$-1] ~ "\"), \"" ~ hookedName ~ "\")"; + if (parameterizedRule) + { + result = " template " ~ completeName ~ "\n" + ~ " {\n"; + innerName ~= "\"" ~ shortName ~ "!(\" ~ "; + hookedName ~= "_" ~ to!string(p.children[0].children[1].children.length); + foreach(i,param; p.children[0].children[1].children) + innerName ~= "pegged.peg.getName!("~ param.children[0].matches[0] + ~ (i"; @@ -2687,14 +2683,14 @@ unittest // Test lambda syntax in semantic actions } return a;} }`, - // List of mixed actions and lambdas - `{ myAction , (a) {return a;}, myAction2 , (a) { /* , } */ return a; } }`, + // List of mixed actions and lambdas + `{ myAction , (a) {return a;}, myAction2 , (a) { /* , } */ return a; } }`, - // Ambiguous lambda (not sure it would compile if used... but it should parse) - `{ myAction, a => transform(a), myAction2 }`, + // Ambiguous lambda (not sure it would compile if used... but it should parse) + `{ myAction, a => transform(a), myAction2 }`, - // Something more convoluted - "{ myAction, (a) { + // Something more convoluted + "{ myAction, (a) { /* block } comment with } braces */ string s = `} {` // wysiwyg string with braces and line comment with brace } if (s is null) { @@ -2728,16 +2724,16 @@ unittest // Test lambda syntax in semantic actions return a; }, myAction2 }", - ]; + ]; auto results = [ - [`myAction`], - [`myAction`,`myAction2`], - [`(a) {return a;}`], - [`(a) { + [`myAction`], + [`myAction`,`myAction2`], + [`(a) {return a;}`], + [`(a) { return a; }`], - [`(a, b) { + [`(a, b) { string s = "}"; if (a.successful,) { s ~= q"<}>"; @@ -2745,9 +2741,9 @@ unittest // Test lambda syntax in semantic actions { s ~= q"<}>"; /* } */ } } return a;}`], - [`myAction`,`(a) {return a;}`,`myAction2`,`(a) { /* , } */ return a; }`], - [`myAction`,`a => transform(a)`,`myAction2`], - [`myAction`,"(a) { + [`myAction`,`(a) {return a;}`,`myAction2`,`(a) { /* , } */ return a; }`], + [`myAction`,`a => transform(a)`,`myAction2`], + [`myAction`,"(a) { /* block } comment with } braces */ string s = `} {` // wysiwyg string with braces and line comment with brace } if (s is null) { @@ -2781,7 +2777,7 @@ unittest // Test lambda syntax in semantic actions return a; }",`myAction2`] - ]; + ]; foreach(idx, act; actions) { @@ -2791,24 +2787,24 @@ unittest // Test lambda syntax in semantic actions assert(p.successful); auto action = p.children[0].children[1] // Pegged.Definition - .children[2] // Pegged.Expression - .children[0] // Pegged.FirstExpression - .children[0] // Pegged.Sequence - .children[0] // Pegged.Prefix - .children[0] // Pegged.Suffix - .children[1]; // Pegged.Action + .children[2] // Pegged.Expression + .children[0] // Pegged.FirstExpression + .children[0] // Pegged.Sequence + .children[0] // Pegged.Prefix + .children[0] // Pegged.Suffix + .children[1]; // Pegged.Action assert(action.matches.length == results[idx].length); foreach(i, s; action.matches) assert(strip(s) == results[idx][i], - "\nGot |"~s~"|" ~ "\nNeeded: |"~results[idx][i]~"|"); + "\nGot |"~s~"|" ~ "\nNeeded: |"~results[idx][i]~"|"); } } unittest { // Higher-level word boundary test. - mixin(grammar(` + mixin(grammar(` TestGrammar: Foo < '{' 'X' '}' @@ -2868,8 +2864,6 @@ unittest // Issue #129 unit test unittest // Direct left-recursion { - alias ParseTree = DefaultParseTree; - enum LeftGrammar = ` Left: S <- E eoi @@ -2883,8 +2877,6 @@ unittest // Direct left-recursion unittest // Indirect left-recursion { - alias ParseTree = DefaultParseTree; - enum LeftGrammar = ` Left: S <- E eoi @@ -2899,8 +2891,6 @@ unittest // Indirect left-recursion unittest // Proper blocking of memoization { - alias ParseTree = DefaultParseTree; - // Three interlocking cycles of indirect left-recursion. enum LeftGrammar = ` Left: @@ -2922,14 +2912,14 @@ unittest // Proper blocking of memoization unittest // Mutual left-recursion { /* A thing about stoppers: - Because P is at the intersection of left-recursive cycles P -> P and L -> P -> L, it should - suffice to make only P a stopper to stop unbounded left-recursion. And so it does. But, - stoppers parse greedily: they always consume the maximum of input. So below, if only P is a stopper, - at some point P parses the complete input. Then L fails because it cannot append ".x", then M fails. - If both are made a stopper then M succeeds. That is because P will try L when P '(n)' no longer - consumes input, which will appear as a left-recursion to L if it is a stopper and because of that - it will have a chance to succeed on the full input which it recorded in its seed for the previous - recursion. + Because P is at the intersection of left-recursive cycles P -> P and L -> P -> L, it should + suffice to make only P a stopper to stop unbounded left-recursion. And so it does. But, + stoppers parse greedily: they always consume the maximum of input. So below, if only P is a stopper, + at some point P parses the complete input. Then L fails because it cannot append ".x", then M fails. + If both are made a stopper then M succeeds. That is because P will try L when P '(n)' no longer + consumes input, which will appear as a left-recursion to L if it is a stopper and because of that + it will have a chance to succeed on the full input which it recorded in its seed for the previous + recursion. */ alias ParseTree = DefaultParseTree; @@ -2947,8 +2937,6 @@ unittest // Mutual left-recursion unittest // Left- and right-recursion (is right-associative!) { - alias ParseTree = DefaultParseTree; - enum LeftRightGrammar = ` LeftRight: M <- E eoi diff --git a/pegged/parser.d b/pegged/parser.d index 0f82f5f..8d39781 100644 --- a/pegged/parser.d +++ b/pegged/parser.d @@ -2115,4 +2115,5 @@ struct GenericPegged(ParseTree) } } +private import pegged.parsetree : DefaultParseTree; alias GenericPegged!(DefaultParseTree).Pegged Pegged; diff --git a/pegged/peg.d b/pegged/peg.d index fde5a7a..6960be9 100644 --- a/pegged/peg.d +++ b/pegged/peg.d @@ -24,6 +24,7 @@ import std.array; import std.conv; import std.string: strip; import std.typetuple; +import pegged.parsetree : isParseTree; // Returns quoted and escaped version of the input, but if the input is null, then return `"end of input"`. package string stringified(string inp) @safe @@ -104,33 +105,6 @@ string any(GetName g) @safe return "any"; } -import std.traits : isType, ReturnType, ForeachType, isCallable, Unqual; -template Returns(alias M) { - static if (isType!M) { - alias U = M; - } - else { - alias U = typeof(M); - } - static if (isCallable!U) { - alias Returns = Unqual!(ReturnType!U); - } - else { - alias Returns = Unqual!(U); - } -} - -enum isParseTree(T) = - is(Returns!(T.name) == string) && - is(Returns!(T.successful) == bool) && - is(Returns!(T.input) == string) && - is(Returns!(T.begin) == size_t) && - is(Returns!(T.end) == size_t) && - is(Returns!(T.failEnd) == size_t) && - is(ForeachType!(Returns!(T.matches)) == string) && - is(ForeachType!(Returns!(T.children)) == T) && - is(ForeachType!(Returns!(T.failedChild)) == T); - /** Matches the end of input. Fails if there is any character left. */ @@ -181,143 +155,6 @@ ParseTree fail(ParseTree)(const ParseTree p) @safe if (isParseTree!ParseTree) { -mixin template ParseTreeM() { - import pegged.peg; - import std.functional : toDelegate; - alias ParseTree = typeof(this); - string name; /// The node name - bool successful; /// Indicates whether a parsing was successful or not - string[] matches; /// The matched input's parts. Some expressions match at more than one place, hence matches is an array. - - string input; /// The input string that generated the parse tree. Stored here for the parse tree to be passed to other expressions, as input. - size_t begin, end; /// Indices for the matched part from the very beginning of the first match to the last char of the last match. - - ParseTree[] children; /// The sub-trees created by sub-rules parsing. - - size_t failEnd; // The furthest this tree could match the input (including !successful rules). - ParseTree[] failedChild; /// The !successful child that could still be partially parsed. - - /** - Basic toString for easy pretty-printing. - */ - string toString(string tabs = "") const - { - string result = name; - - string childrenString; - bool allChildrenSuccessful = true; - - foreach(i,child; children) - { - childrenString ~= tabs ~ " +-" ~ child.toString(tabs ~ ((i < children.length -1 ) ? " | " : " ")); - if (!child.successful) { - allChildrenSuccessful = false; - } - } - result ~= this.toStringThisNode(allChildrenSuccessful); - return result ~ childrenString; - } - - /** - * Basic toString of only this node, without the children - */ - private string toStringThisNode(bool allChildrenSuccessful) const - { - if (successful) { - return to!string([begin, end]) ~ to!string(matches) ~ "\n"; - } else { // some failure info is needed - if (allChildrenSuccessful) { // no one calculated the position yet - return " " ~ this.failMsg ~ "\n"; - } else { - return " (failure)\n"; - } - } - } - - /** - * Generates a generic error when a node fails - * - * @param successMsg String returned when there isn't an error - * @param formatFailMsg Formating delegate function that generates the error message. - */ - string failMsg(string delegate(Position, string, string, const ParseTree) formatFailMsg = toDelegate(&defaultFormatFailMsg!ParseTree), - string successMsg = "Sucess") const @property - { - foreach(i, child; children) { - if (!child.successful) { - return child.failMsg(formatFailMsg, successMsg); - } - } - - if (!successful) { - Position pos = position(this); - string left, right; - - if (pos.index < 10) { - left = input[0 .. pos.index]; - } else { - left = input[pos.index - 10 .. pos.index]; - } - if (pos.index + 10 < input.length) { - right = input[pos.index .. pos.index + 10]; - } else { - right = input[pos.index .. $]; - } - return formatFailMsg(pos, left, right, this); - } - - return successMsg; - } - - ParseTree dup() const @property - { - ParseTree result; - result.name = name; - result.successful = successful; - result.matches = matches.dup; - result.input = input; - result.begin = begin; - result.end = end; - result.failEnd = failEnd; - result.failedChild = map!(p => p.dup)(failedChild).array(); - result.children = map!(p => p.dup)(children).array(); - return result; - } - - immutable(ParseTree) idup() const @property - { - return cast(immutable)dup(); - } - - // Override opIndex operators - ref ParseTree opIndex(size_t index) { - return children[index]; - } - - ref ParseTree[] opIndex() return { - return children; - } - - size_t opDollar(size_t pos)() const - { - return children.length; - } - - ParseTree[] opSlice(size_t i, size_t j) { - return children[i..j]; - } -} - -/** - The basic parse tree, as used throughout the project. - You can define your own parse tree node, but respect the basic layout. -*/ -struct DefaultParseTree -{ - mixin ParseTreeM; -} - -static assert(isParseTree!DefaultParseTree); /** CT Switch for testing 'keywords' implementations */ @@ -551,7 +388,6 @@ struct PeggedT(ParseTree) { } } -/// ditto static ParseTree fail(string input) { return fail(ParseTree("", false, [], input)); @@ -583,12 +419,12 @@ struct PeggedT(ParseTree) { return any(ParseTree("", false, [], input)); } -/// ditto static ParseTree wordBoundary(string input) { return ParseTree("wordBoundary", isAlpha(input.front()), [], input, 0,0, null); } +/// ditto static string wordBoundary(GetName g) { return "wordBoundary"; @@ -611,9 +447,10 @@ struct PeggedT(ParseTree) { version(unittest) { private { - alias ParseTree = DefaultParseTree; + private import pegged.parsetree : DefaultParseTree; + private alias ParseTree = DefaultParseTree; mixin ParseCollections!ParseTree; - alias PEG=PeggedT!ParseTree; + private alias PEG=PeggedT!ParseTree; mixin DefaultParsePatterns!PEG; } } diff --git a/pegged/tester/testerparser.d b/pegged/tester/testerparser.d index 9267b2e..89784f0 100644 --- a/pegged/tester/testerparser.d +++ b/pegged/tester/testerparser.d @@ -203,4 +203,5 @@ struct GenericTesterGrammar(ParseTree) } } +private import pegged.parsetree : DefaultParseTree; alias GenericTesterGrammar!(DefaultParseTree).TesterGrammar TesterGrammar; From a0e9b2f18be29afb36cc148ee69896056973726b Mon Sep 17 00:00:00 2001 From: cbleser Date: Tue, 1 Jun 2021 10:11:51 +0300 Subject: [PATCH 09/29] WIP: GrammarOptions now it the grammar generator --- pegged/grammar.d | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/pegged/grammar.d b/pegged/grammar.d index 1f4de1f..a2a2693 100644 --- a/pegged/grammar.d +++ b/pegged/grammar.d @@ -15,6 +15,11 @@ public import pegged.peg; import pegged.parser; import pegged.parsetree : DefaultParseTree, isParseTree; +struct GrammarOptions { + string parsetreeName; +} + +enum defaultGrammarOptions = GrammarOptions(DefaultParseTree.stringof); /** @@ -26,7 +31,7 @@ enum Memoization { no, yes } This function takes a (future) module name, a (future) file name and a grammar as a string or a file. It writes the corresponding parser inside a module with the given name. */ -void asModule(Memoization withMemo = Memoization.yes)(string moduleName, string fileName, string grammarString, string optHeader = "") +void asModule(Memoization withMemo = Memoization.yes, ParseTree=DefaultParseTree)(string moduleName, string fileName, string grammarString, string optHeader = "", immutable GrammarOptions optGrammar=defaultGrammarOptions) if (isParseTree!ParseTree) { import std.stdio; auto f = File(fileName ~ ".d","w"); @@ -40,21 +45,29 @@ void asModule(Memoization withMemo = Memoization.yes)(string moduleName, string if (optHeader.length > 0) f.write(optHeader ~ "\n\n"); + static if (is(ParseTree == DefaultParseTree)) { + f.writeln("public import pegged.parsetree : DefaultParseTree;"); + } + else { + f.writefln(`static assert(is(%s), "ParseTree %s must be defined");`, ParseTree.stringof, ParseTree.stringof); + f.writefln(`static assert(isParseTree!(%s), "%s must compile with isParseTree");`, ParseTree.stringof, ParseTree.stringof); + + } f.write("public import pegged.peg;\n"); f.write("import std.algorithm: startsWith;\n"); f.write("import std.functional: toDelegate;\n\n"); - f.write(grammar!(withMemo)(grammarString)); + f.write(grammar!(withMemo)(grammarString, optGrammar)); } /// ditto -void asModule(Memoization withMemo = Memoization.yes)(string moduleName, File file, string optHeader = "") +void asModule(Memoization withMemo = Memoization.yes)(string moduleName, File file, string optHeader = "", immutable GrammarOptions optGrammar=defaultGrammarOptions) { string grammarDefinition; foreach(line; file.byLine) { grammarDefinition ~= line ~ '\n'; } - asModule!(withMemo)(moduleName, grammarDefinition, optHeader); + asModule!(withMemo)(moduleName, grammarDefinition, optHeader, optGrammar); } // Helper to insert 'Spacing' before and after Primaries @@ -97,7 +110,8 @@ ParseTree spaceArrow(ParseTree)(ParseTree input) ParseTree p = Gram("abcbccbcd"); ---- */ -string grammar(Memoization withMemo = Memoization.yes, ParseTree=DefaultParseTree)(string definition) +string grammar(Memoization withMemo = Memoization.yes, ParseTree=DefaultParseTree)(string definition, + GrammarOptions optGrammar=defaultGrammarOptions) if (isParseTree!ParseTree) { ParseTree defAsParseTree = Pegged(definition); @@ -107,10 +121,11 @@ string grammar(Memoization withMemo = Memoization.yes, ParseTree=DefaultParseTre string result = "static assert(false, `" ~ defAsParseTree.toString("") ~ "`);"; return result; } - return grammar!(ParseTree, withMemo)(defAsParseTree); + return grammar!(ParseTree, withMemo)(defAsParseTree, optGrammar); } /// ditto -string grammar(ParseTree, Memoization withMemo = Memoization.yes)(ParseTree defAsParseTree) if (isParseTree!ParseTree) +string grammar(ParseTree, Memoization withMemo = Memoization.yes)(ParseTree defAsParseTree, + GrammarOptions optGrammar=defaultGrammarOptions) if (isParseTree!ParseTree) { string[] composedGrammars; @@ -203,8 +218,10 @@ string grammar(ParseTree, Memoization withMemo = Memoization.yes)(ParseTree defA string shortGrammarName = p.children[0].matches[0]; //string invokedGrammarName = generateCode(transformName(p.children[0])); string firstRuleName = generateCode(p.children[1].children[0]); - result = "import pegged.parsetree : DefaultParseTree;\n"; + if (optGrammar.parsetreeName ==DefaultParseTree.stringof) { + result = "import pegged.parsetree : DefaultParseTree;\n"; + } result ~= "struct Generic" ~ shortGrammarName ~ "(ParseTree) { @@ -397,7 +414,7 @@ string grammar(ParseTree, Memoization withMemo = Memoization.yes)(ParseTree defA result ~= generateForgetMemo(); result ~= " }\n" // end of grammar struct definition ~ "}\n\n" // end of template definition - ~ "alias Generic" ~ shortGrammarName ~ "!(DefaultParseTree)." + ~ "alias Generic" ~ shortGrammarName ~ "!(" ~ optGrammar.parsetreeName ~ ")." ~ shortGrammarName ~ " " ~ shortGrammarName ~ ";\n\n"; break; case "Pegged.Definition": From 23140c69b0fdc38c877132a2dcbcc9e066838504 Mon Sep 17 00:00:00 2001 From: cbleser Date: Tue, 1 Jun 2021 10:17:47 +0300 Subject: [PATCH 10/29] WIP: forgot to add the pegged/parsetree.d module --- pegged/parsetree.d | 190 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 pegged/parsetree.d diff --git a/pegged/parsetree.d b/pegged/parsetree.d new file mode 100644 index 0000000..45ef4b9 --- /dev/null +++ b/pegged/parsetree.d @@ -0,0 +1,190 @@ +/** + This module contaits functions and parameter for ParseTree data element + */ +module pegged.parsetree; + +import std.traits : isType, ReturnType, ForeachType, isCallable, Unqual; +/** + Returns: + Gets the lvalue of M where M can be a function/data as type of data + */ +template Returns(alias M) { + static if (isType!M) { + alias U = M; + } + else { + alias U = typeof(M); + } + static if (isCallable!U) { + alias Returns = Unqual!(ReturnType!U); + } + else { + alias Returns = Unqual!(U); + } +} + +/** + Returns + true if T is a value ParseTree type + */ +enum isParseTree(T) = + is(Returns!(T.name) == string) && + is(Returns!(T.successful) == bool) && + is(Returns!(T.input) == string) && + is(Returns!(T.begin) == size_t) && + is(Returns!(T.end) == size_t) && + is(Returns!(T.failEnd) == size_t) && + is(ForeachType!(Returns!(T.matches)) == string) && + is(ForeachType!(Returns!(T.children)) == T) && + is(ForeachType!(Returns!(T.failedChild)) == T); + + +/** + Contains the basic data and function for a ParseTree data element + */ +mixin template ParseTreeM() { + import pegged.peg; + import std.functional : toDelegate; + import std.conv : to; + import std.algorithm.iteration : map; + import std.array : array; + + alias ParseTree = typeof(this); + string name; /// The node name + bool successful; /// Indicates whether a parsing was successful or not + string[] matches; /// The matched input's parts. Some expressions match at more than one place, hence matches is an array. + + string input; /// The input string that generated the parse tree. Stored here for the parse tree to be passed to other expressions, as input. + size_t begin, end; /// Indices for the matched part from the very beginning of the first match to the last char of the last match. + + ParseTree[] children; /// The sub-trees created by sub-rules parsing. + + size_t failEnd; // The furthest this tree could match the input (including !successful rules). + ParseTree[] failedChild; /// The !successful child that could still be partially parsed. + + /** + Basic toString for easy pretty-printing. + */ + string toString(string tabs = "") const + { + string result = name; + + string childrenString; + bool allChildrenSuccessful = true; + + foreach(i,child; children) + { + childrenString ~= tabs ~ " +-" ~ child.toString(tabs ~ ((i < children.length -1 ) ? " | " : " ")); + if (!child.successful) { + allChildrenSuccessful = false; + } + } + result ~= this.toStringThisNode(allChildrenSuccessful); + return result ~ childrenString; + } + + /** + * Basic toString of only this node, without the children + */ + private string toStringThisNode(bool allChildrenSuccessful) const + { + if (successful) { + return to!string([begin, end]) ~ to!string(matches) ~ "\n"; + } else { // some failure info is needed + if (allChildrenSuccessful) { // no one calculated the position yet + return " " ~ this.failMsg ~ "\n"; + } else { + return " (failure)\n"; + } + } + } + + /** + * Generates a generic error when a node fails + * + * @param successMsg String returned when there isn't an error + * @param formatFailMsg Formating delegate function that generates the error message. + */ + string failMsg(string delegate(Position, string, string, const ParseTree) formatFailMsg = toDelegate(&defaultFormatFailMsg!ParseTree), + string successMsg = "Sucess") const @property + { + foreach(i, child; children) { + if (!child.successful) { + return child.failMsg(formatFailMsg, successMsg); + } + } + + if (!successful) { + Position pos = position(this); + string left, right; + + if (pos.index < 10) { + left = input[0 .. pos.index]; + } else { + left = input[pos.index - 10 .. pos.index]; + } + if (pos.index + 10 < input.length) { + right = input[pos.index .. pos.index + 10]; + } else { + right = input[pos.index .. $]; + } + return formatFailMsg(pos, left, right, this); + } + + return successMsg; + } + + ParseTree dup() const @property + { + ParseTree result; + result.name = name; + result.successful = successful; + result.matches = matches.dup; + result.input = input; + result.begin = begin; + result.end = end; + result.failEnd = failEnd; + result.failedChild = map!(p => p.dup)(failedChild).array(); + result.children = map!(p => p.dup)(children).array(); + return result; + } + + immutable(ParseTree) idup() const @property + { + return cast(immutable)dup(); + } + + // Override opIndex operators + ref ParseTree opIndex(size_t index) { + return children[index]; + } + + ref ParseTree[] opIndex() return { + return children; + } + + size_t opDollar(size_t pos)() const + { + return children.length; + } + + ParseTree[] opSlice(size_t i, size_t j) { + return children[i..j]; + } +} + +/** + The basic parse tree, as used throughout the project. + You can define your own parse tree node, but respect the basic layout. + Example: + struct MyParseTree { + mixin ParseTreeM; + ... My own stuff + } +*/ +struct DefaultParseTree +{ + mixin ParseTreeM; +} + +static assert(isParseTree!DefaultParseTree); From 183a7d1f7e962b9403316057f8e14c539cbaed9b Mon Sep 17 00:00:00 2001 From: cbleser Date: Tue, 1 Jun 2021 13:20:44 +0300 Subject: [PATCH 11/29] WIP: maxEnd syntax error corrected --- pegged/peg.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pegged/peg.d b/pegged/peg.d index 6960be9..65289a4 100644 --- a/pegged/peg.d +++ b/pegged/peg.d @@ -1283,7 +1283,7 @@ auto maxFailEnd(ParseTree)(ParseTree[] children) if (isParseTree!ParseTree) { return children.map!(c => c.failEnd).maxElement; } -auto maxEnd(ParseTreeT)(ParseTreeT[] children) if (isParseTree!ParseTree) { +auto maxEnd(ParseTree)(ParseTree[] children) if (isParseTree!ParseTree) { return children.map!(c => c.end).maxElement; } From bb9b0a01f5337f8172da0691263ab7a1459a27fc Mon Sep 17 00:00:00 2001 From: cbleser Date: Tue, 1 Jun 2021 13:24:41 +0300 Subject: [PATCH 12/29] WIP: getUpto syntax error corrected --- pegged/peg.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pegged/peg.d b/pegged/peg.d index 65289a4..9b50698 100644 --- a/pegged/peg.d +++ b/pegged/peg.d @@ -1653,7 +1653,7 @@ template orT(ParseTree, rules...) if (rules.length > 0) } } -auto getUpto(ParseTreeT)(ParseTreeT[] children, size_t minFailedLength) { +auto getUpto(ParseTree)(ParseTree[] children, size_t minFailedLength) if (isParseTree!ParseTree) { return children.filter!(r => max(r.end, r.failEnd) >= minFailedLength).array(); } From 4e86f03e3dc4bc2002a55b2ed1a914e1959e13de Mon Sep 17 00:00:00 2001 From: cbleser Date: Wed, 2 Jun 2021 10:36:24 +0300 Subject: [PATCH 13/29] WIP: grammar generator now imports isParseTree --- pegged/grammar.d | 1 + 1 file changed, 1 insertion(+) diff --git a/pegged/grammar.d b/pegged/grammar.d index a2a2693..811c1b7 100644 --- a/pegged/grammar.d +++ b/pegged/grammar.d @@ -49,6 +49,7 @@ void asModule(Memoization withMemo = Memoization.yes, ParseTree=DefaultParseTree f.writeln("public import pegged.parsetree : DefaultParseTree;"); } else { + f.writefln("import pegged.parsetree : isParseTree;"); f.writefln(`static assert(is(%s), "ParseTree %s must be defined");`, ParseTree.stringof, ParseTree.stringof); f.writefln(`static assert(isParseTree!(%s), "%s must compile with isParseTree");`, ParseTree.stringof, ParseTree.stringof); From 3c16ea9c157ef2ee71f874483b01b6274591bd33 Mon Sep 17 00:00:00 2001 From: cbleser Date: Wed, 2 Jun 2021 11:19:28 +0300 Subject: [PATCH 14/29] WIP: Dynamic parser changed to support costume ParseTree --- pegged/dynamic/grammar.d | 40 ++++++++++++++++++++++++++-------------- pegged/grammar.d | 4 ++-- pegged/parser.d | 4 ++-- pegged/parsetree.d | 2 ++ 4 files changed, 32 insertions(+), 18 deletions(-) diff --git a/pegged/dynamic/grammar.d b/pegged/dynamic/grammar.d index fb127ce..bdbbd18 100644 --- a/pegged/dynamic/grammar.d +++ b/pegged/dynamic/grammar.d @@ -20,16 +20,24 @@ import pegged.parser; import pegged.dynamic.peg; private import pegged.parsetree : DefaultParseTree, isParseTree; -private alias ParseTree=DefaultParseTree; -struct ParameterizedRule +struct ParameterizedRule(ParseTree) { size_t numArgs; - Dynamic delegate(Dynamic[]) code; - + alias Dynamic=ParseTree.Dynamic; + alias DynamicModifier = Dynamic delegate(Dynamic[]); + DynamicModifier code; + +// @disbale this(); + this(const size_t num, DynamicModifier code) { + numArgs = num; + this.code=code; + } Dynamic opCall(D...)(D rules) { Dynamic[] args; + //args.length = rules.length; + pragma(msg, "Dynmaic ", typeof(rules)); foreach(i,rule; rules) { static if (is(typeof(rule) == Dynamic)) @@ -67,21 +75,25 @@ struct ParameterizedRule } } -ParameterizedRule parameterizedRule(size_t n, Dynamic delegate(Dynamic[] d) code) + ParameterizedRule!ParseTree parameterizedRule(ParseTree)(size_t n, Dynamic delegate(Dynamic[] d) code) { - ParameterizedRule pr; - pr.numArgs = n; - pr.code = code; - return pr; + return ParameterizedRule(n, code); + // ParameterizedRule pr; + // pr.numArgs = n; + // pr.code = code; + // return pr; } -struct DynamicGrammar +private alias ParseTree=DefaultParseTree; + +struct DynamicGrammar(ParseTree) { string grammarName; string startingRule; + alias Dynamic = ParseTree.Dynamic; Dynamic[string] rules; - ParameterizedRule[string] paramRules; - private alias ParseTree=DefaultParseTree; + ParameterizedRule!ParseTree[string] paramRules; +// private alias ParseTree=DefaultParseTree; ParseTree decimateTree(ParseTree p) { @@ -390,7 +402,7 @@ Dynamic makeRule(ParseTree)(ParseTree def, Dynamic[string] context) if (isParseT return named(code, def.matches[0]); } -DynamicGrammar grammar(string definition, Dynamic[string] context = null) +DynamicGrammar!ParseTree grammar(ParseTree)(string definition, ParseTree.Dynamic[string] context = null) if(isParseTree!ParseTree) { //writeln("Entering dyn gram"); ParseTree defAsParseTree = Pegged(definition); @@ -401,7 +413,7 @@ DynamicGrammar grammar(string definition, Dynamic[string] context = null) throw new Exception("Bad grammar input: " ~ defAsParseTree.toString("")); } - DynamicGrammar gram; + DynamicGrammar!ParseTree gram; foreach(name, rule; context) { gram.rules[name] = rule; diff --git a/pegged/grammar.d b/pegged/grammar.d index 811c1b7..b2bb5be 100644 --- a/pegged/grammar.d +++ b/pegged/grammar.d @@ -300,7 +300,7 @@ string grammar(ParseTree, Memoization withMemo = Memoization.yes)(ParseTree defA static void addRuleBefore(string parentRule, string ruleSyntax) { // enum name is the current grammar name - DynamicGrammar dg = pegged.dynamic.grammar.grammar(name ~ \": \" ~ ruleSyntax, rules); + auto dg = pegged.dynamic.grammar.grammar!ParseTree(name ~ \": \" ~ ruleSyntax, rules); foreach(ruleName,rule; dg.rules) if (ruleName != \"Spacing\") // Keep the local Spacing rule, do not overwrite it rules[ruleName] = rule; @@ -310,7 +310,7 @@ string grammar(ParseTree, Memoization withMemo = Memoization.yes)(ParseTree defA static void addRuleAfter(string parentRule, string ruleSyntax) { // enum name is the current grammar named - DynamicGrammar dg = pegged.dynamic.grammar.grammar(name ~ \": \" ~ ruleSyntax, rules); + auto dg = pegged.dynamic.grammar.grammar!ParseTree(name ~ \": \" ~ ruleSyntax, rules); foreach(ruleName,rule; dg.rules) { if (ruleName != \"Spacing\") diff --git a/pegged/parser.d b/pegged/parser.d index 8d39781..7336aa4 100644 --- a/pegged/parser.d +++ b/pegged/parser.d @@ -238,7 +238,7 @@ struct GenericPegged(ParseTree) static void addRuleBefore(string parentRule, string ruleSyntax) { // enum name is the current grammar name - DynamicGrammar dg = pegged.dynamic.grammar.grammar(name ~ ": " ~ ruleSyntax, rules); + auto dg = pegged.dynamic.grammar.grammar!ParseTree(name ~ ": " ~ ruleSyntax, rules); foreach(ruleName,rule; dg.rules) if (ruleName != "Spacing") // Keep the local Spacing rule, do not overwrite it rules[ruleName] = rule; @@ -248,7 +248,7 @@ struct GenericPegged(ParseTree) static void addRuleAfter(string parentRule, string ruleSyntax) { // enum name is the current grammar named - DynamicGrammar dg = pegged.dynamic.grammar.grammar(name ~ ": " ~ ruleSyntax, rules); + auto dg = pegged.dynamic.grammar.grammar!ParseTree(name ~ ": " ~ ruleSyntax, rules); foreach(name,rule; dg.rules) { if (name != "Spacing") diff --git a/pegged/parsetree.d b/pegged/parsetree.d index 45ef4b9..806274c 100644 --- a/pegged/parsetree.d +++ b/pegged/parsetree.d @@ -50,6 +50,8 @@ mixin template ParseTreeM() { import std.array : array; alias ParseTree = typeof(this); + alias Dynamic = ParseTree delegate(ParseTree); + string name; /// The node name bool successful; /// Indicates whether a parsing was successful or not string[] matches; /// The matched input's parts. Some expressions match at more than one place, hence matches is an array. From c0ca51fadb97bf090d1a45e40806b18b9d9def60 Mon Sep 17 00:00:00 2001 From: cbleser Date: Wed, 2 Jun 2021 13:10:14 +0300 Subject: [PATCH 15/29] WIP: Dynamic grammar is now change to take a ParseTree meta type --- pegged/grammar.d | 13 +--- pegged/parser.d | 5 +- pegged/parsetree.d | 2 + pegged/peg.d | 138 ++++++++++++++++++----------------- pegged/tester/testerparser.d | 4 +- 5 files changed, 79 insertions(+), 83 deletions(-) diff --git a/pegged/grammar.d b/pegged/grammar.d index b2bb5be..cd72fef 100644 --- a/pegged/grammar.d +++ b/pegged/grammar.d @@ -13,7 +13,7 @@ import std.stdio; public import pegged.peg; import pegged.parser; -import pegged.parsetree : DefaultParseTree, isParseTree; +package import pegged.parsetree; struct GrammarOptions { string parsetreeName; @@ -46,13 +46,12 @@ void asModule(Memoization withMemo = Memoization.yes, ParseTree=DefaultParseTree f.write(optHeader ~ "\n\n"); static if (is(ParseTree == DefaultParseTree)) { - f.writeln("public import pegged.parsetree : DefaultParseTree;"); + f.writeln("public import pegged.parsetree;"); } else { f.writefln("import pegged.parsetree : isParseTree;"); f.writefln(`static assert(is(%s), "ParseTree %s must be defined");`, ParseTree.stringof, ParseTree.stringof); f.writefln(`static assert(isParseTree!(%s), "%s must compile with isParseTree");`, ParseTree.stringof, ParseTree.stringof); - } f.write("public import pegged.peg;\n"); f.write("import std.algorithm: startsWith;\n"); @@ -229,9 +228,7 @@ string grammar(ParseTree, Memoization withMemo = Memoization.yes)(ParseTree defA import std.functional : toDelegate; import pegged.dynamic.grammar; static import pegged.peg; - mixin ParseCollections!ParseTree; alias PEG=PeggedT!ParseTree; - mixin DefaultParsePatterns!PEG; struct " ~ grammarName ~ "\n { enum name = \"" ~ shortGrammarName ~ "\"; @@ -1005,9 +1002,7 @@ mixin template expected() version(unittest) { private alias ParseTree = DefaultParseTree; - mixin ParseCollections!ParseTree; private alias PEG=PeggedT!ParseTree; - mixin DefaultParsePatterns!PEG; } unittest // 'grammar' unit test: low-level functionalities @@ -2215,10 +2210,6 @@ unittest // qualified names for rules unittest // Parameterized rules { - alias ParseTree = DefaultParseTree; - alias PEG=PeggedT!ParseTree; - mixin DefaultParsePatterns!PEG; - mixin(grammar(` Parameterized: # Different arities diff --git a/pegged/parser.d b/pegged/parser.d index 7336aa4..7234618 100644 --- a/pegged/parser.d +++ b/pegged/parser.d @@ -137,11 +137,11 @@ public import pegged.peg; import std.algorithm: startsWith; import std.functional: toDelegate; +private import pegged.parsetree; struct GenericPegged(ParseTree) { -// mixin ParseCollections!ParseTree; alias PEG=PeggedT!ParseTree; - mixin DefaultParsePatterns!PEG; +// mixin DefaultParsePatterns!PEG; import std.functional : toDelegate; import pegged.dynamic.grammar; static import pegged.peg; @@ -2115,5 +2115,4 @@ struct GenericPegged(ParseTree) } } -private import pegged.parsetree : DefaultParseTree; alias GenericPegged!(DefaultParseTree).Pegged Pegged; diff --git a/pegged/parsetree.d b/pegged/parsetree.d index 806274c..314c1e2 100644 --- a/pegged/parsetree.d +++ b/pegged/parsetree.d @@ -175,6 +175,8 @@ mixin template ParseTreeM() { } } +private import pegged.peg : ParseCollections; +mixin ParseCollections!DefaultParseTree; /** The basic parse tree, as used throughout the project. You can define your own parse tree node, but respect the basic layout. diff --git a/pegged/peg.d b/pegged/peg.d index 9b50698..2fb07c1 100644 --- a/pegged/peg.d +++ b/pegged/peg.d @@ -451,7 +451,7 @@ version(unittest) { private alias ParseTree = DefaultParseTree; mixin ParseCollections!ParseTree; private alias PEG=PeggedT!ParseTree; - mixin DefaultParsePatterns!PEG; +// mixin DefaultParsePatterns!PEG; } } @@ -3433,60 +3433,58 @@ template AddSpaceT(ParseTree, alias sp) unittest // 'spaceAnd' unit test { - with(PEG) { - alias literal!"a" a; - alias literal!"b" b; + alias a = PEG.literal!"a"; + alias b = PEG.literal!"b"; - //Basic use - alias and!(a,b) ab; - alias spaceAnd!(oneOrMore!blank, a, b) a_b; + //Basic use + alias ab = PEG.and!(a,b); + alias a_b = PEG.spaceAnd!(PEG.oneOrMore!(PEG.blank), a, b); - ParseTree reference = ab("ab"); - ParseTree result = a_b("ab"); + ParseTree reference = ab("ab"); + ParseTree result = a_b("ab"); - assert(reference.successful); - assert(result.successful); - assert(result.matches == reference.matches); - assert(result.begin == reference.begin); - assert(result.end == reference.end); - assert(result.children == reference.children); + assert(reference.successful); + assert(result.successful); + assert(result.matches == reference.matches); + assert(result.begin == reference.begin); + assert(result.end == reference.end); + assert(result.children == reference.children); - reference = ab(" a b "); - result = a_b( " a b "); + reference = ab(" a b "); + result = a_b( " a b "); - assert(!reference.successful); - assert(result.successful); - assert(result.matches == ["a","b"]); - assert(result.begin == 0); - assert(result.end == " a b ".length); - assert(result.children.length == 2); + assert(!reference.successful); + assert(result.successful); + assert(result.matches == ["a","b"]); + assert(result.begin == 0); + assert(result.end == " a b ".length); + assert(result.children.length == 2); - reference = ab("ac"); - result = a_b("ac"); + reference = ab("ac"); + result = a_b("ac"); - assert(!reference.successful); - assert(!result.successful); + assert(!reference.successful); + assert(!result.successful); - reference = ab(" a c "); - result = a_b(" a c "); + reference = ab(" a c "); + result = a_b(" a c "); - assert(!reference.successful); - assert(!result.successful); + assert(!reference.successful); + assert(!result.successful); - // With another separator than spaces - alias spaceAnd!(digit, a, b) a0b; + // With another separator than spaces + alias a0b = PEG.spaceAnd!(digit, a, b); - assert(a0b("ab").successful); - assert(!a0b(" a b ").successful); + assert(a0b("ab").successful); + assert(!a0b(" a b ").successful); - result = a0b("012a34b567"); + result = a0b("012a34b567"); - assert(result.successful); - assert(result.matches == ["a", "b"]); - assert(result.begin == 0); - assert(result.end == "012a34b567".length); - assert(result.children.length == 2); - } + assert(result.successful); + assert(result.matches == ["a", "b"]); + assert(result.begin == 0); + assert(result.end == "012a34b567".length); + assert(result.children.length == 2); } /// Mixin to simplify a parse tree inside a grammar @@ -3608,6 +3606,7 @@ ParseTree modify(ParseTree, alias predicate, alias modifier)(ParseTree input) if } mixin template ParseCollections(ParseTree) { + import pegged.peg; alias literal(string s) = literalT!(ParseTree, s); alias caseInsensitiveLiteral(string s) = caseInsensitiveLiteralT!(ParseTree, s); alias charRange(dchar begin, dchar end) = charRangeT!(ParseTree, begin, end); @@ -3634,47 +3633,52 @@ mixin template ParseCollections(ParseTree) { alias keep(alias r) = keepT!(ParseTree, r); alias AddSpace(alias sp) = AddSpaceT!(ParseTree, sp); -} +// } -mixin template DefaultParsePatterns(alias PEG) { +// mixin template DefaultParsePatterns() { import std.meta : staticMap; /* ****************** predefined rules ******************** */ - alias endOfLine = PEG.named!(PEG.or!(PEG.literal!("\r\n"), PEG.literal!("\n"), PEG.literal!("\r")), "endOfLine"); /// predefined end-of-line parser + alias endOfLine = named!(or!(literal!("\r\n"), literal!("\n"), literal!("\r")), "endOfLine"); /// predefined end-of-line parser alias eol = endOfLine; /// helper alias. - alias space = PEG.or!(PEG.literal!(" "), PEG.literal!("\t"), PEG.literal!("\v")); /// predefined space-recognizing parser (space or tabulation). - alias tab = PEG.named!(PEG.literal!"\t", "tab"); /// A parser recognizing \t (tabulation) - alias spaces = PEG.named!(PEG.fuse!(PEG.discardChildren!(PEG.oneOrMore!space)), + alias space = or!(literal!(" "), literal!("\t"), literal!("\v")); /// predefined space-recognizing parser (space or tabulation). + alias tab = named!(literal!"\t", "tab"); /// A parser recognizing \t (tabulation) + alias spaces = named!(fuse!(discardChildren!(oneOrMore!space)), "spaces"); /// aka '~space+' - alias blank = PEG.or!(space, endOfLine); /// Any blank char (spaces or end of line). - alias spacing = PEG.named!(PEG.discard!(PEG.zeroOrMore!blank), - "spacing"); /// The basic space-management parser: PEG.discard zero or more blank spaces. + alias blank = or!(space, endOfLine); /// Any blank char (spaces or end of line). + alias spacing = named!(discard!(zeroOrMore!blank), + "spacing"); /// The basic space-management parser: discard zero or more blank spaces. - alias digit = PEG.charRange!('0', '9'); /// Decimal digit: [0-9] - alias digits = PEG.named!(PEG.fuse!(PEG.discardChildren!(PEG.oneOrMore!digit)), "digits"); /// [0-9]+ + alias digit = charRange!('0', '9'); /// Decimal digit: [0-9] + alias digits = named!(fuse!(discardChildren!(oneOrMore!digit)), "digits"); /// [0-9]+ - alias hexDigit = PEG.or!(PEG.charRange!('0','9'), PEG.charRange!('a','f'), PEG.charRange!('A', 'F')); /// Hexadecimal digit: [0-9a-fA-F] + alias hexDigit = or!(charRange!('0','9'), charRange!('a','f'), charRange!('A', 'F')); /// Hexadecimal digit: [0-9a-fA-F] - alias alpha = PEG.charRange!('a', 'z'); /// [a-z] - alias Alpha = PEG.charRange!('A', 'Z'); /// [A-Z] + alias alpha = charRange!('a', 'z'); /// [a-z] + alias Alpha = charRange!('A', 'Z'); /// [A-Z] - alias ident = PEG.and!(PEG.oneOrMore!(PEG.or!(alpha, Alpha, PEG.literal!("_"))), PEG.zeroOrMore!(PEG.or!(digit, alpha, Alpha, PEG.literal!("_")))); - alias identifier = PEG.named!(PEG.fuse!(PEG.discardChildren!ident), + alias ident = and!(oneOrMore!(or!(alpha, Alpha, literal!("_"))), zeroOrMore!(or!(digit, alpha, Alpha, literal!("_")))); + alias identifier = named!(fuse!(discardChildren!ident), "identifier"); /// [a-zA-Z_][a-zA-Z_0-9]*, the basic C-family identifier - alias qualifiedIdentifier = PEG.named!(PEG.fuse!(PEG.discardChildren!(PEG.and!(identifier, PEG.zeroOrMore!(PEG.and!(PEG.literal!".", identifier))))), + alias qualifiedIdentifier = named!(fuse!(discardChildren!(and!(identifier, zeroOrMore!(and!(literal!".", identifier))))), "qualifiedIdentifier"); /// qualified identifiers (ids separated by dots: abd.def.g). - alias slash = PEG.named!(PEG.literal!"/", "slash"); /// A parser recognizing '/' - alias backslash = PEG.named!(PEG.literal!"\\", "backslash"); /// A parser recognizing '\' - alias quote = PEG.named!(PEG.literal!"'", "quote"); /// A parser recognizing ' (single quote) - alias doublequote = PEG.named!(PEG.literal!"\"", "doublequote"); /// A parser recognizing " (double quote) - alias backquote = PEG.named!(PEG.literal!"`", "backquote"); /// A parser recognizing $(BACKTICK) (backquote) + alias slash = named!(literal!"/", "slash"); /// A parser recognizing '/' + alias backslash = named!(literal!"\\", "backslash"); /// A parser recognizing '\' + alias quote = named!(literal!"'", "quote"); /// A parser recognizing ' (single quote) + alias doublequote = named!(literal!"\"", "doublequote"); /// A parser recognizing " (double quote) + alias backquote = named!(literal!"`", "backquote"); /// A parser recognizing $(BACKTICK) (backquote) /// A list of elem's separated by sep's. One element minimum. - alias list(alias elem, alias sep) = PEG.named!(spaceAnd!(PEG.oneOrMore!blank, PEG.and!(elem, PEG.zeroOrMore!(spaceAnd!(PEG.discardMatches!(sep), elem)))), "list"); + alias list(alias elem, alias sep) = named!(spaceAnd!(oneOrMore!blank, and!(elem, zeroOrMore!(spaceAnd!(discardMatches!(sep), elem)))), "list"); /// A list of elem's separated by sep's. The empty list (no elem, no sep) is OK. - alias list0(alias elem, alias sep) = PEG.named!(spaceAnd!(PEG.oneOrMore!blank, PEG.option!(PEG.and!(elem, PEG.zeroOrMore!(spaceAnd!(PEG.discardMatches!(sep), elem))))), "list0"); + alias list0(alias elem, alias sep) = named!(spaceAnd!(oneOrMore!blank, option!(and!(elem, zeroOrMore!(spaceAnd!(discardMatches!(sep), elem))))), "list0"); + + alias spaceAnd(alias sp, rules...) = and!(discard!(zeroOrMore!sp), staticMap!(AddSpace!(zeroOrMore!sp), rules)); + + static bool isParseCollectionDefined(ParseTree dummy) pure nothrow { + return true; + } - alias spaceAnd(alias sp, rules...) = PEG.and!(PEG.discard!(PEG.zeroOrMore!sp), staticMap!(AddSpace!(PEG.zeroOrMore!sp), rules)); } diff --git a/pegged/tester/testerparser.d b/pegged/tester/testerparser.d index 89784f0..ba29234 100644 --- a/pegged/tester/testerparser.d +++ b/pegged/tester/testerparser.d @@ -39,10 +39,11 @@ NestedCommentEnd <- '+/' module pegged.tester.testerparser; public import pegged.peg; +private import pegged.parsetree; struct GenericTesterGrammar(ParseTree) { alias PEG=PeggedT!ParseTree; - mixin DefaultParsePatterns!PEG; +// mixin DefaultParsePatterns!PEG; struct TesterGrammar { @@ -203,5 +204,4 @@ struct GenericTesterGrammar(ParseTree) } } -private import pegged.parsetree : DefaultParseTree; alias GenericTesterGrammar!(DefaultParseTree).TesterGrammar TesterGrammar; From 4b516d4673d94346c9618b57441d65619a428580 Mon Sep 17 00:00:00 2001 From: cbleser Date: Wed, 2 Jun 2021 13:21:26 +0300 Subject: [PATCH 16/29] WIP: Dynamic parsre support function has been change to work on ParseTree meta types --- pegged/dynamic/grammar.d | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/pegged/dynamic/grammar.d b/pegged/dynamic/grammar.d index bdbbd18..7958049 100644 --- a/pegged/dynamic/grammar.d +++ b/pegged/dynamic/grammar.d @@ -75,7 +75,7 @@ struct ParameterizedRule(ParseTree) } } - ParameterizedRule!ParseTree parameterizedRule(ParseTree)(size_t n, Dynamic delegate(Dynamic[] d) code) +ParameterizedRule!ParseTree parameterizedRule(ParseTree)(size_t n, Dynamic delegate(Dynamic[] d) code) { return ParameterizedRule(n, code); // ParameterizedRule pr; @@ -84,7 +84,7 @@ struct ParameterizedRule(ParseTree) // return pr; } -private alias ParseTree=DefaultParseTree; +//private alias ParseTree=DefaultParseTree; struct DynamicGrammar(ParseTree) { @@ -180,17 +180,19 @@ ParseTree spaceArrow(ParseTree)(ParseTree input) if (isParseTree!ParseTree) wrapInSpaces)(input); } -Dynamic makeRule(string def, Dynamic[string] context) +ParseTree.Dynamic makeRule(ParseTree)(string def, Dynamic[string] context) if(isParseTree!ParseTree) { ParseTree p = Pegged.decimateTree(Pegged.Definition(def)); return makeRule(p, context); } -Dynamic makeRule(ParseTree)(ParseTree def, Dynamic[string] context) if (isParseTree!ParseTree) + + +ParseTree.Dynamic makeRule(ParseTree)(ParseTree def, ParseTree.Dynamic[string] context) if (isParseTree!ParseTree) { - Dynamic code; + ParseTree.Dynamic code; - Dynamic getDyn(string name) + ParseTree.Dynamic getDyn(string name) { if (name in context) return context[name]; @@ -198,7 +200,7 @@ Dynamic makeRule(ParseTree)(ParseTree def, Dynamic[string] context) if (isParseT throw new Exception("Unknown name: " ~ name); } - Dynamic ruleFromTree(ParseTree p) + ParseTree.Dynamic ruleFromTree(ParseTree p) { //writeln("rfT: ", p.name, " ", p.matches); //Dynamic result; @@ -210,7 +212,7 @@ Dynamic makeRule(ParseTree)(ParseTree def, Dynamic[string] context) if (isParseT Dynamic[] children; foreach(seq; p.children) children ~= ruleFromTree(seq); - return distribute!(or)(children); + return distribute!(ParseTree, or)(children); //} //else // One child -> just a sequence, no need for a or!( , ) //{ @@ -223,7 +225,7 @@ Dynamic makeRule(ParseTree)(ParseTree def, Dynamic[string] context) if (isParseT Dynamic[] children; foreach(seq; p.children) children ~= ruleFromTree(seq); - return distribute!(pegged.dynamic.peg.and)(children); + return distribute!(ParseTree, and)(children); /+} else // One child -> just a Suffix, no need for a and!( , ) { @@ -266,7 +268,7 @@ Dynamic makeRule(ParseTree)(ParseTree def, Dynamic[string] context) if (isParseT Dynamic[] children; foreach(seq; p.children) children ~= ruleFromTree(seq); - return distribute!(pegged.dynamic.peg.or)(children); + return distribute!(ParseTree, or)(children); } else // One child -> just a sequence, no need for a or!( , ) { @@ -443,13 +445,13 @@ DynamicGrammar!ParseTree grammar(ParseTree)(string definition, ParseTree.Dynamic gram.startingRule = shortName; // prepending the global grammar name, to get a qualified-name rule 'Gram.Rule' def.matches[0] = shortGrammarName ~ "." ~ def.matches[0]; - gram.rules[shortName] = makeRule(def, gram.rules); + gram.rules[shortName] = makeRule!ParseTree(def, gram.rules); } return gram; } -Dynamic distribute(alias fun)(Dynamic[] args) +ParseTree.Dynamic distribute(ParseTree, alias fun)(ParseTree.Dynamic[] args) if(isParseTree!ParseTree) { //mixin(makeSwitch(40)); switch(args.length) @@ -467,6 +469,6 @@ Dynamic distribute(alias fun)(Dynamic[] args) case 6: return fun(args[0], args[1], args[2], args[3], args[4], args[5]); default: - return fun(fun(args[0], args[1], args[2], args[3], args[4], args[5]), distribute!fun(args[6..$])); + return fun(fun(args[0], args[1], args[2], args[3], args[4], args[5]), distribute!(ParseTree, fun)(args[6..$])); } } From ec6ea23e312ddc8b8d4d85b23774f38bb184bcd3 Mon Sep 17 00:00:00 2001 From: cbleser Date: Wed, 2 Jun 2021 13:22:54 +0300 Subject: [PATCH 17/29] WIP: Dynamic parsre support function has been change to work on ParseTree meta types --- pegged/dynamic/grammar.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pegged/dynamic/grammar.d b/pegged/dynamic/grammar.d index 7958049..8358d3b 100644 --- a/pegged/dynamic/grammar.d +++ b/pegged/dynamic/grammar.d @@ -37,7 +37,7 @@ struct ParameterizedRule(ParseTree) { Dynamic[] args; //args.length = rules.length; - pragma(msg, "Dynmaic ", typeof(rules)); + pragma(msg, "Dynmaic ", D); foreach(i,rule; rules) { static if (is(typeof(rule) == Dynamic)) From e5f837b1beb02dcbaf0311704397186df6c980c0 Mon Sep 17 00:00:00 2001 From: cbleser Date: Wed, 2 Jun 2021 13:26:33 +0300 Subject: [PATCH 18/29] WIP: Some compile time printouts removed --- pegged/dynamic/grammar.d | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/pegged/dynamic/grammar.d b/pegged/dynamic/grammar.d index 8358d3b..3df5588 100644 --- a/pegged/dynamic/grammar.d +++ b/pegged/dynamic/grammar.d @@ -36,8 +36,6 @@ struct ParameterizedRule(ParseTree) Dynamic opCall(D...)(D rules) { Dynamic[] args; - //args.length = rules.length; - pragma(msg, "Dynmaic ", D); foreach(i,rule; rules) { static if (is(typeof(rule) == Dynamic)) @@ -75,14 +73,14 @@ struct ParameterizedRule(ParseTree) } } -ParameterizedRule!ParseTree parameterizedRule(ParseTree)(size_t n, Dynamic delegate(Dynamic[] d) code) -{ - return ParameterizedRule(n, code); - // ParameterizedRule pr; - // pr.numArgs = n; - // pr.code = code; - // return pr; -} +// ParameterizedRule!ParseTree parameterizedRule(ParseTree)(size_t n, Dynamic delegate(Dynamic[] d) code) +// { +// return ParameterizedRule(n, code); +// // ParameterizedRule pr; +// // pr.numArgs = n; +// // pr.code = code; +// // return pr; +// } //private alias ParseTree=DefaultParseTree; From 3f3a117cbd6f1900f6bff486adfb8e913ed2d495 Mon Sep 17 00:00:00 2001 From: cbleser Date: Thu, 3 Jun 2021 09:14:33 +0300 Subject: [PATCH 19/29] WIP: All the lexer functions have been moved into the ParseCollections mixin --- .gitignore | 3 + pegged/dynamic/grammar.d | 2 +- pegged/grammar.d | 20 ++- pegged/parser.d | 13 +- pegged/peg.d | 310 +++++++++++++++++++++-------------- pegged/tester/testerparser.d | 12 +- 6 files changed, 220 insertions(+), 140 deletions(-) diff --git a/.gitignore b/.gitignore index 23e910d..64d6090 100644 --- a/.gitignore +++ b/.gitignore @@ -45,3 +45,6 @@ build/* .vscode/ +# Emacs +*# +*.parked \ No newline at end of file diff --git a/pegged/dynamic/grammar.d b/pegged/dynamic/grammar.d index 3df5588..74ee6f2 100644 --- a/pegged/dynamic/grammar.d +++ b/pegged/dynamic/grammar.d @@ -405,7 +405,7 @@ ParseTree.Dynamic makeRule(ParseTree)(ParseTree def, ParseTree.Dynamic[string] c DynamicGrammar!ParseTree grammar(ParseTree)(string definition, ParseTree.Dynamic[string] context = null) if(isParseTree!ParseTree) { //writeln("Entering dyn gram"); - ParseTree defAsParseTree = Pegged(definition); + ParseTree defAsParseTree = GenericPegged!(ParseTree).Pegged(definition); //writeln(defAsParseTree); if (!defAsParseTree.successful) { diff --git a/pegged/grammar.d b/pegged/grammar.d index cd72fef..3bbf7fa 100644 --- a/pegged/grammar.d +++ b/pegged/grammar.d @@ -225,10 +225,14 @@ string grammar(ParseTree, Memoization withMemo = Memoization.yes)(ParseTree defA result ~= "struct Generic" ~ shortGrammarName ~ "(ParseTree) { + static if (is(ParseTree == DefaultParseTree)) { + import PEG=pegged.parsetree; + } + import std.functional : toDelegate; import pegged.dynamic.grammar; static import pegged.peg; - alias PEG=PeggedT!ParseTree; + //alias PEG=PeggedT!ParseTree; struct " ~ grammarName ~ "\n { enum name = \"" ~ shortGrammarName ~ "\"; @@ -362,7 +366,7 @@ string grammar(ParseTree, Memoization withMemo = Memoization.yes)(ParseTree defA ~ parameterizedRulesSpecialCode ~ " return false;\n }\n }\n"; +/ - result ~= " mixin decimateTree;\n\n"; + result ~= " mixin decimateTree!ParseTree;\n\n"; // If the grammar provides a Spacing rule, then this will be used. // else, the predefined 'spacing' rule is used. @@ -1002,11 +1006,17 @@ mixin template expected() version(unittest) { private alias ParseTree = DefaultParseTree; - private alias PEG=PeggedT!ParseTree; + private import PEG=pegged.parsetree; } unittest // 'grammar' unit test: low-level functionalities { + pragma(msg, grammar(` + Test1: + Rule1 <- 'a' + Rule2 <- 'b' + `)); + mixin(grammar(` Test1: Rule1 <- 'a' @@ -2236,7 +2246,7 @@ unittest // Parameterized rules # Another common PEG pattern AllUntil(End) <~ (!End .)* :End `)); - with(PEG) { +// with(PEG) { alias Parameterized.Rule1!(PEG.literal!"a") R1; alias PEG.oneOrMore!(PEG.literal!"a") Ref1; @@ -2410,7 +2420,7 @@ Here is another line. assert(!Arith1("1 + 2*3/456").successful); assert(Arith2("1 + 2*3/456").successful); assert(Arith2("1 + 2*3/z").successful); - } +// } } version(unittest) // Semantic actions diff --git a/pegged/parser.d b/pegged/parser.d index 7234618..2816c51 100644 --- a/pegged/parser.d +++ b/pegged/parser.d @@ -140,11 +140,14 @@ import std.functional: toDelegate; private import pegged.parsetree; struct GenericPegged(ParseTree) { - alias PEG=PeggedT!ParseTree; + static if (is(ParseTree == DefaultParseTree)) { + import PEG=pegged.parsetree; + } +// alias PEG=PeggedT!ParseTree; // mixin DefaultParsePatterns!PEG; import std.functional : toDelegate; import pegged.dynamic.grammar; - static import pegged.peg; + //static import pegged.peg; struct Pegged { enum name = "Pegged"; @@ -262,17 +265,17 @@ struct GenericPegged(ParseTree) import std.algorithm : startsWith; return s.startsWith("Pegged."); } - mixin decimateTree; + mixin decimateTree!ParseTree; static ParseTree Grammar(ParseTree p) { if(__ctfe) { - return PEG.defined!(PEG.and!(Spacing, GrammarName, PEG.oneOrMore!(Definition), PEG.discard!(eoi)), "Pegged.Grammar")(p); + return PEG.defined!(PEG.and!(Spacing, GrammarName, PEG.oneOrMore!(Definition), PEG.discard!(PEG.eoi)), "Pegged.Grammar")(p); } else { - return hooked!(PEG.defined!(PEG.and!(Spacing, GrammarName, PEG.oneOrMore!(Definition), PEG.discard!(eoi)), "Pegged.Grammar"), "Grammar")(p); + return hooked!(PEG.defined!(PEG.and!(Spacing, GrammarName, PEG.oneOrMore!(Definition), PEG.discard!(PEG.eoi)), "Pegged.Grammar"), "Grammar")(p); } } static ParseTree Grammar(string s) diff --git a/pegged/peg.d b/pegged/peg.d index 2fb07c1..a2fb578 100644 --- a/pegged/peg.d +++ b/pegged/peg.d @@ -90,36 +90,6 @@ string getName(alias expr)() @property return __traits(identifier, expr); } -string fail(GetName g) @safe -{ - return "fail"; -} - -string eoi(GetName g) @safe -{ - return "eoi"; -} - -string any(GetName g) @safe -{ - return "any"; -} - -/** - Matches the end of input. Fails if there is any character left. -*/ -ParseTree eoi(ParseTree)(const ParseTree p) @safe if (isParseTree!ParseTree) { - if (p.end == p.input.length) - return ParseTree("eoi", true, [], p.input, p.end, p.end); - else - return ParseTree("eoi", false, ["end of input"], p.input, p.end, p.end); -} - -ParseTree eps(ParseTree)(const ParseTree p) @safe if (isParseTree!ParseTree) { - return ParseTree("eps", true, [""], p.input, p.end, p.end); -} - - /// To compare two trees for content (not bothering with node names) /// That's useful to compare the results from two different grammars. bool softCompare(ParseTree)(const ParseTree p1, const ParseTree p2) @safe if (isParseTree!ParseTree) { @@ -146,14 +116,6 @@ ParseTree wordBoundary(ParseTree)(const ParseTree p) @safe if (isParseTree!Parse return ParseTree("wordBoundary", matched, ["word boundary"], p.input, p.end, p.end, null); } -/** - Basic rule, that always fail without consuming. -*/ -ParseTree fail(ParseTree)(const ParseTree p) @safe if (isParseTree!ParseTree) { - return ParseTree("fail", false, [], p.input, p.end, p.end, null); -} - - /** CT Switch for testing 'keywords' implementations @@ -216,7 +178,7 @@ Position position(string s) /** Same as previous overload, but from the begin of P.input to p.end */ -Position position(ParseTree)(const ParseTree p) +Position position(ParseTree)(const ParseTree p) if(isParseTree!ParseTree) { return position(p.input[0..p.end]); } @@ -242,8 +204,9 @@ unittest struct PeggedT(ParseTree) { - import pegged.peg : fail, eoi, wordBoundary, eps; - mixin ParseCollections!ParseTree; + +// import pegged.peg : fail, eoi, wordBoundary, eps; +// mixin ParseCollections!ParseTree; version (tracer) { import std.experimental.logger; @@ -388,37 +351,7 @@ struct PeggedT(ParseTree) { } } - static ParseTree fail(string input) - { - return fail(ParseTree("", false, [], input)); - } - -/// ditto - static ParseTree eoi(string input) - { - return eoi(ParseTree("", false, [], input)); - } - - alias eoi endOfInput; /// helper alias. - -/** - Match any character. As long as there is at least a character left in the input, it succeeds. - Conversely, it fails only if called at the end of the input. -*/ - static ParseTree any(ParseTree p) - { - if (p.end < p.input.length) - return ParseTree("any", true, [p.input[p.end..p.end+1]], p.input, p.end, p.end+1); - else - return ParseTree("any", false, ["any char"], p.input, p.end, p.end); - } - -/// ditto - static ParseTree any(string input) - { - return any(ParseTree("", false, [], input)); - } - +// alias endOfInput = PEG.eoi; /// helper alias. static ParseTree wordBoundary(string input) { return ParseTree("wordBoundary", isAlpha(input.front()), [], input, 0,0, null); @@ -430,27 +363,15 @@ struct PeggedT(ParseTree) { return "wordBoundary"; } -/** - eps matches the empty string (usually denoted by the Greek letter 'epsilon') and always succeeds. - It's equivalent to literal!"" (for example, it creates a match of [""]: one match, the empty string). -*/ - static ParseTree eps(string input) - { - return eps(ParseTree("",false,[], input)); - } - - static string eps(GetName g) - { - return "eps"; - } } version(unittest) { private { private import pegged.parsetree : DefaultParseTree; private alias ParseTree = DefaultParseTree; - mixin ParseCollections!ParseTree; - private alias PEG=PeggedT!ParseTree; + private import PEG=pegged.parsetree; +// mixin ParseCollections!ParseTree; +// private alias PEG=PeggedT!ParseTree; // mixin DefaultParsePatterns!PEG; } } @@ -530,7 +451,7 @@ unittest // 'fail' unit test { ParseTree input = ParseTree("input", true, [], "This is the input string.", 0,0, null); - ParseTree result = fail(input); + ParseTree result = PEG.fail(input); assert(result.name == "fail"); assert(!result.successful, "'fail' fails."); assert(result.matches is null, "'fail' makes no match."); @@ -546,7 +467,7 @@ unittest // 'fail' unit test unittest // 'eoi' unit test { ParseTree input = ParseTree("input", true, [], "This is the input string.", 0,0, null); - ParseTree result = eoi(input); + ParseTree result = PEG.eoi(input); assert(result.name == "eoi"); assert(!result.successful, "'eoi' fails on non-null string."); assert(result.matches == ["end of input"], "'eoi' error message."); @@ -555,7 +476,7 @@ unittest // 'eoi' unit test assert(result.children is null, "'eoi' has no children."); input = ParseTree("input", true, [], "", 0,0, null); - result = eoi(input); + result = PEG.eoi(input); assert(result.successful, "'eoi' succeeds on strings of length 0."); result = PEG.eoi(""); assert(result.successful, "'eoi' succeeds on strings of length 0."); @@ -637,7 +558,7 @@ unittest // 'eps' unit test { ParseTree input = ParseTree("input", true, [], "abcdef", 0,0, null); - ParseTree result = eps(input); + ParseTree result = PEG.eps(input); assert(result.name == "eps"); assert(result.successful, "'eps' succeeds on non-null inputs."); @@ -648,7 +569,7 @@ unittest // 'eps' unit test input.input = ""; - result = eps(input); + result = PEG.eps(input); assert(result.name == "eps"); assert(result.successful, "'eps' succeeds on empty strings."); assert(result.matches == [""], "'eps' matches '' at the beginning, even on empty strings."); @@ -669,6 +590,102 @@ static string defaultFormatFailMsg(ParseTree)(Position pos, string left, string ~ `, but got ` ~ right.stringified; }; +template eoiT(ParseTree) { + @safe: +/** + Matches the end of input. Fails if there is any character left. +*/ + ParseTree eoiT(ParseTree p) { + if (p.end == p.input.length) + return ParseTree("eoi", true, [], p.input, p.end, p.end); + else + return ParseTree("eoi", false, ["end of input"], p.input, p.end, p.end); + } + +/// ditto + ParseTree eoiT(string input) + { + return eoiT(ParseTree("", false, [], input)); + } + + + string eoiT(GetName g) @safe + { + return "eoi"; + } +} + + +template epsT(ParseTree) { +/** + eps matches the empty string (usually denoted by the Greek letter 'epsilon') and always succeeds. + It's equivalent to literal!"" (for example, it creates a match of [""]: one match, the empty string). +*/ + ParseTree epsT(const ParseTree p) { + return ParseTree("eps", true, [""], p.input, p.end, p.end); + } + + ParseTree epsT(string input) + { + return epsT(ParseTree("",false,[], input)); + } + + string epsT(GetName g) + { + return "eps"; + } +} + + +template anyT(ParseTree) { + /** + Match any character. As long as there is at least a character left in the input, it succeeds. + Conversely, it fails only if called at the end of the input. + */ + ParseTree anyT(ParseTree p) { + if (p.end < p.input.length) + return ParseTree("any", true, [p.input[p.end..p.end+1]], p.input, p.end, p.end+1); + else + return ParseTree("any", false, ["any char"], p.input, p.end, p.end); + } + + + /// ditto + ParseTree anyT(string input) + { + return anyT(ParseTree("", false, [], input)); + } + + + string anyT(GetName g) @safe + { + return "any"; + } +} + +template failT(ParseTree) { + /** + Basic rule, that always fail without consuming. + */ + ParseTree failT(ParseTree p) @safe { + return ParseTree("fail", false, [], p.input, p.end, p.end, null); + } + + + + ParseTree failT(string input) + { + return failT(ParseTree("", false, [], input)); + } + + + string failT(GetName g) @safe + { + return "fail"; + } +} + + /** @@ -711,9 +728,9 @@ unittest // 'literal' unit test ParseTree input = ParseTree("input", true, [], "abcdef", 0,0, null); - alias literal!"a" a; - alias literal!"abc" abc; - alias literal!"" empty; + alias a = PEG.literal!"a"; + alias abc = PEG.literal!"abc"; + alias empty = PEG.literal!""; ParseTree result = a(input); @@ -854,9 +871,9 @@ unittest // 'caseInsensitiveLiteral' unit test { ParseTree input = ParseTree("input", true, [], "AbCdEf", 0,0, null); - alias caseInsensitiveLiteral!"a" a; - alias caseInsensitiveLiteral!"aBC" abc; - alias caseInsensitiveLiteral!"" empty; + alias PEG.caseInsensitiveLiteral!"a" a; + alias PEG.caseInsensitiveLiteral!"aBC" abc; + alias PEG.caseInsensitiveLiteral!"" empty; ParseTree result = a(input); @@ -962,7 +979,7 @@ unittest // 'caseInsensitiveLiteral' unit test assert(result.children is null, "'' has no children."); input.input = "ÄöÜæØå"; - result = caseInsensitiveLiteral!"äÖüÆøÅ"(input); + result = PEG.caseInsensitiveLiteral!"äÖüÆøÅ"(input); assert(result.successful, "Unicode characters are matched case insensitively."); } @@ -1004,11 +1021,11 @@ unittest // 'charRange' unit test { ParseTree input = ParseTree("input", true, [], "abcdef", 0,0, null); - alias charRange!('a','a') aa; - alias charRange!('a','b') ab; - alias charRange!('a','z') az; - alias charRange!(dchar.min,dchar.max) allChars; - alias charRange!('\U00000000','\U000000FF') ASCII; + alias aa = PEG.charRange!('a','a'); + alias ab = PEG.charRange!('a','b'); + alias az = PEG.charRange!('a','z'); + alias allChars = PEG.charRange!(dchar.min,dchar.max); + alias ASCII = PEG.charRange!('\U00000000','\U000000FF'); static assert(!__traits(compiles, {alias charRange!('z','a') za;})); @@ -1323,15 +1340,14 @@ bool failedChildFixup(ParseTree)(ref ParseTree p, size_t failEnd) if (isParseTre unittest // 'and' unit test { - alias literal!"abc" abc; - alias literal!"de" de; - alias literal!"f" f; - - alias and!(abc) abcAnd; - alias and!(abc,de) abcde; - alias and!(abc,de,f) abcdef; - alias and!(eps, abc, eps, de, eps, f, eps) withEps; + alias abc= PEG.literal!"abc"; + alias de = PEG.literal!"de"; + alias f = PEG.literal!"f"; + alias abcAnd = PEG.and!(abc); + alias abcde = PEG.and!(abc,de); + alias abcdef = PEG.and!(abc,de,f); + alias withEps = PEG.and!(PEG.eps, abc, PEG.eps, de, PEG.eps, f, PEG.eps); //assert(getName!(abcAnd)() == `and!(literal!("abc"))`); //assert(getName!(abcde)() == `and!(literal!("abc"), literal!("de"))`); //assert(getName!(abcdef)() == `and!(literal!("abc"), literal!("de"), literal!("f"))`); @@ -1401,11 +1417,12 @@ version (unittest) { unittest // 'and' unit test with zeroOrMore and longest failing match { - alias literal!"abc" A; - alias literal!"def" B; - alias literal!"ghi" C; + with(PEG) { + alias A = literal!"abc"; + alias B = literal!"def"; + alias C = literal!"ghi"; - alias and!(zeroOrMore!(and!(A,B)), C) Thing; + alias Thing = and!(zeroOrMore!(and!(A,B)), C) Thing; ParseTree input = ParseTree("",false,[], "abc"); ParseTree result = Thing(input); @@ -1413,11 +1430,13 @@ unittest // 'and' unit test with zeroOrMore and longest failing match assert(!result.successful); assert(getError(result).matches[$-1] == "\"def\"", "and!(zeroOrMore!(and!(literal!\"abc\", literal!\"def\")), literal!\"ghi\") should expected def when input is \"abc\""); assert(result.matches == []); + } } unittest // 'and' unit test with option and longest failing match { + with(PEG) { alias literal!"abc" A; alias literal!"def" B; alias literal!"ghi" C; @@ -1430,11 +1449,13 @@ unittest // 'and' unit test with option and longest failing match assert(!result.successful); assert(getError(result).matches[$-1] == "\"def\"", "and!(option!(and!(literal!\"abc\", literal!\"def\")), literal!\"ghi\") should expected def when input is \"abc\""); assert(result.matches == []); + } } unittest // 'and' unit test with oneOrMore and longest failing match { + with(PEG) { alias literal!"abc" A; alias literal!"def" B; alias literal!"ghi" C; @@ -1447,6 +1468,7 @@ unittest // 'and' unit test with oneOrMore and longest failing match assert(!result.successful); assert(getError(result).matches[$-1] == "\"def\"", "and!(oneOrMore!(and!(literal!\"abc\", literal!\"def\")), literal!\"ghi\") should expected def when input is \"abcdefabc\""); assert(result.matches == ["abc", "def"]); + } } template wrapAroundT(ParseTree, alias before, alias target, alias after) @@ -1660,6 +1682,7 @@ auto getUpto(ParseTree)(ParseTree[] children, size_t minFailedLength) if (isPars unittest // 'or' unit test { + with(PEG) { alias charRange!('a','b') ab; alias charRange!('c','d') cd; @@ -1718,6 +1741,7 @@ unittest // 'or' unit test assert(result.matches == [ "a char between 'a' and 'b' (charRange!('a','b')) or a char between 'c' and 'd' (charRange!('c','d'))"] , "or!([a-b],[c-d]) error message."); + } } /** @@ -1853,6 +1877,7 @@ template longest_matchT(ParseTree, rules...) if (rules.length > 0) unittest // 'longest_match' unit test { + with(PEG) { alias charRange!('a','b') ab; alias charRange!('c','d') cd; @@ -1921,6 +1946,7 @@ unittest // 'longest_match' unit test assert(result.matches == ["a", "a", "a"], "or! takes the first matching rule."); result = longest_match!(oneOrMore!(literal!("a")), and!(oneOrMore!(literal!("a")), literal!("cc")))(input); assert(result.matches == ["a", "a", "a", "cc"], "longest_match! takes the longest matching rule."); + } } @@ -2118,6 +2144,7 @@ template keywordsT(ParseTree,kws...) if (kws.length > 0) unittest { + with(PEG) { alias keywords!("abc","de","f") kw; assert(getName!(kw)() == `keywords!("abc", "de", "f")`); @@ -2159,6 +2186,7 @@ unittest assert(result.matches == [`one among ["abc", "de", "f"]`], "keywords error message."); assert(result.end == input.end, "keywords does not advance the index."); assert(result.children is null, "No children for `keywords`."); + } } @@ -2259,6 +2287,7 @@ template zeroOrMoreT(ParseTree, alias r) unittest // 'zeroOrMore' unit test { + with(PEG) { alias literal!"a" a; alias literal!"abc" abc; alias charRange!('a','z') az; @@ -2320,6 +2349,7 @@ unittest // 'zeroOrMore' unit test assert(result.end == 3); assert(result.children.length == 3); assert(result.children == [ az("abc"), az(az("abc")), az(az(az("abc")))]); + } } /** @@ -2428,6 +2458,7 @@ template oneOrMoreT(ParseTree, alias r) unittest // 'oneOrMore' unit test { + with(PEG) { alias literal!"a" a; alias literal!"abc" abc; alias charRange!('a','z') az; @@ -2490,6 +2521,7 @@ unittest // 'oneOrMore' unit test assert(result.end == 3); assert(result.children.length == 3); assert(result.children == [ az("abc"), az(az("abc")), az(az(az("abc")))]); + } } /** @@ -2538,6 +2570,7 @@ template optionT(ParseTree, alias r) unittest // 'option' unit test { + with(PEG) { alias literal!"a" a; alias literal!"abc" abc; @@ -2595,6 +2628,7 @@ unittest // 'option' unit test assert(result.begin == 0); assert(result.end == 0); assert(result.children.length == 0); + } } /** @@ -2632,6 +2666,7 @@ template posLookaheadT(ParseTree, alias r) unittest // 'posLookahead' unit test { + with(PEG) { alias literal!"a" a; alias literal!"abc" abc; @@ -2686,6 +2721,7 @@ unittest // 'posLookahead' unit test assert(result.begin == 0); assert(result.end == 0); assert(result.children.length == 0); + } } /** @@ -2703,6 +2739,7 @@ template negLookaheadT(ParseTree, alias r) if (shouldTrace(getName!(r)(), p)) trace(traceMsg(p, name, getName!(r)())); } + ParseTree temp = r(p); if (temp.successful) return ParseTree(name, false, ["anything but \"" ~ p.input[temp.begin..temp.end] ~ "\""], p.input, p.end, p.end); @@ -2723,6 +2760,7 @@ template negLookaheadT(ParseTree, alias r) unittest // 'negLookahead' unit test { + with(PEG) { alias literal!"a" a; alias literal!"abc" abc; @@ -2777,6 +2815,7 @@ unittest // 'negLookahead' unit test assert(result.begin == 0); assert(result.end == 0); assert(result.children.length == 0); + } } /** @@ -2831,6 +2870,7 @@ template namedT(ParseTree, alias r, string name) unittest // 'named' unit test { + with(PEG) { alias or!(literal!("abc"), charRange!('0','9')) rule; alias named!(rule, "myRule") myRule; @@ -2858,6 +2898,7 @@ unittest // 'named' unit test assert(myResult.begin == result.begin); assert(myResult.end == result.end); assert(myResult.children == result.children); + } } /** @@ -2913,6 +2954,7 @@ template definedT(ParseTree, alias r, string name) unittest // 'defined' unit test { + with(PEG) { alias or!(literal!("abc"), charRange!('0','9')) rule; alias defined!(rule, "myRule") myRule; @@ -2940,6 +2982,7 @@ unittest // 'defined' unit test assert(myResult.begin == result.begin); assert(myResult.end == result.end); assert(myResult.children[0] == result); + } } /** @@ -2972,7 +3015,7 @@ unittest // 'action' unit test p.matches ~= p.matches; // doubling matches return p; } - + with(PEG) { alias literal!("abc") abc; alias action!(abc, foo) abcfoo; @@ -2999,6 +3042,7 @@ unittest // 'action' unit test assert(result.begin == reference.begin); assert(result.end == reference.end); assert(result.children == reference.children); + } } /** @@ -3033,6 +3077,7 @@ template fuseT(ParseTree, alias r) unittest // 'fuse' unit test { + with(PEG) { alias oneOrMore!(literal!("abc")) abcs; alias fuse!(abcs) f; @@ -3072,6 +3117,7 @@ unittest // 'fuse' unit test assert(result.begin == reference.begin); assert(result.end == reference.end); assert(result.children == reference.children); + } } /** @@ -3154,6 +3200,7 @@ template discardT(ParseTree, alias r) unittest // 'discard' unit test { + with(PEG) { alias literal!"abc" abc; alias oneOrMore!abc abcs; alias discard!(literal!("abc")) dabc; @@ -3203,6 +3250,7 @@ unittest // 'discard' unit test assert(result.end == 3*3); assert(result.children.length == 2); assert(result.children == [abc("abcabcabc"), abc(abc(abc("abcabcabc")))]); + } } /** @@ -3234,6 +3282,7 @@ template dropT(ParseTree, alias r) unittest // 'drop' unit test { + with(PEG) { alias literal!"abc" abc; alias oneOrMore!abc abcs; alias drop!(literal!("abc")) dabc; @@ -3283,6 +3332,7 @@ unittest // 'drop' unit test assert(result.end == 3*3); assert(result.children.length == 2, "but only 2 children."); assert(result.children == [abc("abcabcabc"), abc(abc(abc("abcabcabc")))]); + } } /** @@ -3341,8 +3391,9 @@ template keepT(ParseTree, alias r) unittest // 'keep' unit test { + with(PEG) { // Grammar mimicry - struct KeepTest + static struct KeepTest { static bool isRule(string s) { @@ -3352,7 +3403,7 @@ unittest // 'keep' unit test return false; } - mixin decimateTree; + mixin decimateTree!ParseTree; // Equivalent to A <- 'a' 'b' static ParseTree A(string s) @@ -3379,6 +3430,7 @@ unittest // 'keep' unit test assert(reference.children.length == 0); assert(result.children.length == 1); assert(result.children == [literal!("b")(literal!("a")("abc"))], "'b' node was kept."); + } } template AddSpaceT(ParseTree, alias sp) @@ -3433,12 +3485,13 @@ template AddSpaceT(ParseTree, alias sp) unittest // 'spaceAnd' unit test { - alias a = PEG.literal!"a"; - alias b = PEG.literal!"b"; + with(PEG) { + alias a = literal!"a"; + alias b = literal!"b"; //Basic use - alias ab = PEG.and!(a,b); - alias a_b = PEG.spaceAnd!(PEG.oneOrMore!(PEG.blank), a, b); + alias ab = and!(a,b); + alias a_b = spaceAnd!(PEG.oneOrMore!(PEG.blank), a, b); ParseTree reference = ab("ab"); ParseTree result = a_b("ab"); @@ -3473,7 +3526,7 @@ unittest // 'spaceAnd' unit test assert(!result.successful); // With another separator than spaces - alias a0b = PEG.spaceAnd!(digit, a, b); + alias a0b = spaceAnd!(digit, a, b); assert(a0b("ab").successful); assert(!a0b(" a b ").successful); @@ -3485,10 +3538,11 @@ unittest // 'spaceAnd' unit test assert(result.begin == 0); assert(result.end == "012a34b567".length); assert(result.children.length == 2); + } } /// Mixin to simplify a parse tree inside a grammar -mixin template decimateTree() +mixin template decimateTree(ParseTree) { static ParseTree decimateTree(ParseTree p) { @@ -3606,7 +3660,13 @@ ParseTree modify(ParseTree, alias predicate, alias modifier)(ParseTree input) if } mixin template ParseCollections(ParseTree) { + @safe: import pegged.peg; + alias eoi = eoiT!ParseTree; + + alias eps = epsT!ParseTree; + alias any = anyT!ParseTree; + alias fail = failT!ParseTree; alias literal(string s) = literalT!(ParseTree, s); alias caseInsensitiveLiteral(string s) = caseInsensitiveLiteralT!(ParseTree, s); alias charRange(dchar begin, dchar end) = charRangeT!(ParseTree, begin, end); diff --git a/pegged/tester/testerparser.d b/pegged/tester/testerparser.d index ba29234..ef96a8d 100644 --- a/pegged/tester/testerparser.d +++ b/pegged/tester/testerparser.d @@ -42,7 +42,11 @@ public import pegged.peg; private import pegged.parsetree; struct GenericTesterGrammar(ParseTree) { - alias PEG=PeggedT!ParseTree; + static if (is(ParseTree == DefaultParseTree)) { + import PEG=pegged.parsetree; + } + + //alias PEG=PeggedT!ParseTree; // mixin DefaultParsePatterns!PEG; struct TesterGrammar @@ -66,14 +70,14 @@ struct GenericTesterGrammar(ParseTree) return false; } } - mixin decimateTree; + mixin decimateTree!ParseTree; static ParseTree Root(ParseTree p) { - return PEG.named!(PEG.and!(PEG.wrapAround!(Spacing, Node, Spacing), PEG.wrapAround!(Spacing, eoi, Spacing)), "TesterGrammar.Root")(p); + return PEG.named!(PEG.and!(PEG.wrapAround!(Spacing, Node, Spacing), PEG.wrapAround!(Spacing, PEG.eoi, Spacing)), "TesterGrammar.Root")(p); } static ParseTree Root(string s) { - return PEG.named!(PEG.and!(PEG.wrapAround!(Spacing, Node, Spacing), PEG.wrapAround!(Spacing, eoi, Spacing)), "TesterGrammar.Root")(ParseTree("", false,[], s)); + return PEG.named!(PEG.and!(PEG.wrapAround!(Spacing, Node, Spacing), PEG.wrapAround!(Spacing, PEG.eoi, Spacing)), "TesterGrammar.Root")(ParseTree("", false,[], s)); } static string Root(GetName g) { From b9d43db0f5391246f28d0cbc7689bfb305acc503 Mon Sep 17 00:00:00 2001 From: cbleser Date: Thu, 3 Jun 2021 14:09:57 +0300 Subject: [PATCH 20/29] The lexer patter has been moved into the ParseTree using the mixin template ParseCollectionsM; --- pegged/grammar.d | 37 ++--- pegged/parser.d | 8 +- pegged/parsetree.d | 33 +++- pegged/peg.d | 301 +++++++++++++++++++---------------- pegged/tester/testerparser.d | 6 +- 5 files changed, 215 insertions(+), 170 deletions(-) diff --git a/pegged/grammar.d b/pegged/grammar.d index 3bbf7fa..1fecf1a 100644 --- a/pegged/grammar.d +++ b/pegged/grammar.d @@ -225,13 +225,14 @@ string grammar(ParseTree, Memoization withMemo = Memoization.yes)(ParseTree defA result ~= "struct Generic" ~ shortGrammarName ~ "(ParseTree) { - static if (is(ParseTree == DefaultParseTree)) { - import PEG=pegged.parsetree; - } +// static if (is(ParseTree == DefaultParseTree)) { + alias PEG=ParseTree; +// } import std.functional : toDelegate; import pegged.dynamic.grammar; static import pegged.peg; + mixin DefaultPatters!ParseTree; //alias PEG=PeggedT!ParseTree; struct " ~ grammarName ~ "\n { @@ -1011,12 +1012,6 @@ version(unittest) { unittest // 'grammar' unit test: low-level functionalities { - pragma(msg, grammar(` - Test1: - Rule1 <- 'a' - Rule2 <- 'b' - `)); - mixin(grammar(` Test1: Rule1 <- 'a' @@ -1059,6 +1054,7 @@ unittest // 'grammar' unit test: PEG syntax Chars4 <- [\U00000000-\U000000FF] `)); + mixin DefaultPatters!ParseTree; ParseTree result = Terminals("abc"); assert(result.name == "Terminals", "Grammar name test."); @@ -2246,10 +2242,10 @@ unittest // Parameterized rules # Another common PEG pattern AllUntil(End) <~ (!End .)* :End `)); -// with(PEG) { - alias Parameterized.Rule1!(PEG.literal!"a") R1; - alias PEG.oneOrMore!(PEG.literal!"a") Ref1; + mixin DefaultPatters!ParseTree; + alias R1 = Parameterized.Rule1!(literal!"a"); + alias Ref1 = oneOrMore!(literal!"a"); ParseTree reference = Ref1("aaaa"); ParseTree result = R1("aaaa"); @@ -2269,8 +2265,8 @@ unittest // Parameterized rules assert(result.begin == reference.begin); assert(result.end == reference.end); - alias Parameterized.Rule1!(PEG.literal!"abc") R1long; - alias Ref1long=PEG.oneOrMore!(PEG.literal!"abc"); + alias Parameterized.Rule1!(literal!"abc") R1long; + alias Ref1long=oneOrMore!(literal!"abc"); reference = Ref1long("abcabcabcabc"); result = R1long("abcabcabcabc"); @@ -2282,8 +2278,8 @@ unittest // Parameterized rules assert(result.begin == reference.begin); assert(result.end == reference.end); - alias Parameterized.Rule1!(PEG.literal!"a", PEG.literal!"b") R2; - alias Ref2=PEG.oneOrMore!(PEG.and!(PEG.literal!"a", PEG.literal!"b")); + alias R2 = Parameterized.Rule1!(literal!"a", literal!"b"); + alias Ref2 = oneOrMore!(and!(literal!"a", literal!"b")); reference = Ref2("abababab"); result = R2("abababab"); @@ -2303,8 +2299,8 @@ unittest // Parameterized rules assert(result.begin == reference.begin); assert(result.end == reference.end); - alias Parameterized.Rule1!(PEG.literal!"a", PEG.literal!"b", PEG.literal!"c") R3; - alias oneOrMore!(PEG.and!(PEG.literal!"a", literal!"b", literal!"c")) Ref3; + alias R3 = Parameterized.Rule1!(literal!"a", literal!"b", literal!"c"); + alias Ref3 = oneOrMore!(and!(literal!"a", literal!"b", literal!"c")); reference = Ref3("abcabcabcabc"); result = R3("abcabcabcabc"); @@ -2752,14 +2748,14 @@ unittest // Test lambda syntax in semantic actions [`(a) { return a; }`], - [`(a, b) { + [q{(a, b) { string s = "}"; if (a.successful,) { s ~= q"<}>"; } else { { s ~= q"<}>"; /* } */ } } - return a;}`], + return a;}}], [`myAction`,`(a) {return a;}`,`myAction2`,`(a) { /* , } */ return a; }`], [`myAction`,`a => transform(a)`,`myAction2`], [`myAction`,"(a) { @@ -2888,6 +2884,7 @@ unittest // Direct left-recursion S <- E eoi E <- E '+n' / 'n' `; + pragma(msg, grammar(LeftGrammar)); mixin(grammar(LeftGrammar)); ParseTree result = Left("n+n+n+n"); assert(result.successful); diff --git a/pegged/parser.d b/pegged/parser.d index 2816c51..20973a5 100644 --- a/pegged/parser.d +++ b/pegged/parser.d @@ -140,9 +140,11 @@ import std.functional: toDelegate; private import pegged.parsetree; struct GenericPegged(ParseTree) { - static if (is(ParseTree == DefaultParseTree)) { - import PEG=pegged.parsetree; - } + alias PEG=ParseTree; + mixin DefaultPatters!ParseTree; + // static if (is(ParseTree == DefaultParseTree)) { + // import PEG=pegged.parsetree; + // } // alias PEG=PeggedT!ParseTree; // mixin DefaultParsePatterns!PEG; import std.functional : toDelegate; diff --git a/pegged/parsetree.d b/pegged/parsetree.d index 314c1e2..99c983d 100644 --- a/pegged/parsetree.d +++ b/pegged/parsetree.d @@ -85,6 +85,17 @@ mixin template ParseTreeM() { return result ~ childrenString; } + static ParseTree[] getUpto(ParseTree[] children, size_t minFailedLength) { + import std.algorithm : filter, max; + ParseTree[] arr; + foreach(a; children.filter!(r => max(r.end, r.failEnd) >= minFailedLength)) { + arr~=a; + } + return arr; +// return children.filter!(r => max(r.end, r.failEnd) >= minFailedLength).array(); + } + + /** * Basic toString of only this node, without the children */ @@ -101,13 +112,25 @@ mixin template ParseTreeM() { } } + /** + * Default fail message formating function + */ + static string defaultFormatFailMsg(Position pos, string left, string right, const ParseTree pt) + { + return "Failure at line " ~ to!string(pos.line) ~ ", col " ~ to!string(pos.col) ~ ", " + ~ (left.length > 0 ? "after " ~ left.stringified ~ " " : "") + ~ "expected " ~ (pt.matches.length > 0 ? pt.matches[$ - 1].stringified : "NO MATCH") + ~ `, but got ` ~ right.stringified; + }; + + /** * Generates a generic error when a node fails * * @param successMsg String returned when there isn't an error * @param formatFailMsg Formating delegate function that generates the error message. */ - string failMsg(string delegate(Position, string, string, const ParseTree) formatFailMsg = toDelegate(&defaultFormatFailMsg!ParseTree), + string failMsg(string delegate(Position, string, string, const ParseTree) formatFailMsg = toDelegate(&defaultFormatFailMsg), string successMsg = "Sucess") const @property { foreach(i, child; children) { @@ -175,8 +198,7 @@ mixin template ParseTreeM() { } } -private import pegged.peg : ParseCollections; -mixin ParseCollections!DefaultParseTree; +private import pegged.peg : ParseCollectionsM; /** The basic parse tree, as used throughout the project. You can define your own parse tree node, but respect the basic layout. @@ -186,9 +208,10 @@ mixin ParseCollections!DefaultParseTree; ... My own stuff } */ -struct DefaultParseTree -{ +struct DefaultParseTree { mixin ParseTreeM; + mixin ParseCollectionsM; } + static assert(isParseTree!DefaultParseTree); diff --git a/pegged/peg.d b/pegged/peg.d index a2fb578..0d66d22 100644 --- a/pegged/peg.d +++ b/pegged/peg.d @@ -451,7 +451,7 @@ unittest // 'fail' unit test { ParseTree input = ParseTree("input", true, [], "This is the input string.", 0,0, null); - ParseTree result = PEG.fail(input); + ParseTree result = ParseTree.fail(input); assert(result.name == "fail"); assert(!result.successful, "'fail' fails."); assert(result.matches is null, "'fail' makes no match."); @@ -459,7 +459,7 @@ unittest // 'fail' unit test assert(result.end == input.end, "'fail' puts the index after the previous parse."); assert(result.children is null, "'fail' has no children."); - result = PEG.fail("This is the input string."); + result = ParseTree.fail("This is the input string."); assert(!result.successful, "'fail' fails."); } @@ -467,7 +467,7 @@ unittest // 'fail' unit test unittest // 'eoi' unit test { ParseTree input = ParseTree("input", true, [], "This is the input string.", 0,0, null); - ParseTree result = PEG.eoi(input); + ParseTree result = ParseTree.eoi(input); assert(result.name == "eoi"); assert(!result.successful, "'eoi' fails on non-null string."); assert(result.matches == ["end of input"], "'eoi' error message."); @@ -476,11 +476,11 @@ unittest // 'eoi' unit test assert(result.children is null, "'eoi' has no children."); input = ParseTree("input", true, [], "", 0,0, null); - result = PEG.eoi(input); + result = ParseTree.eoi(input); assert(result.successful, "'eoi' succeeds on strings of length 0."); - result = PEG.eoi(""); + result = ParseTree.eoi(""); assert(result.successful, "'eoi' succeeds on strings of length 0."); - result = PEG.eoi(null); + result = ParseTree.eoi(null); assert(result.successful, "'eoi' succeeds on null strings"); } @@ -488,7 +488,7 @@ unittest // 'eoi' unit test unittest // 'any' unit test { ParseTree input = ParseTree("input", true, [], "This is the input string.", 0,0, null); - ParseTree result = PEG.any(input); + ParseTree result = ParseTree.any(input); assert(result.name == "any"); assert(result.successful, "'any' succeeds on non-null strings."); @@ -497,7 +497,7 @@ unittest // 'any' unit test assert(result.end == input.end+1, "'any' advances the index by one position."); assert(result.children is null, "'any' has no children."); - result = PEG.any("a"); + result = ParseTree.any("a"); assert(result.successful, "'any' matches on strings of length one."); assert(result.matches == ["a"], "'any' matches the first char in an input."); assert(result.input == "a", "'any' does not change the input."); @@ -506,17 +506,17 @@ unittest // 'any' unit test input = ParseTree("input", true, [], "", 0,0, null); - result = PEG.any(input); + result = ParseTree.any(input); assert(!result.successful, "'any' fails on strings of length 0."); assert(result.matches == ["any char"], "'any' error message on strings of length 0."); assert(result.end == 0, "'any' does not advance the index."); - result = PEG.any(""); + result = ParseTree.any(""); assert(!result.successful, "'any' fails on strings of length 0."); assert(result.matches == ["any char"], "'any' error message on strings of length 0."); assert(result.end == 0, "'any' does not advance the index."); - result = PEG.any(null); + result = ParseTree.any(null); assert(!result.successful, "'any' fails on null strings."); assert(result.matches == ["any char"], "'any' error message on strings of length 0."); assert(result.end == 0, "'any' does not advance the index."); @@ -558,7 +558,7 @@ unittest // 'eps' unit test { ParseTree input = ParseTree("input", true, [], "abcdef", 0,0, null); - ParseTree result = PEG.eps(input); + ParseTree result = ParseTree.eps(input); assert(result.name == "eps"); assert(result.successful, "'eps' succeeds on non-null inputs."); @@ -569,7 +569,7 @@ unittest // 'eps' unit test input.input = ""; - result = PEG.eps(input); + result = ParseTree.eps(input); assert(result.name == "eps"); assert(result.successful, "'eps' succeeds on empty strings."); assert(result.matches == [""], "'eps' matches '' at the beginning, even on empty strings."); @@ -579,16 +579,6 @@ unittest // 'eps' unit test } -/** - * Default fail message formating function - */ -static string defaultFormatFailMsg(ParseTree)(Position pos, string left, string right, const ParseTree pt) if (isParseTree!ParseTree) -{ - return "Failure at line " ~ to!string(pos.line) ~ ", col " ~ to!string(pos.col) ~ ", " - ~ (left.length > 0 ? "after " ~ left.stringified ~ " " : "") - ~ "expected " ~ (pt.matches.length > 0 ? pt.matches[$ - 1].stringified : "NO MATCH") - ~ `, but got ` ~ right.stringified; -}; template eoiT(ParseTree) { @safe: @@ -728,9 +718,9 @@ unittest // 'literal' unit test ParseTree input = ParseTree("input", true, [], "abcdef", 0,0, null); - alias a = PEG.literal!"a"; - alias abc = PEG.literal!"abc"; - alias empty = PEG.literal!""; + alias a = ParseTree.literal!"a"; + alias abc = ParseTree.literal!"abc"; + alias empty = ParseTree.literal!""; ParseTree result = a(input); @@ -871,9 +861,9 @@ unittest // 'caseInsensitiveLiteral' unit test { ParseTree input = ParseTree("input", true, [], "AbCdEf", 0,0, null); - alias PEG.caseInsensitiveLiteral!"a" a; - alias PEG.caseInsensitiveLiteral!"aBC" abc; - alias PEG.caseInsensitiveLiteral!"" empty; + alias ParseTree.caseInsensitiveLiteral!"a" a; + alias ParseTree.caseInsensitiveLiteral!"aBC" abc; + alias ParseTree.caseInsensitiveLiteral!"" empty; ParseTree result = a(input); @@ -979,7 +969,7 @@ unittest // 'caseInsensitiveLiteral' unit test assert(result.children is null, "'' has no children."); input.input = "ÄöÜæØå"; - result = PEG.caseInsensitiveLiteral!"äÖüÆøÅ"(input); + result = ParseTree.caseInsensitiveLiteral!"äÖüÆøÅ"(input); assert(result.successful, "Unicode characters are matched case insensitively."); } @@ -1021,11 +1011,11 @@ unittest // 'charRange' unit test { ParseTree input = ParseTree("input", true, [], "abcdef", 0,0, null); - alias aa = PEG.charRange!('a','a'); - alias ab = PEG.charRange!('a','b'); - alias az = PEG.charRange!('a','z'); - alias allChars = PEG.charRange!(dchar.min,dchar.max); - alias ASCII = PEG.charRange!('\U00000000','\U000000FF'); + alias aa = ParseTree.charRange!('a','a'); + alias ab = ParseTree.charRange!('a','b'); + alias az = ParseTree.charRange!('a','z'); + alias allChars = ParseTree.charRange!(dchar.min,dchar.max); + alias ASCII = ParseTree.charRange!('\U00000000','\U000000FF'); static assert(!__traits(compiles, {alias charRange!('z','a') za;})); @@ -1340,14 +1330,15 @@ bool failedChildFixup(ParseTree)(ref ParseTree p, size_t failEnd) if (isParseTre unittest // 'and' unit test { - alias abc= PEG.literal!"abc"; - alias de = PEG.literal!"de"; - alias f = PEG.literal!"f"; + mixin DefaultPatters!ParseTree; + alias abc= ParseTree.literal!"abc"; + alias de = ParseTree.literal!"de"; + alias f = ParseTree.literal!"f"; - alias abcAnd = PEG.and!(abc); - alias abcde = PEG.and!(abc,de); - alias abcdef = PEG.and!(abc,de,f); - alias withEps = PEG.and!(PEG.eps, abc, PEG.eps, de, PEG.eps, f, PEG.eps); + alias abcAnd = and!(abc); + alias abcde = and!(abc,de); + alias abcdef = and!(abc,de,f); + alias withEps = and!(eps, abc, eps, de, eps, f, eps); //assert(getName!(abcAnd)() == `and!(literal!("abc"))`); //assert(getName!(abcde)() == `and!(literal!("abc"), literal!("de"))`); //assert(getName!(abcdef)() == `and!(literal!("abc"), literal!("de"), literal!("f"))`); @@ -1417,12 +1408,11 @@ version (unittest) { unittest // 'and' unit test with zeroOrMore and longest failing match { - with(PEG) { - alias A = literal!"abc"; - alias B = literal!"def"; - alias C = literal!"ghi"; + alias A = ParseTree.literal!"abc"; + alias B = ParseTree.literal!"def"; + alias C = ParseTree.literal!"ghi"; - alias Thing = and!(zeroOrMore!(and!(A,B)), C) Thing; + alias Thing = ParseTree.and!(ParseTree.zeroOrMore!(ParseTree.and!(A,B)), C) Thing; ParseTree input = ParseTree("",false,[], "abc"); ParseTree result = Thing(input); @@ -1430,18 +1420,16 @@ unittest // 'and' unit test with zeroOrMore and longest failing match assert(!result.successful); assert(getError(result).matches[$-1] == "\"def\"", "and!(zeroOrMore!(and!(literal!\"abc\", literal!\"def\")), literal!\"ghi\") should expected def when input is \"abc\""); assert(result.matches == []); - } } unittest // 'and' unit test with option and longest failing match { - with(PEG) { - alias literal!"abc" A; - alias literal!"def" B; - alias literal!"ghi" C; + alias A = ParseTree.literal!"abc"; + alias B = ParseTree.literal!"def"; + alias C = ParseTree.literal!"ghi"; - alias and!(option!(and!(A,B)), C) Thing; + alias Thing = ParseTree.and!(ParseTree.option!(ParseTree.and!(A,B)), C); ParseTree input = ParseTree("",false,[], "abc"); ParseTree result = Thing(input); @@ -1449,18 +1437,16 @@ unittest // 'and' unit test with option and longest failing match assert(!result.successful); assert(getError(result).matches[$-1] == "\"def\"", "and!(option!(and!(literal!\"abc\", literal!\"def\")), literal!\"ghi\") should expected def when input is \"abc\""); assert(result.matches == []); - } } unittest // 'and' unit test with oneOrMore and longest failing match { - with(PEG) { - alias literal!"abc" A; - alias literal!"def" B; - alias literal!"ghi" C; + alias ParseTree.literal!"abc" A; + alias ParseTree.literal!"def" B; + alias ParseTree.literal!"ghi" C; - alias and!(oneOrMore!(and!(A,B)), C) Thing; + alias Thing = ParseTree.and!(ParseTree.oneOrMore!(ParseTree.and!(A,B)), C); ParseTree input = ParseTree("",false,[], "abcdefabc"); ParseTree result = Thing(input); @@ -1468,7 +1454,6 @@ unittest // 'and' unit test with oneOrMore and longest failing match assert(!result.successful); assert(getError(result).matches[$-1] == "\"def\"", "and!(oneOrMore!(and!(literal!\"abc\", literal!\"def\")), literal!\"ghi\") should expected def when input is \"abcdefabc\""); assert(result.matches == ["abc", "def"]); - } } template wrapAroundT(ParseTree, alias before, alias target, alias after) @@ -1660,7 +1645,7 @@ template orT(ParseTree, 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[].getUpto(maxFailedLength); + auto children = ParseTree.getUpto(results, maxFailedLength); return ParseTree(name, false, longestFail.matches, p.input, p.end, longestFail.end, children, children.maxFailEnd); } @@ -1675,14 +1660,10 @@ template orT(ParseTree, rules...) if (rules.length > 0) } } -auto getUpto(ParseTree)(ParseTree[] children, size_t minFailedLength) if (isParseTree!ParseTree) { - return children.filter!(r => max(r.end, r.failEnd) >= minFailedLength).array(); -} - unittest // 'or' unit test { - with(PEG) { + mixin DefaultPatters!ParseTree; alias charRange!('a','b') ab; alias charRange!('c','d') cd; @@ -1741,7 +1722,6 @@ unittest // 'or' unit test assert(result.matches == [ "a char between 'a' and 'b' (charRange!('a','b')) or a char between 'c' and 'd' (charRange!('c','d'))"] , "or!([a-b],[c-d]) error message."); - } } /** @@ -1876,13 +1856,13 @@ template longest_matchT(ParseTree, rules...) if (rules.length > 0) unittest // 'longest_match' unit test { + mixin DefaultPatters!ParseTree; - with(PEG) { - alias charRange!('a','b') ab; - alias charRange!('c','d') cd; + alias ab = charRange!('a','b'); + alias cd = charRange!('c','d'); - alias longest_match!(ab) abOr; - alias longest_match!(ab,cd) abOrcd; + alias abOr = longest_match!(ab); + alias abOrcd = longest_match!(ab,cd); assert(getName!(ab)() == "charRange!('a','b')"); assert(getName!(cd)() == "charRange!('c','d')"); @@ -1946,7 +1926,6 @@ unittest // 'longest_match' unit test assert(result.matches == ["a", "a", "a"], "or! takes the first matching rule."); result = longest_match!(oneOrMore!(literal!("a")), and!(oneOrMore!(literal!("a")), literal!("cc")))(input); assert(result.matches == ["a", "a", "a", "cc"], "longest_match! takes the longest matching rule."); - } } @@ -2144,8 +2123,7 @@ template keywordsT(ParseTree,kws...) if (kws.length > 0) unittest { - with(PEG) { - alias keywords!("abc","de","f") kw; + alias kw = ParseTree.keywords!("abc","de","f"); assert(getName!(kw)() == `keywords!("abc", "de", "f")`); @@ -2186,7 +2164,6 @@ unittest assert(result.matches == [`one among ["abc", "de", "f"]`], "keywords error message."); assert(result.end == input.end, "keywords does not advance the index."); assert(result.children is null, "No children for `keywords`."); - } } @@ -2287,7 +2264,7 @@ template zeroOrMoreT(ParseTree, alias r) unittest // 'zeroOrMore' unit test { - with(PEG) { + mixin DefaultPatters!ParseTree; alias literal!"a" a; alias literal!"abc" abc; alias charRange!('a','z') az; @@ -2349,7 +2326,6 @@ unittest // 'zeroOrMore' unit test assert(result.end == 3); assert(result.children.length == 3); assert(result.children == [ az("abc"), az(az("abc")), az(az(az("abc")))]); - } } /** @@ -2458,14 +2434,14 @@ template oneOrMoreT(ParseTree, alias r) unittest // 'oneOrMore' unit test { - with(PEG) { - alias literal!"a" a; - alias literal!"abc" abc; - alias charRange!('a','z') az; + mixin DefaultPatters!(ParseTree, [q{literal}, q{charRange}, q{oneOrMore}]); + alias a = literal!"a"; + alias abc = literal!"abc"; + alias az = charRange!('a','z'); - alias oneOrMore!(a) as; - alias oneOrMore!(abc) abcs; - alias oneOrMore!(az) azs; + alias as = oneOrMore!(a); + alias abcs = oneOrMore!(abc); + alias azs = oneOrMore!(az); assert(getName!(as)() == `oneOrMore!(literal!("a"))`); assert(getName!(abcs)() == `oneOrMore!(literal!("abc"))`); @@ -2521,7 +2497,6 @@ unittest // 'oneOrMore' unit test assert(result.end == 3); assert(result.children.length == 3); assert(result.children == [ az("abc"), az(az("abc")), az(az(az("abc")))]); - } } /** @@ -2570,7 +2545,7 @@ template optionT(ParseTree, alias r) unittest // 'option' unit test { - with(PEG) { + mixin DefaultPatters!(ParseTree, [q{literal}, q{option}]); alias literal!"a" a; alias literal!"abc" abc; @@ -2628,7 +2603,6 @@ unittest // 'option' unit test assert(result.begin == 0); assert(result.end == 0); assert(result.children.length == 0); - } } /** @@ -2666,12 +2640,13 @@ template posLookaheadT(ParseTree, alias r) unittest // 'posLookahead' unit test { - with(PEG) { - alias literal!"a" a; - alias literal!"abc" abc; + mixin DefaultPatters!(ParseTree, [q{literal}, q{posLookahead}]); + + alias a = literal!"a"; + alias abc = literal!"abc"; - alias posLookahead!(a) a_; - alias posLookahead!(abc) abc_; + alias a_ = posLookahead!(a); + alias abc_ = posLookahead!(abc); assert(getName!(a_)() == `posLookahead!(literal!("a"))`); assert(getName!(abc_)() == `posLookahead!(literal!("abc"))`); @@ -2721,7 +2696,6 @@ unittest // 'posLookahead' unit test assert(result.begin == 0); assert(result.end == 0); assert(result.children.length == 0); - } } /** @@ -2760,12 +2734,13 @@ template negLookaheadT(ParseTree, alias r) unittest // 'negLookahead' unit test { - with(PEG) { - alias literal!"a" a; - alias literal!"abc" abc; + mixin DefaultPatters!(ParseTree, [q{literal}, q{negLookahead}]); + + alias a = literal!"a"; + alias abc = literal!"abc"; - alias negLookahead!(a) a_; - alias negLookahead!(abc) abc_; + alias a_ = negLookahead!(a); + alias abc_ = negLookahead!(abc); assert(getName!(a_)() == `negLookahead!(literal!("a"))`); assert(getName!(abc_)() == `negLookahead!(literal!("abc"))`); @@ -2815,7 +2790,6 @@ unittest // 'negLookahead' unit test assert(result.begin == 0); assert(result.end == 0); assert(result.children.length == 0); - } } /** @@ -2870,9 +2844,10 @@ template namedT(ParseTree, alias r, string name) unittest // 'named' unit test { - with(PEG) { - alias or!(literal!("abc"), charRange!('0','9')) rule; - alias named!(rule, "myRule") myRule; + mixin DefaultPatters!(ParseTree, [q{literal}, q{or}, q{named}, q{charRange}]); + + alias rule = or!(literal!("abc"), charRange!('0','9')); + alias myRule = named!(rule, "myRule"); assert(getName!(rule)() == `or!(literal!("abc"), charRange!('0','9'))`); assert(getName!(myRule)() == "myRule"); @@ -2898,7 +2873,6 @@ unittest // 'named' unit test assert(myResult.begin == result.begin); assert(myResult.end == result.end); assert(myResult.children == result.children); - } } /** @@ -2954,9 +2928,10 @@ template definedT(ParseTree, alias r, string name) unittest // 'defined' unit test { - with(PEG) { - alias or!(literal!("abc"), charRange!('0','9')) rule; - alias defined!(rule, "myRule") myRule; + mixin DefaultPatters!(ParseTree, [q{literal}, q{or}, q{named}, q{charRange}, q{defined}]); + + alias rule = or!(literal!("abc"), charRange!('0','9')); + alias myRule = defined!(rule, "myRule"); assert(getName!(rule)() == `or!(literal!("abc"), charRange!('0','9'))`); assert(getName!(myRule)() == "myRule"); @@ -2982,7 +2957,6 @@ unittest // 'defined' unit test assert(myResult.begin == result.begin); assert(myResult.end == result.end); assert(myResult.children[0] == result); - } } /** @@ -3010,12 +2984,13 @@ template actionT(ParseTree, alias r, alias act) unittest // 'action' unit test { + mixin DefaultPatters!(ParseTree, [q{literal}, q{action}]); + ParseTree foo(ParseTree p) { p.matches ~= p.matches; // doubling matches return p; } - with(PEG) { alias literal!("abc") abc; alias action!(abc, foo) abcfoo; @@ -3042,7 +3017,6 @@ unittest // 'action' unit test assert(result.begin == reference.begin); assert(result.end == reference.end); assert(result.children == reference.children); - } } /** @@ -3077,10 +3051,11 @@ template fuseT(ParseTree, alias r) unittest // 'fuse' unit test { - with(PEG) { - alias oneOrMore!(literal!("abc")) abcs; + mixin DefaultPatters!(ParseTree, [q{literal}, q{oneOrMore}, q{fuse}, q{discard}]); + + alias abcs = oneOrMore!(literal!("abc")); - alias fuse!(abcs) f; + alias f = fuse!(abcs); assert(getName!(f) == `fuse!(oneOrMore!(literal!("abc")))`); @@ -3106,8 +3081,8 @@ unittest // 'fuse' unit test assert(result.end == reference.end); assert(result.children == reference.children); - alias discard!(literal!("abc")) dabc; - alias fuse!(dabc) f2; + alias dabc = discard!(literal!("abc")); + alias f2 = fuse!(dabc); result = f2("abcabc"); reference = dabc("abcabc"); @@ -3117,7 +3092,6 @@ unittest // 'fuse' unit test assert(result.begin == reference.begin); assert(result.end == reference.end); assert(result.children == reference.children); - } } /** @@ -3200,11 +3174,12 @@ template discardT(ParseTree, alias r) unittest // 'discard' unit test { - with(PEG) { - alias literal!"abc" abc; - alias oneOrMore!abc abcs; - alias discard!(literal!("abc")) dabc; - alias discard!(oneOrMore!(literal!("abc")))dabcs; + mixin DefaultPatters!(ParseTree, [q{literal}, q{oneOrMore}, q{discard}, q{and}]); + + alias abc = literal!"abc"; + alias abcs = oneOrMore!abc; + alias dabc = discard!(literal!("abc")); + alias dabcs = discard!(oneOrMore!(literal!("abc"))); ParseTree reference = abc("abc"); ParseTree result =dabc("abc"); @@ -3241,7 +3216,7 @@ unittest // 'discard' unit test assert(result.children is null); // Action on 'and' - alias and!(abc,dabc,abc) discardMiddle; + alias discardMiddle = and!(abc,dabc,abc) discardMiddle; result = discardMiddle("abcabcabc"); assert(result.successful); @@ -3250,7 +3225,6 @@ unittest // 'discard' unit test assert(result.end == 3*3); assert(result.children.length == 2); assert(result.children == [abc("abcabcabc"), abc(abc(abc("abcabcabc")))]); - } } /** @@ -3282,11 +3256,12 @@ template dropT(ParseTree, alias r) unittest // 'drop' unit test { - with(PEG) { - alias literal!"abc" abc; - alias oneOrMore!abc abcs; - alias drop!(literal!("abc")) dabc; - alias drop!(oneOrMore!(literal!("abc"))) dabcs; + mixin DefaultPatters!(ParseTree, [q{literal}, q{charRange}, q{drop}, q{oneOrMore}, q{and}]); + + alias abc = literal!"abc"; + alias abcs = oneOrMore!abc; + alias dabc = drop!(literal!("abc")); + alias dabcs = drop!(oneOrMore!(literal!("abc"))); ParseTree reference = abc("abc"); ParseTree result =dabc("abc"); @@ -3332,7 +3307,6 @@ unittest // 'drop' unit test assert(result.end == 3*3); assert(result.children.length == 2, "but only 2 children."); assert(result.children == [abc("abcabcabc"), abc(abc(abc("abcabcabc")))]); - } } /** @@ -3391,7 +3365,7 @@ template keepT(ParseTree, alias r) unittest // 'keep' unit test { - with(PEG) { + mixin DefaultPatters!(ParseTree, [q{literal}, q{and}, q{named}, q{keep}]); // Grammar mimicry static struct KeepTest { @@ -3430,7 +3404,6 @@ unittest // 'keep' unit test assert(reference.children.length == 0); assert(result.children.length == 1); assert(result.children == [literal!("b")(literal!("a")("abc"))], "'b' node was kept."); - } } template AddSpaceT(ParseTree, alias sp) @@ -3485,13 +3458,14 @@ template AddSpaceT(ParseTree, alias sp) unittest // 'spaceAnd' unit test { - with(PEG) { + mixin DefaultPatters!(ParseTree, [q{literal}, q{and}, q{oneOrMore}, q{spaceAnd}, q{blank}, q{digit}]); + alias a = literal!"a"; alias b = literal!"b"; //Basic use alias ab = and!(a,b); - alias a_b = spaceAnd!(PEG.oneOrMore!(PEG.blank), a, b); + alias a_b = spaceAnd!(oneOrMore!(blank), a, b); ParseTree reference = ab("ab"); ParseTree result = a_b("ab"); @@ -3538,7 +3512,6 @@ unittest // 'spaceAnd' unit test assert(result.begin == 0); assert(result.end == "012a34b567".length); assert(result.children.length == 2); - } } /// Mixin to simplify a parse tree inside a grammar @@ -3659,7 +3632,18 @@ ParseTree modify(ParseTree, alias predicate, alias modifier)(ParseTree input) if return input; } -mixin template ParseCollections(ParseTree) { +// mixin template ParseCollections(alias ParseTreeT=void) { +// static if (is(ParseTreeT == void)) { +// alias ParseTree = typeof(this); +// } +// else { +// alias ParseTree = ParseTreeT; +// } +// mixin ParseCollectionsM; +// } + +mixin template ParseCollectionsM() { +// static assert(isParseTree!ParseTree, "ParseTreeT must be a isParseTree type"); @safe: import pegged.peg; alias eoi = eoiT!ParseTree; @@ -3736,9 +3720,50 @@ mixin template ParseCollections(ParseTree) { alias list0(alias elem, alias sep) = named!(spaceAnd!(oneOrMore!blank, option!(and!(elem, zeroOrMore!(spaceAnd!(discardMatches!(sep), elem))))), "list0"); alias spaceAnd(alias sp, rules...) = and!(discard!(zeroOrMore!sp), staticMap!(AddSpace!(zeroOrMore!sp), rules)); +} - static bool isParseCollectionDefined(ParseTree dummy) pure nothrow { - return true; - } +enum defaultNames =[ + "eol", + "eoi", + "blank", + "quote", + "doublequote", + "backquote", + "alpha", + "Alpha", + "spacing", + "identifier", + "ident", + "backslash", + "hexDigit", + "endOfLine", + "qualifiedIdentifier", + "literal", + "posLookahead", + "negLookahead", + "option", + "defined", + "eps", + "literal", + "zeroOrMore", + "oneOrMore", + "literal", + "list", + "and", + "or", + "fail", + "digits", + "charRange", + "longest_match", + ]; +/** + Change the namespace of the grammar pattern in the ParseTree to scope if the mixin. + names is the list of the pattern-names inside the ParseTree + */ +mixin template DefaultPatters(ParseTree, string[] names = defaultNames) { + private import std.format; + static foreach(name; names) { + mixin(format!q{alias %1$s = ParseTree.%1$s;}(name)); + } } diff --git a/pegged/tester/testerparser.d b/pegged/tester/testerparser.d index ef96a8d..87c6135 100644 --- a/pegged/tester/testerparser.d +++ b/pegged/tester/testerparser.d @@ -42,10 +42,8 @@ public import pegged.peg; private import pegged.parsetree; struct GenericTesterGrammar(ParseTree) { - static if (is(ParseTree == DefaultParseTree)) { - import PEG=pegged.parsetree; - } - + alias PEG=ParseTree; + mixin DefaultPatters!ParseTree; //alias PEG=PeggedT!ParseTree; // mixin DefaultParsePatterns!PEG; From 358153e65f77cc2293673d4f985d000284fc5a32 Mon Sep 17 00:00:00 2001 From: cbleser Date: Thu, 3 Jun 2021 16:21:11 +0300 Subject: [PATCH 21/29] WIP: Problems in dynamic grammar concerning use of costume ParseTree --- pegged/dynamic/grammar.d | 20 ++++++-------------- pegged/grammar.d | 2 +- pegged/parser.d | 25 +++++++++++++------------ pegged/peg.d | 2 +- 4 files changed, 21 insertions(+), 28 deletions(-) diff --git a/pegged/dynamic/grammar.d b/pegged/dynamic/grammar.d index 74ee6f2..46008e2 100644 --- a/pegged/dynamic/grammar.d +++ b/pegged/dynamic/grammar.d @@ -15,11 +15,10 @@ import std.algorithm : startsWith; import std.array; import std.stdio; -import pegged.peg; import pegged.parser; import pegged.dynamic.peg; -private import pegged.parsetree : DefaultParseTree, isParseTree; +private import pegged.parsetree : isParseTree; struct ParameterizedRule(ParseTree) { @@ -73,17 +72,6 @@ struct ParameterizedRule(ParseTree) } } -// ParameterizedRule!ParseTree parameterizedRule(ParseTree)(size_t n, Dynamic delegate(Dynamic[] d) code) -// { -// return ParameterizedRule(n, code); -// // ParameterizedRule pr; -// // pr.numArgs = n; -// // pr.code = code; -// // return pr; -// } - -//private alias ParseTree=DefaultParseTree; - struct DynamicGrammar(ParseTree) { string grammarName; @@ -91,7 +79,6 @@ struct DynamicGrammar(ParseTree) alias Dynamic = ParseTree.Dynamic; Dynamic[string] rules; ParameterizedRule!ParseTree[string] paramRules; -// private alias ParseTree=DefaultParseTree; ParseTree decimateTree(ParseTree p) { @@ -174,6 +161,7 @@ ParseTree spaceArrow(ParseTree)(ParseTree input) if (isParseTree!ParseTree) result.children = spacer ~ result.children ~ spacer; return result; } + import pegged.peg : modify; return modify!(ParseTree, p => p.name == "Pegged.Primary", wrapInSpaces)(input); } @@ -413,6 +401,7 @@ DynamicGrammar!ParseTree grammar(ParseTree)(string definition, ParseTree.Dynamic throw new Exception("Bad grammar input: " ~ defAsParseTree.toString("")); } + pragma(msg, "ParseTree ", ParseTree); DynamicGrammar!ParseTree gram; foreach(name, rule; context) { @@ -426,6 +415,9 @@ DynamicGrammar!ParseTree grammar(ParseTree)(string definition, ParseTree.Dynamic gram.grammarName = shortGrammarName; // Predefined spacing + pragma(msg, `ParseTree.Dynamic `, ParseTree.Dynamic); + pragma(msg, `gram.rules["Spacing"] `, typeof(gram.rules["Spacing"])); + pragma(msg, `discard(zeroOrMore(or(literal(" "), literal("\t"), literal("\n"), literal("\r"))))`, typeof(discard(zeroOrMore(or(literal(" "), literal("\t"), literal("\n"), literal("\r")))))); gram.rules["Spacing"] = discard(zeroOrMore(or(literal(" "), literal("\t"), literal("\n"), literal("\r")))); ParseTree[] definitions = p.children[1 .. $]; diff --git a/pegged/grammar.d b/pegged/grammar.d index 1fecf1a..7edb69c 100644 --- a/pegged/grammar.d +++ b/pegged/grammar.d @@ -219,7 +219,7 @@ string grammar(ParseTree, Memoization withMemo = Memoization.yes)(ParseTree defA //string invokedGrammarName = generateCode(transformName(p.children[0])); string firstRuleName = generateCode(p.children[1].children[0]); - if (optGrammar.parsetreeName ==DefaultParseTree.stringof) { + if (optGrammar.parsetreeName == DefaultParseTree.stringof) { result = "import pegged.parsetree : DefaultParseTree;\n"; } result ~= diff --git a/pegged/parser.d b/pegged/parser.d index 20973a5..a2fdc01 100644 --- a/pegged/parser.d +++ b/pegged/parser.d @@ -133,13 +133,14 @@ NestedList(L,R) <- ^L ( !(L/R) . )* (NestedList(L,R) / ( !(L/R) . )*)* ( !(L/R) +/ module pegged.parser; -public import pegged.peg; +//public import pegged.peg; import std.algorithm: startsWith; import std.functional: toDelegate; private import pegged.parsetree; struct GenericPegged(ParseTree) { + import pegged.peg : DefaultPatters, decimateTree, GetName; alias PEG=ParseTree; mixin DefaultPatters!ParseTree; // static if (is(ParseTree == DefaultParseTree)) { @@ -149,7 +150,7 @@ struct GenericPegged(ParseTree) // mixin DefaultParsePatterns!PEG; import std.functional : toDelegate; import pegged.dynamic.grammar; - //static import pegged.peg; + private import peg = pegged.peg; struct Pegged { enum name = "Pegged"; @@ -2043,26 +2044,26 @@ struct GenericPegged(ParseTree) { if(__ctfe) { - return PEG.defined!(PEG.and!(PEG.keep!(L), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)), PEG.zeroOrMore!(PEG.or!(Items, NestedList!(L, Items, R), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)))), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)), PEG.keep!(R)), "Pegged.NestedList!(" ~ pegged.peg.getName!(L)() ~ ", " ~ pegged.peg.getName!(Items)() ~ ", " ~ pegged.peg.getName!(R) ~ ")")(p); + return PEG.defined!(PEG.and!(PEG.keep!(L), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)), PEG.zeroOrMore!(PEG.or!(Items, NestedList!(L, Items, R), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)))), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)), PEG.keep!(R)), "Pegged.NestedList!(" ~ peg.getName!(L)() ~ ", " ~ peg.getName!(Items)() ~ ", " ~ peg.getName!(R) ~ ")")(p); } else { - return hooked!(PEG.defined!(PEG.and!(PEG.keep!(L), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)), PEG.zeroOrMore!(PEG.or!(Items, NestedList!(L, Items, R), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)))), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)), PEG.keep!(R)), "Pegged.NestedList!(" ~ pegged.peg.getName!(L)() ~ ", " ~ pegged.peg.getName!(Items)() ~ ", " ~ pegged.peg.getName!(R) ~ ")"), "NestedList_3")(p); + return hooked!(PEG.defined!(PEG.and!(PEG.keep!(L), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)), PEG.zeroOrMore!(PEG.or!(Items, NestedList!(L, Items, R), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)))), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)), PEG.keep!(R)), "Pegged.NestedList!(" ~ peg.getName!(L)() ~ ", " ~ peg.getName!(Items)() ~ ", " ~ peg.getName!(R) ~ ")"), "NestedList_3")(p); } } static ParseTree NestedList(string s) { if(__ctfe) - return PEG.defined!(PEG.and!(PEG.keep!(L), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)), PEG.zeroOrMore!(PEG.or!(Items, NestedList!(L, Items, R), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)))), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)), PEG.keep!(R)), "Pegged.NestedList!(" ~ pegged.peg.getName!(L)() ~ ", " ~ pegged.peg.getName!(Items)() ~ ", " ~ pegged.peg.getName!(R) ~ ")")(ParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(PEG.keep!(L), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)), PEG.zeroOrMore!(PEG.or!(Items, NestedList!(L, Items, R), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)))), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)), PEG.keep!(R)), "Pegged.NestedList!(" ~ peg.getName!(L)() ~ ", " ~ peg.getName!(Items)() ~ ", " ~ peg.getName!(R) ~ ")")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(PEG.defined!(PEG.and!(PEG.keep!(L), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)), PEG.zeroOrMore!(PEG.or!(Items, NestedList!(L, Items, R), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)))), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)), PEG.keep!(R)), "Pegged.NestedList!(" ~ pegged.peg.getName!(L)() ~ ", " ~ pegged.peg.getName!(Items)() ~ ", " ~ pegged.peg.getName!(R) ~ ")"), "NestedList_3")(ParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(PEG.keep!(L), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)), PEG.zeroOrMore!(PEG.or!(Items, NestedList!(L, Items, R), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)))), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)), PEG.keep!(R)), "Pegged.NestedList!(" ~ peg.getName!(L)() ~ ", " ~ peg.getName!(Items)() ~ ", " ~ peg.getName!(R) ~ ")"), "NestedList_3")(ParseTree("", false,[], s)); } } static string NestedList(GetName g) { - return "Pegged.NestedList!(" ~ pegged.peg.getName!(L)() ~ ", " ~ pegged.peg.getName!(Items)() ~ ", " ~ pegged.peg.getName!(R) ~ ")"; + return "Pegged.NestedList!(" ~ peg.getName!(L)() ~ ", " ~ peg.getName!(Items)() ~ ", " ~ peg.getName!(R) ~ ")"; } } @@ -2072,26 +2073,26 @@ struct GenericPegged(ParseTree) { if(__ctfe) { - return PEG.defined!(PEG.and!(PEG.keep!(L), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)), PEG.zeroOrMore!(PEG.or!(NestedList!(L, R), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)))), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)), PEG.keep!(R)), "Pegged.NestedList!(" ~ pegged.peg.getName!(L)() ~ ", " ~ pegged.peg.getName!(R) ~ ")")(p); + return PEG.defined!(PEG.and!(PEG.keep!(L), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)), PEG.zeroOrMore!(PEG.or!(NestedList!(L, R), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)))), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)), PEG.keep!(R)), "Pegged.NestedList!(" ~ peg.getName!(L)() ~ ", " ~ peg.getName!(R) ~ ")")(p); } else { - return hooked!(PEG.defined!(PEG.and!(PEG.keep!(L), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)), PEG.zeroOrMore!(PEG.or!(NestedList!(L, R), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)))), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)), PEG.keep!(R)), "Pegged.NestedList!(" ~ pegged.peg.getName!(L)() ~ ", " ~ pegged.peg.getName!(R) ~ ")"), "NestedList_2")(p); + return hooked!(PEG.defined!(PEG.and!(PEG.keep!(L), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)), PEG.zeroOrMore!(PEG.or!(NestedList!(L, R), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)))), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)), PEG.keep!(R)), "Pegged.NestedList!(" ~ peg.getName!(L)() ~ ", " ~ peg.getName!(R) ~ ")"), "NestedList_2")(p); } } static ParseTree NestedList(string s) { if(__ctfe) - return PEG.defined!(PEG.and!(PEG.keep!(L), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)), PEG.zeroOrMore!(PEG.or!(NestedList!(L, R), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)))), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)), PEG.keep!(R)), "Pegged.NestedList!(" ~ pegged.peg.getName!(L)() ~ ", " ~ pegged.peg.getName!(R) ~ ")")(ParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(PEG.keep!(L), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)), PEG.zeroOrMore!(PEG.or!(NestedList!(L, R), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)))), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)), PEG.keep!(R)), "Pegged.NestedList!(" ~ peg.getName!(L)() ~ ", " ~ peg.getName!(R) ~ ")")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(PEG.defined!(PEG.and!(PEG.keep!(L), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)), PEG.zeroOrMore!(PEG.or!(NestedList!(L, R), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)))), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)), PEG.keep!(R)), "Pegged.NestedList!(" ~ pegged.peg.getName!(L)() ~ ", " ~ pegged.peg.getName!(R) ~ ")"), "NestedList_2")(ParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(PEG.keep!(L), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)), PEG.zeroOrMore!(PEG.or!(NestedList!(L, R), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)))), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)), PEG.keep!(R)), "Pegged.NestedList!(" ~ peg.getName!(L)() ~ ", " ~ peg.getName!(R) ~ ")"), "NestedList_2")(ParseTree("", false,[], s)); } } static string NestedList(GetName g) { - return "Pegged.NestedList!(" ~ pegged.peg.getName!(L)() ~ ", " ~ pegged.peg.getName!(R) ~ ")"; + return "Pegged.NestedList!(" ~ peg.getName!(L)() ~ ", " ~ peg.getName!(R) ~ ")"; } } diff --git a/pegged/peg.d b/pegged/peg.d index 0d66d22..61e05ba 100644 --- a/pegged/peg.d +++ b/pegged/peg.d @@ -27,7 +27,7 @@ import std.typetuple; import pegged.parsetree : isParseTree; // Returns quoted and escaped version of the input, but if the input is null, then return `"end of input"`. -package string stringified(string inp) @safe +string stringified(string inp) @safe { import std.format : format; From 9576258eecbb3f2d527ba5748adf5ad7968aad34 Mon Sep 17 00:00:00 2001 From: cbleser Date: Wed, 9 Jun 2021 18:12:03 +0300 Subject: [PATCH 22/29] WIP: dynamic.peg is now moved into a static struct --- dub.json | 1 + pegged/defaultparsetree.d | 32 ++ pegged/dynamic/grammar.d | 93 +++-- pegged/dynamic/peg.d | 766 ++++++++++++++++++----------------- pegged/grammar.d | 14 +- pegged/parser.d | 2 +- pegged/parsetree.d | 34 +- pegged/peg.d | 2 +- pegged/tester/testerparser.d | 1 + 9 files changed, 497 insertions(+), 448 deletions(-) create mode 100644 pegged/defaultparsetree.d diff --git a/dub.json b/dub.json index cffeee7..412260f 100644 --- a/dub.json +++ b/dub.json @@ -9,6 +9,7 @@ "pegged/grammar.d", "pegged/parser.d", "pegged/parsetree.d", + "pegged/defaultparsetree.d", "pegged/introspection.d", "pegged/tohtml.d", "pegged/dynamic/grammar.d", diff --git a/pegged/defaultparsetree.d b/pegged/defaultparsetree.d new file mode 100644 index 0000000..88931a5 --- /dev/null +++ b/pegged/defaultparsetree.d @@ -0,0 +1,32 @@ +/** + This module contaits functions and parameter for ParseTree data element + */ +module pegged.defaultparsetree; + +import std.traits : isType, ReturnType, ForeachType, isCallable, Unqual; + +private import pegged.peg : ParseCollectionsM; +private import pegged.dynamic.peg : DynamicPeg; +import pegged.parsetree : isParseTree, ParseTreeM; +/** + The basic parse tree, as used throughout the project. + You can define your own parse tree node, but respect the basic layout. + Example: + struct MyParseTree { + mixin ParseTreeM; + ... My own stuff + } +*/ + +struct DefaultParseTree { + mixin ParseTreeM; + mixin ParseCollectionsM; + alias DPEG=DynamicPeg!(ParseTree); +// mixin DynamicParseCollectionsM; + +} + +//mixin DynmicParseCollectionM!(ParseTree); + + +static assert(isParseTree!DefaultParseTree); diff --git a/pegged/dynamic/grammar.d b/pegged/dynamic/grammar.d index 46008e2..f66f42d 100644 --- a/pegged/dynamic/grammar.d +++ b/pegged/dynamic/grammar.d @@ -74,6 +74,7 @@ struct ParameterizedRule(ParseTree) struct DynamicGrammar(ParseTree) { + alias DPEG=ParseTree.DPEG; string grammarName; string startingRule; alias Dynamic = ParseTree.Dynamic; @@ -133,7 +134,7 @@ struct DynamicGrammar(ParseTree) void opIndexAssign(D)(D code, string s) { - rules[s]= named(code, grammarName ~ "." ~ s); + rules[s]= DPEG.named(code, grammarName ~ "." ~ s); } Dynamic opIndex(string s) @@ -176,6 +177,7 @@ ParseTree.Dynamic makeRule(ParseTree)(string def, Dynamic[string] context) if(is ParseTree.Dynamic makeRule(ParseTree)(ParseTree def, ParseTree.Dynamic[string] context) if (isParseTree!ParseTree) { + alias DPEG=ParseTree.DPEG; ParseTree.Dynamic code; ParseTree.Dynamic getDyn(string name) @@ -195,10 +197,10 @@ ParseTree.Dynamic makeRule(ParseTree)(ParseTree def, ParseTree.Dynamic[string] c case "Pegged.Expression": //if (p.children.length > 1) // OR expression //{ - Dynamic[] children; + ParseTree.Dynamic[] children; foreach(seq; p.children) children ~= ruleFromTree(seq); - return distribute!(ParseTree, or)(children); + return distribute!(ParseTree, DPEG.or)(children); //} //else // One child -> just a sequence, no need for a or!( , ) //{ @@ -208,10 +210,10 @@ ParseTree.Dynamic makeRule(ParseTree)(ParseTree def, ParseTree.Dynamic[string] c case "Pegged.Sequence": //if (p.children.length > 1) // real sequence //{ - Dynamic[] children; + ParseTree.Dynamic[] children; foreach(seq; p.children) children ~= ruleFromTree(seq); - return distribute!(ParseTree, and)(children); + return distribute!(ParseTree, DPEG.and)(children); /+} else // One child -> just a Suffix, no need for a and!( , ) { @@ -245,16 +247,16 @@ ParseTree.Dynamic makeRule(ParseTree)(ParseTree def, ParseTree.Dynamic[string] c case "Pegged.Literal": //writeln("Literal: ", p.matches); if(p.matches.length == 3) // standard case - return literal(p.matches[1]); + return DPEG.literal(p.matches[1]); else // only two children -> empty literal - return eps(); + return DPEG.eps(); case "Pegged.CharClass": if (p.children.length > 1) { - Dynamic[] children; + ParseTree.Dynamic[] children; foreach(seq; p.children) children ~= ruleFromTree(seq); - return distribute!(ParseTree, or)(children); + return distribute!(ParseTree, DPEG.or)(children); } else // One child -> just a sequence, no need for a or!( , ) { @@ -265,7 +267,7 @@ ParseTree.Dynamic makeRule(ParseTree)(ParseTree def, ParseTree.Dynamic[string] c /// Make the generation at the Char level: directly what is needed, be it `` or "" or whatever if (p.children.length > 1) // a-b range { - return charRange(p.matches[0].front, p.matches[2].front); + return DPEG.charRange(p.matches[0].front, p.matches[2].front); } else // lone char { @@ -276,23 +278,23 @@ ParseTree.Dynamic makeRule(ParseTree)(ParseTree def, ParseTree.Dynamic[string] c case "\\[": case "\\]": case "\\-": - return literal(ch[0..1]); + return DPEG.literal(ch[0..1]); case "\\\'": - return literal("\'"); + return DPEG.literal("\'"); case "\\`": - return literal("`"); + return DPEG.literal("`"); case "\\": case "\\\\": - return literal("\\"); + return DPEG.literal("\\"); case "\"": case "\\\"": - return literal("\""); + return DPEG.literal("\""); case "\n": case "\r": case "\t": - return literal(ch); + return DPEG.literal(ch); default: - return literal(ch); + return DPEG.literal(ch); } } case "Pegged.Char": @@ -307,44 +309,44 @@ ParseTree.Dynamic makeRule(ParseTree)(ParseTree def, ParseTree.Dynamic[string] c case "\\\"": case "\\`": case "\\\\": - return literal(ch[1..$]); + return DPEG.literal(ch[1..$]); case "\n": case "\r": case "\t": - return literal(ch); + return DPEG.literal(ch); default: - return literal(ch); + return DPEG.literal(ch); } //break; case "Pegged.POS": - return posLookahead(ruleFromTree(p.children[0])); + return DPEG.posLookahead(ruleFromTree(p.children[0])); case "Pegged.NEG": - return negLookahead(ruleFromTree(p.children[0])); + return DPEG.negLookahead(ruleFromTree(p.children[0])); case "Pegged.FUSE": - return fuse(ruleFromTree(p.children[0])); + return DPEG.fuse(ruleFromTree(p.children[0])); case "Pegged.DISCARD": - return discard(ruleFromTree(p.children[0])); + return DPEG.discard(ruleFromTree(p.children[0])); case "Pegged.KEEP": - return keep(ruleFromTree(p.children[0])); + return DPEG.keep(ruleFromTree(p.children[0])); case "Pegged.DROP": - return drop(ruleFromTree(p.children[0])); + return DPEG.drop(ruleFromTree(p.children[0])); case "Pegged.PROPAGATE": - return propagate(ruleFromTree(p.children[0])); + return DPEG.propagate(ruleFromTree(p.children[0])); case "Pegged.OPTION": - return option(ruleFromTree(p.children[0])); + return DPEG.option(ruleFromTree(p.children[0])); case "Pegged.ZEROORMORE": - return zeroOrMore(ruleFromTree(p.children[0])); + return DPEG.zeroOrMore(ruleFromTree(p.children[0])); case "Pegged.ONEORMORE": - return oneOrMore(ruleFromTree(p.children[0])); + return DPEG.oneOrMore(ruleFromTree(p.children[0])); case "Pegged.Action": - Dynamic result = ruleFromTree(p.children[0]); + ParseTree.Dynamic result = ruleFromTree(p.children[0]); foreach(act; p.matches[1..$]) - result = action(result, getDyn(act)); + result = DPEG.action(result, getDyn(act)); return result; case "Pegged.ANY": - return any(); + return DPEG.any(); case "Pegged.WrapAround": - return wrapAround( ruleFromTree(p.children[0]) + return DPEG.wrapAround( ruleFromTree(p.children[0]) , ruleFromTree(p.children[1]) , ruleFromTree(p.children[2])); default: @@ -358,28 +360,28 @@ ParseTree.Dynamic makeRule(ParseTree)(ParseTree def, ParseTree.Dynamic[string] c code = ruleFromTree(def.children[2]); break; case "Pegged.FUSEARROW": - code = fuse(ruleFromTree(def.children[2])); + code = DPEG.fuse(ruleFromTree(def.children[2])); break; case "Pegged.DISCARDARROW": - code = discard(ruleFromTree(def.children[2])); + code = DPEG.discard(ruleFromTree(def.children[2])); break; case "Pegged.KEEPARROW": - code = keep(ruleFromTree(def.children[2])); + code = DPEG.keep(ruleFromTree(def.children[2])); break; case "Pegged.DROPARROW": - code = drop(ruleFromTree(def.children[2])); + code = DPEG.drop(ruleFromTree(def.children[2])); break; case "Pegged.PROPAGATEARROW": - code = propagate(ruleFromTree(def.children[2])); + code = DPEG.propagate(ruleFromTree(def.children[2])); break; case "Pegged.SPACEARROW": ParseTree modified = spaceArrow(def.children[2]); code = ruleFromTree(modified); break; case "Pegged.ACTIONARROW": - Dynamic actionResult = ruleFromTree(def.children[2]); + ParseTree.Dynamic actionResult = ruleFromTree(def.children[2]); foreach(act; def.children[1].matches[1..$]) - actionResult = action(actionResult, getDyn(act)); + actionResult = DPEG.action(actionResult, getDyn(act)); code = actionResult; break; default: @@ -387,11 +389,12 @@ ParseTree.Dynamic makeRule(ParseTree)(ParseTree def, ParseTree.Dynamic[string] c //break; } - return named(code, def.matches[0]); + return DPEG.named(code, def.matches[0]); } DynamicGrammar!ParseTree grammar(ParseTree)(string definition, ParseTree.Dynamic[string] context = null) if(isParseTree!ParseTree) { + alias DPEG=ParseTree.DPEG; //writeln("Entering dyn gram"); ParseTree defAsParseTree = GenericPegged!(ParseTree).Pegged(definition); //writeln(defAsParseTree); @@ -417,14 +420,14 @@ DynamicGrammar!ParseTree grammar(ParseTree)(string definition, ParseTree.Dynamic // Predefined spacing pragma(msg, `ParseTree.Dynamic `, ParseTree.Dynamic); pragma(msg, `gram.rules["Spacing"] `, typeof(gram.rules["Spacing"])); - pragma(msg, `discard(zeroOrMore(or(literal(" "), literal("\t"), literal("\n"), literal("\r"))))`, typeof(discard(zeroOrMore(or(literal(" "), literal("\t"), literal("\n"), literal("\r")))))); - gram.rules["Spacing"] = discard(zeroOrMore(or(literal(" "), literal("\t"), literal("\n"), literal("\r")))); +// pragma(msg, `discard(zeroOrMore(or(literal(" "), literal("\t"), literal("\n"), literal("\r"))))`, typeof(discard(zeroOrMore(or(literal(" "), literal("\t"), literal("\n"), literal("\r")))))); + gram.rules["Spacing"] = DPEG.discard(DPEG.zeroOrMore(DPEG.or(DPEG.literal(" "), DPEG.literal("\t"), DPEG.literal("\n"), DPEG.literal("\r")))); ParseTree[] definitions = p.children[1 .. $]; foreach(i,def; definitions) { - gram[def.matches[0]] = fail(); + gram[def.matches[0]] = DPEG.fail(); } foreach(i,def; definitions) diff --git a/pegged/dynamic/peg.d b/pegged/dynamic/peg.d index 159c813..3d9604b 100644 --- a/pegged/dynamic/peg.d +++ b/pegged/dynamic/peg.d @@ -9,448 +9,452 @@ import std.stdio; import pegged.peg; -private import pegged.parsetree : DefaultParseTree; -private alias ParseTree=DefaultParseTree; -alias ParseTree delegate(ParseTree) Dynamic; +private import pegged.parsetree : isParseTree; +// private alias ParseTree=DefaultParseTree; +// alias ParseTree delegate(ParseTree) Dynamic; -string getName(D)(D rule) -{ - return callDynamic(rule, ParseTree()).name; -} +struct DynamicPeg(ParseTree) { + static { + static string getName(D)(D rule) + { + return callDynamic(rule, ParseTree()).name; + } -ParseTree callDynamic(D)(D d, string s) -{ - static if (is(typeof(d) : ParseTree delegate(ParseTree)) || is(typeof(d) : ParseTree function(ParseTree))) - return d(ParseTree("",false,[], s)); - else static if (is(typeof(d) : ParseTree delegate(ParseTree) delegate()) || is(typeof(d) : ParseTree function(ParseTree) delegate())) - return d()(ParseTree("",false,[], s)); - else static if (is(typeof(d) : ParseTree delegate(string)) || is(typeof(d) : ParseTree function(string))) - return d(s); - else static if (is(typeof(d) : ParseTree delegate(string) delegate()) || is(typeof(d) : ParseTree function(string) delegate())) - return d()(s); - else - static assert(false, "Bad callDynamic, with type " ~ D.stringof); -} + ParseTree callDynamic(D)(D d, string s) + { + static if (is(typeof(d) : ParseTree delegate(ParseTree)) || is(typeof(d) : ParseTree function(ParseTree))) + return d(ParseTree("",false,[], s)); + else static if (is(typeof(d) : ParseTree delegate(ParseTree) delegate()) || is(typeof(d) : ParseTree function(ParseTree) delegate())) + return d()(ParseTree("",false,[], s)); + else static if (is(typeof(d) : ParseTree delegate(string)) || is(typeof(d) : ParseTree function(string))) + return d(s); + else static if (is(typeof(d) : ParseTree delegate(string) delegate()) || is(typeof(d) : ParseTree function(string) delegate())) + return d()(s); + else + assert(false, "Bad callDynamic, with type " ~ D.stringof); + } -ParseTree callDynamic(D)(D d, ParseTree p) -{ - static if (is(typeof(d) : ParseTree delegate(ParseTree)) || is(typeof(d) : ParseTree function(ParseTree))) - return d(p); - else static if (is(typeof(d) : ParseTree delegate(ParseTree) delegate()) || is(typeof(d) : ParseTree function(ParseTree) 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..$]); - else static if (is(typeof(d) : ParseTree delegate(string) delegate()) || is(typeof(d) : ParseTree function(string) delegate())) - return d()(p.input[p.end..$]); - else - static assert(false, "Bad callDynamic, with type " ~ D.stringof); -} + ParseTree callDynamic(D)(D d, ParseTree p) + { + static if (is(typeof(d) : ParseTree delegate(ParseTree)) || is(typeof(d) : ParseTree function(ParseTree))) + return d(p); + else static if (is(typeof(d) : ParseTree delegate(ParseTree) delegate()) || is(typeof(d) : ParseTree function(ParseTree) 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..$]); + else static if (is(typeof(d) : ParseTree delegate(string) delegate()) || is(typeof(d) : ParseTree function(string) delegate())) + return d()(p.input[p.end..$]); + else + static assert(false, "Bad callDynamic, with type " ~ D.stringof); + } -Dynamic fail() -{ - return (ParseTree p) - { - return ParseTree("fail", false, ["fail"], p.input, p.end, p.end); - }; -} + ParseTree.Dynamic fail() + { + return (ParseTree p) + { + return ParseTree("fail", false, ["fail"], p.input, p.end, p.end); + }; + } -Dynamic eoi() -{ - return (ParseTree p) - { - if (p.end == p.input.length) - return ParseTree("eoi", true, [], p.input, p.end, p.end); - else - return ParseTree("eoi", false, ["end of input"], p.input, p.end, p.end); - }; -} + ParseTree.Dynamic eoi() + { + return (ParseTree p) + { + if (p.end == p.input.length) + return ParseTree("eoi", true, [], p.input, p.end, p.end); + else + return ParseTree("eoi", false, ["end of input"], p.input, p.end, p.end); + }; + } -Dynamic eps() -{ - return (ParseTree p) - { - return ParseTree("eps", true, [""], p.input, p.end, p.end); - }; -} + ParseTree.Dynamic eps() + { + return (ParseTree p) + { + return ParseTree("eps", true, [""], p.input, p.end, p.end); + }; + } -Dynamic any() -{ - return(ParseTree p) - { - if (p.end < p.input.length) - return ParseTree("any", true, [p.input[p.end..p.end+1]], p.input, p.end, p.end+1); - else - return ParseTree("any", false, ["any char"], p.input, p.end, p.end); - }; -} + ParseTree.Dynamic any() + { + return(ParseTree p) + { + if (p.end < p.input.length) + return ParseTree("any", true, [p.input[p.end..p.end+1]], p.input, p.end, p.end+1); + else + return ParseTree("any", false, ["any char"], p.input, p.end, p.end); + }; + } -Dynamic literal(string s) -{ - return (ParseTree p) - { - if (p.end+s.length <= p.input.length && p.input[p.end..p.end+s.length] == s) - return ParseTree("literal!(\"" ~ s ~ "\")", true, [s], p.input, p.end, p.end+s.length); - else - return ParseTree("literal!(\"" ~ s ~ "\")", false, [`"` ~ s ~ `"`], p.input, p.end, p.end); + ParseTree.Dynamic literal(string s) + { + return (ParseTree p) + { + if (p.end+s.length <= p.input.length && p.input[p.end..p.end+s.length] == s) + return ParseTree("literal!(\"" ~ s ~ "\")", true, [s], p.input, p.end, p.end+s.length); + else + return ParseTree("literal!(\"" ~ s ~ "\")", false, [`"` ~ s ~ `"`], p.input, p.end, p.end); - }; -} + }; + } -Dynamic charRange(dchar begin, dchar end) -{ - return (ParseTree p) - { - string longName = "a char between '"~to!string(begin)~"' and '"~to!string(end)~"'"; - if (p.end < p.input.length && p.input[p.end] >= begin && p.input[p.end] <= end) - return ParseTree("charRange!(" ~ to!string(begin) ~ ", " ~ to!string(end) ~ ")", true, [p.input[p.end..p.end+1]], p.input, p.end, p.end+1); - else - return ParseTree("charRange!(" ~ to!string(begin) ~ ", " ~ to!string(end) ~ ")", false, [longName], p.input, p.end, p.end); - }; + ParseTree.Dynamic charRange(dchar begin, dchar end) + { + return (ParseTree p) + { + string longName = "a char between '"~to!string(begin)~"' and '"~to!string(end)~"'"; + if (p.end < p.input.length && p.input[p.end] >= begin && p.input[p.end] <= end) + return ParseTree("charRange!(" ~ to!string(begin) ~ ", " ~ to!string(end) ~ ")", true, [p.input[p.end..p.end+1]], p.input, p.end, p.end+1); + else + return ParseTree("charRange!(" ~ to!string(begin) ~ ", " ~ to!string(end) ~ ")", false, [longName], p.input, p.end, p.end); + }; -} + } -Dynamic wrapAround(B, M, A)(B before, M middle, A after) -{ - return(ParseTree p) - { - ParseTree temp = callDynamic(before,p); - if (!temp.successful) - return temp; + ParseTree.Dynamic wrapAround(B, M, A)(B before, M middle, A after) + { + return(ParseTree p) + { + ParseTree temp = callDynamic(before,p); + if (!temp.successful) + return temp; - ParseTree result = callDynamic(middle,temp); - if (!result.successful) - return result; - result.begin = temp.begin; + ParseTree result = callDynamic(middle,temp); + if (!result.successful) + return result; + result.begin = temp.begin; - temp = callDynamic(after,result); - if (!temp.successful) - return temp; + temp = callDynamic(after,result); + if (!temp.successful) + return temp; - result.end = temp.end; - return result; - }; -} + result.end = temp.end; + return result; + }; + } -Dynamic zeroOrMore(D)(D d) -{ - return (ParseTree p) - { - string name = "zeroOrMore!(" ~ getName(d) ~ ")"; - ParseTree result = ParseTree(name, true, [], p.input, p.end, p.end); - ParseTree temp = callDynamic(d,result); - while(temp.successful - && (temp.begin < temp.end // To avoid infinite loops on epsilon-matching rules - || temp.name.startsWith("discard!("))) + ParseTree.Dynamic zeroOrMore(D)(D d) { - result.matches ~= temp.matches; - result.children ~= temp; - result.end = temp.end; - temp = callDynamic(d, result); + return (ParseTree p) + { + string name = "zeroOrMore!(" ~ getName(d) ~ ")"; + ParseTree result = ParseTree(name, true, [], p.input, p.end, p.end); + ParseTree temp = callDynamic(d,result); + while(temp.successful + && (temp.begin < temp.end // To avoid infinite loops on epsilon-matching rules + || temp.name.startsWith("discard!("))) + { + result.matches ~= temp.matches; + result.children ~= temp; + result.end = temp.end; + temp = callDynamic(d, result); + } + result.successful = true; + return result; + }; } - result.successful = true; - return result; - }; -} -Dynamic oneOrMore(D)(D d) -{ - return(ParseTree p) - { - string name = "oneOrMore!(" ~ getName(d) ~ ")"; - ParseTree result = ParseTree(name, false, [], p.input, p.end, p.end); - ParseTree temp = callDynamic(d, result); - - if (!temp.successful) + ParseTree.Dynamic oneOrMore(D)(D d) { - result.matches = temp.matches; - result.children = [temp]; - result.end = temp.end; + return(ParseTree p) + { + string name = "oneOrMore!(" ~ getName(d) ~ ")"; + ParseTree result = ParseTree(name, false, [], p.input, p.end, p.end); + ParseTree temp = callDynamic(d, result); + + if (!temp.successful) + { + result.matches = temp.matches; + result.children = [temp]; + result.end = temp.end; + } + else + { + while( temp.successful + && (temp.begin < temp.end // To avoid infinite loops on epsilon-matching rules + || temp.name.startsWith("discard!("))) + { + result.matches ~= temp.matches; + result.children ~= temp; + result.end = temp.end; + temp = callDynamic(d, result); + } + result.successful = true; + } + return result; + }; } - else + + ParseTree.Dynamic option(D)(D d) { - while( temp.successful - && (temp.begin < temp.end // To avoid infinite loops on epsilon-matching rules - || temp.name.startsWith("discard!("))) + return (ParseTree p) { - result.matches ~= temp.matches; - result.children ~= temp; - result.end = temp.end; - temp = callDynamic(d, result); - } - result.successful = true; + string name = "option!(" ~ getName(d) ~ ")"; + ParseTree result = callDynamic(d, p); + if (result.successful) + return ParseTree(name, true, result.matches, result.input, result.begin, result.end, [result]); + else + return ParseTree(name, true, [], p.input, p.end, p.end, null); + }; } - return result; - }; -} -Dynamic option(D)(D d) -{ - return (ParseTree p) + ParseTree.Dynamic and(T...)(T rules) if (T.length) { - string name = "option!(" ~ getName(d) ~ ")"; - ParseTree result = callDynamic(d, p); - if (result.successful) - return ParseTree(name, true, result.matches, result.input, result.begin, result.end, [result]); - else - return ParseTree(name, true, [], p.input, p.end, p.end, null); - }; -} - -Dynamic and(T...)(T rules) if (T.length) -{ - return (ParseTree p) - { - bool keepNode(ParseTree node) + return (ParseTree p) { - return node.name.startsWith("keep!(") - || ( !node.name.startsWith("discard!(") - //&& !node.name.startsWith("drop!(") - && node.matches !is null - //&& node.begin != node.end - ); - } - + bool keepNode(ParseTree node) + { + return node.name.startsWith("keep!(") + || ( !node.name.startsWith("discard!(") + //&& !node.name.startsWith("drop!(") + && node.matches !is null + //&& node.begin != node.end + ); + } - string name = "and!(" ~ ")"; - ParseTree result = ParseTree(name, false, [], p.input, p.end, p.end, []); + string name = "and!(" ~ ")"; - foreach(i,r; rules) - { - ParseTree temp = callDynamic(r, result); + ParseTree result = ParseTree(name, false, [], p.input, p.end, p.end, []); - result.end = temp.end; - if (temp.successful) + foreach(i,r; rules) { - if (keepNode(temp)) + ParseTree temp = callDynamic(r, result); + + result.end = temp.end; + if (temp.successful) { - result.matches ~= temp.matches; - if (temp.name.startsWith("drop!(")) - {} - else if (temp.name.startsWith("propagate!(")) - result.children ~= temp.children; - else - result.children ~= temp; + if (keepNode(temp)) + { + result.matches ~= temp.matches; + if (temp.name.startsWith("drop!(")) + {} + else if (temp.name.startsWith("propagate!(")) + result.children ~= temp.children; + else + result.children ~= temp; + } + } + else + { + result.children ~= temp;// add the failed node, to indicate which failed + if (temp.matches.length > 0) + result.matches ~= temp.matches[$-1]; + return result; // and end the parsing attempt right there } } - else - { - result.children ~= temp;// add the failed node, to indicate which failed - if (temp.matches.length > 0) - result.matches ~= temp.matches[$-1]; - return result; // and end the parsing attempt right there - } - } - result.successful = true; - return result; - }; -} + result.successful = true; + return result; + }; + } -Dynamic or(T...)(T rules) -{ - return (ParseTree p) - { - // error-management - ParseTree longestFail = ParseTree("or", false, [], p.input, p.end, 0); - string[] errorStrings; - size_t errorStringChars; - string orErrorString; - - ParseTree[rules.length] results; - string[rules.length] names; - size_t[rules.length] failedLength; - size_t maxFailedLength; - - // Real 'or' loop - foreach(i,r; rules) + ParseTree.Dynamic or(T...)(T rules) { - ParseTree temp = callDynamic(r, p); - if (temp.successful) - { - temp.children = [temp]; - temp.name = "or"; - return temp; - } - else + return (ParseTree p) { - enum errName = " (" ~")"; - failedLength[i] = temp.end; - if (temp.end >= longestFail.end) + // error-management + ParseTree longestFail = ParseTree("or", false, [], p.input, p.end, 0); + string[] errorStrings; + size_t errorStringChars; + string orErrorString; + + ParseTree[rules.length] results; + string[rules.length] names; + size_t[rules.length] failedLength; + size_t maxFailedLength; + + // Real 'or' loop + foreach(i,r; rules) { - maxFailedLength = temp.end; - longestFail = temp; - names[i] = errName; - results[i] = temp; - - if (temp.end == longestFail.end) - errorStringChars += temp.matches[$-1].length + errName.length + 4; + ParseTree temp = callDynamic(r, p); + if (temp.successful) + { + temp.children = [temp]; + temp.name = "or"; + return temp; + } else - errorStringChars = temp.matches[$-1].length + errName.length + 4; + { + enum errName = " (" ~")"; + failedLength[i] = temp.end; + if (temp.end >= longestFail.end) + { + maxFailedLength = temp.end; + longestFail = temp; + names[i] = errName; + results[i] = temp; + + if (temp.end == longestFail.end) + errorStringChars += temp.matches[$-1].length + errName.length + 4; + else + errorStringChars = temp.matches[$-1].length + errName.length + 4; + } + // Else, this error parsed less input than another one: we discard it. + } } - // Else, this error parsed less input than another one: we discard it. - } - } - // All subrules failed, we will take the longest match as the result - // If more than one node failed at the same (farthest) position, we concatenate their error messages + // All subrules failed, we will take the longest match as the result + // If more than one node failed at the same (farthest) position, we concatenate their error messages - char[] errString;// = new char[](errorStringChars); - errString.length = errorStringChars; - uint start = 0; - foreach(i; 0..rules.length) + char[] errString;// = new char[](errorStringChars); + errString.length = errorStringChars; + uint start = 0; + foreach(i; 0..rules.length) + { + if (failedLength[i] == maxFailedLength) + { + auto temp = results[i]; + auto len = temp.matches[$-1].length; + auto nlen = names[i].length; + errString[start .. start+len] = temp.matches[$-1][]; + errString[start+len .. start+len+names[i].length] = names[i][]; + errString[start+len+nlen .. start+len+nlen+4] = " or "; + start += len + names[i].length + 4; + } + } + 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. + longestFail.name = "or"; + longestFail.begin = p.end; + return longestFail; + }; + } + + ParseTree.Dynamic posLookahead(D)(D d) { - if (failedLength[i] == maxFailedLength) + return (ParseTree p) { - auto temp = results[i]; - auto len = temp.matches[$-1].length; - auto nlen = names[i].length; - errString[start .. start+len] = temp.matches[$-1][]; - errString[start+len .. start+len+names[i].length] = names[i][]; - errString[start+len+nlen .. start+len+nlen+4] = " or "; - start += len + names[i].length + 4; - } + string name = "posLookahead!(" ~ getName(d) ~ ")"; + ParseTree temp = callDynamic(d,p); + if (temp.successful) + return ParseTree(name, temp.successful, [], p.input, p.end, p.end); + else + return ParseTree(name, temp.successful, [temp.matches[$-1]], p.input, p.end, p.end); + }; } - 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. - longestFail.name = "or"; - longestFail.begin = p.end; - return longestFail; - }; -} -Dynamic posLookahead(D)(D d) -{ - return (ParseTree p) - { - string name = "posLookahead!(" ~ getName(d) ~ ")"; - ParseTree temp = callDynamic(d,p); - if (temp.successful) - return ParseTree(name, temp.successful, [], p.input, p.end, p.end); - else - return ParseTree(name, temp.successful, [temp.matches[$-1]], p.input, p.end, p.end); - }; -} - -Dynamic negLookahead(D)(D d) -{ - return (ParseTree p) - { - string name = "negLookahead!(" ~ getName(d) ~ ")"; - ParseTree temp = callDynamic(d,p); - if (temp.successful) - return ParseTree(name, false, ["anything but \"" ~ p.input[temp.begin..temp.end] ~ "\""], p.input, p.end, p.end); - else - return ParseTree(name, true, [], p.input, p.end, p.end); - }; -} + ParseTree.Dynamic negLookahead(D)(D d) + { + return (ParseTree p) + { + string name = "negLookahead!(" ~ getName(d) ~ ")"; + ParseTree temp = callDynamic(d,p); + if (temp.successful) + return ParseTree(name, false, ["anything but \"" ~ p.input[temp.begin..temp.end] ~ "\""], p.input, p.end, p.end); + else + return ParseTree(name, true, [], p.input, p.end, p.end); + }; + } -Dynamic named(D)(D d, string name) -{ - return (ParseTree p) - { - ParseTree result = callDynamic(d,p); - result.name = name; - return result; - }; -} + ParseTree.Dynamic named(D)(D d, string name) + { + return (ParseTree p) + { + ParseTree result = callDynamic(d,p); + result.name = name; + return result; + }; + } -Dynamic action(D, A)(D d, A act) -{ - return (ParseTree p) - { - return callDynamic(act, callDynamic(d,p)); - }; -} + ParseTree.Dynamic action(D, A)(D d, A act) + { + return (ParseTree p) + { + return callDynamic(act, callDynamic(d,p)); + }; + } -Dynamic fuse(D)(D d) -{ - return(ParseTree p) - { - p = callDynamic(d,p); - if (p.successful) + ParseTree.Dynamic fuse(D)(D d) { - if (p.matches.length != 0) - p.matches = [join(p.matches)]; + return(ParseTree p) + { + p = callDynamic(d,p); + if (p.successful) + { + if (p.matches.length != 0) + p.matches = [join(p.matches)]; - p.children = null; // also discard children + p.children = null; // also discard children + } + return p; + }; } - return p; - }; -} -Dynamic discardChildren(D)(D d) -{ - return (ParseTree p) - { - p = callDynamic(d,p); - p.children = null; - return p; - }; -} + ParseTree.Dynamic discardChildren(D)(D d) + { + return (ParseTree p) + { + p = callDynamic(d,p); + p.children = null; + return p; + }; + } -Dynamic discardMatches(D)(D d) -{ - return (ParseTree p) - { - p = callDynamic(d,p); - if (p.successful) - p.matches = null; - return p; - }; -} + ParseTree.Dynamic discardMatches(D)(D d) + { + return (ParseTree p) + { + p = callDynamic(d,p); + if (p.successful) + p.matches = null; + return p; + }; + } -Dynamic discard(D)(D d) -{ - return (ParseTree p) - { - ParseTree result = callDynamic(d,p); - result.name = "discard!(" ~ getName(d) ~ ")"; - //result.begin = result.end; - result.children = null; - if (result.successful) - result.matches = null;//to keep error messages, if any - - return result; - }; -} + static ParseTree.Dynamic discard(D)(D d) + { + return (ParseTree p) + { + ParseTree result = callDynamic(d,p); + result.name = "discard!(" ~ getName(d) ~ ")"; + //result.begin = result.end; + result.children = null; + if (result.successful) + result.matches = null;//to keep error messages, if any + + return result; + }; + } -Dynamic drop(D)(D d) -{ - return (ParseTree p) - { - ParseTree result = callDynamic(d,p); - result.children = null; - if (result.successful) - result.name = "drop!(" ~ getName(d) ~ ")"; - return result; - }; -} + ParseTree.Dynamic drop(D)(D d) + { + return (ParseTree p) + { + ParseTree result = callDynamic(d,p); + result.children = null; + if (result.successful) + result.name = "drop!(" ~ getName(d) ~ ")"; + return result; + }; + } -Dynamic propagate(D)(D d) -{ - return (ParseTree p) - { - ParseTree result = callDynamic(d,p); - if (result.successful) - result.name = "propagate!(" ~ getName(d) ~ ")"; - return result; - }; -} + ParseTree.Dynamic propagate(D)(D d) + { + return (ParseTree p) + { + ParseTree result = callDynamic(d,p); + if (result.successful) + result.name = "propagate!(" ~ getName(d) ~ ")"; + return result; + }; + } -Dynamic keep(D)(D d) -{ - return (ParseTree p) - { - ParseTree result = callDynamic(d,p); - if (result.successful) + ParseTree.Dynamic keep(D)(D d) { - result.children = [result]; - result.name = "keep!(" ~ getName(d) ~ ")"; + return (ParseTree p) + { + ParseTree result = callDynamic(d,p); + if (result.successful) + { + result.children = [result]; + result.name = "keep!(" ~ getName(d) ~ ")"; + } + return result; + }; } - return result; - }; + } } diff --git a/pegged/grammar.d b/pegged/grammar.d index 7edb69c..36a4758 100644 --- a/pegged/grammar.d +++ b/pegged/grammar.d @@ -13,7 +13,8 @@ import std.stdio; public import pegged.peg; import pegged.parser; -package import pegged.parsetree; +package import pegged.defaultparsetree : DefaultParseTree; +package import pegged.parsetree : isParseTree; struct GrammarOptions { string parsetreeName; @@ -46,7 +47,7 @@ void asModule(Memoization withMemo = Memoization.yes, ParseTree=DefaultParseTree f.write(optHeader ~ "\n\n"); static if (is(ParseTree == DefaultParseTree)) { - f.writeln("public import pegged.parsetree;"); + f.writeln("public import pegged.defaultparsetree;"); } else { f.writefln("import pegged.parsetree : isParseTree;"); @@ -220,7 +221,7 @@ string grammar(ParseTree, Memoization withMemo = Memoization.yes)(ParseTree defA string firstRuleName = generateCode(p.children[1].children[0]); if (optGrammar.parsetreeName == DefaultParseTree.stringof) { - result = "import pegged.parsetree : DefaultParseTree;\n"; + result = "import pegged.defaultparsetree : DefaultParseTree;\n"; } result ~= "struct Generic" ~ shortGrammarName ~ "(ParseTree) @@ -1012,6 +1013,13 @@ version(unittest) { unittest // 'grammar' unit test: low-level functionalities { + pragma(msg, grammar(` + Test1: + Rule1 <- 'a' + Rule2 <- 'b' + `)); + + mixin(grammar(` Test1: Rule1 <- 'a' diff --git a/pegged/parser.d b/pegged/parser.d index a2fdc01..56447ca 100644 --- a/pegged/parser.d +++ b/pegged/parser.d @@ -137,7 +137,6 @@ module pegged.parser; import std.algorithm: startsWith; import std.functional: toDelegate; -private import pegged.parsetree; struct GenericPegged(ParseTree) { import pegged.peg : DefaultPatters, decimateTree, GetName; @@ -2121,4 +2120,5 @@ struct GenericPegged(ParseTree) } } +private import pegged.defaultparsetree : DefaultParseTree; alias GenericPegged!(DefaultParseTree).Pegged Pegged; diff --git a/pegged/parsetree.d b/pegged/parsetree.d index 99c983d..52d134d 100644 --- a/pegged/parsetree.d +++ b/pegged/parsetree.d @@ -198,20 +198,20 @@ mixin template ParseTreeM() { } } -private import pegged.peg : ParseCollectionsM; -/** - The basic parse tree, as used throughout the project. - You can define your own parse tree node, but respect the basic layout. - Example: - struct MyParseTree { - mixin ParseTreeM; - ... My own stuff - } -*/ -struct DefaultParseTree { - mixin ParseTreeM; - mixin ParseCollectionsM; -} - - -static assert(isParseTree!DefaultParseTree); +// private import pegged.peg : ParseCollectionsM; +// /** +// The basic parse tree, as used throughout the project. +// You can define your own parse tree node, but respect the basic layout. +// Example: +// struct MyParseTree { +// mixin ParseTreeM; +// ... My own stuff +// } +// */ +// struct DefaultParseTree { +// mixin ParseTreeM; +// mixin ParseCollectionsM; +// } + + +// static assert(isParseTree!DefaultParseTree); diff --git a/pegged/peg.d b/pegged/peg.d index 61e05ba..e0b9ac8 100644 --- a/pegged/peg.d +++ b/pegged/peg.d @@ -367,7 +367,7 @@ struct PeggedT(ParseTree) { version(unittest) { private { - private import pegged.parsetree : DefaultParseTree; + private import pegged.defaultparsetree : DefaultParseTree; private alias ParseTree = DefaultParseTree; private import PEG=pegged.parsetree; // mixin ParseCollections!ParseTree; diff --git a/pegged/tester/testerparser.d b/pegged/tester/testerparser.d index 87c6135..c3499ae 100644 --- a/pegged/tester/testerparser.d +++ b/pegged/tester/testerparser.d @@ -206,4 +206,5 @@ struct GenericTesterGrammar(ParseTree) } } +import pegged.defaultparsetree : DefaultParseTree; alias GenericTesterGrammar!(DefaultParseTree).TesterGrammar TesterGrammar; From ac6472f2ccf691a2d80f7e74a75afc66ba323e97 Mon Sep 17 00:00:00 2001 From: cbleser Date: Thu, 10 Jun 2021 10:06:33 +0300 Subject: [PATCH 23/29] WIP: Dynamic peg is now moved into a struct called DynamicPeg and must be declated a static member inside the ParseTree object --- pegged/dynamic/peg.d | 143 ++++++++++++++++++----------------- pegged/grammar.d | 20 ++--- pegged/parser.d | 4 +- pegged/parsetree.d | 8 +- pegged/peg.d | 113 ++++++++++++++------------- pegged/tester/testerparser.d | 2 +- 6 files changed, 151 insertions(+), 139 deletions(-) diff --git a/pegged/dynamic/peg.d b/pegged/dynamic/peg.d index 3d9604b..4070409 100644 --- a/pegged/dynamic/peg.d +++ b/pegged/dynamic/peg.d @@ -13,14 +13,14 @@ private import pegged.parsetree : isParseTree; // private alias ParseTree=DefaultParseTree; // alias ParseTree delegate(ParseTree) Dynamic; -struct DynamicPeg(ParseTree) { +@safe struct DynamicPeg(ParseTree) { static { - static string getName(D)(D rule) + string getName(D)(D rule) { return callDynamic(rule, ParseTree()).name; } - ParseTree callDynamic(D)(D d, string s) + ParseTree callDynamic(D)(D d, string s) { static if (is(typeof(d) : ParseTree delegate(ParseTree)) || is(typeof(d) : ParseTree function(ParseTree))) return d(ParseTree("",false,[], s)); @@ -34,7 +34,7 @@ struct DynamicPeg(ParseTree) { assert(false, "Bad callDynamic, with type " ~ D.stringof); } - ParseTree callDynamic(D)(D d, ParseTree p) + ParseTree callDynamic(D)(D d, ParseTree p) { static if (is(typeof(d) : ParseTree delegate(ParseTree)) || is(typeof(d) : ParseTree function(ParseTree))) return d(p); @@ -48,7 +48,7 @@ struct DynamicPeg(ParseTree) { static assert(false, "Bad callDynamic, with type " ~ D.stringof); } - ParseTree.Dynamic fail() + ParseTree.Dynamic fail() { return (ParseTree p) { @@ -56,7 +56,7 @@ struct DynamicPeg(ParseTree) { }; } - ParseTree.Dynamic eoi() + ParseTree.Dynamic eoi() { return (ParseTree p) { @@ -67,7 +67,7 @@ struct DynamicPeg(ParseTree) { }; } - ParseTree.Dynamic eps() + ParseTree.Dynamic eps() { return (ParseTree p) { @@ -75,7 +75,7 @@ struct DynamicPeg(ParseTree) { }; } - ParseTree.Dynamic any() + ParseTree.Dynamic any() { return(ParseTree p) { @@ -86,7 +86,7 @@ struct DynamicPeg(ParseTree) { }; } - ParseTree.Dynamic literal(string s) + ParseTree.Dynamic literal(string s) { return (ParseTree p) { @@ -98,7 +98,7 @@ struct DynamicPeg(ParseTree) { }; } - ParseTree.Dynamic charRange(dchar begin, dchar end) + ParseTree.Dynamic charRange(dchar begin, dchar end) { return (ParseTree p) { @@ -111,7 +111,7 @@ struct DynamicPeg(ParseTree) { } - ParseTree.Dynamic wrapAround(B, M, A)(B before, M middle, A after) + ParseTree.Dynamic wrapAround(B, M, A)(B before, M middle, A after) { return(ParseTree p) { @@ -133,7 +133,7 @@ struct DynamicPeg(ParseTree) { }; } - ParseTree.Dynamic zeroOrMore(D)(D d) + ParseTree.Dynamic zeroOrMore(D)(D d) { return (ParseTree p) { @@ -154,7 +154,7 @@ struct DynamicPeg(ParseTree) { }; } - ParseTree.Dynamic oneOrMore(D)(D d) + ParseTree.Dynamic oneOrMore(D)(D d) { return(ParseTree p) { @@ -185,7 +185,7 @@ struct DynamicPeg(ParseTree) { }; } - ParseTree.Dynamic option(D)(D d) + ParseTree.Dynamic option(D)(D d) { return (ParseTree p) { @@ -198,65 +198,65 @@ struct DynamicPeg(ParseTree) { }; } - ParseTree.Dynamic and(T...)(T rules) if (T.length) - { - return (ParseTree p) + ParseTree.Dynamic and(T...)(T rules) if (T.length) { - bool keepNode(ParseTree node) + return (ParseTree p) { - return node.name.startsWith("keep!(") - || ( !node.name.startsWith("discard!(") - //&& !node.name.startsWith("drop!(") - && node.matches !is null - //&& node.begin != node.end - ); - } + bool keepNode(ParseTree node) + { + return node.name.startsWith("keep!(") + || ( !node.name.startsWith("discard!(") + //&& !node.name.startsWith("drop!(") + && node.matches !is null + //&& node.begin != node.end + ); + } - string name = "and!(" ~ ")"; + string name = "and!(" ~ ")"; - ParseTree result = ParseTree(name, false, [], p.input, p.end, p.end, []); + ParseTree result = ParseTree(name, false, [], p.input, p.end, p.end, []); - foreach(i,r; rules) - { - ParseTree temp = callDynamic(r, result); - - result.end = temp.end; - if (temp.successful) + foreach(i,r; rules) { - if (keepNode(temp)) + ParseTree temp = callDynamic(r, result); + + result.end = temp.end; + if (temp.successful) { - result.matches ~= temp.matches; - if (temp.name.startsWith("drop!(")) - {} - else if (temp.name.startsWith("propagate!(")) - result.children ~= temp.children; - else - result.children ~= temp; + if (keepNode(temp)) + { + result.matches ~= temp.matches; + if (temp.name.startsWith("drop!(")) + {} + else if (temp.name.startsWith("propagate!(")) + result.children ~= temp.children; + else + result.children ~= temp; + } + } + else + { + result.children ~= temp;// add the failed node, to indicate which failed + if (temp.matches.length > 0) + result.matches ~= temp.matches[$-1]; + return result; // and end the parsing attempt right there } } - else - { - result.children ~= temp;// add the failed node, to indicate which failed - if (temp.matches.length > 0) - result.matches ~= temp.matches[$-1]; - return result; // and end the parsing attempt right there - } - } - result.successful = true; - return result; - }; - } + result.successful = true; + return result; + }; + } - ParseTree.Dynamic or(T...)(T rules) + ParseTree.Dynamic or(T...)(T rules) { - return (ParseTree p) + return (ParseTree p) @safe { // error-management ParseTree longestFail = ParseTree("or", false, [], p.input, p.end, 0); string[] errorStrings; size_t errorStringChars; - string orErrorString; + //string orErrorString; ParseTree[rules.length] results; string[rules.length] names; @@ -314,17 +314,18 @@ struct DynamicPeg(ParseTree) { start += len + names[i].length + 4; } } - 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. + (() @trusted { + string 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. + })(); longestFail.name = "or"; longestFail.begin = p.end; return longestFail; }; } - ParseTree.Dynamic posLookahead(D)(D d) + ParseTree.Dynamic posLookahead(D)(D d) { return (ParseTree p) { @@ -337,7 +338,7 @@ struct DynamicPeg(ParseTree) { }; } - ParseTree.Dynamic negLookahead(D)(D d) + ParseTree.Dynamic negLookahead(D)(D d) { return (ParseTree p) { @@ -350,7 +351,7 @@ struct DynamicPeg(ParseTree) { }; } - ParseTree.Dynamic named(D)(D d, string name) + ParseTree.Dynamic named(D)(D d, string name) { return (ParseTree p) { @@ -360,7 +361,7 @@ struct DynamicPeg(ParseTree) { }; } - ParseTree.Dynamic action(D, A)(D d, A act) + ParseTree.Dynamic action(D, A)(D d, A act) { return (ParseTree p) { @@ -368,7 +369,7 @@ struct DynamicPeg(ParseTree) { }; } - ParseTree.Dynamic fuse(D)(D d) + ParseTree.Dynamic fuse(D)(D d) { return(ParseTree p) { @@ -384,7 +385,7 @@ struct DynamicPeg(ParseTree) { }; } - ParseTree.Dynamic discardChildren(D)(D d) + ParseTree.Dynamic discardChildren(D)(D d) { return (ParseTree p) { @@ -394,7 +395,7 @@ struct DynamicPeg(ParseTree) { }; } - ParseTree.Dynamic discardMatches(D)(D d) + ParseTree.Dynamic discardMatches(D)(D d) { return (ParseTree p) { @@ -405,7 +406,7 @@ struct DynamicPeg(ParseTree) { }; } - static ParseTree.Dynamic discard(D)(D d) + static ParseTree.Dynamic discard(D)(D d) { return (ParseTree p) { @@ -420,7 +421,7 @@ struct DynamicPeg(ParseTree) { }; } - ParseTree.Dynamic drop(D)(D d) + ParseTree.Dynamic drop(D)(D d) { return (ParseTree p) { @@ -432,7 +433,7 @@ struct DynamicPeg(ParseTree) { }; } - ParseTree.Dynamic propagate(D)(D d) + ParseTree.Dynamic propagate(D)(D d) { return (ParseTree p) { @@ -443,7 +444,7 @@ struct DynamicPeg(ParseTree) { }; } - ParseTree.Dynamic keep(D)(D d) + ParseTree.Dynamic keep(D)(D d) { return (ParseTree p) { diff --git a/pegged/grammar.d b/pegged/grammar.d index 36a4758..3b06f1f 100644 --- a/pegged/grammar.d +++ b/pegged/grammar.d @@ -224,7 +224,7 @@ string grammar(ParseTree, Memoization withMemo = Memoization.yes)(ParseTree defA result = "import pegged.defaultparsetree : DefaultParseTree;\n"; } result ~= - "struct Generic" ~ shortGrammarName ~ "(ParseTree) + "@safe struct Generic" ~ shortGrammarName ~ "(ParseTree) { // static if (is(ParseTree == DefaultParseTree)) { alias PEG=ParseTree; @@ -236,16 +236,16 @@ string grammar(ParseTree, Memoization withMemo = Memoization.yes)(ParseTree defA mixin DefaultPatters!ParseTree; //alias PEG=PeggedT!ParseTree; - struct " ~ grammarName ~ "\n { - enum name = \"" ~ shortGrammarName ~ "\"; - static ParseTree delegate(ParseTree)[string] before; - static ParseTree delegate(ParseTree)[string] after; - static ParseTree delegate(ParseTree)[string] rules;"; + @safe struct " ~ grammarName ~ "\n { + enum name = \"" ~ shortGrammarName ~ "\"; + static ParseTree.Dynamic[string] before; + static ParseTree.Dynamic[string] after; + static ParseTree.Dynamic[string] rules;"; if (withMemo == Memoization.yes) { result ~= " - import std.typecons:Tuple, tuple; - static ParseTree[Tuple!(string, size_t)] memo;"; + import std.typecons:Tuple, tuple; + static ParseTree[Tuple!(string, size_t)] memo;"; if (grammarInfo.leftRecursiveCycles.length > 0) result ~= " import std.algorithm: canFind, countUntil, remove; @@ -253,7 +253,7 @@ string grammar(ParseTree, Memoization withMemo = Memoization.yes)(ParseTree defA } result ~= " - static this()\n {\n"; + static this() @trusted\n {\n"; ParseTree[] definitions = p.children[1 .. $]; bool userDefinedSpacing; @@ -275,6 +275,7 @@ string grammar(ParseTree, Memoization withMemo = Memoization.yes)(ParseTree defA template hooked(alias r, string name) { + @safe { static ParseTree hooked(ParseTree p) { ParseTree result; @@ -298,6 +299,7 @@ string grammar(ParseTree, Memoization withMemo = Memoization.yes)(ParseTree defA { return hooked!(r, name)(ParseTree(\"\",false,[],input)); } + } } static void addRuleBefore(string parentRule, string ruleSyntax) diff --git a/pegged/parser.d b/pegged/parser.d index 56447ca..1a55830 100644 --- a/pegged/parser.d +++ b/pegged/parser.d @@ -137,7 +137,7 @@ module pegged.parser; import std.algorithm: startsWith; import std.functional: toDelegate; -struct GenericPegged(ParseTree) +@safe struct GenericPegged(ParseTree) { import pegged.peg : DefaultPatters, decimateTree, GetName; alias PEG=ParseTree; @@ -156,7 +156,7 @@ struct GenericPegged(ParseTree) static ParseTree delegate(ParseTree)[string] before; static ParseTree delegate(ParseTree)[string] after; static ParseTree delegate(ParseTree)[string] rules; - static this() + static this() @trusted { rules["Grammar"] = toDelegate(&Grammar); rules["Definition"] = toDelegate(&Definition); diff --git a/pegged/parsetree.d b/pegged/parsetree.d index 52d134d..c406f10 100644 --- a/pegged/parsetree.d +++ b/pegged/parsetree.d @@ -50,8 +50,9 @@ mixin template ParseTreeM() { import std.array : array; alias ParseTree = typeof(this); - alias Dynamic = ParseTree delegate(ParseTree); + @safe { + alias Dynamic = ParseTree delegate(ParseTree) @safe; string name; /// The node name bool successful; /// Indicates whether a parsing was successful or not string[] matches; /// The matched input's parts. Some expressions match at more than one place, hence matches is an array. @@ -130,7 +131,7 @@ mixin template ParseTreeM() { * @param successMsg String returned when there isn't an error * @param formatFailMsg Formating delegate function that generates the error message. */ - string failMsg(string delegate(Position, string, string, const ParseTree) formatFailMsg = toDelegate(&defaultFormatFailMsg), + string failMsg(string delegate(Position, string, string, const ParseTree) @safe formatFailMsg = toDelegate(&defaultFormatFailMsg), string successMsg = "Sucess") const @property { foreach(i, child; children) { @@ -174,7 +175,7 @@ mixin template ParseTreeM() { return result; } - immutable(ParseTree) idup() const @property + @trusted immutable(ParseTree) idup() const @property { return cast(immutable)dup(); } @@ -196,6 +197,7 @@ mixin template ParseTreeM() { ParseTree[] opSlice(size_t i, size_t j) { return children[i..j]; } + } } // private import pegged.peg : ParseCollectionsM; diff --git a/pegged/peg.d b/pegged/peg.d index e0b9ac8..4b91938 100644 --- a/pegged/peg.d +++ b/pegged/peg.d @@ -25,6 +25,7 @@ import std.conv; import std.string: strip; import std.typetuple; import pegged.parsetree : isParseTree; +import std.exception : assumeUnique; // Returns quoted and escaped version of the input, but if the input is null, then return `"end of input"`. string stringified(string inp) @safe @@ -148,7 +149,7 @@ struct Position ") == Position(2,4,8)); --- */ -Position position(string s) +Position position(string s) @safe { size_t col, line, index, prev_i; char prev_c; @@ -178,12 +179,12 @@ Position position(string s) /** Same as previous overload, but from the begin of P.input to p.end */ -Position position(ParseTree)(const ParseTree p) if(isParseTree!ParseTree) +Position position(ParseTree)(const ParseTree p) @safe if(isParseTree!ParseTree) { return position(p.input[0..p.end]); } -unittest +@safe unittest { assert(position("") == Position(0,0,0), "Null string, position 0."); assert(position("abc") == Position(0,3,3), "length 3 string, no line feed."); @@ -376,7 +377,7 @@ version(unittest) { } } -unittest // ParseTree testing +@safe unittest // ParseTree testing { ParseTree p; assert(p == p, "Self-identity on null tree."); @@ -431,7 +432,7 @@ unittest // ParseTree testing assert(p.failMsg == `Failure at line 0, col 1, after "i" expected "def", but got "nput"`); } -unittest // softCompare +@safe unittest // softCompare { ParseTree p = ParseTree("Name", true, ["abc", "", "def"], "input", 0, 1, null); ParseTree child = ParseTree("Child", true, ["abc", "", "def"], "input", 0, 1, null); @@ -447,7 +448,7 @@ unittest // softCompare } -unittest // 'fail' unit test +@safe unittest // 'fail' unit test { ParseTree input = ParseTree("input", true, [], "This is the input string.", 0,0, null); @@ -464,7 +465,7 @@ unittest // 'fail' unit test } -unittest // 'eoi' unit test +@safe unittest // 'eoi' unit test { ParseTree input = ParseTree("input", true, [], "This is the input string.", 0,0, null); ParseTree result = ParseTree.eoi(input); @@ -485,7 +486,7 @@ unittest // 'eoi' unit test } -unittest // 'any' unit test +@safe unittest // 'any' unit test { ParseTree input = ParseTree("input", true, [], "This is the input string.", 0,0, null); ParseTree result = ParseTree.any(input); @@ -523,7 +524,7 @@ unittest // 'any' unit test } -unittest // word boundary +@safe unittest // word boundary { ParseTree input = ParseTree("", false, [], "This is a word."); auto wb = [// "This" @@ -554,7 +555,7 @@ unittest // word boundary } -unittest // 'eps' unit test +@safe unittest // 'eps' unit test { ParseTree input = ParseTree("input", true, [], "abcdef", 0,0, null); @@ -713,7 +714,7 @@ template literalT(ParseTree, string s) } -unittest // 'literal' unit test +@safe unittest // 'literal' unit test { ParseTree input = ParseTree("input", true, [], "abcdef", 0,0, null); @@ -857,7 +858,7 @@ template caseInsensitiveLiteralT(ParseTree, string s) } -unittest // 'caseInsensitiveLiteral' unit test +@safe unittest // 'caseInsensitiveLiteral' unit test { ParseTree input = ParseTree("input", true, [], "AbCdEf", 0,0, null); @@ -1007,7 +1008,7 @@ template charRangeT(ParseTree, dchar begin, dchar end) if (begin <= end) } } -unittest // 'charRange' unit test +@safe unittest // 'charRange' unit test { ParseTree input = ParseTree("input", true, [], "abcdef", 0,0, null); @@ -1328,7 +1329,7 @@ bool failedChildFixup(ParseTree)(ref ParseTree p, size_t failEnd) if (isParseTre } } -unittest // 'and' unit test +@safe unittest // 'and' unit test { mixin DefaultPatters!ParseTree; alias abc= ParseTree.literal!"abc"; @@ -1406,7 +1407,7 @@ version (unittest) { } } -unittest // 'and' unit test with zeroOrMore and longest failing match +@safe unittest // 'and' unit test with zeroOrMore and longest failing match { alias A = ParseTree.literal!"abc"; alias B = ParseTree.literal!"def"; @@ -1422,7 +1423,7 @@ unittest // 'and' unit test with zeroOrMore and longest failing match assert(result.matches == []); } -unittest // 'and' unit test with option and longest failing match +@safe unittest // 'and' unit test with option and longest failing match { alias A = ParseTree.literal!"abc"; @@ -1439,7 +1440,7 @@ unittest // 'and' unit test with option and longest failing match assert(result.matches == []); } -unittest // 'and' unit test with oneOrMore and longest failing match +@safe unittest // 'and' unit test with oneOrMore and longest failing match { alias ParseTree.literal!"abc" A; @@ -1532,9 +1533,9 @@ template wrapAroundT(ParseTree, alias before, alias target, alias after) So we know 'or' failed, that the 'and' sub-rule had the longest match, matching 'ab' and failing for [0-9] on index 2. */ -template orT(ParseTree, rules...) if (rules.length > 0) -{ - string ctfeGetNameOr() +template orT(ParseTree, rules...) if (rules.length > 0) { + @safe { + string ctfeGetNameOr() { string name = "or!("; foreach(i,rule; rules) @@ -1544,15 +1545,15 @@ template orT(ParseTree, rules...) if (rules.length > 0) return name; } - enum name = ctfeGetNameOr(); + enum name = ctfeGetNameOr(); - ParseTree orT(ParseTree p) + ParseTree orT(ParseTree p) { // error-management ParseTree longestFail = ParseTree(name, false, [], p.input, p.end, 0); string[] errorStrings; size_t errorStringChars; - string orErrorString; + //string orErrorString; ParseTree[rules.length] results; string[rules.length] names; @@ -1640,7 +1641,8 @@ template orT(ParseTree, rules...) if (rules.length > 0) start += len + names[i].length + 4; } } - orErrorString = cast(string)(errString[0..$-4]); + string orErrorString = errString[0..$-4].idup; + longestFail.matches = longestFail.matches.length == 0 ? [orErrorString] : longestFail.matches[0..$-1] // discarding longestFail error message @@ -1649,18 +1651,19 @@ template orT(ParseTree, rules...) if (rules.length > 0) return ParseTree(name, false, longestFail.matches, p.input, p.end, longestFail.end, children, children.maxFailEnd); } - ParseTree orT(string input) + ParseTree orT(string input) { return orT!(ParseTree,rules)(ParseTree("",false,[],input)); } - string orT(GetName g) + string orT(GetName g) { return name; } + } } -unittest // 'or' unit test +@safe unittest // 'or' unit test { mixin DefaultPatters!ParseTree; @@ -1733,7 +1736,8 @@ unittest // 'or' unit test */ template longest_matchT(ParseTree, rules...) if (rules.length > 0) { - string ctfeGetNameOr() + @safe { + string ctfeGetNameOr() { string name = "longest_match!("; foreach(i,rule; rules) @@ -1743,15 +1747,15 @@ template longest_matchT(ParseTree, rules...) if (rules.length > 0) return name; } - enum name = ctfeGetNameOr(); + enum name = ctfeGetNameOr(); - ParseTree longest_matchT(ParseTree p) + ParseTree longest_matchT(ParseTree p) { // error-management ParseTree longest, longestFail = ParseTree(name, false, [], p.input, p.end, 0); string[] errorStrings; size_t errorStringChars; - string orErrorString; + //string orErrorString; ParseTree[rules.length] results; string[rules.length] names; @@ -1833,28 +1837,31 @@ template longest_matchT(ParseTree, rules...) if (rules.length > 0) start += len + names[i].length + 4; } } - orErrorString = cast(string)(errString[0..$-4]); + (() @trusted { + string orErrorString = cast(string)errString[0..$-4]; - longestFail.matches = longestFail.matches.length == 0 ? [orErrorString] : - longestFail.matches[0..$-1] // discarding longestFail error message - ~ [orErrorString]; // and replacing it by the new, concatenated one. + longestFail.matches = longestFail.matches.length == 0 ? [orErrorString] : + longestFail.matches[0..$-1] // discarding longestFail error message + ~ [orErrorString]; // and replacing it by the new, concatenated one. + })(); longestFail.name = name; longestFail.begin = p.end; return longestFail; } - ParseTree longest_matchT(string input) + ParseTree longest_matchT(string input) { return orT!(ParseTree, rules)(ParseTree("",false,[],input)); } - string longest_matchT(GetName g) + string longest_matchT(GetName g) { return name; } + } } -unittest // 'longest_match' unit test +@safe unittest // 'longest_match' unit test { mixin DefaultPatters!ParseTree; @@ -2120,7 +2127,7 @@ template keywordsT(ParseTree,kws...) if (kws.length > 0) } } -unittest +@safe unittest { alias kw = ParseTree.keywords!("abc","de","f"); @@ -2262,7 +2269,7 @@ template zeroOrMoreT(ParseTree, alias r) } } -unittest // 'zeroOrMore' unit test +@safe unittest // 'zeroOrMore' unit test { mixin DefaultPatters!ParseTree; alias literal!"a" a; @@ -2432,7 +2439,7 @@ template oneOrMoreT(ParseTree, alias r) } } -unittest // 'oneOrMore' unit test +@safe unittest // 'oneOrMore' unit test { mixin DefaultPatters!(ParseTree, [q{literal}, q{charRange}, q{oneOrMore}]); alias a = literal!"a"; @@ -2543,7 +2550,7 @@ template optionT(ParseTree, alias r) } } -unittest // 'option' unit test +@safe unittest // 'option' unit test { mixin DefaultPatters!(ParseTree, [q{literal}, q{option}]); alias literal!"a" a; @@ -2638,7 +2645,7 @@ template posLookaheadT(ParseTree, alias r) } } -unittest // 'posLookahead' unit test +@safe unittest // 'posLookahead' unit test { mixin DefaultPatters!(ParseTree, [q{literal}, q{posLookahead}]); @@ -2732,7 +2739,7 @@ template negLookaheadT(ParseTree, alias r) } } -unittest // 'negLookahead' unit test +@safe unittest // 'negLookahead' unit test { mixin DefaultPatters!(ParseTree, [q{literal}, q{negLookahead}]); @@ -2842,7 +2849,7 @@ template namedT(ParseTree, alias r, string name) } } -unittest // 'named' unit test +@safe unittest // 'named' unit test { mixin DefaultPatters!(ParseTree, [q{literal}, q{or}, q{named}, q{charRange}]); @@ -2926,7 +2933,7 @@ template definedT(ParseTree, alias r, string name) } } -unittest // 'defined' unit test +@safe unittest // 'defined' unit test { mixin DefaultPatters!(ParseTree, [q{literal}, q{or}, q{named}, q{charRange}, q{defined}]); @@ -2982,7 +2989,7 @@ template actionT(ParseTree, alias r, alias act) } } -unittest // 'action' unit test +@safe unittest // 'action' unit test { mixin DefaultPatters!(ParseTree, [q{literal}, q{action}]); @@ -3049,7 +3056,7 @@ template fuseT(ParseTree, alias r) } } -unittest // 'fuse' unit test +@safe unittest // 'fuse' unit test { mixin DefaultPatters!(ParseTree, [q{literal}, q{oneOrMore}, q{fuse}, q{discard}]); @@ -3172,7 +3179,7 @@ template discardT(ParseTree, alias r) } } -unittest // 'discard' unit test +@safe unittest // 'discard' unit test { mixin DefaultPatters!(ParseTree, [q{literal}, q{oneOrMore}, q{discard}, q{and}]); @@ -3254,7 +3261,7 @@ template dropT(ParseTree, alias r) } } -unittest // 'drop' unit test +@safe unittest // 'drop' unit test { mixin DefaultPatters!(ParseTree, [q{literal}, q{charRange}, q{drop}, q{oneOrMore}, q{and}]); @@ -3363,7 +3370,7 @@ template keepT(ParseTree, alias r) } } -unittest // 'keep' unit test +@safe unittest // 'keep' unit test { mixin DefaultPatters!(ParseTree, [q{literal}, q{and}, q{named}, q{keep}]); // Grammar mimicry @@ -3456,7 +3463,7 @@ template AddSpaceT(ParseTree, alias sp) ---- */ -unittest // 'spaceAnd' unit test +@safe unittest // 'spaceAnd' unit test { mixin DefaultPatters!(ParseTree, [q{literal}, q{and}, q{oneOrMore}, q{spaceAnd}, q{blank}, q{digit}]); @@ -3760,7 +3767,7 @@ enum defaultNames =[ /** Change the namespace of the grammar pattern in the ParseTree to scope if the mixin. names is the list of the pattern-names inside the ParseTree - */ +*/ mixin template DefaultPatters(ParseTree, string[] names = defaultNames) { private import std.format; static foreach(name; names) { diff --git a/pegged/tester/testerparser.d b/pegged/tester/testerparser.d index c3499ae..700fa90 100644 --- a/pegged/tester/testerparser.d +++ b/pegged/tester/testerparser.d @@ -40,7 +40,7 @@ module pegged.tester.testerparser; public import pegged.peg; private import pegged.parsetree; -struct GenericTesterGrammar(ParseTree) +@safe struct GenericTesterGrammar(ParseTree) { alias PEG=ParseTree; mixin DefaultPatters!ParseTree; From b77059426eab9fb11673e745d98ed45b68206ce0 Mon Sep 17 00:00:00 2001 From: cbleser Date: Thu, 10 Jun 2021 10:10:57 +0300 Subject: [PATCH 24/29] WIP: CTE debug printout removed --- pegged/dynamic/grammar.d | 4 ---- pegged/grammar.d | 8 -------- 2 files changed, 12 deletions(-) diff --git a/pegged/dynamic/grammar.d b/pegged/dynamic/grammar.d index f66f42d..2493abc 100644 --- a/pegged/dynamic/grammar.d +++ b/pegged/dynamic/grammar.d @@ -404,7 +404,6 @@ DynamicGrammar!ParseTree grammar(ParseTree)(string definition, ParseTree.Dynamic throw new Exception("Bad grammar input: " ~ defAsParseTree.toString("")); } - pragma(msg, "ParseTree ", ParseTree); DynamicGrammar!ParseTree gram; foreach(name, rule; context) { @@ -418,9 +417,6 @@ DynamicGrammar!ParseTree grammar(ParseTree)(string definition, ParseTree.Dynamic gram.grammarName = shortGrammarName; // Predefined spacing - pragma(msg, `ParseTree.Dynamic `, ParseTree.Dynamic); - pragma(msg, `gram.rules["Spacing"] `, typeof(gram.rules["Spacing"])); -// pragma(msg, `discard(zeroOrMore(or(literal(" "), literal("\t"), literal("\n"), literal("\r"))))`, typeof(discard(zeroOrMore(or(literal(" "), literal("\t"), literal("\n"), literal("\r")))))); gram.rules["Spacing"] = DPEG.discard(DPEG.zeroOrMore(DPEG.or(DPEG.literal(" "), DPEG.literal("\t"), DPEG.literal("\n"), DPEG.literal("\r")))); ParseTree[] definitions = p.children[1 .. $]; diff --git a/pegged/grammar.d b/pegged/grammar.d index 3b06f1f..174a09e 100644 --- a/pegged/grammar.d +++ b/pegged/grammar.d @@ -1015,13 +1015,6 @@ version(unittest) { unittest // 'grammar' unit test: low-level functionalities { - pragma(msg, grammar(` - Test1: - Rule1 <- 'a' - Rule2 <- 'b' - `)); - - mixin(grammar(` Test1: Rule1 <- 'a' @@ -2894,7 +2887,6 @@ unittest // Direct left-recursion S <- E eoi E <- E '+n' / 'n' `; - pragma(msg, grammar(LeftGrammar)); mixin(grammar(LeftGrammar)); ParseTree result = Left("n+n+n+n"); assert(result.successful); From c78d673e4af268a9913ce6208fada9743542c2d8 Mon Sep 17 00:00:00 2001 From: cbleser Date: Thu, 10 Jun 2021 10:27:48 +0300 Subject: [PATCH 25/29] makefile updated to included addtinal source files --- makefile | 11 ++++++++--- setup.mk | 1 + 2 files changed, 9 insertions(+), 3 deletions(-) create mode 100644 setup.mk diff --git a/makefile b/makefile index 73c975b..d0d51ef 100644 --- a/makefile +++ b/makefile @@ -1,11 +1,16 @@ +include setup.mk + all: if [ -x /usr/bin/dmd ]; then \ - dmd -w -wi -O -release -noboundscheck -lib -oflibpegged.a pegged/peg.d pegged/grammar.d pegged/parser.d pegged/introspection.d pegged/dynamic/grammar.d pegged/dynamic/peg.d; \ + dmd -w -wi -O -release -noboundscheck -lib -oflibpegged.a $(DFILES); \ elif [ -x /usr/bin/ldc2 ]; then \ - ldc2 -w -wi -O2 -release -boundscheck=off -c -of=libpegged.a pegged/peg.d pegged/grammar.d pegged/parser.d pegged/dynamic/grammar.d pegged/dynamic/peg.d; \ + ldc2 -w -wi -O2 -release -boundscheck=off -c -of=libpegged.a $(DFILES); \ elif [ -x /usr/bin/gdc ]; then \ - gdc -Wall -O2 -frelease -fbounds-check=off -c -olibpegged.a pegged/peg.d pegged/grammar.d pegged/parser.d pegged/dynamic/grammar.d pegged/dynamic/peg.d; \ + gdc -Wall -O2 -frelease -fbounds-check=off -c -olibpegged.a $(DFILES); \ fi clean: rm -f libpegged.a + +info: + @echo "DFILES = $(DFILES)" diff --git a/setup.mk b/setup.mk new file mode 100644 index 0000000..52db063 --- /dev/null +++ b/setup.mk @@ -0,0 +1 @@ +DFILES := ${shell find pegged -name "*.d" -not \( -path "*dev*" -o -path "*tester*" -o -path "*introspection.d" -o -path "*performancetest*" -o -path "*tohtml.d" \) } From ab150e68a7d1c55f019a1121f607f22c9503c1da Mon Sep 17 00:00:00 2001 From: cbleser Date: Thu, 10 Jun 2021 10:51:57 +0300 Subject: [PATCH 26/29] WIP: pegged/tester/grammartester.d is changed to @safe --- pegged/grammar.d | 52 +++++++++++++++++------------------ pegged/tester/grammartester.d | 21 +++++++------- 2 files changed, 37 insertions(+), 36 deletions(-) diff --git a/pegged/grammar.d b/pegged/grammar.d index 174a09e..3ffbe93 100644 --- a/pegged/grammar.d +++ b/pegged/grammar.d @@ -1013,7 +1013,7 @@ version(unittest) { private import PEG=pegged.parsetree; } -unittest // 'grammar' unit test: low-level functionalities +@safe unittest // 'grammar' unit test: low-level functionalities { mixin(grammar(` Test1: @@ -1033,7 +1033,7 @@ unittest // 'grammar' unit test: low-level functionalities assert(__traits(hasMember, Test1, "isRule"), "Test1 has a member named isRule."); } -unittest // 'grammar' unit test: PEG syntax +@safe unittest // 'grammar' unit test: PEG syntax { // Here we do not test PEG.*, just the grammar transformations // From a PEG to a Pegged expression template. @@ -1362,7 +1362,7 @@ unittest // 'grammar' unit test: PEG syntax assert(CaseSensitive("abci").successful); } -unittest // Multilines rules +@safe unittest // Multilines rules { mixin(grammar(` Indentation: @@ -1393,7 +1393,7 @@ Rule4 <- 'f' Rule5 # Rule4 ends with 'f', then it's Rule5 assert(Indentation.Rule5("gh").successful); } -unittest // Parsing at compile-time +@safe unittest // Parsing at compile-time { alias ParseTree = DefaultParseTree; @@ -1417,7 +1417,7 @@ unittest // Parsing at compile-time assert(CTfailure == result, "Compile-time parsing is equal to runtime parsing on failure."); } -unittest // PEG extensions (arrows, prefixes, suffixes) +@safe unittest // PEG extensions (arrows, prefixes, suffixes) { alias ParseTree = DefaultParseTree; @@ -1569,7 +1569,7 @@ unittest // PEG extensions (arrows, prefixes, suffixes) assert(result.children[2].name == "Arrows.DEF"); } -unittest //More space arrow tests +@safe unittest //More space arrow tests { mixin(grammar(` Spaces: @@ -1604,7 +1604,7 @@ unittest //More space arrow tests assert(result.children[4].name == "Spaces.C"); } -unittest // Prefix and suffix tests +@safe unittest // Prefix and suffix tests { mixin(grammar(` PrefixSuffix: @@ -2005,7 +2005,7 @@ unittest // Prefix and suffix tests assert(result.children[0].children[0].children[0].children[2].name == `literal!("abc")`); } -unittest // Issue #88 unit test +@safe unittest // Issue #88 unit test { alias ParseTree = DefaultParseTree; enum gram = ` @@ -2031,7 +2031,7 @@ unittest // Issue #88 unit test assert(p2.end == input.length); } -unittest // Leading alternation +@safe unittest // Leading alternation { alias ParseTree = DefaultParseTree; @@ -2061,7 +2061,7 @@ unittest // Leading alternation assert(result.matches == ["b"]); } -unittest // Extended chars tests +@safe unittest // Extended chars tests { mixin(grammar(" Chars: @@ -2123,7 +2123,7 @@ mixin(grammar(" assert(Chars.decimateTree(Chars.Spanish("¡Hola!")).successful); } -unittest // Extended char range tests +@safe unittest // Extended char range tests { import std.conv; @@ -2168,7 +2168,7 @@ unittest // Extended char range tests } } -unittest // qualified names for rules +@safe unittest // qualified names for rules { mixin(grammar(` First: @@ -2217,7 +2217,7 @@ unittest // qualified names for rules assert(result.matches == ["foo", "bar", "baz"]); } -unittest // Parameterized rules +@safe unittest // Parameterized rules { mixin(grammar(` Parameterized: @@ -2432,7 +2432,7 @@ version(unittest) // Semantic actions } } -unittest // Semantic actions, testing { foo } and { foo, bar, baz } +@safe unittest // Semantic actions, testing { foo } and { foo, bar, baz } { alias ParseTree = DefaultParseTree; @@ -2614,7 +2614,7 @@ badGrammar!"Name: } +/ -unittest // Memoization testing +@safe unittest // Memoization testing { enum gram1 = ` Test1: @@ -2650,7 +2650,7 @@ unittest // Memoization testing assert(softCompare(result1, result4)); } -unittest // Memoization reset in composed grammars. Issue #162 +@safe unittest // Memoization reset in composed grammars. Issue #162 { enum MathGrammar = ` Math: @@ -2670,7 +2670,7 @@ unittest // Memoization reset in composed grammars. Issue #162 // not cleared in all composed grammars. } -unittest // Test lambda syntax in semantic actions +@safe unittest // Test lambda syntax in semantic actions { import std.array; import std.string : strip; @@ -2819,7 +2819,7 @@ unittest // Test lambda syntax in semantic actions } } -unittest +@safe unittest { // Higher-level word boundary test. mixin(grammar(` @@ -2850,7 +2850,7 @@ unittest assert(!pt.successful); } -unittest // Issue #129 unit test +@safe unittest // Issue #129 unit test { alias ParseTree = DefaultParseTree; @@ -2880,7 +2880,7 @@ unittest // Issue #129 unit test assert(p.children[0].children[0].children[0].children[0].children.length == 0); } -unittest // Direct left-recursion +@safe unittest // Direct left-recursion { enum LeftGrammar = ` Left: @@ -2893,7 +2893,7 @@ unittest // Direct left-recursion assert(result.matches == ["n", "+n", "+n", "+n"]); } -unittest // Indirect left-recursion +@safe unittest // Indirect left-recursion { enum LeftGrammar = ` Left: @@ -2907,7 +2907,7 @@ unittest // Indirect left-recursion assert(result.matches == ["n", "+", "n", "+", "n", "+", "n"]); } -unittest // Proper blocking of memoization +@safe unittest // Proper blocking of memoization { // Three interlocking cycles of indirect left-recursion. enum LeftGrammar = ` @@ -2927,7 +2927,7 @@ unittest // Proper blocking of memoization } // Example from http://www.inf.puc-rio.br/~roberto/docs/sblp2012.pdf -unittest // Mutual left-recursion +@safe unittest // Mutual left-recursion { /* A thing about stoppers: Because P is at the intersection of left-recursive cycles P -> P and L -> P -> L, it should @@ -2953,7 +2953,7 @@ unittest // Mutual left-recursion assert(result.matches == ["x", "(n)", "(n)", ".x", "(n)", ".x"]); } -unittest // Left- and right-recursion (is right-associative!) +@safe unittest // Left- and right-recursion (is right-associative!) { enum LeftRightGrammar = ` LeftRight: @@ -2966,7 +2966,7 @@ unittest // Left- and right-recursion (is right-associative!) assert(result.matches == ["n", "+", "n", "+", "n", "+", "n"]); } -unittest // Hidden left-recursion +@safe unittest // Hidden left-recursion { enum HiddenLeft = ` Test: @@ -2980,7 +2980,7 @@ unittest // Hidden left-recursion assert(Test("bbca").successful); } -unittest // Null-matching left-recursion +@safe unittest // Null-matching left-recursion { enum NullMatch = ` Test: diff --git a/pegged/tester/grammartester.d b/pegged/tester/grammartester.d index 89f2b70..7faf35c 100644 --- a/pegged/tester/grammartester.d +++ b/pegged/tester/grammartester.d @@ -15,7 +15,7 @@ import std.string : stripRight, stripLeft, lineSplitter; import pegged.tester.testerparser; import pegged.grammar; -class GrammarTester(grammar, string startSymbol) +@safe class GrammarTester(grammar, string startSymbol) { bool soft = false; @@ -84,6 +84,9 @@ class GrammarTester(grammar, string startSymbol) if ( treeGot.successful && treeChecker.successful ) { auto ctx = getDifferencer(treeGot, treeChecker); + pragma(msg, "treeGot ", typeof(treeGot)); + // pragma(msg, "treeGot ", typeof(treeChecker)); + pragma(msg, typeof(ctx)); latestDiff = ctx.diff(); bool pass; @@ -111,7 +114,7 @@ class GrammarTester(grammar, string startSymbol) return runTest(file, lineNo, textToParse, desiredTreeRepresentation, true); } - static auto getDifferencer(T,P)( auto ref T treeRoot, auto ref P patternRoot ) + static auto getDifferencer(T,P)( auto ref T treeRoot, auto ref P patternRoot ) @trusted { Differencer!(T,P) t; t.treeRoot = &treeRoot; @@ -120,7 +123,7 @@ class GrammarTester(grammar, string startSymbol) } } -private struct Differencer(T,P) +@safe private struct Differencer(T,P) { size_t level = 0; size_t differences = 0; @@ -161,7 +164,7 @@ private struct Differencer(T,P) return diffText.data; } - private void diffNode( const(T*) node, const(P*) pattern ) + private void diffNode( const(T*) node, const(P*) pattern ) @trusted { assert(pattern); switch ( pattern.name ) @@ -221,7 +224,7 @@ private struct Differencer(T,P) } } - private void traverseUnexpected( const(T*) node ) + private void traverseUnexpected( const(T*) node ) @trusted { assert(node); lineDiff(node, null); @@ -231,7 +234,7 @@ private struct Differencer(T,P) level--; } - private void diffBranch( const(T*) node, const(P*) pattern, bool[] visited, ref size_t cursor ) + private void diffBranch( const(T*) node, const(P*) pattern, bool[] visited, ref size_t cursor ) @trusted { assert(pattern); switch ( pattern.name ) @@ -386,7 +389,7 @@ private struct Differencer(T,P) } } -unittest +@safe unittest { string normalizeStr(string str) { @@ -575,7 +578,7 @@ TesterGrammar.Root = Root assert(tester.errorText.length > 0); } -unittest +@safe unittest { mixin(grammar(` Arithmetic: @@ -628,5 +631,3 @@ unittest /+ For reference: +/ - - From aca0ddaad8735582db4bdafaa2671821f277a779 Mon Sep 17 00:00:00 2001 From: cbleser Date: Thu, 10 Jun 2021 12:00:28 +0300 Subject: [PATCH 27/29] introstion.d is change to be @safe parser.r has been self gererated from pegged/dev/regenerate.d A Makefile has been added to pegged/dev/, to build the regenerate --- .gitignore | 5 +- pegged/dev/Makefile | 11 +++ pegged/dev/regenerate.d | 2 +- pegged/introspection.d | 40 +++++----- pegged/parser.d | 67 ++++++++-------- pegged/parsetree.d | 142 +++++++++++++++------------------- pegged/tester/grammartester.d | 3 - setup.mk | 2 +- 8 files changed, 134 insertions(+), 138 deletions(-) create mode 100644 pegged/dev/Makefile diff --git a/.gitignore b/.gitignore index 64d6090..ced0609 100644 --- a/.gitignore +++ b/.gitignore @@ -47,4 +47,7 @@ build/* # Emacs *# -*.parked \ No newline at end of file +*.parked + +# Pegged self generator +pegged/dev/peggedgrammar \ No newline at end of file diff --git a/pegged/dev/Makefile b/pegged/dev/Makefile new file mode 100644 index 0000000..512eabf --- /dev/null +++ b/pegged/dev/Makefile @@ -0,0 +1,11 @@ + +DCFALGS+=-I../../ +DCFALGS+=-I../../examples/peggedgrammar/src/ +LDFLAGS+=../../libpegged.a +DFILES+=../../examples/peggedgrammar/src/pegged/examples/peggedgrammar.d + +all: + dmd $(DCFALGS) $(DFILES) regenerate.d $(LDFLAGS) + +clean: + rm -f regenerate diff --git a/pegged/dev/regenerate.d b/pegged/dev/regenerate.d index 961118b..5141885 100644 --- a/pegged/dev/regenerate.d +++ b/pegged/dev/regenerate.d @@ -5,7 +5,7 @@ module pegged.dev.regenerate; import pegged.grammar; import pegged.examples.peggedgrammar; -import pegged.examples.testergrammar; +//import pegged.examples.testergrammar; void main() { diff --git a/pegged/introspection.d b/pegged/introspection.d index 5a62fea..6744a23 100644 --- a/pegged/introspection.d +++ b/pegged/introspection.d @@ -40,7 +40,7 @@ enum InfiniteLoop { no, yes, indeterminate } /** Struct holding the introspection info on a rule. */ -struct RuleInfo +@safe struct RuleInfo { Recursive recursion; /// Is the rule recursive? LeftRecursive leftRecursion; /// Is the rule left-recursive? @@ -52,13 +52,13 @@ struct RuleInfo /** Struct holding the introspection info on a grammar. */ -struct GrammarInfo +@safe struct GrammarInfo { RuleInfo[string] ruleInfo; immutable(string[])[] leftRecursiveCycles; } -pure void appendCycleIfUnique(ref immutable(string[])[] cycles, const string[] cycle) +@safe pure void appendCycleIfUnique(ref immutable(string[])[] cycles, const string[] cycle) { bool exists() { @@ -89,7 +89,7 @@ Returns for all grammar rules: This kind of potential problem can be detected statically and should be transmitted to the grammar designer. */ -pure GrammarInfo grammarInfo(ParseTree)(ParseTree p) +GrammarInfo grammarInfo(ParseTree)(ParseTree p) pure @safe { if (p.name == "Pegged") return grammarInfo(p.children[0]); @@ -109,18 +109,18 @@ pure GrammarInfo grammarInfo(ParseTree)(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) @trusted { bool[string] idList; if (p.name == "Pegged.Identifier") idList[p.matches[0]] = true; - else + else { foreach(child; p.children) foreach(name; findIdentifiers(child).keys) idList[name] = true; - + } return idList; } @@ -144,7 +144,7 @@ pure GrammarInfo grammarInfo(ParseTree)(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) @trusted { bool[string][string] path; foreach(rule, children; graph) // deep-dupping, to avoid children aliasing @@ -169,7 +169,7 @@ pure GrammarInfo grammarInfo(ParseTree)(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); @@ -189,7 +189,7 @@ pure GrammarInfo grammarInfo(ParseTree)(ParseTree p) return result; } - NullMatch nullMatching(ParseTree p) + NullMatch nullMatching(ParseTree p) @safe { switch (p.name) { @@ -428,18 +428,18 @@ Returns for all grammar rules: This kind of potential problem can be detected statically and should be transmitted to the grammar designer. */ -pure RuleInfo[string] ruleInfo(ParseTree)(ParseTree p) +@safe pure RuleInfo[string] ruleInfo(ParseTree)(ParseTree p) { return grammarInfo(p).ruleInfo; } /** ditto */ -RuleInfo[string] ruleInfo(string grammar) +@safe RuleInfo[string] ruleInfo(string grammar) { return ruleInfo(Pegged(grammar).children[0]); } -unittest +@safe unittest { auto info = ruleInfo(` Test: @@ -463,7 +463,7 @@ unittest } // Test against infinite recursion in detection of indirect left-recursion. -unittest +@safe unittest { auto info = ruleInfo(` Test: @@ -475,7 +475,7 @@ unittest } // Test against compile-time infinite recursion. -unittest // Mutual left-recursion +@safe unittest // Mutual left-recursion { enum ct = ruleInfo(` Left: @@ -498,7 +498,7 @@ unittest // Mutual left-recursion assert(rt["P"].leftRecursion == LeftRecursive.direct); } -unittest // Intersecting cycles of left-recursion +@safe unittest // Intersecting cycles of left-recursion { enum ct = ruleInfo(` Left: @@ -520,7 +520,7 @@ unittest // Intersecting cycles of left-recursion assert(rt["B"].leftRecursion == LeftRecursive.indirect); } -unittest // Null-matching +@safe unittest // Null-matching { enum ct = ruleInfo(` NM: @@ -538,7 +538,7 @@ unittest // Null-matching assert(rt["NMM"].nullMatch == NullMatch.yes); } -unittest // Not null-matching +@safe unittest // Not null-matching { enum ct = ruleInfo(` Left: @@ -560,7 +560,7 @@ unittest // Not null-matching assert(rt["P"].nullMatch == NullMatch.no); } -unittest // Left-recursive null-matching +@safe unittest // Left-recursive null-matching { enum ct = ruleInfo(` Left: diff --git a/pegged/parser.d b/pegged/parser.d index 1a55830..72f8d11 100644 --- a/pegged/parser.d +++ b/pegged/parser.d @@ -109,7 +109,7 @@ TKNString <- (&'q{' ('q' NestedList('{',DString,'}'))) DLMString <- ('q' doublequote) ( (&'{' NestedList('{',DString,'}')) / (&'[' NestedList('[',DString,']')) - / (&'$(LPAREN)' NestedList('(',DString,')')) + / (&'(' NestedList('(',DString,')')) / (&'<' NestedList('<',DString,'>')) ) doublequote @@ -133,29 +133,30 @@ NestedList(L,R) <- ^L ( !(L/R) . )* (NestedList(L,R) / ( !(L/R) . )*)* ( !(L/R) +/ module pegged.parser; -//public import pegged.peg; +public import pegged.defaultparsetree; +public import pegged.peg; import std.algorithm: startsWith; import std.functional: toDelegate; +import pegged.defaultparsetree : DefaultParseTree; @safe struct GenericPegged(ParseTree) { - import pegged.peg : DefaultPatters, decimateTree, GetName; - alias PEG=ParseTree; - mixin DefaultPatters!ParseTree; - // static if (is(ParseTree == DefaultParseTree)) { - // import PEG=pegged.parsetree; - // } -// alias PEG=PeggedT!ParseTree; -// mixin DefaultParsePatterns!PEG; +// static if (is(ParseTree == DefaultParseTree)) { + alias PEG=ParseTree; +// } + import std.functional : toDelegate; import pegged.dynamic.grammar; - private import peg = pegged.peg; - struct Pegged + static import pegged.peg; + mixin DefaultPatters!ParseTree; + //alias PEG=PeggedT!ParseTree; + + @safe struct Pegged { - enum name = "Pegged"; - static ParseTree delegate(ParseTree)[string] before; - static ParseTree delegate(ParseTree)[string] after; - static ParseTree delegate(ParseTree)[string] rules; + enum name = "Pegged"; + static ParseTree.Dynamic[string] before; + static ParseTree.Dynamic[string] after; + static ParseTree.Dynamic[string] rules; static this() @trusted { rules["Grammar"] = toDelegate(&Grammar); @@ -215,6 +216,7 @@ import std.functional: toDelegate; template hooked(alias r, string name) { + @safe { static ParseTree hooked(ParseTree p) { ParseTree result; @@ -238,6 +240,7 @@ import std.functional: toDelegate; { return hooked!(r, name)(ParseTree("",false,[],input)); } + } } static void addRuleBefore(string parentRule, string ruleSyntax) @@ -254,10 +257,10 @@ import std.functional: toDelegate; { // enum name is the current grammar named auto dg = pegged.dynamic.grammar.grammar!ParseTree(name ~ ": " ~ ruleSyntax, rules); - foreach(name,rule; dg.rules) + foreach(ruleName,rule; dg.rules) { - if (name != "Spacing") - rules[name] = rule; + if (ruleName != "Spacing") + rules[ruleName] = rule; } after[parentRule] = rules[dg.startingRule]; } @@ -273,11 +276,11 @@ import std.functional: toDelegate; { if(__ctfe) { - return PEG.defined!(PEG.and!(Spacing, GrammarName, PEG.oneOrMore!(Definition), PEG.discard!(PEG.eoi)), "Pegged.Grammar")(p); + return PEG.defined!(PEG.and!(Spacing, GrammarName, PEG.oneOrMore!(Definition), PEG.discard!(eoi)), "Pegged.Grammar")(p); } else { - return hooked!(PEG.defined!(PEG.and!(Spacing, GrammarName, PEG.oneOrMore!(Definition), PEG.discard!(PEG.eoi)), "Pegged.Grammar"), "Grammar")(p); + return hooked!(PEG.defined!(PEG.and!(Spacing, GrammarName, PEG.oneOrMore!(Definition), PEG.discard!(eoi)), "Pegged.Grammar"), "Grammar")(p); } } static ParseTree Grammar(string s) @@ -2043,26 +2046,26 @@ import std.functional: toDelegate; { if(__ctfe) { - return PEG.defined!(PEG.and!(PEG.keep!(L), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)), PEG.zeroOrMore!(PEG.or!(Items, NestedList!(L, Items, R), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)))), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)), PEG.keep!(R)), "Pegged.NestedList!(" ~ peg.getName!(L)() ~ ", " ~ peg.getName!(Items)() ~ ", " ~ peg.getName!(R) ~ ")")(p); + return PEG.defined!(PEG.and!(PEG.keep!(L), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)), PEG.zeroOrMore!(PEG.or!(Items, NestedList!(L, Items, R), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)))), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)), PEG.keep!(R)), "Pegged.NestedList!(" ~ pegged.peg.getName!(L)() ~ ", " ~ pegged.peg.getName!(Items)() ~ ", " ~ pegged.peg.getName!(R) ~ ")")(p); } else { - return hooked!(PEG.defined!(PEG.and!(PEG.keep!(L), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)), PEG.zeroOrMore!(PEG.or!(Items, NestedList!(L, Items, R), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)))), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)), PEG.keep!(R)), "Pegged.NestedList!(" ~ peg.getName!(L)() ~ ", " ~ peg.getName!(Items)() ~ ", " ~ peg.getName!(R) ~ ")"), "NestedList_3")(p); + return hooked!(PEG.defined!(PEG.and!(PEG.keep!(L), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)), PEG.zeroOrMore!(PEG.or!(Items, NestedList!(L, Items, R), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)))), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)), PEG.keep!(R)), "Pegged.NestedList!(" ~ pegged.peg.getName!(L)() ~ ", " ~ pegged.peg.getName!(Items)() ~ ", " ~ pegged.peg.getName!(R) ~ ")"), "NestedList_3")(p); } } static ParseTree NestedList(string s) { if(__ctfe) - return PEG.defined!(PEG.and!(PEG.keep!(L), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)), PEG.zeroOrMore!(PEG.or!(Items, NestedList!(L, Items, R), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)))), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)), PEG.keep!(R)), "Pegged.NestedList!(" ~ peg.getName!(L)() ~ ", " ~ peg.getName!(Items)() ~ ", " ~ peg.getName!(R) ~ ")")(ParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(PEG.keep!(L), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)), PEG.zeroOrMore!(PEG.or!(Items, NestedList!(L, Items, R), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)))), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)), PEG.keep!(R)), "Pegged.NestedList!(" ~ pegged.peg.getName!(L)() ~ ", " ~ pegged.peg.getName!(Items)() ~ ", " ~ pegged.peg.getName!(R) ~ ")")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(PEG.defined!(PEG.and!(PEG.keep!(L), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)), PEG.zeroOrMore!(PEG.or!(Items, NestedList!(L, Items, R), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)))), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)), PEG.keep!(R)), "Pegged.NestedList!(" ~ peg.getName!(L)() ~ ", " ~ peg.getName!(Items)() ~ ", " ~ peg.getName!(R) ~ ")"), "NestedList_3")(ParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(PEG.keep!(L), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)), PEG.zeroOrMore!(PEG.or!(Items, NestedList!(L, Items, R), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)))), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R, Items)), PEG.any)), PEG.keep!(R)), "Pegged.NestedList!(" ~ pegged.peg.getName!(L)() ~ ", " ~ pegged.peg.getName!(Items)() ~ ", " ~ pegged.peg.getName!(R) ~ ")"), "NestedList_3")(ParseTree("", false,[], s)); } } static string NestedList(GetName g) { - return "Pegged.NestedList!(" ~ peg.getName!(L)() ~ ", " ~ peg.getName!(Items)() ~ ", " ~ peg.getName!(R) ~ ")"; + return "Pegged.NestedList!(" ~ pegged.peg.getName!(L)() ~ ", " ~ pegged.peg.getName!(Items)() ~ ", " ~ pegged.peg.getName!(R) ~ ")"; } } @@ -2072,26 +2075,26 @@ import std.functional: toDelegate; { if(__ctfe) { - return PEG.defined!(PEG.and!(PEG.keep!(L), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)), PEG.zeroOrMore!(PEG.or!(NestedList!(L, R), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)))), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)), PEG.keep!(R)), "Pegged.NestedList!(" ~ peg.getName!(L)() ~ ", " ~ peg.getName!(R) ~ ")")(p); + return PEG.defined!(PEG.and!(PEG.keep!(L), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)), PEG.zeroOrMore!(PEG.or!(NestedList!(L, R), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)))), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)), PEG.keep!(R)), "Pegged.NestedList!(" ~ pegged.peg.getName!(L)() ~ ", " ~ pegged.peg.getName!(R) ~ ")")(p); } else { - return hooked!(PEG.defined!(PEG.and!(PEG.keep!(L), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)), PEG.zeroOrMore!(PEG.or!(NestedList!(L, R), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)))), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)), PEG.keep!(R)), "Pegged.NestedList!(" ~ peg.getName!(L)() ~ ", " ~ peg.getName!(R) ~ ")"), "NestedList_2")(p); + return hooked!(PEG.defined!(PEG.and!(PEG.keep!(L), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)), PEG.zeroOrMore!(PEG.or!(NestedList!(L, R), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)))), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)), PEG.keep!(R)), "Pegged.NestedList!(" ~ pegged.peg.getName!(L)() ~ ", " ~ pegged.peg.getName!(R) ~ ")"), "NestedList_2")(p); } } static ParseTree NestedList(string s) { if(__ctfe) - return PEG.defined!(PEG.and!(PEG.keep!(L), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)), PEG.zeroOrMore!(PEG.or!(NestedList!(L, R), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)))), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)), PEG.keep!(R)), "Pegged.NestedList!(" ~ peg.getName!(L)() ~ ", " ~ peg.getName!(R) ~ ")")(ParseTree("", false,[], s)); + return PEG.defined!(PEG.and!(PEG.keep!(L), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)), PEG.zeroOrMore!(PEG.or!(NestedList!(L, R), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)))), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)), PEG.keep!(R)), "Pegged.NestedList!(" ~ pegged.peg.getName!(L)() ~ ", " ~ pegged.peg.getName!(R) ~ ")")(ParseTree("", false,[], s)); else { forgetMemo(); - return hooked!(PEG.defined!(PEG.and!(PEG.keep!(L), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)), PEG.zeroOrMore!(PEG.or!(NestedList!(L, R), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)))), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)), PEG.keep!(R)), "Pegged.NestedList!(" ~ peg.getName!(L)() ~ ", " ~ peg.getName!(R) ~ ")"), "NestedList_2")(ParseTree("", false,[], s)); + return hooked!(PEG.defined!(PEG.and!(PEG.keep!(L), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)), PEG.zeroOrMore!(PEG.or!(NestedList!(L, R), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)))), PEG.zeroOrMore!(PEG.and!(PEG.negLookahead!(PEG.or!(L, R)), PEG.any)), PEG.keep!(R)), "Pegged.NestedList!(" ~ pegged.peg.getName!(L)() ~ ", " ~ pegged.peg.getName!(R) ~ ")"), "NestedList_2")(ParseTree("", false,[], s)); } } static string NestedList(GetName g) { - return "Pegged.NestedList!(" ~ peg.getName!(L)() ~ ", " ~ peg.getName!(R) ~ ")"; + return "Pegged.NestedList!(" ~ pegged.peg.getName!(L)() ~ ", " ~ pegged.peg.getName!(R) ~ ")"; } } @@ -2120,5 +2123,5 @@ import std.functional: toDelegate; } } -private import pegged.defaultparsetree : DefaultParseTree; alias GenericPegged!(DefaultParseTree).Pegged Pegged; + diff --git a/pegged/parsetree.d b/pegged/parsetree.d index c406f10..a404ac4 100644 --- a/pegged/parsetree.d +++ b/pegged/parsetree.d @@ -1,13 +1,13 @@ /** This module contaits functions and parameter for ParseTree data element - */ +*/ module pegged.parsetree; import std.traits : isType, ReturnType, ForeachType, isCallable, Unqual; /** Returns: Gets the lvalue of M where M can be a function/data as type of data - */ +*/ template Returns(alias M) { static if (isType!M) { alias U = M; @@ -26,7 +26,7 @@ template Returns(alias M) { /** Returns true if T is a value ParseTree type - */ +*/ enum isParseTree(T) = is(Returns!(T.name) == string) && is(Returns!(T.successful) == bool) && @@ -41,7 +41,7 @@ enum isParseTree(T) = /** Contains the basic data and function for a ParseTree data element - */ +*/ mixin template ParseTreeM() { import pegged.peg; import std.functional : toDelegate; @@ -52,23 +52,23 @@ mixin template ParseTreeM() { alias ParseTree = typeof(this); @safe { - alias Dynamic = ParseTree delegate(ParseTree) @safe; - string name; /// The node name - bool successful; /// Indicates whether a parsing was successful or not - string[] matches; /// The matched input's parts. Some expressions match at more than one place, hence matches is an array. + alias Dynamic = ParseTree delegate(ParseTree) @safe; + string name; /// The node name + bool successful; /// Indicates whether a parsing was successful or not + string[] matches; /// The matched input's parts. Some expressions match at more than one place, hence matches is an array. - string input; /// The input string that generated the parse tree. Stored here for the parse tree to be passed to other expressions, as input. - size_t begin, end; /// Indices for the matched part from the very beginning of the first match to the last char of the last match. + string input; /// The input string that generated the parse tree. Stored here for the parse tree to be passed to other expressions, as input. + size_t begin, end; /// Indices for the matched part from the very beginning of the first match to the last char of the last match. - ParseTree[] children; /// The sub-trees created by sub-rules parsing. + ParseTree[] children; /// The sub-trees created by sub-rules parsing. - size_t failEnd; // The furthest this tree could match the input (including !successful rules). - ParseTree[] failedChild; /// The !successful child that could still be partially parsed. + size_t failEnd; // The furthest this tree could match the input (including !successful rules). + ParseTree[] failedChild; /// The !successful child that could still be partially parsed. - /** - Basic toString for easy pretty-printing. - */ - string toString(string tabs = "") const + /** + Basic toString for easy pretty-printing. + */ + string toString(string tabs = "") const { string result = name; @@ -86,21 +86,21 @@ mixin template ParseTreeM() { return result ~ childrenString; } - static ParseTree[] getUpto(ParseTree[] children, size_t minFailedLength) { - import std.algorithm : filter, max; - ParseTree[] arr; - foreach(a; children.filter!(r => max(r.end, r.failEnd) >= minFailedLength)) { - arr~=a; - } - return arr; + static ParseTree[] getUpto(ParseTree[] children, size_t minFailedLength) { + import std.algorithm : filter, max; + ParseTree[] arr; + foreach(a; children.filter!(r => max(r.end, r.failEnd) >= minFailedLength)) { + arr~=a; + } + return arr; // return children.filter!(r => max(r.end, r.failEnd) >= minFailedLength).array(); - } + } - /** - * Basic toString of only this node, without the children - */ - private string toStringThisNode(bool allChildrenSuccessful) const + /** + * Basic toString of only this node, without the children + */ + private string toStringThisNode(bool allChildrenSuccessful) const { if (successful) { return to!string([begin, end]) ~ to!string(matches) ~ "\n"; @@ -113,26 +113,26 @@ mixin template ParseTreeM() { } } - /** - * Default fail message formating function - */ - static string defaultFormatFailMsg(Position pos, string left, string right, const ParseTree pt) - { - return "Failure at line " ~ to!string(pos.line) ~ ", col " ~ to!string(pos.col) ~ ", " - ~ (left.length > 0 ? "after " ~ left.stringified ~ " " : "") - ~ "expected " ~ (pt.matches.length > 0 ? pt.matches[$ - 1].stringified : "NO MATCH") - ~ `, but got ` ~ right.stringified; - }; - - - /** - * Generates a generic error when a node fails - * - * @param successMsg String returned when there isn't an error - * @param formatFailMsg Formating delegate function that generates the error message. - */ - string failMsg(string delegate(Position, string, string, const ParseTree) @safe formatFailMsg = toDelegate(&defaultFormatFailMsg), - string successMsg = "Sucess") const @property + /** + * Default fail message formating function + */ + static string defaultFormatFailMsg(Position pos, string left, string right, const ParseTree pt) + { + return "Failure at line " ~ to!string(pos.line) ~ ", col " ~ to!string(pos.col) ~ ", " + ~ (left.length > 0 ? "after " ~ left.stringified ~ " " : "") + ~ "expected " ~ (pt.matches.length > 0 ? pt.matches[$ - 1].stringified : "NO MATCH") + ~ `, but got ` ~ right.stringified; + }; + + + /** + * Generates a generic error when a node fails + * + * @param successMsg String returned when there isn't an error + * @param formatFailMsg Formating delegate function that generates the error message. + */ + string failMsg(string delegate(Position, string, string, const ParseTree) @safe formatFailMsg = toDelegate(&defaultFormatFailMsg), + string successMsg = "Sucess") const @property { foreach(i, child; children) { if (!child.successful) { @@ -160,7 +160,7 @@ mixin template ParseTreeM() { return successMsg; } - ParseTree dup() const @property + ParseTree dup() const @property { ParseTree result; result.name = name; @@ -175,45 +175,27 @@ mixin template ParseTreeM() { return result; } - @trusted immutable(ParseTree) idup() const @property + @trusted immutable(ParseTree) idup() const @property { return cast(immutable)dup(); } - // Override opIndex operators - ref ParseTree opIndex(size_t index) { - return children[index]; - } + // Override opIndex operators + ref ParseTree opIndex(size_t index) { + return children[index]; + } - ref ParseTree[] opIndex() return { - return children; - } + ref ParseTree[] opIndex() return { + return children; + } - size_t opDollar(size_t pos)() const + size_t opDollar(size_t pos)() const { return children.length; } - ParseTree[] opSlice(size_t i, size_t j) { - return children[i..j]; - } + ParseTree[] opSlice(size_t i, size_t j) { + return children[i..j]; + } } } - -// private import pegged.peg : ParseCollectionsM; -// /** -// The basic parse tree, as used throughout the project. -// You can define your own parse tree node, but respect the basic layout. -// Example: -// struct MyParseTree { -// mixin ParseTreeM; -// ... My own stuff -// } -// */ -// struct DefaultParseTree { -// mixin ParseTreeM; -// mixin ParseCollectionsM; -// } - - -// static assert(isParseTree!DefaultParseTree); diff --git a/pegged/tester/grammartester.d b/pegged/tester/grammartester.d index 7faf35c..013732a 100644 --- a/pegged/tester/grammartester.d +++ b/pegged/tester/grammartester.d @@ -84,9 +84,6 @@ import pegged.grammar; if ( treeGot.successful && treeChecker.successful ) { auto ctx = getDifferencer(treeGot, treeChecker); - pragma(msg, "treeGot ", typeof(treeGot)); - // pragma(msg, "treeGot ", typeof(treeChecker)); - pragma(msg, typeof(ctx)); latestDiff = ctx.diff(); bool pass; diff --git a/setup.mk b/setup.mk index 52db063..cfe4c94 100644 --- a/setup.mk +++ b/setup.mk @@ -1 +1 @@ -DFILES := ${shell find pegged -name "*.d" -not \( -path "*dev*" -o -path "*tester*" -o -path "*introspection.d" -o -path "*performancetest*" -o -path "*tohtml.d" \) } +DFILES := ${shell find pegged -name "*.d" -not \( -path "*dev*" -o -path "*tester*" -o -path "*performancetest*" -o -path "*tohtml.d" \) } From 6ce89963a85b4e763b061ce8a466e43f3592a77c Mon Sep 17 00:00:00 2001 From: cbleser Date: Thu, 10 Jun 2021 13:46:49 +0300 Subject: [PATCH 28/29] make target added to run all examples make test-all Examples. src/pegged/examples/cparser.d source/app.d src/pegged/examples/constraints.d Does not pass --- .../src/pegged/examples/arithmetic.d | 1 + examples/c/src/pegged/examples/cparser.d | 6 ++-- .../src/pegged/examples/parameterized.d | 2 +- .../src/pegged/examples/simple_arithmetic.d | 2 +- makefile | 31 +++++++++++++++++++ pegged/grammar.d | 3 +- pegged/peg.d | 6 ++++ pegged/tohtml.d | 11 ++++--- 8 files changed, 52 insertions(+), 10 deletions(-) diff --git a/examples/arithmetic/src/pegged/examples/arithmetic.d b/examples/arithmetic/src/pegged/examples/arithmetic.d index 5138ece..e2c016a 100644 --- a/examples/arithmetic/src/pegged/examples/arithmetic.d +++ b/examples/arithmetic/src/pegged/examples/arithmetic.d @@ -7,6 +7,7 @@ module pegged.examples.arithmetic; import std.conv: to; import pegged.grammar; +import pegged.defaultparsetree : ParseTree = DefaultParseTree; mixin(grammar(` # Arithmetic grammar with variable terminal diff --git a/examples/c/src/pegged/examples/cparser.d b/examples/c/src/pegged/examples/cparser.d index 42a607c..b722598 100644 --- a/examples/c/src/pegged/examples/cparser.d +++ b/examples/c/src/pegged/examples/cparser.d @@ -2,7 +2,7 @@ module pegged.examples.cparser; import pegged.grammar; -struct C +@safe struct C { enum names = [`TranslationUnit`:true, `ExternalDeclaration`:true, `FunctionDefinition`:true, `PrimaryExpression`:true, `PostfixExpression`:true, `ArgumentExpressionList`:true, `UnaryExpression`:true, `IncrementExpression`:true, `PlusPlus`:true, @@ -21,7 +21,9 @@ struct C `Keyword`:true, `Spacing`:true, `Comment`:true, `StringLiteral`:true, `DQChar`:true, `EscapeSequence`:true, `CharLiteral`:true, `IntegerLiteral`:true, `Integer`:true, `IntegerSuffix`:true, `FloatLiteral`:true, `Sign`:true]; - mixin decimateTree; + import pegged.defaultparsetree : ParseTree = DefaultParseTree; + mixin decimateTree!ParseTree; + mixin DefaultPatters!ParseTree; static ParseTree TranslationUnit(ParseTree p) { diff --git a/examples/parameterized/src/pegged/examples/parameterized.d b/examples/parameterized/src/pegged/examples/parameterized.d index 938e61c..0b76e6e 100644 --- a/examples/parameterized/src/pegged/examples/parameterized.d +++ b/examples/parameterized/src/pegged/examples/parameterized.d @@ -113,7 +113,7 @@ unittest A <- Parameterized.LineComment ")); - ParseTree p5 = ParamTest5("// This is a comment! + auto p5 = ParamTest5("// This is a comment! This is not a comment. End."); assert(p5.successful); diff --git a/examples/simple_arithmetic/src/pegged/examples/simple_arithmetic.d b/examples/simple_arithmetic/src/pegged/examples/simple_arithmetic.d index 29bd0d3..9a1ef2b 100644 --- a/examples/simple_arithmetic/src/pegged/examples/simple_arithmetic.d +++ b/examples/simple_arithmetic/src/pegged/examples/simple_arithmetic.d @@ -7,7 +7,7 @@ module pegged.examples.simple_arithmetic; import std.conv: to; import pegged.grammar; - +import pegged.defaultparsetree : ParseTree = DefaultParseTree; mixin(grammar(` Arithmetic: Term < Factor (Add / Sub)* diff --git a/makefile b/makefile index d0d51ef..724b1fb 100644 --- a/makefile +++ b/makefile @@ -14,3 +14,34 @@ clean: info: @echo "DFILES = $(DFILES)" + +ALL_PEG:=${shell find examples -maxdepth 1 -type d -not -path examples} + +define Pegs +$1/.done: + cd $1; dub test + touch $1/.done + +endef + +${foreach DONE,$(ALL_PEG), ${eval ${call Pegs,$(DONE)}}} + +DO_ALL := ${addsuffix /.done,$(ALL_PEG)} + +test-all: $(DO_ALL) + +test-clean: + rm -f $(DO_ALL) + +export DO_ALL_PEG=${foreach DONE,$(ALL_PEG), ${call Pegs,$(DONE)}} + + +CALL_PEG:=${call Pegs,c}} + +export CALL_PEG + +show: + @echo "$$CALL_PEG" + @echo "$$DO_ALL_PEG" + @echo $(ALL_PEG) + @echo $(DO_ALL) diff --git a/pegged/grammar.d b/pegged/grammar.d index 3ffbe93..6e34591 100644 --- a/pegged/grammar.d +++ b/pegged/grammar.d @@ -221,7 +221,8 @@ string grammar(ParseTree, Memoization withMemo = Memoization.yes)(ParseTree defA string firstRuleName = generateCode(p.children[1].children[0]); if (optGrammar.parsetreeName == DefaultParseTree.stringof) { - result = "import pegged.defaultparsetree : DefaultParseTree;\n"; + + result = "import pegged.defaultparsetree;\n"; } result ~= "@safe struct Generic" ~ shortGrammarName ~ "(ParseTree) diff --git a/pegged/peg.d b/pegged/peg.d index 4b91938..ae8f8b9 100644 --- a/pegged/peg.d +++ b/pegged/peg.d @@ -3732,6 +3732,7 @@ mixin template ParseCollectionsM() { enum defaultNames =[ "eol", "eoi", + "named", "blank", "quote", "doublequote", @@ -3759,9 +3760,14 @@ enum defaultNames =[ "and", "or", "fail", + "fuse", "digits", "charRange", + "discard", "longest_match", + "spaceAnd", + "space", + "digit", ]; /** diff --git a/pegged/tohtml.d b/pegged/tohtml.d index 2a51c91..fa2f4a1 100644 --- a/pegged/tohtml.d +++ b/pegged/tohtml.d @@ -4,6 +4,7 @@ import std.stdio; import std.conv, std.string; import std.algorithm.searching; import pegged.peg; +import pegged.parsetree : isParseTree; enum Expand { @@ -21,8 +22,8 @@ enum Expand * p = The ParseTree to represent. * file = The file where to write the tree. */ -void toHTML(Expand e = Expand.no, Details...)(const ref ParseTree p, - File file) +void toHTML(ParseTree, Expand e = Expand.no, Details...)(const ref ParseTree p, + File file) if (isParseTree!ParseTree) { file.write(` @@ -163,10 +164,10 @@ details.leaf summary::-webkit-details-marker { * p = The ParseTree to represent. * filename = The name of file where tree is written. */ -void toHTML(Expand e = Expand.no, Details...)(const ref ParseTree p, - string filename) +void toHTML(ParseTree, Expand e = Expand.no, Details...)(const ref ParseTree p, + string filename) if(isParseTree!ParseTree) { if (filename.endsWith(".html", ".htm") == 0) filename ~= ".html"; - toHTML!(e, Details)(p, File(filename, "w")); + toHTML!(ParseTree, e, Details)(p, File(filename, "w")); } From 238b3a1bfc59ab68d85480a2800ae56c65b5b1ff Mon Sep 17 00:00:00 2001 From: cbleser Date: Thu, 10 Jun 2021 13:54:46 +0300 Subject: [PATCH 29/29] .done added to .gitignore --- .gitignore | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index ced0609..6c8fc75 100644 --- a/.gitignore +++ b/.gitignore @@ -50,4 +50,7 @@ build/* *.parked # Pegged self generator -pegged/dev/peggedgrammar \ No newline at end of file +pegged/dev/peggedgrammar + +# Test .done +.done