blob: 68e5aeff6e0b6ce00f25087d1c24a4b270493ec2 [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())
swissChilie386bc72022-02-24 21:31:31 -080054 return QChar(0);
swissChilic71acc62021-12-07 08:03:37 -080055
56 return _input[_pos];
57}
58
59QChar Parser::get()
60{
swissChilie386bc72022-02-24 21:31:31 -080061 QChar c;
62
63 if (_pos < _input.size())
64 c = _input[_pos++];
65 else
66 return QChar(0);
swissChili847a78c2021-12-09 17:44:52 -080067
68 if (c == '\n')
69 {
70 _line++;
71 _offset = 0;
72 }
73 else
74 {
75 _offset++;
76 }
77
78 return c;
swissChilic71acc62021-12-07 08:03:37 -080079}
80
81bool Parser::atEnd()
82{
83 return _pos >= _input.length();
84}
85
86void Parser::skip()
87{
88 while (peek().isSpace())
89 get();
90}
91
swissChili323883d2022-02-20 16:35:23 -080092QString Parser::line(int n) const
93{
94 return _input.split("\n")[n];
95}
96
swissChili847a78c2021-12-09 17:44:52 -080097ParsePos Parser::save() const
98{
99 return ParsePos{_line, _pos, _offset};
100}
101
102void Parser::reset(ParsePos pos)
103{
104 _line = pos.line;
105 _pos = pos.pos;
106 _offset = pos.lineOffset;
107}
108
swissChili682e7bc2021-12-07 09:04:54 -0800109template <typename T>
swissChili847a78c2021-12-09 17:44:52 -0800110ParseResult Parser::parseSymbol(T *node)
swissChilic71acc62021-12-07 08:03:37 -0800111{
112 skip();
113
114 if (peek().isLetter())
115 {
swissChili682e7bc2021-12-07 09:04:54 -0800116 *node = T(get());
swissChilic71acc62021-12-07 08:03:37 -0800117 return true;
118 }
119
120 return false;
121}
122
swissChili682e7bc2021-12-07 09:04:54 -0800123template <typename T>
swissChili847a78c2021-12-09 17:44:52 -0800124ParseResult Parser::parseIdentifier(T *node)
swissChilic71acc62021-12-07 08:03:37 -0800125{
126 skip();
127
128 QString buffer;
129
130 if (peek().isUpper())
131 {
132 while (peek().isLetter() || peek() == '-' || peek() == '_' || peek().isNumber())
133 {
134 buffer += get();
135 }
136
swissChili682e7bc2021-12-07 09:04:54 -0800137 *node = T(buffer);
swissChilic71acc62021-12-07 08:03:37 -0800138 return true;
139 }
140
141 return false;
142}
143
swissChili682e7bc2021-12-07 09:04:54 -0800144template <typename T>
swissChili847a78c2021-12-09 17:44:52 -0800145ParseResult Parser::parseNumber(T *node)
swissChilic71acc62021-12-07 08:03:37 -0800146{
147 skip();
148
149 QString buffer;
150
151 if (peek().isDigit())
152 {
153 while (peek().isDigit())
154 buffer += get();
155
swissChili1060c0e2021-12-09 09:46:42 -0800156 *node = T::fromInteger(buffer.toInt());
swissChilic71acc62021-12-07 08:03:37 -0800157 return true;
158 }
159
160 return false;
161}
162
swissChili682e7bc2021-12-07 09:04:54 -0800163template <typename T>
swissChili847a78c2021-12-09 17:44:52 -0800164ParseResult Parser::parseVariable(T *node)
swissChilic71acc62021-12-07 08:03:37 -0800165{
166 skip();
167
swissChili847a78c2021-12-09 17:44:52 -0800168 ParsePos pos = save();
swissChilic71acc62021-12-07 08:03:37 -0800169
170 if (peek() == 's' || peek() == 'e' || peek() == 't')
171 {
172 char type = get().toLatin1();
173
174 if (peek() == '.')
175 {
176 get();
177
swissChili682e7bc2021-12-07 09:04:54 -0800178 T nameNode;
swissChilic71acc62021-12-07 08:03:37 -0800179
swissChili682e7bc2021-12-07 09:04:54 -0800180 if (parseIdentifier(&nameNode))
swissChilic71acc62021-12-07 08:03:37 -0800181 {
swissChili682e7bc2021-12-07 09:04:54 -0800182 *node = T(type, nameNode.name());
183 return true;
184 }
185 else if (parseSymbol(&nameNode))
186 {
187 *node = T(type, QString(nameNode.symbol()));
swissChilic71acc62021-12-07 08:03:37 -0800188 return true;
189 }
swissChili847a78c2021-12-09 17:44:52 -0800190 else
191 {
192 ParseResult ret(ParseResult::INCOMPLETE,
193 "Expected identifier or symbol after . in variable",
swissChili323883d2022-02-20 16:35:23 -0800194 save());
swissChili847a78c2021-12-09 17:44:52 -0800195
196 reset(pos);
197
198 return ret;
199 }
swissChilic71acc62021-12-07 08:03:37 -0800200 }
201 }
202
swissChili847a78c2021-12-09 17:44:52 -0800203 reset(pos);
swissChilic71acc62021-12-07 08:03:37 -0800204 return false;
205}
206
swissChili682e7bc2021-12-07 09:04:54 -0800207template <typename T>
swissChili847a78c2021-12-09 17:44:52 -0800208ParseResult Parser::parseMany(QList<T> *list)
swissChilic71acc62021-12-07 08:03:37 -0800209{
swissChili918557c2022-02-20 20:16:34 -0800210 QList<T> nodes, string;
swissChili682e7bc2021-12-07 09:04:54 -0800211 T next;
swissChili918557c2022-02-20 20:16:34 -0800212 ParseResult ret, stringRet;
swissChilic71acc62021-12-07 08:03:37 -0800213
swissChili918557c2022-02-20 20:16:34 -0800214 while ((ret = parseOne(&next)) || (stringRet = parseString(&string)))
swissChilic71acc62021-12-07 08:03:37 -0800215 {
swissChili918557c2022-02-20 20:16:34 -0800216 if (ret)
217 nodes.append(next);
218 else if (stringRet)
219 nodes.append(string);
220
221 // So that we can check if anything was incomplete recently at the end
222 ret = stringRet = false;
swissChilic71acc62021-12-07 08:03:37 -0800223 }
224
swissChili847a78c2021-12-09 17:44:52 -0800225 *list = nodes;
226
227 if (ret.status() == ParseResult::INCOMPLETE)
228 return ret;
swissChili918557c2022-02-20 20:16:34 -0800229 else if (stringRet.status() == ParseResult::INCOMPLETE)
230 return ret;
swissChili847a78c2021-12-09 17:44:52 -0800231 else
232 return true;
swissChilic71acc62021-12-07 08:03:37 -0800233}
234
swissChili682e7bc2021-12-07 09:04:54 -0800235template <typename T>
swissChili847a78c2021-12-09 17:44:52 -0800236ParseResult Parser::parseParens(T *node)
swissChilic71acc62021-12-07 08:03:37 -0800237{
238 skip();
239
swissChili847a78c2021-12-09 17:44:52 -0800240 ParsePos pos = save();
swissChilic71acc62021-12-07 08:03:37 -0800241
242 if (peek() != '(')
243 return false;
244
245 get();
246
swissChili847a78c2021-12-09 17:44:52 -0800247 QList<T> many;
248 ParseResult ret = parseMany(&many);
249
swissChili682e7bc2021-12-07 09:04:54 -0800250 *node = T(many);
swissChilic71acc62021-12-07 08:03:37 -0800251
252 skip();
253 if (peek() != ')')
254 {
swissChili847a78c2021-12-09 17:44:52 -0800255 ret = ParseResult(ParseResult::INCOMPLETE, "Expected ) in parenthesized list", save());
256 reset(pos);
257
258 return ret;
swissChilic71acc62021-12-07 08:03:37 -0800259 }
260
261 get();
262
263 return true;
264}
265
swissChili847a78c2021-12-09 17:44:52 -0800266ParseResult Parser::parseFunction(AstNode *node)
swissChilic71acc62021-12-07 08:03:37 -0800267{
268 skip();
269
swissChili847a78c2021-12-09 17:44:52 -0800270 ParsePos pos = save();
271 ParseResult ret;
swissChilic71acc62021-12-07 08:03:37 -0800272
273 if (peek() != '<')
274 return false;
275
276 get();
277
278 AstNode head;
swissChili847a78c2021-12-09 17:44:52 -0800279 if (!(ret = parseIdentifier(&head)))
swissChilic71acc62021-12-07 08:03:37 -0800280 {
swissChili323883d2022-02-20 16:35:23 -0800281 ParsePos endPos = save();
swissChili847a78c2021-12-09 17:44:52 -0800282 reset(pos);
swissChili323883d2022-02-20 16:35:23 -0800283 return ParseResult(ParseResult::INCOMPLETE, "Expected identifier following < in function call", endPos);
swissChilic71acc62021-12-07 08:03:37 -0800284 }
285
swissChili847a78c2021-12-09 17:44:52 -0800286 QList<AstNode> body;
287 ret = parseMany(&body);
288
289 if (!ret)
290 {
291 reset(pos);
292 return ret;
293 }
294
swissChilic71acc62021-12-07 08:03:37 -0800295 *node = AstNode(head.name(), body);
296
297 skip();
298 if (peek() != '>')
299 {
swissChili847a78c2021-12-09 17:44:52 -0800300 ret = ParseResult(ParseResult::INCOMPLETE, "Expected >", save());
301 reset(pos);
302 return ret;
swissChilic71acc62021-12-07 08:03:37 -0800303 }
304
305 get();
306
307 return true;
308}
swissChili682e7bc2021-12-07 09:04:54 -0800309
310template <>
swissChili847a78c2021-12-09 17:44:52 -0800311ParseResult Parser::parseOne<Token>(Token *node)
swissChili682e7bc2021-12-07 09:04:54 -0800312{
swissChili323883d2022-02-20 16:35:23 -0800313 ParseResult ret;
314
315 if ((ret = parseVariable(node)).status() == ParseResult::COMPLETE || ret.status() == ParseResult::INCOMPLETE)
316 return ret;
317 if ((ret = parseNumber(node)).status() == ParseResult::COMPLETE || ret.status() == ParseResult::INCOMPLETE)
318 return ret;
319 if ((ret = parseIdentifier(node)).status() == ParseResult::COMPLETE || ret.status() == ParseResult::INCOMPLETE)
320 return ret;
321 if ((ret = parseSymbol(node)).status() == ParseResult::COMPLETE || ret.status() == ParseResult::INCOMPLETE)
322 return ret;
323 return parseParens(node);
swissChili682e7bc2021-12-07 09:04:54 -0800324}
325
326template <>
swissChili847a78c2021-12-09 17:44:52 -0800327ParseResult Parser::parseOne<AstNode>(AstNode *node)
swissChili682e7bc2021-12-07 09:04:54 -0800328{
swissChili323883d2022-02-20 16:35:23 -0800329 ParseResult ret;
330
331 if ((ret = parseFunction(node)).status() == ParseResult::COMPLETE || ret.status() == ParseResult::INCOMPLETE)
332 return ret;
333 if ((ret = parseVariable(node)).status() == ParseResult::COMPLETE || ret.status() == ParseResult::INCOMPLETE)
334 return ret;
335 if ((ret = parseNumber(node)).status() == ParseResult::COMPLETE || ret.status() == ParseResult::INCOMPLETE)
336 return ret;
337 if ((ret = parseIdentifier(node)).status() == ParseResult::COMPLETE || ret.status() == ParseResult::INCOMPLETE)
338 return ret;
339 if ((ret = parseSymbol(node)).status() == ParseResult::COMPLETE || ret.status() == ParseResult::INCOMPLETE)
340 return ret;
341 return parseParens(node);
swissChili682e7bc2021-12-07 09:04:54 -0800342}
swissChili8a581c62021-12-07 13:29:21 -0800343
swissChili847a78c2021-12-09 17:44:52 -0800344ParseResult Parser::parseSentence(Sentence *sentence)
swissChili8a581c62021-12-07 13:29:21 -0800345{
swissChili847a78c2021-12-09 17:44:52 -0800346 ParsePos pos = save();
swissChili8a581c62021-12-07 13:29:21 -0800347
swissChili847a78c2021-12-09 17:44:52 -0800348 if (peek() == '}')
349 {
350 return false;
351 }
352
353 QList<Token> pattern;
354 ParseResult ret = parseMany(&pattern);
355
356 if (!ret)
357 {
swissChili847a78c2021-12-09 17:44:52 -0800358 reset(pos);
359 return ret;
360 }
swissChili8a581c62021-12-07 13:29:21 -0800361
362 skip();
363
364 if (get() != '=')
365 {
swissChili847a78c2021-12-09 17:44:52 -0800366 ret = ParseResult(ParseResult::INCOMPLETE, "Expected = in sentence", save());
367 reset(pos);
368 return ret;
swissChili8a581c62021-12-07 13:29:21 -0800369 }
370
swissChili847a78c2021-12-09 17:44:52 -0800371 QList<AstNode> result;
372 ret = parseMany(&result);
373
374 if (!ret)
375 {
swissChili847a78c2021-12-09 17:44:52 -0800376 reset(pos);
377 return ret;
378 }
swissChili8a581c62021-12-07 13:29:21 -0800379
380 skip();
381
swissChili847a78c2021-12-09 17:44:52 -0800382 if (peek() != '}' && get() != ';')
swissChili8a581c62021-12-07 13:29:21 -0800383 {
swissChili847a78c2021-12-09 17:44:52 -0800384 ret = ParseResult(ParseResult::INCOMPLETE, "Expected ; or } after sentence", save());
385 reset(pos);
386 return ret;
swissChili8a581c62021-12-07 13:29:21 -0800387 }
388
389 *sentence = Sentence(pattern, result);
swissChili847a78c2021-12-09 17:44:52 -0800390
swissChili8a581c62021-12-07 13:29:21 -0800391 return true;
392}
393
swissChili847a78c2021-12-09 17:44:52 -0800394ParseResult Parser::parseFunctionDefinition(Function *function)
swissChili8a581c62021-12-07 13:29:21 -0800395{
swissChili847a78c2021-12-09 17:44:52 -0800396 ParsePos pos = save();
397 ParseResult ret;
swissChili8a581c62021-12-07 13:29:21 -0800398
399 Token identifier;
swissChili847a78c2021-12-09 17:44:52 -0800400 if (!(ret = parseIdentifier(&identifier)))
swissChili8a581c62021-12-07 13:29:21 -0800401 {
swissChili847a78c2021-12-09 17:44:52 -0800402 reset(pos);
403 return ret;
swissChili8a581c62021-12-07 13:29:21 -0800404 }
405
406 QString name = identifier.name();
407 Function func(name);
408
409 skip();
410
411 if (get() != '{')
412 {
swissChili847a78c2021-12-09 17:44:52 -0800413 reset(pos);
414 return false;
swissChili8a581c62021-12-07 13:29:21 -0800415 }
416
417 Sentence sentence;
swissChili847a78c2021-12-09 17:44:52 -0800418 while ((ret = parseSentence(&sentence)))
swissChili8a581c62021-12-07 13:29:21 -0800419 {
420 func.addSentence(sentence);
421 skip();
422 }
423
swissChili323883d2022-02-20 16:35:23 -0800424 if (ret.status() == ParseResult::INCOMPLETE)
swissChili847a78c2021-12-09 17:44:52 -0800425 {
swissChili847a78c2021-12-09 17:44:52 -0800426 reset(pos);
427 return ret;
428 }
429
swissChili8a581c62021-12-07 13:29:21 -0800430 if (get() != '}')
431 {
swissChili323883d2022-02-20 16:35:23 -0800432 ret = ParseResult(ParseResult::INCOMPLETE, "Expected } at end of function", save());
swissChili847a78c2021-12-09 17:44:52 -0800433 reset(pos);
434 return ret;
swissChili8a581c62021-12-07 13:29:21 -0800435 }
436
437 *function = func;
438 return true;
439}
swissChili323883d2022-02-20 16:35:23 -0800440
441ParsePos::operator QString()
442{
443 return QString::number(line) + ":" + QString::number(lineOffset);
444}
swissChili918557c2022-02-20 20:16:34 -0800445
446template <typename T>
447ParseResult Parser::parseString(QList<T> *list)
448{
449 skip();
450
451 ParsePos pos = save();
452
453 if (peek() != '\'')
454 return false;
455
456 get();
457
458 list->clear();
459
460 while (peek() != 0 && peek() != '\'')
461 {
462 QChar c = get();
463 if (c == '\\')
464 {
465 QChar next = get();
466 QString conversions = "''n\nt\tr\r";
467
468 for (int i = 0; i < conversions.size(); i += 2)
469 {
470 if (next == conversions[i])
471 list->append(T(conversions[i + 1]));
472 }
473 }
474 else
475 {
476 list->append(T(c));
477 }
478 }
479
480 if (get() == 0)
481 {
482 ParseResult ret(ParseResult::INCOMPLETE, "Expected ' before end of input", save());
483 reset(pos);
484 return ret;
485 }
486
487 return true;
488}