From 4f39417d3e78ba00fa019306fdcb0a41efb8c62a Mon Sep 17 00:00:00 2001 From: Abdelrahman Date: Sun, 29 Jun 2025 19:25:08 +0100 Subject: [PATCH] Start adding statements --- cclox_src/interpreter.cc | 11 +- cclox_src/parser.cc | 6 +- cclox_src/parser.hh | 2 + cclox_src/parser/ast_interpreter.cc | 76 +++++++++++-- cclox_src/parser/ast_interpreter.hh | 15 ++- cclox_src/parser/ast_printer.cc | 34 +++--- cclox_src/parser/environment.cc | 64 +++++++++++ cclox_src/parser/environment.hh | 28 +++++ cclox_src/parser/expr.cc | 78 +++++++++++++- cclox_src/parser/expr.hh | 25 ++++- cclox_src/parser/parser.cc | 81 +++++++++++++- cclox_src/parser/parser.hh | 10 +- cclox_src/parser/stmt.cc | 162 ++++++++++++++++++++++++++++ cclox_src/parser/stmt.hh | 64 +++++++++++ cclox_src/scanner/object.cc | 22 +--- cclox_src/scanner/object.hh | 2 +- 16 files changed, 613 insertions(+), 67 deletions(-) create mode 100644 cclox_src/parser/environment.cc create mode 100644 cclox_src/parser/environment.hh create mode 100644 cclox_src/parser/stmt.cc create mode 100644 cclox_src/parser/stmt.hh diff --git a/cclox_src/interpreter.cc b/cclox_src/interpreter.cc index 69aaa2b..8cd1d5d 100644 --- a/cclox_src/interpreter.cc +++ b/cclox_src/interpreter.cc @@ -2,10 +2,10 @@ #include "error_handler.hh" #include "tokenizer.hh" #include "parser.hh" +#include #include #include #include -#include #include #define PROMPT "> " @@ -57,15 +57,12 @@ void run(const std::string &code) { std::vector tokens = scanner.scan_tokens(); Parser parser{tokens}; - std::optional expression = parser.parse(); - - static AstInterpreter interpreter{}; + std::vector statements = parser.parse(); if (error_handler.had_error) { return; } - if (expression) { - interpreter.interpret(*expression); - } + static AstInterpreter interpreter{}; + interpreter.interpret(statements); } diff --git a/cclox_src/parser.cc b/cclox_src/parser.cc index f6e9581..a702995 100644 --- a/cclox_src/parser.cc +++ b/cclox_src/parser.cc @@ -1,8 +1,10 @@ -#ifndef PARSER_CC -#define PARSER_CC +#ifndef MAIN_PARSER_CC +#define MAIN_PARSER_CC #include "parser/expr.cc" +#include "parser/stmt.cc" #include "parser/parser.cc" +#include "parser/environment.cc" #include "parser/ast_printer.cc" #include "parser/ast_interpreter.cc" diff --git a/cclox_src/parser.hh b/cclox_src/parser.hh index b77c468..79fab6f 100644 --- a/cclox_src/parser.hh +++ b/cclox_src/parser.hh @@ -2,7 +2,9 @@ #define MAIN_PARSER_HH #include "parser/expr.hh" +#include "parser/stmt.hh" #include "parser/parser.hh" +#include "parser/environment.hh" #include "parser/ast_printer.hh" #include "parser/ast_interpreter.hh" diff --git a/cclox_src/parser/ast_interpreter.cc b/cclox_src/parser/ast_interpreter.cc index 2925759..c866c21 100644 --- a/cclox_src/parser/ast_interpreter.cc +++ b/cclox_src/parser/ast_interpreter.cc @@ -1,33 +1,73 @@ #include "ast_interpreter.hh" #include "expr.hh" +#include "stmt.hh" #include "../error_handler.hh" #include "../tokenizer.hh" #include #include +#include #include #include extern ErrorHandler error_handler; -void AstInterpreter::interpret(const Expr &expression) { +void AstInterpreter::interpret(const std::vector &statements) { try { - Object value = evaluate(expression); - std::cout << value.to_string() << '\n'; + for (const Stmt & stmt : statements) { + execute(stmt); + } } catch (RuntimeException e) { error_handler.runtime_error(e); } } +void AstInterpreter::execute(const Stmt &stmt) { + switch (stmt.type) { + case StmtType::EXPRESSION: return execute_expression_statement(stmt); + case StmtType::PRINT: return execute_print_statement(stmt); + case StmtType::VAR: return execute_var_statement(stmt); + } +} + +void AstInterpreter::execute_expression_statement(const Stmt &stmt) { + std::shared_ptr<_Expression> ptr = std::get>(stmt.value); + assert(ptr != nullptr); + evaluate(ptr->expr); +} + +void AstInterpreter::execute_print_statement(const Stmt &stmt) { + std::shared_ptr<_Print> ptr = std::get>(stmt.value); + assert(ptr != nullptr); + Object value{evaluate(ptr->expr)}; + std::cout << value << '\n'; +} + +void AstInterpreter::execute_var_statement(const Stmt &stmt) { + Object value{}; + std::shared_ptr<_Var> ptr = std::get>(stmt.value); + assert(ptr != nullptr); + + if (ptr->expr.type == ExprType::LITERAL) { + std::shared_ptr<_Literal> eptr = std::get>(ptr->expr.value); + assert(eptr != nullptr); + if (eptr->value.type == ObjectType::NIL) { + environment.define(ptr->name.lexeme, value); + return; + } + } + + value = evaluate(ptr->expr); + environment.define(ptr->name.lexeme, value); +} + Object AstInterpreter::evaluate(const Expr &expr) { switch (expr.type) { - case ExprType::BINARY: - return evaluate_binary_expression(expr); - case ExprType::GROUPING: - return evaluate_grouping_expression(expr); - case ExprType::LITERAL: - return evaluate_literal_expression(expr); - case ExprType::UNARY: - return evaluate_unary_expression(expr); + case ExprType::BINARY: return evaluate_binary_expression(expr); + case ExprType::GROUPING: return evaluate_grouping_expression(expr); + case ExprType::LITERAL: return evaluate_literal_expression(expr); + case ExprType::UNARY: return evaluate_unary_expression(expr); + case ExprType::VARIABLE: return evaluate_variable_expression(expr); + case ExprType::ASSIGN: return evaluate_assignment_expression(expr); } } @@ -156,6 +196,20 @@ Object AstInterpreter::evaluate_unary_expression(const Expr &expr) { return Object{}; } +Object AstInterpreter::evaluate_variable_expression(const Expr &expr) { + std::shared_ptr<_Variable> ptr = std::get>(expr.value); + assert(ptr != nullptr); + return environment.get(ptr->name); +} + +Object AstInterpreter::evaluate_assignment_expression(const Expr &expr) { + std::shared_ptr<_Assign> ptr = std::get>(expr.value); + assert(ptr != nullptr); + Object value = evaluate(ptr->value); + environment.assign(ptr->name, value); + return value; +} + bool AstInterpreter::is_truthy(const Object &object) { switch (object.type) { case ObjectType::NIL: return false; diff --git a/cclox_src/parser/ast_interpreter.hh b/cclox_src/parser/ast_interpreter.hh index b718d4f..eb90514 100644 --- a/cclox_src/parser/ast_interpreter.hh +++ b/cclox_src/parser/ast_interpreter.hh @@ -2,20 +2,31 @@ #define AST_INTERPRETER_HH #include "expr.hh" +#include "stmt.hh" +#include "environment.hh" #include "../tokenizer.hh" -#include +#include struct AstInterpreter { - void interpret(const Expr &expression); + void interpret(const std::vector &statements); private: + void execute(const Stmt &stmt); + void execute_expression_statement(const Stmt &stmt); + void execute_print_statement(const Stmt &stmt); + void execute_var_statement(const Stmt &stmt); + Object evaluate(const Expr &expr); Object evaluate_binary_expression(const Expr &expr); Object evaluate_grouping_expression(const Expr &expr); Object evaluate_literal_expression(const Expr &expr); Object evaluate_unary_expression(const Expr &expr); + Object evaluate_variable_expression(const Expr &expr); + Object evaluate_assignment_expression(const Expr &expr); bool is_truthy(const Object &object); bool is_equal(const Object &left, const Object &right); + + Environment environment{}; }; #endif diff --git a/cclox_src/parser/ast_printer.cc b/cclox_src/parser/ast_printer.cc index 5680938..e6ce280 100644 --- a/cclox_src/parser/ast_printer.cc +++ b/cclox_src/parser/ast_printer.cc @@ -7,24 +7,34 @@ std::string AstPrinter::print(const Expr &expr) { switch (expr.type) { case ExprType::BINARY: { - std::shared_ptr<_Binary> binary = std::get>(expr.value); - assert(binary != nullptr); - return parenthesize(binary->op.lexeme, {&binary->left, &binary->right}); + std::shared_ptr<_Binary> ptr = std::get>(expr.value); + assert(ptr != nullptr); + return parenthesize(ptr->op.lexeme, {&ptr->left, &ptr->right}); } case ExprType::GROUPING: { - std::shared_ptr<_Grouping> group = std::get>(expr.value); - assert(group != nullptr); - return parenthesize("group", {&group->expr}); + std::shared_ptr<_Grouping> ptr = std::get>(expr.value); + assert(ptr != nullptr); + return parenthesize("group", {&ptr->expr}); } case ExprType::LITERAL: { - std::shared_ptr<_Literal> literal = std::get>(expr.value); - assert(literal != nullptr); - return literal->value.to_string(); + std::shared_ptr<_Literal> ptr = std::get>(expr.value); + assert(ptr != nullptr); + return ptr->value.to_string(); } case ExprType::UNARY: { - std::shared_ptr<_Unary> unary = std::get>(expr.value); - assert(unary != nullptr); - return parenthesize(unary->op.lexeme, {&unary->right}); + std::shared_ptr<_Unary> ptr = std::get>(expr.value); + assert(ptr != nullptr); + return parenthesize(ptr->op.lexeme, {&ptr->right}); + } + case ExprType::VARIABLE: { + std::shared_ptr<_Variable> ptr = std::get>(expr.value); + assert(ptr != nullptr); + return ptr->name.lexeme; + } + case ExprType::ASSIGN: { + std::shared_ptr<_Assign> ptr = std::get>(expr.value); + assert(ptr != nullptr); + return ptr->name.lexeme; } } } diff --git a/cclox_src/parser/environment.cc b/cclox_src/parser/environment.cc new file mode 100644 index 0000000..086d274 --- /dev/null +++ b/cclox_src/parser/environment.cc @@ -0,0 +1,64 @@ +#include "environment.hh" +#include "../error_handler.hh" +#include +#include +#include + +Environment::Environment(const Environment &other) : enclosing{other.enclosing}, values{other.values} {} + +Environment::Environment(Environment &&other) noexcept : enclosing{std::move(other.enclosing)}, values{std::move(other.values)} { + other.enclosing.reset(); +} + +Environment &Environment::operator=(const Environment &other) { + if (this == &other) { + return *this; + } + + if (enclosing) { + enclosing.reset(); + } + + enclosing = other.enclosing; + values = other.values; + + return *this; +} + +Environment &Environment::operator=(Environment &&other) noexcept { + if (this == &other) { + return *this; + } + + if (enclosing) { + enclosing.reset(); + } + + enclosing = std::move(other.enclosing); + values = std::move(other.values); + + other.enclosing.reset(); + + return *this; +} + +void Environment::define(const std::string &name, const Object &value) { + values.insert(std::pair(name, value)); +} + +void Environment::assign(const Token &name, const Object &value) { + if (values.find(name.lexeme) != values.end()) { + values.at(name.lexeme) = value; + return; + } + + throw RuntimeException(name, "Undefined variable '" + name.lexeme + "'."); +} + +Object Environment::get(const Token &name) { + if (values.find(name.lexeme) != values.end()) { + return values.at(name.lexeme); + } + + throw RuntimeException(name, "Undefined variable '" + name.lexeme + "'."); +} diff --git a/cclox_src/parser/environment.hh b/cclox_src/parser/environment.hh new file mode 100644 index 0000000..ad4719d --- /dev/null +++ b/cclox_src/parser/environment.hh @@ -0,0 +1,28 @@ +#ifndef ENVIRONMENT_HH +#define ENVIRONMENT_HH + +#include "../tokenizer.hh" +#include +#include +#include + +struct Environment { + Environment() : enclosing{nullptr}, values{} {} + Environment(std::shared_ptr enclosing) : enclosing{enclosing}, values{} {} + Environment(const Environment &other); + Environment(Environment &&other) noexcept; + + Environment &operator=(const Environment &other); + Environment &operator=(Environment &&other) noexcept; + + ~Environment() = default; + + void define(const std::string &name, const Object &value); + void assign(const Token &name, const Object &value); + Object get(const Token &name); +private: + std::shared_ptr enclosing; + std::unordered_map values; +}; + +#endif diff --git a/cclox_src/parser/expr.cc b/cclox_src/parser/expr.cc index 057166d..b1f02bf 100644 --- a/cclox_src/parser/expr.cc +++ b/cclox_src/parser/expr.cc @@ -33,11 +33,23 @@ Expr::Expr(const Expr &other) : type{other.type} { value = std::make_shared<_Unary>(*ptr); break; } + case ExprType::VARIABLE: { + std::shared_ptr<_Variable> ptr = std::get>(other.value); + assert(ptr != nullptr); + value = std::make_shared<_Variable>(*ptr); + break; + } + case ExprType::ASSIGN: { + std::shared_ptr<_Assign> ptr = std::get>(other.value); + assert(ptr != nullptr); + value = std::make_shared<_Assign>(*ptr); + break; + } } } // Move constructor -Expr::Expr(const Expr &&other) : type{other.type}, value{std::move(other.value)} { +Expr::Expr(Expr &&other) : type{other.type}, value{std::move(other.value)} { switch(type) { case ExprType::BINARY: { std::shared_ptr<_Binary> ptr = std::get>(other.value); @@ -63,6 +75,18 @@ Expr::Expr(const Expr &&other) : type{other.type}, value{std::move(other.value)} ptr.reset(); break; } + case ExprType::VARIABLE: { + std::shared_ptr<_Variable> ptr = std::get>(other.value); + assert(ptr != nullptr); + ptr.reset(); + break; + } + case ExprType::ASSIGN: { + std::shared_ptr<_Assign> ptr = std::get>(other.value); + assert(ptr != nullptr); + ptr.reset(); + break; + } } } @@ -97,6 +121,18 @@ Expr &Expr::operator=(const Expr &other) { ptr.reset(); break; } + case ExprType::VARIABLE: { + std::shared_ptr<_Variable> ptr = std::get>(value); + assert(ptr != nullptr); + ptr.reset(); + break; + } + case ExprType::ASSIGN: { + std::shared_ptr<_Assign> ptr = std::get>(value); + assert(ptr != nullptr); + ptr.reset(); + break; + } } type = other.type; @@ -126,13 +162,25 @@ Expr &Expr::operator=(const Expr &other) { value = std::make_shared<_Unary>(*ptr); break; } + case ExprType::VARIABLE: { + std::shared_ptr<_Variable> ptr = std::get>(other.value); + assert(ptr != nullptr); + value = std::make_shared<_Variable>(*ptr); + break; + } + case ExprType::ASSIGN: { + std::shared_ptr<_Assign> ptr = std::get>(other.value); + assert(ptr != nullptr); + value = std::make_shared<_Assign>(*ptr); + break; + } } return *this; } // Move assignment -Expr &Expr::operator=(const Expr &&other) { +Expr &Expr::operator=(Expr &&other) { if (this == &other) { return *this; } @@ -162,6 +210,18 @@ Expr &Expr::operator=(const Expr &&other) { ptr.reset(); break; } + case ExprType::VARIABLE: { + std::shared_ptr<_Variable> ptr = std::get>(value); + assert(ptr != nullptr); + ptr.reset(); + break; + } + case ExprType::ASSIGN: { + std::shared_ptr<_Assign> ptr = std::get>(value); + assert(ptr != nullptr); + ptr.reset(); + break; + } } type = other.type; @@ -195,6 +255,20 @@ Expr &Expr::operator=(const Expr &&other) { ptr.reset(); break; } + case ExprType::VARIABLE: { + std::shared_ptr<_Variable> ptr = std::get>(other.value); + assert(ptr != nullptr); + value = std::move(other.value); + ptr.reset(); + break; + } + case ExprType::ASSIGN: { + std::shared_ptr<_Assign> ptr = std::get>(other.value); + assert(ptr != nullptr); + value = std::move(other.value); + ptr.reset(); + break; + } } return *this; diff --git a/cclox_src/parser/expr.hh b/cclox_src/parser/expr.hh index 4c393ce..4ba2ddb 100644 --- a/cclox_src/parser/expr.hh +++ b/cclox_src/parser/expr.hh @@ -10,25 +10,33 @@ struct _Binary; struct _Grouping; struct _Literal; struct _Unary; +struct _Variable; +struct _Assign; enum class ExprType { BINARY, GROUPING, LITERAL, UNARY, + VARIABLE, + ASSIGN, }; using ExprVariant = std::variant< std::shared_ptr<_Binary>, std::shared_ptr<_Grouping>, std::shared_ptr<_Literal>, - std::shared_ptr<_Unary> + std::shared_ptr<_Unary>, + std::shared_ptr<_Variable>, + std::shared_ptr<_Assign> >; #define Binary(LEFT, OP, RIGHT) (Expr{ExprType::BINARY, std::make_shared<_Binary>(LEFT, OP, RIGHT)}) #define Grouping(EXPR) (Expr{ExprType::GROUPING, std::make_shared<_Grouping>(EXPR)}) #define Literal(VALUE) (Expr{ExprType::LITERAL, std::make_shared<_Literal>(VALUE)}) #define Unary(OP, RIGHT) (Expr{ExprType::UNARY, std::make_shared<_Unary>(OP, RIGHT)}) +#define Variable(NAME) (Expr{ExprType::VARIABLE, std::make_shared<_Variable>(NAME)}) +#define Assign(NAME, VALUE) (Expr{ExprType::ASSIGN, std::make_shared<_Assign>(NAME, VALUE)}) struct Expr { Expr(ExprType type, ExprVariant value); @@ -37,13 +45,13 @@ struct Expr { Expr(const Expr &other); // Move constructor - Expr(const Expr &&other); + Expr(Expr &&other); // Copy assignment Expr &operator=(const Expr &other); // Move assignment - Expr &operator=(const Expr &&other); + Expr &operator=(Expr &&other); ExprType type; ExprVariant value; @@ -72,4 +80,15 @@ struct _Unary { Expr right; }; +struct _Variable { + _Variable(Token name) : name{name} {} + Token name; +}; + +struct _Assign { + _Assign(Token name, const Expr &value) : name{name}, value{value} {} + Token name; + Expr value; +}; + #endif diff --git a/cclox_src/parser/parser.cc b/cclox_src/parser/parser.cc index 7bbd85a..faad05c 100644 --- a/cclox_src/parser/parser.cc +++ b/cclox_src/parser/parser.cc @@ -1,21 +1,88 @@ #include "parser.hh" #include "expr.hh" +#include "stmt.hh" #include "../error_handler.hh" #include "../tokenizer.hh" -#include +#include extern ErrorHandler error_handler; -std::optional Parser::parse() { +std::vector Parser::parse() { + std::vector statements{}; + while (!is_at_end()) { + statements.push_back(declaration()); + } + + return statements; +} + +Stmt Parser::declaration() { try { - return expression(); + if (match({TokenType::VAR})) { + return var_declaration(); + } + + return statement(); } catch (ParseException e) { - return std::nullopt; + synchronize(); + return Expression(Literal(Object{})); } } +Stmt Parser::var_declaration() { + Token name = consume(TokenType::IDENTIFIER, "Expect variable name."); + Expr initializer = Literal(Object{}); + + if (match({TokenType::EQUAL})) { + initializer = expression(); + } + + consume(TokenType::SEMICOLON, "Expect ';' after variable declaration"); + return Var(name, initializer); +} + +Stmt Parser::statement() { + if (match({TokenType::PRINT})) { + return print_statement(); + } + + return expression_statement(); +} + +Stmt Parser::print_statement() { + Expr value{expression()}; + consume(TokenType::SEMICOLON, "Expect ';' after value."); + return Print(value); +} + +Stmt Parser::expression_statement() { + Expr value{expression()}; + consume(TokenType::SEMICOLON, "Expect ';' after value."); + return Expression(value); +} + Expr Parser::expression() { - return equality(); + return assignment(); +} + +Expr Parser::assignment() { + Expr expr = equality(); + + if (match({TokenType::EQUAL})) { + Token equals = previous(); + Expr value = assignment(); + + if (expr.type == ExprType::VARIABLE) { + std::shared_ptr<_Variable> ptr = std::get>(expr.value); + assert(ptr != nullptr); + Token name = ptr->name; + return Assign(name, value); + } + + error_handler.error(equals, "Invalid assignment target."); + } + + return expr; } Expr Parser::equality() { @@ -94,6 +161,10 @@ Expr Parser::primary() { return Literal(previous().literal); } + if (match({TokenType::IDENTIFIER})) { + return Variable(previous()); + } + if (match({TokenType::LEFT_PAREN})) { Expr expr = expression(); consume(TokenType::RIGHT_PAREN, "Expect ')' after expression."); diff --git a/cclox_src/parser/parser.hh b/cclox_src/parser/parser.hh index 0e05aa4..cac4cf0 100644 --- a/cclox_src/parser/parser.hh +++ b/cclox_src/parser/parser.hh @@ -2,10 +2,10 @@ #define PARSER_HH #include "expr.hh" +#include "stmt.hh" #include "../tokenizer.hh" #include #include -#include #include struct ParseException : public std::exception { @@ -21,8 +21,14 @@ private: struct Parser { Parser(std::vector tokens) : tokens{tokens} {} - std::optional parse(); + std::vector parse(); + Stmt declaration(); + Stmt var_declaration(); + Stmt statement(); + Stmt print_statement(); + Stmt expression_statement(); Expr expression(); + Expr assignment(); Expr equality(); Expr comparison(); Expr term(); diff --git a/cclox_src/parser/stmt.cc b/cclox_src/parser/stmt.cc new file mode 100644 index 0000000..a9d2aba --- /dev/null +++ b/cclox_src/parser/stmt.cc @@ -0,0 +1,162 @@ +#include "stmt.hh" +#include +#include + +Stmt::Stmt(StmtType type, StmtVariant value) : type{type}, value{value} {} + +// Copy constructor +Stmt::Stmt(const Stmt &other) : type{other.type} { + switch(type) { + case StmtType::EXPRESSION: { + std::shared_ptr<_Expression> ptr = std::get>(other.value); + assert(ptr != nullptr); + value = std::make_shared<_Expression>(*ptr); + break; + } + case StmtType::PRINT: { + std::shared_ptr<_Print> ptr = std::get>(other.value); + assert(ptr != nullptr); + value = std::make_shared<_Print>(*ptr); + break; + } + case StmtType::VAR: { + std::shared_ptr<_Var> ptr = std::get>(other.value); + assert(ptr != nullptr); + value = std::make_shared<_Var>(*ptr); + break; + } + } +} + +// Move constructor +Stmt::Stmt(const Stmt &&other) : type{other.type}, value{std::move(other.value)} { + switch(type) { + case StmtType::EXPRESSION: { + std::shared_ptr<_Expression> ptr = std::get>(other.value); + assert(ptr != nullptr); + ptr.reset(); + break; + } + case StmtType::PRINT: { + std::shared_ptr<_Print> ptr = std::get>(other.value); + assert(ptr != nullptr); + ptr.reset(); + break; + } + case StmtType::VAR: { + std::shared_ptr<_Var> ptr = std::get>(other.value); + assert(ptr != nullptr); + ptr.reset(); + break; + } + } +} + +// Copy assignment +Stmt &Stmt::operator=(const Stmt &other) { + if (this == &other) { + return *this; + } + + switch(type) { + case StmtType::EXPRESSION: { + std::shared_ptr<_Expression> ptr = std::get>(value); + assert(ptr != nullptr); + ptr.reset(); + break; + } + case StmtType::PRINT: { + std::shared_ptr<_Print> ptr = std::get>(value); + assert(ptr != nullptr); + ptr.reset(); + break; + } + case StmtType::VAR: { + std::shared_ptr<_Var> ptr = std::get>(value); + assert(ptr != nullptr); + ptr.reset(); + break; + } + } + + type = other.type; + + switch(type) { + case StmtType::EXPRESSION: { + std::shared_ptr<_Expression> ptr = std::get>(other.value); + assert(ptr != nullptr); + value = std::make_shared<_Expression>(*ptr); + break; + } + case StmtType::PRINT: { + std::shared_ptr<_Print> ptr = std::get>(other.value); + assert(ptr != nullptr); + value = std::make_shared<_Print>(*ptr); + break; + } + case StmtType::VAR: { + std::shared_ptr<_Var> ptr = std::get>(other.value); + assert(ptr != nullptr); + value = std::make_shared<_Var>(*ptr); + break; + } + } + + return *this; +} + +// Move assignment +Stmt &Stmt::operator=(const Stmt &&other) { + if (this == &other) { + return *this; + } + + switch(type) { + case StmtType::EXPRESSION: { + std::shared_ptr<_Expression> ptr = std::get>(value); + assert(ptr != nullptr); + ptr.reset(); + break; + } + case StmtType::PRINT: { + std::shared_ptr<_Print> ptr = std::get>(value); + assert(ptr != nullptr); + ptr.reset(); + break; + } + case StmtType::VAR: { + std::shared_ptr<_Var> ptr = std::get>(value); + assert(ptr != nullptr); + ptr.reset(); + break; + } + } + + type = other.type; + + switch(type) { + case StmtType::EXPRESSION: { + std::shared_ptr<_Expression> ptr = std::get>(other.value); + assert(ptr != nullptr); + value = std::move(other.value); + ptr.reset(); + break; + } + case StmtType::PRINT: { + std::shared_ptr<_Print> ptr = std::get>(other.value); + assert(ptr != nullptr); + value = std::move(other.value); + ptr.reset(); + break; + } + case StmtType::VAR: { + std::shared_ptr<_Var> ptr = std::get>(other.value); + assert(ptr != nullptr); + value = std::move(other.value); + ptr.reset(); + break; + } + } + + return *this; +} diff --git a/cclox_src/parser/stmt.hh b/cclox_src/parser/stmt.hh new file mode 100644 index 0000000..3d7fc0c --- /dev/null +++ b/cclox_src/parser/stmt.hh @@ -0,0 +1,64 @@ +#ifndef STMT_HH +#define STMT_HH + +#include "expr.hh" +#include +#include + +struct Stmt; +struct _Expression; +struct _Print; +struct _Var; + +enum class StmtType { + EXPRESSION, + PRINT, + VAR, +}; + +using StmtVariant = std::variant< + std::shared_ptr<_Expression>, + std::shared_ptr<_Print>, + std::shared_ptr<_Var> +>; + +#define Expression(EXPR) (Stmt{StmtType::EXPRESSION, std::make_shared<_Expression>(EXPR)}) +#define Print(EXPR) (Stmt{StmtType::PRINT, std::make_shared<_Print>(EXPR)}) +#define Var(NAME, EXPR) (Stmt{StmtType::VAR, std::make_shared<_Var>(NAME, EXPR)}) + +struct Stmt { + Stmt(StmtType type, StmtVariant value); + + // Copy constructor + Stmt(const Stmt &other); + + // Move constructor + Stmt(const Stmt &&other); + + // Copy assignment + Stmt &operator=(const Stmt &other); + + // Move assignment + Stmt &operator=(const Stmt &&other); + + StmtType type; + StmtVariant value; +}; + +struct _Expression { + _Expression(const Expr &expr) : expr{expr} {} + Expr expr; +}; + +struct _Print { + _Print(const Expr &expr) : expr{expr} {} + Expr expr; +}; + +struct _Var { + _Var(const Token &name, const Expr &expr) : name{name}, expr{expr} {} + Token name; + Expr expr; +}; + +#endif diff --git a/cclox_src/scanner/object.cc b/cclox_src/scanner/object.cc index dc14f91..0f86f54 100644 --- a/cclox_src/scanner/object.cc +++ b/cclox_src/scanner/object.cc @@ -2,7 +2,7 @@ #include #include -std::string Object::to_string() { +std::string Object::to_string() const { switch (type) { case ObjectType::NIL: return "nil"; @@ -78,25 +78,7 @@ std::ostream &operator<<(std::ostream &os, const ObjectType &type) { } std::ostream &operator<<(std::ostream &os, const Object &obj) { - os << "Object(" << obj.type; - - switch (obj.type) { - case ObjectType::NIL: - break; - case ObjectType::BOOL: - os << ", " << std::to_string(std::get(obj.value)); - break; - case ObjectType::IDENTIFIER: - case ObjectType::STRING_LIT: - os << ", " << std::get(obj.value); - break; - case ObjectType::NUMBER: - os << ", " << std::get(obj.value); - break; - } - - os << ')'; - + os << obj.to_string(); return os; } diff --git a/cclox_src/scanner/object.hh b/cclox_src/scanner/object.hh index ee919e9..fbcb8c8 100644 --- a/cclox_src/scanner/object.hh +++ b/cclox_src/scanner/object.hh @@ -29,7 +29,7 @@ struct Object { ObjectType::STRING_LIT }, value{std::move(value)} {}; - std::string to_string(); + std::string to_string() const; bool operator==(const Object &other); bool operator!=(const Object &other);