#include "Environment.h" #include "Parser.h" #include namespace NVL::Environment { Environment ENVIRONMENT; Variable::Variable() : type(Type::Nil), length(0) { } Variable::Variable(Type t) : type(t), length(0) { if (t != Type::Nil) throw std::runtime_error("Cannot create non-nil object with type alone"); } Variable::Variable(const Number& v) : type(Type::Number), value(v), length(1) {} Variable::Variable(const String& v) : type(Type::String), value(v), length(1) {} Variable::Variable(const std::vector& v) : type(Type::Array), value(v), length(v.size()) {} Variable::Variable(const std::function < Variable(std::vector)>& v, u32 l) : type(Type::Procedure), value(v), length(l) {} bool Variable::operator==(const Variable& other) const { if (other.type != type) return false; switch (type) { case Type::Number: return std::get(other.value) == std::get(value); case Type::String: return std::get(other.value) == std::get(value); default: return false; } } void Environment::enter(const String& name, Variable p) { if (!env.emplace(name, p).second) throw std::runtime_error("Redefinition of symbol in environment"); } void Environment::enter(std::initializer_list> p) { for (auto& i : p) enter(i.first, i.second); } void Environment::set(const String& name, Variable p) { if (env.find(name) == env.end()) throw std::runtime_error("Attempting to set undefined variable"); env[name] = p; } Variable& Environment::get(const String& name) { return env.at(name); } bool Environment::exists(const String& name) { return env.find(name) != env.end(); } Variable Eval(const Parse::Object& obj) { switch (obj.type) { case Parse::Type::Symbol: return ENVIRONMENT.get(std::get(obj.value)); case Parse::Type::Number: return Variable(std::get(obj.value)); case Parse::Type::String: return Variable(std::get(obj.value)); case Parse::Type::Array: { std::vector v{}; for (const auto& x : std::get>(obj.value)) v.push_back(Eval(x)); return Variable(v); } case Parse::Type::Subexpression: { return Apply(std::get>(obj.value)); } } } Variable Apply(const Parse::Command& c) { std::vector args{}; Variable f = Eval(c[0]); u32 i = 1; while (i < c.size()) { args.push_back(Eval(c[i++])); } if (f.length != -1 && f.length != i - 1) throw std::runtime_error("Function arity mismatch"); return std::get)>>(f.value)(args); } void EvalScene(const Parse::Scene& s) { for (const auto& c : s.get()) Apply(c); } // Check MatchMarkup for more information MarkupString UnpackMarkupVariable(const std::vector& v) { MarkupString ms{}; for (const Variable& segment : v) { const auto& pair = std::get>(segment.value); const String s = std::get(pair[0].value); std::vector>> efs; for (const Variable& combination : std::get>(pair[1].value)) { if (combination.type == Type::String) { const String ef = std::get(combination.value); efs.push_back({ ef, {} }); } else if (combination.type == Type::Array) { const std::vector& ef_t = std::get>(combination.value); const String& ef = std::get(ef_t[0].value); const std::vector& args = std::get>(ef_t[1].value); std::vector ss{}; for (const auto& s : args) { ss.push_back(std::get(s.value)); } efs.push_back({ ef, ss }); } } ms.segments.push_back({ s, efs }); } return ms; } size_t MarkupString::length() const { // you do realize this memoization fails if we change the var if (mem_length == -1) { size_t r = 0; for (const auto& s : segments) r += s.str.length(); return r; } else return mem_length; } MarkupString MarkupString::substr(size_t i) const { size_t r = 0; MarkupString res; for (const auto& s : segments) { size_t last_r = r; r += s.str.length(); if (r <= i) res.segments.push_back(s); else { auto copy = s; copy.str = copy.str.substr(0, i - last_r); res.segments.push_back(copy); break; } } return res; } }