Added variable assignments

This commit is contained in:
Bobby Lucero 2023-05-31 01:48:50 -04:00
parent 03bfae9eb4
commit 7e0cead697
16 changed files with 376 additions and 53 deletions

View File

@ -6,12 +6,16 @@
#include <initializer_list>
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:

21
headers/Environment.h Normal file
View File

@ -0,0 +1,21 @@
#pragma once
#include <unordered_map>
#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<Object> get(Token name);
private:
std::unordered_map<std::string, sptr(Object)> variables;
};

View File

@ -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<AssignExpr>
{
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<BinaryExpr>
{
@ -37,7 +54,7 @@ struct BinaryExpr : Expr, public std::enable_shared_from_this<BinaryExpr>
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<GroupingExpr>
{
const std::shared_ptr<Expr> 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>
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>
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<VarExpr>
{
const Token name;
explicit VarExpr(Token name) : name(name){};
sptr(Object) accept(ExprVisitor* visitor) override
{
return visitor->visitVariableExpr(shared_from_this());
}
};
////

View File

@ -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<sptr(Stmt)> 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<Stmt> statement);
};

View File

@ -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<std::string, TokenType> KEYWORDS {
{"super", SUPER},
{"this", THIS},
{"none", NONE},
{"return", RETURN}
{"return", RETURN},
{"print", PRINT}
};
struct Token

View File

@ -3,6 +3,7 @@
#include <vector>
#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<Token> tokens) : tokens(std::move(tokens)){};
sptr(Expr) parse();
std::vector<sptr(Stmt)> 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<Stmt> printStatement();
std::shared_ptr<Stmt> expressionStatement();
std::shared_ptr<Stmt> declaration();
std::shared_ptr<Stmt> varDeclaration();
std::shared_ptr<Expr> assignment();
};

64
headers/Statement.h Normal file
View File

@ -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<ExpressionStmt>
{
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<PrintStmt>
{
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<VarStmt>
{
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());
}
};

View File

@ -1,5 +1,6 @@
#pragma once
#include <string>
#include <iostream>
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

View File

@ -1,3 +1 @@
//10 + 10
//0xFF + 0xFF
0xFF + 0xFF00 == 0xFFFF
10 10;

View File

@ -39,3 +39,11 @@ sptr(Object) ASTPrinter::parenthesize(std::string name, std::vector<sptr(Expr)>
return msptr(String)(builder);
}
sptr(Object) ASTPrinter::visitAssignExpr(std::shared_ptr<AssignExpr> expr) {
return std::shared_ptr<String>();
}
sptr(Object) ASTPrinter::visitVariableExpr(std::shared_ptr<VarExpr> expr) {
return std::shared_ptr<String>();
}

34
source/Environment.cpp Normal file
View File

@ -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<Object> value) {
if(variables.count(name.lexeme) > 0)
{
variables[name.lexeme] = value;
return;
}
throw std::runtime_error("Undefined variable '" + name.lexeme + "'.");
}

View File

@ -6,6 +6,7 @@
#include <cmath>
#include <iomanip>
#include <limits>
#include <cmath>
#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<Number>(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<None>(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<sptr(Stmt)> 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> 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> object) {
if(std::dynamic_pointer_cast<None>(object))
{
return "None";
return "none";
}
else if(auto num = std::dynamic_pointer_cast<Number>(object))
{
@ -267,3 +314,8 @@ bool Interpreter::isWholeNumer(double num) {

View File

@ -63,6 +63,11 @@ std::vector<Token> 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);

View File

@ -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<VarExpr>(expr))
{
Token name = std::dynamic_pointer_cast<VarExpr>(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<sptr(Stmt)> Parser::parse() {
return expression();
std::vector<sptr(Stmt)> 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);
}

View File

@ -49,17 +49,16 @@ void Bob::run(string source)
{
try {
vector<Token> tokens = lexer.Tokenize(source);
// for(Token t : tokens){
// cout << "{type: " << enum_mapping[t.type] << ", value: " << t.lexeme << "}" << endl;
// }
Parser p(tokens);
shared_ptr<Expr> expr = p.parse();
interpreter.interpret(expr);
vector<sptr(Stmt)> statements = p.parse();
interpreter.interpret(statements);
//cout << "=========================" << endl;
ASTPrinter printer;
//cout << dynamic_pointer_cast<String>(printer.print(expr))->value << endl;
for(Token t : tokens){
//cout << "{type: " << enum_mapping[t.type] << ", value: " << t.lexeme << "}" << endl;
}
}

View File

@ -1,5 +1,5 @@
template <typename T>
struct BinaryExpr : Expr<T>, Visitor<T>
struct BinaryExpr : Expr<T>, ExprVisitor<T>
{
const Expr<T> left;
const Token oper;
@ -8,36 +8,36 @@ struct BinaryExpr : Expr<T>, Visitor<T>
BinaryExpr(Expr<T> left, Token oper, Expr<T> right) : left(left), oper(oper), right(right)
{
}
T accept(Visitor<T> visitor){
T accept(ExprVisitor<T> visitor){
return visitor.visitBinaryExpr(this);
}
};
template <typename T>
struct GroupingExpr : Expr<T>, Visitor<T>
struct GroupingExpr : Expr<T>, ExprVisitor<T>
{
const Expr<T> expression;
GroupingExpr(Expr<T> expression) : expression(expression)
{
}
T accept(Visitor<T> visitor){
T accept(ExprVisitor<T> visitor){
return visitor.visitGroupingExpr(this);
}
};
template <typename T>
struct LiteralExpr : Expr<T>, Visitor<T>
struct LiteralExpr : Expr<T>, ExprVisitor<T>
{
const std::string value;
LiteralExpr(std::string value) : value(value)
{
}
T accept(Visitor<T> visitor){
T accept(ExprVisitor<T> visitor){
return visitor.visitLiteralExpr(this);
}
};
template <typename T>
struct UnaryExpr : Expr<T>, Visitor<T>
struct UnaryExpr : Expr<T>, ExprVisitor<T>
{
const Token oper;
const Expr<T> right;
@ -45,7 +45,7 @@ struct UnaryExpr : Expr<T>, Visitor<T>
UnaryExpr(Token oper, Expr<T> right) : oper(oper), right(right)
{
}
T accept(Visitor<T> visitor){
T accept(ExprVisitor<T> visitor){
return visitor.visitUnaryExpr(this);
}
};