diff --git a/include/bolt/Evaluator.hpp b/include/bolt/Evaluator.hpp new file mode 100644 index 000000000..ae5127951 --- /dev/null +++ b/include/bolt/Evaluator.hpp @@ -0,0 +1,187 @@ + +#pragma once + +#include +#include + +#include "bolt/ByteString.hpp" +#include "bolt/CST.hpp" + +namespace bolt { + + enum class ValueKind { + Empty, + String, + Integer, + Tuple, + SourceFunction, + NativeFunction, + }; + + class Value { + + using NativeFunction = std::function)>; + + using Tuple = std::vector; + + ValueKind Kind; + + union { + ByteString S; + Integer I; + LetDeclaration* D; + NativeFunction F; + Tuple T; + }; + + public: + + Value(): + Kind(ValueKind::Empty) {} + + Value(ByteString S): + Kind(ValueKind::String), S(S) {} + + Value(Integer I): + Kind(ValueKind::Integer), I(I) {} + + Value(LetDeclaration* D): + Kind(ValueKind::SourceFunction), D(D) {} + + Value(NativeFunction F): + Kind(ValueKind::NativeFunction), F(F) {} + + Value(std::vector T): + Kind(ValueKind::Tuple), T(T) {} + + Value(const Value& V): + Kind(V.Kind) { + switch (Kind) { + case ValueKind::String: + new (&S) ByteString(V.S); + break; + case ValueKind::Integer: + new (&I) Integer(V.I); + break; + case ValueKind::Tuple: + new (&I) Tuple(V.T); + break; + case ValueKind::SourceFunction: + new (&D) LetDeclaration*(V.D); + break; + case ValueKind::NativeFunction: + new (&F) NativeFunction(V.F); + break; + case ValueKind::Empty: + break; + } + } + + Value& operator=(const Value& Other) noexcept { + Kind = Other.Kind; + switch (Kind) { + case ValueKind::String: + new (&S) ByteString(Other.S); + break; + case ValueKind::Integer: + new (&I) Integer(Other.I); + break; + case ValueKind::Tuple: + new (&I) Tuple(Other.T); + break; + case ValueKind::SourceFunction: + new (&D) LetDeclaration*(Other.D); + break; + case ValueKind::NativeFunction: + new (&F) NativeFunction(Other.F); + break; + case ValueKind::Empty: + break; + } + return *this; + } + + // Add move constructor and move assignment methods + + inline ValueKind getKind() const noexcept { + return Kind; + } + + inline ByteString& asString() { + ZEN_ASSERT(Kind == ValueKind::String); + return S; + } + + inline LetDeclaration* getDeclaration() { + ZEN_ASSERT(Kind == ValueKind::SourceFunction); + return D; + } + + inline NativeFunction getBinding() { + ZEN_ASSERT(Kind == ValueKind::NativeFunction); + return F; + } + + static Value binding(NativeFunction F) { + return Value(F); + } + + static Value unit() { + return Value(Tuple {}); + } + + ~Value() { + switch (Kind) { + case ValueKind::String: + S.~ByteString(); + break; + case ValueKind::Integer: + I.~Integer(); + break; + case ValueKind::Tuple: + T.~Tuple(); + break; + case ValueKind::SourceFunction: + break; + case ValueKind::NativeFunction: + F.~NativeFunction(); + break; + case ValueKind::Empty: + break; + } + } + + }; + + class Env { + + std::unordered_map Bindings; + + public: + + void add(const ByteString& Name, Value V) { + Bindings.emplace(Name, V); + } + + Value& lookup(const ByteString& Name) { + auto Match = Bindings.find(Name); + ZEN_ASSERT(Match != Bindings.end()); + return Match->second; + } + + }; + + class Evaluator { + + public: + + void assignPattern(Pattern* P, Value& V, Env& E); + + Value apply(Value Op, std::vector Args); + + Value evaluateExpression(Expression* N, Env& E); + + void evaluate(Node* N, Env& E); + + }; +} diff --git a/src/Evaluator.cc b/src/Evaluator.cc new file mode 100644 index 000000000..3ceffb252 --- /dev/null +++ b/src/Evaluator.cc @@ -0,0 +1,127 @@ + +#include "zen/range.hpp" + +#include "bolt/CST.hpp" +#include "bolt/Evaluator.hpp" + +namespace bolt { + + Value Evaluator::evaluateExpression(Expression* X, Env& E) { + switch (X->getKind()) { + case NodeKind::ReferenceExpression: + { + auto RE = static_cast(X); + return E.lookup(RE->Name->getCanonicalText()); + // auto Decl = RE->getScope()->lookup(RE->getSymbolPath()); + // ZEN_ASSERT(Decl && Decl->getKind() == NodeKind::FunctionDeclaration); + // return static_cast(Decl); + } + case NodeKind::ConstantExpression: + { + auto CE = static_cast(X); + switch (CE->Token->getKind()) { + case NodeKind::IntegerLiteral: + return static_cast(CE->Token)->V; + case NodeKind::StringLiteral: + return static_cast(CE->Token)->Text; + default: + ZEN_UNREACHABLE + } + } + case NodeKind::CallExpression: + { + auto CE = static_cast(X); + auto Op = evaluateExpression(CE->Function, E); + std::vector Args; + for (auto Arg: CE->Args) { + Args.push_back(evaluateExpression(Arg, E)); + } + return apply(Op, Args); + } + default: + ZEN_UNREACHABLE + } + } + + void Evaluator::assignPattern(Pattern* P, Value& V, Env& E) { + switch (P->getKind()) { + case NodeKind::BindPattern: + { + auto BP = static_cast(P); + E.add(BP->Name->getCanonicalText(), V); + break; + } + default: + ZEN_UNREACHABLE + } + } + + Value Evaluator::apply(Value Op, std::vector Args) { + switch (Op.getKind()) { + case ValueKind::SourceFunction: + { + auto Fn = Op.getDeclaration(); + Env NewEnv; + for (auto [Param, Arg]: zen::zip(Fn->Params, Args)) { + assignPattern(Param->Pattern, Arg, NewEnv); + } + switch (Fn->Body->getKind()) { + case NodeKind::LetExprBody: + return evaluateExpression(static_cast(Fn->Body)->Expression, NewEnv); + default: + ZEN_UNREACHABLE + } + } + case ValueKind::NativeFunction: + { + auto Fn = Op.getBinding(); + return Fn(Args); + } + default: + ZEN_UNREACHABLE + } + } + + void Evaluator::evaluate(Node* N, Env& E) { + switch (N->getKind()) { + case NodeKind::SourceFile: + { + auto SF = static_cast(N); + for (auto Element: SF->Elements) { + evaluate(Element, E); + } + break; + } + case NodeKind::ExpressionStatement: + { + auto ES = static_cast(N); + evaluateExpression(ES->Expression, E); + break; + } + case NodeKind::LetDeclaration: + { + auto Decl = static_cast(N); + if (Decl->isFunction()) { + E.add(Decl->getNameAsString(), Decl); + } else { + Value V; + if (Decl->Body) { + switch (Decl->Body->getKind()) { + case NodeKind::LetExprBody: + { + auto Body = static_cast(Decl->Body); + V = evaluateExpression(Body->Expression, E); + } + default: + ZEN_UNREACHABLE + } + } + } + break; + } + default: + ZEN_UNREACHABLE + } + } + +}