Start adding statements

This commit is contained in:
Abdelrahman Said 2025-06-29 19:25:08 +01:00
parent 2690c07220
commit 4f39417d3e
16 changed files with 613 additions and 67 deletions

View File

@ -2,10 +2,10 @@
#include "error_handler.hh" #include "error_handler.hh"
#include "tokenizer.hh" #include "tokenizer.hh"
#include "parser.hh" #include "parser.hh"
#include <vector>
#include <cstdint> #include <cstdint>
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
#include <optional>
#include <sysexits.h> #include <sysexits.h>
#define PROMPT "> " #define PROMPT "> "
@ -57,15 +57,12 @@ void run(const std::string &code) {
std::vector<Token> tokens = scanner.scan_tokens(); std::vector<Token> tokens = scanner.scan_tokens();
Parser parser{tokens}; Parser parser{tokens};
std::optional<Expr> expression = parser.parse(); std::vector<Stmt> statements = parser.parse();
static AstInterpreter interpreter{};
if (error_handler.had_error) { if (error_handler.had_error) {
return; return;
} }
if (expression) { static AstInterpreter interpreter{};
interpreter.interpret(*expression); interpreter.interpret(statements);
}
} }

View File

@ -1,8 +1,10 @@
#ifndef PARSER_CC #ifndef MAIN_PARSER_CC
#define PARSER_CC #define MAIN_PARSER_CC
#include "parser/expr.cc" #include "parser/expr.cc"
#include "parser/stmt.cc"
#include "parser/parser.cc" #include "parser/parser.cc"
#include "parser/environment.cc"
#include "parser/ast_printer.cc" #include "parser/ast_printer.cc"
#include "parser/ast_interpreter.cc" #include "parser/ast_interpreter.cc"

View File

@ -2,7 +2,9 @@
#define MAIN_PARSER_HH #define MAIN_PARSER_HH
#include "parser/expr.hh" #include "parser/expr.hh"
#include "parser/stmt.hh"
#include "parser/parser.hh" #include "parser/parser.hh"
#include "parser/environment.hh"
#include "parser/ast_printer.hh" #include "parser/ast_printer.hh"
#include "parser/ast_interpreter.hh" #include "parser/ast_interpreter.hh"

View File

@ -1,33 +1,73 @@
#include "ast_interpreter.hh" #include "ast_interpreter.hh"
#include "expr.hh" #include "expr.hh"
#include "stmt.hh"
#include "../error_handler.hh" #include "../error_handler.hh"
#include "../tokenizer.hh" #include "../tokenizer.hh"
#include <memory> #include <memory>
#include <string> #include <string>
#include <vector>
#include <cassert> #include <cassert>
#include <iostream> #include <iostream>
extern ErrorHandler error_handler; extern ErrorHandler error_handler;
void AstInterpreter::interpret(const Expr &expression) { void AstInterpreter::interpret(const std::vector<Stmt> &statements) {
try { try {
Object value = evaluate(expression); for (const Stmt & stmt : statements) {
std::cout << value.to_string() << '\n'; execute(stmt);
}
} catch (RuntimeException e) { } catch (RuntimeException e) {
error_handler.runtime_error(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<std::shared_ptr<_Expression>>(stmt.value);
assert(ptr != nullptr);
evaluate(ptr->expr);
}
void AstInterpreter::execute_print_statement(const Stmt &stmt) {
std::shared_ptr<_Print> ptr = std::get<std::shared_ptr<_Print>>(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<std::shared_ptr<_Var>>(stmt.value);
assert(ptr != nullptr);
if (ptr->expr.type == ExprType::LITERAL) {
std::shared_ptr<_Literal> eptr = std::get<std::shared_ptr<_Literal>>(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) { Object AstInterpreter::evaluate(const Expr &expr) {
switch (expr.type) { switch (expr.type) {
case ExprType::BINARY: case ExprType::BINARY: return evaluate_binary_expression(expr);
return evaluate_binary_expression(expr); case ExprType::GROUPING: return evaluate_grouping_expression(expr);
case ExprType::GROUPING: case ExprType::LITERAL: return evaluate_literal_expression(expr);
return evaluate_grouping_expression(expr); case ExprType::UNARY: return evaluate_unary_expression(expr);
case ExprType::LITERAL: case ExprType::VARIABLE: return evaluate_variable_expression(expr);
return evaluate_literal_expression(expr); case ExprType::ASSIGN: return evaluate_assignment_expression(expr);
case ExprType::UNARY:
return evaluate_unary_expression(expr);
} }
} }
@ -156,6 +196,20 @@ Object AstInterpreter::evaluate_unary_expression(const Expr &expr) {
return Object{}; return Object{};
} }
Object AstInterpreter::evaluate_variable_expression(const Expr &expr) {
std::shared_ptr<_Variable> ptr = std::get<std::shared_ptr<_Variable>>(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<std::shared_ptr<_Assign>>(expr.value);
assert(ptr != nullptr);
Object value = evaluate(ptr->value);
environment.assign(ptr->name, value);
return value;
}
bool AstInterpreter::is_truthy(const Object &object) { bool AstInterpreter::is_truthy(const Object &object) {
switch (object.type) { switch (object.type) {
case ObjectType::NIL: return false; case ObjectType::NIL: return false;

View File

@ -2,20 +2,31 @@
#define AST_INTERPRETER_HH #define AST_INTERPRETER_HH
#include "expr.hh" #include "expr.hh"
#include "stmt.hh"
#include "environment.hh"
#include "../tokenizer.hh" #include "../tokenizer.hh"
#include <string> #include <vector>
struct AstInterpreter { struct AstInterpreter {
void interpret(const Expr &expression); void interpret(const std::vector<Stmt> &statements);
private: 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(const Expr &expr);
Object evaluate_binary_expression(const Expr &expr); Object evaluate_binary_expression(const Expr &expr);
Object evaluate_grouping_expression(const Expr &expr); Object evaluate_grouping_expression(const Expr &expr);
Object evaluate_literal_expression(const Expr &expr); Object evaluate_literal_expression(const Expr &expr);
Object evaluate_unary_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_truthy(const Object &object);
bool is_equal(const Object &left, const Object &right); bool is_equal(const Object &left, const Object &right);
Environment environment{};
}; };
#endif #endif

View File

@ -7,24 +7,34 @@
std::string AstPrinter::print(const Expr &expr) { std::string AstPrinter::print(const Expr &expr) {
switch (expr.type) { switch (expr.type) {
case ExprType::BINARY: { case ExprType::BINARY: {
std::shared_ptr<_Binary> binary = std::get<std::shared_ptr<_Binary>>(expr.value); std::shared_ptr<_Binary> ptr = std::get<std::shared_ptr<_Binary>>(expr.value);
assert(binary != nullptr); assert(ptr != nullptr);
return parenthesize(binary->op.lexeme, {&binary->left, &binary->right}); return parenthesize(ptr->op.lexeme, {&ptr->left, &ptr->right});
} }
case ExprType::GROUPING: { case ExprType::GROUPING: {
std::shared_ptr<_Grouping> group = std::get<std::shared_ptr<_Grouping>>(expr.value); std::shared_ptr<_Grouping> ptr = std::get<std::shared_ptr<_Grouping>>(expr.value);
assert(group != nullptr); assert(ptr != nullptr);
return parenthesize("group", {&group->expr}); return parenthesize("group", {&ptr->expr});
} }
case ExprType::LITERAL: { case ExprType::LITERAL: {
std::shared_ptr<_Literal> literal = std::get<std::shared_ptr<_Literal>>(expr.value); std::shared_ptr<_Literal> ptr = std::get<std::shared_ptr<_Literal>>(expr.value);
assert(literal != nullptr); assert(ptr != nullptr);
return literal->value.to_string(); return ptr->value.to_string();
} }
case ExprType::UNARY: { case ExprType::UNARY: {
std::shared_ptr<_Unary> unary = std::get<std::shared_ptr<_Unary>>(expr.value); std::shared_ptr<_Unary> ptr = std::get<std::shared_ptr<_Unary>>(expr.value);
assert(unary != nullptr); assert(ptr != nullptr);
return parenthesize(unary->op.lexeme, {&unary->right}); return parenthesize(ptr->op.lexeme, {&ptr->right});
}
case ExprType::VARIABLE: {
std::shared_ptr<_Variable> ptr = std::get<std::shared_ptr<_Variable>>(expr.value);
assert(ptr != nullptr);
return ptr->name.lexeme;
}
case ExprType::ASSIGN: {
std::shared_ptr<_Assign> ptr = std::get<std::shared_ptr<_Assign>>(expr.value);
assert(ptr != nullptr);
return ptr->name.lexeme;
} }
} }
} }

View File

@ -0,0 +1,64 @@
#include "environment.hh"
#include "../error_handler.hh"
#include <algorithm>
#include <memory>
#include <utility>
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 + "'.");
}

View File

@ -0,0 +1,28 @@
#ifndef ENVIRONMENT_HH
#define ENVIRONMENT_HH
#include "../tokenizer.hh"
#include <memory>
#include <string>
#include <unordered_map>
struct Environment {
Environment() : enclosing{nullptr}, values{} {}
Environment(std::shared_ptr<Environment> 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<Environment> enclosing;
std::unordered_map<std::string, Object> values;
};
#endif

View File

@ -33,11 +33,23 @@ Expr::Expr(const Expr &other) : type{other.type} {
value = std::make_shared<_Unary>(*ptr); value = std::make_shared<_Unary>(*ptr);
break; break;
} }
case ExprType::VARIABLE: {
std::shared_ptr<_Variable> ptr = std::get<std::shared_ptr<_Variable>>(other.value);
assert(ptr != nullptr);
value = std::make_shared<_Variable>(*ptr);
break;
}
case ExprType::ASSIGN: {
std::shared_ptr<_Assign> ptr = std::get<std::shared_ptr<_Assign>>(other.value);
assert(ptr != nullptr);
value = std::make_shared<_Assign>(*ptr);
break;
}
} }
} }
// Move constructor // 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) { switch(type) {
case ExprType::BINARY: { case ExprType::BINARY: {
std::shared_ptr<_Binary> ptr = std::get<std::shared_ptr<_Binary>>(other.value); std::shared_ptr<_Binary> ptr = std::get<std::shared_ptr<_Binary>>(other.value);
@ -63,6 +75,18 @@ Expr::Expr(const Expr &&other) : type{other.type}, value{std::move(other.value)}
ptr.reset(); ptr.reset();
break; break;
} }
case ExprType::VARIABLE: {
std::shared_ptr<_Variable> ptr = std::get<std::shared_ptr<_Variable>>(other.value);
assert(ptr != nullptr);
ptr.reset();
break;
}
case ExprType::ASSIGN: {
std::shared_ptr<_Assign> ptr = std::get<std::shared_ptr<_Assign>>(other.value);
assert(ptr != nullptr);
ptr.reset();
break;
}
} }
} }
@ -97,6 +121,18 @@ Expr &Expr::operator=(const Expr &other) {
ptr.reset(); ptr.reset();
break; break;
} }
case ExprType::VARIABLE: {
std::shared_ptr<_Variable> ptr = std::get<std::shared_ptr<_Variable>>(value);
assert(ptr != nullptr);
ptr.reset();
break;
}
case ExprType::ASSIGN: {
std::shared_ptr<_Assign> ptr = std::get<std::shared_ptr<_Assign>>(value);
assert(ptr != nullptr);
ptr.reset();
break;
}
} }
type = other.type; type = other.type;
@ -126,13 +162,25 @@ Expr &Expr::operator=(const Expr &other) {
value = std::make_shared<_Unary>(*ptr); value = std::make_shared<_Unary>(*ptr);
break; break;
} }
case ExprType::VARIABLE: {
std::shared_ptr<_Variable> ptr = std::get<std::shared_ptr<_Variable>>(other.value);
assert(ptr != nullptr);
value = std::make_shared<_Variable>(*ptr);
break;
}
case ExprType::ASSIGN: {
std::shared_ptr<_Assign> ptr = std::get<std::shared_ptr<_Assign>>(other.value);
assert(ptr != nullptr);
value = std::make_shared<_Assign>(*ptr);
break;
}
} }
return *this; return *this;
} }
// Move assignment // Move assignment
Expr &Expr::operator=(const Expr &&other) { Expr &Expr::operator=(Expr &&other) {
if (this == &other) { if (this == &other) {
return *this; return *this;
} }
@ -162,6 +210,18 @@ Expr &Expr::operator=(const Expr &&other) {
ptr.reset(); ptr.reset();
break; break;
} }
case ExprType::VARIABLE: {
std::shared_ptr<_Variable> ptr = std::get<std::shared_ptr<_Variable>>(value);
assert(ptr != nullptr);
ptr.reset();
break;
}
case ExprType::ASSIGN: {
std::shared_ptr<_Assign> ptr = std::get<std::shared_ptr<_Assign>>(value);
assert(ptr != nullptr);
ptr.reset();
break;
}
} }
type = other.type; type = other.type;
@ -195,6 +255,20 @@ Expr &Expr::operator=(const Expr &&other) {
ptr.reset(); ptr.reset();
break; break;
} }
case ExprType::VARIABLE: {
std::shared_ptr<_Variable> ptr = std::get<std::shared_ptr<_Variable>>(other.value);
assert(ptr != nullptr);
value = std::move(other.value);
ptr.reset();
break;
}
case ExprType::ASSIGN: {
std::shared_ptr<_Assign> ptr = std::get<std::shared_ptr<_Assign>>(other.value);
assert(ptr != nullptr);
value = std::move(other.value);
ptr.reset();
break;
}
} }
return *this; return *this;

View File

@ -10,25 +10,33 @@ struct _Binary;
struct _Grouping; struct _Grouping;
struct _Literal; struct _Literal;
struct _Unary; struct _Unary;
struct _Variable;
struct _Assign;
enum class ExprType { enum class ExprType {
BINARY, BINARY,
GROUPING, GROUPING,
LITERAL, LITERAL,
UNARY, UNARY,
VARIABLE,
ASSIGN,
}; };
using ExprVariant = std::variant< using ExprVariant = std::variant<
std::shared_ptr<_Binary>, std::shared_ptr<_Binary>,
std::shared_ptr<_Grouping>, std::shared_ptr<_Grouping>,
std::shared_ptr<_Literal>, 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 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 Grouping(EXPR) (Expr{ExprType::GROUPING, std::make_shared<_Grouping>(EXPR)})
#define Literal(VALUE) (Expr{ExprType::LITERAL, std::make_shared<_Literal>(VALUE)}) #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 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 { struct Expr {
Expr(ExprType type, ExprVariant value); Expr(ExprType type, ExprVariant value);
@ -37,13 +45,13 @@ struct Expr {
Expr(const Expr &other); Expr(const Expr &other);
// Move constructor // Move constructor
Expr(const Expr &&other); Expr(Expr &&other);
// Copy assignment // Copy assignment
Expr &operator=(const Expr &other); Expr &operator=(const Expr &other);
// Move assignment // Move assignment
Expr &operator=(const Expr &&other); Expr &operator=(Expr &&other);
ExprType type; ExprType type;
ExprVariant value; ExprVariant value;
@ -72,4 +80,15 @@ struct _Unary {
Expr right; 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 #endif

View File

@ -1,21 +1,88 @@
#include "parser.hh" #include "parser.hh"
#include "expr.hh" #include "expr.hh"
#include "stmt.hh"
#include "../error_handler.hh" #include "../error_handler.hh"
#include "../tokenizer.hh" #include "../tokenizer.hh"
#include <optional> #include <cassert>
extern ErrorHandler error_handler; extern ErrorHandler error_handler;
std::optional<Expr> Parser::parse() { std::vector<Stmt> Parser::parse() {
std::vector<Stmt> statements{};
while (!is_at_end()) {
statements.push_back(declaration());
}
return statements;
}
Stmt Parser::declaration() {
try { try {
return expression(); if (match({TokenType::VAR})) {
return var_declaration();
}
return statement();
} catch (ParseException e) { } 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() { 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<std::shared_ptr<_Variable>>(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() { Expr Parser::equality() {
@ -94,6 +161,10 @@ Expr Parser::primary() {
return Literal(previous().literal); return Literal(previous().literal);
} }
if (match({TokenType::IDENTIFIER})) {
return Variable(previous());
}
if (match({TokenType::LEFT_PAREN})) { if (match({TokenType::LEFT_PAREN})) {
Expr expr = expression(); Expr expr = expression();
consume(TokenType::RIGHT_PAREN, "Expect ')' after expression."); consume(TokenType::RIGHT_PAREN, "Expect ')' after expression.");

View File

@ -2,10 +2,10 @@
#define PARSER_HH #define PARSER_HH
#include "expr.hh" #include "expr.hh"
#include "stmt.hh"
#include "../tokenizer.hh" #include "../tokenizer.hh"
#include <cstddef> #include <cstddef>
#include <exception> #include <exception>
#include <optional>
#include <vector> #include <vector>
struct ParseException : public std::exception { struct ParseException : public std::exception {
@ -21,8 +21,14 @@ private:
struct Parser { struct Parser {
Parser(std::vector<Token> tokens) : tokens{tokens} {} Parser(std::vector<Token> tokens) : tokens{tokens} {}
std::optional<Expr> parse(); std::vector<Stmt> parse();
Stmt declaration();
Stmt var_declaration();
Stmt statement();
Stmt print_statement();
Stmt expression_statement();
Expr expression(); Expr expression();
Expr assignment();
Expr equality(); Expr equality();
Expr comparison(); Expr comparison();
Expr term(); Expr term();

162
cclox_src/parser/stmt.cc Normal file
View File

@ -0,0 +1,162 @@
#include "stmt.hh"
#include <cassert>
#include <utility>
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<std::shared_ptr<_Expression>>(other.value);
assert(ptr != nullptr);
value = std::make_shared<_Expression>(*ptr);
break;
}
case StmtType::PRINT: {
std::shared_ptr<_Print> ptr = std::get<std::shared_ptr<_Print>>(other.value);
assert(ptr != nullptr);
value = std::make_shared<_Print>(*ptr);
break;
}
case StmtType::VAR: {
std::shared_ptr<_Var> ptr = std::get<std::shared_ptr<_Var>>(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<std::shared_ptr<_Expression>>(other.value);
assert(ptr != nullptr);
ptr.reset();
break;
}
case StmtType::PRINT: {
std::shared_ptr<_Print> ptr = std::get<std::shared_ptr<_Print>>(other.value);
assert(ptr != nullptr);
ptr.reset();
break;
}
case StmtType::VAR: {
std::shared_ptr<_Var> ptr = std::get<std::shared_ptr<_Var>>(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<std::shared_ptr<_Expression>>(value);
assert(ptr != nullptr);
ptr.reset();
break;
}
case StmtType::PRINT: {
std::shared_ptr<_Print> ptr = std::get<std::shared_ptr<_Print>>(value);
assert(ptr != nullptr);
ptr.reset();
break;
}
case StmtType::VAR: {
std::shared_ptr<_Var> ptr = std::get<std::shared_ptr<_Var>>(value);
assert(ptr != nullptr);
ptr.reset();
break;
}
}
type = other.type;
switch(type) {
case StmtType::EXPRESSION: {
std::shared_ptr<_Expression> ptr = std::get<std::shared_ptr<_Expression>>(other.value);
assert(ptr != nullptr);
value = std::make_shared<_Expression>(*ptr);
break;
}
case StmtType::PRINT: {
std::shared_ptr<_Print> ptr = std::get<std::shared_ptr<_Print>>(other.value);
assert(ptr != nullptr);
value = std::make_shared<_Print>(*ptr);
break;
}
case StmtType::VAR: {
std::shared_ptr<_Var> ptr = std::get<std::shared_ptr<_Var>>(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<std::shared_ptr<_Expression>>(value);
assert(ptr != nullptr);
ptr.reset();
break;
}
case StmtType::PRINT: {
std::shared_ptr<_Print> ptr = std::get<std::shared_ptr<_Print>>(value);
assert(ptr != nullptr);
ptr.reset();
break;
}
case StmtType::VAR: {
std::shared_ptr<_Var> ptr = std::get<std::shared_ptr<_Var>>(value);
assert(ptr != nullptr);
ptr.reset();
break;
}
}
type = other.type;
switch(type) {
case StmtType::EXPRESSION: {
std::shared_ptr<_Expression> ptr = std::get<std::shared_ptr<_Expression>>(other.value);
assert(ptr != nullptr);
value = std::move(other.value);
ptr.reset();
break;
}
case StmtType::PRINT: {
std::shared_ptr<_Print> ptr = std::get<std::shared_ptr<_Print>>(other.value);
assert(ptr != nullptr);
value = std::move(other.value);
ptr.reset();
break;
}
case StmtType::VAR: {
std::shared_ptr<_Var> ptr = std::get<std::shared_ptr<_Var>>(other.value);
assert(ptr != nullptr);
value = std::move(other.value);
ptr.reset();
break;
}
}
return *this;
}

64
cclox_src/parser/stmt.hh Normal file
View File

@ -0,0 +1,64 @@
#ifndef STMT_HH
#define STMT_HH
#include "expr.hh"
#include <memory>
#include <variant>
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

View File

@ -2,7 +2,7 @@
#include <cstddef> #include <cstddef>
#include <string> #include <string>
std::string Object::to_string() { std::string Object::to_string() const {
switch (type) { switch (type) {
case ObjectType::NIL: case ObjectType::NIL:
return "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) { std::ostream &operator<<(std::ostream &os, const Object &obj) {
os << "Object(" << obj.type; os << obj.to_string();
switch (obj.type) {
case ObjectType::NIL:
break;
case ObjectType::BOOL:
os << ", " << std::to_string(std::get<bool>(obj.value));
break;
case ObjectType::IDENTIFIER:
case ObjectType::STRING_LIT:
os << ", " << std::get<std::string>(obj.value);
break;
case ObjectType::NUMBER:
os << ", " << std::get<double>(obj.value);
break;
}
os << ')';
return os; return os;
} }

View File

@ -29,7 +29,7 @@ struct Object {
ObjectType::STRING_LIT ObjectType::STRING_LIT
}, },
value{std::move(value)} {}; value{std::move(value)} {};
std::string to_string(); std::string to_string() const;
bool operator==(const Object &other); bool operator==(const Object &other);
bool operator!=(const Object &other); bool operator!=(const Object &other);