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);
Token unary_op{TokenType::MINUS, "-", Object{}, 1};
Expr left_literal = Literal(123);
Expr left = Unary(unary_op, left_literal.to_expr_ptr());
Expr left{unary_op, Expr{123}};
Token op{TokenType::STAR, "*", Object{}, 1};
Expr right_literal = Literal(45.67);
Expr right = Grouping(right_literal.to_expr_ptr());
Expr right{Expr{45.67}, nullptr};
Expr expr = Binary(left.to_expr_ptr(), op, right.to_expr_ptr());
Expr expr{left, op, right};
AstPrinter printer{};
std::cout << printer.print(expr) << '\n';

View File

@ -1,42 +1,90 @@
#include "expr.hh"
#include "../tokenizer.hh"
#include <cassert>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#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) {
switch (expr.type) {
case ExprType::BINARY: {
_Binary node = std::get<_Binary>(expr.value);
assert(node.left != NULL && node.right != NULL);
return parenthesize(node.op.lexeme, {*node.left, *node.right});
std::shared_ptr<Binary> binary = std::get<std::shared_ptr<Binary>>(expr.value);
assert(binary != nullptr);
return parenthesize(binary->op.lexeme, {binary->left, binary->right});
}
case ExprType::GROUPING: {
_Grouping node = std::get<_Grouping>(expr.value);
assert(node.expression != NULL);
return parenthesize("group", {*node.expression});
std::shared_ptr<Grouping> group = std::get<std::shared_ptr<Grouping>>(expr.value);
assert(group != nullptr);
return parenthesize("group", {group->expr});
}
case ExprType::LITERAL: {
_Literal node = std::get<_Literal>(expr.value);
switch (node.value.type) {
std::shared_ptr<Literal> literal = std::get<std::shared_ptr<Literal>>(expr.value);
assert(literal != nullptr);
switch (literal->value.type) {
case ObjectType::NIL:
return "nil";
case ObjectType::IDENTIFIER:
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;
}
case ObjectType::NUMBER: {
double value = std::get<double>(node.value.value);
double value = std::get<double>(literal->value.value);
return std::to_string(value);
}
}
}
case ExprType::UNARY: {
_Unary node = std::get<_Unary>(expr.value);
assert(node.right != NULL);
return parenthesize(node.op.lexeme, {*node.right});
std::shared_ptr<Unary> unary = std::get<std::shared_ptr<Unary>>(expr.value);
assert(unary != nullptr);
return parenthesize(unary->op.lexeme, {unary->right});
}
}
}

View File

@ -7,27 +7,10 @@
#include <variant>
struct Expr;
using ExprPtr = std::shared_ptr<Expr>;
struct _Binary {
ExprPtr left;
Token op;
ExprPtr right;
};
struct _Grouping {
ExprPtr expression;
};
struct _Literal {
Object value;
};
struct _Unary {
Token op;
ExprPtr right;
};
struct Binary;
struct Grouping;
struct Literal;
struct Unary;
enum class ExprType {
BINARY,
@ -36,30 +19,59 @@ enum class ExprType {
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 {
// 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;
ExprVariant value;
ExprPtr to_expr_ptr() { return std::make_shared<Expr>(*this); }
};
inline Expr Binary(ExprPtr left, Token op, ExprPtr right) {
return Expr{ExprType::BINARY, _Binary{left, op, right}};
}
struct Binary {
Binary(Expr left, Token op, Expr right) : left{left}, op{op}, right{right} {}
Expr left;
Token op;
Expr right;
};
inline Expr Grouping(ExprPtr expr) {
return Expr{ExprType::GROUPING, _Grouping{expr}};
}
struct Grouping {
Grouping(Expr expr) : expr{expr} {}
Expr expr;
};
inline Expr Literal(Object value) {
return Expr{ExprType::LITERAL, _Literal{value}};
}
struct Literal {
Literal(Object value) : value{value} {}
Object value;
};
inline Expr Unary(Token op, ExprPtr right) {
return Expr{ExprType::UNARY, _Unary{op, right}};
}
struct Unary {
Unary(Token op, Expr right) : op{op}, right{right} {}
Token op;
Expr right;
};
class AstPrinter {
public: