Tidy code, interactive interpreter prints out result of expression without explicit print statement
This commit is contained in:
parent
fe26a7c2e0
commit
942c1e323b
8
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
8
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<profile version="1.0">
|
||||||
|
<option name="myName" value="Project Default" />
|
||||||
|
<inspection_tool class="ClangTidy" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="clangTidyChecks" value="-*,bugprone-argument-comment,bugprone-assert-side-effect,bugprone-bad-signal-to-kill-thread,bugprone-branch-clone,bugprone-copy-constructor-init,bugprone-dangling-handle,bugprone-dynamic-static-initializers,bugprone-fold-init-type,bugprone-forward-declaration-namespace,bugprone-forwarding-reference-overload,bugprone-inaccurate-erase,bugprone-incorrect-roundings,bugprone-integer-division,bugprone-lambda-function-name,bugprone-macro-parentheses,bugprone-macro-repeated-side-effects,bugprone-misplaced-operator-in-strlen-in-alloc,bugprone-misplaced-pointer-arithmetic-in-alloc,bugprone-misplaced-widening-cast,bugprone-move-forwarding-reference,bugprone-multiple-statement-macro,bugprone-no-escape,bugprone-not-null-terminated-result,bugprone-parent-virtual-call,bugprone-posix-return,bugprone-reserved-identifier,bugprone-sizeof-container,bugprone-sizeof-expression,bugprone-spuriously-wake-up-functions,bugprone-string-constructor,bugprone-string-integer-assignment,bugprone-string-literal-with-embedded-nul,bugprone-suspicious-enum-usage,bugprone-suspicious-include,bugprone-suspicious-memory-comparison,bugprone-suspicious-memset-usage,bugprone-suspicious-missing-comma,bugprone-suspicious-semicolon,bugprone-suspicious-string-compare,bugprone-swapped-arguments,bugprone-terminating-continue,bugprone-throw-keyword-missing,bugprone-too-small-loop-variable,bugprone-undefined-memory-manipulation,bugprone-undelegated-constructor,bugprone-unhandled-self-assignment,bugprone-unused-raii,bugprone-unused-return-value,bugprone-use-after-move,bugprone-virtual-near-miss,cert-dcl21-cpp,cert-dcl58-cpp,cert-err34-c,cert-err52-cpp,cert-err60-cpp,cert-flp30-c,cert-msc50-cpp,cert-msc51-cpp,cert-str34-c,cppcoreguidelines-interfaces-global-init,cppcoreguidelines-narrowing-conversions,cppcoreguidelines-pro-type-member-init,cppcoreguidelines-pro-type-static-cast-downcast,cppcoreguidelines-slicing,google-default-arguments,google-explicit-constructor,google-runtime-operator,hicpp-exception-baseclass,hicpp-multiway-paths-covered,misc-misplaced-const,misc-new-delete-overloads,misc-non-copyable-objects,misc-throw-by-value-catch-by-reference,misc-unconventional-assign-operator,misc-uniqueptr-reset-release,modernize-avoid-bind,modernize-concat-nested-namespaces,modernize-deprecated-headers,modernize-deprecated-ios-base-aliases,modernize-loop-convert,modernize-make-shared,modernize-make-unique,modernize-pass-by-value,modernize-raw-string-literal,modernize-redundant-void-arg,modernize-replace-auto-ptr,modernize-replace-disallow-copy-and-assign-macro,modernize-replace-random-shuffle,modernize-return-braced-init-list,modernize-shrink-to-fit,modernize-unary-static-assert,modernize-use-auto,modernize-use-bool-literals,modernize-use-emplace,modernize-use-equals-default,modernize-use-equals-delete,modernize-use-nodiscard,modernize-use-noexcept,modernize-use-nullptr,modernize-use-override,modernize-use-transparent-functors,modernize-use-uncaught-exceptions,mpi-buffer-deref,mpi-type-mismatch,openmp-use-default-none,performance-faster-string-find,performance-for-range-copy,performance-implicit-conversion-in-loop,performance-inefficient-algorithm,performance-inefficient-string-concatenation,performance-inefficient-vector-operation,performance-move-const-arg,performance-move-constructor-init,performance-no-automatic-move,performance-noexcept-move-constructor,performance-trivially-destructible,performance-type-promotion-in-math-fn,performance-unnecessary-copy-initialization,performance-unnecessary-value-param,portability-simd-intrinsics,readability-avoid-const-params-in-decls,readability-const-return-type,readability-container-size-empty,readability-convert-member-functions-to-static,readability-delete-null-pointer,readability-deleted-default,readability-inconsistent-declaration-parameter-name,readability-make-member-function-const,readability-misleading-indentation,readability-misplaced-array-index,readability-non-const-parameter,readability-redundant-control-flow,readability-redundant-declaration,readability-redundant-function-ptr-dereference,readability-redundant-smartptr-get,readability-redundant-string-cstr,readability-redundant-string-init,readability-simplify-subscript-expr,readability-static-accessed-through-instance,readability-static-definition-in-anonymous-namespace,readability-string-compare,readability-uniqueptr-delete-release" />
|
||||||
|
</inspection_tool>
|
||||||
|
</profile>
|
||||||
|
</component>
|
||||||
@ -28,7 +28,7 @@ struct ExprVisitor
|
|||||||
|
|
||||||
struct Expr{
|
struct Expr{
|
||||||
virtual sptr(Object) accept(ExprVisitor* visitor) = 0;
|
virtual sptr(Object) accept(ExprVisitor* visitor) = 0;
|
||||||
virtual ~Expr(){}
|
virtual ~Expr() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AssignExpr : Expr, public std::enable_shared_from_this<AssignExpr>
|
struct AssignExpr : Expr, public std::enable_shared_from_this<AssignExpr>
|
||||||
|
|||||||
@ -23,25 +23,21 @@ public:
|
|||||||
|
|
||||||
void interpret(std::vector<sptr(Stmt)> statements);
|
void interpret(std::vector<sptr(Stmt)> statements);
|
||||||
|
|
||||||
Interpreter(){
|
explicit Interpreter(bool IsInteractive) : IsInteractive(IsInteractive){
|
||||||
environment = msptr(Environment)();
|
environment = msptr(Environment)();
|
||||||
}
|
}
|
||||||
|
~Interpreter();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
sptr(Environment) environment;
|
sptr(Environment) environment;
|
||||||
|
bool IsInteractive;
|
||||||
|
|
||||||
|
|
||||||
sptr(Object) evaluate(sptr(Expr) expr);
|
sptr(Object) evaluate(sptr(Expr) expr);
|
||||||
bool isTruthy(sptr(Object) object);
|
bool isTruthy(sptr(Object) object);
|
||||||
bool isEqual(sptr(Object) a, sptr(Object) b);
|
bool isEqual(sptr(Object) a, sptr(Object) b);
|
||||||
|
|
||||||
std::string stringify(sptr(Object) object);
|
std::string stringify(sptr(Object) object);
|
||||||
|
|
||||||
bool isWholeNumer(double num);
|
bool isWholeNumer(double num);
|
||||||
|
|
||||||
void execute(std::shared_ptr<Stmt> statement);
|
void execute(std::shared_ptr<Stmt> statement);
|
||||||
|
|
||||||
void executeBlock(std::vector<std::shared_ptr<Stmt>> statements, std::shared_ptr<Environment> env);
|
void executeBlock(std::vector<std::shared_ptr<Stmt>> statements, std::shared_ptr<Environment> env);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -8,7 +8,7 @@ enum TokenType{
|
|||||||
OPEN_PAREN, CLOSE_PAREN, OPEN_BRACE, CLOSE_BRACE,
|
OPEN_PAREN, CLOSE_PAREN, OPEN_BRACE, CLOSE_BRACE,
|
||||||
COMMA, DOT, MINUS, PLUS, SEMICOLON, SLASH, STAR, PERCENT,
|
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,
|
BANG, BANG_EQUAL,
|
||||||
EQUAL, DOUBLE_EQUAL,
|
EQUAL, DOUBLE_EQUAL,
|
||||||
@ -56,7 +56,8 @@ const std::map<std::string, TokenType> KEYWORDS {
|
|||||||
{"this", THIS},
|
{"this", THIS},
|
||||||
{"none", NONE},
|
{"none", NONE},
|
||||||
{"return", RETURN},
|
{"return", RETURN},
|
||||||
{"print", PRINT}
|
{"print", PRINT},
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Token
|
struct Token
|
||||||
|
|||||||
@ -26,14 +26,14 @@ private:
|
|||||||
sptr(Expr) unary();
|
sptr(Expr) unary();
|
||||||
sptr(Expr) primary();
|
sptr(Expr) primary();
|
||||||
|
|
||||||
bool match(std::vector<TokenType> types);
|
bool match(const std::vector<TokenType>& types);
|
||||||
|
|
||||||
bool check(TokenType type);
|
bool check(TokenType type);
|
||||||
bool isAtEnd();
|
bool isAtEnd();
|
||||||
Token advance();
|
Token advance();
|
||||||
Token peek();
|
Token peek();
|
||||||
Token previous();
|
Token previous();
|
||||||
Token consume(TokenType type, std::string message);
|
Token consume(TokenType type, const std::string& message);
|
||||||
sptr(Stmt) statement();
|
sptr(Stmt) statement();
|
||||||
|
|
||||||
void sync();
|
void sync();
|
||||||
|
|||||||
@ -12,14 +12,19 @@ class Bob
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Lexer lexer;
|
Lexer lexer;
|
||||||
Interpreter interpreter;
|
Interpreter* interpreter;
|
||||||
|
|
||||||
|
~Bob()
|
||||||
|
{
|
||||||
|
delete interpreter;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void runFile(std::string path);
|
void runFile(const std::string& path);
|
||||||
|
|
||||||
void runPrompt();
|
void runPrompt();
|
||||||
|
|
||||||
void error(int line, std::string message);
|
void error(int line, const std::string& message);
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@ -58,6 +58,19 @@ sptr(Object) Interpreter::visitUnaryExpr(sptr(UnaryExpr) expression)
|
|||||||
return msptr(Boolean)(!isTruthy(right));
|
return msptr(Boolean)(!isTruthy(right));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(expression->oper.type == BIN_NOT)
|
||||||
|
{
|
||||||
|
if(std::dynamic_pointer_cast<Number>(right))
|
||||||
|
{
|
||||||
|
double value = std::dynamic_pointer_cast<Number>(right)->value;
|
||||||
|
return msptr(Number)((~(long)value));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Operand must be an int when using: " + expression->oper.lexeme);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//unreachable
|
//unreachable
|
||||||
throw std::runtime_error("Invalid unary expression");
|
throw std::runtime_error("Invalid unary expression");
|
||||||
|
|
||||||
@ -162,7 +175,10 @@ void Interpreter::visitBlockStmt(std::shared_ptr<BlockStmt> statement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::visitExpressionStmt(sptr(ExpressionStmt) 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) {
|
void Interpreter::visitPrintStmt(sptr(PrintStmt) statement) {
|
||||||
@ -336,6 +352,8 @@ bool Interpreter::isWholeNumer(double num) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Interpreter::~Interpreter() = default;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -68,6 +68,11 @@ std::vector<Token> Lexer::Tokenize(std::string source){
|
|||||||
tokens.push_back(Token{PERCENT, std::string(1, t), line});
|
tokens.push_back(Token{PERCENT, std::string(1, t), line});
|
||||||
advance();
|
advance();
|
||||||
}
|
}
|
||||||
|
else if(t == '~')
|
||||||
|
{
|
||||||
|
tokens.push_back(Token{BIN_NOT, std::string(1, t), line});
|
||||||
|
advance();
|
||||||
|
}
|
||||||
else if(t == '=')
|
else if(t == '=')
|
||||||
{
|
{
|
||||||
std::string token = std::string(1, t);
|
std::string token = std::string(1, t);
|
||||||
@ -88,9 +93,19 @@ std::vector<Token> Lexer::Tokenize(std::string source){
|
|||||||
{
|
{
|
||||||
std::string token = std::string(1, t);
|
std::string token = std::string(1, t);
|
||||||
advance();
|
advance();
|
||||||
bool match = matchOn('=');
|
if(matchOn('='))
|
||||||
token += match ? "=" : "";
|
{
|
||||||
tokens.push_back(Token{match ? LESS_EQUAL : LESS, token, line});
|
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 == '>')
|
else if(t == '>')
|
||||||
{
|
{
|
||||||
|
|||||||
@ -96,7 +96,7 @@ sptr(Expr) Parser::factor()
|
|||||||
|
|
||||||
sptr(Expr) Parser::unary()
|
sptr(Expr) Parser::unary()
|
||||||
{
|
{
|
||||||
if(match({BANG, MINUS}))
|
if(match({BANG, MINUS, BIN_NOT}))
|
||||||
{
|
{
|
||||||
Token op = previous();
|
Token op = previous();
|
||||||
sptr(Expr) right = unary();
|
sptr(Expr) right = unary();
|
||||||
@ -144,6 +144,32 @@ std::vector<sptr(Stmt)> 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()
|
sptr(Stmt) Parser::statement()
|
||||||
{
|
{
|
||||||
if(match({PRINT})) return printStatement();
|
if(match({PRINT})) return printStatement();
|
||||||
@ -178,35 +204,11 @@ std::vector<sptr(Stmt)> Parser::block()
|
|||||||
return statements;
|
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<TokenType> types) {
|
|
||||||
|
bool Parser::match(const std::vector<TokenType>& types) {
|
||||||
for(TokenType t : types)
|
for(TokenType t : types)
|
||||||
{
|
{
|
||||||
if(check(t))
|
if(check(t))
|
||||||
@ -241,10 +243,10 @@ Token Parser::previous() {
|
|||||||
return tokens[current - 1];
|
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();
|
if(check(type)) return advance();
|
||||||
|
|
||||||
throw std::runtime_error(peek().lexeme +": "+ message);
|
throw std::runtime_error("Unexpected symbol '" + peek().lexeme +"': "+ message);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Parser::sync()
|
void Parser::sync()
|
||||||
|
|||||||
@ -1,13 +1,16 @@
|
|||||||
|
#include <utility>
|
||||||
|
|
||||||
#include "../headers/bob.h"
|
#include "../headers/bob.h"
|
||||||
#include "../headers/Parser.h"
|
#include "../headers/Parser.h"
|
||||||
#include "../headers/ASTPrinter.h"
|
#include "../headers/ASTPrinter.h"
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
void Bob::runFile(string path)
|
void Bob::runFile(const string& path)
|
||||||
{
|
{
|
||||||
|
this->interpreter = new Interpreter(false);
|
||||||
ifstream file = ifstream(path);
|
ifstream file = ifstream(path);
|
||||||
|
|
||||||
string source = "";
|
string source;
|
||||||
|
|
||||||
if(file.is_open()){
|
if(file.is_open()){
|
||||||
source = string(istreambuf_iterator<char>(file), istreambuf_iterator<char>());
|
source = string(istreambuf_iterator<char>(file), istreambuf_iterator<char>());
|
||||||
@ -23,6 +26,8 @@ void Bob::runFile(string path)
|
|||||||
|
|
||||||
void Bob::runPrompt()
|
void Bob::runPrompt()
|
||||||
{
|
{
|
||||||
|
this->interpreter = new Interpreter(true);
|
||||||
|
|
||||||
cout << "Bob v" << VERSION << ", 2023" << endl;
|
cout << "Bob v" << VERSION << ", 2023" << endl;
|
||||||
for(;;)
|
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)
|
void Bob::run(string source)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
vector<Token> tokens = lexer.Tokenize(source);
|
vector<Token> tokens = lexer.Tokenize(std::move(source));
|
||||||
// for(Token t : tokens){
|
// for(Token t : tokens){
|
||||||
// cout << "{type: " << enum_mapping[t.type] << ", value: " << t.lexeme << "}" << endl;
|
// cout << "{type: " << enum_mapping[t.type] << ", value: " << t.lexeme << "}" << endl;
|
||||||
// }
|
// }
|
||||||
@ -56,7 +61,7 @@ void Bob::run(string source)
|
|||||||
|
|
||||||
Parser p(tokens);
|
Parser p(tokens);
|
||||||
vector<sptr(Stmt)> statements = p.parse();
|
vector<sptr(Stmt)> statements = p.parse();
|
||||||
interpreter.interpret(statements);
|
interpreter->interpret(statements);
|
||||||
//cout << "=========================" << endl;
|
//cout << "=========================" << endl;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,15 +1,13 @@
|
|||||||
//
|
//
|
||||||
// Created by Bobby Lucero on 5/21/23.
|
// Created by Bobby Lucero on 5/21/23.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
#include "../headers/bob.h"
|
#include "../headers/bob.h"
|
||||||
|
|
||||||
int main(){
|
int main(){
|
||||||
Bob bobLang;
|
Bob bobLang;
|
||||||
|
|
||||||
bobLang.runFile("source.bob");
|
bobLang.runFile("source.bob");
|
||||||
//bobLang.runPrompt();
|
bobLang.runPrompt();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user