1 module tcenal.parser_combinator.combinators;
2 
3 import tcenal.parser_combinator.token : Token;
4 import tcenal.parser_combinator.parsing_result : ParsingResult;
5 import tcenal.parser_combinator.parse_tree_node : ParseTreeNode;
6 import tcenal.parser_combinator.memo : Memo, MemoEntry;
7 
8 import compile_time_unittest;
9 
10 import std.algorithm : startsWith, until;
11 import std.range : retro;
12 import std.array : array;
13 import std.conv : to;
14 
15 mixin enableCompileTimeUnittest;
16 
17 
18 ParsingResult parseToken(string tokenValue, string tokenType = "")(Token[] input, size_t position, ref Memo memo)
19 {
20     if (input.length > position && input[position].type == tokenType && input[position].value == tokenValue)
21     {
22         return ParsingResult(true, position + 1, ParseTreeNode(input[position]));
23     }
24     else
25     {
26         return ParsingResult(false);
27     }
28 }
29 unittest
30 {
31     Memo memo;
32 
33     with (parseToken!"foo"([Token("foo")], 0, memo))
34     {
35         assert (success);
36         assert (nextPosition == 1);
37         assert (node.token.value == "foo");
38     }
39 }
40 
41 
42 ParsingResult parseTokenWithType(string tokenType)(Token[] input, size_t position, ref Memo memo)
43 {
44     if (input.length > position && input[position].type == tokenType)
45     {
46         return ParsingResult(true, position + 1, ParseTreeNode(input[position]));
47     }
48     else
49     {
50         return ParsingResult(false);
51     }
52 }
53 unittest
54 {
55     Memo memo;
56 
57     with (parseTokenWithType!"identifier"([Token("foo", "identifier")], 0, memo))
58     {
59         assert (success);
60         assert (nextPosition == 1);
61         assert (node.token.value == "foo");
62         assert (node.token.type == "identifier");
63     }
64 }
65 
66 
67 ParsingResult parseTokenWithValue(string tokenValue)(Token[] input, size_t position, ref Memo memo)
68 {
69     if (input.length > position && input[position].value == tokenValue)
70     {
71         return ParsingResult(true, position + 1, ParseTreeNode(input[position]));
72     }
73     else
74     {
75         return ParsingResult(false);
76     }
77 }
78 unittest
79 {
80     Memo memo;
81 
82     with (parseTokenWithValue!"foo"([Token("foo", "identifier")], 0, memo))
83     {
84         assert (success);
85         assert (nextPosition == 1);
86         assert (node.token.value == "foo");
87         assert (node.token.type == "identifier");
88     }
89 }
90 
91 
92 ParsingResult parseWithMakingRuleNode(alias parser, string ruleName)(Token[] input, size_t position, ref Memo memo)
93 {
94     ParsingResult parsingResult = parser(input, position, memo);
95 
96     if (parsingResult.success)
97     {
98         parsingResult.node = ParseTreeNode(Token(), [parsingResult.node], ruleName);
99     }
100 
101     return parsingResult;
102 }
103 unittest
104 {
105     Memo memo;
106 
107     with (parseWithMakingRuleNode!(parseToken!"foo", "bar")([Token("foo")], 0, memo))
108     {
109         assert (success);
110         assert (nextPosition == 1);
111         assert (node.ruleName == "bar");
112         assert (node.children[0].token.value == "foo");
113     }
114 }
115 
116 
117 ParsingResult applyRule(alias parser, string ruleName = __FUNCTION__)(Token[] input, size_t position, ref Memo memo)
118 {
119     enum simplifiedRuleName = ruleName.retro().until('.').array().retro().to!string();
120 
121     if (position in memo)
122     {
123         if (ruleName in memo[position])
124         {
125             memo[position][ruleName].isCalled = true;
126             return memo[position][ruleName].parsingResult;
127         }
128     }
129 
130     memo[position][ruleName] = MemoEntry();
131     ParsingResult parsingResult = parseWithMakingRuleNode!(parser, simplifiedRuleName)(input, position, memo);
132 
133     if (!parsingResult.success)
134     {
135         return parsingResult;
136     }
137 
138     memo[position][ruleName].parsingResult = parsingResult;
139 
140     if (!memo[position][ruleName].isCalled)
141     {
142         return parsingResult;
143     }
144 
145     while (true)
146     {
147         size_t previousNextPosition = parsingResult.nextPosition;
148 
149         parsingResult = parseWithMakingRuleNode!(parser, simplifiedRuleName)(input, position, memo);
150 
151         if (!parsingResult.success)
152         {
153             assert(false);
154         }
155 
156         if (parsingResult.nextPosition <= previousNextPosition)
157         {
158             break;
159         }
160 
161         memo[position][ruleName].parsingResult = parsingResult;
162     }
163 
164     return memo[position][ruleName].parsingResult;
165 }
166 unittest
167 {
168     Memo memo;
169 
170     with (applyRule!(parseToken!"foo", "parseFoo")([Token("foo")], 0, memo))
171     {
172         assert (success);
173         assert (nextPosition == 1);
174         assert (node.ruleName == "parseFoo");
175         assert (node.children[0].token.value == "foo");
176     }
177 
178     with (memo[0]["parseFoo"])
179     {
180         assert (parsingResult.success);
181         assert (parsingResult.nextPosition == 1);
182         assert (parsingResult.node.ruleName == "parseFoo");
183         assert (parsingResult.node.children[0].token.value == "foo");
184         assert (!isCalled);
185     }
186 
187     static ParsingResult ruleForTest(Token[] input, size_t position, ref Memo memo)
188     {
189         return applyRule!(
190             choice!(
191                 sequence!(ruleForTest, parseToken!"+", parseToken!"1"),
192                 parseToken!"1"
193             ),
194             "ruleForTest"
195         )(input, position, memo);
196     }
197 
198     with (ruleForTest([Token("1")], 0, memo))
199     {
200         assert (success);
201         assert (nextPosition == 1);
202         assert (node.ruleName == "ruleForTest");
203         assert (node.children[0].token.value == "1");
204     }
205 
206     memo = memo.init;
207 
208     with (ruleForTest([Token("1"), Token("+"), Token("1")], 0, memo))
209     {
210         assert (success);
211         assert (nextPosition == 3);
212         assert (node.ruleName == "ruleForTest");
213         assert (node.children[0].children[0].ruleName == "ruleForTest");
214         assert (node.children[0].children[0].children[0].token.value == "1");
215         assert (node.children[0].children[1].token.value == "+");
216         assert (node.children[0].children[2].token.value == "1");
217     }
218 
219     memo = memo.init;
220 
221     with (ruleForTest([Token("1"), Token("+"), Token("1"), Token("+"), Token("1")], 0, memo))
222     {
223         assert (success);
224         assert (nextPosition == 5);
225         assert (node.ruleName == "ruleForTest");
226         assert (node.children[0].children[0].ruleName == "ruleForTest");
227         assert (node.children[0].children[0].children[0].children[0].ruleName == "ruleForTest");
228         assert (node.children[0].children[0].children[0].children[0].children[0].token.value == "1");
229         assert (node.children[0].children[0].children[0].children[1].token.value == "+");
230         assert (node.children[0].children[0].children[0].children[2].token.value == "1");
231         assert (node.children[0].children[1].token.value == "+");
232         assert (node.children[0].children[2].token.value == "1");
233     }
234 
235     with (memo[0]["ruleForTest"])
236     {
237         assert (parsingResult.success);
238         assert (parsingResult.nextPosition == 5);
239         assert (parsingResult.node.ruleName == "ruleForTest");
240         assert (parsingResult.node.children[0].children[0].ruleName == "ruleForTest");
241         assert (parsingResult.node.children[0].children[0].children[0].children[0].ruleName == "ruleForTest");
242         assert (parsingResult.node.children[0].children[0].children[0].children[0].children[0].token.value == "1");
243         assert (parsingResult.node.children[0].children[0].children[0].children[1].token.value == "+");
244         assert (parsingResult.node.children[0].children[0].children[0].children[2].token.value == "1");
245         assert (parsingResult.node.children[0].children[1].token.value == "+");
246         assert (parsingResult.node.children[0].children[2].token.value == "1");
247         assert (isCalled);
248     }
249 }
250 
251 
252 ParsingResult sequence(parsers...)(Token[] input, size_t position, ref Memo memo)
253 {
254     ParsingResult parsingWholeResult = ParsingResult(true, position);
255     parsingWholeResult.node.ruleName = "#sequence";
256 
257     foreach (parser; parsers)
258     {
259         ParsingResult parsingResult = parser(input, parsingWholeResult.nextPosition, memo);
260 
261         if (!parsingResult.success)
262         {
263             return ParsingResult(false);
264         }
265 
266         parsingWholeResult.node.children ~= parsingResult.node;
267         parsingWholeResult.nextPosition = parsingResult.nextPosition;
268     }
269 
270     return parsingWholeResult;
271 }
272 unittest
273 {
274     Memo memo;
275 
276     with (sequence!(parseToken!"foo", parseToken!"bar")([Token("foo"), Token("bar")], 0, memo))
277     {
278         assert (success);
279         assert (nextPosition == 2);
280         assert (node.ruleName == "#sequence");
281     }
282 }
283 
284 
285 ParsingResult select(size_t n, parsers...)(Token[] input, size_t position, ref Memo memo) if (n < parsers.length)
286 {
287     ParsingResult parsingResult = sequence!(parsers)(input, position, memo);
288 
289     if (parsingResult.success)
290     {
291         parsingResult.node = parsingResult.node.children[n];
292     }
293 
294     return parsingResult;
295 }
296 unittest
297 {
298     Memo memo;
299     with (select!(1, parseToken!"foo", parseToken!"bar")([Token("foo"), Token("bar")], 0, memo))
300     {
301         assert (success);
302         assert (nextPosition == 2);
303         assert (node.token.value == "bar");
304     }
305 }
306 
307 
308 ParsingResult choice(parsers...)(Token[] input, size_t position, ref Memo memo)
309 {
310     foreach (parser; parsers)
311     {
312         ParsingResult parsingResult = parser(input, position, memo);
313 
314         if (parsingResult.success)
315         {
316             return parsingResult;
317         }
318     }
319 
320     return ParsingResult();
321 }
322 unittest
323 {
324     Memo memo;
325 
326     with (choice!(parseToken!"foo", parseToken!"bar")([Token("foo")], 0, memo))
327     {
328         assert (success);
329         assert (nextPosition == 1);
330         assert (node.token.value == "foo");
331     }
332 
333     with (choice!(parseToken!"foo", parseToken!"bar")([Token("bar")], 0, memo))
334     {
335         assert (success);
336         assert (nextPosition == 1);
337         assert (node.token.value == "bar");
338     }
339 }
340 
341 
342 ParsingResult option(alias parser)(Token[] input, size_t position, ref Memo memo)
343 {
344     ParsingResult parsingWholeResult = ParsingResult(true, position);
345     parsingWholeResult.node.ruleName = "#option";
346 
347     ParsingResult parsingResult = parser(input, position, memo);
348 
349     if (parsingResult.success)
350     {
351         parsingWholeResult.nextPosition = parsingResult.nextPosition;
352         parsingWholeResult.node.children ~= parsingResult.node;
353     }
354 
355     return parsingWholeResult;
356 }
357 unittest
358 {
359     Memo memo;
360 
361     with (option!(parseToken!"foo")([Token("foo")], 0, memo))
362     {
363         assert (success);
364         assert (nextPosition == 1);
365         assert (node.ruleName == "#option");
366         assert (node.children[0].token.value == "foo");
367     }
368 
369     with (option!(parseToken!"foo")([Token("bar")], 0, memo))
370     {
371         assert (success);
372         assert (node.ruleName == "#option");
373         assert (node.children.length == 0);
374     }
375 }
376 
377 
378 ParsingResult repeat(alias parser, size_t n)(Token[] input, size_t position, ref Memo memo)
379 {
380     ParsingResult parsingWholeResult;
381     parsingWholeResult.node.ruleName = "#repeat";
382 
383     size_t currentPosition = position;
384 
385     while (true)
386     {
387         ParsingResult parsingResult = parser(input, currentPosition ,memo);
388 
389         if (!parsingResult.success)
390         {
391             break;
392         }
393 
394         currentPosition = parsingResult.nextPosition;
395         parsingWholeResult.node.children ~= parsingResult.node;
396     }
397 
398     parsingWholeResult.nextPosition = currentPosition;
399 
400     if (n <= parsingWholeResult.node.children.length)
401     {
402         parsingWholeResult.success = true;
403     }
404 
405     return parsingWholeResult;
406 }
407 unittest
408 {
409     Memo memo;
410 
411     with (repeat!(parseToken!"foo", 2)([Token("foo"), Token("foo")], 0, memo))
412     {
413         assert (success);
414         assert (nextPosition == 2);
415         assert (node.children[0].token.value == "foo");
416         assert (node.children[1].token.value == "foo");
417     }
418 
419     assert (!repeat!(parseToken!"foo", 2)([Token("foo")], 0, memo).success);
420 }
421 
422 
423 alias zeroOrMore(alias parser) = repeat!(parser, 0);
424 alias oneOrMore(alias parser) = repeat!(parser, 1);
425 
426 
427 ParsingResult repeatWithSeparator(alias parser, alias separator, size_t n)(Token[] input, size_t position, ref Memo memo)
428 {
429     ParsingResult parsingResult = sequence!(parser, zeroOrMore!(select!(1, separator, parser)))(input, position, memo);
430 
431     if (n == 0 && !parsingResult.success)
432     {
433         return ParsingResult(true, position, ParseTreeNode(Token(), [], "#repeat"));
434     }
435 
436     if (parsingResult.node.children[1].children.length + 1 < n)
437     {
438         return ParsingResult(false);
439     }
440 
441     if (parsingResult.success)
442     {
443         parsingResult.node.ruleName = "#repeat";
444         parsingResult.node.children = parsingResult.node.children[0] ~ parsingResult.node.children[1].children;
445     }
446 
447     return parsingResult;
448 }
449 unittest
450 {
451     Memo memo;
452 
453     with (repeatWithSeparator!(parseToken!"foo", parseToken!",", 2)([Token("foo"), Token(","), Token("foo"), Token(","), Token("foo")], 0, memo))
454     {
455         assert (success);
456         assert (nextPosition == 5);
457         assert (node.ruleName == "#repeat");
458         assert (node.children[0].token.value == "foo");
459         assert (node.children[1].token.value == "foo");
460         assert (node.children[2].token.value == "foo");
461     }
462 
463     assert (!repeatWithSeparator!(parseToken!"foo", parseToken!",", 4)([Token("foo"), Token(","), Token("foo"), Token(","), Token("foo")], 0, memo).success);
464 }
465 
466 
467 alias zeroOrMoreWithSeparator(alias parser, alias separator) = repeatWithSeparator!(parser, separator, 0);
468 alias oneOrMoreWithSeparator(alias parser, alias separator) = repeatWithSeparator!(parser, separator, 1);
469 
470 
471 ParsingResult not(alias parser)(Token[] input, size_t position, ref Memo memo)
472 {
473     return ParsingResult(!parser(input, position, memo).success, position);
474 }