Skip to content

Commit 33b3da6

Browse files
committed
parser fluent api : many operands
1 parent 4cd3f8a commit 33b3da6

File tree

3 files changed

+243
-6
lines changed

3 files changed

+243
-6
lines changed

src/sly/parser/generator/ExpressionRulesGenerator.cs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,37 @@ private string GetOperandNonTerminal(Type parserClass, ParserConfiguration<IN,OU
158158

159159
if (configuration.OperandRules != null && configuration.OperandRules.Any())
160160
{
161+
if (configuration.OperandRules.Count == 1)
162+
{
163+
return configuration.OperandRules[0].NonTerminalName;
164+
}
165+
161166
string nonTerminalName = string.Join("-",configuration.OperandRules.Select(x => x.NonTerminalName).Distinct());
167+
168+
// operandNonTerminalName = $"{parserClass.Name}_operand";
169+
// var operandNonTerminals = operandMethods.Select<MethodInfo, string>(GetNonTerminalNameFromProductionMethod);
170+
var operandNonTerminal = new NonTerminal<IN, OUT>(nonTerminalName);
171+
172+
173+
foreach (var operand in configuration.OperandRules)
174+
{
175+
if (!string.IsNullOrEmpty(operand.NonTerminalName))
176+
{
177+
var rule = new Rule<IN, OUT>
178+
{
179+
IsByPassRule = true,
180+
IsExpressionRule = true,
181+
Clauses = new List<IClause<IN, OUT>> {new NonTerminalClause<IN, OUT>(operand.NonTerminalName)}
182+
};
183+
operandNonTerminal.Rules.Add(rule);
184+
}
185+
}
186+
187+
configuration.NonTerminals[nonTerminalName] = operandNonTerminal;
188+
189+
162190
return nonTerminalName;
191+
163192
}
164193

165194
List<MethodInfo> methods;

tests/ParserTests/samples/FluentIndentedWhileParserBuilder.cs

Lines changed: 188 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,190 @@ public IFluentLexemeBuilder<IndentedWhileTokenGeneric> GetLexer()
6767
return lexer;
6868
}
6969

70-
public BuildResult<Parser<IndentedWhileTokenGeneric, WhileAST>> GetParser()
70+
public BuildResult<Parser<IndentedWhileTokenGeneric, WhileAST>> GetParserWithManyOperands()
71+
{
72+
var instance = new IndentedWhileParserGeneric();
73+
var builder = FluentEBNFParserBuilder<IndentedWhileTokenGeneric, WhileAST>.NewBuilder(instance,"program", "en");
74+
75+
var binary = (Func<WhileAST, Token<IndentedWhileTokenGeneric>, WhileAST, WhileAST> instanceCallback) =>
76+
{
77+
Func<object[], WhileAST> callback = (object[] args) =>
78+
{
79+
WhileAST left = (WhileAST)args[0];
80+
Token<IndentedWhileTokenGeneric> op = (Token<IndentedWhileTokenGeneric>)args[1];
81+
WhileAST right = (WhileAST)args[2];
82+
return instanceCallback(left, op, right);
83+
};
84+
return callback;
85+
};
86+
87+
var prefix = (Func<Token<IndentedWhileTokenGeneric>, WhileAST, WhileAST> instanceCallback) =>
88+
{
89+
Func<object[], WhileAST> callback = (object[] args) =>
90+
{
91+
Token<IndentedWhileTokenGeneric> op = (Token<IndentedWhileTokenGeneric>)args[0];
92+
WhileAST right = (WhileAST)args[1];
93+
return instanceCallback(op, right);
94+
};
95+
return callback;
96+
};
97+
98+
var postfix = (Func<WhileAST, Token<IndentedWhileTokenGeneric>, WhileAST> instanceCallback) =>
99+
{
100+
Func<object[], WhileAST> callback = (object[] args) =>
101+
{
102+
Token<IndentedWhileTokenGeneric> op = (Token<IndentedWhileTokenGeneric>)args[0];
103+
WhileAST right = (WhileAST)args[1];
104+
return instanceCallback(right, op);
105+
};
106+
return callback;
107+
};
108+
109+
var comparisonCallback = binary((left, op, right) =>
110+
{
111+
return instance.binaryComparisonExpression(left, op, right);
112+
});
113+
114+
var stringCallback = binary((left, op, right) =>
115+
{
116+
return instance.binaryStringExpression(left, op, right);
117+
});
118+
var factorCallback = binary((left, op, right) =>
119+
{
120+
return instance.binaryFactorNumericExpression(left, op, right);
121+
});
122+
var termCallback = binary((left, op, right) =>
123+
{
124+
return instance.binaryTermNumericExpression(left, op, right);
125+
});
126+
127+
128+
var parser = builder
129+
.UseAutoCloseIndentations(true)
130+
.UseMemoization(true)
131+
// expressions
132+
.Right(IndentedWhileTokenGeneric.LESSER, 50, comparisonCallback)
133+
.Right(IndentedWhileTokenGeneric.GREATER, 50, comparisonCallback)
134+
.Right(IndentedWhileTokenGeneric.EQUALS, 50, comparisonCallback)
135+
.Right(IndentedWhileTokenGeneric.DIFFERENT, 50, comparisonCallback)
136+
.Right(IndentedWhileTokenGeneric.CONCAT, 50, stringCallback)
137+
.Right(IndentedWhileTokenGeneric.PLUS, 10, termCallback)
138+
.Right(IndentedWhileTokenGeneric.MINUS, 10, termCallback)
139+
.Right(IndentedWhileTokenGeneric.TIMES, 50, factorCallback)
140+
.Right(IndentedWhileTokenGeneric.DIVIDE, 50, factorCallback)
141+
.Prefix(IndentedWhileTokenGeneric.MINUS, 100,
142+
prefix((op, value) => instance.unaryNumericExpression(op, value)))
143+
.Right(IndentedWhileTokenGeneric.OR, 10,
144+
binary((left, op, right) => instance.binaryOrExpression(left, op, right)))
145+
.Right(IndentedWhileTokenGeneric.AND, 50,
146+
binary((left, op, right) => instance.binaryAndExpression(left, op, right)))
147+
.Prefix(IndentedWhileTokenGeneric.NOT, 100, prefix((op, value) => instance.unaryNotExpression(op, value)))
148+
// operands
149+
.Operand("int : INT", (args) =>
150+
{
151+
return instance.PrimaryInt((Token<IndentedWhileTokenGeneric>)args[0]);
152+
})
153+
.Operand("id : IDENTIFIER", (args) =>
154+
{
155+
return instance.PrimaryId((Token<IndentedWhileTokenGeneric>)args[0]);
156+
})
157+
.Operand("bool : [TRUE|FALSE]", (args) =>
158+
{
159+
return instance.PrimaryBool((Token<IndentedWhileTokenGeneric>)args[0]);
160+
})
161+
.Operand("group : OPEN_PAREN[d] IndentedWhileParserGeneric_expressions CLOSE_PAREN[d]", args =>
162+
{
163+
return (WhileAST)args[0];
164+
})
165+
.Operand(
166+
"ternary : QUESTION[d] IndentedWhileParserGeneric_expressions ARROW[d] IndentedWhileParserGeneric_expressions COLON[d] IndentedWhileParserGeneric_expressions",
167+
args =>
168+
{
169+
var condition = (WhileAST)args[0];
170+
var ifTrue = (WhileAST)args[1];
171+
var ifFalse = (WhileAST)args[2];
172+
return instance.TernaryQuestion(condition, ifTrue, ifFalse);
173+
})
174+
// fstrings
175+
.Operand("fstring : OPEN_FSTRING[d] fstring_element* CLOSE_FSTRING[d]", args =>
176+
{
177+
var elements = (List<WhileAST>)args[0];
178+
return instance.fstring(elements);
179+
;
180+
})
181+
.Production("fstring_element : FSTRING_CONTENT", args =>
182+
{
183+
return instance.FStringContent((Token<IndentedWhileTokenGeneric>)args[0]);
184+
})
185+
.Production(
186+
"fstring_element : OPEN_FSTRING_EXPPRESSION[d] IndentedWhileParserGeneric_expressions CLOSE_FSTRING_EXPPRESSION[d]",
187+
args =>
188+
{
189+
return (WhileAST)args[0];
190+
})
191+
// main
192+
.Production("program: sequence", args =>
193+
{
194+
return (WhileAST)args[0];
195+
})
196+
.Production("block : INDENT[d] sequence UINDENT[d]", args =>
197+
{
198+
return (WhileAST)args[0];
199+
})
200+
// statements
201+
.Production("statement : block", args =>
202+
{
203+
return (WhileAST)args[0];
204+
})
205+
.Production("sequence: statement*", args =>
206+
{
207+
return instance.sequence((List<WhileAST>)args[0]);
208+
})
209+
.Production("statement: IF[d] IndentedWhileParserGeneric_expressions THEN[d] block (ELSE[d] block)?",
210+
args =>
211+
{
212+
var condition = (WhileAST)args[0];
213+
var ifTrue = (WhileAST)args[1];
214+
var ifFalse = (ValueOption<Group<IndentedWhileTokenGeneric, WhileAST>>)args[2];
215+
return instance.ifStmt(condition, ifTrue, ifFalse);
216+
})
217+
.Production("statement: WHILE[d] IndentedWhileParserGeneric_expressions DO[d] block", args =>
218+
{
219+
var condition = (WhileAST)args[0];
220+
var block = (WhileAST)args[1];
221+
return instance.whileStmt(condition, block);
222+
})
223+
.Production("statement: IDENTIFIER ASSIGN[d] IndentedWhileParserGeneric_expressions", args =>
224+
{
225+
var id = (Token<IndentedWhileTokenGeneric>)args[0];
226+
var value = (Expression)args[1];
227+
return instance.assignStmt(id, value);
228+
})
229+
.Production("statement: SKIP[d]", args =>
230+
{
231+
return new SkipStatement();
232+
})
233+
.Production("statement: RETURN[d] IndentedWhileParserGeneric_expressions", args =>
234+
{
235+
var value = (Expression)args[0];
236+
return new ReturnStatement(value);
237+
})
238+
.Production("statement: PRINT[d] IndentedWhileParserGeneric_expressions", args =>
239+
{
240+
var value = (Expression)args[0];
241+
return new PrintStatement(value);
242+
})
243+
.WithLexerbuilder(GetLexer())
244+
.BuildParser();
245+
246+
247+
return parser;
248+
249+
250+
251+
}
252+
253+
public BuildResult<Parser<IndentedWhileTokenGeneric, WhileAST>> GetParserWithSingleOperand()
71254
{
72255
var instance = new IndentedWhileParserGeneric();
73256
var builder = FluentEBNFParserBuilder<IndentedWhileTokenGeneric, WhileAST>.NewBuilder(instance,"program", "en");
@@ -154,6 +337,10 @@ public BuildResult<Parser<IndentedWhileTokenGeneric, WhileAST>> GetParser()
154337
{
155338
return instance.PrimaryId((Token<IndentedWhileTokenGeneric>)args[0]);
156339
})
340+
.Operand("operand : primary", (args) =>
341+
{
342+
return (WhileAST)args[0];
343+
})
157344
.Production("primary : [TRUE|FALSE]", (args) =>
158345
{
159346
return instance.PrimaryBool((Token<IndentedWhileTokenGeneric>)args[0]);
@@ -171,10 +358,6 @@ public BuildResult<Parser<IndentedWhileTokenGeneric, WhileAST>> GetParser()
171358
var ifFalse = (WhileAST)args[2];
172359
return instance.TernaryQuestion(condition, ifTrue, ifFalse);
173360
})
174-
.Operand("operand: primary", (args) =>
175-
{
176-
return (WhileAST)args[0];
177-
})
178361
// fstrings
179362
.Production("primary : OPEN_FSTRING[d] fstring_element* CLOSE_FSTRING[d]", args =>
180363
{

tests/ParserTests/samples/FluentIndentedWhileTests.cs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public BuildResult<Parser<IndentedWhileTokenGeneric, WhileAST>> buildParser()
2424
{
2525
var whileParser = new IndentedWhileParserGeneric();
2626
FluentIndentedWhileParserBuilder builder = new FluentIndentedWhileParserBuilder();
27-
Parser = builder.GetParser();
27+
Parser = builder.GetParserWithManyOperands();
2828
Check.That(Parser).IsOk();
2929
}
3030

@@ -34,6 +34,31 @@ public BuildResult<Parser<IndentedWhileTokenGeneric, WhileAST>> buildParser()
3434

3535
[Fact]
3636
public void TestAssignAdd()
37+
{
38+
var whileParser = new IndentedWhileParserGeneric();
39+
FluentIndentedWhileParserBuilder builder = new FluentIndentedWhileParserBuilder();
40+
var Parser = builder.GetParserWithSingleOperand();
41+
Check.That(Parser).IsOk();
42+
var buildResult = buildParser();
43+
var parser = buildResult.Result;
44+
var result = parser.Parse("a:=1+1");
45+
Check.That(result).IsOkParsing();
46+
47+
Check.That(result.Result).IsInstanceOf<SequenceStatement>();
48+
var seq = result.Result as SequenceStatement;
49+
Check.That(seq.Get(0)).IsInstanceOf<AssignStatement>();
50+
var assign = seq.Get(0) as AssignStatement;
51+
Check.That(assign.VariableName).IsEqualTo("a");
52+
var val = assign.Value;
53+
Check.That(val).IsInstanceOf<BinaryOperation>();
54+
var bin = val as BinaryOperation;
55+
Check.That(bin.Operator).IsEqualTo(BinaryOperator.ADD);
56+
Check.That((bin.Left as IntegerConstant)?.Value).IsEqualTo(1);
57+
Check.That((bin.Right as IntegerConstant)?.Value).IsEqualTo(1);
58+
}
59+
60+
[Fact]
61+
public void TestAssignAddSingleOperand()
3762
{
3863
var buildResult = buildParser();
3964
var parser = buildResult.Result;

0 commit comments

Comments
 (0)