blob: 5177fe55543376092bff783eb4af867bc1bc3abe [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>
8
9RuntimeResult::RuntimeResult(QList<Token> result)
10{
11 _result = result;
12}
13
14RuntimeResult::RuntimeResult(QString message)
15{
16 _errorMessage = message;
swissChili923bd532021-12-08 22:48:58 -080017 _success = false;
swissChili07d325f2021-12-08 20:02:05 -080018}
19
20bool RuntimeResult::success() const
21{
22 return _success;
23}
24
25QString RuntimeResult::message() const
26{
27 return _errorMessage;
28}
29
30QList<Token> RuntimeResult::result() const
31{
32 return _result;
33}
34
35RuntimeResult::operator QString() const
36{
37 return QString(_success) + " " + _errorMessage;
38}
39
swissChili323883d2022-02-20 16:35:23 -080040Evaluator::Evaluator()
41{
swissChili918557c2022-02-20 20:16:34 -080042 Function buryFn("Br");
43 buryFn.addNativeSentence("s.Name '=' e.Expr", [this](VarContext args)
44 {
45 Token name = args.singleVar("Name");
46 if (name.type() != Token::IDENT)
47 rtError("Invalid argument", "First argument to <Br> must be an identifier, received " + pprint(name));
48
49 bury(name.name(), args.expressionVar("Expr"));
50
51 return QList<Token>();
52 });
53 addFunction(buryFn);
54
55 Function digFn("Dg");
56 digFn.addNativeSentence("s.Name", [this](VarContext args)
57 {
58 Token name = args.singleVar("Name");
59 if (name.type() != Token::IDENT)
60 rtError("Invalid argument", "First argument to <Dg> must be an identifier, received " + pprint(name));
61
62 return dig(name.name());
63 });
64 addFunction(digFn);
65
66 Function copyFn("Cp");
67 copyFn.addNativeSentence("s.Name", [this](VarContext args)
68 {
69 Token name = args.singleVar("Name");
70 if (name.type() != Token::IDENT)
71 rtError("Invalid argument", "First argument to <Cp> must be an identifier, received " + pprint(name));
72
73 return copy(name.name());
74 });
75 addFunction(copyFn);
swissChili323883d2022-02-20 16:35:23 -080076}
77
swissChili07d325f2021-12-08 20:02:05 -080078void Evaluator::addFunction(Function func)
79{
80 _functions[func.name()] = func;
81}
82
83void Evaluator::clearFunction(QString name)
84{
85 _functions.remove(name);
86}
87
88RuntimeResult Evaluator::evaluate(AstNode node, VarContext ctx)
89{
90 if (node.isSym())
91 {
92 return RuntimeResult(QList<Token>{Token(node.symbol())});
93 }
94 else if (node.isIdent())
95 {
96 return RuntimeResult(QList<Token>{Token(node.name())});
97 }
swissChili1060c0e2021-12-09 09:46:42 -080098 else if (node.isInteger())
99 {
100 return RuntimeResult(QList<Token>{Token::fromInteger(node.integer())});
101 }
swissChili07d325f2021-12-08 20:02:05 -0800102 else if (node.isVar())
103 {
104 if (!ctx.exists(node.name()) || ctx.exists(node.name()) != node.symbol())
105 return RuntimeResult("Variable " + node + " is not defined");
106
107 if (node.symbol() == 'e')
108 {
109 return RuntimeResult(ctx.expressionVar(node.name()));
110 }
111 else
112 {
113 return RuntimeResult(QList<Token>{
114 ctx.singleVar(node.name())
115 });
116 }
117 }
118 else if (node.isParen())
119 {
120 QList<Token> result;
121
122 for (const AstNode &n : node.parenContent())
123 {
124 RuntimeResult internalResult = evaluate(n, ctx);
125 if (!internalResult.success())
126 return internalResult;
127
128 result.append(internalResult.result());
129 }
130
131 return RuntimeResult(QList<Token>{
132 Token(result)
133 });
134 }
135 else if (node.isFunc())
136 {
137 QList<Token> args;
138
139 for (const AstNode &arg : node.funcArgs())
140 {
141 RuntimeResult internalResult = evaluate(arg, ctx);
142 if (!internalResult.success())
143 return internalResult;
144
145 args.append(internalResult.result());
146 }
147
148 return callFunction(node.name(), args);
149 }
150
151 return RuntimeResult("#TYPE_ERROR");
152}
153
154RuntimeResult Evaluator::callFunction(QString name, QList<Token> args)
155{
156 if (!_functions.contains(name))
157 return RuntimeResult("Function " + name + " is not defined.");
158
159 Function func = _functions[name];
160
161 for (const Sentence &sentence : func.sentences())
162 {
163 MatchResult res = match(args, sentence.pattern(), VarContext());
164
165 if (!res.success)
166 continue;
167
swissChili323883d2022-02-20 16:35:23 -0800168 if (sentence.isExternal())
169 {
swissChili918557c2022-02-20 20:16:34 -0800170 return RuntimeResult(sentence.externResult(res));
swissChili323883d2022-02-20 16:35:23 -0800171 }
172
swissChili07d325f2021-12-08 20:02:05 -0800173 QList<Token> final;
174 for (const AstNode &node : sentence.result())
175 {
176 RuntimeResult argRes = evaluate(node, res.context);
177 if (!argRes.success())
178 return argRes;
179
180 final.append(argRes.result());
181 }
182
183 return RuntimeResult(final);
184 }
185
swissChili918557c2022-02-20 20:16:34 -0800186 return RuntimeResult("Function " + name + " had no matching sentences for input");
187}
188
189QList<Token> Evaluator::dig(QString name)
190{
191 if (_vars.contains(name))
192 {
193 QList<Token> value = _vars[name].pop();
194
195 if (_vars[name].empty())
196 {
197 _vars.remove(name);
198 }
199
200 return value;
201 }
202 else
203 {
204 return {};
205 }
206}
207
208QList<Token> Evaluator::copy(QString name)
209{
210 if (_vars.contains(name))
211 {
212 return _vars[name].last();
213 }
214 else
215 {
216 return {};
217 }
218}
219
220void Evaluator::bury(QString name, QList<Token> expression)
221{
222 if (!_vars.contains(name))
223 {
224 _vars[name] = QStack<QList<Token>>();
225 }
226
227 _vars[name].push(expression);
228}
229
230void rtError(QString brief, QString details)
231{
232 eout("Runtime Error: " + brief);
233 eout(details);
swissChili07d325f2021-12-08 20:02:05 -0800234}