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