Finish parsing expressions
This commit is contained in:
		@@ -1,10 +1,19 @@
 | 
				
			|||||||
#include "error_handler.hh"
 | 
					#include "error_handler.hh"
 | 
				
			||||||
 | 
					#include "tokenizer.hh"
 | 
				
			||||||
#include <iostream>
 | 
					#include <iostream>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ErrorHandler::error(int line, const std::string &message) {
 | 
					void ErrorHandler::error(int line, const std::string &message) {
 | 
				
			||||||
  report(line, "", message);
 | 
					  report(line, "", message);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ErrorHandler::error(Token token, const std::string &message) {
 | 
				
			||||||
 | 
					  if (token.type == TokenType::EOFILE) {
 | 
				
			||||||
 | 
					    report(token.line, " at end", message);
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    report(token.line, " at '" + token.lexeme + "'", message);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ErrorHandler::report(int line, const std::string &where, const std::string &message) {
 | 
					void ErrorHandler::report(int line, const std::string &where, const std::string &message) {
 | 
				
			||||||
  std::cout << "[line " << line << "] Error" << where << ": " << message << '\n';
 | 
					  std::cout << "[line " << line << "] Error" << where << ": " << message << '\n';
 | 
				
			||||||
  had_error = true;
 | 
					  had_error = true;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,11 +1,13 @@
 | 
				
			|||||||
#ifndef ERROR_HANDLER_HH
 | 
					#ifndef ERROR_HANDLER_HH
 | 
				
			||||||
#define ERROR_HANDLER_HH
 | 
					#define ERROR_HANDLER_HH
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "tokenizer.hh"
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct ErrorHandler {
 | 
					struct ErrorHandler {
 | 
				
			||||||
  ErrorHandler() : had_error{false} {};
 | 
					  ErrorHandler() : had_error{false} {};
 | 
				
			||||||
  void error(int line, const std::string &message);
 | 
					  void error(int line, const std::string &message);
 | 
				
			||||||
 | 
					  void error(Token token, const std::string &message);
 | 
				
			||||||
  void report(int line, const std::string &where, const std::string &message);
 | 
					  void report(int line, const std::string &where, const std::string &message);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bool had_error;
 | 
					  bool had_error;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,11 @@
 | 
				
			|||||||
#include "interpreter.hh"
 | 
					#include "interpreter.hh"
 | 
				
			||||||
#include "error_handler.hh"
 | 
					#include "error_handler.hh"
 | 
				
			||||||
#include "tokenizer.hh"
 | 
					#include "tokenizer.hh"
 | 
				
			||||||
 | 
					#include "parser.hh"
 | 
				
			||||||
#include <cstdint>
 | 
					#include <cstdint>
 | 
				
			||||||
#include <fstream>
 | 
					#include <fstream>
 | 
				
			||||||
#include <iostream>
 | 
					#include <iostream>
 | 
				
			||||||
 | 
					#include <optional>
 | 
				
			||||||
#include <sysexits.h>
 | 
					#include <sysexits.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define PROMPT "> "
 | 
					#define PROMPT "> "
 | 
				
			||||||
@@ -50,7 +52,11 @@ void run(const std::string &code) {
 | 
				
			|||||||
  Scanner scanner{code};
 | 
					  Scanner scanner{code};
 | 
				
			||||||
  std::vector<Token> tokens = scanner.scan_tokens();
 | 
					  std::vector<Token> tokens = scanner.scan_tokens();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  for (const auto &token : tokens) {
 | 
					  Parser parser{tokens};
 | 
				
			||||||
    std::cout << token << '\n';
 | 
					  std::optional<Expr> expression = parser.parse();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (expression) {
 | 
				
			||||||
 | 
					    AstPrinter printer{};
 | 
				
			||||||
 | 
							std::cout << printer.print(*expression) << '\n';
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,26 +8,12 @@
 | 
				
			|||||||
ErrorHandler error_handler{};
 | 
					ErrorHandler error_handler{};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int main(int argc, char *argv[]) {
 | 
					int main(int argc, char *argv[]) {
 | 
				
			||||||
  (void)argc;
 | 
					  if (argc > 2) {
 | 
				
			||||||
  (void)argv;
 | 
					    std::cout << "Usage: cclox [script]\n";
 | 
				
			||||||
  // if (argc > 2) {
 | 
					    exit(EX_USAGE);
 | 
				
			||||||
  //   std::cout << "Usage: cclox [script]\n";
 | 
					  }
 | 
				
			||||||
  //   exit(EX_USAGE);
 | 
					 | 
				
			||||||
  // }
 | 
					 | 
				
			||||||
  //
 | 
					 | 
				
			||||||
  // run_interpreter(argc, argv);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Token unary_op{TokenType::MINUS, "-", Object{}, 1};
 | 
					  run_interpreter(argc, argv);
 | 
				
			||||||
  Expr left{Unary(unary_op, Literal(123))};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  Token op{TokenType::STAR, "*", Object{}, 1};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  Expr right{Grouping(Literal(45.67))};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  Expr expr{Binary(left, op, right)};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  AstPrinter printer{};
 | 
					 | 
				
			||||||
  std::cout << printer.print(expr) << '\n';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return 0;
 | 
					  return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,5 +3,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "parser/expr.cc"
 | 
					#include "parser/expr.cc"
 | 
				
			||||||
#include "parser/printer.cc"
 | 
					#include "parser/printer.cc"
 | 
				
			||||||
 | 
					#include "parser/parser.cc"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,8 @@
 | 
				
			|||||||
#ifndef PARSER_HH
 | 
					#ifndef MAIN_PARSER_HH
 | 
				
			||||||
#define PARSER_HH
 | 
					#define MAIN_PARSER_HH
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "parser/expr.hh"
 | 
					#include "parser/expr.hh"
 | 
				
			||||||
#include "parser/printer.hh"
 | 
					#include "parser/printer.hh"
 | 
				
			||||||
 | 
					#include "parser/parser.hh"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										186
									
								
								cclox_src/parser/parser.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										186
									
								
								cclox_src/parser/parser.cc
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,186 @@
 | 
				
			|||||||
 | 
					#include "parser.hh"
 | 
				
			||||||
 | 
					#include "expr.hh"
 | 
				
			||||||
 | 
					#include "../error_handler.hh"
 | 
				
			||||||
 | 
					#include "../tokenizer.hh"
 | 
				
			||||||
 | 
					#include <optional>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern ErrorHandler error_handler;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::optional<Expr> Parser::parse() {
 | 
				
			||||||
 | 
					  try {
 | 
				
			||||||
 | 
					    return expression();
 | 
				
			||||||
 | 
					  } catch (ParseException e) {
 | 
				
			||||||
 | 
					    return std::nullopt;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Expr Parser::expression() {
 | 
				
			||||||
 | 
					  return equality();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Expr Parser::equality() {
 | 
				
			||||||
 | 
					  Expr expr = comparison();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  while (match({TokenType::BANG_EQUAL, TokenType::EQUAL_EQUAL})) {
 | 
				
			||||||
 | 
					    Token op   = previous();
 | 
				
			||||||
 | 
					    Expr right = comparison();
 | 
				
			||||||
 | 
					    expr       = Binary(expr, op, right);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return expr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Expr Parser::comparison() {
 | 
				
			||||||
 | 
					  Expr expr = term();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  while (match({TokenType::GREATER, TokenType::GREATER_EQUAL, TokenType::LESS, TokenType::LESS_EQUAL})) {
 | 
				
			||||||
 | 
					    Token op   = previous();
 | 
				
			||||||
 | 
					    Expr right = term();
 | 
				
			||||||
 | 
					    expr       = Binary(expr, op, right);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return expr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Expr Parser::term() {
 | 
				
			||||||
 | 
					  Expr expr = factor();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  while (match({TokenType::MINUS, TokenType::PLUS})) {
 | 
				
			||||||
 | 
					    Token op = previous();
 | 
				
			||||||
 | 
					    Expr right = factor();
 | 
				
			||||||
 | 
					    expr = Binary(expr, op, right);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return expr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Expr Parser::factor() {
 | 
				
			||||||
 | 
					  Expr expr = unary();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  while (match({TokenType::SLASH, TokenType::STAR})) {
 | 
				
			||||||
 | 
					    Token op   = previous();
 | 
				
			||||||
 | 
					    Expr right = unary();
 | 
				
			||||||
 | 
					    expr       = Binary(expr, op, right);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return expr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Expr Parser::unary() {
 | 
				
			||||||
 | 
					  if (match({TokenType::BANG, TokenType::MINUS})) {
 | 
				
			||||||
 | 
					    Token op   = previous();
 | 
				
			||||||
 | 
					    Expr right = unary();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return Unary(op, right);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return primary();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Expr Parser::primary() {
 | 
				
			||||||
 | 
					  if (match({TokenType::FALSE})) {
 | 
				
			||||||
 | 
					    return Literal(false);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (match({TokenType::TRUE})) {
 | 
				
			||||||
 | 
					    return Literal(true);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (match({TokenType::NIL})) {
 | 
				
			||||||
 | 
					    return Literal(Object{});
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (match({TokenType::NUMBER, TokenType::STRING})) {
 | 
				
			||||||
 | 
					    return Literal(previous().literal);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (match({TokenType::LEFT_PAREN})) {
 | 
				
			||||||
 | 
					    Expr expr = expression();
 | 
				
			||||||
 | 
					    consume(TokenType::RIGHT_PAREN, "Expect ')' after expression.");
 | 
				
			||||||
 | 
					    return Grouping(expr);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  throw error(peek(), "Expect expression.");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Token Parser::advance() {
 | 
				
			||||||
 | 
					  if (!is_at_end()) {
 | 
				
			||||||
 | 
					    ++current;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return previous();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Token Parser::peek() {
 | 
				
			||||||
 | 
					  return tokens.at(current);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Token Parser::previous() {
 | 
				
			||||||
 | 
					  return tokens.at(current - 1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Token Parser::consume(TokenType type, std::string &&message) {
 | 
				
			||||||
 | 
					  if (check(type)) {
 | 
				
			||||||
 | 
					    return advance();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  throw error(peek(), message);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool Parser::match(std::vector<TokenType> types) {
 | 
				
			||||||
 | 
					  for (const auto &type : types) {
 | 
				
			||||||
 | 
					    if (check(type)) {
 | 
				
			||||||
 | 
					      advance();
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool Parser::check(TokenType type) {
 | 
				
			||||||
 | 
					  if (is_at_end()) {
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return peek().type == type;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool Parser::is_at_end() {
 | 
				
			||||||
 | 
					  return peek().type == TokenType::EOFILE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ParseException Parser::error(Token token, std::string &message) {
 | 
				
			||||||
 | 
					  error_handler.error(token, message);
 | 
				
			||||||
 | 
					  return ParseException{};
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ParseException Parser::error(Token token, std::string &&message) {
 | 
				
			||||||
 | 
					  return error(token, message);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Parser::synchronize() {
 | 
				
			||||||
 | 
					  advance();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  while (!is_at_end()) {
 | 
				
			||||||
 | 
					    if (previous().type == TokenType::SEMICOLON) {
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch (peek().type) {
 | 
				
			||||||
 | 
					      case TokenType::CLASS:
 | 
				
			||||||
 | 
					      case TokenType::FUN:
 | 
				
			||||||
 | 
					      case TokenType::VAR:
 | 
				
			||||||
 | 
					      case TokenType::FOR:
 | 
				
			||||||
 | 
					      case TokenType::IF:
 | 
				
			||||||
 | 
					      case TokenType::WHILE:
 | 
				
			||||||
 | 
					      case TokenType::PRINT:
 | 
				
			||||||
 | 
					      case TokenType::RETURN:
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					      default:
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    advance();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										47
									
								
								cclox_src/parser/parser.hh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								cclox_src/parser/parser.hh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,47 @@
 | 
				
			|||||||
 | 
					#ifndef PARSER_HH
 | 
				
			||||||
 | 
					#define PARSER_HH
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "expr.hh"
 | 
				
			||||||
 | 
					#include "../tokenizer.hh"
 | 
				
			||||||
 | 
					#include <cstddef>
 | 
				
			||||||
 | 
					#include <exception>
 | 
				
			||||||
 | 
					#include <optional>
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ParseException : public std::exception {
 | 
				
			||||||
 | 
					  ParseException() : message{""} {}
 | 
				
			||||||
 | 
					  ParseException(const std::string& message) : message{message} {}
 | 
				
			||||||
 | 
					  const char* what() const noexcept override {
 | 
				
			||||||
 | 
					      return message.c_str();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
					  std::string message;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct Parser {
 | 
				
			||||||
 | 
					  Parser(std::vector<Token> tokens) : tokens{tokens} {}
 | 
				
			||||||
 | 
					  std::optional<Expr> parse();
 | 
				
			||||||
 | 
					  Expr expression();
 | 
				
			||||||
 | 
					  Expr equality();
 | 
				
			||||||
 | 
					  Expr comparison();
 | 
				
			||||||
 | 
					  Expr term();
 | 
				
			||||||
 | 
					  Expr factor();
 | 
				
			||||||
 | 
					  Expr unary();
 | 
				
			||||||
 | 
					  Expr primary();
 | 
				
			||||||
 | 
					  Token advance();
 | 
				
			||||||
 | 
					  Token peek();
 | 
				
			||||||
 | 
					  Token previous();
 | 
				
			||||||
 | 
					  Token consume(TokenType type, std::string &&message);
 | 
				
			||||||
 | 
					  bool match(std::vector<TokenType> types);
 | 
				
			||||||
 | 
					  bool check(TokenType type);
 | 
				
			||||||
 | 
					  bool is_at_end();
 | 
				
			||||||
 | 
					  ParseException error(Token token, std::string &message);
 | 
				
			||||||
 | 
					  ParseException error(Token token, std::string &&message);
 | 
				
			||||||
 | 
					  void synchronize();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  std::vector<Token> tokens;
 | 
				
			||||||
 | 
					  size_t current = 0;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
@@ -22,6 +22,10 @@ std::string AstPrinter::print(const Expr &expr) {
 | 
				
			|||||||
      switch (literal->value.type) {
 | 
					      switch (literal->value.type) {
 | 
				
			||||||
        case ObjectType::NIL:
 | 
					        case ObjectType::NIL:
 | 
				
			||||||
          return "nil";
 | 
					          return "nil";
 | 
				
			||||||
 | 
					        case ObjectType::BOOL: {
 | 
				
			||||||
 | 
					          bool value = std::get<bool>(literal->value.value);
 | 
				
			||||||
 | 
					          return (value ? "true" : "false");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        case ObjectType::IDENTIFIER:
 | 
					        case ObjectType::IDENTIFIER:
 | 
				
			||||||
        case ObjectType::STRING_LIT: {
 | 
					        case ObjectType::STRING_LIT: {
 | 
				
			||||||
          std::string value = std::get<std::string>(literal->value.value);
 | 
					          std::string value = std::get<std::string>(literal->value.value);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,8 @@ std::ostream &operator<<(std::ostream &os, const ObjectType &type) {
 | 
				
			|||||||
    case ObjectType::NIL:
 | 
					    case ObjectType::NIL:
 | 
				
			||||||
      os << "ObjectType::NIL";
 | 
					      os << "ObjectType::NIL";
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
 | 
					    case ObjectType::BOOL:
 | 
				
			||||||
 | 
					      os << "ObjectType::BOOL";
 | 
				
			||||||
    case ObjectType::IDENTIFIER:
 | 
					    case ObjectType::IDENTIFIER:
 | 
				
			||||||
      os << "ObjectType::IDENTIFIER";
 | 
					      os << "ObjectType::IDENTIFIER";
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
@@ -26,6 +28,9 @@ std::ostream &operator<<(std::ostream &os, const Object &obj) {
 | 
				
			|||||||
  switch (obj.type) {
 | 
					  switch (obj.type) {
 | 
				
			||||||
    case ObjectType::NIL:
 | 
					    case ObjectType::NIL:
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
 | 
					    case ObjectType::BOOL:
 | 
				
			||||||
 | 
					      os << ", " << std::to_string(std::get<bool>(obj.value));
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
    case ObjectType::IDENTIFIER:
 | 
					    case ObjectType::IDENTIFIER:
 | 
				
			||||||
    case ObjectType::STRING_LIT:
 | 
					    case ObjectType::STRING_LIT:
 | 
				
			||||||
      os << ", " << std::get<std::string>(obj.value);
 | 
					      os << ", " << std::get<std::string>(obj.value);
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user