blob: 92979c4f88f6d8acda5b6f05e0f432c83e4641f2 [file] [log] [blame]
swissChili682e7bc2021-12-07 09:04:54 -08001#include "Evaluator.h"
swissChili07d325f2021-12-08 20:02:05 -08002#include "Function.h"
3#include "Matcher.h"
4#include "VarContext.h"
swissChili918557c2022-02-20 20:16:34 -08005#include "PPrint.h"
swissChili682e7bc2021-12-07 09:04:54 -08006
swissChili07d325f2021-12-08 20:02:05 -08007#include <QDebug>
swissChilid85daa92022-02-24 15:29:02 -08008#include <QCoreApplication>
swissChili07d325f2021-12-08 20:02:05 -08009
10RuntimeResult::RuntimeResult(QList<Token> result)
11{
12 _result = result;
13}
14
15RuntimeResult::RuntimeResult(QString message)
16{
17 _errorMessage = message;
swissChilid85daa92022-02-24 15:29:02 -080018 _success = false;
19}
20
21RuntimeResult &RuntimeResult::operator =(const RuntimeResult &other)
22{
23 _errorMessage = other._errorMessage;
24 _success = other._success;
25 _result = other._result;
26
27 return *this;
28}
29
30RuntimeResult RuntimeResult::operator +(const RuntimeResult &other)
31{
32 RuntimeResult res;
33
34 if (_success)
35 {
36 res._success = other._success;
37 res._result = _result;
38 res._result.append(other._result);
39 res._errorMessage = other._errorMessage;
40 }
41 else
42 {
43 res = *this;
44 }
45
46 return res;
47}
48
49RuntimeResult &RuntimeResult::operator +=(const RuntimeResult &other)
50{
51 *this = *this + other;
52 return *this;
swissChili07d325f2021-12-08 20:02:05 -080053}
54
55bool RuntimeResult::success() const
56{
57 return _success;
58}
59
60QString RuntimeResult::message() const
61{
62 return _errorMessage;
63}
64
65QList<Token> RuntimeResult::result() const
66{
67 return _result;
68}
69
70RuntimeResult::operator QString() const
71{
swissChilid85daa92022-02-24 15:29:02 -080072 return _errorMessage + pprint(_result);
swissChili07d325f2021-12-08 20:02:05 -080073}
74
swissChili323883d2022-02-20 16:35:23 -080075Evaluator::Evaluator()
76{
swissChili918557c2022-02-20 20:16:34 -080077 Function buryFn("Br");
78 buryFn.addNativeSentence("s.Name '=' e.Expr", [this](VarContext args)
79 {
80 Token name = args.singleVar("Name");
81 if (name.type() != Token::IDENT)
82 rtError("Invalid argument", "First argument to <Br> must be an identifier, received " + pprint(name));
83
84 bury(name.name(), args.expressionVar("Expr"));
85
86 return QList<Token>();
87 });
88 addFunction(buryFn);
89
90 Function digFn("Dg");
91 digFn.addNativeSentence("s.Name", [this](VarContext args)
92 {
93 Token name = args.singleVar("Name");
94 if (name.type() != Token::IDENT)
95 rtError("Invalid argument", "First argument to <Dg> must be an identifier, received " + pprint(name));
96
97 return dig(name.name());
98 });
99 addFunction(digFn);
100
101 Function copyFn("Cp");
102 copyFn.addNativeSentence("s.Name", [this](VarContext args)
103 {
104 Token name = args.singleVar("Name");
105 if (name.type() != Token::IDENT)
106 rtError("Invalid argument", "First argument to <Cp> must be an identifier, received " + pprint(name));
107
108 return copy(name.name());
109 });
110 addFunction(copyFn);
swissChilid85daa92022-02-24 15:29:02 -0800111
112 Function undefFn("Undef");
113 undefFn.addNativeSentence("s.Name", [this](VarContext args)
114 {
115 Token name = args.singleVar("Name");
116 if (name.type() != Token::IDENT)
117 rtError("Invalid argument", "First argument to <Undef> must be an identifier, received " + pprint(name));
118
119 clearFunction(name.name());
120
121 return QList<Token>();
122 });
123 addFunction(undefFn);
swissChili323883d2022-02-20 16:35:23 -0800124}
125
swissChili07d325f2021-12-08 20:02:05 -0800126void Evaluator::addFunction(Function func)
127{
128 _functions[func.name()] = func;
129}
130
131void Evaluator::clearFunction(QString name)
132{
133 _functions.remove(name);
134}
135
swissChilid85daa92022-02-24 15:29:02 -0800136RuntimeResult Evaluator::evaluate(AstNode node, VarContext ctx, int recursionDepth)
swissChili07d325f2021-12-08 20:02:05 -0800137{
swissChilid85daa92022-02-24 15:29:02 -0800138 if (recursionDepth > _recursionLimit)
139 {
140 throw StackOverflowException(node);
141 }
142
swissChili07d325f2021-12-08 20:02:05 -0800143 if (node.isSym())
144 {
145 return RuntimeResult(QList<Token>{Token(node.symbol())});
146 }
147 else if (node.isIdent())
148 {
149 return RuntimeResult(QList<Token>{Token(node.name())});
150 }
swissChili1060c0e2021-12-09 09:46:42 -0800151 else if (node.isInteger())
152 {
153 return RuntimeResult(QList<Token>{Token::fromInteger(node.integer())});
154 }
swissChili07d325f2021-12-08 20:02:05 -0800155 else if (node.isVar())
156 {
157 if (!ctx.exists(node.name()) || ctx.exists(node.name()) != node.symbol())
158 return RuntimeResult("Variable " + node + " is not defined");
159
160 if (node.symbol() == 'e')
161 {
162 return RuntimeResult(ctx.expressionVar(node.name()));
163 }
164 else
165 {
166 return RuntimeResult(QList<Token>{
167 ctx.singleVar(node.name())
168 });
169 }
170 }
171 else if (node.isParen())
172 {
173 QList<Token> result;
174
175 for (const AstNode &n : node.parenContent())
176 {
177 RuntimeResult internalResult = evaluate(n, ctx);
178 if (!internalResult.success())
179 return internalResult;
180
181 result.append(internalResult.result());
182 }
183
184 return RuntimeResult(QList<Token>{
185 Token(result)
186 });
187 }
188 else if (node.isFunc())
189 {
190 QList<Token> args;
191
192 for (const AstNode &arg : node.funcArgs())
193 {
swissChilid85daa92022-02-24 15:29:02 -0800194 RuntimeResult internalResult = evaluate(arg, ctx, recursionDepth + 1);
swissChili07d325f2021-12-08 20:02:05 -0800195 if (!internalResult.success())
196 return internalResult;
197
198 args.append(internalResult.result());
199 }
200
swissChilid85daa92022-02-24 15:29:02 -0800201 return callFunction(node.name(), args, recursionDepth + 1);
swissChili07d325f2021-12-08 20:02:05 -0800202 }
203
204 return RuntimeResult("#TYPE_ERROR");
205}
206
swissChilid85daa92022-02-24 15:29:02 -0800207RuntimeResult Evaluator::callFunction(QString name, QList<Token> args, int recursionDepth)
swissChili07d325f2021-12-08 20:02:05 -0800208{
209 if (!_functions.contains(name))
210 return RuntimeResult("Function " + name + " is not defined.");
211
212 Function func = _functions[name];
213
214 for (const Sentence &sentence : func.sentences())
215 {
216 MatchResult res = match(args, sentence.pattern(), VarContext());
217
218 if (!res.success)
219 continue;
220
swissChili323883d2022-02-20 16:35:23 -0800221 if (sentence.isExternal())
222 {
swissChili918557c2022-02-20 20:16:34 -0800223 return RuntimeResult(sentence.externResult(res));
swissChili323883d2022-02-20 16:35:23 -0800224 }
225
swissChili07d325f2021-12-08 20:02:05 -0800226 QList<Token> final;
227 for (const AstNode &node : sentence.result())
228 {
swissChilid85daa92022-02-24 15:29:02 -0800229 RuntimeResult argRes = evaluate(node, res.context, recursionDepth);
swissChili07d325f2021-12-08 20:02:05 -0800230 if (!argRes.success())
231 return argRes;
232
233 final.append(argRes.result());
234 }
235
236 return RuntimeResult(final);
237 }
238
swissChili918557c2022-02-20 20:16:34 -0800239 return RuntimeResult("Function " + name + " had no matching sentences for input");
240}
241
swissChilid85daa92022-02-24 15:29:02 -0800242void Evaluator::quit()
243{
244 throw EvalQuitException();
245}
246
swissChilia44bf722022-04-16 18:41:54 -0700247void Evaluator::reset()
248{
249 _vars = {};
250 _functions = {};
251 _shouldContinue = true;
252}
253
swissChili918557c2022-02-20 20:16:34 -0800254QList<Token> Evaluator::dig(QString name)
255{
256 if (_vars.contains(name))
257 {
258 QList<Token> value = _vars[name].pop();
259
260 if (_vars[name].empty())
261 {
262 _vars.remove(name);
263 }
264
265 return value;
266 }
267 else
268 {
269 return {};
270 }
271}
272
273QList<Token> Evaluator::copy(QString name)
274{
275 if (_vars.contains(name))
276 {
277 return _vars[name].last();
278 }
279 else
280 {
281 return {};
282 }
283}
284
285void Evaluator::bury(QString name, QList<Token> expression)
286{
287 if (!_vars.contains(name))
288 {
289 _vars[name] = QStack<QList<Token>>();
290 }
291
292 _vars[name].push(expression);
293}
294
295void rtError(QString brief, QString details)
296{
swissChili5d3e5562022-02-24 16:49:19 -0800297 throw AssertionException(brief + "\n" + details);
swissChili07d325f2021-12-08 20:02:05 -0800298}
swissChilid85daa92022-02-24 15:29:02 -0800299
300void EvalQuitException::raise() const
301{
302 throw *this;
303}
304
305EvalQuitException *EvalQuitException::clone() const
306{
307 return new EvalQuitException(*this);
308}
309
310StackOverflowException::StackOverflowException(AstNode failedAt)
311 : QException()
312{
313 _failedAt = failedAt;
314}
315
316AstNode StackOverflowException::failedAt() const
317{
318 return _failedAt;
319}
320
321void StackOverflowException::raise() const
322{
323 throw *this;
324}
325
326StackOverflowException *StackOverflowException::clone() const
327{
328 return new StackOverflowException(*this);
329}
330
331StackOverflowException::operator QString() const
332{
333 return "StackOverflowException: at " + pprint(_failedAt);
334}
swissChili5d3e5562022-02-24 16:49:19 -0800335
336AssertionException::AssertionException(QString message)
337 : QException()
338{
339 _message = message;
340}
341
342QString AssertionException::message() const
343{
344 return _message;
345}
346
347void AssertionException::raise() const
348{
349 throw *this;
350}
351
352AssertionException *AssertionException::clone() const
353{
354 return new AssertionException(*this);
355}
356
357AssertionException::operator QString() const
358{
359 return "AssertionException: " + _message;
360}