diff --git a/Makefile b/Makefile index 6b956dd..0f0b78e 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ OBJ_FILES := $(patsubst $(SRC_DIR)/%.cpp,$(BUILD_DIR)/%.o,$(CPP_FILES)) $(shell mkdir -p $(dir $(OBJ_FILES))) # Default target -all: clean $(BUILD_DIR)/bob +all: build run # Rule to create necessary directories $(DIRS): @@ -37,8 +37,12 @@ $(BUILD_DIR)/bob: $(OBJ_FILES) $(CC) $(CFLAGS) $^ -o $@ +run: ./$(BUILD_DIR)/bob +build: clean $(BUILD_DIR)/bob + + # Clean build directory clean: rm -rf $(BUILD_DIR)/* diff --git a/headers/ASTPrinter.h b/headers/ASTPrinter.h index 64a823f..9d5f93d 100644 --- a/headers/ASTPrinter.h +++ b/headers/ASTPrinter.h @@ -6,14 +6,14 @@ #include -class ASTPrinter : public Visitor +class ASTPrinter : Visitor { - sptr(Object) visitBinaryExpr(BinaryExpr* expression) override; - sptr(Object) visitGroupingExpr(GroupingExpr* expression) override; - sptr(Object) visitLiteralExpr(LiteralExpr* expression) override; - sptr(Object) visitUnaryExpr(UnaryExpr* expression) override; + 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; public: - sptr(Object) print(Expr* expr); + sptr(Object) print(sptr(Expr) expr); private: sptr(Object) parenthesize(std::string name, std::vector exprs); diff --git a/headers/Expression.h b/headers/Expression.h index d87497e..39c6b23 100644 --- a/headers/Expression.h +++ b/headers/Expression.h @@ -15,10 +15,10 @@ struct UnaryExpr; struct Visitor { - virtual sptr(Object) visitBinaryExpr(BinaryExpr* expression) = 0; - virtual sptr(Object) visitGroupingExpr(GroupingExpr* expression) = 0; - virtual sptr(Object) visitLiteralExpr(LiteralExpr* expression) = 0; - virtual sptr(Object) visitUnaryExpr(UnaryExpr* expression) = 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; }; @@ -28,7 +28,7 @@ struct Expr{ }; -struct BinaryExpr : Expr +struct BinaryExpr : Expr, public std::enable_shared_from_this { const std::shared_ptr left; const Token oper; @@ -38,11 +38,11 @@ struct BinaryExpr : Expr { } sptr(Object) accept(Visitor* visitor) override{ - return visitor->visitBinaryExpr(this); + return visitor->visitBinaryExpr(shared_from_this() ); } }; -struct GroupingExpr : Expr +struct GroupingExpr : Expr, public std::enable_shared_from_this { const std::shared_ptr expression; @@ -50,23 +50,24 @@ struct GroupingExpr : Expr { } sptr(Object) accept(Visitor* visitor) override{ - return visitor->visitGroupingExpr(this); + return visitor->visitGroupingExpr(shared_from_this()); } }; -struct LiteralExpr : Expr +struct LiteralExpr : Expr, public std::enable_shared_from_this { const std::string value; const bool isNumber; - LiteralExpr(std::string value, bool isNumber) : value(value), isNumber(isNumber) + const bool isNull; + LiteralExpr(std::string value, bool isNumber, bool isNull) : value(value), isNumber(isNumber), isNull(isNull) { } sptr(Object) accept(Visitor* visitor) override{ - return visitor->visitLiteralExpr(this); + return visitor->visitLiteralExpr(shared_from_this()); } }; -struct UnaryExpr : Expr +struct UnaryExpr : Expr, public std::enable_shared_from_this { const Token oper; const std::shared_ptr right; @@ -75,7 +76,7 @@ struct UnaryExpr : Expr { } sptr(Object) accept(Visitor* visitor) override{ - return visitor->visitUnaryExpr(this); + return visitor->visitUnaryExpr(shared_from_this()); } }; diff --git a/headers/Interpreter.h b/headers/Interpreter.h new file mode 100644 index 0000000..83e0c4f --- /dev/null +++ b/headers/Interpreter.h @@ -0,0 +1,23 @@ +#pragma once +#include "Expression.h" +#include "helperFunctions/ShortHands.h" +#include "TypeWrapper.h" + +class Interpreter : Visitor +{ + +public: + sptr(Object) visitBinaryExpr(sptr(BinaryExpr) expression) override; + sptr(Object) visitGroupingExpr(sptr(GroupingExpr) expression) override; + sptr(Object) visitLiteralExpr(sptr(LiteralExpr) expression) override; + sptr(Object) visitUnaryExpr(sptr(UnaryExpr) expression) override; + + void interpret(sptr(Expr) expr); + +private: + 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); +}; diff --git a/headers/TypeWrapper.h b/headers/TypeWrapper.h index 8145cbc..0bf34fa 100644 --- a/headers/TypeWrapper.h +++ b/headers/TypeWrapper.h @@ -5,14 +5,25 @@ struct Object virtual ~Object(){}; }; -struct Number : public Object +struct Number : Object { double value; explicit Number(double value) : value(value) {} }; -struct String : public Object +struct String : Object { std::string value; explicit String(std::string str) : value(str) {} +}; + +struct Boolean : Object +{ + bool value; + explicit Boolean(bool value) : value(value) {} +}; + +struct None : public Object +{ + }; \ No newline at end of file diff --git a/headers/bob.h b/headers/bob.h index 2d9cb3d..af73f19 100644 --- a/headers/bob.h +++ b/headers/bob.h @@ -4,6 +4,7 @@ #include #include #include "../headers/Lexer.h" +#include "../headers/Interpreter.h" #define VERSION "0.0.1" @@ -11,6 +12,7 @@ class Bob { public: Lexer lexer; + Interpreter interpreter; public: void runFile(std::string path); diff --git a/source/ASTPrinter.cpp b/source/ASTPrinter.cpp index 18f849c..212fcdb 100644 --- a/source/ASTPrinter.cpp +++ b/source/ASTPrinter.cpp @@ -4,22 +4,22 @@ #include "../headers/ASTPrinter.h" -sptr(Object) ASTPrinter::visitBinaryExpr(BinaryExpr* expression){ +sptr(Object) ASTPrinter::visitBinaryExpr(sptr(BinaryExpr) expression){ std::cout << expression->left << std::endl; return parenthesize(expression->oper.lexeme, std::vector{expression->left, expression->right}); } -sptr(Object) ASTPrinter::visitGroupingExpr(GroupingExpr* expression){ +sptr(Object) ASTPrinter::visitGroupingExpr(sptr(GroupingExpr) expression){ return parenthesize("group", std::vector{expression->expression}); } -sptr(Object) ASTPrinter::visitLiteralExpr(LiteralExpr* expression){ +sptr(Object) ASTPrinter::visitLiteralExpr(sptr(LiteralExpr) expression){ return msptr(String)(expression->value); } -sptr(Object) ASTPrinter::visitUnaryExpr(UnaryExpr* expression){ +sptr(Object) ASTPrinter::visitUnaryExpr(sptr(UnaryExpr) expression){ return parenthesize(expression->oper.lexeme, std::vector{expression->right}); } -sptr(Object) ASTPrinter::print(Expr *expr) { +sptr(Object) ASTPrinter::print(sptr(Expr) expr) { return expr->accept(this); } diff --git a/source/Interpreter.cpp b/source/Interpreter.cpp new file mode 100644 index 0000000..696c0a7 --- /dev/null +++ b/source/Interpreter.cpp @@ -0,0 +1,206 @@ +// +// Created by Bobby Lucero on 5/27/23. +// +#include +#include +#include +#include +#include +#include "../headers/Interpreter.h" + + +sptr(Object) Interpreter::visitLiteralExpr(sptr(LiteralExpr) expr) { + if(expr->isNull) return msptr(None)(); + if(expr->isNumber) return msptr(Number)(std::stod(expr->value)); + return msptr(String)(expr->value); +} + +sptr(Object) Interpreter::visitGroupingExpr(sptr(GroupingExpr) expression) { + + return evaluate(expression->expression); +} + +sptr(Object) Interpreter::visitUnaryExpr(sptr(UnaryExpr) expression) +{ + sptr(Object) right = evaluate(expression->right); + + if(expression->oper.type == MINUS) + { + if(std::dynamic_pointer_cast(right)) + { + double value = std::dynamic_pointer_cast(right)->value; + return msptr(Number)(-value); + } + else + { + throw std::runtime_error("Operand must be a number when using: " + expression->oper.lexeme); + } + + } + + if(expression->oper.type == BANG) + { + return msptr(Boolean)(!isTruthy(right)); + } + +} + +sptr(Object) Interpreter::visitBinaryExpr(sptr(BinaryExpr) expression) +{ + sptr(Object) left = evaluate(expression->left); + sptr(Object) right = evaluate(expression->right); + + switch (expression->oper.type) { + case BANG_EQUAL: + return msptr(Boolean)(!isEqual(left, right)); + case DOUBLE_EQUAL: + return msptr(Boolean)(isEqual(left, right)); + default: + ; + } + + if(std::dynamic_pointer_cast(left) && std::dynamic_pointer_cast(right)) + { + double left_double = std::dynamic_pointer_cast(left)->value; + double right_double = std::dynamic_pointer_cast(right)->value; + switch (expression->oper.type) { + case GREATER: + return msptr(Boolean)(left_double > right_double); + case GREATER_EQUAL: + return msptr(Boolean)(left_double >= right_double); + case LESS: + return msptr(Boolean)(left_double < right_double); + case LESS_EQUAL: + return msptr(Boolean)(left_double <= right_double); + case MINUS: + return msptr(Number)(left_double - right_double); + case PLUS: + return msptr(Number)(left_double + right_double); + case SLASH: + return msptr(Number)(left_double / right_double); + case STAR: + return msptr(Number)(left_double * right_double); + default: + return msptr(None)(); //unreachable + } + } + else if(std::dynamic_pointer_cast(left) && std::dynamic_pointer_cast(right)) + { + std::string left_string = std::dynamic_pointer_cast(left)->value; + std::string right_string = std::dynamic_pointer_cast(right)->value; + return msptr(String)(left_string + right_string); + } + else + { + throw std::runtime_error("Operands must be of same type when using: " + expression->oper.lexeme); + } + +} + +sptr(Object) Interpreter::evaluate(sptr(Expr) expr) { + return expr->accept(this); +} + +bool Interpreter::isTruthy(sptr(Object) object) { + + if(auto boolean = std::dynamic_pointer_cast(object)) + { + boolean->value; + } + + if(auto obj = std::dynamic_pointer_cast(object)) + { + return false; + } + + return true; +} + +bool Interpreter::isEqual(sptr(Object) a, sptr(Object) b) { + if(auto left = std::dynamic_pointer_cast(a)) + { + if(auto right = std::dynamic_pointer_cast(b)) + { + return left->value == right->value; + } + + return false; + } + else if(auto left = std::dynamic_pointer_cast(a)) + { + if(auto right = std::dynamic_pointer_cast(b)) + { + return left->value == right->value; + } + + return false; + } + else if(auto left = std::dynamic_pointer_cast(a)) + { + if(auto right = std::dynamic_pointer_cast(b)) + { + return left->value == right->value; + } + + return false; + } + else if(auto left = std::dynamic_pointer_cast(a)) + { + if(auto right = std::dynamic_pointer_cast(b)) + { + return true; + } + + return false; + } +} + +void Interpreter::interpret(std::shared_ptr expr) { + + sptr(Object) value = evaluate(std::move(expr)); + std::cout << stringify(value) << std::endl; + +} + +std::string Interpreter::stringify(std::shared_ptr object) { + if(std::dynamic_pointer_cast(object)) + { + return "None"; + } + else if(auto num = std::dynamic_pointer_cast(object)) + { + double integral = num->value; + double fractional = std::modf(num->value, &integral); + + std::stringstream ss; + if(std::abs(fractional) < std::numeric_limits::epsilon()) + { + ss << std::fixed << std::setprecision(0) << integral; + + return ss.str(); + } + else + { + ss << std::fixed << std::setprecision(std::numeric_limits::digits10) << num->value;\ + std::string str = ss.str(); + str.erase(str.find_last_not_of('0') + 1, std::string::npos); + if (str.back() == '.') { + str.pop_back(); + } + + return str; + } + } + else if(auto string = std::dynamic_pointer_cast(object)) + { + return string->value; + } + else if(auto Bool = std::dynamic_pointer_cast(object)) + { + return Bool->value == 1 ? "true" : "false"; + } +} + + + + diff --git a/source/Lexer.cpp b/source/Lexer.cpp index 5287809..5dd40ea 100644 --- a/source/Lexer.cpp +++ b/source/Lexer.cpp @@ -120,7 +120,7 @@ std::vector Lexer::Tokenize(std::string source){ } else if(t == '"') { - std::string str = std::string(1, src[0]); + std::string str; advance(); while(!src.empty() && src[0] != '"') { @@ -134,7 +134,7 @@ std::vector Lexer::Tokenize(std::string source){ } else if(src[0] == '"') { - str += '"'; + advance(); tokens.push_back(Token{STRING, str, line}); } diff --git a/source/Parser.cpp b/source/Parser.cpp index 518879c..131e714 100644 --- a/source/Parser.cpp +++ b/source/Parser.cpp @@ -47,7 +47,6 @@ sptr(Expr) Parser::term() while(match({MINUS, PLUS})) { - std::cout << "Found comparison" << std::endl; Token op = previous(); sptr(Expr) right = factor(); expr = msptr(BinaryExpr)(expr, op, right); @@ -84,12 +83,12 @@ sptr(Expr) Parser::unary() sptr(Expr) Parser::primary() { - if(match({FALSE})) return msptr(LiteralExpr)("true", false); - if(match({TRUE})) return msptr(LiteralExpr)("true", false); - if(match({NONE})) return msptr(LiteralExpr)("none", false); + if(match({FALSE})) return msptr(LiteralExpr)("true", false, false); + if(match({TRUE})) return msptr(LiteralExpr)("true", false, false); + if(match({NONE})) return msptr(LiteralExpr)("none", false, false); - if(match({NUMBER})) return msptr(LiteralExpr)(previous().lexeme, true); - if(match({STRING})) return msptr(LiteralExpr)(previous().lexeme, false); + if(match({NUMBER})) return msptr(LiteralExpr)(previous().lexeme, true, false); + if(match({STRING})) return msptr(LiteralExpr)(previous().lexeme, false, false); if(match({OPEN_PAREN})) { diff --git a/source/bob.cpp b/source/bob.cpp index 689e1c2..25a5b98 100644 --- a/source/bob.cpp +++ b/source/bob.cpp @@ -51,11 +51,7 @@ void Bob::run(string source) vector tokens = lexer.Tokenize(source); Parser p(tokens); shared_ptr expr = p.parse(); - - - ASTPrinter printer; - - cout << dynamic_pointer_cast(printer.print(expr.get()))->value << endl; + interpreter.interpret(expr); for(Token t : tokens){