diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..20aff15 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/headers/Expression.h b/headers/Expression.h index dc4b053..6f5b1f5 100644 --- a/headers/Expression.h +++ b/headers/Expression.h @@ -28,7 +28,7 @@ struct ExprVisitor struct Expr{ virtual sptr(Object) accept(ExprVisitor* visitor) = 0; - virtual ~Expr(){} + virtual ~Expr() = default; }; struct AssignExpr : Expr, public std::enable_shared_from_this diff --git a/headers/Interpreter.h b/headers/Interpreter.h index 5e7def7..9380e63 100644 --- a/headers/Interpreter.h +++ b/headers/Interpreter.h @@ -23,25 +23,21 @@ public: void interpret(std::vector statements); - Interpreter(){ + explicit Interpreter(bool IsInteractive) : IsInteractive(IsInteractive){ environment = msptr(Environment)(); } + ~Interpreter(); private: sptr(Environment) environment; - - + bool IsInteractive; sptr(Object) evaluate(sptr(Expr) expr); bool isTruthy(sptr(Object) object); bool isEqual(sptr(Object) a, sptr(Object) b); - std::string stringify(sptr(Object) object); - bool isWholeNumer(double num); - void execute(std::shared_ptr statement); - void executeBlock(std::vector> statements, std::shared_ptr env); }; diff --git a/headers/Lexer.h b/headers/Lexer.h index 134125f..8459ae6 100644 --- a/headers/Lexer.h +++ b/headers/Lexer.h @@ -8,7 +8,7 @@ enum TokenType{ OPEN_PAREN, CLOSE_PAREN, OPEN_BRACE, CLOSE_BRACE, COMMA, DOT, MINUS, PLUS, SEMICOLON, SLASH, STAR, PERCENT, - BINARY_OP, + BIN_OR, BIN_AND, BIN_NOT, BIN_XOR, BIN_SLEFT, BIN_SRIGHT, BANG, BANG_EQUAL, EQUAL, DOUBLE_EQUAL, @@ -56,7 +56,8 @@ const std::map KEYWORDS { {"this", THIS}, {"none", NONE}, {"return", RETURN}, - {"print", PRINT} + {"print", PRINT}, + }; struct Token diff --git a/headers/Parser.h b/headers/Parser.h index 92ad4cc..0759891 100644 --- a/headers/Parser.h +++ b/headers/Parser.h @@ -26,14 +26,14 @@ private: sptr(Expr) unary(); sptr(Expr) primary(); - bool match(std::vector types); + bool match(const std::vector& types); bool check(TokenType type); bool isAtEnd(); Token advance(); Token peek(); Token previous(); - Token consume(TokenType type, std::string message); + Token consume(TokenType type, const std::string& message); sptr(Stmt) statement(); void sync(); diff --git a/headers/bob.h b/headers/bob.h index af73f19..5058dfb 100644 --- a/headers/bob.h +++ b/headers/bob.h @@ -12,14 +12,19 @@ class Bob { public: Lexer lexer; - Interpreter interpreter; + Interpreter* interpreter; + + ~Bob() + { + delete interpreter; + } public: - void runFile(std::string path); + void runFile(const std::string& path); void runPrompt(); - void error(int line, std::string message); + void error(int line, const std::string& message); private: diff --git a/source/Interpreter.cpp b/source/Interpreter.cpp index ec5aef8..de6a383 100644 --- a/source/Interpreter.cpp +++ b/source/Interpreter.cpp @@ -58,6 +58,19 @@ sptr(Object) Interpreter::visitUnaryExpr(sptr(UnaryExpr) expression) return msptr(Boolean)(!isTruthy(right)); } + if(expression->oper.type == BIN_NOT) + { + if(std::dynamic_pointer_cast(right)) + { + double value = std::dynamic_pointer_cast(right)->value; + return msptr(Number)((~(long)value)); + } + else + { + throw std::runtime_error("Operand must be an int when using: " + expression->oper.lexeme); + } + } + //unreachable throw std::runtime_error("Invalid unary expression"); @@ -162,7 +175,10 @@ void Interpreter::visitBlockStmt(std::shared_ptr statement) { } void Interpreter::visitExpressionStmt(sptr(ExpressionStmt) statement) { - evaluate(statement->expression); + sptr(Object) value = evaluate(statement->expression); + + if(IsInteractive) + std::cout << "\u001b[38;5;8m[" << stringify(value) << "]\u001b[38;5;15m" << std::endl; } void Interpreter::visitPrintStmt(sptr(PrintStmt) statement) { @@ -336,6 +352,8 @@ bool Interpreter::isWholeNumer(double num) { } } +Interpreter::~Interpreter() = default; + diff --git a/source/Lexer.cpp b/source/Lexer.cpp index e48b6ae..25b2b37 100644 --- a/source/Lexer.cpp +++ b/source/Lexer.cpp @@ -68,6 +68,11 @@ std::vector Lexer::Tokenize(std::string source){ tokens.push_back(Token{PERCENT, std::string(1, t), line}); advance(); } + else if(t == '~') + { + tokens.push_back(Token{BIN_NOT, std::string(1, t), line}); + advance(); + } else if(t == '=') { std::string token = std::string(1, t); @@ -88,9 +93,19 @@ std::vector Lexer::Tokenize(std::string source){ { std::string token = std::string(1, t); advance(); - bool match = matchOn('='); - token += match ? "=" : ""; - tokens.push_back(Token{match ? LESS_EQUAL : LESS, token, line}); + if(matchOn('=')) + { + tokens.push_back(Token{LESS_EQUAL, "<=", line}); + } + else if(matchOn('<')) + { + tokens.push_back(Token{BIN_SLEFT, "<<", line}); + } + else + { + tokens.push_back(Token{LESS, token, line}); + } + } else if(t == '>') { diff --git a/source/Parser.cpp b/source/Parser.cpp index 7b68d49..d6922d9 100644 --- a/source/Parser.cpp +++ b/source/Parser.cpp @@ -96,7 +96,7 @@ sptr(Expr) Parser::factor() sptr(Expr) Parser::unary() { - if(match({BANG, MINUS})) + if(match({BANG, MINUS, BIN_NOT})) { Token op = previous(); sptr(Expr) right = unary(); @@ -144,6 +144,32 @@ std::vector Parser::parse() { } +sptr(Stmt) Parser::declaration() +{ + try{ + if(match({VAR})) return varDeclaration(); + return statement(); + } + catch(std::runtime_error& e) + { + sync(); + throw std::runtime_error(e.what()); + } +} + +sptr(Stmt) Parser::varDeclaration() +{ + Token name = consume(IDENTIFIER, "Expected variable name."); + + sptr(Expr) initializer = msptr(LiteralExpr)("none", false, true); + if(match({EQUAL})) + { + initializer = expression(); + } + consume(SEMICOLON, "Expected ';' after variable declaration."); + return msptr(VarStmt)(name, initializer); +} + sptr(Stmt) Parser::statement() { if(match({PRINT})) return printStatement(); @@ -178,35 +204,11 @@ std::vector Parser::block() return statements; } -sptr(Stmt) Parser::declaration() -{ - try{ - if(match({VAR})) return varDeclaration(); - return statement(); - } - catch(std::runtime_error e) - { - sync(); - throw std::runtime_error(e.what()); - } -} - -sptr(Stmt) Parser::varDeclaration() -{ - Token name = consume(IDENTIFIER, "Expected variable name."); - - sptr(Expr) initializer = msptr(LiteralExpr)("none", false, true); - if(match({EQUAL})) - { - initializer = expression(); - } - consume(SEMICOLON, "Expected ';' after variable declaration."); - return msptr(VarStmt)(name, initializer); -} -bool Parser::match(std::vector types) { + +bool Parser::match(const std::vector& types) { for(TokenType t : types) { if(check(t)) @@ -241,10 +243,10 @@ Token Parser::previous() { return tokens[current - 1]; } -Token Parser::consume(TokenType type, std::string message) { +Token Parser::consume(TokenType type, const std::string& message) { if(check(type)) return advance(); - throw std::runtime_error(peek().lexeme +": "+ message); + throw std::runtime_error("Unexpected symbol '" + peek().lexeme +"': "+ message); } void Parser::sync() diff --git a/source/bob.cpp b/source/bob.cpp index 4198651..c055619 100644 --- a/source/bob.cpp +++ b/source/bob.cpp @@ -1,13 +1,16 @@ +#include + #include "../headers/bob.h" #include "../headers/Parser.h" #include "../headers/ASTPrinter.h" using namespace std; -void Bob::runFile(string path) +void Bob::runFile(const string& path) { + this->interpreter = new Interpreter(false); ifstream file = ifstream(path); - string source = ""; + string source; if(file.is_open()){ source = string(istreambuf_iterator(file), istreambuf_iterator()); @@ -23,6 +26,8 @@ void Bob::runFile(string path) void Bob::runPrompt() { + this->interpreter = new Interpreter(true); + cout << "Bob v" << VERSION << ", 2023" << endl; for(;;) { @@ -40,7 +45,7 @@ void Bob::runPrompt() } } -void Bob::error(int line, string message) +void Bob::error(int line, const string& message) { } @@ -48,7 +53,7 @@ void Bob::error(int line, string message) void Bob::run(string source) { try { - vector tokens = lexer.Tokenize(source); + vector tokens = lexer.Tokenize(std::move(source)); // for(Token t : tokens){ // cout << "{type: " << enum_mapping[t.type] << ", value: " << t.lexeme << "}" << endl; // } @@ -56,7 +61,7 @@ void Bob::run(string source) Parser p(tokens); vector statements = p.parse(); - interpreter.interpret(statements); + interpreter->interpret(statements); //cout << "=========================" << endl; diff --git a/source/main.cpp b/source/main.cpp index 3c74612..bfbf871 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -1,15 +1,13 @@ // // Created by Bobby Lucero on 5/21/23. // - - #include "../headers/bob.h" int main(){ Bob bobLang; bobLang.runFile("source.bob"); - //bobLang.runPrompt(); + bobLang.runPrompt(); return 0; }