Start adding statements
This commit is contained in:
		@@ -2,10 +2,10 @@
 | 
			
		||||
#include "error_handler.hh"
 | 
			
		||||
#include "tokenizer.hh"
 | 
			
		||||
#include "parser.hh"
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <fstream>
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <optional>
 | 
			
		||||
#include <sysexits.h>
 | 
			
		||||
 | 
			
		||||
#define PROMPT "> "
 | 
			
		||||
@@ -57,15 +57,12 @@ void run(const std::string &code) {
 | 
			
		||||
  std::vector<Token> tokens = scanner.scan_tokens();
 | 
			
		||||
 | 
			
		||||
  Parser parser{tokens};
 | 
			
		||||
  std::optional<Expr> expression = parser.parse();
 | 
			
		||||
 | 
			
		||||
  static AstInterpreter interpreter{};
 | 
			
		||||
  std::vector<Stmt> statements = parser.parse();
 | 
			
		||||
 | 
			
		||||
  if (error_handler.had_error) {
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (expression) {
 | 
			
		||||
    interpreter.interpret(*expression);
 | 
			
		||||
  }
 | 
			
		||||
  static AstInterpreter interpreter{};
 | 
			
		||||
  interpreter.interpret(statements);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,10 @@
 | 
			
		||||
#ifndef PARSER_CC
 | 
			
		||||
#define PARSER_CC
 | 
			
		||||
#ifndef MAIN_PARSER_CC
 | 
			
		||||
#define MAIN_PARSER_CC
 | 
			
		||||
 | 
			
		||||
#include "parser/expr.cc"
 | 
			
		||||
#include "parser/stmt.cc"
 | 
			
		||||
#include "parser/parser.cc"
 | 
			
		||||
#include "parser/environment.cc"
 | 
			
		||||
#include "parser/ast_printer.cc"
 | 
			
		||||
#include "parser/ast_interpreter.cc"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,9 @@
 | 
			
		||||
#define MAIN_PARSER_HH
 | 
			
		||||
 | 
			
		||||
#include "parser/expr.hh"
 | 
			
		||||
#include "parser/stmt.hh"
 | 
			
		||||
#include "parser/parser.hh"
 | 
			
		||||
#include "parser/environment.hh"
 | 
			
		||||
#include "parser/ast_printer.hh"
 | 
			
		||||
#include "parser/ast_interpreter.hh"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,33 +1,73 @@
 | 
			
		||||
#include "ast_interpreter.hh"
 | 
			
		||||
#include "expr.hh"
 | 
			
		||||
#include "stmt.hh"
 | 
			
		||||
#include "../error_handler.hh"
 | 
			
		||||
#include "../tokenizer.hh"
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <cassert>
 | 
			
		||||
#include <iostream>
 | 
			
		||||
 | 
			
		||||
extern ErrorHandler error_handler;
 | 
			
		||||
 | 
			
		||||
void AstInterpreter::interpret(const Expr &expression) {
 | 
			
		||||
void AstInterpreter::interpret(const std::vector<Stmt> &statements) {
 | 
			
		||||
  try {
 | 
			
		||||
    Object value = evaluate(expression);
 | 
			
		||||
    std::cout << value.to_string() << '\n';
 | 
			
		||||
    for (const Stmt & stmt : statements) {
 | 
			
		||||
      execute(stmt);
 | 
			
		||||
    }
 | 
			
		||||
  } catch (RuntimeException e) {
 | 
			
		||||
    error_handler.runtime_error(e);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AstInterpreter::execute(const Stmt &stmt) {
 | 
			
		||||
  switch (stmt.type) {
 | 
			
		||||
    case StmtType::EXPRESSION: return execute_expression_statement(stmt);
 | 
			
		||||
    case StmtType::PRINT:      return execute_print_statement(stmt);
 | 
			
		||||
    case StmtType::VAR:        return execute_var_statement(stmt);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AstInterpreter::execute_expression_statement(const Stmt &stmt) {
 | 
			
		||||
  std::shared_ptr<_Expression> ptr = std::get<std::shared_ptr<_Expression>>(stmt.value);
 | 
			
		||||
  assert(ptr != nullptr);
 | 
			
		||||
  evaluate(ptr->expr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AstInterpreter::execute_print_statement(const Stmt &stmt) {
 | 
			
		||||
  std::shared_ptr<_Print> ptr = std::get<std::shared_ptr<_Print>>(stmt.value);
 | 
			
		||||
  assert(ptr != nullptr);
 | 
			
		||||
  Object value{evaluate(ptr->expr)};
 | 
			
		||||
  std::cout << value << '\n';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AstInterpreter::execute_var_statement(const Stmt &stmt) {
 | 
			
		||||
  Object value{};
 | 
			
		||||
  std::shared_ptr<_Var> ptr = std::get<std::shared_ptr<_Var>>(stmt.value);
 | 
			
		||||
  assert(ptr != nullptr);
 | 
			
		||||
 | 
			
		||||
  if (ptr->expr.type == ExprType::LITERAL) {
 | 
			
		||||
    std::shared_ptr<_Literal> eptr = std::get<std::shared_ptr<_Literal>>(ptr->expr.value);
 | 
			
		||||
    assert(eptr != nullptr);
 | 
			
		||||
    if (eptr->value.type == ObjectType::NIL) {
 | 
			
		||||
      environment.define(ptr->name.lexeme, value);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  value = evaluate(ptr->expr);
 | 
			
		||||
  environment.define(ptr->name.lexeme, value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Object AstInterpreter::evaluate(const Expr &expr) {
 | 
			
		||||
  switch (expr.type) {
 | 
			
		||||
    case ExprType::BINARY:
 | 
			
		||||
      return evaluate_binary_expression(expr);
 | 
			
		||||
    case ExprType::GROUPING:
 | 
			
		||||
      return evaluate_grouping_expression(expr);
 | 
			
		||||
    case ExprType::LITERAL:
 | 
			
		||||
      return evaluate_literal_expression(expr);
 | 
			
		||||
    case ExprType::UNARY:
 | 
			
		||||
      return evaluate_unary_expression(expr);
 | 
			
		||||
    case ExprType::BINARY:   return evaluate_binary_expression(expr);
 | 
			
		||||
    case ExprType::GROUPING: return evaluate_grouping_expression(expr);
 | 
			
		||||
    case ExprType::LITERAL:  return evaluate_literal_expression(expr);
 | 
			
		||||
    case ExprType::UNARY:    return evaluate_unary_expression(expr);
 | 
			
		||||
    case ExprType::VARIABLE: return evaluate_variable_expression(expr);
 | 
			
		||||
    case ExprType::ASSIGN:   return evaluate_assignment_expression(expr);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -156,6 +196,20 @@ Object AstInterpreter::evaluate_unary_expression(const Expr &expr) {
 | 
			
		||||
  return Object{};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Object AstInterpreter::evaluate_variable_expression(const Expr &expr) {
 | 
			
		||||
  std::shared_ptr<_Variable> ptr = std::get<std::shared_ptr<_Variable>>(expr.value);
 | 
			
		||||
  assert(ptr != nullptr);
 | 
			
		||||
  return environment.get(ptr->name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Object AstInterpreter::evaluate_assignment_expression(const Expr &expr) {
 | 
			
		||||
  std::shared_ptr<_Assign> ptr = std::get<std::shared_ptr<_Assign>>(expr.value);
 | 
			
		||||
  assert(ptr != nullptr);
 | 
			
		||||
  Object value = evaluate(ptr->value);
 | 
			
		||||
  environment.assign(ptr->name, value);
 | 
			
		||||
  return value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool AstInterpreter::is_truthy(const Object &object) {
 | 
			
		||||
  switch (object.type) {
 | 
			
		||||
    case ObjectType::NIL: return false;
 | 
			
		||||
 
 | 
			
		||||
@@ -2,20 +2,31 @@
 | 
			
		||||
#define AST_INTERPRETER_HH
 | 
			
		||||
 | 
			
		||||
#include "expr.hh"
 | 
			
		||||
#include "stmt.hh"
 | 
			
		||||
#include "environment.hh"
 | 
			
		||||
#include "../tokenizer.hh"
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
struct AstInterpreter {
 | 
			
		||||
  void interpret(const Expr &expression);
 | 
			
		||||
  void interpret(const std::vector<Stmt> &statements);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
  void execute(const Stmt &stmt);
 | 
			
		||||
  void execute_expression_statement(const Stmt &stmt);
 | 
			
		||||
  void execute_print_statement(const Stmt &stmt);
 | 
			
		||||
  void execute_var_statement(const Stmt &stmt);
 | 
			
		||||
 | 
			
		||||
  Object evaluate(const Expr &expr);
 | 
			
		||||
  Object evaluate_binary_expression(const Expr &expr);
 | 
			
		||||
  Object evaluate_grouping_expression(const Expr &expr);
 | 
			
		||||
  Object evaluate_literal_expression(const Expr &expr);
 | 
			
		||||
  Object evaluate_unary_expression(const Expr &expr);
 | 
			
		||||
  Object evaluate_variable_expression(const Expr &expr);
 | 
			
		||||
  Object evaluate_assignment_expression(const Expr &expr);
 | 
			
		||||
  bool is_truthy(const Object &object);
 | 
			
		||||
  bool is_equal(const Object &left, const Object &right);
 | 
			
		||||
 | 
			
		||||
  Environment environment{};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
@@ -7,24 +7,34 @@
 | 
			
		||||
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});
 | 
			
		||||
      std::shared_ptr<_Binary> ptr = std::get<std::shared_ptr<_Binary>>(expr.value);
 | 
			
		||||
      assert(ptr != nullptr);
 | 
			
		||||
      return parenthesize(ptr->op.lexeme, {&ptr->left, &ptr->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});
 | 
			
		||||
      std::shared_ptr<_Grouping> ptr = std::get<std::shared_ptr<_Grouping>>(expr.value);
 | 
			
		||||
      assert(ptr != nullptr);
 | 
			
		||||
      return parenthesize("group", {&ptr->expr});
 | 
			
		||||
    }
 | 
			
		||||
    case ExprType::LITERAL: {
 | 
			
		||||
      std::shared_ptr<_Literal> literal = std::get<std::shared_ptr<_Literal>>(expr.value);
 | 
			
		||||
      assert(literal != nullptr);
 | 
			
		||||
      return literal->value.to_string();
 | 
			
		||||
      std::shared_ptr<_Literal> ptr = std::get<std::shared_ptr<_Literal>>(expr.value);
 | 
			
		||||
      assert(ptr != nullptr);
 | 
			
		||||
      return ptr->value.to_string();
 | 
			
		||||
    }
 | 
			
		||||
    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::shared_ptr<_Unary> ptr = std::get<std::shared_ptr<_Unary>>(expr.value);
 | 
			
		||||
      assert(ptr != nullptr);
 | 
			
		||||
      return parenthesize(ptr->op.lexeme, {&ptr->right});
 | 
			
		||||
    }
 | 
			
		||||
    case ExprType::VARIABLE: {
 | 
			
		||||
      std::shared_ptr<_Variable> ptr = std::get<std::shared_ptr<_Variable>>(expr.value);
 | 
			
		||||
      assert(ptr != nullptr);
 | 
			
		||||
      return ptr->name.lexeme;
 | 
			
		||||
    }
 | 
			
		||||
    case ExprType::ASSIGN: {
 | 
			
		||||
      std::shared_ptr<_Assign> ptr = std::get<std::shared_ptr<_Assign>>(expr.value);
 | 
			
		||||
      assert(ptr != nullptr);
 | 
			
		||||
      return ptr->name.lexeme;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										64
									
								
								cclox_src/parser/environment.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								cclox_src/parser/environment.cc
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,64 @@
 | 
			
		||||
#include "environment.hh"
 | 
			
		||||
#include "../error_handler.hh"
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <utility>
 | 
			
		||||
 | 
			
		||||
Environment::Environment(const Environment &other) : enclosing{other.enclosing}, values{other.values} {}
 | 
			
		||||
 | 
			
		||||
Environment::Environment(Environment &&other) noexcept : enclosing{std::move(other.enclosing)}, values{std::move(other.values)} {
 | 
			
		||||
  other.enclosing.reset();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Environment &Environment::operator=(const Environment &other) {
 | 
			
		||||
  if (this == &other) {
 | 
			
		||||
    return *this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (enclosing) {
 | 
			
		||||
    enclosing.reset();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  enclosing = other.enclosing;
 | 
			
		||||
  values    = other.values;
 | 
			
		||||
 | 
			
		||||
  return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Environment &Environment::operator=(Environment &&other) noexcept {
 | 
			
		||||
  if (this == &other) {
 | 
			
		||||
    return *this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (enclosing) {
 | 
			
		||||
    enclosing.reset();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  enclosing = std::move(other.enclosing);
 | 
			
		||||
  values    = std::move(other.values);
 | 
			
		||||
 | 
			
		||||
  other.enclosing.reset();
 | 
			
		||||
 | 
			
		||||
  return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Environment::define(const std::string &name, const Object &value) {
 | 
			
		||||
  values.insert(std::pair(name, value));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Environment::assign(const Token &name, const Object &value) {
 | 
			
		||||
  if (values.find(name.lexeme) != values.end()) {
 | 
			
		||||
    values.at(name.lexeme) = value;
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  throw RuntimeException(name, "Undefined variable '" + name.lexeme + "'.");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Object Environment::get(const Token &name) {
 | 
			
		||||
  if (values.find(name.lexeme) != values.end()) {
 | 
			
		||||
    return values.at(name.lexeme);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  throw RuntimeException(name, "Undefined variable '" + name.lexeme + "'.");
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										28
									
								
								cclox_src/parser/environment.hh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								cclox_src/parser/environment.hh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
			
		||||
#ifndef ENVIRONMENT_HH
 | 
			
		||||
#define ENVIRONMENT_HH
 | 
			
		||||
 | 
			
		||||
#include "../tokenizer.hh"
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
 | 
			
		||||
struct Environment {
 | 
			
		||||
  Environment() : enclosing{nullptr}, values{} {}
 | 
			
		||||
  Environment(std::shared_ptr<Environment> enclosing) : enclosing{enclosing}, values{} {}
 | 
			
		||||
  Environment(const Environment &other);
 | 
			
		||||
  Environment(Environment &&other) noexcept;
 | 
			
		||||
 | 
			
		||||
  Environment &operator=(const Environment &other);
 | 
			
		||||
  Environment &operator=(Environment &&other) noexcept;
 | 
			
		||||
 | 
			
		||||
  ~Environment() = default;
 | 
			
		||||
 | 
			
		||||
  void define(const std::string &name, const Object &value);
 | 
			
		||||
  void assign(const Token &name, const Object &value);
 | 
			
		||||
  Object get(const Token &name);
 | 
			
		||||
private:
 | 
			
		||||
  std::shared_ptr<Environment> enclosing;
 | 
			
		||||
  std::unordered_map<std::string, Object> values;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@@ -33,11 +33,23 @@ Expr::Expr(const Expr &other) : type{other.type} {
 | 
			
		||||
      value = std::make_shared<_Unary>(*ptr);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case ExprType::VARIABLE: {
 | 
			
		||||
      std::shared_ptr<_Variable> ptr = std::get<std::shared_ptr<_Variable>>(other.value);
 | 
			
		||||
      assert(ptr != nullptr);
 | 
			
		||||
      value = std::make_shared<_Variable>(*ptr);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case ExprType::ASSIGN: {
 | 
			
		||||
      std::shared_ptr<_Assign> ptr = std::get<std::shared_ptr<_Assign>>(other.value);
 | 
			
		||||
      assert(ptr != nullptr);
 | 
			
		||||
      value = std::make_shared<_Assign>(*ptr);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Move constructor
 | 
			
		||||
Expr::Expr(const Expr &&other) : type{other.type}, value{std::move(other.value)} {
 | 
			
		||||
Expr::Expr(Expr &&other) : type{other.type}, value{std::move(other.value)} {
 | 
			
		||||
  switch(type) {
 | 
			
		||||
    case ExprType::BINARY: {
 | 
			
		||||
      std::shared_ptr<_Binary> ptr = std::get<std::shared_ptr<_Binary>>(other.value);
 | 
			
		||||
@@ -63,6 +75,18 @@ Expr::Expr(const Expr &&other) : type{other.type}, value{std::move(other.value)}
 | 
			
		||||
      ptr.reset();
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case ExprType::VARIABLE: {
 | 
			
		||||
      std::shared_ptr<_Variable> ptr = std::get<std::shared_ptr<_Variable>>(other.value);
 | 
			
		||||
      assert(ptr != nullptr);
 | 
			
		||||
      ptr.reset();
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case ExprType::ASSIGN: {
 | 
			
		||||
      std::shared_ptr<_Assign> ptr = std::get<std::shared_ptr<_Assign>>(other.value);
 | 
			
		||||
      assert(ptr != nullptr);
 | 
			
		||||
      ptr.reset();
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -97,6 +121,18 @@ Expr &Expr::operator=(const Expr &other) {
 | 
			
		||||
      ptr.reset();
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case ExprType::VARIABLE: {
 | 
			
		||||
      std::shared_ptr<_Variable> ptr = std::get<std::shared_ptr<_Variable>>(value);
 | 
			
		||||
      assert(ptr != nullptr);
 | 
			
		||||
      ptr.reset();
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case ExprType::ASSIGN: {
 | 
			
		||||
      std::shared_ptr<_Assign> ptr = std::get<std::shared_ptr<_Assign>>(value);
 | 
			
		||||
      assert(ptr != nullptr);
 | 
			
		||||
      ptr.reset();
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  type = other.type;
 | 
			
		||||
@@ -126,13 +162,25 @@ Expr &Expr::operator=(const Expr &other) {
 | 
			
		||||
      value = std::make_shared<_Unary>(*ptr);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case ExprType::VARIABLE: {
 | 
			
		||||
      std::shared_ptr<_Variable> ptr = std::get<std::shared_ptr<_Variable>>(other.value);
 | 
			
		||||
      assert(ptr != nullptr);
 | 
			
		||||
      value = std::make_shared<_Variable>(*ptr);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case ExprType::ASSIGN: {
 | 
			
		||||
      std::shared_ptr<_Assign> ptr = std::get<std::shared_ptr<_Assign>>(other.value);
 | 
			
		||||
      assert(ptr != nullptr);
 | 
			
		||||
      value = std::make_shared<_Assign>(*ptr);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Move assignment
 | 
			
		||||
Expr &Expr::operator=(const Expr &&other) {
 | 
			
		||||
Expr &Expr::operator=(Expr &&other) {
 | 
			
		||||
  if (this == &other) {
 | 
			
		||||
    return *this;
 | 
			
		||||
  }
 | 
			
		||||
@@ -162,6 +210,18 @@ Expr &Expr::operator=(const Expr &&other) {
 | 
			
		||||
      ptr.reset();
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case ExprType::VARIABLE: {
 | 
			
		||||
      std::shared_ptr<_Variable> ptr = std::get<std::shared_ptr<_Variable>>(value);
 | 
			
		||||
      assert(ptr != nullptr);
 | 
			
		||||
      ptr.reset();
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case ExprType::ASSIGN: {
 | 
			
		||||
      std::shared_ptr<_Assign> ptr = std::get<std::shared_ptr<_Assign>>(value);
 | 
			
		||||
      assert(ptr != nullptr);
 | 
			
		||||
      ptr.reset();
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  type = other.type;
 | 
			
		||||
@@ -195,6 +255,20 @@ Expr &Expr::operator=(const Expr &&other) {
 | 
			
		||||
      ptr.reset();
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case ExprType::VARIABLE: {
 | 
			
		||||
      std::shared_ptr<_Variable> ptr = std::get<std::shared_ptr<_Variable>>(other.value);
 | 
			
		||||
      assert(ptr != nullptr);
 | 
			
		||||
      value = std::move(other.value);
 | 
			
		||||
      ptr.reset();
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case ExprType::ASSIGN: {
 | 
			
		||||
      std::shared_ptr<_Assign> ptr = std::get<std::shared_ptr<_Assign>>(other.value);
 | 
			
		||||
      assert(ptr != nullptr);
 | 
			
		||||
      value = std::move(other.value);
 | 
			
		||||
      ptr.reset();
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return *this;
 | 
			
		||||
 
 | 
			
		||||
@@ -10,25 +10,33 @@ struct _Binary;
 | 
			
		||||
struct _Grouping;
 | 
			
		||||
struct _Literal;
 | 
			
		||||
struct _Unary;
 | 
			
		||||
struct _Variable;
 | 
			
		||||
struct _Assign;
 | 
			
		||||
 | 
			
		||||
enum class ExprType {
 | 
			
		||||
  BINARY,
 | 
			
		||||
  GROUPING,
 | 
			
		||||
  LITERAL,
 | 
			
		||||
  UNARY,
 | 
			
		||||
  VARIABLE,
 | 
			
		||||
  ASSIGN,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
using ExprVariant = std::variant<
 | 
			
		||||
  std::shared_ptr<_Binary>,
 | 
			
		||||
  std::shared_ptr<_Grouping>,
 | 
			
		||||
  std::shared_ptr<_Literal>,
 | 
			
		||||
  std::shared_ptr<_Unary>
 | 
			
		||||
  std::shared_ptr<_Unary>,
 | 
			
		||||
  std::shared_ptr<_Variable>,
 | 
			
		||||
  std::shared_ptr<_Assign>
 | 
			
		||||
>;
 | 
			
		||||
 | 
			
		||||
#define Binary(LEFT, OP, RIGHT) (Expr{ExprType::BINARY, std::make_shared<_Binary>(LEFT, OP, RIGHT)})
 | 
			
		||||
#define Grouping(EXPR) (Expr{ExprType::GROUPING, std::make_shared<_Grouping>(EXPR)})
 | 
			
		||||
#define Literal(VALUE) (Expr{ExprType::LITERAL, std::make_shared<_Literal>(VALUE)})
 | 
			
		||||
#define Unary(OP, RIGHT) (Expr{ExprType::UNARY, std::make_shared<_Unary>(OP, RIGHT)})
 | 
			
		||||
#define Variable(NAME) (Expr{ExprType::VARIABLE, std::make_shared<_Variable>(NAME)})
 | 
			
		||||
#define Assign(NAME, VALUE) (Expr{ExprType::ASSIGN, std::make_shared<_Assign>(NAME, VALUE)})
 | 
			
		||||
 | 
			
		||||
struct Expr {
 | 
			
		||||
  Expr(ExprType type, ExprVariant value);
 | 
			
		||||
@@ -37,13 +45,13 @@ struct Expr {
 | 
			
		||||
  Expr(const Expr &other);
 | 
			
		||||
 | 
			
		||||
  // Move constructor
 | 
			
		||||
  Expr(const Expr &&other);
 | 
			
		||||
  Expr(Expr &&other);
 | 
			
		||||
 | 
			
		||||
  // Copy assignment
 | 
			
		||||
  Expr &operator=(const Expr &other);
 | 
			
		||||
 | 
			
		||||
  // Move assignment
 | 
			
		||||
  Expr &operator=(const Expr &&other);
 | 
			
		||||
  Expr &operator=(Expr &&other);
 | 
			
		||||
 | 
			
		||||
  ExprType type;
 | 
			
		||||
  ExprVariant value;
 | 
			
		||||
@@ -72,4 +80,15 @@ struct _Unary {
 | 
			
		||||
  Expr right;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct _Variable {
 | 
			
		||||
  _Variable(Token name) : name{name} {}
 | 
			
		||||
  Token name;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct _Assign {
 | 
			
		||||
  _Assign(Token name, const Expr &value) : name{name}, value{value} {}
 | 
			
		||||
  Token name;
 | 
			
		||||
  Expr value;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
@@ -1,21 +1,88 @@
 | 
			
		||||
#include "parser.hh"
 | 
			
		||||
#include "expr.hh"
 | 
			
		||||
#include "stmt.hh"
 | 
			
		||||
#include "../error_handler.hh"
 | 
			
		||||
#include "../tokenizer.hh"
 | 
			
		||||
#include <optional>
 | 
			
		||||
#include <cassert>
 | 
			
		||||
 | 
			
		||||
extern ErrorHandler error_handler;
 | 
			
		||||
 | 
			
		||||
std::optional<Expr> Parser::parse() {
 | 
			
		||||
std::vector<Stmt> Parser::parse() {
 | 
			
		||||
  std::vector<Stmt> statements{};
 | 
			
		||||
  while (!is_at_end()) {
 | 
			
		||||
    statements.push_back(declaration());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return statements;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Stmt Parser::declaration() {
 | 
			
		||||
  try {
 | 
			
		||||
    return expression();
 | 
			
		||||
    if (match({TokenType::VAR})) {
 | 
			
		||||
      return var_declaration();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return statement();
 | 
			
		||||
  } catch (ParseException e) {
 | 
			
		||||
    return std::nullopt;
 | 
			
		||||
    synchronize();
 | 
			
		||||
    return Expression(Literal(Object{}));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Stmt Parser::var_declaration() {
 | 
			
		||||
  Token name       = consume(TokenType::IDENTIFIER, "Expect variable name.");
 | 
			
		||||
  Expr initializer = Literal(Object{});
 | 
			
		||||
 | 
			
		||||
  if (match({TokenType::EQUAL})) {
 | 
			
		||||
    initializer = expression();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  consume(TokenType::SEMICOLON, "Expect ';' after variable declaration");
 | 
			
		||||
  return Var(name, initializer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Stmt Parser::statement() {
 | 
			
		||||
  if (match({TokenType::PRINT})) {
 | 
			
		||||
    return print_statement();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return expression_statement();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Stmt Parser::print_statement() {
 | 
			
		||||
  Expr value{expression()};
 | 
			
		||||
  consume(TokenType::SEMICOLON, "Expect ';' after value.");
 | 
			
		||||
  return Print(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Stmt Parser::expression_statement() {
 | 
			
		||||
  Expr value{expression()};
 | 
			
		||||
  consume(TokenType::SEMICOLON, "Expect ';' after value.");
 | 
			
		||||
  return Expression(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Expr Parser::expression() {
 | 
			
		||||
  return equality();
 | 
			
		||||
  return assignment();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Expr Parser::assignment() {
 | 
			
		||||
  Expr expr = equality();
 | 
			
		||||
 | 
			
		||||
  if (match({TokenType::EQUAL})) {
 | 
			
		||||
    Token equals = previous();
 | 
			
		||||
    Expr value   = assignment();
 | 
			
		||||
 | 
			
		||||
    if (expr.type == ExprType::VARIABLE) {
 | 
			
		||||
      std::shared_ptr<_Variable> ptr = std::get<std::shared_ptr<_Variable>>(expr.value);
 | 
			
		||||
      assert(ptr != nullptr);
 | 
			
		||||
      Token name = ptr->name;
 | 
			
		||||
      return Assign(name, value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    error_handler.error(equals, "Invalid assignment target.");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return expr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Expr Parser::equality() {
 | 
			
		||||
@@ -94,6 +161,10 @@ Expr Parser::primary() {
 | 
			
		||||
    return Literal(previous().literal);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (match({TokenType::IDENTIFIER})) {
 | 
			
		||||
    return Variable(previous());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (match({TokenType::LEFT_PAREN})) {
 | 
			
		||||
    Expr expr = expression();
 | 
			
		||||
    consume(TokenType::RIGHT_PAREN, "Expect ')' after expression.");
 | 
			
		||||
 
 | 
			
		||||
@@ -2,10 +2,10 @@
 | 
			
		||||
#define PARSER_HH
 | 
			
		||||
 | 
			
		||||
#include "expr.hh"
 | 
			
		||||
#include "stmt.hh"
 | 
			
		||||
#include "../tokenizer.hh"
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <exception>
 | 
			
		||||
#include <optional>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
struct ParseException : public std::exception {
 | 
			
		||||
@@ -21,8 +21,14 @@ private:
 | 
			
		||||
 | 
			
		||||
struct Parser {
 | 
			
		||||
  Parser(std::vector<Token> tokens) : tokens{tokens} {}
 | 
			
		||||
  std::optional<Expr> parse();
 | 
			
		||||
  std::vector<Stmt> parse();
 | 
			
		||||
  Stmt declaration();
 | 
			
		||||
  Stmt var_declaration();
 | 
			
		||||
  Stmt statement();
 | 
			
		||||
  Stmt print_statement();
 | 
			
		||||
  Stmt expression_statement();
 | 
			
		||||
  Expr expression();
 | 
			
		||||
  Expr assignment();
 | 
			
		||||
  Expr equality();
 | 
			
		||||
  Expr comparison();
 | 
			
		||||
  Expr term();
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										162
									
								
								cclox_src/parser/stmt.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										162
									
								
								cclox_src/parser/stmt.cc
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,162 @@
 | 
			
		||||
#include "stmt.hh"
 | 
			
		||||
#include <cassert>
 | 
			
		||||
#include <utility>
 | 
			
		||||
 | 
			
		||||
Stmt::Stmt(StmtType type, StmtVariant value) : type{type}, value{value} {}
 | 
			
		||||
 | 
			
		||||
// Copy constructor
 | 
			
		||||
Stmt::Stmt(const Stmt &other) : type{other.type} {
 | 
			
		||||
  switch(type) {
 | 
			
		||||
    case StmtType::EXPRESSION: {
 | 
			
		||||
      std::shared_ptr<_Expression> ptr = std::get<std::shared_ptr<_Expression>>(other.value);
 | 
			
		||||
      assert(ptr != nullptr);
 | 
			
		||||
      value = std::make_shared<_Expression>(*ptr);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case StmtType::PRINT: {
 | 
			
		||||
      std::shared_ptr<_Print> ptr = std::get<std::shared_ptr<_Print>>(other.value);
 | 
			
		||||
      assert(ptr != nullptr);
 | 
			
		||||
      value = std::make_shared<_Print>(*ptr);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case StmtType::VAR: {
 | 
			
		||||
      std::shared_ptr<_Var> ptr = std::get<std::shared_ptr<_Var>>(other.value);
 | 
			
		||||
      assert(ptr != nullptr);
 | 
			
		||||
      value = std::make_shared<_Var>(*ptr);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Move constructor
 | 
			
		||||
Stmt::Stmt(const Stmt &&other) : type{other.type}, value{std::move(other.value)} {
 | 
			
		||||
  switch(type) {
 | 
			
		||||
    case StmtType::EXPRESSION: {
 | 
			
		||||
      std::shared_ptr<_Expression> ptr = std::get<std::shared_ptr<_Expression>>(other.value);
 | 
			
		||||
      assert(ptr != nullptr);
 | 
			
		||||
      ptr.reset();
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case StmtType::PRINT: {
 | 
			
		||||
      std::shared_ptr<_Print> ptr = std::get<std::shared_ptr<_Print>>(other.value);
 | 
			
		||||
      assert(ptr != nullptr);
 | 
			
		||||
      ptr.reset();
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case StmtType::VAR: {
 | 
			
		||||
      std::shared_ptr<_Var> ptr = std::get<std::shared_ptr<_Var>>(other.value);
 | 
			
		||||
      assert(ptr != nullptr);
 | 
			
		||||
      ptr.reset();
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Copy assignment
 | 
			
		||||
Stmt &Stmt::operator=(const Stmt &other) {
 | 
			
		||||
  if (this == &other) {
 | 
			
		||||
    return *this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  switch(type) {
 | 
			
		||||
    case StmtType::EXPRESSION: {
 | 
			
		||||
      std::shared_ptr<_Expression> ptr = std::get<std::shared_ptr<_Expression>>(value);
 | 
			
		||||
      assert(ptr != nullptr);
 | 
			
		||||
      ptr.reset();
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case StmtType::PRINT: {
 | 
			
		||||
      std::shared_ptr<_Print> ptr = std::get<std::shared_ptr<_Print>>(value);
 | 
			
		||||
      assert(ptr != nullptr);
 | 
			
		||||
      ptr.reset();
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case StmtType::VAR: {
 | 
			
		||||
      std::shared_ptr<_Var> ptr = std::get<std::shared_ptr<_Var>>(value);
 | 
			
		||||
      assert(ptr != nullptr);
 | 
			
		||||
      ptr.reset();
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  type = other.type;
 | 
			
		||||
 | 
			
		||||
  switch(type) {
 | 
			
		||||
    case StmtType::EXPRESSION: {
 | 
			
		||||
      std::shared_ptr<_Expression> ptr = std::get<std::shared_ptr<_Expression>>(other.value);
 | 
			
		||||
      assert(ptr != nullptr);
 | 
			
		||||
      value = std::make_shared<_Expression>(*ptr);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case StmtType::PRINT: {
 | 
			
		||||
      std::shared_ptr<_Print> ptr = std::get<std::shared_ptr<_Print>>(other.value);
 | 
			
		||||
      assert(ptr != nullptr);
 | 
			
		||||
      value = std::make_shared<_Print>(*ptr);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case StmtType::VAR: {
 | 
			
		||||
      std::shared_ptr<_Var> ptr = std::get<std::shared_ptr<_Var>>(other.value);
 | 
			
		||||
      assert(ptr != nullptr);
 | 
			
		||||
      value = std::make_shared<_Var>(*ptr);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Move assignment
 | 
			
		||||
Stmt &Stmt::operator=(const Stmt &&other) {
 | 
			
		||||
  if (this == &other) {
 | 
			
		||||
    return *this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  switch(type) {
 | 
			
		||||
    case StmtType::EXPRESSION: {
 | 
			
		||||
      std::shared_ptr<_Expression> ptr = std::get<std::shared_ptr<_Expression>>(value);
 | 
			
		||||
      assert(ptr != nullptr);
 | 
			
		||||
      ptr.reset();
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case StmtType::PRINT: {
 | 
			
		||||
      std::shared_ptr<_Print> ptr = std::get<std::shared_ptr<_Print>>(value);
 | 
			
		||||
      assert(ptr != nullptr);
 | 
			
		||||
      ptr.reset();
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case StmtType::VAR: {
 | 
			
		||||
      std::shared_ptr<_Var> ptr = std::get<std::shared_ptr<_Var>>(value);
 | 
			
		||||
      assert(ptr != nullptr);
 | 
			
		||||
      ptr.reset();
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  type = other.type;
 | 
			
		||||
 | 
			
		||||
  switch(type) {
 | 
			
		||||
    case StmtType::EXPRESSION: {
 | 
			
		||||
      std::shared_ptr<_Expression> ptr = std::get<std::shared_ptr<_Expression>>(other.value);
 | 
			
		||||
      assert(ptr != nullptr);
 | 
			
		||||
      value = std::move(other.value);
 | 
			
		||||
      ptr.reset();
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case StmtType::PRINT: {
 | 
			
		||||
      std::shared_ptr<_Print> ptr = std::get<std::shared_ptr<_Print>>(other.value);
 | 
			
		||||
      assert(ptr != nullptr);
 | 
			
		||||
      value = std::move(other.value);
 | 
			
		||||
      ptr.reset();
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case StmtType::VAR: {
 | 
			
		||||
      std::shared_ptr<_Var> ptr = std::get<std::shared_ptr<_Var>>(other.value);
 | 
			
		||||
      assert(ptr != nullptr);
 | 
			
		||||
      value = std::move(other.value);
 | 
			
		||||
      ptr.reset();
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return *this;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										64
									
								
								cclox_src/parser/stmt.hh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								cclox_src/parser/stmt.hh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,64 @@
 | 
			
		||||
#ifndef STMT_HH
 | 
			
		||||
#define STMT_HH
 | 
			
		||||
 | 
			
		||||
#include "expr.hh"
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <variant>
 | 
			
		||||
 | 
			
		||||
struct Stmt;
 | 
			
		||||
struct _Expression;
 | 
			
		||||
struct _Print;
 | 
			
		||||
struct _Var;
 | 
			
		||||
 | 
			
		||||
enum class StmtType {
 | 
			
		||||
  EXPRESSION,
 | 
			
		||||
  PRINT,
 | 
			
		||||
  VAR,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
using StmtVariant = std::variant<
 | 
			
		||||
  std::shared_ptr<_Expression>,
 | 
			
		||||
  std::shared_ptr<_Print>,
 | 
			
		||||
  std::shared_ptr<_Var>
 | 
			
		||||
>;
 | 
			
		||||
 | 
			
		||||
#define Expression(EXPR) (Stmt{StmtType::EXPRESSION, std::make_shared<_Expression>(EXPR)})
 | 
			
		||||
#define Print(EXPR) (Stmt{StmtType::PRINT, std::make_shared<_Print>(EXPR)})
 | 
			
		||||
#define Var(NAME, EXPR) (Stmt{StmtType::VAR, std::make_shared<_Var>(NAME, EXPR)})
 | 
			
		||||
 | 
			
		||||
struct Stmt {
 | 
			
		||||
  Stmt(StmtType type, StmtVariant value);
 | 
			
		||||
 | 
			
		||||
  // Copy constructor
 | 
			
		||||
  Stmt(const Stmt &other);
 | 
			
		||||
 | 
			
		||||
  // Move constructor
 | 
			
		||||
  Stmt(const Stmt &&other);
 | 
			
		||||
 | 
			
		||||
  // Copy assignment
 | 
			
		||||
  Stmt &operator=(const Stmt &other);
 | 
			
		||||
 | 
			
		||||
  // Move assignment
 | 
			
		||||
  Stmt &operator=(const Stmt &&other);
 | 
			
		||||
 | 
			
		||||
  StmtType type;
 | 
			
		||||
  StmtVariant value;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct _Expression {
 | 
			
		||||
  _Expression(const Expr &expr) : expr{expr} {}
 | 
			
		||||
  Expr expr;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct _Print {
 | 
			
		||||
  _Print(const Expr &expr) : expr{expr} {}
 | 
			
		||||
  Expr expr;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct _Var {
 | 
			
		||||
  _Var(const Token &name, const Expr &expr) : name{name}, expr{expr} {}
 | 
			
		||||
  Token name;
 | 
			
		||||
  Expr expr;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@@ -2,7 +2,7 @@
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
std::string Object::to_string() {
 | 
			
		||||
std::string Object::to_string() const {
 | 
			
		||||
  switch (type) {
 | 
			
		||||
    case ObjectType::NIL:
 | 
			
		||||
      return "nil";
 | 
			
		||||
@@ -78,25 +78,7 @@ std::ostream &operator<<(std::ostream &os, const ObjectType &type) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::ostream &operator<<(std::ostream &os, const Object &obj) {
 | 
			
		||||
  os << "Object(" << obj.type;
 | 
			
		||||
 | 
			
		||||
  switch (obj.type) {
 | 
			
		||||
    case ObjectType::NIL:
 | 
			
		||||
      break;
 | 
			
		||||
    case ObjectType::BOOL:
 | 
			
		||||
      os << ", " << std::to_string(std::get<bool>(obj.value));
 | 
			
		||||
      break;
 | 
			
		||||
    case ObjectType::IDENTIFIER:
 | 
			
		||||
    case ObjectType::STRING_LIT:
 | 
			
		||||
      os << ", " << std::get<std::string>(obj.value);
 | 
			
		||||
      break;
 | 
			
		||||
    case ObjectType::NUMBER:
 | 
			
		||||
      os << ", " << std::get<double>(obj.value);
 | 
			
		||||
      break;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  os << ')';
 | 
			
		||||
 | 
			
		||||
  os << obj.to_string();
 | 
			
		||||
  return os;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -29,7 +29,7 @@ struct Object {
 | 
			
		||||
        ObjectType::STRING_LIT
 | 
			
		||||
      },
 | 
			
		||||
      value{std::move(value)} {};
 | 
			
		||||
  std::string to_string();
 | 
			
		||||
  std::string to_string() const;
 | 
			
		||||
  bool operator==(const Object &other);
 | 
			
		||||
  bool operator!=(const Object &other);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user