And that's why I hate C++
This commit is contained in:
parent
339b92dbae
commit
c6f9307253
@ -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:
|
||||
|
Loading…
x
Reference in New Issue
Block a user