Skip to content

Commit e098de2

Browse files
authored
Merge pull request #548 from b3b00/feature/clause-repetition
Feature/clause repetition
2 parents 091f124 + deed5cd commit e098de2

File tree

11 files changed

+668
-45
lines changed

11 files changed

+668
-45
lines changed

src/sly/parser/fluent/FluentRuleParser.cs

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,11 @@ public IFluentLexerBuilder<EbnfTokenGeneric> GetEbnfLexerBuilder()
2323
.Sugar(EbnfTokenGeneric.OR, "|")
2424
.Sugar(EbnfTokenGeneric.LCROG, "[")
2525
.Sugar(EbnfTokenGeneric.RCROG, "]")
26-
.String(EbnfTokenGeneric.STRING, "'", "\\");
26+
.String(EbnfTokenGeneric.STRING, "'", "\\")
27+
.Sugar(EbnfTokenGeneric.DASH, "-")
28+
.Sugar(EbnfTokenGeneric.LCURLY, "{")
29+
.Sugar(EbnfTokenGeneric.RCURLY, "}")
30+
.Int(EbnfTokenGeneric.INT);
2731
return builder;
2832
}
2933

@@ -54,6 +58,43 @@ public BuildResult<Parser<EbnfTokenGeneric, GrammarNode<IN, OUT>>> BuildParser(s
5458
return instance.OneMoreClause((Token<EbnfTokenGeneric>)args[0],
5559
(Token<EbnfTokenGeneric>)args[1]);
5660
}))
61+
.Production("clause : IDENTIFIER LCURLY INT DASH INT RCURLY",
62+
(args =>
63+
{
64+
return instance.RepeatClauseMinMax(
65+
((Token<EbnfTokenGeneric>)args[0]),
66+
((Token<EbnfTokenGeneric>)args[1]),
67+
((Token<EbnfTokenGeneric>)args[2]) ,
68+
((Token<EbnfTokenGeneric>)args[3]),
69+
(Token<EbnfTokenGeneric>)args[4],
70+
((Token<EbnfTokenGeneric>)args[5])
71+
);
72+
}))
73+
.Production("clause : IDENTIFIER LCURLY INT RCURLY",
74+
(args =>
75+
{
76+
return instance.RepeatClause(
77+
((Token<EbnfTokenGeneric>)args[0]),
78+
((Token<EbnfTokenGeneric>)args[1]) ,
79+
((Token<EbnfTokenGeneric>)args[2]),
80+
((Token<EbnfTokenGeneric>)args[3])
81+
);
82+
}))
83+
.Production("clause : LPAREN groupclauses RPAREN LCURLY INT DASH INT RCURLY",
84+
args =>
85+
{
86+
return instance.GroupRepeatRange((Token<EbnfTokenGeneric>) args[0],(GroupClause<IN,OUT>) args[1],
87+
(Token<EbnfTokenGeneric>) args[2],(Token<EbnfTokenGeneric>) args[3],
88+
(Token<EbnfTokenGeneric>) args[4],(Token<EbnfTokenGeneric>) args[5],
89+
(Token<EbnfTokenGeneric>) args[6], (Token<EbnfTokenGeneric>) args[7]);
90+
})
91+
.Production("clause : LPAREN groupclauses RPAREN LCURLY INT RCURLY",
92+
args =>
93+
{
94+
return instance.GroupRepeat((Token<EbnfTokenGeneric>)args[0], (GroupClause<IN, OUT>)args[1],
95+
(Token<EbnfTokenGeneric>)args[2], (Token<EbnfTokenGeneric>)args[3],
96+
(Token<EbnfTokenGeneric>)args[4], (Token<EbnfTokenGeneric>)args[5]);
97+
})
5798
.Production("clause : IDENTIFIER OPTION",
5899
(args =>
59100
{
@@ -158,6 +199,24 @@ public BuildResult<Parser<EbnfTokenGeneric, GrammarNode<IN, OUT>>> BuildParser(s
158199
{
159200
return instance.ChoiceOptional((ChoiceClause<IN, OUT>)args[0], (Token<EbnfTokenGeneric>)args[1]);
160201
})
202+
.Production("clause : choiceclause LCURLY INT DASH INT RCURLY",
203+
args =>
204+
{
205+
return instance.ChoiceRepeatRange((ChoiceClause<IN, OUT>)args[0],
206+
((Token<EbnfTokenGeneric>)args[1]),
207+
((Token<EbnfTokenGeneric>)args[2]),
208+
((Token<EbnfTokenGeneric>)args[3]),
209+
(Token<EbnfTokenGeneric>)args[4],
210+
((Token<EbnfTokenGeneric>)args[5]));
211+
})
212+
.Production("clause : choiceclause LCURLY INT RCURLY",
213+
args =>
214+
{
215+
return instance.ChoiceRepeat((ChoiceClause<IN, OUT>)args[0],
216+
((Token<EbnfTokenGeneric>)args[1]),
217+
((Token<EbnfTokenGeneric>)args[2]),
218+
((Token<EbnfTokenGeneric>)args[3]));
219+
})
161220
.WithLexerbuilder(GetEbnfLexerBuilder());
162221

163222
var parser = builder.BuildParser();

src/sly/parser/generator/EbnfToken.cs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ public enum EbnfToken
1515
[Lexeme("^\\(")] LPAREN = 8,
1616

1717
[Lexeme("^\\)")] RPAREN = 9,
18+
19+
[Lexeme("\\{")] LCURLY = 20,
20+
21+
[Lexeme("\\{")] RCURLY = 21,
22+
23+
[Lexeme("\\-")] DASH = 22,
1824

1925
[Lexeme("[\\n\\r]+", true, true)] EOL = 10
2026
}
@@ -54,8 +60,19 @@ public enum EbnfTokenGeneric
5460
[Lexeme(GenericToken.SugarToken,"]")]
5561
RCROG = 12,
5662

57-
[Lexeme(GenericToken.String, "'","\\")]
63+
[Lexeme(GenericToken.String, "'","\\")]
5864
STRING = 13,
65+
66+
[Lexeme(GenericToken.SugarToken, "-")]
67+
DASH = 14,
68+
69+
[Lexeme(GenericToken.SugarToken, "{")]
70+
LCURLY = 15,
71+
72+
[Lexeme(GenericToken.SugarToken, "}")]
73+
RCURLY = 16,
5974

75+
[Int]
76+
INT = 17
6077
}
6178
}

src/sly/parser/generator/RuleParser.cs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,22 @@ public IClause<IN,OUT> OneMoreClause(Token<EbnfTokenGeneric> id, Token<EbnfToken
4646
var innerClause = BuildTerminalOrNonTerimal(id.Value);
4747
return new OneOrMoreClause<IN,OUT>(innerClause);
4848
}
49+
50+
51+
52+
[Production("clause : IDENTIFIER LCURLY INT DASH INT RCURLY")]
53+
public IClause<IN,OUT> RepeatClauseMinMax(Token<EbnfTokenGeneric> id, Token<EbnfTokenGeneric> lcurl, Token<EbnfTokenGeneric> min, Token<EbnfTokenGeneric> dash, Token<EbnfTokenGeneric> max, Token<EbnfTokenGeneric> rcurl)
54+
{
55+
var innerClause = BuildTerminalOrNonTerimal(id.Value);
56+
return new RepeatClause<IN,OUT>(innerClause, min.IntValue, max.IntValue);
57+
}
58+
59+
[Production("clause : IDENTIFIER LCURLY INT RCURLY")]
60+
public IClause<IN,OUT> RepeatClause(Token<EbnfTokenGeneric> id, Token<EbnfTokenGeneric> lcurl, Token<EbnfTokenGeneric> min, Token<EbnfTokenGeneric> rcurl)
61+
{
62+
var innerClause = BuildTerminalOrNonTerimal(id.Value);
63+
return new RepeatClause<IN,OUT>(innerClause, min.IntValue, min.IntValue);
64+
}
4965

5066
[Production("clause : IDENTIFIER OPTION")]
5167
public IClause<IN,OUT> OptionClause(Token<EbnfTokenGeneric> id, Token<EbnfTokenGeneric> discarded)
@@ -151,6 +167,21 @@ public IClause<IN,OUT> ChoiceZeroOrMore(ChoiceClause<IN,OUT> choices,Token<EbnfT
151167
return new ZeroOrMoreClause<IN,OUT>(choices);
152168
}
153169

170+
[Production("clause : choiceclause LCURLY INT DASH INT RCURLY")]
171+
public IClause<IN,OUT> ChoiceRepeatRange(ChoiceClause<IN,OUT> choices,Token<EbnfTokenGeneric> dicardLcurl,
172+
Token<EbnfTokenGeneric> min, Token<EbnfTokenGeneric> discardDash, Token<EbnfTokenGeneric> max,
173+
Token<EbnfTokenGeneric> discardRcurl)
174+
{
175+
return new RepeatClause<IN, OUT>(choices, min.IntValue, max.IntValue);
176+
}
177+
178+
[Production("clause : choiceclause LCURLY INT RCURLY")]
179+
public IClause<IN,OUT> ChoiceRepeat(ChoiceClause<IN,OUT> choices,Token<EbnfTokenGeneric> dicardLcurl,
180+
Token<EbnfTokenGeneric> min, Token<EbnfTokenGeneric> discardRcurl)
181+
{
182+
return new RepeatClause<IN, OUT>(choices, min.IntValue, min.IntValue);
183+
}
184+
154185

155186
[Production("clause : choiceclause OPTION ")]
156187
public IClause<IN,OUT> ChoiceOptional(ChoiceClause<IN,OUT> choices,Token<EbnfTokenGeneric> discardOption)
@@ -172,6 +203,23 @@ public IClause<IN,OUT> GroupZeroOrMore(Token<EbnfTokenGeneric> discardLeft, Grou
172203
return new ZeroOrMoreClause<IN,OUT>(clauses);
173204
}
174205

206+
[Production("clause : LPAREN groupclauses RPAREN LCURLY INT DASH INT RCURLY")]
207+
public IClause<IN,OUT> GroupRepeatRange(Token<EbnfTokenGeneric> discardLeft, GroupClause<IN,OUT> clauses,
208+
Token<EbnfTokenGeneric> discardRight, Token<EbnfTokenGeneric> discardLcurl, Token<EbnfTokenGeneric> min,
209+
Token<EbnfTokenGeneric> discarddash, Token<EbnfTokenGeneric> max, Token<EbnfTokenGeneric> discardRcurl)
210+
{
211+
return new RepeatClause<IN,OUT>(clauses, min.IntValue, max.IntValue);
212+
}
213+
214+
[Production("clause : LPAREN groupclauses RPAREN LCURLY INT RCURLY")]
215+
public IClause<IN,OUT> GroupRepeat(Token<EbnfTokenGeneric> discardLeft, GroupClause<IN,OUT> clauses,
216+
Token<EbnfTokenGeneric> discardRight, Token<EbnfTokenGeneric> discardLcurl, Token<EbnfTokenGeneric> min,
217+
Token<EbnfTokenGeneric> discardRcurl)
218+
{
219+
return new RepeatClause<IN,OUT>(clauses, min.IntValue, min.IntValue);
220+
}
221+
222+
175223
[Production("clause : LPAREN groupclauses RPAREN OPTION ")]
176224
public IClause<IN,OUT> GroupOptional(Token<EbnfTokenGeneric> discardLeft, GroupClause<IN,OUT> group,
177225
Token<EbnfTokenGeneric> discardRight, Token<EbnfTokenGeneric> option)

src/sly/parser/parser/llparser/ebnf/EBNFRecursiveDescentSyntaxParser.Many.cs

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Linq;
34
using sly.lexer;
45
using sly.parser.syntax.grammar;
56
using sly.parser.syntax.tree;
@@ -93,6 +94,101 @@ public SyntaxParseResult<IN, OUT> ParseZeroOrMore(IList<Token<IN>> tokens, ZeroO
9394
return result;
9495
}
9596

97+
public SyntaxParseResult<IN, OUT> ParseRepeat(IList<Token<IN>> tokens, RepeatClause<IN, OUT> clause, int position,
98+
SyntaxParsingContext<IN, OUT> parsingContext)
99+
{
100+
if (parsingContext.TryGetParseResult(clause, position, out var parseResult))
101+
{
102+
return parseResult;
103+
}
104+
var result = new SyntaxParseResult<IN, OUT>();
105+
var manyNode = new ManySyntaxNode<IN, OUT>($"{clause.Clause.ToString()}+");
106+
107+
var currentPosition = position;
108+
var innerClause = clause.Clause;
109+
SyntaxParseResult<IN, OUT> innerResult = null;
110+
bool hasByPasNodes = false;
111+
112+
List<UnexpectedTokenSyntaxError<IN>> innerErrors = new List<UnexpectedTokenSyntaxError<IN>>();
113+
114+
for (int i = 0; i < clause.MaxRepetitionCount; i++)
115+
{
116+
innerResult = ParseInnerRepeat(tokens, parsingContext, innerClause, manyNode, currentPosition, out hasByPasNodes);
117+
118+
119+
if (innerResult.IsError && clause.MinRepetitionCount != 0 && i != 0)
120+
{
121+
result.IsError = true;
122+
result.AddErrors(innerResult.GetErrors());
123+
124+
break;
125+
}
126+
127+
var errors = innerResult.GetErrors();
128+
if (errors != null && errors.Any())
129+
{
130+
innerErrors.AddRange(innerResult.GetErrors());
131+
break;
132+
}
133+
134+
manyNode.Add(innerResult.Root);
135+
currentPosition = innerResult.EndingPosition;
136+
}
137+
138+
bool isRangeError = false;
139+
if (manyNode.Children.Count < clause.MinRepetitionCount)
140+
{
141+
result.IsError = true;
142+
isRangeError = true;
143+
result.AddErrors(innerErrors);
144+
}
145+
146+
result.EndingPosition = currentPosition;
147+
result.IsError = isRangeError;
148+
result.AddErrors(innerErrors);
149+
result.Root = manyNode;
150+
result.IsEnded = innerResult != null && innerResult.IsEnded;
151+
result.HasByPassNodes = hasByPasNodes;
152+
parsingContext.Memoize(clause, position, result);
153+
154+
155+
return result;
156+
}
157+
158+
private SyntaxParseResult<IN, OUT> ParseInnerRepeat(IList<Token<IN>> tokens, SyntaxParsingContext<IN, OUT> parsingContext, IClause<IN, OUT> innerClause,
159+
ManySyntaxNode<IN, OUT> manyNode, int currentPosition, out bool hasByPasNodes)
160+
{
161+
SyntaxParseResult<IN, OUT> innerResult;
162+
switch (innerClause)
163+
{
164+
case TerminalClause<IN, OUT> terminalClause:
165+
manyNode.IsManyTokens = true;
166+
innerResult = ParseTerminal(tokens, terminalClause, currentPosition, parsingContext);
167+
hasByPasNodes = innerResult.HasByPassNodes;
168+
break;
169+
case NonTerminalClause<IN, OUT> nonTerm:
170+
{
171+
innerResult = ParseNonTerminal(tokens, nonTerm, currentPosition, parsingContext);
172+
hasByPasNodes = innerResult.HasByPassNodes;
173+
if (nonTerm.IsGroup)
174+
manyNode.IsManyGroups = true;
175+
else
176+
manyNode.IsManyValues = true;
177+
break;
178+
}
179+
case ChoiceClause<IN, OUT> choice:
180+
manyNode.IsManyTokens = choice.IsTerminalChoice;
181+
manyNode.IsManyValues = choice.IsNonTerminalChoice;
182+
innerResult = ParseChoice(tokens, choice, currentPosition, parsingContext);
183+
hasByPasNodes = innerResult.HasByPassNodes;
184+
break;
185+
default:
186+
throw new InvalidOperationException("unable to apply repeater to " + innerClause.GetType().Name);
187+
}
188+
189+
return innerResult;
190+
}
191+
96192
public SyntaxParseResult<IN, OUT> ParseOneOrMore(IList<Token<IN>> tokens, OneOrMoreClause<IN, OUT> clause, int position,
97193
SyntaxParsingContext<IN, OUT> parsingContext)
98194
{

src/sly/parser/parser/llparser/ebnf/EBNFRecursiveDescentSyntaxParser.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,14 @@ public override SyntaxParseResult<IN, OUT> Parse(IList<Token<IN>> tokens, Rule<I
7777
}
7878
case OneOrMoreClause<IN, OUT> _:
7979
case ZeroOrMoreClause<IN, OUT> _:
80+
case RepeatClause<IN, OUT> _:
8081
{
8182
SyntaxParseResult<IN, OUT> manyResult = null;
8283
switch (clause)
8384
{
85+
case RepeatClause<IN,OUT> repeat:
86+
manyResult = ParseRepeat(tokens, repeat, currentPosition, parsingContext);
87+
break;
8488
case OneOrMoreClause<IN, OUT> oneOrMore:
8589
manyResult = ParseOneOrMore(tokens, oneOrMore, currentPosition, parsingContext);
8690
break;

0 commit comments

Comments
 (0)