2025-06-21 16:51:35 +01:00

102 lines
3.1 KiB
C++

#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: {
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: {
std::shared_ptr<Grouping> group = std::get<std::shared_ptr<Grouping>>(expr.value);
assert(group != nullptr);
return parenthesize("group", {group->expr});
}
case ExprType::LITERAL: {
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>(literal->value.value);
return value;
}
case ObjectType::NUMBER: {
double value = std::get<double>(literal->value.value);
return std::to_string(value);
}
}
}
case ExprType::UNARY: {
std::shared_ptr<Unary> unary = std::get<std::shared_ptr<Unary>>(expr.value);
assert(unary != nullptr);
return parenthesize(unary->op.lexeme, {unary->right});
}
}
}
std::string AstPrinter::parenthesize(const std::string &name, std::vector<Expr> exprs) {
std::stringstream ss{};
ss << '(' << name;
for (auto &expr : exprs) {
ss << ' ' << print(expr);
}
ss << ')';
return ss.str();
}