#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::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 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{}; for (u32 i = 1; i < c.size(); i++) args.push_back(Eval(c[i])); return std::get)>>(ENVIRONMENT.get(std::get(c[0].value)).value)(args); } void EvalScene(const Parse::Scene& s) { for (const auto& c : s.get()) Apply(c); } // Check ParseMarkup for more information Markup UnpackMarkupVariable(const Variable& m) { const auto& range = std::get>(std::get>(m.value)[0].value); const u32 begin = std::get(range[0].value), end = std::get(range[1].value); std::vector>> efs; for (const Variable& combination : std::get>(std::get>(m.value)[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 }); } } return { begin, end, efs }; } }