diff --git a/src/interpreter/Interpreter.cpp b/src/interpreter/Interpreter.cpp index 417b290..6588114 100644 --- a/src/interpreter/Interpreter.cpp +++ b/src/interpreter/Interpreter.cpp @@ -109,13 +109,26 @@ Value Interpreter::executeNode(std::shared_ptr node) { if (auto forNode = dynamic_pointer_cast(node)) { if (auto range = dynamic_pointer_cast(forNode->iterable)) { - Value endVal = executeNode(range->end); - int end = static_cast(endVal.toNumber()); + int start = range->start ? static_cast(executeNode(range->start).toNumber()) : 0; + int end = static_cast(executeNode(range->end).toNumber()); + int step = range->step ? static_cast(executeNode(range->step).toNumber()) : 1; - for (int i = 0; i < end; i++) { - variables[forNode->varName] = Value(static_cast(i)); - for (const auto &stmt: forNode->body) - executeNode(stmt); + if (step == 0) { + throw std::runtime_error("range() arg 3 must not be zero"); + } + + if (step > 0) { + for (int i = start; i < end; i += step) { + variables[forNode->varName] = Value(static_cast(i)); + for (const auto &stmt: forNode->body) + executeNode(stmt); + } + } else { + for (int i = start; i > end; i += step) { + variables[forNode->varName] = Value(static_cast(i)); + for (const auto &stmt: forNode->body) + executeNode(stmt); + } } } return Value(0.0); diff --git a/src/interpreter/Node/RangeNode.h b/src/interpreter/Node/RangeNode.h index c25516c..701c95f 100644 --- a/src/interpreter/Node/RangeNode.h +++ b/src/interpreter/Node/RangeNode.h @@ -23,9 +23,12 @@ along with this program; if not, see class RangeNode : public ASTNode { public: + std::shared_ptr start; std::shared_ptr end; + std::shared_ptr step; - RangeNode(std::shared_ptr e) : end(e) { + RangeNode(std::shared_ptr s, std::shared_ptr e, std::shared_ptr st) + : start(s), end(e), step(st) { } }; diff --git a/src/interpreter/Parser.cpp b/src/interpreter/Parser.cpp index ea2ec90..b25dcf1 100644 --- a/src/interpreter/Parser.cpp +++ b/src/interpreter/Parser.cpp @@ -54,6 +54,12 @@ void Parser::skipNewlines() { } std::shared_ptr Parser::parsePrimary() { + if (currentToken().type == TokenType::MINUS) { + advance(); + auto operand = parsePrimary(); + return make_shared(std::make_shared(0), TokenType::MINUS, operand); + } + if (currentToken().type == TokenType::NUMBER) { double value = stod(currentToken().value); advance(); @@ -75,9 +81,28 @@ std::shared_ptr Parser::parsePrimary() { if (currentToken().type == TokenType::KEYWORD && currentToken().value == "range") { advance(); expect(TokenType::LPAREN); - auto end = parseExpression(); + + std::vector > args; + args.push_back(parseExpression()); + while (currentToken().type == TokenType::COMMA) { + advance(); + args.push_back(parseExpression()); + } + expect(TokenType::RPAREN); - return std::make_shared(end); + + if (args.size() == 1) { + return std::make_shared(nullptr, args[0], nullptr); + } + if (args.size() == 2) { + return std::make_shared(args[0], args[1], nullptr); + } + if (args.size() == 3) { + return std::make_shared(args[0], args[1], args[2]); + } + + throw std::runtime_error("range() expects 1 to 3 arguments on line " + + std::to_string(currentToken().line)); } if (currentToken().type == TokenType::LPAREN) {