├── .gitignore
├── Directory.Build.props
├── Docs
├── PEG1.png
└── Packrat Parser in C.docx
├── LICENSE
├── PEG.Tests
├── ArgumentsTest.cs
├── CaptureTests.cs
├── CodeGrammarTest.cs
├── CppMacro
│ ├── Macro.cs
│ ├── MacroGrammar.cs
│ └── MacroGrammarTest.cs
├── EncloseTest.cs
├── ExpressionExtensionsTest.cs
├── LambdaGrammarTest.cs
├── Lengths
│ ├── Length.cs
│ └── LengthTests.cs
├── PEG.Tests.csproj
├── ParserTest.cs
├── QutoedStringTests.cs
├── RepeatTests.cs
├── Url
│ ├── Url.cs
│ ├── UrlGrammar.cs
│ └── UrlGrammarTest.cs
└── Xml
│ └── XmlGrammar.cs
├── PEG.sln
├── PEG.sln.DotSettings
├── PEG.sln.DotSettings.user
├── PEG
├── Builder
│ ├── AstAttribute.cs
│ ├── ConsumeAttribute.cs
│ ├── ConsumeChoice.cs
│ ├── ConsumeConditional.cs
│ ├── ConsumeExpression.cs
│ ├── ConsumeExpressionCache.cs
│ ├── ConsumeExpressionParsing.cs
│ ├── ConsumeIndexExpression.cs
│ ├── ConsumeReferenceExpression.cs
│ └── PegBuilder.cs
├── Cst
│ ├── CstBuilder.cs
│ ├── CstCache.cs
│ ├── CstNonterminalNode.cs
│ ├── CstString.cs
│ ├── ICstNode.cs
│ ├── ICstNonterminalNode.cs
│ └── ICstTerminalNode.cs
├── ExpressionCompiler.cs
├── ExpressionEnumerator.cs
├── ExpressionExtensions.cs
├── ExpressionWalker.cs
├── Extensions
│ ├── AttributeExtensions.cs
│ ├── CharExtensions.cs
│ ├── EnumerableExtensions.cs
│ ├── ReflectionExtensions.cs
│ └── StringExtensions.cs
├── FirstSet.cs
├── Grammar.cs
├── GrammarFactory.cs
├── IParseInput.cs
├── IPegBuilder.cs
├── IReplacementTarget.cs
├── LeftRecursion.cs
├── LrParseEngine.cs
├── MemoEntry.cs
├── NonterminalReplacementTarget.cs
├── OutputRecord.cs
├── PEG.csproj
├── ParseEngine.cs
├── ParseError.cs
├── ParseException.cs
├── Peg.cs
├── PegParser.cs
├── Proxies
│ ├── Extensions
│ │ └── EmitExtensions.cs
│ ├── Invocation.cs
│ └── Proxy.cs
├── Replacement.cs
├── StringParseInput.cs
├── StringReplacementTarget.cs
├── SyntaxTree
│ ├── AndPredicate.cs
│ ├── AnyCharacter.cs
│ ├── AnyCharacterTerminal.cs
│ ├── CharacterRange.cs
│ ├── CharacterSet.cs
│ ├── CharacterTerminal.cs
│ ├── EmptyString.cs
│ ├── EncloseExpression.cs
│ ├── Expression.cs
│ ├── ForeignNonterminal.cs
│ ├── IExpressionVisitor.cs
│ ├── Nonterminal.cs
│ ├── NotPredicate.cs
│ ├── NullTerminal.cs
│ ├── OneOrMore.cs
│ ├── Optional.cs
│ ├── OrderedChoice.cs
│ ├── Repeat.cs
│ ├── Sequence.cs
│ ├── Substitution.cs
│ ├── Terminal.cs
│ ├── Token.cs
│ └── ZeroOrMore.cs
├── TokenAttribute.cs
├── TokenParseInput.cs
├── TokenizerAttribute.cs
└── Utils
│ ├── BitShift.cs
│ ├── BooleanSet.cs
│ ├── DictionaryList.cs
│ ├── DictionarySet.cs
│ └── DynamicArray.cs
├── README.md
└── appveyor.yml
/.gitignore:
--------------------------------------------------------------------------------
1 | [Bb]in/
2 | [Oo]bj/
3 | *.suo
4 | *.DS_Store
5 | **/[Pp]ackages/*
6 | .vs/
7 | .idea/
8 | _ReSharper*/
9 | *.[Rr]e[Ss]harper
10 | *.DotSettings.user
11 |
12 | # NuGet Packages
13 | *.nupkg
14 | # NuGet Symbol Packages
15 | *.snupkg
16 |
--------------------------------------------------------------------------------
/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 7.3
5 | 2.0.0
6 | 2.0.0.0
7 | Kirk Woll
8 |
9 |
10 | Copyright 2012-2019
11 | MIT
12 | https://github.com/kswoll/npeg
13 | peg parser
14 | Parsing expression grammar (PEG) DSL for .NET
15 | https://github.com/kswoll/npeg
16 |
17 |
18 | true
19 | true
20 | snupkg
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/Docs/PEG1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kswoll/npeg/8b1caa826a868bc298922e0e738a8d2a2de0d61f/Docs/PEG1.png
--------------------------------------------------------------------------------
/Docs/Packrat Parser in C.docx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kswoll/npeg/8b1caa826a868bc298922e0e738a8d2a2de0d61f/Docs/Packrat Parser in C.docx
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 kswoll
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/PEG.Tests/ArgumentsTest.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 |
3 | namespace PEG.Tests
4 | {
5 | [TestFixture]
6 | public class ArgumentsTest
7 | {
8 | public class ArgumentsGrammar : Grammar
9 | {
10 | public string Argument { get; set; }
11 |
12 | protected override void OnCreated(object[] args)
13 | {
14 | base.OnCreated(args);
15 |
16 | Argument = (string)args[0];
17 | }
18 | }
19 |
20 | [Test]
21 | public void Arguments()
22 | {
23 | var grammar = ArgumentsGrammar.Create("foo");
24 | Assert.AreEqual("foo", grammar.Argument);
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/PEG.Tests/CaptureTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 | using PEG.SyntaxTree;
3 |
4 | namespace PEG.Tests
5 | {
6 | [TestFixture]
7 | public class CaptureTests
8 | {
9 | [Test]
10 | public void CaptureInitializedProperly()
11 | {
12 | var grammar = TestGrammar.Create();
13 | var parser = new PegParser(grammar, grammar.Root());
14 | var input = "AAABBBBB";
15 | var result = parser.Parse(input);
16 | Assert.AreEqual(input, result.Items);
17 | }
18 |
19 | public class TestData
20 | {
21 | public string Items { get; set; }
22 | }
23 |
24 | public class TestGrammar : Grammar
25 | {
26 | public virtual Expression Root()
27 | {
28 | return Items();
29 | }
30 |
31 | /*
32 | public virtual Expression A()
33 | {
34 | return 'A'._().Repeat(4, 6);
35 | }
36 |
37 | public virtual Expression B()
38 | {
39 | return 'A'._() | 'B';
40 | }
41 | */
42 |
43 | public virtual Expression Items()
44 | {
45 | return -('A'._().Repeat(4, 6).Capture("A") | ('A'._() | 'B').Capture("B"));
46 | }
47 | }
48 | }
49 | }
--------------------------------------------------------------------------------
/PEG.Tests/CodeGrammarTest.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 | using PEG.SyntaxTree;
3 |
4 | namespace PEG.Tests
5 | {
6 | [TestFixture]
7 | public class CodeGrammarTest
8 | {
9 | public class TestGrammar1 : Grammar
10 | {
11 | public virtual Expression LetterA()
12 | {
13 | return 'a';
14 | }
15 |
16 | public virtual Expression LetterB()
17 | {
18 | return 'b';
19 | }
20 |
21 | public virtual Expression LetterChoice()
22 | {
23 | return 'a'._() | 'b';
24 | }
25 |
26 | public virtual Expression NonterminalAndLetterChoice()
27 | {
28 | return LetterA() | 'b';
29 | }
30 |
31 | public virtual Expression NonterminalAndNonterminalChoice()
32 | {
33 | return LetterA() | LetterB();
34 | }
35 |
36 | public virtual Expression LetterSequence()
37 | {
38 | return 'a'._() + 'b';
39 | }
40 |
41 | public virtual Expression NonterminalAndLetterSequence()
42 | {
43 | return LetterA() + 'b';
44 | }
45 |
46 | public virtual Expression NonterminalAndNonterminalSequence()
47 | {
48 | return LetterA() + LetterB();
49 | }
50 |
51 | public virtual Expression NotLetterA()
52 | {
53 | return !LetterA();
54 | }
55 |
56 | public virtual Expression AndLetterA()
57 | {
58 | return LetterA().And();
59 | }
60 |
61 | public virtual Expression OneOrMoreLetterA()
62 | {
63 | return +LetterA();
64 | }
65 |
66 | public virtual Expression ZeroOrMoreLetterA()
67 | {
68 | return -LetterA();
69 | }
70 |
71 | public virtual Expression OptionalLetterA()
72 | {
73 | return ~LetterA();
74 | }
75 |
76 | public virtual Expression TwoSequences()
77 | {
78 | return LetterA() + LetterB() | LetterB() + LetterA();
79 | }
80 |
81 | public virtual Expression ThreeChoices()
82 | {
83 | return LetterA() | LetterB() | 'c';
84 | }
85 |
86 | public virtual Expression ThreeExpressionSequence()
87 | {
88 | return LetterA() + LetterB() + 'c';
89 | }
90 | }
91 |
92 | [Test]
93 | public void TestGrammar1Letter()
94 | {
95 | TestGrammar1 grammar = TestGrammar1.Create();
96 | Nonterminal nonterminal = grammar.GetNonterminal(o => o.LetterA());
97 | Assert.AreEqual("LetterA", nonterminal.Name);
98 | Assert.AreEqual('a', ((CharacterTerminal)nonterminal.Expression).Character);
99 | }
100 |
101 | [Test]
102 | public void TestGrammar1LetterChoice()
103 | {
104 | TestGrammar1 grammar = TestGrammar1.Create();
105 | Nonterminal nonterminal = grammar.GetNonterminal(o => o.LetterChoice());
106 | Assert.AreEqual("LetterChoice", nonterminal.Name);
107 | OrderedChoice orderedChoice = (OrderedChoice)nonterminal.Expression;
108 | Assert.AreEqual('a', ((CharacterTerminal)orderedChoice.Expressions[0]).Character);
109 | Assert.AreEqual('b', ((CharacterTerminal)orderedChoice.Expressions[1]).Character);
110 | }
111 |
112 | [Test]
113 | public void TestGrammar1NonterminalAndLetterChoice()
114 | {
115 | TestGrammar1 grammar = TestGrammar1.Create();
116 | Nonterminal nonterminal = grammar.GetNonterminal(o => o.NonterminalAndLetterChoice());
117 | Assert.AreEqual("NonterminalAndLetterChoice", nonterminal.Name);
118 | OrderedChoice orderedChoice = (OrderedChoice)nonterminal.Expression;
119 | Assert.AreEqual("LetterA", ((Nonterminal)orderedChoice.Expressions[0]).Name);
120 | Assert.AreEqual('b', ((CharacterTerminal)orderedChoice.Expressions[1]).Character);
121 | }
122 |
123 | [Test]
124 | public void TestGrammar1NonterminalAndNonterminalChoice()
125 | {
126 | TestGrammar1 grammar = TestGrammar1.Create();
127 | Nonterminal nonterminal = grammar.GetNonterminal(o => o.NonterminalAndNonterminalChoice());
128 | Assert.AreEqual("NonterminalAndNonterminalChoice", nonterminal.Name);
129 | OrderedChoice orderedChoice = (OrderedChoice)nonterminal.Expression;
130 | Assert.AreEqual("LetterA", ((Nonterminal)orderedChoice.Expressions[0]).Name);
131 | Assert.AreEqual("LetterB", ((Nonterminal)orderedChoice.Expressions[1]).Name);
132 | }
133 |
134 | [Test]
135 | public void TestGrammar1LetterSequence()
136 | {
137 | TestGrammar1 grammar = TestGrammar1.Create();
138 | Nonterminal nonterminal = grammar.GetNonterminal(o => o.LetterSequence());
139 | Assert.AreEqual("LetterSequence", nonterminal.Name);
140 | Sequence orderedChoice = (Sequence)nonterminal.Expression;
141 | Assert.AreEqual('a', ((CharacterTerminal)orderedChoice.Expressions[0]).Character);
142 | Assert.AreEqual('b', ((CharacterTerminal)orderedChoice.Expressions[1]).Character);
143 | }
144 |
145 | [Test]
146 | public void TestGrammar1NonterminalAndLetterSequence()
147 | {
148 | TestGrammar1 grammar = TestGrammar1.Create();
149 | Nonterminal nonterminal = grammar.GetNonterminal(o => o.NonterminalAndLetterSequence());
150 | Assert.AreEqual("NonterminalAndLetterSequence", nonterminal.Name);
151 | Sequence orderedChoice = (Sequence)nonterminal.Expression;
152 | Assert.AreEqual("LetterA", ((Nonterminal)orderedChoice.Expressions[0]).Name);
153 | Assert.AreEqual('b', ((CharacterTerminal)orderedChoice.Expressions[1]).Character);
154 | }
155 |
156 | [Test]
157 | public void TestGrammar1NonterminalAndNonterminalSequence()
158 | {
159 | TestGrammar1 grammar = TestGrammar1.Create();
160 | Nonterminal nonterminal = grammar.GetNonterminal(o => o.NonterminalAndNonterminalSequence());
161 | Assert.AreEqual("NonterminalAndNonterminalSequence", nonterminal.Name);
162 | Sequence orderedChoice = (Sequence)nonterminal.Expression;
163 | Assert.AreEqual("LetterA", ((Nonterminal)orderedChoice.Expressions[0]).Name);
164 | Assert.AreEqual("LetterB", ((Nonterminal)orderedChoice.Expressions[1]).Name);
165 | }
166 |
167 | [Test]
168 | public void TestGrammar1NotLetterA()
169 | {
170 | TestGrammar1 grammar = TestGrammar1.Create();
171 | Nonterminal nonterminal = grammar.GetNonterminal(o => o.NotLetterA());
172 | Assert.AreEqual("NotLetterA", nonterminal.Name);
173 | NotPredicate expression = (NotPredicate)nonterminal.Expression;
174 | Assert.AreEqual("LetterA", ((Nonterminal)expression.Operand).Name);
175 | }
176 |
177 | [Test]
178 | public void TestGrammarAndLetterA()
179 | {
180 | TestGrammar1 grammar = TestGrammar1.Create();
181 | Nonterminal nonterminal = grammar.GetNonterminal(o => o.AndLetterA());
182 | Assert.AreEqual("AndLetterA", nonterminal.Name);
183 | AndPredicate expression = (AndPredicate)nonterminal.Expression;
184 | Assert.AreEqual("LetterA", ((Nonterminal)expression.Operand).Name);
185 | }
186 |
187 | [Test]
188 | public void TestGrammarOneOrMoreLetterA()
189 | {
190 | TestGrammar1 grammar = TestGrammar1.Create();
191 | Nonterminal nonterminal = grammar.GetNonterminal(o => o.OneOrMoreLetterA());
192 | Assert.AreEqual("OneOrMoreLetterA", nonterminal.Name);
193 | OneOrMore expression = (OneOrMore)nonterminal.Expression;
194 | Assert.AreEqual("LetterA", ((Nonterminal)expression.Operand).Name);
195 | }
196 |
197 | [Test]
198 | public void TestGrammarZeroOrMoreLetterA()
199 | {
200 | TestGrammar1 grammar = TestGrammar1.Create();
201 | Nonterminal nonterminal = grammar.GetNonterminal(o => o.ZeroOrMoreLetterA());
202 | Assert.AreEqual("ZeroOrMoreLetterA", nonterminal.Name);
203 | ZeroOrMore expression = (ZeroOrMore)nonterminal.Expression;
204 | Assert.AreEqual("LetterA", ((Nonterminal)expression.Operand).Name);
205 | }
206 |
207 | [Test]
208 | public void TestGrammarOptionalLetterA()
209 | {
210 | TestGrammar1 grammar = TestGrammar1.Create();
211 | Nonterminal nonterminal = grammar.GetNonterminal(o => o.OptionalLetterA());
212 | Assert.AreEqual("OptionalLetterA", nonterminal.Name);
213 | Optional expression = (Optional)nonterminal.Expression;
214 | Assert.AreEqual("LetterA", ((Nonterminal)expression.Operand).Name);
215 | }
216 |
217 | [Test]
218 | public void TestGrammarTwoSequences()
219 | {
220 | TestGrammar1 grammar = TestGrammar1.Create();
221 | Nonterminal nonterminal = grammar.GetNonterminal(o => o.TwoSequences());
222 | Assert.AreEqual("TwoSequences", nonterminal.Name);
223 | OrderedChoice orderedChoice = (OrderedChoice)nonterminal.Expression;
224 | Sequence sequence1 = (Sequence)orderedChoice.Expressions[0];
225 | Sequence sequence2 = (Sequence)orderedChoice.Expressions[1];
226 | Assert.AreEqual("LetterA", ((Nonterminal)sequence1.Expressions[0]).Name);
227 | Assert.AreEqual("LetterB", ((Nonterminal)sequence1.Expressions[1]).Name);
228 | Assert.AreEqual("LetterB", ((Nonterminal)sequence2.Expressions[0]).Name);
229 | Assert.AreEqual("LetterA", ((Nonterminal)sequence2.Expressions[1]).Name);
230 | }
231 |
232 | [Test]
233 | public void TestGrammarThreeChoices()
234 | {
235 | TestGrammar1 grammar = TestGrammar1.Create();
236 | Nonterminal nonterminal = grammar.GetNonterminal(o => o.ThreeChoices());
237 | Assert.AreEqual("ThreeChoices", nonterminal.Name);
238 | OrderedChoice orderedChoice = (OrderedChoice)nonterminal.Expression;
239 | Assert.AreEqual("LetterA", ((Nonterminal)orderedChoice.Expressions[0]).Name);
240 | Assert.AreEqual("LetterB", ((Nonterminal)orderedChoice.Expressions[1]).Name);
241 | Assert.AreEqual('c', ((CharacterTerminal)orderedChoice.Expressions[2]).Character);
242 | }
243 |
244 | [Test]
245 | public void TestGrammarThreeExpressionSequence()
246 | {
247 | TestGrammar1 grammar = TestGrammar1.Create();
248 | Nonterminal nonterminal = grammar.GetNonterminal(o => o.ThreeExpressionSequence());
249 | Assert.AreEqual("ThreeExpressionSequence", nonterminal.Name);
250 | Sequence sequence = (Sequence)nonterminal.Expression;
251 | Assert.AreEqual("LetterA", ((Nonterminal)sequence.Expressions[0]).Name);
252 | Assert.AreEqual("LetterB", ((Nonterminal)sequence.Expressions[1]).Name);
253 | Assert.AreEqual('c', ((CharacterTerminal)sequence.Expressions[2]).Character);
254 | }
255 | }
256 | }
--------------------------------------------------------------------------------
/PEG.Tests/CppMacro/Macro.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Diagnostics.CodeAnalysis;
3 | using PEG.Builder;
4 |
5 | namespace PEG.Tests.CppMacro
6 | {
7 | [SuppressMessage("ReSharper", "ClassNeverInstantiated.Global")]
8 | [SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Global")]
9 | [SuppressMessage("ReSharper", "CollectionNeverUpdated.Global")]
10 | [SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
11 | public class Macro
12 | {
13 | private const string NullString = "";
14 | private static readonly PegParser parser = new PegParser(MacroGrammar.Create());
15 | public OrModel Or { get; set; }
16 |
17 | public static Macro Parse(string macro)
18 | {
19 | return parser.Parse(macro);
20 | }
21 |
22 | public override string ToString()
23 | {
24 | return Or?.ToString() ?? NullString;
25 | }
26 |
27 | public class AndModel
28 | {
29 | [Consume] public List PrimitiveCondition { get; set; }
30 |
31 | public override string ToString()
32 | {
33 | var value = string.Join(" && ", PrimitiveCondition);
34 | return PrimitiveCondition.Count > 1 ? $"({value})" : value;
35 | }
36 | }
37 |
38 | public class OrModel
39 | {
40 | [Consume] public List And { get; set; }
41 |
42 | public override string ToString()
43 | {
44 | var value = string.Join(" || ", And);
45 | return And.Count > 1 ? $"({value})" : value;
46 | }
47 | }
48 |
49 | public class PrimitiveConditionModel
50 | {
51 | public OrModel Or { get; set; }
52 | public NegateConditionModel NegateCondition { get; set; }
53 | public DefinedModel Defined { get; set; }
54 | public string Identifier { get; set; }
55 |
56 | public override string ToString()
57 | {
58 | return Identifier ?? Defined?.ToString() ?? NegateCondition?.ToString() ?? Or?.ToString() ?? NullString;
59 | }
60 | }
61 |
62 | public class DefinedModel
63 | {
64 | public IdentifierWrapModel IdentifierWrap { get; set; }
65 |
66 | public override string ToString()
67 | {
68 | return $"defined({IdentifierWrap})";
69 | }
70 | }
71 |
72 | public class NegateConditionModel
73 | {
74 | public OrModel Or { get; set; }
75 |
76 | public override string ToString()
77 | {
78 | return $"!({Or})";
79 | }
80 | }
81 |
82 | public class IdentifierWrapModel
83 | {
84 | public IdentifierWrapModel IdentifierWrap { get; set; }
85 | public string Identifier { get; set; }
86 |
87 | public override string ToString()
88 | {
89 | return Identifier ?? IdentifierWrap?.ToString() ?? NullString;
90 | }
91 | }
92 | }
93 | }
--------------------------------------------------------------------------------
/PEG.Tests/CppMacro/MacroGrammar.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics.CodeAnalysis;
2 | using PEG.SyntaxTree;
3 |
4 | namespace PEG.Tests.CppMacro
5 | {
6 | [SuppressMessage("ReSharper", "FunctionRecursiveOnAllPaths")]
7 | public class MacroGrammar : Grammar
8 | {
9 | ///
10 | /// You should always make the constructor private so that you never accidentally instantiate it directly.
11 | /// Always use the .Create() method inherited from Grammar. i.e. MacroGrammar.Create();
12 | ///
13 | private MacroGrammar()
14 | {
15 | }
16 |
17 | public virtual Expression Root()
18 | {
19 | return Or();
20 | }
21 |
22 | public virtual Expression And()
23 | {
24 | return PrimitiveCondition() + -("&&" + PrimitiveCondition());
25 | }
26 |
27 | public virtual Expression Or()
28 | {
29 | return And() + -("||" + And());
30 | }
31 |
32 | public virtual Expression PrimitiveCondition()
33 | {
34 | return ~Space() + (('(' + Or() + ')') | Defined() | NegateCondition() | Identifier()) + ~Space();
35 | }
36 |
37 | public virtual Expression NegateCondition()
38 | {
39 | return '!' + Or();
40 | }
41 |
42 | public virtual Expression Defined()
43 | {
44 | return ~Space() + "defined" + IdentifierWrap();
45 | }
46 |
47 | public virtual Expression IdentifierWrap()
48 | {
49 | return ~Space() + (('(' + IdentifierWrap() + ')') | Identifier()) + ~Space();
50 | }
51 |
52 | public virtual Expression Identifier()
53 | {
54 | return IdentifierStartChar() + -IdentifierChar();
55 | }
56 |
57 | public virtual Expression IdentifierChar()
58 | {
59 | return IdentifierStartChar() | '0'.To('9');
60 | }
61 |
62 | public virtual Expression IdentifierStartChar()
63 | {
64 | return 'a'.To('Z') | '_';
65 | }
66 |
67 | public virtual Expression Space()
68 | {
69 | return +(' '._() | '\r' | '\n' | '\t');
70 | }
71 | }
72 | }
--------------------------------------------------------------------------------
/PEG.Tests/CppMacro/MacroGrammarTest.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 |
3 | namespace PEG.Tests.CppMacro
4 | {
5 | [TestFixture]
6 | public class MacroGrammarTest
7 | {
8 | [Test]
9 | public void AndBuiltInIdentifier()
10 | {
11 | var macro = Macro.Parse("ASMJIT_CXX_CLANG && defined(__has_builtin)");
12 | Assert.AreEqual("(ASMJIT_CXX_CLANG && defined(__has_builtin))", macro.ToString());
13 | }
14 |
15 | [Test]
16 | public void AndNot()
17 | {
18 | var macro = Macro.Parse("defined(ASMJIT_NO_TEXT) && !defined(ASMJIT_NO_LOGGING)");
19 | Assert.AreEqual("(defined(ASMJIT_NO_TEXT) && !(defined(ASMJIT_NO_LOGGING)))", macro.ToString());
20 | }
21 |
22 | [Test]
23 | public void AndNotOr()
24 | {
25 | var macro = Macro.Parse(
26 | "(defined(_M_IX86) || defined(_M_AMD64) || defined(_M_ARM)) && !defined(MIDL_PASS)"
27 | );
28 | Assert.AreEqual(
29 | "((defined(_M_IX86) || defined(_M_AMD64) || defined(_M_ARM)) && !(defined(MIDL_PASS)))",
30 | macro.ToString()
31 | );
32 | }
33 |
34 | [Test]
35 | public void BuiltInIdentifier()
36 | {
37 | var macro = Macro.Parse("__cplusplus");
38 | Assert.AreEqual("__cplusplus", macro.ToString());
39 | }
40 |
41 | [Test]
42 | public void Defined()
43 | {
44 | var macro = Macro.Parse("defined(_WIN32)");
45 | Assert.AreEqual("defined(_WIN32)", macro.ToString());
46 | }
47 |
48 | [Test]
49 | public void DefinedSpace()
50 | {
51 | var macro = Macro.Parse("defined (_WIN64)");
52 | Assert.AreEqual("defined(_WIN64)", macro.ToString());
53 | }
54 | }
55 | }
--------------------------------------------------------------------------------
/PEG.Tests/EncloseTest.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 | using static PEG.Peg;
3 |
4 | namespace PEG.Tests
5 | {
6 | [TestFixture]
7 | public class EncloseTest
8 | {
9 | [Test]
10 | public void SimpleQuotes()
11 | {
12 | Assert.IsTrue('"'.Enclose(-Any).Match("\"Hello\""));
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/PEG.Tests/ExpressionExtensionsTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Linq.Expressions;
4 | using System.Reflection;
5 | using NUnit.Framework;
6 |
7 | namespace PEG.Tests
8 | {
9 | [TestFixture]
10 | public class ExpressionExtensionsTest
11 | {
12 | [Test]
13 | public void MatchString()
14 | {
15 | var pattern = +('a'.To('Z') | '.') + '@' + +('a'.To('Z') | '.');
16 |
17 | Assert.IsTrue(pattern.Match("john@test.com"));
18 | Assert.IsFalse(pattern.Match("john@test@com"));
19 | }
20 |
21 | [Test]
22 | public void ContainsString()
23 | {
24 | var pattern = +('a'.To('Z') | '.') + '@' + +('a'.To('Z') | '.');
25 |
26 | var pattern2 = +'0'.To('9');
27 | pattern2.Match("42");
28 |
29 | Assert.IsTrue(pattern.Contains("asdf john@test.com asfd asdf asdf asdf"));
30 | Assert.IsFalse(pattern.Contains("asdf john%test%com"));
31 | }
32 |
33 | [Test]
34 | public void Test()
35 | {
36 | var pattern = '"' + +(!('"'._() | @"\") + Peg.Any | @"\\" | @"\""") + '"';
37 |
38 | Assert.IsTrue(pattern.Match("\"value\""));
39 | Assert.IsTrue(pattern.Match("\"the \\\"quote\\\"\""));
40 | }
41 |
42 | ///
43 | /// Replace the month and day components.
44 | ///
45 | [Test]
46 | public void Replace()
47 | {
48 | var digit = ('0').To('9');
49 | var month = digit.Repeat(1, 2).Capture();
50 | var day = digit.Repeat(1, 2).Capture();
51 | var pattern = month + '/' + day + '/' + digit.Repeat(4);
52 |
53 | const string input = "12/1/2004";
54 | string result = pattern.Transform(input, month.To(day), day.To(month));
55 |
56 | Assert.AreEqual("1/12/2004", result);
57 | }
58 |
59 | ///
60 | /// Replace the month and day components.
61 | ///
62 | [Test]
63 | public void ReplaceAll()
64 | {
65 | var digit = ('0').To('9');
66 | var month = digit.Repeat(1, 2).Capture();
67 | var day = digit.Repeat(1, 2).Capture();
68 | var pattern = month + '/' + day + '/' + digit.Repeat(4);
69 |
70 | const string input = "12/1/2004 and 2/8/1988";
71 |
72 | string result = pattern.Replace(input, month.To(day), day.To(month));
73 |
74 | Assert.AreEqual("1/12/2004 and 8/2/1988", result);
75 | }
76 |
77 | [Test]
78 | public void ReplaceToString()
79 | {
80 | var digit = ('0').To('9');
81 | var month = digit.Repeat(1, 2).Capture();
82 | var day = digit.Repeat(1, 2).Capture();
83 | var pattern = month + '/' + day + '/' + digit.Repeat(4);
84 |
85 | const string input = "12/1/2004 and 2/8/1988";
86 |
87 | string result = pattern.Replace(input, month.To("MM"));
88 |
89 | Assert.AreEqual("MM/1/2004 and MM/8/1988", result);
90 | }
91 |
92 | [Test]
93 | public void Length()
94 | {
95 | var number = +'0'.To('9');
96 | var feet = number.Capture();
97 | var inches = number.Capture();
98 | var pattern = feet + '\'' + ~(-' '._() + inches + '\"');
99 |
100 | var results = pattern.Parse("5' 6\"");
101 | int feetResult = int.Parse(results[feet]);
102 | int inchesResult = int.Parse(results[inches]);
103 |
104 | Assert.AreEqual(5, feetResult);
105 | Assert.AreEqual(6, inchesResult);
106 | }
107 | }
108 | }
--------------------------------------------------------------------------------
/PEG.Tests/LambdaGrammarTest.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 |
3 | namespace PEG.Tests
4 | {
5 | [TestFixture]
6 | public class LambdaGrammarTest
7 | {
8 | [Test]
9 | public void Integer()
10 | {
11 | bool success = (+('0'.To('9'))).Match("12345");
12 | Assert.IsTrue(success);
13 | }
14 |
15 | [Test]
16 | public void Decimal()
17 | {
18 | var i = +('0'.To('9'));
19 | var d = i + ~('.' + i);
20 |
21 | Assert.IsTrue(d.Match("12345"));
22 | Assert.IsTrue(d.Match("1.2"));
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/PEG.Tests/Lengths/Length.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using PEG.SyntaxTree;
3 |
4 | namespace PEG.Samples.Lengths
5 | {
6 | public struct Length
7 | {
8 | public decimal Inches { get; private set; }
9 |
10 | private static LengthGrammar grammar = LengthGrammar.Create();
11 | private static PegParser parser = new PegParser(grammar, grammar.Start());
12 |
13 | public Length(decimal inches) : this()
14 | {
15 | Inches = inches;
16 | }
17 |
18 | public Length(int feet, decimal inches) : this()
19 | {
20 | Inches = feet * 12 + inches;
21 | }
22 |
23 | public decimal Feet
24 | {
25 | get { return Inches / 12; }
26 | }
27 |
28 | ///
29 | /// Valid measurement patterns:
30 | ///
31 | /// X' Y.Z" (feet, then inches in decimal)
32 | /// X'Y.Z" (feet, then inches in decimal without any space)
33 | /// X' Y.Z" (feet, then inches in decimal, multiple spaces)
34 | /// X.Z' (feet in decimal)
35 | /// Y.Z" (inches in decimal)
36 | /// X'Y" (feet, then inches)
37 | /// Y" (inches)
38 | ///
39 | public static bool TryParse(string s, out Length result)
40 | {
41 | ParsedLength parsedLength;
42 | int amountRead;
43 | if (!parser.Parse(s.Trim(), out parsedLength, out amountRead))
44 | {
45 | result = default(Length);
46 | return false;
47 | }
48 | result =
49 | parsedLength.IntegerFeet > 0 ? new Length(parsedLength.IntegerFeet, parsedLength.Inches) :
50 | parsedLength.DecimalFeet > 0 ? new Length(parsedLength.DecimalFeet * 12) :
51 | new Length(parsedLength.Inches);
52 | return true;
53 | }
54 |
55 | public static Length Parse(string s)
56 | {
57 | Length result;
58 | if (TryParse(s, out result))
59 | return result;
60 | else
61 | throw new Exception("Unable to parse length: " + s);
62 | }
63 |
64 | public class ParsedLength
65 | {
66 | public int IntegerFeet { get; set; }
67 | public decimal DecimalFeet { get; set; }
68 | public decimal Inches { get; set; }
69 | }
70 |
71 | public class LengthGrammar : Grammar
72 | {
73 | public virtual Expression Start()
74 | {
75 | return
76 | IntegerFeet() + OptionalWhitespace() + '\'' + OptionalWhitespace() + Inches() + OptionalWhitespace() + '"' |
77 | DecimalFeet() + OptionalWhitespace() + '\'' |
78 | Inches() + OptionalWhitespace() + '"';
79 | }
80 |
81 | public virtual Expression IntegerFeet()
82 | {
83 | return Integer();
84 | }
85 |
86 | public virtual Expression DecimalFeet()
87 | {
88 | return Decimal();
89 | }
90 |
91 | public virtual Expression Inches()
92 | {
93 | return Decimal();
94 | }
95 |
96 | public virtual Expression OptionalWhitespace()
97 | {
98 | return -' '._();
99 | }
100 |
101 | public virtual Expression Integer()
102 | {
103 | return +'0'.To('9');
104 | }
105 |
106 | public virtual Expression Decimal()
107 | {
108 | return Integer() + ~('.' + Integer());
109 | }
110 | }
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/PEG.Tests/Lengths/LengthTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 |
3 | namespace PEG.Samples.Lengths
4 | {
5 | [TestFixture]
6 | public class LengthTests
7 | {
8 | [Test]
9 | public void IntegerDecimal()
10 | {
11 | var s = "5.5'";
12 | var length = Length.Parse(s);
13 | Assert.AreEqual(5.5, length.Feet);
14 | }
15 |
16 | [Test]
17 | public void InchesInteger()
18 | {
19 | var s = "5\"";
20 | var length = Length.Parse(s);
21 | Assert.AreEqual(5, length.Inches);
22 | }
23 |
24 | [Test]
25 | public void FeetAndInchesInteger()
26 | {
27 | var s = "5' 4\"";
28 | var length = Length.Parse(s);
29 | Assert.AreEqual(64, length.Inches);
30 | }
31 | }
32 | }
--------------------------------------------------------------------------------
/PEG.Tests/PEG.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.2
5 | false
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/PEG.Tests/ParserTest.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 | using PEG.SyntaxTree;
3 |
4 | namespace PEG.Tests
5 | {
6 | [TestFixture]
7 | public class ParserTest
8 | {
9 | public class TestGrammar1 : Grammar
10 | {
11 | public virtual Expression LetterA()
12 | {
13 | return 'a';
14 | }
15 |
16 | public virtual Expression LetterB()
17 | {
18 | return 'b';
19 | }
20 |
21 | public virtual Expression LetterChoice()
22 | {
23 | return 'a'._() | 'b';
24 | }
25 |
26 | public virtual Expression NonterminalAndLetterChoice()
27 | {
28 | return LetterA() | 'b';
29 | }
30 |
31 | public virtual Expression NonterminalAndNonterminalChoice()
32 | {
33 | return LetterA() | LetterB();
34 | }
35 |
36 | public virtual Expression LetterSequence()
37 | {
38 | return 'a'._() + 'b';
39 | }
40 |
41 | public virtual Expression NonterminalAndLetterSequence()
42 | {
43 | return LetterA() + 'b';
44 | }
45 |
46 | public virtual Expression NonterminalAndNonterminalSequence()
47 | {
48 | return LetterA() + LetterB();
49 | }
50 |
51 | public virtual Expression NotLetterA()
52 | {
53 | return !LetterA();
54 | }
55 |
56 | public virtual Expression AndLetterA()
57 | {
58 | return LetterA().And();
59 | }
60 |
61 | public virtual Expression OneOrMoreLetterA()
62 | {
63 | return +LetterA();
64 | }
65 |
66 | public virtual Expression ZeroOrMoreLetterA()
67 | {
68 | return -LetterA();
69 | }
70 |
71 | public virtual Expression OptionalLetterA()
72 | {
73 | return ~LetterA();
74 | }
75 |
76 | public virtual Expression TwoSequences()
77 | {
78 | return LetterA() + LetterB() | LetterB() + LetterA();
79 | }
80 |
81 | public virtual Expression ThreeChoices()
82 | {
83 | return LetterA() | LetterB() | 'c';
84 | }
85 |
86 | public virtual Expression ThreeExpressionSequence()
87 | {
88 | return LetterA() + LetterB() + 'c';
89 | }
90 |
91 | public virtual Expression LeftRecursion()
92 | {
93 | return LeftRecursion() + LetterA() | LetterA();
94 | }
95 | }
96 |
97 | [Test]
98 | public void LetterA()
99 | {
100 | TestGrammar1 grammar = TestGrammar1.Create();
101 | PegParser parser = new PegParser(grammar, grammar.GetNonterminal(o => o.LetterA()));
102 | Assert.IsNotNull(parser.ParseString("a"));
103 | Assert.IsNull(parser.ParseString("b"));
104 | }
105 |
106 | [Test]
107 | public void LetterChoice()
108 | {
109 | TestGrammar1 grammar = TestGrammar1.Create();
110 | PegParser parser = new PegParser(grammar, grammar.GetNonterminal(o => o.LetterChoice()));
111 | Assert.IsNotNull(parser.ParseString("a"));
112 | Assert.IsNotNull(parser.ParseString("b"));
113 | Assert.IsNull(parser.ParseString("c"));
114 | }
115 |
116 | [Test]
117 | public void NonterminalAndLetterChoice()
118 | {
119 | TestGrammar1 grammar = TestGrammar1.Create();
120 | PegParser parser = new PegParser(grammar, grammar.GetNonterminal(o => o.NonterminalAndLetterChoice()));
121 | Assert.IsNotNull(parser.ParseString("a"));
122 | Assert.IsNotNull(parser.ParseString("b"));
123 | Assert.IsNull(parser.ParseString("c"));
124 | }
125 |
126 | [Test]
127 | public void NonterminalAndNonterminalChoice()
128 | {
129 | TestGrammar1 grammar = TestGrammar1.Create();
130 | PegParser parser = new PegParser(grammar, grammar.GetNonterminal(o => o.NonterminalAndNonterminalChoice()));
131 | Assert.IsNotNull(parser.ParseString("a"));
132 | Assert.IsNotNull(parser.ParseString("b"));
133 | Assert.IsNull(parser.ParseString("c"));
134 | }
135 |
136 | [Test]
137 | public void LetterSequence()
138 | {
139 | TestGrammar1 grammar = TestGrammar1.Create();
140 | PegParser parser = new PegParser(grammar, grammar.GetNonterminal(o => o.LetterSequence()));
141 | Assert.IsNotNull(parser.ParseString("ab"));
142 | Assert.IsNull(parser.ParseString("a"));
143 | Assert.IsNull(parser.ParseString("b"));
144 | }
145 |
146 | [Test]
147 | public void NotLetterA()
148 | {
149 | TestGrammar1 grammar = TestGrammar1.Create();
150 | PegParser parser = new PegParser(grammar, grammar.GetNonterminal(o => o.NotLetterA()));
151 | Assert.IsNull(parser.ParseString("a"));
152 | Assert.IsNotNull(parser.ParseString("b", false));
153 | }
154 |
155 | [Test]
156 | public void AndLetterA()
157 | {
158 | TestGrammar1 grammar = TestGrammar1.Create();
159 | PegParser parser = new PegParser(grammar, grammar.GetNonterminal(o => o.AndLetterA()));
160 | Assert.IsNotNull(parser.ParseString("a", false));
161 | Assert.IsNull(parser.ParseString("b"));
162 | }
163 |
164 | [Test]
165 | public void OneOrMoreLetterA()
166 | {
167 | TestGrammar1 grammar = TestGrammar1.Create();
168 | PegParser parser = new PegParser(grammar, grammar.GetNonterminal(o => o.OneOrMoreLetterA()));
169 | Assert.IsNotNull(parser.ParseString("a"));
170 | Assert.IsNotNull(parser.ParseString("aa"));
171 | Assert.IsNotNull(parser.ParseString("aaa"));
172 | Assert.IsNull(parser.ParseString("b"));
173 | Assert.IsNull(parser.ParseString(""));
174 | }
175 |
176 | [Test]
177 | public void ZeroOrMoreLetterA()
178 | {
179 | TestGrammar1 grammar = TestGrammar1.Create();
180 | PegParser parser = new PegParser(grammar, grammar.GetNonterminal(o => o.ZeroOrMoreLetterA()));
181 | Assert.IsNotNull(parser.ParseString(""));
182 | Assert.IsNotNull(parser.ParseString("a"));
183 | Assert.IsNotNull(parser.ParseString("aa"));
184 | Assert.IsNotNull(parser.ParseString("aaa"));
185 | }
186 |
187 | [Test]
188 | public void LeftRecursion()
189 | {
190 | TestGrammar1 grammar = TestGrammar1.Create();
191 | PegParser parser = new PegParser(grammar, grammar.GetNonterminal(o => o.LeftRecursion()));
192 | Assert.IsNotNull(parser.ParseString("a"));
193 | Assert.IsNotNull(parser.ParseString("aa"));
194 | Assert.IsNotNull(parser.ParseString("aaa"));
195 | }
196 | }
197 | }
--------------------------------------------------------------------------------
/PEG.Tests/QutoedStringTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using NUnit.Framework;
3 |
4 | namespace PEG.Tests
5 | {
6 | [TestFixture]
7 | public class QutoedStringTests
8 | {
9 | [Test]
10 | public void EscapedQuote()
11 | {
12 | var body = (-(!('"'._() | @"\") + Peg.Any | @"\\" | @"\""")).Capture();
13 | var pattern = '"' + body + '"';
14 |
15 | Console.WriteLine(pattern.Parse("\"abc\"")[body]);
16 | Console.WriteLine(pattern.Parse("\"a\\\"bc\"")[body]);
17 |
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/PEG.Tests/RepeatTests.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using NUnit.Framework;
3 | using PEG.SyntaxTree;
4 |
5 | namespace PEG.Tests
6 | {
7 | [TestFixture]
8 | public class RepeatTests
9 | {
10 | [Test]
11 | public void RepeatResets()
12 | {
13 | var grammar = TestGrammar.Create();
14 | var parser = new PegParser(grammar, grammar.Root());
15 | var input = "AAABBBBB";
16 | var result = parser.Parse(input);
17 | Assert.AreEqual(input, result.Items);
18 | }
19 |
20 | public class TestData
21 | {
22 | public string Items { get; set; }
23 | }
24 |
25 | public class TestGrammar : Grammar
26 | {
27 | public virtual Expression Root()
28 | {
29 | return Items();
30 | }
31 |
32 | public virtual Expression Items()
33 | {
34 | return -(A() | B());
35 | }
36 |
37 | public virtual Expression A()
38 | {
39 | return 'A'._().Repeat(4, 6);
40 | }
41 |
42 | public virtual Expression B()
43 | {
44 | return 'A'._() | 'B';
45 | }
46 | }
47 | }
48 | }
--------------------------------------------------------------------------------
/PEG.Tests/Url/Url.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Text;
3 |
4 | namespace PEG.Samples.Url
5 | {
6 | public class Url
7 | {
8 | public string Protocol { get; set; }
9 | public string Domain { get; set; }
10 | public string Port { get; set; }
11 | public string Path { get; set; }
12 | public List QueryString { get; set; }
13 |
14 | private static PegParser parser = new PegParser(UrlGrammar.Create());
15 |
16 | public static Url Parse(string url)
17 | {
18 | return parser.Parse(url);
19 | }
20 |
21 | public override string ToString()
22 | {
23 | StringBuilder builder = new StringBuilder(Protocol + "://" + Domain);
24 | if (Port != null)
25 | builder.Append(':' + Port);
26 | if (Path != null)
27 | builder.Append(Path);
28 | if (QueryString != null)
29 | {
30 | builder.Append('?');
31 | for (int i = 0; i < QueryString.Count; i++)
32 | {
33 | var nameValue = QueryString[i];
34 | builder.Append(nameValue.Name);
35 | builder.Append('=');
36 | builder.Append(nameValue.Value);
37 | if (i < QueryString.Count - 1)
38 | builder.Append('&');
39 | }
40 | }
41 | return builder.ToString();
42 | }
43 |
44 | public class NameValue
45 | {
46 | public string Name { get; set; }
47 | public string Value { get; set; }
48 | }
49 | }
50 | }
--------------------------------------------------------------------------------
/PEG.Tests/Url/UrlGrammar.cs:
--------------------------------------------------------------------------------
1 | using PEG.SyntaxTree;
2 |
3 | namespace PEG.Samples.Url
4 | {
5 | ///
6 | /// Provides the grammar for a URL
7 | ///
8 | public class UrlGrammar : Grammar
9 | {
10 | ///
11 | /// You should always make the constructor private so that you never accidentally instantiate it directly.
12 | /// Always use the .Create() method inherited from Grammar. i.e. UrlGrammar.Create();
13 | ///
14 | private UrlGrammar()
15 | {
16 | }
17 |
18 | public virtual Expression Url()
19 | {
20 | return Protocol() + "://" + Domain() + ~(':' + Port()) + ~(Path() + ~('?' + QueryString()));
21 | }
22 |
23 | public virtual Expression Protocol()
24 | {
25 | return "http"._() | "https";
26 | }
27 |
28 | public virtual Expression Domain()
29 | {
30 | return Domain() + '.' + DomainWord() | DomainWord();
31 | }
32 |
33 | public virtual Expression DomainWord()
34 | {
35 | return +('a'.To('z') | 'A'.To('Z') | '0'.To('9') | '-');
36 | }
37 |
38 | public virtual Expression Port()
39 | {
40 | return +('0'.To('9'));
41 | }
42 |
43 | public virtual Expression Path()
44 | {
45 | return +('/' + +('a'.To('z') | 'A'.To('Z') | '0'.To('9') | '.' | '_'));
46 | }
47 |
48 | public virtual Expression QueryString()
49 | {
50 | return NameValue() + -('&' + NameValue());
51 | }
52 |
53 | public virtual Expression NameValue()
54 | {
55 | return Name() + '=' + Value();
56 | }
57 |
58 | public virtual Expression Name()
59 | {
60 | return +('a'.To('z') | 'A'.To('Z') | '0'.To('9'));
61 | }
62 |
63 | public virtual Expression Value()
64 | {
65 | return -('a'.To('z') | 'A'.To('Z') | '0'.To('9') | '%');
66 | }
67 | }
68 | }
--------------------------------------------------------------------------------
/PEG.Tests/Url/UrlGrammarTest.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 |
3 | namespace PEG.Samples.Url
4 | {
5 | [TestFixture]
6 | public class UrlGrammarTest
7 | {
8 | [Test]
9 | public void JustDomain()
10 | {
11 | Url url = Url.Parse("http://test.com");
12 | Assert.AreEqual("test.com", url.Domain);
13 | }
14 |
15 | [Test]
16 | public void DomainAndPort()
17 | {
18 | Url url = Url.Parse("http://test.com:433");
19 | Assert.AreEqual("test.com", url.Domain);
20 | Assert.AreEqual("433", url.Port);
21 | }
22 |
23 | [Test]
24 | public void DomainAndPortAndFile()
25 | {
26 | Url url = Url.Parse("http://test.com:433/Test.txt");
27 | Assert.AreEqual("test.com", url.Domain);
28 | Assert.AreEqual("433", url.Port);
29 | Assert.AreEqual("/Test.txt", url.Path);
30 | }
31 |
32 | [Test]
33 | public void DomainAndFile()
34 | {
35 | Url url = Url.Parse("http://test.com/Test.txt");
36 | Assert.AreEqual("test.com", url.Domain);
37 | Assert.AreEqual("/Test.txt", url.Path);
38 | }
39 |
40 | [Test]
41 | public void DomainAndFileQueryString()
42 | {
43 | Url url = Url.Parse("http://test.com/Test.txt?name1=value1");
44 | Assert.AreEqual("test.com", url.Domain);
45 | Assert.AreEqual("/Test.txt", url.Path);
46 | Assert.AreEqual("name1", url.QueryString[0].Name);
47 | Assert.AreEqual("value1", url.QueryString[0].Value);
48 | }
49 |
50 | [Test]
51 | public void DomainAndFileQueryString2()
52 | {
53 | Url url = Url.Parse("http://test.com/Test.txt?name1=value1&name2=value2");
54 | Assert.AreEqual("test.com", url.Domain);
55 | Assert.AreEqual("/Test.txt", url.Path);
56 | Assert.AreEqual("name1", url.QueryString[0].Name);
57 | Assert.AreEqual("value1", url.QueryString[0].Value);
58 | Assert.AreEqual("name2", url.QueryString[1].Name);
59 | Assert.AreEqual("value2", url.QueryString[1].Value);
60 | }
61 | }
62 | }
--------------------------------------------------------------------------------
/PEG.Tests/Xml/XmlGrammar.cs:
--------------------------------------------------------------------------------
1 | using PEG.SyntaxTree;
2 |
3 | namespace PEG.Samples.Xml
4 | {
5 | public class XmlGrammar : Grammar
6 | {
7 | private XmlGrammar()
8 | {
9 | }
10 |
11 | public virtual Expression Symbol()
12 | {
13 | return Element() |
14 | Text();
15 | }
16 |
17 | public virtual Expression Element()
18 | {
19 | return ElementStart() + -Symbol() + ElementEnd() |
20 | ElementClosed();
21 | }
22 |
23 | public virtual Expression ElementStart()
24 | {
25 | return '<' + ElementHead() + '>';
26 | }
27 |
28 | public virtual Expression ElementClosed()
29 | {
30 | return '<' + ElementHead() + "/>";
31 | }
32 |
33 | public virtual Expression ElementEnd()
34 | {
35 | return "" + QualifiableName() + '>';
36 | }
37 |
38 | public virtual Expression Text()
39 | {
40 | return !'<'._() + Any;
41 | }
42 |
43 | public virtual Expression ElementHead()
44 | {
45 | return ~WS() + QualifiableName() + Attributes() + ~WS();
46 | }
47 |
48 | public virtual Expression Attributes()
49 | {
50 | return -Attribute();
51 | }
52 |
53 | public virtual Expression Attribute()
54 | {
55 | return ' ' + QualifiableName() + ~WS() + '=' + ~WS() + AttributeValuePart();
56 | }
57 |
58 | public virtual Expression AttributeValuePart()
59 | {
60 | return '"' + DoubleQuoteAttributeValue() + '"' |
61 | '\'' + SingleQuoteAttributeValue() + '\'';
62 | }
63 |
64 | public virtual Expression DoubleQuoteAttributeValue()
65 | {
66 | return -DoubleQuoteAttributeValueChar();
67 | }
68 |
69 | public virtual Expression SingleQuoteAttributeValue()
70 | {
71 | return -SingleQuoteAttributeValueChar();
72 | }
73 |
74 | public virtual Expression DoubleQuoteAttributeValueChar()
75 | {
76 | return !('"'._() | '\\') + Any | "\\\"" | "\\\\";
77 | }
78 |
79 | public virtual Expression SingleQuoteAttributeValueChar()
80 | {
81 | return !('\''._() | '\\') + Any | "\\\'" | "\\\\";
82 | }
83 |
84 | public virtual Expression QualifiableName()
85 | {
86 | return ~(Prefix() + ':') + Identifier();
87 | }
88 |
89 | public virtual Expression Prefix()
90 | {
91 | return Identifier();
92 | }
93 |
94 | public virtual Expression Identifier()
95 | {
96 | return IdentifierStartChar() + -IdentifierChar();
97 | }
98 |
99 | public virtual Expression IdentifierChar()
100 | {
101 | return IdentifierStartChar() | '0'.To('9') | '-';
102 | }
103 |
104 | public virtual Expression IdentifierStartChar()
105 | {
106 | return 'a'.To('Z');
107 | }
108 |
109 | public virtual Expression WS()
110 | {
111 | return +(' '._() | '\r' | '\n' | '\t');
112 | }
113 | }
114 | }
--------------------------------------------------------------------------------
/PEG.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.29020.237
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PEG", "PEG\PEG.csproj", "{716F258F-FEC8-4836-AE98-151727E584E8}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PEG.Tests", "PEG.Tests\PEG.Tests.csproj", "{572B9375-2FE3-489F-86E1-425E39AC6D74}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Release|Any CPU = Release|Any CPU
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {716F258F-FEC8-4836-AE98-151727E584E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17 | {716F258F-FEC8-4836-AE98-151727E584E8}.Debug|Any CPU.Build.0 = Debug|Any CPU
18 | {716F258F-FEC8-4836-AE98-151727E584E8}.Release|Any CPU.ActiveCfg = Release|Any CPU
19 | {716F258F-FEC8-4836-AE98-151727E584E8}.Release|Any CPU.Build.0 = Release|Any CPU
20 | {572B9375-2FE3-489F-86E1-425E39AC6D74}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {572B9375-2FE3-489F-86E1-425E39AC6D74}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {572B9375-2FE3-489F-86E1-425E39AC6D74}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {572B9375-2FE3-489F-86E1-425E39AC6D74}.Release|Any CPU.Build.0 = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {8914B0DE-3A4A-4279-BB04-2F211C866EB3}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/PEG.sln.DotSettings:
--------------------------------------------------------------------------------
1 |
2 | DO_NOT_SHOW
3 | DO_NOT_SHOW
4 | DO_NOT_SHOW
5 | DO_NOT_SHOW
6 | DO_NOT_SHOW
7 | DO_NOT_SHOW
8 | DO_NOT_SHOW
9 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
--------------------------------------------------------------------------------
/PEG.sln.DotSettings.user:
--------------------------------------------------------------------------------
1 |
2 | True
--------------------------------------------------------------------------------
/PEG/Builder/AstAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace PEG.Builder
4 | {
5 | public enum AstStructure
6 | {
7 | RecursiveList
8 | }
9 |
10 | [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
11 | public class AstAttribute : Attribute
12 | {
13 | public Type Type { get; set; }
14 | public string Condition { get; set; }
15 | public AstStructure Structure { get; set; }
16 |
17 | public AstAttribute(string expression)
18 | {
19 | Condition = expression;
20 | }
21 |
22 | public AstAttribute(Type type)
23 | {
24 | Type = type;
25 | }
26 |
27 | public AstAttribute(string condition, Type type)
28 | {
29 | Condition = condition;
30 | Type = type;
31 | }
32 |
33 | public AstAttribute(Type type, AstStructure structure, string expression)
34 | {
35 | Type = type;
36 | Condition = expression;
37 | Structure = structure;
38 | }
39 |
40 | public ConsumeExpression GetExpression()
41 | {
42 | return Condition != null ? ConsumeExpressionCache.Get(Condition) : null;
43 | }
44 | }
45 | }
--------------------------------------------------------------------------------
/PEG/Builder/ConsumeAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace PEG.Builder
4 | {
5 | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = true)]
6 | public class ConsumeAttribute : Attribute
7 | {
8 | public string Expression { get; set; }
9 |
10 | public object Value { get; set; }
11 |
12 | public Type Type { get; set; }
13 |
14 | public Type Converter { get; set; }
15 |
16 | public object ConverterArgs { get; set; }
17 |
18 | public int Production { get; set; }
19 |
20 | public ConsumeAttribute()
21 | {
22 | }
23 |
24 | public ConsumeAttribute(string expression)
25 | : this()
26 | {
27 | Expression = expression;
28 | }
29 |
30 | public ConsumeAttribute(string expression, Type valueType)
31 | : this()
32 | {
33 | Expression = expression;
34 | Type = valueType;
35 | }
36 |
37 | public ConsumeAttribute(int production)
38 | {
39 | Production = production;
40 | }
41 |
42 | public ConsumeExpression GetExpression()
43 | {
44 | return Expression != null ? ConsumeExpressionCache.Get(Expression) : null;
45 | }
46 | }
47 | }
--------------------------------------------------------------------------------
/PEG/Builder/ConsumeChoice.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using PEG.Cst;
4 |
5 | namespace PEG.Builder
6 | {
7 | public class ConsumeChoice : ConsumeExpression
8 | {
9 | public List Choices { get; set; }
10 |
11 | public ConsumeChoice()
12 | {
13 | Choices = new List();
14 | }
15 |
16 | public override IEnumerable Resolve(ICstNonterminalNode node)
17 | {
18 | IEnumerable result = new ICstNode[0];
19 | foreach (ConsumeExpression choice in Choices)
20 | {
21 | result = result.Concat(choice.Resolve(node));
22 | }
23 | bool anyNull = result.Contains(null);
24 | return result.Cast().OrderBy(o => o.AbsoluteIndex).Cast();
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/PEG/Builder/ConsumeConditional.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using PEG.Cst;
3 |
4 | namespace PEG.Builder
5 | {
6 | public class ConsumeConditional : ConsumeExpression
7 | {
8 | [Consume("expression[1]")]
9 | public ConsumeExpression Predicate { get; set; }
10 |
11 | [Consume("expression[2]")]
12 | public ConsumeExpression Expression { get; set; }
13 |
14 | public override IEnumerable Resolve(ICstNonterminalNode node)
15 | {
16 | if (Predicate == null || Predicate.Resolve(node) != null)
17 | return Expression.Resolve(node);
18 | else
19 | return new ICstNode[0];
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/PEG/Builder/ConsumeExpression.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using PEG.Cst;
4 |
5 | namespace PEG.Builder
6 | {
7 | [Consume("expression")]
8 | public abstract class ConsumeExpression
9 | {
10 | public abstract IEnumerable Resolve(ICstNonterminalNode node);
11 |
12 | public string ResolveAsString(ICstNonterminalNode node)
13 | {
14 | var result = Resolve(node);
15 | if (result.Any())
16 | return result.First().Coalesce();
17 | else
18 | return null;
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/PEG/Builder/ConsumeExpressionCache.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace PEG.Builder
4 | {
5 | public class ConsumeExpressionCache
6 | {
7 | private static Dictionary cache = new Dictionary();
8 | private static object lockObject = new object();
9 |
10 | public static ConsumeExpression Get(string expression)
11 | {
12 | ConsumeExpression result;
13 | bool found;
14 | lock (lockObject)
15 | {
16 | found = cache.TryGetValue(expression, out result);
17 | }
18 | if (!found)
19 | {
20 | result = ConsumeExpressionParsing.Parse(expression);
21 | lock (lockObject)
22 | {
23 | cache[expression] = result;
24 | }
25 | }
26 | return result;
27 | }
28 | }
29 | }
--------------------------------------------------------------------------------
/PEG/Builder/ConsumeExpressionParsing.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using PEG.Cst;
3 | using PEG.SyntaxTree;
4 |
5 | namespace PEG.Builder
6 | {
7 | public class ConsumeExpressionParsing : Grammar
8 | {
9 | public virtual Expression Choice()
10 | {
11 | return Choice() + ~WS() + '|' + ~WS() + Conditional() | Conditional();
12 | }
13 |
14 | public virtual Expression Conditional()
15 | {
16 | return Expression() | Expression() + ~WS() + ':' + ~WS() + Expression();
17 | }
18 |
19 | public virtual Expression Expression()
20 | {
21 | return IndexExpression() | ReferenceExpression();
22 | }
23 |
24 | public virtual Expression IndexExpression()
25 | {
26 | return Expression() + ~WS() + '[' + ~WS() + Number() + ~WS() + ']';
27 | }
28 |
29 | public virtual Expression ReferenceExpression()
30 | {
31 | return Expression() + '.' + Identifier() | Identifier();
32 | }
33 |
34 | public virtual Expression Identifier()
35 | {
36 | return IdentifierStartChar() + -IdentifierChar();
37 | }
38 |
39 | public virtual Expression IdentifierChar()
40 | {
41 | return IdentifierStartChar() | Digit() | '-';
42 | }
43 |
44 | public virtual Expression IdentifierStartChar()
45 | {
46 | return 'a'.To('z') | 'A'.To('Z');
47 | }
48 |
49 | public virtual Expression Digit()
50 | {
51 | return '0'.To('9');
52 | }
53 |
54 | public virtual Expression Number()
55 | {
56 | return +Digit();
57 | }
58 |
59 | public virtual Expression WS()
60 | {
61 | return +WhitespaceChar();
62 | }
63 |
64 | public virtual Expression WhitespaceChar()
65 | {
66 | return ' ';
67 | }
68 |
69 | public static ConsumeExpressionParsing Grammar = Create();
70 | public static PegParser Parser = new PegParser(Grammar, Grammar.Choice());
71 | // public static PegBuilder Builder = new PegBuilder(Grammar);
72 |
73 | public static ConsumeExpression Parse(string s)
74 | {
75 | var result = Parser.ParseString(s);
76 |
77 | // Bypass BnfBuilder because that depends on this in order to work
78 | CstNonterminalNode cst = CstBuilder.Build(result);
79 | return BuildChoice(cst);
80 | }
81 |
82 | private static ConsumeChoice BuildChoice(CstNonterminalNode node)
83 | {
84 | ConsumeChoice result = new ConsumeChoice();
85 | CstNonterminalNode current = node;
86 | while (current != null)
87 | {
88 | if (current.Children.Count == 1)
89 | {
90 | result.Choices.Insert(0, BuildConditional((CstNonterminalNode)current.Children[0]));
91 | current = null;
92 | }
93 | else
94 | {
95 | result.Choices.Insert(0, BuildConditional((CstNonterminalNode)current.Children[2]));
96 | current = (CstNonterminalNode)current.Children[0];
97 | }
98 | }
99 | return result;
100 | }
101 |
102 | private static ConsumeConditional BuildConditional(CstNonterminalNode node)
103 | {
104 | CstNonterminalNode predicate;
105 | CstNonterminalNode expression;
106 | if (node.Children.Count == 1)
107 | {
108 | predicate = null;
109 | expression = (CstNonterminalNode)node.Children[0];
110 | }
111 | else
112 | {
113 | predicate = (CstNonterminalNode)node.Children[0];
114 | expression = (CstNonterminalNode)node.Children[2];
115 | }
116 | ConsumeConditional conditional = new ConsumeConditional();
117 | if (predicate != null)
118 | conditional.Predicate = BuildExpression(predicate);
119 | conditional.Expression = BuildExpression(expression);
120 | return conditional;
121 | }
122 |
123 | private static ConsumeExpression BuildExpression(CstNonterminalNode node)
124 | {
125 | CstNonterminalNode expressionType = (CstNonterminalNode)node.Children[0];
126 | if (expressionType.Nonterminal.Name == "Expression")
127 | expressionType = (CstNonterminalNode)expressionType.Children[0];
128 | switch (expressionType.Nonterminal.Name)
129 | {
130 | case "ReferenceExpression":
131 | return BuildReferenceExpression(expressionType);
132 | case "IndexExpression":
133 | return BuildIndexExpression(expressionType);
134 | default:
135 | throw new InvalidOperationException();
136 | }
137 | }
138 |
139 | private static ConsumeReferenceExpression BuildReferenceExpression(CstNonterminalNode node)
140 | {
141 | ConsumeReferenceExpression expression = new ConsumeReferenceExpression();
142 | if (node.Children.Count == 1)
143 | {
144 | // CstNonterminalNode nonterminal = (CstNonterminalNode)((Token)((ICstTerminalNode)node.Children[0]).Terminal).StructuredLexeme;
145 | expression.NonTerminal = node.Children[0].Coalesce();
146 | }
147 | else
148 | {
149 | CstNonterminalNode targetNode = (CstNonterminalNode)node.Children[0];
150 | ConsumeExpression target = BuildExpression(targetNode);
151 | expression.Target = target;
152 |
153 | // CstNonterminalNode nonterminal = (CstNonterminalNode)((Token)((ICstTerminalNode)node.Children[2]).Terminal).StructuredLexeme;
154 | expression.NonTerminal = node.Children[2].Coalesce();//nonterminal.Coalesce();
155 | }
156 | return expression;
157 | }
158 |
159 | private static ConsumeIndexExpression BuildIndexExpression(CstNonterminalNode node)
160 | {
161 | ConsumeIndexExpression expression = new ConsumeIndexExpression();
162 |
163 | CstNonterminalNode targetNode = (CstNonterminalNode)node.Children[0];
164 | expression.Target = BuildExpression(targetNode);
165 |
166 | // CstNonterminalNode indexNode = (CstNonterminalNode)((Token)((ICstTerminalNode)node.Children[2]).Terminal).StructuredLexeme;
167 | expression.Index = int.Parse(node.Children[2].Coalesce());
168 |
169 | return expression;
170 | }
171 | }
172 | }
--------------------------------------------------------------------------------
/PEG/Builder/ConsumeIndexExpression.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using PEG.Cst;
5 | using PEG.Extensions;
6 |
7 | namespace PEG.Builder
8 | {
9 | [Consume("index-expression")]
10 | public class ConsumeIndexExpression : ConsumeExpression
11 | {
12 | [Consume("expression")]
13 | public ConsumeExpression Target { get; set; }
14 |
15 | [Consume("number")]
16 | public int Index { get; set; }
17 |
18 | public override string ToString()
19 | {
20 | return Target.ToString() + '[' + Index + ']';
21 | }
22 |
23 | public override IEnumerable Resolve(ICstNonterminalNode node)
24 | {
25 | if (Index < 1)
26 | throw new InvalidOperationException("Indices in consume attributes are 1-based: " + this);
27 |
28 | ConsumeReferenceExpression targetAsReference = (ConsumeReferenceExpression)Target;
29 | Func ret = cstNode => cstNode.Children.OfType().Where(o => o.Nonterminal.Name == targetAsReference.NonTerminal).ElementAtOrDefault(Index - 1);
30 | IEnumerable result = new ICstNode[0];
31 |
32 | if (targetAsReference.Target != null)
33 | foreach (ICstNonterminalNode child in targetAsReference.Target.Resolve(node))
34 | {
35 | if (child != null)
36 | {
37 | ICstNode element = ret(child);
38 | if (element != null)
39 | result = result.Union(element);
40 | }
41 | }
42 | else
43 | {
44 | ICstNode element = ret(node);
45 | if (element != null)
46 | result = result.Union(element);
47 | }
48 |
49 | return result;
50 | }
51 | }
52 | }
--------------------------------------------------------------------------------
/PEG/Builder/ConsumeReferenceExpression.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using PEG.Cst;
6 |
7 | namespace PEG.Builder
8 | {
9 | [Consume("reference-expression")]
10 | public class ConsumeReferenceExpression : ConsumeExpression
11 | {
12 | [Consume("expression")]
13 | public ConsumeExpression Target { get; set; }
14 |
15 | [Consume("identifier")]
16 | public string NonTerminal { get; set; }
17 |
18 | public override string ToString()
19 | {
20 | StringBuilder result = new StringBuilder();
21 | if (Target != null)
22 | {
23 | result.Append(Target);
24 | result.Append('.');
25 | }
26 | result.Append(NonTerminal);
27 | return result.ToString();
28 | }
29 |
30 | public override IEnumerable Resolve(ICstNonterminalNode node)
31 | {
32 | Func> ret = cstNode => cstNode.Children.OfType().Where(o => o.Nonterminal.Name == NonTerminal).Cast();
33 | IEnumerable result = new ICstNode[0];
34 | if (Target != null)
35 | {
36 | foreach (ICstNonterminalNode current in Target.Resolve(node))
37 | {
38 | result = result.Concat(ret(current));
39 | }
40 | }
41 | else
42 | {
43 | result = result.Concat(ret(node));
44 | }
45 | return result;
46 | }
47 | }
48 | }
--------------------------------------------------------------------------------
/PEG/Cst/CstBuilder.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using PEG.SyntaxTree;
4 |
5 | namespace PEG.Cst
6 | {
7 | public static class CstBuilder
8 | {
9 | public static CstNonterminalNode Build(IEnumerable outputStream)
10 | {
11 | if (outputStream == null || !outputStream.Any())
12 | return null;
13 |
14 | Stack stack = new Stack();
15 |
16 | int absoluteIndex = 0;
17 | CstNonterminalNode current = new CstNonterminalNode(null, absoluteIndex);
18 |
19 | foreach (OutputRecord output in outputStream)
20 | {
21 | switch (output.OutputType)
22 | {
23 | case OutputType.None:
24 | current.Children.Add((Terminal)output.Expression);
25 | break;
26 | case OutputType.Begin:
27 | CstNonterminalNode nonterminalNode = new CstNonterminalNode((Nonterminal)output.Expression, ++absoluteIndex);
28 | stack.Push(current);
29 | current = nonterminalNode;
30 | break;
31 | case OutputType.End:
32 | CstNonterminalNode node = current;
33 | current = stack.Pop();
34 | current.Children.Add(node);
35 | break;
36 | }
37 | }
38 |
39 | return current;
40 | }
41 | }
42 | }
--------------------------------------------------------------------------------
/PEG/Cst/CstCache.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using PEG.SyntaxTree;
4 |
5 | namespace PEG.Cst
6 | {
7 | public class CstCache
8 | {
9 | public Dictionary> cache = new Dictionary>();
10 |
11 | public CstCache(CstNonterminalNode node)
12 | {
13 | ScanNonterminal(node);
14 | }
15 |
16 | public List this[Nonterminal nonterminal]
17 | {
18 | get
19 | {
20 | List list;
21 | cache.TryGetValue(nonterminal, out list);
22 | return list;
23 | }
24 | }
25 |
26 | private void Cache(CstNonterminalNode node)
27 | {
28 | List list;
29 | if (!cache.TryGetValue(node.Nonterminal, out list))
30 | {
31 | list = new List();
32 | cache[node.Nonterminal] = list;
33 | }
34 | list.Add(node);
35 | }
36 |
37 | private void ScanNonterminal(CstNonterminalNode node)
38 | {
39 | Cache(node);
40 |
41 | foreach (var child in node.Children)
42 | {
43 | if (child is CstNonterminalNode)
44 | ScanNonterminal((CstNonterminalNode)child);
45 | }
46 | }
47 | }
48 | }
--------------------------------------------------------------------------------
/PEG/Cst/CstNonterminalNode.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using PEG.SyntaxTree;
6 |
7 | namespace PEG.Cst
8 | {
9 | public class CstNonterminalNode : ICstNonterminalNode
10 | {
11 | public int AbsoluteIndex { get; private set; }
12 | public Nonterminal Nonterminal { get; private set; }
13 | public List Children { get; private set; }
14 |
15 | public CstNonterminalNode(Nonterminal nonterminal, int absoluteIndex)
16 | {
17 | Nonterminal = nonterminal;
18 | Children = new List();
19 | AbsoluteIndex = absoluteIndex;
20 | }
21 |
22 | public ICstNode Transform(Func transformer)
23 | {
24 | ICstNode result = transformer(this);
25 | if (result == null)
26 | {
27 | result = new CstNonterminalNode(Nonterminal, -1);
28 |
29 | foreach (var child in Children)
30 | {
31 | if (child is CstNonterminalNode)
32 | {
33 | var nonterminalChild = (CstNonterminalNode)child;
34 | ((CstNonterminalNode)result).Children.Add(nonterminalChild.Transform(transformer));
35 | }
36 | else
37 | ((CstNonterminalNode)result).Children.Add(child);
38 | }
39 | }
40 | return result;
41 | }
42 |
43 | public override string ToString()
44 | {
45 | return Nonterminal != null ? Nonterminal.Name : "Root";
46 | }
47 |
48 | public string Coalesce()
49 | {
50 | StringBuilder builder = new StringBuilder();
51 | foreach (ICstNode child in Children)
52 | {
53 | builder.Append(child.Coalesce());
54 | }
55 | return builder.ToString();
56 | }
57 |
58 | public IEnumerable FindAllNonterminalNodes()
59 | {
60 | Stack nodes = new Stack();
61 | nodes.Push(this);
62 |
63 | while (nodes.Any())
64 | {
65 | var node = nodes.Pop();
66 | var nonterminalNode = node as ICstNonterminalNode;
67 |
68 | if (nonterminalNode != null)
69 | {
70 | yield return nonterminalNode;
71 |
72 | foreach (var child in nonterminalNode.Children)
73 | nodes.Push(child);
74 | }
75 | }
76 | }
77 | }
78 | }
--------------------------------------------------------------------------------
/PEG/Cst/CstString.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace PEG.Cst
4 | {
5 | public class CstString : ICstNode
6 | {
7 | private string s;
8 |
9 | public CstString(string s)
10 | {
11 | this.s = s;
12 | }
13 |
14 | public string Coalesce()
15 | {
16 | return s;
17 | }
18 | }
19 | }
--------------------------------------------------------------------------------
/PEG/Cst/ICstNode.cs:
--------------------------------------------------------------------------------
1 | namespace PEG.Cst
2 | {
3 | public interface ICstNode
4 | {
5 | string Coalesce();
6 | }
7 | }
--------------------------------------------------------------------------------
/PEG/Cst/ICstNonterminalNode.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using PEG.SyntaxTree;
3 |
4 | namespace PEG.Cst
5 | {
6 | public interface ICstNonterminalNode : ICstNode
7 | {
8 | int AbsoluteIndex { get; }
9 | Nonterminal Nonterminal { get; }
10 | List Children { get; }
11 | }
12 | }
--------------------------------------------------------------------------------
/PEG/Cst/ICstTerminalNode.cs:
--------------------------------------------------------------------------------
1 | using PEG.SyntaxTree;
2 |
3 | namespace PEG.Cst
4 | {
5 | public interface ICstTerminalNode : ICstNode
6 | {
7 | Terminal Terminal { get; }
8 | }
9 | }
--------------------------------------------------------------------------------
/PEG/ExpressionCompiler.cs:
--------------------------------------------------------------------------------
1 | using PEG.SyntaxTree;
2 |
3 | namespace PEG
4 | {
5 | public class ExpressionCompiler : ExpressionWalker