diff --git a/headers/ASTPrinter.h b/headers/ASTPrinter.h index 9d5f93d..fe66abf 100644 --- a/headers/ASTPrinter.h +++ b/headers/ASTPrinter.h @@ -6,12 +6,16 @@ #include -class ASTPrinter : Visitor +class ASTPrinter : ExprVisitor { sptr(Object) visitBinaryExpr(sptr(BinaryExpr) expr) override; sptr(Object) visitGroupingExpr(sptr(GroupingExpr) expr) override; sptr(Object) visitLiteralExpr(sptr(LiteralExpr) expr) override; sptr(Object) visitUnaryExpr(sptr(UnaryExpr) expr) override; + sptr(Object) visitAssignExpr(sptr(AssignExpr) expr) override; + sptr(Object) visitVariableExpr(sptr(VarExpr) expr) override; + + public: sptr(Object) print(sptr(Expr) expr); private: diff --git a/headers/Environment.h b/headers/Environment.h new file mode 100644 index 0000000..1a98106 --- /dev/null +++ b/headers/Environment.h @@ -0,0 +1,21 @@ +#pragma once + +#include +#include "TypeWrapper.h" +#include "helperFunctions/ShortHands.h" +#include "Lexer.h" + +class Environment +{ +public: + + void define(std::string name, sptr(Object) value); + + void assign(Token name, sptr(Object) value); + + std::shared_ptr get(Token name); + +private: + std::unordered_map variables; + +}; \ No newline at end of file diff --git a/headers/Expression.h b/headers/Expression.h index 39c6b23..dc4b053 100644 --- a/headers/Expression.h +++ b/headers/Expression.h @@ -8,25 +8,42 @@ #include "helperFunctions/ShortHands.h" #include "TypeWrapper.h" +struct AssignExpr; struct BinaryExpr; struct GroupingExpr; struct LiteralExpr; struct UnaryExpr; +struct VarExpr; -struct Visitor +struct ExprVisitor { + virtual sptr(Object) visitAssignExpr(sptr(AssignExpr) expr) = 0; virtual sptr(Object) visitBinaryExpr(sptr(BinaryExpr) expr) = 0; virtual sptr(Object) visitGroupingExpr(sptr(GroupingExpr) expr) = 0; virtual sptr(Object) visitLiteralExpr(sptr(LiteralExpr) expr) = 0; virtual sptr(Object) visitUnaryExpr(sptr(UnaryExpr) expr) = 0; + virtual sptr(Object) visitVariableExpr(sptr(VarExpr) expr) = 0; }; struct Expr{ - virtual sptr(Object) accept(Visitor* visitor) = 0; + virtual sptr(Object) accept(ExprVisitor* visitor) = 0; virtual ~Expr(){} }; +struct AssignExpr : Expr, public std::enable_shared_from_this +{ + const Token name; + const sptr(Expr) value; + AssignExpr(Token name, sptr(Expr) value) : name(name), value(value) + { + } + + sptr(Object) accept(ExprVisitor* visitor) override + { + return visitor->visitAssignExpr(shared_from_this()); + } +}; struct BinaryExpr : Expr, public std::enable_shared_from_this { @@ -37,7 +54,7 @@ struct BinaryExpr : Expr, public std::enable_shared_from_this BinaryExpr(sptr(Expr) left, Token oper, sptr(Expr) right) : left(left), oper(oper), right(right) { } - sptr(Object) accept(Visitor* visitor) override{ + sptr(Object) accept(ExprVisitor* visitor) override{ return visitor->visitBinaryExpr(shared_from_this() ); } }; @@ -46,10 +63,10 @@ struct GroupingExpr : Expr, public std::enable_shared_from_this { const std::shared_ptr expression; - GroupingExpr(sptr(Expr) expression) : expression(expression) + explicit GroupingExpr(sptr(Expr) expression) : expression(expression) { } - sptr(Object) accept(Visitor* visitor) override{ + sptr(Object) accept(ExprVisitor* visitor) override{ return visitor->visitGroupingExpr(shared_from_this()); } }; @@ -62,7 +79,7 @@ struct LiteralExpr : Expr, public std::enable_shared_from_this LiteralExpr(std::string value, bool isNumber, bool isNull) : value(value), isNumber(isNumber), isNull(isNull) { } - sptr(Object) accept(Visitor* visitor) override{ + sptr(Object) accept(ExprVisitor* visitor) override{ return visitor->visitLiteralExpr(shared_from_this()); } }; @@ -75,10 +92,20 @@ struct UnaryExpr : Expr, public std::enable_shared_from_this UnaryExpr(Token oper, sptr(Expr) right) : oper(oper), right(right) { } - sptr(Object) accept(Visitor* visitor) override{ + sptr(Object) accept(ExprVisitor* visitor) override{ return visitor->visitUnaryExpr(shared_from_this()); } }; +struct VarExpr : Expr, public std::enable_shared_from_this +{ + const Token name; + explicit VarExpr(Token name) : name(name){}; + sptr(Object) accept(ExprVisitor* visitor) override + { + return visitor->visitVariableExpr(shared_from_this()); + } +}; + //// diff --git a/headers/Interpreter.h b/headers/Interpreter.h index 6ecd5e0..8e26dde 100644 --- a/headers/Interpreter.h +++ b/headers/Interpreter.h @@ -1,9 +1,11 @@ #pragma once #include "Expression.h" +#include "Statement.h" #include "helperFunctions/ShortHands.h" #include "TypeWrapper.h" +#include "Environment.h" -class Interpreter : Visitor +class Interpreter : ExprVisitor, StmtVisitor { public: @@ -11,10 +13,19 @@ public: sptr(Object) visitGroupingExpr(sptr(GroupingExpr) expression) override; sptr(Object) visitLiteralExpr(sptr(LiteralExpr) expression) override; sptr(Object) visitUnaryExpr(sptr(UnaryExpr) expression) override; + sptr(Object) visitVariableExpr(sptr(VarExpr) expression) override; + sptr(Object) visitAssignExpr(sptr(AssignExpr) expression) override; - void interpret(sptr(Expr) expr); + void visitExpressionStmt(sptr(ExpressionStmt) statement) override; + void visitPrintStmt(sptr(PrintStmt) statement) override; + void visitVarStmt(sptr(VarStmt) statement) override; + + void interpret(std::vector statements); private: + + Environment environment; + sptr(Object) evaluate(sptr(Expr) expr); bool isTruthy(sptr(Object) object); bool isEqual(sptr(Object) a, sptr(Object) b); @@ -22,4 +33,6 @@ private: std::string stringify(sptr(Object) object); bool isWholeNumer(double num); + + void execute(std::shared_ptr statement); }; diff --git a/headers/Lexer.h b/headers/Lexer.h index 7c6be66..83b08be 100644 --- a/headers/Lexer.h +++ b/headers/Lexer.h @@ -6,7 +6,7 @@ enum TokenType{ OPEN_PAREN, CLOSE_PAREN, OPEN_BRACE, CLOSE_BRACE, - COMMA, DOT, MINUS, PLUS, SEMICOLON, SLASH, STAR, + COMMA, DOT, MINUS, PLUS, SEMICOLON, SLASH, STAR, PERCENT, BINARY_OP, @@ -15,16 +15,16 @@ enum TokenType{ GREATER, GREATER_EQUAL, LESS, LESS_EQUAL, - IDENTIFIER, STRING, NUMBER, + IDENTIFIER, STRING, NUMBER, BOOL, AND, OR, TRUE, FALSE, IF, ELSE, FUNCTION, FOR, - WHILE, VAR, CLASS, SUPER, THIS, NONE, RETURN, + WHILE, VAR, CLASS, SUPER, THIS, NONE, RETURN, PRINT, END_OF_FILE }; inline std::string enum_mapping[] = {"OPEN_PAREN", "CLOSE_PAREN", "OPEN_BRACE", "CLOSE_BRACE", - "COMMA", "DOT", "MINUS", "PLUS", "SEMICOLON", "SLASH", "STAR", + "COMMA", "DOT", "MINUS", "PLUS", "SEMICOLON", "SLASH", "STAR", "PERCENT", "BINARY_OP", @@ -33,10 +33,10 @@ inline std::string enum_mapping[] = {"OPEN_PAREN", "CLOSE_PAREN", "OPEN_BRACE", "GREATER", "GREATER_EQUAL", "LESS", "LESS_EQUAL", - "IDENTIFIER", "STRING", "NUMBER", + "IDENTIFIER", "STRING", "NUMBER", "BOOL", "AND", "OR", "TRUE", "FALSE", "IF", "ELSE", "FUNCTION", "FOR", - "WHILE", "VAR", "CLASS", "SUPER", "THIS", "NONE", "RETURN", + "WHILE", "VAR", "CLASS", "SUPER", "THIS", "NONE", "RETURN", "PRINT", "END_OF_FILE"}; @@ -55,7 +55,8 @@ const std::map KEYWORDS { {"super", SUPER}, {"this", THIS}, {"none", NONE}, - {"return", RETURN} + {"return", RETURN}, + {"print", PRINT} }; struct Token diff --git a/headers/Parser.h b/headers/Parser.h index 236acf6..d230919 100644 --- a/headers/Parser.h +++ b/headers/Parser.h @@ -3,6 +3,7 @@ #include #include "Lexer.h" #include "Expression.h" +#include "Statement.h" #include "TypeWrapper.h" #include "helperFunctions/ShortHands.h" @@ -14,7 +15,7 @@ private: public: explicit Parser(std::vector tokens) : tokens(std::move(tokens)){}; - sptr(Expr) parse(); + std::vector parse(); private: sptr(Expr) expression(); @@ -33,7 +34,17 @@ private: Token peek(); Token previous(); Token consume(TokenType type, std::string message); + sptr(Stmt) statement(); void sync(); + std::shared_ptr printStatement(); + + std::shared_ptr expressionStatement(); + + std::shared_ptr declaration(); + + std::shared_ptr varDeclaration(); + + std::shared_ptr assignment(); }; \ No newline at end of file diff --git a/headers/Statement.h b/headers/Statement.h new file mode 100644 index 0000000..e2ea73c --- /dev/null +++ b/headers/Statement.h @@ -0,0 +1,64 @@ +#pragma once + + +#include "helperFunctions/ShortHands.h" +#include "TypeWrapper.h" +#include "Expression.h" + +struct ExpressionStmt; +struct PrintStmt; +struct VarStmt; + +struct StmtVisitor +{ + virtual void visitExpressionStmt(sptr(ExpressionStmt) stmt) = 0; + virtual void visitPrintStmt(sptr(PrintStmt) stmt) = 0; + virtual void visitVarStmt(sptr(VarStmt) stmt) = 0; +}; + +struct Stmt +{ + const sptr(Expr) expression; + virtual void accept(StmtVisitor* visitor) = 0; + virtual ~Stmt(){}; +}; + +struct ExpressionStmt : Stmt, public std::enable_shared_from_this +{ + const sptr(Expr) expression; + explicit ExpressionStmt(sptr(Expr) expression) : expression(expression) + { + } + + void accept(StmtVisitor* visitor) override + { + visitor->visitExpressionStmt(shared_from_this()); + } +}; + +struct PrintStmt : Stmt, public std::enable_shared_from_this +{ + const sptr(Expr) expression; + explicit PrintStmt(sptr(Expr) expression) : expression(expression) + { + } + + void accept(StmtVisitor* visitor) override + { + visitor->visitPrintStmt(shared_from_this()); + } +}; + +struct VarStmt : Stmt, public std::enable_shared_from_this +{ + Token name; + const sptr(Expr) initializer; + VarStmt(Token name, sptr(Expr) initializer) : name(name), initializer(initializer) + { + } + + void accept(StmtVisitor* visitor) override + { + visitor->visitVarStmt(shared_from_this()); + } +}; \ No newline at end of file diff --git a/headers/TypeWrapper.h b/headers/TypeWrapper.h index 0bf34fa..00dae47 100644 --- a/headers/TypeWrapper.h +++ b/headers/TypeWrapper.h @@ -1,5 +1,6 @@ #pragma once #include +#include struct Object { virtual ~Object(){}; @@ -15,6 +16,10 @@ struct String : Object { std::string value; explicit String(std::string str) : value(str) {} + ~String(){ + std::cout << value.size() << std::endl; + std::cout << "String being destroyed..." << std::endl; + } }; struct Boolean : Object diff --git a/source.bob b/source.bob index 261aba8..07e3668 100644 --- a/source.bob +++ b/source.bob @@ -1,3 +1 @@ -//10 + 10 -//0xFF + 0xFF -0xFF + 0xFF00 == 0xFFFF \ No newline at end of file +10 10; \ No newline at end of file diff --git a/source/ASTPrinter.cpp b/source/ASTPrinter.cpp index 212fcdb..eac80d4 100644 --- a/source/ASTPrinter.cpp +++ b/source/ASTPrinter.cpp @@ -39,3 +39,11 @@ sptr(Object) ASTPrinter::parenthesize(std::string name, std::vector return msptr(String)(builder); } + +sptr(Object) ASTPrinter::visitAssignExpr(std::shared_ptr expr) { + return std::shared_ptr(); +} + +sptr(Object) ASTPrinter::visitVariableExpr(std::shared_ptr expr) { + return std::shared_ptr(); +} diff --git a/source/Environment.cpp b/source/Environment.cpp new file mode 100644 index 0000000..5bed3ed --- /dev/null +++ b/source/Environment.cpp @@ -0,0 +1,34 @@ +// +// Created by Bobby Lucero on 5/30/23. +// + +#include "../headers/Environment.h" +#include "../headers/Lexer.h" + + +sptr(Object) Environment::get(Token name) +{ + if(variables.count(name.lexeme)) + { + return variables[name.lexeme]; + } + + throw std::runtime_error("Undefined variable '" + name.lexeme + "'."); +} + +void Environment::define(std::string name, sptr(Object) value) { + if(variables.count(name) > 0){ + throw std::runtime_error("'" + name + "' already defined."); + } + variables.insert(std::make_pair(name, value)); +} + +void Environment::assign(Token name, std::shared_ptr value) { + if(variables.count(name.lexeme) > 0) + { + variables[name.lexeme] = value; + return; + } + + throw std::runtime_error("Undefined variable '" + name.lexeme + "'."); +} diff --git a/source/Interpreter.cpp b/source/Interpreter.cpp index 03fe954..287a55c 100644 --- a/source/Interpreter.cpp +++ b/source/Interpreter.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "../headers/Interpreter.h" #include "../headers/helperFunctions/HelperFunctions.h" @@ -94,9 +95,12 @@ sptr(Object) Interpreter::visitBinaryExpr(sptr(BinaryExpr) expression) case PLUS: return msptr(Number)(left_double + right_double); case SLASH: + if(right_double == 0) throw std::runtime_error("DivisionByZeroError: Cannot divide by 0"); return msptr(Number)(left_double / right_double); case STAR: return msptr(Number)(left_double * right_double); + case PERCENT: + return msptr(Number)(fmod(left_double, right_double)); default: return msptr(None)(); //unreachable } @@ -120,11 +124,11 @@ sptr(Object) Interpreter::visitBinaryExpr(sptr(BinaryExpr) expression) double right_number = std::dynamic_pointer_cast(right)->value; if(isWholeNumer(right_number)) { - std::stringstream ss; + std::string s; for (int i = 0; i < (int)right_number; ++i) { - ss << left_string; + s += left_string; } - return msptr(String)(ss.str()); + return msptr(String)(s); } else @@ -142,6 +146,56 @@ sptr(Object) Interpreter::visitBinaryExpr(sptr(BinaryExpr) expression) } +sptr(Object) Interpreter::visitVariableExpr(sptr(VarExpr) expression) +{ + return environment.get(expression->name); +} + +sptr(Object) Interpreter::visitAssignExpr(sptr(AssignExpr) expression) { + sptr(Object) value = evaluate(expression->value); + environment.assign(expression->name, value); + return value; +} + +void Interpreter::visitExpressionStmt(sptr(ExpressionStmt) statement) { + evaluate(statement->expression); +} + +void Interpreter::visitPrintStmt(sptr(PrintStmt) statement) { + sptr(Object) value = evaluate(statement->expression); + std::cout << stringify(value) << std::endl; +} + +void Interpreter::visitVarStmt(sptr(VarStmt) statement) +{ + sptr(Object) value = msptr(None)(); + if(!std::dynamic_pointer_cast(statement->initializer)) + { + value = evaluate(statement->initializer); + } + + //std::cout << "Visit var stmt: " << statement->name.lexeme << " set to: " << stringify(value) << std::endl; + + environment.define(statement->name.lexeme, value); +} + +void Interpreter::interpret(std::vector statements) { + + + for(sptr(Stmt) s : statements) + { + execute(s); + } + + //std::cout << "\033[0;32m" << stringify(value) << std::endl; + +} + +void Interpreter::execute(sptr(Stmt) statement) +{ + statement->accept(this); +} + sptr(Object) Interpreter::evaluate(sptr(Expr) expr) { return expr->accept(this); } @@ -202,17 +256,10 @@ bool Interpreter::isEqual(sptr(Object) a, sptr(Object) b) { throw std::runtime_error("Invalid isEqual compariosn"); } -void Interpreter::interpret(std::shared_ptr expr) { - - sptr(Object) value = evaluate(std::move(expr)); - std::cout << "\033[0;32m" << stringify(value) << std::endl; - -} - std::string Interpreter::stringify(std::shared_ptr object) { if(std::dynamic_pointer_cast(object)) { - return "None"; + return "none"; } else if(auto num = std::dynamic_pointer_cast(object)) { @@ -267,3 +314,8 @@ bool Interpreter::isWholeNumer(double num) { + + + + + diff --git a/source/Lexer.cpp b/source/Lexer.cpp index 507e15f..e48b6ae 100644 --- a/source/Lexer.cpp +++ b/source/Lexer.cpp @@ -63,6 +63,11 @@ std::vector Lexer::Tokenize(std::string source){ tokens.push_back(Token{STAR, std::string(1, t), line}); advance(); } + else if(t == '%') + { + tokens.push_back(Token{PERCENT, std::string(1, t), line}); + advance(); + } else if(t == '=') { std::string token = std::string(1, t); diff --git a/source/Parser.cpp b/source/Parser.cpp index cf17b39..0b36482 100644 --- a/source/Parser.cpp +++ b/source/Parser.cpp @@ -10,7 +10,32 @@ sptr(Expr) Parser::expression() { - return equality(); + return assignment(); +} + +sptr(Expr) Parser::assignment() +{ + + sptr(Expr) expr = equality(); + + if(match({EQUAL})) + { + Token equals = previous(); + + sptr(Expr) value = assignment(); + + if(std::dynamic_pointer_cast(expr)) + { + + Token name = std::dynamic_pointer_cast(expr)->name; + + return msptr(AssignExpr)(name, value); + } + + throw std::runtime_error("Invalid assignment target."); + } + + return expr; } sptr(Expr) Parser::equality() @@ -59,7 +84,7 @@ sptr(Expr) Parser::factor() { sptr(Expr) expr = unary(); - while(match({SLASH, STAR})) + while(match({SLASH, STAR, PERCENT})) { Token op = previous(); sptr(Expr) right = unary(); @@ -85,11 +110,15 @@ sptr(Expr) Parser::primary() { if(match({FALSE})) return msptr(LiteralExpr)("false", false, false); if(match({TRUE})) return msptr(LiteralExpr)("true", false, false); - if(match({NONE})) return msptr(LiteralExpr)("none", false, false); + if(match({NONE})) return msptr(LiteralExpr)("none", false, true); if(match({NUMBER})) return msptr(LiteralExpr)(previous().lexeme, true, false); if(match({STRING})) return msptr(LiteralExpr)(previous().lexeme, false, false); + if(match( {IDENTIFIER})) { + return msptr(VarExpr)(previous()); + } + if(match({OPEN_PAREN})) { sptr(Expr) expr = expression(); @@ -103,10 +132,62 @@ sptr(Expr) Parser::primary() /////////////////////////////////////////// -sptr(Expr) Parser::parse() { +std::vector Parser::parse() { - return expression(); + std::vector statements; + while(!isAtEnd()) + { + statements.push_back(declaration()); + } + return statements; + +} + +sptr(Stmt) Parser::statement() +{ + if(match({PRINT})) return printStatement(); + return expressionStatement(); +} + +sptr(Stmt) Parser::printStatement() +{ + sptr(Expr) value = expression(); + consume(SEMICOLON, "Expected ';' after value."); + return msptr(PrintStmt)(value); +} + +sptr(Stmt) Parser::expressionStatement() +{ + sptr(Expr) expr = expression(); + consume(SEMICOLON, "Expected ';' after expression."); + return msptr(ExpressionStmt)(expr); +} + +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); } diff --git a/source/bob.cpp b/source/bob.cpp index 2c3f588..4198651 100644 --- a/source/bob.cpp +++ b/source/bob.cpp @@ -49,17 +49,16 @@ void Bob::run(string source) { try { vector tokens = lexer.Tokenize(source); +// for(Token t : tokens){ +// cout << "{type: " << enum_mapping[t.type] << ", value: " << t.lexeme << "}" << endl; +// } + + Parser p(tokens); - shared_ptr expr = p.parse(); - interpreter.interpret(expr); + vector statements = p.parse(); + interpreter.interpret(statements); //cout << "=========================" << endl; - ASTPrinter printer; - //cout << dynamic_pointer_cast(printer.print(expr))->value << endl; - - for(Token t : tokens){ - //cout << "{type: " << enum_mapping[t.type] << ", value: " << t.lexeme << "}" << endl; - } } diff --git a/testthing b/testthing index a1ced34..ded6190 100644 --- a/testthing +++ b/testthing @@ -1,5 +1,5 @@ template -struct BinaryExpr : Expr, Visitor +struct BinaryExpr : Expr, ExprVisitor { const Expr left; const Token oper; @@ -8,36 +8,36 @@ struct BinaryExpr : Expr, Visitor BinaryExpr(Expr left, Token oper, Expr right) : left(left), oper(oper), right(right) { } - T accept(Visitor visitor){ + T accept(ExprVisitor visitor){ return visitor.visitBinaryExpr(this); } }; template -struct GroupingExpr : Expr, Visitor +struct GroupingExpr : Expr, ExprVisitor { const Expr expression; GroupingExpr(Expr expression) : expression(expression) { } - T accept(Visitor visitor){ + T accept(ExprVisitor visitor){ return visitor.visitGroupingExpr(this); } }; template -struct LiteralExpr : Expr, Visitor +struct LiteralExpr : Expr, ExprVisitor { const std::string value; LiteralExpr(std::string value) : value(value) { } - T accept(Visitor visitor){ + T accept(ExprVisitor visitor){ return visitor.visitLiteralExpr(this); } }; template -struct UnaryExpr : Expr, Visitor +struct UnaryExpr : Expr, ExprVisitor { const Token oper; const Expr right; @@ -45,7 +45,7 @@ struct UnaryExpr : Expr, Visitor UnaryExpr(Token oper, Expr right) : oper(oper), right(right) { } - T accept(Visitor visitor){ + T accept(ExprVisitor visitor){ return visitor.visitUnaryExpr(this); } };