And that's why I hate C++
This commit is contained in:
		@@ -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';
 | 
			
		||||
 
 | 
			
		||||
@@ -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});
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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:
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user