blob: 9679b4cf58a52a2f5c0b44a2336239b13afb0a68 [file] [log] [blame]
swissChilic71acc62021-12-07 08:03:37 -08001#include "Parser.h"
swissChilid85daa92022-02-24 15:29:02 -08002#include "PPrint.h"
swissChilic71acc62021-12-07 08:03:37 -08003
4#include <QDebug>
5
swissChili847a78c2021-12-09 17:44:52 -08006ParseResult::ParseResult(bool okay)
7 : ParseResult((int)okay)
8{}
9
10ParseResult::ParseResult(int status, ParsePos pos)
11 : ParseResult(status, "", pos)
12{}
13
14ParseResult::ParseResult(int status, QString message, ParsePos pos)
15{
16 _status = status;
swissChili323883d2022-02-20 16:35:23 -080017 _message = message;
swissChili847a78c2021-12-09 17:44:52 -080018 _pos = pos;
19}
20
21ParseResult::operator bool() const
22{
23 return _status == COMPLETE;
24}
25
26ParsePos ParseResult::pos() const
27{
28 return _pos;
29}
30
31QString ParseResult::message() const
32{
33 return _message;
34}
35
36int ParseResult::status() const
37{
swissChilid85daa92022-02-24 15:29:02 -080038 return _status;
39}
40
41ParseResult::operator QString() const
42{
43 return pprint(pos()) + "\n" + message();
swissChili847a78c2021-12-09 17:44:52 -080044}
45
swissChilic71acc62021-12-07 08:03:37 -080046Parser::Parser(QString input)
47{
48 _input = input;
49}
50
51QChar Parser::peek()
52{
53 if (atEnd())
54 return 0;
55
56 return _input[_pos];
57}
58
59QChar Parser::get()
60{
swissChili847a78c2021-12-09 17:44:52 -080061 QChar c = _input[_pos++];
62
63 if (c == '\n')
64 {
65 _line++;
66 _offset = 0;
67 }
68 else
69 {
70 _offset++;
71 }
72
73 return c;
swissChilic71acc62021-12-07 08:03:37 -080074}
75
76bool Parser::atEnd()
77{
78 return _pos >= _input.length();
79}
80
81void Parser::skip()
82{
83 while (peek().isSpace())
84 get();
85}
86
swissChili323883d2022-02-20 16:35:23 -080087QString Parser::line(int n) const
88{
89 return _input.split("\n")[n];
90}
91
swissChili847a78c2021-12-09 17:44:52 -080092ParsePos Parser::save() const
93{
94 return ParsePos{_line, _pos, _offset};
95}
96
97void Parser::reset(ParsePos pos)
98{
99 _line = pos.line;
100 _pos = pos.pos;
101 _offset = pos.lineOffset;
102}
103
swissChili682e7bc2021-12-07 09:04:54 -0800104template <typename T>
swissChili847a78c2021-12-09 17:44:52 -0800105ParseResult Parser::parseSymbol(T *node)
swissChilic71acc62021-12-07 08:03:37 -0800106{
107 skip();
108
109 if (peek().isLetter())
110 {
swissChili682e7bc2021-12-07 09:04:54 -0800111 *node = T(get());
swissChilic71acc62021-12-07 08:03:37 -0800112 return true;
113 }
114
115 return false;
116}
117
swissChili682e7bc2021-12-07 09:04:54 -0800118template <typename T>
swissChili847a78c2021-12-09 17:44:52 -0800119ParseResult Parser::parseIdentifier(T *node)
swissChilic71acc62021-12-07 08:03:37 -0800120{
121 skip();
122
123 QString buffer;
124
125 if (peek().isUpper())
126 {
127 while (peek().isLetter() || peek() == '-' || peek() == '_' || peek().isNumber())
128 {
129 buffer += get();
130 }
131
swissChili682e7bc2021-12-07 09:04:54 -0800132 *node = T(buffer);
swissChilic71acc62021-12-07 08:03:37 -0800133 return true;
134 }
135
136 return false;
137}
138
swissChili682e7bc2021-12-07 09:04:54 -0800139template <typename T>
swissChili847a78c2021-12-09 17:44:52 -0800140ParseResult Parser::parseNumber(T *node)
swissChilic71acc62021-12-07 08:03:37 -0800141{
142 skip();
143
144 QString buffer;
145
146 if (peek().isDigit())
147 {
148 while (peek().isDigit())
149 buffer += get();
150
swissChili1060c0e2021-12-09 09:46:42 -0800151 *node = T::fromInteger(buffer.toInt());
swissChilic71acc62021-12-07 08:03:37 -0800152 return true;
153 }
154
155 return false;
156}
157
swissChili682e7bc2021-12-07 09:04:54 -0800158template <typename T>
swissChili847a78c2021-12-09 17:44:52 -0800159ParseResult Parser::parseVariable(T *node)
swissChilic71acc62021-12-07 08:03:37 -0800160{
161 skip();
162
swissChili847a78c2021-12-09 17:44:52 -0800163 ParsePos pos = save();
swissChilic71acc62021-12-07 08:03:37 -0800164
165 if (peek() == 's' || peek() == 'e' || peek() == 't')
166 {
167 char type = get().toLatin1();
168
169 if (peek() == '.')
170 {
171 get();
172
swissChili682e7bc2021-12-07 09:04:54 -0800173 T nameNode;
swissChilic71acc62021-12-07 08:03:37 -0800174
swissChili682e7bc2021-12-07 09:04:54 -0800175 if (parseIdentifier(&nameNode))
swissChilic71acc62021-12-07 08:03:37 -0800176 {
swissChili682e7bc2021-12-07 09:04:54 -0800177 *node = T(type, nameNode.name());
178 return true;
179 }
180 else if (parseSymbol(&nameNode))
181 {
182 *node = T(type, QString(nameNode.symbol()));
swissChilic71acc62021-12-07 08:03:37 -0800183 return true;
184 }
swissChili847a78c2021-12-09 17:44:52 -0800185 else
186 {
187 ParseResult ret(ParseResult::INCOMPLETE,
188 "Expected identifier or symbol after . in variable",
swissChili323883d2022-02-20 16:35:23 -0800189 save());
swissChili847a78c2021-12-09 17:44:52 -0800190
191 reset(pos);
192
193 return ret;
194 }
swissChilic71acc62021-12-07 08:03:37 -0800195 }
196 }
197
swissChili847a78c2021-12-09 17:44:52 -0800198 reset(pos);
swissChilic71acc62021-12-07 08:03:37 -0800199 return false;
200}
201
swissChili682e7bc2021-12-07 09:04:54 -0800202template <typename T>
swissChili847a78c2021-12-09 17:44:52 -0800203ParseResult Parser::parseMany(QList<T> *list)
swissChilic71acc62021-12-07 08:03:37 -0800204{
swissChili918557c2022-02-20 20:16:34 -0800205 QList<T> nodes, string;
swissChili682e7bc2021-12-07 09:04:54 -0800206 T next;
swissChili918557c2022-02-20 20:16:34 -0800207 ParseResult ret, stringRet;
swissChilic71acc62021-12-07 08:03:37 -0800208
swissChili918557c2022-02-20 20:16:34 -0800209 while ((ret = parseOne(&next)) || (stringRet = parseString(&string)))
swissChilic71acc62021-12-07 08:03:37 -0800210 {
swissChili918557c2022-02-20 20:16:34 -0800211 if (ret)
212 nodes.append(next);
213 else if (stringRet)
214 nodes.append(string);
215
216 // So that we can check if anything was incomplete recently at the end
217 ret = stringRet = false;
swissChilic71acc62021-12-07 08:03:37 -0800218 }
219
swissChili847a78c2021-12-09 17:44:52 -0800220 *list = nodes;
221
222 if (ret.status() == ParseResult::INCOMPLETE)
223 return ret;
swissChili918557c2022-02-20 20:16:34 -0800224 else if (stringRet.status() == ParseResult::INCOMPLETE)
225 return ret;
swissChili847a78c2021-12-09 17:44:52 -0800226 else
227 return true;
swissChilic71acc62021-12-07 08:03:37 -0800228}
229
swissChili682e7bc2021-12-07 09:04:54 -0800230template <typename T>
swissChili847a78c2021-12-09 17:44:52 -0800231ParseResult Parser::parseParens(T *node)
swissChilic71acc62021-12-07 08:03:37 -0800232{
233 skip();
234
swissChili847a78c2021-12-09 17:44:52 -0800235 ParsePos pos = save();
swissChilic71acc62021-12-07 08:03:37 -0800236
237 if (peek() != '(')
238 return false;
239
240 get();
241
swissChili847a78c2021-12-09 17:44:52 -0800242 QList<T> many;
243 ParseResult ret = parseMany(&many);
244
swissChili682e7bc2021-12-07 09:04:54 -0800245 *node = T(many);
swissChilic71acc62021-12-07 08:03:37 -0800246
247 skip();
248 if (peek() != ')')
249 {
swissChili847a78c2021-12-09 17:44:52 -0800250 ret = ParseResult(ParseResult::INCOMPLETE, "Expected ) in parenthesized list", save());
251 reset(pos);
252
253 return ret;
swissChilic71acc62021-12-07 08:03:37 -0800254 }
255
256 get();
257
258 return true;
259}
260
swissChili847a78c2021-12-09 17:44:52 -0800261ParseResult Parser::parseFunction(AstNode *node)
swissChilic71acc62021-12-07 08:03:37 -0800262{
263 skip();
264
swissChili847a78c2021-12-09 17:44:52 -0800265 ParsePos pos = save();
266 ParseResult ret;
swissChilic71acc62021-12-07 08:03:37 -0800267
268 if (peek() != '<')
269 return false;
270
271 get();
272
273 AstNode head;
swissChili847a78c2021-12-09 17:44:52 -0800274 if (!(ret = parseIdentifier(&head)))
swissChilic71acc62021-12-07 08:03:37 -0800275 {
swissChili323883d2022-02-20 16:35:23 -0800276 ParsePos endPos = save();
swissChili847a78c2021-12-09 17:44:52 -0800277 reset(pos);
swissChili323883d2022-02-20 16:35:23 -0800278 return ParseResult(ParseResult::INCOMPLETE, "Expected identifier following < in function call", endPos);
swissChilic71acc62021-12-07 08:03:37 -0800279 }
280
swissChili847a78c2021-12-09 17:44:52 -0800281 QList<AstNode> body;
282 ret = parseMany(&body);
283
284 if (!ret)
285 {
286 reset(pos);
287 return ret;
288 }
289
swissChilic71acc62021-12-07 08:03:37 -0800290 *node = AstNode(head.name(), body);
291
292 skip();
293 if (peek() != '>')
294 {
swissChili847a78c2021-12-09 17:44:52 -0800295 ret = ParseResult(ParseResult::INCOMPLETE, "Expected >", save());
296 reset(pos);
297 return ret;
swissChilic71acc62021-12-07 08:03:37 -0800298 }
299
300 get();
301
302 return true;
303}
swissChili682e7bc2021-12-07 09:04:54 -0800304
305template <>
swissChili847a78c2021-12-09 17:44:52 -0800306ParseResult Parser::parseOne<Token>(Token *node)
swissChili682e7bc2021-12-07 09:04:54 -0800307{
swissChili323883d2022-02-20 16:35:23 -0800308 ParseResult ret;
309
310 if ((ret = parseVariable(node)).status() == ParseResult::COMPLETE || ret.status() == ParseResult::INCOMPLETE)
311 return ret;
312 if ((ret = parseNumber(node)).status() == ParseResult::COMPLETE || ret.status() == ParseResult::INCOMPLETE)
313 return ret;
314 if ((ret = parseIdentifier(node)).status() == ParseResult::COMPLETE || ret.status() == ParseResult::INCOMPLETE)
315 return ret;
316 if ((ret = parseSymbol(node)).status() == ParseResult::COMPLETE || ret.status() == ParseResult::INCOMPLETE)
317 return ret;
318 return parseParens(node);
swissChili682e7bc2021-12-07 09:04:54 -0800319}
320
321template <>
swissChili847a78c2021-12-09 17:44:52 -0800322ParseResult Parser::parseOne<AstNode>(AstNode *node)
swissChili682e7bc2021-12-07 09:04:54 -0800323{
swissChili323883d2022-02-20 16:35:23 -0800324 ParseResult ret;
325
326 if ((ret = parseFunction(node)).status() == ParseResult::COMPLETE || ret.status() == ParseResult::INCOMPLETE)
327 return ret;
328 if ((ret = parseVariable(node)).status() == ParseResult::COMPLETE || ret.status() == ParseResult::INCOMPLETE)
329 return ret;
330 if ((ret = parseNumber(node)).status() == ParseResult::COMPLETE || ret.status() == ParseResult::INCOMPLETE)
331 return ret;
332 if ((ret = parseIdentifier(node)).status() == ParseResult::COMPLETE || ret.status() == ParseResult::INCOMPLETE)
333 return ret;
334 if ((ret = parseSymbol(node)).status() == ParseResult::COMPLETE || ret.status() == ParseResult::INCOMPLETE)
335 return ret;
336 return parseParens(node);
swissChili682e7bc2021-12-07 09:04:54 -0800337}
swissChili8a581c62021-12-07 13:29:21 -0800338
swissChili847a78c2021-12-09 17:44:52 -0800339ParseResult Parser::parseSentence(Sentence *sentence)
swissChili8a581c62021-12-07 13:29:21 -0800340{
swissChili847a78c2021-12-09 17:44:52 -0800341 ParsePos pos = save();
swissChili8a581c62021-12-07 13:29:21 -0800342
swissChili847a78c2021-12-09 17:44:52 -0800343 if (peek() == '}')
344 {
345 return false;
346 }
347
348 QList<Token> pattern;
349 ParseResult ret = parseMany(&pattern);
350
351 if (!ret)
352 {
swissChili847a78c2021-12-09 17:44:52 -0800353 reset(pos);
354 return ret;
355 }
swissChili8a581c62021-12-07 13:29:21 -0800356
357 skip();
358
359 if (get() != '=')
360 {
swissChili847a78c2021-12-09 17:44:52 -0800361 ret = ParseResult(ParseResult::INCOMPLETE, "Expected = in sentence", save());
362 reset(pos);
363 return ret;
swissChili8a581c62021-12-07 13:29:21 -0800364 }
365
swissChili847a78c2021-12-09 17:44:52 -0800366 QList<AstNode> result;
367 ret = parseMany(&result);
368
369 if (!ret)
370 {
swissChili847a78c2021-12-09 17:44:52 -0800371 reset(pos);
372 return ret;
373 }
swissChili8a581c62021-12-07 13:29:21 -0800374
375 skip();
376
swissChili847a78c2021-12-09 17:44:52 -0800377 if (peek() != '}' && get() != ';')
swissChili8a581c62021-12-07 13:29:21 -0800378 {
swissChili847a78c2021-12-09 17:44:52 -0800379 ret = ParseResult(ParseResult::INCOMPLETE, "Expected ; or } after sentence", save());
380 reset(pos);
381 return ret;
swissChili8a581c62021-12-07 13:29:21 -0800382 }
383
384 *sentence = Sentence(pattern, result);
swissChili847a78c2021-12-09 17:44:52 -0800385
swissChili8a581c62021-12-07 13:29:21 -0800386 return true;
387}
388
swissChili847a78c2021-12-09 17:44:52 -0800389ParseResult Parser::parseFunctionDefinition(Function *function)
swissChili8a581c62021-12-07 13:29:21 -0800390{
swissChili847a78c2021-12-09 17:44:52 -0800391 ParsePos pos = save();
392 ParseResult ret;
swissChili8a581c62021-12-07 13:29:21 -0800393
394 Token identifier;
swissChili847a78c2021-12-09 17:44:52 -0800395 if (!(ret = parseIdentifier(&identifier)))
swissChili8a581c62021-12-07 13:29:21 -0800396 {
swissChili847a78c2021-12-09 17:44:52 -0800397 reset(pos);
398 return ret;
swissChili8a581c62021-12-07 13:29:21 -0800399 }
400
401 QString name = identifier.name();
402 Function func(name);
403
404 skip();
405
406 if (get() != '{')
407 {
swissChili847a78c2021-12-09 17:44:52 -0800408 reset(pos);
409 return false;
swissChili8a581c62021-12-07 13:29:21 -0800410 }
411
412 Sentence sentence;
swissChili847a78c2021-12-09 17:44:52 -0800413 while ((ret = parseSentence(&sentence)))
swissChili8a581c62021-12-07 13:29:21 -0800414 {
415 func.addSentence(sentence);
416 skip();
417 }
418
swissChili323883d2022-02-20 16:35:23 -0800419 if (ret.status() == ParseResult::INCOMPLETE)
swissChili847a78c2021-12-09 17:44:52 -0800420 {
swissChili847a78c2021-12-09 17:44:52 -0800421 reset(pos);
422 return ret;
423 }
424
swissChili8a581c62021-12-07 13:29:21 -0800425 if (get() != '}')
426 {
swissChili323883d2022-02-20 16:35:23 -0800427 ret = ParseResult(ParseResult::INCOMPLETE, "Expected } at end of function", save());
swissChili847a78c2021-12-09 17:44:52 -0800428 reset(pos);
429 return ret;
swissChili8a581c62021-12-07 13:29:21 -0800430 }
431
432 *function = func;
433 return true;
434}
swissChili323883d2022-02-20 16:35:23 -0800435
436ParsePos::operator QString()
437{
438 return QString::number(line) + ":" + QString::number(lineOffset);
439}
swissChili918557c2022-02-20 20:16:34 -0800440
441template <typename T>
442ParseResult Parser::parseString(QList<T> *list)
443{
444 skip();
445
446 ParsePos pos = save();
447
448 if (peek() != '\'')
449 return false;
450
451 get();
452
453 list->clear();
454
455 while (peek() != 0 && peek() != '\'')
456 {
457 QChar c = get();
458 if (c == '\\')
459 {
460 QChar next = get();
461 QString conversions = "''n\nt\tr\r";
462
463 for (int i = 0; i < conversions.size(); i += 2)
464 {
465 if (next == conversions[i])
466 list->append(T(conversions[i + 1]));
467 }
468 }
469 else
470 {
471 list->append(T(c));
472 }
473 }
474
475 if (get() == 0)
476 {
477 ParseResult ret(ParseResult::INCOMPLETE, "Expected ' before end of input", save());
478 reset(pos);
479 return ret;
480 }
481
482 return true;
483}