diff --git a/AST.cpp b/AST.cpp index 75013d3..44362e9 100644 --- a/AST.cpp +++ b/AST.cpp @@ -121,61 +121,92 @@ std::shared_ptr IfAST::getResult(Context* parent) { } -std::shared_ptr LoopAST::eval(Context* parent) { - // Eval start & end - auto s = this->start->eval(parent); - auto e = this->end->eval(parent); - if (s->isArray() || e->isArray()) - throw std::runtime_error("Cannot eval loop start or end as integer"); - auto sc = std::dynamic_pointer_cast(s); - auto ec = std::dynamic_pointer_cast(e); - if (!sc || !ec) - throw std::runtime_error("Unexpected error"); - - if (sc->isT()) { - while (true) { - // No need to create a new context - for (auto& stmt : this->body) { - auto* ptr = stmt.get(); - if (ptr->getType() == T_IfAST) - ptr = dynamic_cast(ptr)->getResult(parent).get(); - if (!ptr) - continue; - if (ptr->getType() == T_ReturnAST) - return ptr->eval(parent); - stmt->eval(parent); - } +std::shared_ptr LoopForeverAST::eval(Context* parent) { + // No context is needed + while (true) { + for (auto& stmt : this->body) { + auto* ptr = stmt.get(); + if (ptr->getType() == T_IfAST) + ptr = dynamic_cast(ptr)->getResult(parent).get(); + if (!ptr) + continue; + if (ptr->getType() == T_ReturnAST) + return ptr->eval(parent); + ptr->eval(parent); } - } else { - if (!sc->isInt() || !ec->isInt()) - throw std::runtime_error("Cannot eval loop start or end as integer"); + } + throw std::runtime_error("Unexpected error"); +} - auto ss = sc->getInt(); - auto ee = ec->getInt(); +std::shared_ptr LoopForAST::eval(Context* parent) { + // Create a new context + auto ctx = std::make_shared(parent); - // Create a new context - auto ctx = std::make_shared(parent); + // Eval condition + auto s = std::dynamic_pointer_cast(this->start->eval(parent)->copy()); + auto e = std::dynamic_pointer_cast(this->end->eval(parent)); - for (auto i = ss; i <= ee; ++i) { - ctx->setVariable(this->loopVar, std::make_shared(i)); - for (auto& stmt : this->body) { - auto* ptr = stmt.get(); - if (ptr->getType() == T_IfAST) - ptr = dynamic_cast(ptr)->getResult(ctx.get()).get(); - if (!ptr) - continue; - if (ptr->getType() == T_ReturnAST) - return ptr->eval(ctx.get()); - stmt->eval(ctx.get()); - } + // Assert that s and e are numeric + if (!s || !e || (!s->isInt() && !s->isFloat()) || (!e->isInt() && !e->isFloat())) + throw std::runtime_error("LoopForAST: start and end must be numeric"); + + // Main loop + while (*s <= *e) { + // Set the variable + ctx->setVariable(this->name, s); + + // Eval body + for (auto& stmt : this->body) { + auto* ptr = stmt.get(); + if (ptr->getType() == T_IfAST) + ptr = dynamic_cast(ptr)->getResult(ctx.get()).get(); + if (!ptr) + continue; + if (ptr->getType() == T_ReturnAST) + return ptr->eval(ctx.get()); + ptr->eval(ctx.get()); + } + + // Increment + s->operator++(); + } + + // Return nil + return std::make_shared(false); +} + +std::shared_ptr LoopDoTimesAST::eval(Context* parent) { + // Create a new context + auto ctx = std::make_shared(parent); + + // Eval condition + auto terminate = std::dynamic_pointer_cast(this->times->eval(parent)->copy()); + if (!terminate || !terminate->isInt()) + throw std::runtime_error("DOTIMES: times must be an integer"); + auto n = terminate->getInt(); + + // Main Loop + for (std::int64_t i = 0; i < n; ++i) { + // Set Variable + ctx->setVariable(this->name, std::make_shared(i)); + + // Eval Body + for (auto& stmt : this->body) { + auto* ptr = stmt.get(); + if (ptr->getType() == T_IfAST) + ptr = dynamic_cast(ptr)->getResult(ctx.get()).get(); + if (!ptr) + continue; + if (ptr->getType() == T_ReturnAST) + return ptr->eval(ctx.get()); + ptr->eval(ctx.get()); } } // Return nil - return std::make_shared(); + return std::make_shared(false); } - std::shared_ptr UnaryAST::eval(Context* parent) { auto val = this->expr->eval(parent); auto valS = std::dynamic_pointer_cast(val); diff --git a/AST.h b/AST.h index 2bc1528..f632e43 100644 --- a/AST.h +++ b/AST.h @@ -17,6 +17,9 @@ enum ASTType { T_FuncCallAST, T_IfAST, T_LoopAST, + T_LoopForeverAST, + T_LoopForAST, + T_LoopDoTimesAST, T_UnaryAST, T_BinaryAST, T_ListAST, @@ -132,20 +135,52 @@ public: } }; -class LoopAST : public ExprAST { +class LoopAST : public ExprAST {}; + +class LoopForeverAST : public LoopAST { private: - std::string loopVar; + std::vector> body; + +public: + explicit LoopForeverAST(std::vector> body) : body(std::move(body)) {} + + std::shared_ptr eval(Context* parent) override final; + + inline ASTType getType() const override final { + return T_LoopForeverAST; + } +}; + +class LoopForAST : public LoopAST { +private: + std::string name; std::shared_ptr start; std::shared_ptr end; std::vector> body; public: - LoopAST(std::string loopVar, std::shared_ptr start, std::shared_ptr end, std::vector> body) : loopVar(std::move(loopVar)), start(std::move(start)), end(std::move(end)), body(std::move(body)) {} + LoopForAST(std::string name, std::shared_ptr start, std::shared_ptr end, std::vector> body) : name(std::move(name)), start(std::move(start)), end(std::move(end)), body(std::move(body)) {} std::shared_ptr eval(Context* parent) override final; inline ASTType getType() const override final { - return T_LoopAST; + return T_LoopForAST; + } +}; + +class LoopDoTimesAST : public LoopAST { +private: + std::string name; + std::shared_ptr times; + std::vector> body; + +public: + LoopDoTimesAST(std::string name, std::shared_ptr times, std::vector> body) : name(std::move(name)), times(std::move(times)), body(std::move(body)) {} + + std::shared_ptr eval(Context* parent) override final; + + inline ASTType getType() const override final { + return T_LoopDoTimesAST; } }; diff --git a/DragonLispDriver.cpp b/DragonLispDriver.cpp index 6dc6d45..db59014 100644 --- a/DragonLispDriver.cpp +++ b/DragonLispDriver.cpp @@ -99,25 +99,21 @@ std::shared_ptr DLDriver::constructReturnAST(std::shared_ptr } std::shared_ptr DLDriver::constructLoopAST(std::vector> body) { - return std::make_shared( - "", - std::make_shared(true), - std::make_shared(true), + return std::make_shared( std::move(body) ); } std::shared_ptr DLDriver::constructLoopAST(std::string id, std::shared_ptr to, std::vector> body) { - return std::make_shared( + return std::make_shared( std::move(id), - std::make_shared(std::int64_t(0)), std::move(to), std::move(body) ); } std::shared_ptr DLDriver::constructLoopAST(std::string id, std::shared_ptr from, std::shared_ptr to, std::vector> body) { - return std::make_shared( + return std::make_shared( std::move(id), std::move(from), std::move(to), diff --git a/value.h b/value.h index d429b17..734f5a1 100644 --- a/value.h +++ b/value.h @@ -106,6 +106,62 @@ public: bool operator==(const SingleValue& rhs) const { return type == rhs.type && value == rhs.value; } + + bool operator<(const SingleValue& rhs) const { + if ((!this->isInt() && !this->isFloat()) || (!rhs.isInt() && !rhs.isFloat())) + throw std::runtime_error("Cannot compare non-numeric values"); + if (this->isInt() && rhs.isInt()) + return this->getInt() < rhs.getInt(); + if (this->isInt()) + return this->getInt() < rhs.getFloat(); + if (rhs.isInt()) + return this->getFloat() < rhs.getInt(); + return this->getFloat() < rhs.getFloat(); + } + + bool operator<=(const SingleValue& rhs) const { + if ((!this->isInt() && !this->isFloat()) || (!rhs.isInt() && !rhs.isFloat())) + throw std::runtime_error("Cannot compare non-numeric values"); + if (this->isInt() && rhs.isInt()) + return this->getInt() <= rhs.getInt(); + if (this->isInt()) + return this->getInt() <= rhs.getFloat(); + if (rhs.isInt()) + return this->getFloat() <= rhs.getInt(); + return this->getFloat() <= rhs.getFloat(); + } + + SingleValue& operator++() { + if (this->isInt()) + this->value = this->getInt() + 1; + else if (this->isFloat()) + this->value = this->getFloat() + 1; + else + throw std::runtime_error("Cannot increment non-numeric value"); + return *this; + } + + SingleValue& operator--() { + if (this->isInt()) + this->value = this->getInt() - 1; + else if (this->isFloat()) + this->value = this->getFloat() - 1; + else + throw std::runtime_error("Cannot decrement non-numeric value"); + return *this; + } + + SingleValue operator++(int) { + SingleValue tmp(*this); + operator++(); + return tmp; + } + + SingleValue operator--(int) { + SingleValue tmp(*this); + operator--(); + return tmp; + } }; class ArrayValue : public Value {