blob: e4e5d6f697a458cc4caa352eba80ddc682912b03 [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"
swissChili682e7bc2021-12-07 09:04:54 -08005
swissChili07d325f2021-12-08 20:02:05 -08006#include <QDebug>
7
8RuntimeResult::RuntimeResult(QList<Token> result)
9{
10 _result = result;
11}
12
13RuntimeResult::RuntimeResult(QString message)
14{
15 _errorMessage = message;
16}
17
18bool RuntimeResult::success() const
19{
20 return _success;
21}
22
23QString RuntimeResult::message() const
24{
25 return _errorMessage;
26}
27
28QList<Token> RuntimeResult::result() const
29{
30 return _result;
31}
32
33RuntimeResult::operator QString() const
34{
35 return QString(_success) + " " + _errorMessage;
36}
37
38void Evaluator::addFunction(Function func)
39{
40 _functions[func.name()] = func;
41}
42
43void Evaluator::clearFunction(QString name)
44{
45 _functions.remove(name);
46}
47
48RuntimeResult Evaluator::evaluate(AstNode node, VarContext ctx)
49{
50 if (node.isSym())
51 {
52 return RuntimeResult(QList<Token>{Token(node.symbol())});
53 }
54 else if (node.isIdent())
55 {
56 return RuntimeResult(QList<Token>{Token(node.name())});
57 }
58 else if (node.isVar())
59 {
60 if (!ctx.exists(node.name()) || ctx.exists(node.name()) != node.symbol())
61 return RuntimeResult("Variable " + node + " is not defined");
62
63 if (node.symbol() == 'e')
64 {
65 return RuntimeResult(ctx.expressionVar(node.name()));
66 }
67 else
68 {
69 return RuntimeResult(QList<Token>{
70 ctx.singleVar(node.name())
71 });
72 }
73 }
74 else if (node.isParen())
75 {
76 QList<Token> result;
77
78 for (const AstNode &n : node.parenContent())
79 {
80 RuntimeResult internalResult = evaluate(n, ctx);
81 if (!internalResult.success())
82 return internalResult;
83
84 result.append(internalResult.result());
85 }
86
87 return RuntimeResult(QList<Token>{
88 Token(result)
89 });
90 }
91 else if (node.isFunc())
92 {
93 QList<Token> args;
94
95 for (const AstNode &arg : node.funcArgs())
96 {
97 RuntimeResult internalResult = evaluate(arg, ctx);
98 if (!internalResult.success())
99 return internalResult;
100
101 args.append(internalResult.result());
102 }
103
104 return callFunction(node.name(), args);
105 }
106
107 return RuntimeResult("#TYPE_ERROR");
108}
109
110RuntimeResult Evaluator::callFunction(QString name, QList<Token> args)
111{
112 if (!_functions.contains(name))
113 return RuntimeResult("Function " + name + " is not defined.");
114
115 Function func = _functions[name];
116
117 for (const Sentence &sentence : func.sentences())
118 {
119 MatchResult res = match(args, sentence.pattern(), VarContext());
120
121 if (!res.success)
122 continue;
123
124 QList<Token> final;
125 for (const AstNode &node : sentence.result())
126 {
127 RuntimeResult argRes = evaluate(node, res.context);
128 if (!argRes.success())
129 return argRes;
130
131 final.append(argRes.result());
132 }
133
134 return RuntimeResult(final);
135 }
136
137 return RuntimeResult("Function " + name + " had no matching sentences for input");
138}