diff --git a/include/Function.h b/include/Function.h index bae1fd8..12d66f8 100644 --- a/include/Function.h +++ b/include/Function.h @@ -3,11 +3,13 @@ #include "CruxCallable.h" #include "Statement.h" +#include "env/Env.h" class CruxFunction : public CruxCallable { public: Function *declaration; - CruxFunction(Function *declaration); + Environment *closure; + CruxFunction(Function *declaration, Environment *closure); virtual int arity() override; virtual Object call(Interpreter *interpreter, std::vector) override; virtual std::string str() override; diff --git a/include/Interpreter.h b/include/Interpreter.h index f1f3d3e..365f26f 100644 --- a/include/Interpreter.h +++ b/include/Interpreter.h @@ -47,6 +47,8 @@ class Interpreter { void interpret(std::vector &statements); + void resolve(); + void visitPrintStmnt(Print *stmnt); void visitBlockStmnt(Block *stmnt); diff --git a/include/Resolver.h b/include/Resolver.h new file mode 100644 index 0000000..f2f0c46 --- /dev/null +++ b/include/Resolver.h @@ -0,0 +1,74 @@ + +#ifndef CRUX_RESOLVER_H +#define CRUX_RESOLVER_H + +#include "Interpreter.h" +#include +#include +#include + +struct varFlags { + bool isInitilised; + bool isReferenced; +}; + +class Resolver { + +private: + std::vector *> scopes; + Interpreter *interpreter; + Resolver(Interpreter *interpreter); + +public: + void resolve(std::vector stmnts); + void resolve(Expr *expr); + void resolve(Statement *stmnt); + + void beginScope(); + void endScope(); + + void declare(Token *name); + void define(Token *name); + + void resolveLocal(Expr *expr, Token *name); + + Object excecuteBlock(std::vector stmnts, Environment *env); + + void interpret(std::vector &statements); + + void visitPrintStmnt(Print *stmnt); + + void visitBlockStmnt(Block *stmnt); + + void visitExprStmnt(Expression *stmnt); + + void visitVarStmnt(Var *stmnt); + + void visitIfStmnt(If *stmnt); + + void visitWhileStmnt(While *stmnt); + + void visitFuncStmnt(Function *stmnt); + + void visitReturnStmnt(Return *stmnt); + + void visitAssignment(Assignment *expr); + + void visitLogicalExp(Logical *expr); + + void visitLiteral(Literal *expr); + + void visitGroupExp(Grouping *expr); + + void visitCall(Call *stmnt); + + void visitUnaryExp(Unary *expr); + + void visitBinaryExp(Binary *expr); + + void visitTernaryExp(Ternary *expr); + + void visitVariableExp(Variable *expr); +}; + +#endif // CRUX_RESOLVER_H diff --git a/src/Function.cpp b/src/Function.cpp index 6d5e403..c0a264c 100644 --- a/src/Function.cpp +++ b/src/Function.cpp @@ -8,12 +8,13 @@ #include "utls/Object.h" #include -CruxFunction::CruxFunction(Function *declaration) : declaration(declaration) {} +CruxFunction::CruxFunction(Function *declaration, Environment *closure) + : declaration(declaration), closure(closure) {} int CruxFunction::arity() { return declaration->params.size(); } Object CruxFunction::call(Interpreter *interpreter, std::vector args) { - Environment *env = new Environment(interpreter->globals); + Environment *env = new Environment(closure); for (int i = 0; i < declaration->params.size(); i++) { env->define(declaration->params[i], args[i]); } diff --git a/src/Interpreter.cpp b/src/Interpreter.cpp index fa414a7..9ece8b7 100644 --- a/src/Interpreter.cpp +++ b/src/Interpreter.cpp @@ -73,6 +73,8 @@ Object Interpreter::evaluate(Expr *expr) { return visitVariableExp((Variable *)expr); case ExprType_Assignment: return visitAssignment((Assignment *)expr); + case ExprType_Logical: + return visitLogicalExp((Logical *)expr); case ExprType_Call: return visitCall((Call *)expr); } @@ -165,7 +167,7 @@ void Interpreter::visitWhileStmnt(While *stmnt) { } void Interpreter::visitFuncStmnt(Function *stmnt) { - Object declaration(new CruxFunction(stmnt)); + Object declaration(new CruxFunction(stmnt, environment)); environment->define(stmnt->name, declaration); } diff --git a/src/Resolver.cpp b/src/Resolver.cpp new file mode 100644 index 0000000..416874d --- /dev/null +++ b/src/Resolver.cpp @@ -0,0 +1,135 @@ +// +// +// +#include "Resolver.h" +#include "Error.h" +#include "Expr.h" +#include "Statement.h" +#include +#include +#include + +Resolver::Resolver(Interpreter *interpreter) : interpreter(interpreter) {} + +void Resolver::resolve(std::vector stmnts) { + for (Statement *stmnt : stmnts) { + resolve(stmnt); + } +} + +void Resolver::resolve(Statement *stmnt) { + switch (stmnt->type) { + case StmntPrint_type: + visitPrintStmnt((Print *)stmnt); + break; + case StmntExpr_type: + visitExprStmnt((Expression *)stmnt); + break; + case StmntVar_type: + visitVarStmnt((Var *)stmnt); + break; + case StmntBlock_type: + visitBlockStmnt((Block *)stmnt); + break; + case StmntIf_type: + visitIfStmnt((If *)stmnt); + break; + case StmntWhile_type: + visitWhileStmnt((While *)stmnt); + break; + case StmntFunc_type: + visitFuncStmnt((Function *)stmnt); + break; + case StmntReturn_type: + visitReturnStmnt((Return *)stmnt); + break; + case StmntBreak_type: + break; + } +} + +void Resolver::resolve(Expr *expr) { + switch (expr->type) { + case ExprType_Binary: + return visitBinaryExp((Binary *)expr); + case ExprType_Unary: + return visitUnaryExp((Unary *)expr); + case ExprType_Literal: + return visitLiteral((Literal *)expr); + case ExprType_Grouping: + return visitGroupExp((Grouping *)expr); + case ExprType_Ternary: + return visitTernaryExp((Ternary *)expr); + case ExprType_Variable: + return visitVariableExp((Variable *)expr); + case ExprType_Assignment: + return visitAssignment((Assignment *)expr); + case ExprType_Logical: + return visitLogicalExp((Logical *)expr); + case ExprType_Call: + return visitCall((Call *)expr); + } +} + +void Resolver::beginScope() { + scopes.push_back(new std::unordered_map()); +} + +void Resolver::endScope() { + auto scope = scopes.back(); + delete scope; + scopes.pop_back(); +} + +void Resolver::declare(Token *name) { + if (scopes.empty()) + return; + std::unordered_map *scope = scopes.back(); + (*scope)[name->lexeme].isReferenced = false; + (*scope)[name->lexeme].isInitilised = false; +} + +void Resolver::define(Token *name) { + if (scopes.empty()) + return; + std::unordered_map *scope = scopes.back(); + (*scope)[name->lexeme].isInitilised = true; +} + +void Resolver::resolveLocal(Expr *expr, Token *name) { + for (int i = scopes.size(); i >= 0; i--) { + if (scopes[i]->find(name->lexeme) != scopes[i]->end()) + interpreter.resolve(expr, scopes.size() - i - 1); + return; + } +} + +void Resolver::visitBlockStmnt(Block *block) { + beginScope(); + resolve(block->stmnt); + endScope(); +} + +void Resolver::visitVarStmnt(Var *stmnt) { + declare(stmnt->name); + if (stmnt->expression != nullptr) { + resolve(stmnt->expression); + } + define(stmnt->name); +} + +void Resolver::visitVariableExp(Variable *expr) { + if (!scopes.empty()) { + auto scope = scopes.back(); + auto it = scope->find(expr->name->lexeme); + if (it != scope->end() && !it->second.isInitilised == true) + crux::error(*expr->name, + "Can't read local variable in its own initializer."); + } + resolveLocal(expr, expr->name); +} + +void Resolver::visitAssignment(Assignment *expr) { + resolve(expr->value); + resolveLocal(expr, expr->name); +} diff --git a/test.crux b/test.crux new file mode 100644 index 0000000..e69de29