blob: 6ce62face93a33b20dce501c8dfadbfe3c4529af [file] [log] [blame]
swissChilic71acc62021-12-07 08:03:37 -08001#include "Parser.h"
2
3#include <QDebug>
4
swissChili847a78c2021-12-09 17:44:52 -08005ParseResult::ParseResult(bool okay)
6 : ParseResult((int)okay)
7{}
8
9ParseResult::ParseResult(int status, ParsePos pos)
10 : ParseResult(status, "", pos)
11{}
12
13ParseResult::ParseResult(int status, QString message, ParsePos pos)
14{
15 _status = status;
swissChili323883d2022-02-20 16:35:23 -080016 _message = message;
swissChili847a78c2021-12-09 17:44:52 -080017 _pos = pos;
18}
19
20ParseResult::operator bool() const
21{
22 return _status == COMPLETE;
23}
24
25ParsePos ParseResult::pos() const
26{
27 return _pos;
28}
29
30QString ParseResult::message() const
31{
32 return _message;
33}
34
35int ParseResult::status() const
36{
37 return _status;
38}
39
swissChilic71acc62021-12-07 08:03:37 -080040Parser::Parser(QString input)
41{
42 _input = input;
43}
44
45QChar Parser::peek()
46{
47 if (atEnd())
48 return 0;
49
50 return _input[_pos];
51}
52
53QChar Parser::get()
54{
swissChili847a78c2021-12-09 17:44:52 -080055 QChar c = _input[_pos++];
56
57 if (c == '\n')
58 {
59 _line++;
60 _offset = 0;
61 }
62 else
63 {
64 _offset++;
65 }
66
67 return c;
swissChilic71acc62021-12-07 08:03:37 -080068}
69
70bool Parser::atEnd()
71{
72 return _pos >= _input.length();
73}
74
75void Parser::skip()
76{
77 while (peek().isSpace())
78 get();
79}
80
swissChili323883d2022-02-20 16:35:23 -080081QString Parser::line(int n) const
82{
83 return _input.split("\n")[n];
84}
85
swissChili847a78c2021-12-09 17:44:52 -080086ParsePos Parser::save() const
87{
88 return ParsePos{_line, _pos, _offset};
89}
90
91void Parser::reset(ParsePos pos)
92{
93 _line = pos.line;
94 _pos = pos.pos;
95 _offset = pos.lineOffset;
96}
97
swissChili682e7bc2021-12-07 09:04:54 -080098template <typename T>
swissChili847a78c2021-12-09 17:44:52 -080099ParseResult Parser::parseSymbol(T *node)
swissChilic71acc62021-12-07 08:03:37 -0800100{
101 skip();
102
103 if (peek().isLetter())
104 {
swissChili682e7bc2021-12-07 09:04:54 -0800105 *node = T(get());
swissChilic71acc62021-12-07 08:03:37 -0800106 return true;
107 }
108
109 return false;
110}
111
swissChili682e7bc2021-12-07 09:04:54 -0800112template <typename T>
swissChili847a78c2021-12-09 17:44:52 -0800113ParseResult Parser::parseIdentifier(T *node)
swissChilic71acc62021-12-07 08:03:37 -0800114{
115 skip();
116
117 QString buffer;
118
119 if (peek().isUpper())
120 {
121 while (peek().isLetter() || peek() == '-' || peek() == '_' || peek().isNumber())
122 {
123 buffer += get();
124 }
125
swissChili682e7bc2021-12-07 09:04:54 -0800126 *node = T(buffer);
swissChilic71acc62021-12-07 08:03:37 -0800127 return true;
128 }
129
130 return false;
131}
132
swissChili682e7bc2021-12-07 09:04:54 -0800133template <typename T>
swissChili847a78c2021-12-09 17:44:52 -0800134ParseResult Parser::parseNumber(T *node)
swissChilic71acc62021-12-07 08:03:37 -0800135{
136 skip();
137
138 QString buffer;
139
140 if (peek().isDigit())
141 {
142 while (peek().isDigit())
143 buffer += get();
144
swissChili1060c0e2021-12-09 09:46:42 -0800145 *node = T::fromInteger(buffer.toInt());
swissChilic71acc62021-12-07 08:03:37 -0800146 return true;
147 }
148
149 return false;
150}
151
swissChili682e7bc2021-12-07 09:04:54 -0800152template <typename T>
swissChili847a78c2021-12-09 17:44:52 -0800153ParseResult Parser::parseVariable(T *node)
swissChilic71acc62021-12-07 08:03:37 -0800154{
155 skip();
156
swissChili847a78c2021-12-09 17:44:52 -0800157 ParsePos pos = save();
swissChilic71acc62021-12-07 08:03:37 -0800158
159 if (peek() == 's' || peek() == 'e' || peek() == 't')
160 {
161 char type = get().toLatin1();
162
163 if (peek() == '.')
164 {
165 get();
166
swissChili682e7bc2021-12-07 09:04:54 -0800167 T nameNode;
swissChilic71acc62021-12-07 08:03:37 -0800168
swissChili682e7bc2021-12-07 09:04:54 -0800169 if (parseIdentifier(&nameNode))
swissChilic71acc62021-12-07 08:03:37 -0800170 {
swissChili682e7bc2021-12-07 09:04:54 -0800171 *node = T(type, nameNode.name());
172 return true;
173 }
174 else if (parseSymbol(&nameNode))
175 {
176 *node = T(type, QString(nameNode.symbol()));
swissChilic71acc62021-12-07 08:03:37 -0800177 return true;
178 }
swissChili847a78c2021-12-09 17:44:52 -0800179 else
180 {
181 ParseResult ret(ParseResult::INCOMPLETE,
182 "Expected identifier or symbol after . in variable",
swissChili323883d2022-02-20 16:35:23 -0800183 save());
swissChili847a78c2021-12-09 17:44:52 -0800184
185 reset(pos);
186
187 return ret;
188 }
swissChilic71acc62021-12-07 08:03:37 -0800189 }
190 }
191
swissChili847a78c2021-12-09 17:44:52 -0800192 reset(pos);
swissChilic71acc62021-12-07 08:03:37 -0800193 return false;
194}
195
swissChili682e7bc2021-12-07 09:04:54 -0800196template <typename T>
swissChili847a78c2021-12-09 17:44:52 -0800197ParseResult Parser::parseMany(QList<T> *list)
swissChilic71acc62021-12-07 08:03:37 -0800198{
swissChili918557c2022-02-20 20:16:34 -0800199 QList<T> nodes, string;
swissChili682e7bc2021-12-07 09:04:54 -0800200 T next;
swissChili918557c2022-02-20 20:16:34 -0800201 ParseResult ret, stringRet;
swissChilic71acc62021-12-07 08:03:37 -0800202
swissChili918557c2022-02-20 20:16:34 -0800203 while ((ret = parseOne(&next)) || (stringRet = parseString(&string)))
swissChilic71acc62021-12-07 08:03:37 -0800204 {
swissChili918557c2022-02-20 20:16:34 -0800205 if (ret)
206 nodes.append(next);
207 else if (stringRet)
208 nodes.append(string);
209
210 // So that we can check if anything was incomplete recently at the end
211 ret = stringRet = false;
swissChilic71acc62021-12-07 08:03:37 -0800212 }
213
swissChili847a78c2021-12-09 17:44:52 -0800214 *list = nodes;
215
216 if (ret.status() == ParseResult::INCOMPLETE)
217 return ret;
swissChili918557c2022-02-20 20:16:34 -0800218 else if (stringRet.status() == ParseResult::INCOMPLETE)
219 return ret;
swissChili847a78c2021-12-09 17:44:52 -0800220 else
221 return true;
swissChilic71acc62021-12-07 08:03:37 -0800222}
223
swissChili682e7bc2021-12-07 09:04:54 -0800224template <typename T>
swissChili847a78c2021-12-09 17:44:52 -0800225ParseResult Parser::parseParens(T *node)
swissChilic71acc62021-12-07 08:03:37 -0800226{
227 skip();
228
swissChili847a78c2021-12-09 17:44:52 -0800229 ParsePos pos = save();
swissChilic71acc62021-12-07 08:03:37 -0800230
231 if (peek() != '(')
232 return false;
233
234 get();
235
swissChili847a78c2021-12-09 17:44:52 -0800236 QList<T> many;
237 ParseResult ret = parseMany(&many);
238
swissChili682e7bc2021-12-07 09:04:54 -0800239 *node = T(many);
swissChilic71acc62021-12-07 08:03:37 -0800240
241 skip();
242 if (peek() != ')')
243 {
swissChili847a78c2021-12-09 17:44:52 -0800244 ret = ParseResult(ParseResult::INCOMPLETE, "Expected ) in parenthesized list", save());
245 reset(pos);
246
247 return ret;
swissChilic71acc62021-12-07 08:03:37 -0800248 }
249
250 get();
251
252 return true;
253}
254
swissChili847a78c2021-12-09 17:44:52 -0800255ParseResult Parser::parseFunction(AstNode *node)
swissChilic71acc62021-12-07 08:03:37 -0800256{
257 skip();
258
swissChili847a78c2021-12-09 17:44:52 -0800259 ParsePos pos = save();
260 ParseResult ret;
swissChilic71acc62021-12-07 08:03:37 -0800261
262 if (peek() != '<')
263 return false;
264
265 get();
266
267 AstNode head;
swissChili847a78c2021-12-09 17:44:52 -0800268 if (!(ret = parseIdentifier(&head)))
swissChilic71acc62021-12-07 08:03:37 -0800269 {
swissChili323883d2022-02-20 16:35:23 -0800270 ParsePos endPos = save();
swissChili847a78c2021-12-09 17:44:52 -0800271 reset(pos);
swissChili323883d2022-02-20 16:35:23 -0800272 return ParseResult(ParseResult::INCOMPLETE, "Expected identifier following < in function call", endPos);
swissChilic71acc62021-12-07 08:03:37 -0800273 }
274
swissChili847a78c2021-12-09 17:44:52 -0800275 QList<AstNode> body;
276 ret = parseMany(&body);
277
278 if (!ret)
279 {
280 reset(pos);
281 return ret;
282 }
283
swissChilic71acc62021-12-07 08:03:37 -0800284 *node = AstNode(head.name(), body);
285
286 skip();
287 if (peek() != '>')
288 {
swissChili847a78c2021-12-09 17:44:52 -0800289 ret = ParseResult(ParseResult::INCOMPLETE, "Expected >", save());
290 reset(pos);
291 return ret;
swissChilic71acc62021-12-07 08:03:37 -0800292 }
293
294 get();
295
296 return true;
297}
swissChili682e7bc2021-12-07 09:04:54 -0800298
299template <>
swissChili847a78c2021-12-09 17:44:52 -0800300ParseResult Parser::parseOne<Token>(Token *node)
swissChili682e7bc2021-12-07 09:04:54 -0800301{
swissChili323883d2022-02-20 16:35:23 -0800302 ParseResult ret;
303
304 if ((ret = parseVariable(node)).status() == ParseResult::COMPLETE || ret.status() == ParseResult::INCOMPLETE)
305 return ret;
306 if ((ret = parseNumber(node)).status() == ParseResult::COMPLETE || ret.status() == ParseResult::INCOMPLETE)
307 return ret;
308 if ((ret = parseIdentifier(node)).status() == ParseResult::COMPLETE || ret.status() == ParseResult::INCOMPLETE)
309 return ret;
310 if ((ret = parseSymbol(node)).status() == ParseResult::COMPLETE || ret.status() == ParseResult::INCOMPLETE)
311 return ret;
312 return parseParens(node);
swissChili682e7bc2021-12-07 09:04:54 -0800313}
314
315template <>
swissChili847a78c2021-12-09 17:44:52 -0800316ParseResult Parser::parseOne<AstNode>(AstNode *node)
swissChili682e7bc2021-12-07 09:04:54 -0800317{
swissChili323883d2022-02-20 16:35:23 -0800318 ParseResult ret;
319
320 if ((ret = parseFunction(node)).status() == ParseResult::COMPLETE || ret.status() == ParseResult::INCOMPLETE)
321 return ret;
322 if ((ret = parseVariable(node)).status() == ParseResult::COMPLETE || ret.status() == ParseResult::INCOMPLETE)
323 return ret;
324 if ((ret = parseNumber(node)).status() == ParseResult::COMPLETE || ret.status() == ParseResult::INCOMPLETE)
325 return ret;
326 if ((ret = parseIdentifier(node)).status() == ParseResult::COMPLETE || ret.status() == ParseResult::INCOMPLETE)
327 return ret;
328 if ((ret = parseSymbol(node)).status() == ParseResult::COMPLETE || ret.status() == ParseResult::INCOMPLETE)
329 return ret;
330 return parseParens(node);
swissChili682e7bc2021-12-07 09:04:54 -0800331}
swissChili8a581c62021-12-07 13:29:21 -0800332
swissChili847a78c2021-12-09 17:44:52 -0800333ParseResult Parser::parseSentence(Sentence *sentence)
swissChili8a581c62021-12-07 13:29:21 -0800334{
swissChili847a78c2021-12-09 17:44:52 -0800335 ParsePos pos = save();
swissChili8a581c62021-12-07 13:29:21 -0800336
swissChili847a78c2021-12-09 17:44:52 -0800337 if (peek() == '}')
338 {
339 return false;
340 }
341
342 QList<Token> pattern;
343 ParseResult ret = parseMany(&pattern);
344
345 if (!ret)
346 {
swissChili847a78c2021-12-09 17:44:52 -0800347 reset(pos);
348 return ret;
349 }
swissChili8a581c62021-12-07 13:29:21 -0800350
351 skip();
352
353 if (get() != '=')
354 {
swissChili847a78c2021-12-09 17:44:52 -0800355 ret = ParseResult(ParseResult::INCOMPLETE, "Expected = in sentence", save());
356 reset(pos);
357 return ret;
swissChili8a581c62021-12-07 13:29:21 -0800358 }
359
swissChili847a78c2021-12-09 17:44:52 -0800360 QList<AstNode> result;
361 ret = parseMany(&result);
362
363 if (!ret)
364 {
swissChili847a78c2021-12-09 17:44:52 -0800365 reset(pos);
366 return ret;
367 }
swissChili8a581c62021-12-07 13:29:21 -0800368
369 skip();
370
swissChili847a78c2021-12-09 17:44:52 -0800371 if (peek() != '}' && get() != ';')
swissChili8a581c62021-12-07 13:29:21 -0800372 {
swissChili847a78c2021-12-09 17:44:52 -0800373 ret = ParseResult(ParseResult::INCOMPLETE, "Expected ; or } after sentence", save());
374 reset(pos);
375 return ret;
swissChili8a581c62021-12-07 13:29:21 -0800376 }
377
378 *sentence = Sentence(pattern, result);
swissChili847a78c2021-12-09 17:44:52 -0800379
swissChili8a581c62021-12-07 13:29:21 -0800380 return true;
381}
382
swissChili847a78c2021-12-09 17:44:52 -0800383ParseResult Parser::parseFunctionDefinition(Function *function)
swissChili8a581c62021-12-07 13:29:21 -0800384{
swissChili847a78c2021-12-09 17:44:52 -0800385 ParsePos pos = save();
386 ParseResult ret;
swissChili8a581c62021-12-07 13:29:21 -0800387
388 Token identifier;
swissChili847a78c2021-12-09 17:44:52 -0800389 if (!(ret = parseIdentifier(&identifier)))
swissChili8a581c62021-12-07 13:29:21 -0800390 {
swissChili847a78c2021-12-09 17:44:52 -0800391 reset(pos);
392 return ret;
swissChili8a581c62021-12-07 13:29:21 -0800393 }
394
395 QString name = identifier.name();
396 Function func(name);
397
398 skip();
399
400 if (get() != '{')
401 {
swissChili847a78c2021-12-09 17:44:52 -0800402 reset(pos);
403 return false;
swissChili8a581c62021-12-07 13:29:21 -0800404 }
405
406 Sentence sentence;
swissChili847a78c2021-12-09 17:44:52 -0800407 while ((ret = parseSentence(&sentence)))
swissChili8a581c62021-12-07 13:29:21 -0800408 {
409 func.addSentence(sentence);
410 skip();
411 }
412
swissChili323883d2022-02-20 16:35:23 -0800413 if (ret.status() == ParseResult::INCOMPLETE)
swissChili847a78c2021-12-09 17:44:52 -0800414 {
swissChili847a78c2021-12-09 17:44:52 -0800415 reset(pos);
416 return ret;
417 }
418
swissChili8a581c62021-12-07 13:29:21 -0800419 if (get() != '}')
420 {
swissChili323883d2022-02-20 16:35:23 -0800421 ret = ParseResult(ParseResult::INCOMPLETE, "Expected } at end of function", save());
swissChili847a78c2021-12-09 17:44:52 -0800422 reset(pos);
423 return ret;
swissChili8a581c62021-12-07 13:29:21 -0800424 }
425
426 *function = func;
427 return true;
428}
swissChili323883d2022-02-20 16:35:23 -0800429
430ParsePos::operator QString()
431{
432 return QString::number(line) + ":" + QString::number(lineOffset);
433}
swissChili918557c2022-02-20 20:16:34 -0800434
435template <typename T>
436ParseResult Parser::parseString(QList<T> *list)
437{
438 skip();
439
440 ParsePos pos = save();
441
442 if (peek() != '\'')
443 return false;
444
445 get();
446
447 list->clear();
448
449 while (peek() != 0 && peek() != '\'')
450 {
451 QChar c = get();
452 if (c == '\\')
453 {
454 QChar next = get();
455 QString conversions = "''n\nt\tr\r";
456
457 for (int i = 0; i < conversions.size(); i += 2)
458 {
459 if (next == conversions[i])
460 list->append(T(conversions[i + 1]));
461 }
462 }
463 else
464 {
465 list->append(T(c));
466 }
467 }
468
469 if (get() == 0)
470 {
471 ParseResult ret(ParseResult::INCOMPLETE, "Expected ' before end of input", save());
472 reset(pos);
473 return ret;
474 }
475
476 return true;
477}