Add evaluator
diff --git a/Evaluator.cpp b/Evaluator.cpp
index 70ed91b..e4e5d6f 100644
--- a/Evaluator.cpp
+++ b/Evaluator.cpp
@@ -1,2 +1,138 @@
#include "Evaluator.h"
+#include "Function.h"
+#include "Matcher.h"
+#include "VarContext.h"
+#include <QDebug>
+
+RuntimeResult::RuntimeResult(QList<Token> result)
+{
+ _result = result;
+}
+
+RuntimeResult::RuntimeResult(QString message)
+{
+ _errorMessage = message;
+}
+
+bool RuntimeResult::success() const
+{
+ return _success;
+}
+
+QString RuntimeResult::message() const
+{
+ return _errorMessage;
+}
+
+QList<Token> RuntimeResult::result() const
+{
+ return _result;
+}
+
+RuntimeResult::operator QString() const
+{
+ return QString(_success) + " " + _errorMessage;
+}
+
+void Evaluator::addFunction(Function func)
+{
+ _functions[func.name()] = func;
+}
+
+void Evaluator::clearFunction(QString name)
+{
+ _functions.remove(name);
+}
+
+RuntimeResult Evaluator::evaluate(AstNode node, VarContext ctx)
+{
+ if (node.isSym())
+ {
+ return RuntimeResult(QList<Token>{Token(node.symbol())});
+ }
+ else if (node.isIdent())
+ {
+ return RuntimeResult(QList<Token>{Token(node.name())});
+ }
+ else if (node.isVar())
+ {
+ if (!ctx.exists(node.name()) || ctx.exists(node.name()) != node.symbol())
+ return RuntimeResult("Variable " + node + " is not defined");
+
+ if (node.symbol() == 'e')
+ {
+ return RuntimeResult(ctx.expressionVar(node.name()));
+ }
+ else
+ {
+ return RuntimeResult(QList<Token>{
+ ctx.singleVar(node.name())
+ });
+ }
+ }
+ else if (node.isParen())
+ {
+ QList<Token> result;
+
+ for (const AstNode &n : node.parenContent())
+ {
+ RuntimeResult internalResult = evaluate(n, ctx);
+ if (!internalResult.success())
+ return internalResult;
+
+ result.append(internalResult.result());
+ }
+
+ return RuntimeResult(QList<Token>{
+ Token(result)
+ });
+ }
+ else if (node.isFunc())
+ {
+ QList<Token> args;
+
+ for (const AstNode &arg : node.funcArgs())
+ {
+ RuntimeResult internalResult = evaluate(arg, ctx);
+ if (!internalResult.success())
+ return internalResult;
+
+ args.append(internalResult.result());
+ }
+
+ return callFunction(node.name(), args);
+ }
+
+ return RuntimeResult("#TYPE_ERROR");
+}
+
+RuntimeResult Evaluator::callFunction(QString name, QList<Token> args)
+{
+ if (!_functions.contains(name))
+ return RuntimeResult("Function " + name + " is not defined.");
+
+ Function func = _functions[name];
+
+ for (const Sentence &sentence : func.sentences())
+ {
+ MatchResult res = match(args, sentence.pattern(), VarContext());
+
+ if (!res.success)
+ continue;
+
+ QList<Token> final;
+ for (const AstNode &node : sentence.result())
+ {
+ RuntimeResult argRes = evaluate(node, res.context);
+ if (!argRes.success())
+ return argRes;
+
+ final.append(argRes.result());
+ }
+
+ return RuntimeResult(final);
+ }
+
+ return RuntimeResult("Function " + name + " had no matching sentences for input");
+}