And that's why I hate C++

This commit is contained in:
Abdelrahman Said 2025-06-21 16:51:35 +01:00
parent 339b92dbae
commit c6f9307253
3 changed files with 112 additions and 54 deletions

View File

@ -18,15 +18,13 @@ int main(int argc, char *argv[]) {
// run_interpreter(argc, argv); // run_interpreter(argc, argv);
Token unary_op{TokenType::MINUS, "-", Object{}, 1}; Token unary_op{TokenType::MINUS, "-", Object{}, 1};
Expr left_literal = Literal(123); Expr left{unary_op, Expr{123}};
Expr left = Unary(unary_op, left_literal.to_expr_ptr());
Token op{TokenType::STAR, "*", Object{}, 1}; Token op{TokenType::STAR, "*", Object{}, 1};
Expr right_literal = Literal(45.67); Expr right{Expr{45.67}, nullptr};
Expr right = Grouping(right_literal.to_expr_ptr());
Expr expr = Binary(left.to_expr_ptr(), op, right.to_expr_ptr()); Expr expr{left, op, right};
AstPrinter printer{}; AstPrinter printer{};
std::cout << printer.print(expr) << '\n'; std::cout << printer.print(expr) << '\n';

View File

@ -1,42 +1,90 @@
#include "expr.hh" #include "expr.hh"
#include "../tokenizer.hh" #include "../tokenizer.hh"
#include <cassert> #include <cassert>
#include <memory>
#include <string> #include <string>
#include <utility>
#include <vector> #include <vector>
#include <sstream> #include <sstream>
Expr::Expr(const Expr &other) : type{other.type} {
switch(type) {
case ExprType::BINARY: {
std::shared_ptr<Binary> ptr = std::get<std::shared_ptr<Binary>>(other.value);
value = std::make_shared<Binary>(*ptr);
break;
}
case ExprType::GROUPING: {
std::shared_ptr<Grouping> ptr = std::get<std::shared_ptr<Grouping>>(other.value);
value = std::make_shared<Grouping>(*ptr);
break;
}
case ExprType::LITERAL: {
std::shared_ptr<Literal> ptr = std::get<std::shared_ptr<Literal>>(other.value);
value = std::make_shared<Literal>(*ptr);
break;
}
case ExprType::UNARY: {
std::shared_ptr<Unary> ptr = std::get<std::shared_ptr<Unary>>(other.value);
value = std::make_shared<Unary>(*ptr);
break;
}
}
}
// Move constructor
Expr::Expr(const Expr &&other) : type{other.type}, value{std::move(other.value)} {}
// Binary expressoin
Expr::Expr(Expr left, Token op, Expr right)
: type{ExprType::BINARY}, value{std::make_shared<Binary>(left, op, right)} {}
// Literal expression
Expr::Expr(Object value)
: type{ExprType::LITERAL}, value{std::make_shared<Literal>(value)} {}
// Unary expressoin
Expr::Expr(Token op, Expr right)
: type{ExprType::UNARY}, value{std::make_shared<Unary>(op, right)} {}
// Group expression
// Has to take an extra parameter to avoid conflicting with copy constructor
Expr::Expr(Expr expr, void *ptr)
: type{ExprType::GROUPING}, value{std::make_shared<Grouping>(expr)} { (void)ptr; }
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: {
_Binary node = std::get<_Binary>(expr.value); std::shared_ptr<Binary> binary = std::get<std::shared_ptr<Binary>>(expr.value);
assert(node.left != NULL && node.right != NULL); assert(binary != nullptr);
return parenthesize(node.op.lexeme, {*node.left, *node.right}); return parenthesize(binary->op.lexeme, {binary->left, binary->right});
} }
case ExprType::GROUPING: { case ExprType::GROUPING: {
_Grouping node = std::get<_Grouping>(expr.value); std::shared_ptr<Grouping> group = std::get<std::shared_ptr<Grouping>>(expr.value);
assert(node.expression != NULL); assert(group != nullptr);
return parenthesize("group", {*node.expression}); return parenthesize("group", {group->expr});
} }
case ExprType::LITERAL: { case ExprType::LITERAL: {
_Literal node = std::get<_Literal>(expr.value); std::shared_ptr<Literal> literal = std::get<std::shared_ptr<Literal>>(expr.value);
switch (node.value.type) { assert(literal != nullptr);
switch (literal->value.type) {
case ObjectType::NIL: case ObjectType::NIL:
return "nil"; return "nil";
case ObjectType::IDENTIFIER: case ObjectType::IDENTIFIER:
case ObjectType::STRING_LIT: { case ObjectType::STRING_LIT: {
std::string value = std::get<std::string>(node.value.value); std::string value = std::get<std::string>(literal->value.value);
return value; return value;
} }
case ObjectType::NUMBER: { case ObjectType::NUMBER: {
double value = std::get<double>(node.value.value); double value = std::get<double>(literal->value.value);
return std::to_string(value); return std::to_string(value);
} }
} }
} }
case ExprType::UNARY: { case ExprType::UNARY: {
_Unary node = std::get<_Unary>(expr.value); std::shared_ptr<Unary> unary = std::get<std::shared_ptr<Unary>>(expr.value);
assert(node.right != NULL); assert(unary != nullptr);
return parenthesize(node.op.lexeme, {*node.right}); return parenthesize(unary->op.lexeme, {unary->right});
} }
} }
} }

View File

@ -7,27 +7,10 @@
#include <variant> #include <variant>
struct Expr; struct Expr;
struct Binary;
using ExprPtr = std::shared_ptr<Expr>; struct Grouping;
struct Literal;
struct _Binary { struct Unary;
ExprPtr left;
Token op;
ExprPtr right;
};
struct _Grouping {
ExprPtr expression;
};
struct _Literal {
Object value;
};
struct _Unary {
Token op;
ExprPtr right;
};
enum class ExprType { enum class ExprType {
BINARY, BINARY,
@ -36,30 +19,59 @@ enum class ExprType {
UNARY, UNARY,
}; };
using ExprVariant = std::variant<_Binary, _Grouping, _Literal, _Unary>; using ExprVariant = std::variant<
std::shared_ptr<Binary>,
std::shared_ptr<Grouping>,
std::shared_ptr<Literal>,
std::shared_ptr<Unary>
>;
struct Expr { struct Expr {
// Copy constructor
Expr(const Expr &other);
// Move constructor
Expr(const Expr &&other);
// Binary expressoin
Expr(Expr left, Token op, Expr right);
// Literal expression
Expr(Object value);
// Unary expressoin
Expr(Token op, Expr right);
// Group expression
// Has to take an extra parameter to avoid conflicting with copy constructor
Expr(Expr expr, void *ptr);
ExprType type; ExprType type;
ExprVariant value; ExprVariant value;
ExprPtr to_expr_ptr() { return std::make_shared<Expr>(*this); }
}; };
inline Expr Binary(ExprPtr left, Token op, ExprPtr right) { struct Binary {
return Expr{ExprType::BINARY, _Binary{left, op, right}}; Binary(Expr left, Token op, Expr right) : left{left}, op{op}, right{right} {}
} Expr left;
Token op;
Expr right;
};
inline Expr Grouping(ExprPtr expr) { struct Grouping {
return Expr{ExprType::GROUPING, _Grouping{expr}}; Grouping(Expr expr) : expr{expr} {}
} Expr expr;
};
inline Expr Literal(Object value) { struct Literal {
return Expr{ExprType::LITERAL, _Literal{value}}; Literal(Object value) : value{value} {}
} Object value;
};
inline Expr Unary(Token op, ExprPtr right) { struct Unary {
return Expr{ExprType::UNARY, _Unary{op, right}}; Unary(Token op, Expr right) : op{op}, right{right} {}
} Token op;
Expr right;
};
class AstPrinter { class AstPrinter {
public: public: