blob: 2c62f276db71b2d546cce8d4874406b3dea0a1a5 [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;
16 _message = message;
17 _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
swissChili2506b922022-02-15 21:07:20 -080040ParseResult ParseResult::operator ||(const ParseResult &other) const
41{
42 if (_status == COMPLETE || _status == INCOMPLETE)
43 return *this;
44 else
45 return other;
46}
47
swissChilic71acc62021-12-07 08:03:37 -080048Parser::Parser(QString input)
49{
50 _input = input;
51}
52
53QChar Parser::peek()
54{
55 if (atEnd())
56 return 0;
57
58 return _input[_pos];
59}
60
61QChar Parser::get()
62{
swissChili847a78c2021-12-09 17:44:52 -080063 QChar c = _input[_pos++];
64
65 if (c == '\n')
66 {
67 _line++;
68 _offset = 0;
69 }
70 else
71 {
72 _offset++;
73 }
74
75 return c;
swissChilic71acc62021-12-07 08:03:37 -080076}
77
78bool Parser::atEnd()
79{
80 return _pos >= _input.length();
81}
82
83void Parser::skip()
84{
85 while (peek().isSpace())
86 get();
87}
88
swissChili847a78c2021-12-09 17:44:52 -080089ParsePos Parser::save() const
90{
91 return ParsePos{_line, _pos, _offset};
92}
93
94void Parser::reset(ParsePos pos)
95{
96 _line = pos.line;
97 _pos = pos.pos;
98 _offset = pos.lineOffset;
99}
100
swissChili682e7bc2021-12-07 09:04:54 -0800101template <typename T>
swissChili847a78c2021-12-09 17:44:52 -0800102ParseResult Parser::parseSymbol(T *node)
swissChilic71acc62021-12-07 08:03:37 -0800103{
104 skip();
105
106 if (peek().isLetter())
107 {
swissChili682e7bc2021-12-07 09:04:54 -0800108 *node = T(get());
swissChilic71acc62021-12-07 08:03:37 -0800109 return true;
110 }
111
112 return false;
113}
114
swissChili682e7bc2021-12-07 09:04:54 -0800115template <typename T>
swissChili847a78c2021-12-09 17:44:52 -0800116ParseResult Parser::parseIdentifier(T *node)
swissChilic71acc62021-12-07 08:03:37 -0800117{
118 skip();
119
120 QString buffer;
121
122 if (peek().isUpper())
123 {
124 while (peek().isLetter() || peek() == '-' || peek() == '_' || peek().isNumber())
125 {
126 buffer += get();
127 }
128
swissChili682e7bc2021-12-07 09:04:54 -0800129 *node = T(buffer);
swissChilic71acc62021-12-07 08:03:37 -0800130 return true;
131 }
132
133 return false;
134}
135
swissChili682e7bc2021-12-07 09:04:54 -0800136template <typename T>
swissChili847a78c2021-12-09 17:44:52 -0800137ParseResult Parser::parseNumber(T *node)
swissChilic71acc62021-12-07 08:03:37 -0800138{
139 skip();
140
141 QString buffer;
142
143 if (peek().isDigit())
144 {
145 while (peek().isDigit())
146 buffer += get();
147
swissChili1060c0e2021-12-09 09:46:42 -0800148 *node = T::fromInteger(buffer.toInt());
swissChilic71acc62021-12-07 08:03:37 -0800149 return true;
150 }
151
152 return false;
153}
154
swissChili682e7bc2021-12-07 09:04:54 -0800155template <typename T>
swissChili847a78c2021-12-09 17:44:52 -0800156ParseResult Parser::parseVariable(T *node)
swissChilic71acc62021-12-07 08:03:37 -0800157{
158 skip();
159
swissChili847a78c2021-12-09 17:44:52 -0800160 ParsePos pos = save();
swissChilic71acc62021-12-07 08:03:37 -0800161
162 if (peek() == 's' || peek() == 'e' || peek() == 't')
163 {
164 char type = get().toLatin1();
165
166 if (peek() == '.')
167 {
168 get();
169
swissChili682e7bc2021-12-07 09:04:54 -0800170 T nameNode;
swissChilic71acc62021-12-07 08:03:37 -0800171
swissChili682e7bc2021-12-07 09:04:54 -0800172 if (parseIdentifier(&nameNode))
swissChilic71acc62021-12-07 08:03:37 -0800173 {
swissChili682e7bc2021-12-07 09:04:54 -0800174 *node = T(type, nameNode.name());
175 return true;
176 }
177 else if (parseSymbol(&nameNode))
178 {
179 *node = T(type, QString(nameNode.symbol()));
swissChilic71acc62021-12-07 08:03:37 -0800180 return true;
181 }
swissChili847a78c2021-12-09 17:44:52 -0800182 else
183 {
184 ParseResult ret(ParseResult::INCOMPLETE,
185 "Expected identifier or symbol after . in variable",
186 pos);
187
188 reset(pos);
189
190 return ret;
191 }
swissChilic71acc62021-12-07 08:03:37 -0800192 }
193 }
194
swissChili847a78c2021-12-09 17:44:52 -0800195 reset(pos);
swissChilic71acc62021-12-07 08:03:37 -0800196 return false;
197}
198
swissChili682e7bc2021-12-07 09:04:54 -0800199template <typename T>
swissChili847a78c2021-12-09 17:44:52 -0800200ParseResult Parser::parseMany(QList<T> *list)
swissChilic71acc62021-12-07 08:03:37 -0800201{
swissChili847a78c2021-12-09 17:44:52 -0800202 QList<T> nodes;
swissChili682e7bc2021-12-07 09:04:54 -0800203 T next;
swissChili847a78c2021-12-09 17:44:52 -0800204 ParseResult ret;
swissChilic71acc62021-12-07 08:03:37 -0800205
swissChili847a78c2021-12-09 17:44:52 -0800206 while ((ret = parseOne(&next)))
swissChilic71acc62021-12-07 08:03:37 -0800207 {
208 nodes.append(next);
209 }
210
swissChili847a78c2021-12-09 17:44:52 -0800211 *list = nodes;
212
213 if (ret.status() == ParseResult::INCOMPLETE)
214 return ret;
215 else
216 return true;
swissChilic71acc62021-12-07 08:03:37 -0800217}
218
swissChili682e7bc2021-12-07 09:04:54 -0800219template <typename T>
swissChili847a78c2021-12-09 17:44:52 -0800220ParseResult Parser::parseParens(T *node)
swissChilic71acc62021-12-07 08:03:37 -0800221{
222 skip();
223
swissChili847a78c2021-12-09 17:44:52 -0800224 ParsePos pos = save();
swissChilic71acc62021-12-07 08:03:37 -0800225
226 if (peek() != '(')
227 return false;
228
229 get();
230
swissChili847a78c2021-12-09 17:44:52 -0800231 QList<T> many;
232 ParseResult ret = parseMany(&many);
233
swissChili682e7bc2021-12-07 09:04:54 -0800234 *node = T(many);
swissChilic71acc62021-12-07 08:03:37 -0800235
236 skip();
237 if (peek() != ')')
238 {
swissChili847a78c2021-12-09 17:44:52 -0800239 ret = ParseResult(ParseResult::INCOMPLETE, "Expected ) in parenthesized list", save());
240 reset(pos);
241
242 return ret;
swissChilic71acc62021-12-07 08:03:37 -0800243 }
244
245 get();
246
247 return true;
248}
249
swissChili847a78c2021-12-09 17:44:52 -0800250ParseResult Parser::parseFunction(AstNode *node)
swissChilic71acc62021-12-07 08:03:37 -0800251{
252 skip();
253
swissChili847a78c2021-12-09 17:44:52 -0800254 ParsePos pos = save();
255 ParseResult ret;
swissChilic71acc62021-12-07 08:03:37 -0800256
257 if (peek() != '<')
258 return false;
259
260 get();
261
262 AstNode head;
swissChili847a78c2021-12-09 17:44:52 -0800263 if (!(ret = parseIdentifier(&head)))
swissChilic71acc62021-12-07 08:03:37 -0800264 {
swissChili847a78c2021-12-09 17:44:52 -0800265 reset(pos);
266 return ret;
swissChilic71acc62021-12-07 08:03:37 -0800267 }
268
swissChili847a78c2021-12-09 17:44:52 -0800269 QList<AstNode> body;
270 ret = parseMany(&body);
271
272 if (!ret)
273 {
274 reset(pos);
275 return ret;
276 }
277
swissChilic71acc62021-12-07 08:03:37 -0800278 *node = AstNode(head.name(), body);
279
280 skip();
281 if (peek() != '>')
282 {
swissChili847a78c2021-12-09 17:44:52 -0800283 ret = ParseResult(ParseResult::INCOMPLETE, "Expected >", save());
284 reset(pos);
285 return ret;
swissChilic71acc62021-12-07 08:03:37 -0800286 }
287
288 get();
289
290 return true;
291}
swissChili682e7bc2021-12-07 09:04:54 -0800292
293template <>
swissChili847a78c2021-12-09 17:44:52 -0800294ParseResult Parser::parseOne<Token>(Token *node)
swissChili682e7bc2021-12-07 09:04:54 -0800295{
296 return parseVariable(node) ||
297 parseNumber(node) ||
298 parseIdentifier(node) ||
299 parseSymbol(node) ||
300 parseParens(node);
301}
302
303template <>
swissChili847a78c2021-12-09 17:44:52 -0800304ParseResult Parser::parseOne<AstNode>(AstNode *node)
swissChili682e7bc2021-12-07 09:04:54 -0800305{
306 return parseFunction(node) ||
307 parseVariable(node) ||
308 parseNumber(node) ||
309 parseIdentifier(node) ||
310 parseSymbol(node) ||
311 parseParens(node);
312}
swissChili8a581c62021-12-07 13:29:21 -0800313
swissChili847a78c2021-12-09 17:44:52 -0800314ParseResult Parser::parseSentence(Sentence *sentence)
swissChili8a581c62021-12-07 13:29:21 -0800315{
swissChili847a78c2021-12-09 17:44:52 -0800316 ParsePos pos = save();
swissChili8a581c62021-12-07 13:29:21 -0800317
swissChili847a78c2021-12-09 17:44:52 -0800318 if (peek() == '}')
319 {
320 return false;
321 }
322
323 QList<Token> pattern;
324 ParseResult ret = parseMany(&pattern);
325
326 if (!ret)
327 {
swissChili847a78c2021-12-09 17:44:52 -0800328 reset(pos);
329 return ret;
330 }
swissChili8a581c62021-12-07 13:29:21 -0800331
332 skip();
333
334 if (get() != '=')
335 {
swissChili847a78c2021-12-09 17:44:52 -0800336 ret = ParseResult(ParseResult::INCOMPLETE, "Expected = in sentence", save());
337 reset(pos);
338 return ret;
swissChili8a581c62021-12-07 13:29:21 -0800339 }
340
swissChili847a78c2021-12-09 17:44:52 -0800341 QList<AstNode> result;
342 ret = parseMany(&result);
343
344 if (!ret)
345 {
swissChili847a78c2021-12-09 17:44:52 -0800346 reset(pos);
347 return ret;
348 }
swissChili8a581c62021-12-07 13:29:21 -0800349
350 skip();
351
swissChili847a78c2021-12-09 17:44:52 -0800352 if (peek() != '}' && get() != ';')
swissChili8a581c62021-12-07 13:29:21 -0800353 {
swissChili847a78c2021-12-09 17:44:52 -0800354 ret = ParseResult(ParseResult::INCOMPLETE, "Expected ; or } after sentence", save());
355 reset(pos);
356 return ret;
swissChili8a581c62021-12-07 13:29:21 -0800357 }
358
359 *sentence = Sentence(pattern, result);
swissChili847a78c2021-12-09 17:44:52 -0800360
swissChili8a581c62021-12-07 13:29:21 -0800361 return true;
362}
363
swissChili847a78c2021-12-09 17:44:52 -0800364ParseResult Parser::parseFunctionDefinition(Function *function)
swissChili8a581c62021-12-07 13:29:21 -0800365{
swissChili847a78c2021-12-09 17:44:52 -0800366 ParsePos pos = save();
367 ParseResult ret;
swissChili8a581c62021-12-07 13:29:21 -0800368
369 Token identifier;
swissChili847a78c2021-12-09 17:44:52 -0800370 if (!(ret = parseIdentifier(&identifier)))
swissChili8a581c62021-12-07 13:29:21 -0800371 {
swissChili847a78c2021-12-09 17:44:52 -0800372 reset(pos);
373 return ret;
swissChili8a581c62021-12-07 13:29:21 -0800374 }
375
376 QString name = identifier.name();
377 Function func(name);
378
379 skip();
380
381 if (get() != '{')
382 {
swissChili847a78c2021-12-09 17:44:52 -0800383 reset(pos);
384 return false;
swissChili8a581c62021-12-07 13:29:21 -0800385 }
386
387 Sentence sentence;
swissChili847a78c2021-12-09 17:44:52 -0800388 while ((ret = parseSentence(&sentence)))
swissChili8a581c62021-12-07 13:29:21 -0800389 {
390 func.addSentence(sentence);
391 skip();
392 }
393
swissChili847a78c2021-12-09 17:44:52 -0800394 if (ret.status() == ParseResult::INCOMPLETE)
395 {
swissChili847a78c2021-12-09 17:44:52 -0800396 reset(pos);
397 return ret;
398 }
399
swissChili8a581c62021-12-07 13:29:21 -0800400 if (get() != '}')
401 {
swissChili847a78c2021-12-09 17:44:52 -0800402 ret = ParseResult(ParseResult::INCOMPLETE, "Expected } at end of function");
403 reset(pos);
404 return ret;
swissChili8a581c62021-12-07 13:29:21 -0800405 }
406
407 *function = func;
408 return true;
409}