1 module tcenal.dsl.generate_parsers;
2 
3 import tcenal.parser_combinator.parse_tree_node : ParseTreeNode;
4 import tcenal.parser_combinator.memo : Memo;
5 import tcenal.dsl.lexer : lex;
6 import tcenal.dsl.parsers : rules;
7 
8 
9 private string generate(ParseTreeNode node, string ruleName = "")
10 {
11     string generated;
12 
13     switch (node.ruleName)
14     {
15         case "rules":
16             foreach (i, child; node.children[0].children)
17             {
18                 if (i)
19                 {
20                     generated ~= "\n\n\n";
21                 }
22 
23                 generated ~= child.generate();
24             }
25             break;
26 
27         case "rule":
28             ruleName = node.children[0].children[0].token.value;
29             generated  = "tcenal.parser_combinator.parsing_result.ParsingResult " ~ ruleName ~ "(alias ruleSelector)(tcenal.parser_combinator.token.Token[] input, size_t position, ref tcenal.parser_combinator.memo.Memo memo)\n";
30             generated ~= "{\nreturn tcenal.parser_combinator.combinators.applyRule!(\n";
31             generated ~= node.children[0].children[1].generate(ruleName);
32             generated ~= "\n)(input, position, memo);\n}";
33             break;
34 
35         case "choiceExpr":
36             if (node.children[0].children.length == 1)
37             {
38                 generated = node.children[0].children[0].generate(ruleName);
39             }
40             else
41             {
42                 generated = "tcenal.parser_combinator.combinators.choice!(\n" ~ node.children[0].generate(ruleName) ~ "\n)";
43             }
44             break;
45 
46         case "sequenceExpr":
47             if (node.children[0].children.length == 1)
48             {
49                 generated = node.children[0].children[0].generate(ruleName);
50             }
51             else
52             {
53                 generated = "tcenal.parser_combinator.combinators.sequence!(\n" ~ node.children[0].generate(ruleName) ~ "\n)";
54             }
55             break;
56 
57         case "prefixExpr":
58             if (node.children[0].ruleName == "#sequence" && node.children[0].children[0].token.type == "")
59             {
60                 switch (node.children[0].children[0].token.value)
61                 {
62                     case "&":
63                         generated = "tcenal.parser_combinator.combinators.andPred!(\n" ~ node.children[0].children[1].generate(ruleName) ~ "\n)";
64                         break;
65 
66                     case "!":
67                         generated = "tcenal.parser_combinator.combinators.notPred!(\n" ~ node.children[0].children[1].generate(ruleName) ~ "\n)";
68                         break;
69 
70                     default:
71                         assert (0);
72                 }
73             }
74             else
75             {
76                 generated = node.children[0].generate(ruleName);
77             }
78             break;
79 
80         case "postfixExpr":
81             if (node.children[0].ruleName == "#sequence" && node.children[0].children[1].token.type == "")
82             {
83                 switch (node.children[0].children[1].token.value)
84                 {
85                     case "*":
86                         if (node.children[0].children[2].children.length == 1)
87                         {
88                             generated = "tcenal.parser_combinator.combinators.zeroOrMoreWithSeparator!(\n" ~ node.children[0].children[0].generate(ruleName) ~ ",\n" ~ node.children[0].children[2].children[0].generate(ruleName) ~ "\n)";
89                         }
90                         else
91                         {
92                             generated = "tcenal.parser_combinator.combinators.zeroOrMore!(\n" ~ node.children[0].children[0].generate(ruleName) ~ "\n)";
93                         }
94 
95                         break;
96 
97                     case "+":
98                         if (node.children[0].children[2].children.length == 1)
99                         {
100                             generated = "tcenal.parser_combinator.combinators.oneOrMoreWithSeparator!(\n" ~ node.children[0].children[0].generate(ruleName) ~ ",\n)" ~ node.children[0].children[2].children[0].generate(ruleName) ~ "\n)";
101                         }
102                         else
103                         {
104                             generated = "tcenal.parser_combinator.combinators.oneOrMore!(\n" ~ node.children[0].children[0].generate(ruleName) ~ "\n)";
105                         }
106                         break;
107 
108                     case "?":
109                         generated = "tcenal.parser_combinator.combinators.option!(\n" ~ node.children[0].children[0].generate(ruleName) ~ "\n)";
110                         break;
111 
112                     default:
113                         assert (0);
114                 }
115             }
116             else
117             {
118                 generated = node.children[0].generate(ruleName);
119             }
120             break;
121 
122         case "primaryExpr":
123             generated = node.children[0].generate(ruleName);
124             break;
125 
126         case "ruleName":
127             if (node.children[0].token.value == "super")
128             {
129                 generated = "ruleSelector!(\"" ~ ruleName ~ "\", true)";
130             }
131             else
132             {
133                 generated = "ruleSelector!\"" ~ node.children[0].token.value ~ "\"";
134             }
135             break;
136 
137         case "tokenValue":
138             generated = "tcenal.parser_combinator.combinators.parseTokenWithValue!\"" ~ node.children[0].token.value ~ "\"";
139             break;
140 
141         case "tokenType":
142             generated = "tcenal.parser_combinator.combinators.parseTokenWithType!\"" ~ node.children[0].token.value ~ "\"";
143             break;
144 
145         case "#repeat":
146             foreach (i, child; node.children)
147             {
148                 if (i)
149                 {
150                     generated ~= ",\n";
151                 }
152 
153                 generated ~= child.generate(ruleName);
154             }
155             break;
156 
157         default:
158             assert(false, node.toString());
159     }
160 
161     return generated;
162 }
163 
164 
165 string generateParsers(string src)
166 {
167     enum preamble = q{
168         static import tcenal.parser_combinator.token;
169         static import tcenal.parser_combinator.memo;
170         static import tcenal.parser_combinator.parsing_result;
171         static import tcenal.parser_combinator.combinators;
172     };
173 
174     Memo memo;
175 
176     return preamble ~ src.lex().rules(0, memo).node.generate();
177 }