blob: 9ce5bf7cd6c8df9bb27365c86e0411d406ec4132 [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
swissChili918557c2022-02-20 20:16:34 -0800247QList<Token> Evaluator::dig(QString name)
248{
249 if (_vars.contains(name))
250 {
251 QList<Token> value = _vars[name].pop();
252
253 if (_vars[name].empty())
254 {
255 _vars.remove(name);
256 }
257
258 return value;
259 }
260 else
261 {
262 return {};
263 }
264}
265
266QList<Token> Evaluator::copy(QString name)
267{
268 if (_vars.contains(name))
269 {
270 return _vars[name].last();
271 }
272 else
273 {
274 return {};
275 }
276}
277
278void Evaluator::bury(QString name, QList<Token> expression)
279{
280 if (!_vars.contains(name))
281 {
282 _vars[name] = QStack<QList<Token>>();
283 }
284
285 _vars[name].push(expression);
286}
287
288void rtError(QString brief, QString details)
289{
swissChili5d3e5562022-02-24 16:49:19 -0800290 throw AssertionException(brief + "\n" + details);
swissChili07d325f2021-12-08 20:02:05 -0800291}
swissChilid85daa92022-02-24 15:29:02 -0800292
293void EvalQuitException::raise() const
294{
295 throw *this;
296}
297
298EvalQuitException *EvalQuitException::clone() const
299{
300 return new EvalQuitException(*this);
301}
302
303StackOverflowException::StackOverflowException(AstNode failedAt)
304 : QException()
305{
306 _failedAt = failedAt;
307}
308
309AstNode StackOverflowException::failedAt() const
310{
311 return _failedAt;
312}
313
314void StackOverflowException::raise() const
315{
316 throw *this;
317}
318
319StackOverflowException *StackOverflowException::clone() const
320{
321 return new StackOverflowException(*this);
322}
323
324StackOverflowException::operator QString() const
325{
326 return "StackOverflowException: at " + pprint(_failedAt);
327}
swissChili5d3e5562022-02-24 16:49:19 -0800328
329AssertionException::AssertionException(QString message)
330 : QException()
331{
332 _message = message;
333}
334
335QString AssertionException::message() const
336{
337 return _message;
338}
339
340void AssertionException::raise() const
341{
342 throw *this;
343}
344
345AssertionException *AssertionException::clone() const
346{
347 return new AssertionException(*this);
348}
349
350AssertionException::operator QString() const
351{
352 return "AssertionException: " + _message;
353}