diff --git a/.DS_Store b/.DS_Store index 47c1ed6..52afa97 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/CMakeLists.txt b/CMakeLists.txt index 84972b2..8e4d57f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,13 +4,21 @@ project(cpp_lox LANGUAGES CXX) set(CMAKE_INCLUDE_CURRENT_DIR ON) -set(CMAKE_AUTOUIC ON) -set(CMAKE_AUTOMOC ON) -set(CMAKE_AUTORCC ON) - set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) -add_executable(cpp_lox - main.cpp -) +set(SOURCE_FILES + LoxInstance.cpp LoxInstance.hpp + LoxClass.cpp LoxClass.hpp + Resolver.cpp Resolver.hpp + Token.cpp Token.hpp + LoxFunction.cpp LoxFunction.hpp + Environment.cpp Environment.hpp + Interpreter.cpp Interpreter.hpp + lox.cpp lox.hpp + Parser.cpp Parser.hpp + Scanner.cpp Scanner.hpp + Stmt.hpp Expr.hpp + main.cpp + ) +add_executable(cpp_lox ${SOURCE_FILES}) diff --git a/CMakeLists.txt.user b/CMakeLists.txt.user deleted file mode 100644 index 7d054e4..0000000 --- a/CMakeLists.txt.user +++ /dev/null @@ -1,356 +0,0 @@ - - - - - - EnvironmentId - {a792350e-130b-4b17-9442-9f782b4e3dc6} - - - ProjectExplorer.Project.ActiveTarget - 0 - - - ProjectExplorer.Project.EditorSettings - - true - false - true - - Cpp - - CppGlobal - - - - QmlJS - - QmlJSGlobal - - - 2 - UTF-8 - false - 4 - false - 80 - true - true - 1 - true - false - 0 - true - true - 0 - 8 - true - 1 - true - true - true - false - - - - ProjectExplorer.Project.PluginSettings - - - true - - true - Builtin.TidyAndClazy - 2 - - - - true - - - - - ProjectExplorer.Project.Target.0 - - Desktop (x86-darwin-generic-mach_o-64bit) - Desktop (x86-darwin-generic-mach_o-64bit) - {1dc348e8-307a-4675-a7df-a40c9c375037} - 0 - 0 - 0 - - - CMAKE_BUILD_TYPE:STRING=Debug - CMAKE_CXX_COMPILER:STRING=%{Compiler:Executable:Cxx} - CMAKE_C_COMPILER:STRING=%{Compiler:Executable:C} - CMAKE_PREFIX_PATH:STRING=%{Qt:QT_INSTALL_PREFIX} - QT_QMAKE_EXECUTABLE:STRING=%{Qt:qmakeExecutable} - - /Users/tiger/Documents/learning/cplusplus/build-cpp_lox-Desktop_x86_darwin_generic_mach_o_64bit-Debug - - - - - all - - true - CMakeProjectManager.MakeStep - - 1 - Build - Build - ProjectExplorer.BuildSteps.Build - - - - - - clean - - true - CMakeProjectManager.MakeStep - - 1 - Clean - Clean - ProjectExplorer.BuildSteps.Clean - - 2 - false - - Debug - CMakeProjectManager.CMakeBuildConfiguration - - - - CMAKE_BUILD_TYPE:STRING=Release - CMAKE_CXX_COMPILER:STRING=%{Compiler:Executable:Cxx} - CMAKE_C_COMPILER:STRING=%{Compiler:Executable:C} - CMAKE_PREFIX_PATH:STRING=%{Qt:QT_INSTALL_PREFIX} - QT_QMAKE_EXECUTABLE:STRING=%{Qt:qmakeExecutable} - - /Users/tiger/Documents/learning/cplusplus/build-cpp_lox-Desktop_x86_darwin_generic_mach_o_64bit-Release - - - - - all - - true - CMakeProjectManager.MakeStep - - 1 - Build - Build - ProjectExplorer.BuildSteps.Build - - - - - - clean - - true - CMakeProjectManager.MakeStep - - 1 - Clean - Clean - ProjectExplorer.BuildSteps.Clean - - 2 - false - - Release - CMakeProjectManager.CMakeBuildConfiguration - - - - CMAKE_BUILD_TYPE:STRING=RelWithDebInfo - CMAKE_CXX_COMPILER:STRING=%{Compiler:Executable:Cxx} - CMAKE_C_COMPILER:STRING=%{Compiler:Executable:C} - CMAKE_PREFIX_PATH:STRING=%{Qt:QT_INSTALL_PREFIX} - QT_QMAKE_EXECUTABLE:STRING=%{Qt:qmakeExecutable} - - /Users/tiger/Documents/learning/cplusplus/build-cpp_lox-Desktop_x86_darwin_generic_mach_o_64bit-RelWithDebInfo - - - - - all - - true - CMakeProjectManager.MakeStep - - 1 - Build - Build - ProjectExplorer.BuildSteps.Build - - - - - - clean - - true - CMakeProjectManager.MakeStep - - 1 - Clean - Clean - ProjectExplorer.BuildSteps.Clean - - 2 - false - - Release with Debug Information - CMakeProjectManager.CMakeBuildConfiguration - - - - CMAKE_BUILD_TYPE:STRING=MinSizeRel - CMAKE_CXX_COMPILER:STRING=%{Compiler:Executable:Cxx} - CMAKE_C_COMPILER:STRING=%{Compiler:Executable:C} - CMAKE_PREFIX_PATH:STRING=%{Qt:QT_INSTALL_PREFIX} - QT_QMAKE_EXECUTABLE:STRING=%{Qt:qmakeExecutable} - - /Users/tiger/Documents/learning/cplusplus/build-cpp_lox-Desktop_x86_darwin_generic_mach_o_64bit-MinSizeRel - - - - - all - - true - CMakeProjectManager.MakeStep - - 1 - Build - Build - ProjectExplorer.BuildSteps.Build - - - - - - clean - - true - CMakeProjectManager.MakeStep - - 1 - Clean - Clean - ProjectExplorer.BuildSteps.Clean - - 2 - false - - Minimum Size Release - CMakeProjectManager.CMakeBuildConfiguration - - 4 - - - 0 - Deploy - Deploy - ProjectExplorer.BuildSteps.Deploy - - 1 - ProjectExplorer.DefaultDeployConfiguration - - 1 - - - dwarf - - cpu-cycles - - - 250 - - -e - cpu-cycles - --call-graph - dwarf,4096 - -F - 250 - - -F - true - 4096 - false - false - 1000 - - true - - false - false - false - false - true - 0.01 - 10 - true - kcachegrind - 1 - 25 - - 1 - true - false - true - valgrind - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - - 2 - - cpp_lox - CMakeProjectManager.CMakeRunConfiguration.cpp_lox - cpp_lox - - false - - false - true - false - true - false - false - true - - /private/var/folders/tw/ss12ypqj7dj84rk07_x7pzmw0000gp/T/QtCreator-nklAxp/qtc-cmake-popfLRfM - - 1 - - - - ProjectExplorer.Project.TargetCount - 1 - - - ProjectExplorer.Project.Updater.FileVersion - 22 - - - Version - 22 - - diff --git a/Interpreter.cpp b/Interpreter.cpp index e7cb778..f8798c5 100644 --- a/Interpreter.cpp +++ b/Interpreter.cpp @@ -15,6 +15,7 @@ #include "./LoxCallable.hpp" #include "./LoxFunction.hpp" #include "./ReturnError.hpp" +#include "./LoxClass.hpp" #include "./lox.hpp" using std::stod; @@ -184,18 +185,24 @@ Object Interpreter::visitCallExpr(shared_ptr> expr) { arguments.push_back(evaluate(argument)); } - if (callee.type != Object::Object_fun) { + if (callee.type != Object::Object_fun && callee.type != Object::Object_class) { throw RuntimeError(expr->paren, "Can only call functions and classes."); } - shared_ptr function = callee.function; - if (arguments.size() != function->arity()) { + shared_ptr callable; + if (callee.type == Object::Object_fun) { + callable = callee.function; + } + if (callee.type == Object::Object_class) { + callable = callee.lox_class; + } + if (arguments.size() != callable->arity()) { throw RuntimeError(expr->paren, "Expected " + - to_string(function->arity()) + " arguments but got " + + to_string(callable->arity()) + " arguments but got " + to_string(arguments.size()) + "."); } - return function->call(shared_from_this(), arguments); + return callable->call(shared_from_this(), arguments); } void Interpreter::visitExpressionStmt(const Expression& stmt) { @@ -226,6 +233,12 @@ void Interpreter::visitBlockStmt(const Block& stmt) { executeBlock(stmt.statements, env); } +void Interpreter::visitClassStmt(const Class& stmt) { + environment->define(stmt.name.lexeme, Object::make_nil_obj()); + auto klass = shared_ptr(new LoxClass(stmt.name.lexeme)); + environment->assign(stmt.name, Object::make_class_obj(klass)); +} + void Interpreter::visitWhileStmt(const While& stmt) { while (isTruthy(evaluate(stmt.condition))) { Object obj = evaluate(stmt.condition); diff --git a/Interpreter.hpp b/Interpreter.hpp index dba77b1..a282aee 100644 --- a/Interpreter.hpp +++ b/Interpreter.hpp @@ -38,6 +38,7 @@ class Interpreter: void visitPrintStmt(const Print& stmt); void visitVarStmt(const Var& stmt); void visitBlockStmt(const Block& stmt); + void visitClassStmt(const Class& stmt); void visitIfStmt(const If& stmt); void visitWhileStmt(const While& stmt); void visitFunctionStmt(const Function& stmt); diff --git a/LoxClass.cpp b/LoxClass.cpp new file mode 100644 index 0000000..604ce2d --- /dev/null +++ b/LoxClass.cpp @@ -0,0 +1,31 @@ +// Copyright 2020.2.23 + +#include +#include +#include + +#include "./LoxClass.hpp" +#include "./LoxInstance.hpp" +#include "./Interpreter.hpp" +#include "./Token.hpp" + +using std::string; +using std::shared_ptr; +using std::vector; + + +LoxClass::LoxClass(string name_): name(name_) {} + +Object LoxClass::call( + shared_ptr interpreter, + vector arguments) { + auto instance = shared_ptr(new LoxInstance(*this)); + return Object::make_instance_obj(instance); +} + +int LoxClass::arity() { + return 0; +} +string LoxClass::toString() { + return name; +} diff --git a/LoxClass.hpp b/LoxClass.hpp new file mode 100644 index 0000000..9dfa1bc --- /dev/null +++ b/LoxClass.hpp @@ -0,0 +1,28 @@ +// Copyright 2020.2.23 + +#ifndef LOXCLASS_HPP_ +#define LOXCLASS_HPP_ + +#include +#include +#include +#include "./LoxCallable.hpp" +#include "./Interpreter.hpp" +#include "./Token.hpp" + +using std::string; +using std::shared_ptr; +using std::vector; + +class LoxClass: public LoxCallable { + public: + string name; + explicit LoxClass(string name_); + Object call( + shared_ptr interpreter, + vector arguments); + int arity(); + string toString(); +}; + +#endif // LOXCLASS_HPP_ diff --git a/LoxInstance.cpp b/LoxInstance.cpp new file mode 100644 index 0000000..c2e0d07 --- /dev/null +++ b/LoxInstance.cpp @@ -0,0 +1,14 @@ +// Copyright 2020.2.23 + +#include + +#include "./LoxInstance.hpp" +#include "./LoxClass.hpp" + +using std::string; + +LoxInstance::LoxInstance(LoxClass klass_): klass(klass_) {} + +string LoxInstance::toString() { + return klass.name + " instance"; +} diff --git a/LoxInstance.hpp b/LoxInstance.hpp new file mode 100644 index 0000000..749dcc6 --- /dev/null +++ b/LoxInstance.hpp @@ -0,0 +1,18 @@ +// Copyright 2020.2.23 + +#ifndef LOXINSTANCE_HPP_ +#define LOXINSTANCE_HPP_ + +#include +#include "./LoxClass.hpp" + +using std::string; + +class LoxInstance { + public: + LoxClass klass; + explicit LoxInstance(LoxClass klass_); + string toString(); +}; + +#endif // LOXINSTANCE_HPP_ diff --git a/Makefile b/Makefile index 7bafd9b..081b0e2 100644 --- a/Makefile +++ b/Makefile @@ -1,21 +1,20 @@ CXXFLAGS=-g -std=c++11 -Wall -pedantic CXX = g++ -all: main test demo +all: main +LoxInstance.o: LoxInstance.cpp LoxInstance.hpp +LoxClass.o: LoxClass.cpp LoxClass.hpp Resolver.o: Resolver.cpp Resolver.hpp Token.o: Token.cpp Token.hpp LoxFunction.o: LoxFunction.cpp LoxFunction.hpp Environment.o: Environment.cpp Environment.hpp -Interpreter.o: Interpreter.cpp Interpreter.hpp Environment.o LoxFunction.o -lox.o: lox.cpp lox.hpp Interpreter.o Resolver.o +Interpreter.o: Interpreter.cpp Interpreter.hpp +lox.o: lox.cpp lox.hpp Parser.o: Parser.cpp Parser.hpp Scanner.o: Scanner.cpp Scanner.hpp -AstPrinter.o: AstPrinter.hpp AstPrinter.cpp -main: main.cpp lox.o LoxFunction.o Token.o Scanner.o Parser.o Interpreter.o Environment.o Resolver.o -test: test.cpp AstPrinter.o Token.o -demo: demo.cpp +main: main.cpp lox.o LoxFunction.o Token.o Scanner.o Parser.o Interpreter.o Environment.o Resolver.o LoxClass.o LoxInstance.o clean: rm -f *.o main \ No newline at end of file diff --git a/Parser.cpp b/Parser.cpp index 520c995..083e512 100644 --- a/Parser.cpp +++ b/Parser.cpp @@ -423,6 +423,7 @@ shared_ptr Parser::varDeclaration() { shared_ptr Parser::declaration() { try { + if (match({ CLASS })) return classDeclaration(); if (match({ FUN })) return function("function"); if (match({ VAR })) return varDeclaration(); return statement(); @@ -432,6 +433,19 @@ shared_ptr Parser::declaration() { } } +shared_ptr Parser::classDeclaration() { + Token name = consume(IDENTIFIER, "Expect class name."); + consume(LEFT_BRACE, "Expect '{' before class body."); + + vector> methods; + while (!check(RIGHT_BRACE) && !isAtEnd()) { + methods.push_back(function("method")); + } + consume(RIGHT_BRACE, "Expect '}' after class body."); + + return shared_ptr(new Class(name, methods)); +} + vector> Parser::parse() { vector> statements; while (!isAtEnd()) { diff --git a/Parser.hpp b/Parser.hpp index 19d179d..8e9d800 100644 --- a/Parser.hpp +++ b/Parser.hpp @@ -56,6 +56,7 @@ class Parser { shared_ptr expressionStatement(); shared_ptr function(string kind); shared_ptr declaration(); + shared_ptr classDeclaration(); shared_ptr varDeclaration(); vector> block(); }; diff --git a/Resolver.cpp b/Resolver.cpp index 48f37c2..2bf4222 100644 --- a/Resolver.cpp +++ b/Resolver.cpp @@ -95,6 +95,11 @@ void Resolver::visitBlockStmt(const Block& stmt) { endScope(); } +void Resolver::visitClassStmt(const Class& stmt) { + declare(stmt.name); + define(stmt.name); +} + void Resolver::visitIfStmt(const If& stmt) { resolve(stmt.condition); resolve(stmt.thenBranch); diff --git a/Resolver.hpp b/Resolver.hpp index af25f90..02de04b 100644 --- a/Resolver.hpp +++ b/Resolver.hpp @@ -37,6 +37,7 @@ class Resolver: void visitPrintStmt(const Print& stmt); void visitVarStmt(const Var& stmt); void visitBlockStmt(const Block& stmt); + void visitClassStmt(const Class& stmt); void visitIfStmt(const If& stmt); void visitWhileStmt(const While& stmt); void visitFunctionStmt(const Function& stmt); diff --git a/Stmt.hpp b/Stmt.hpp index ec96dff..2f4d3ec 100644 --- a/Stmt.hpp +++ b/Stmt.hpp @@ -3,10 +3,13 @@ /* program → declaration* EOF ; -declaration → funDecl +declaration → classDecl + |funDecl | varDecl | statement ; +classDecl → "class" IDENTIFIER "{" function* "}" ; + funDecl → "fun" function ; function → IDENTIFIER "(" parameters? ")" block ; parameters → IDENTIFIER ( "," IDENTIFIER )* ; @@ -59,6 +62,7 @@ class If; class While; class Function; class Return; +class Class; class Visitor_Stmt { public: @@ -71,6 +75,7 @@ class Visitor_Stmt { virtual void visitWhileStmt(const While& stmt) = 0; virtual void visitFunctionStmt(const Function& stmt) = 0; virtual void visitReturnStmt(const Return& stmt) = 0; + virtual void visitClassStmt(const Class& stmt) = 0; }; class Stmt { @@ -181,4 +186,15 @@ class Return: public Stmt { shared_ptr> value; }; +class Class: public Stmt { + public: + Class(Token name_, vector> function_): + name(name_), function(function_) { } + void accept(shared_ptr visitor) override { + visitor->visitClassStmt(*this); + } + Token name; + vector> function; +}; + #endif // STMT_HPP_ diff --git a/Token.hpp b/Token.hpp index f34dded..ff5e174 100644 --- a/Token.hpp +++ b/Token.hpp @@ -10,6 +10,8 @@ using std::string; using std::shared_ptr; class LoxCallable; +class LoxInstance; +class LoxClass; typedef enum { LEFT_PAREN, RIGHT_PAREN, LEFT_BRACE, RIGHT_BRACE, @@ -39,6 +41,8 @@ class Object { Object_bool, Object_nil, Object_fun, + Object_instance, + Object_class, } Object_type; string str; double num; @@ -47,11 +51,15 @@ class Object { Object_type type; string toString(); shared_ptr function; + shared_ptr instance; + shared_ptr lox_class; static Object make_num_obj(double num); static Object make_str_obj(string str); static Object make_bool_obj(bool boolean); static Object make_nil_obj(); static Object make_fun_obj(shared_ptr function_); + static Object make_instance_obj(shared_ptr instance_); + static Object make_class_obj(shared_ptr lox_class_); }; class Token { diff --git a/cpp_lox.creator.user b/cpp_lox.creator.user deleted file mode 100644 index 0f6d990..0000000 --- a/cpp_lox.creator.user +++ /dev/null @@ -1,215 +0,0 @@ - - - - - - EnvironmentId - {a792350e-130b-4b17-9442-9f782b4e3dc6} - - - ProjectExplorer.Project.ActiveTarget - 0 - - - ProjectExplorer.Project.EditorSettings - - true - false - true - - Cpp - - CppGlobal - - - - QmlJS - - QmlJSGlobal - - - 2 - UTF-8 - false - 4 - false - 80 - true - true - 1 - true - false - 0 - true - true - 0 - 8 - true - 1 - true - true - true - false - - - - ProjectExplorer.Project.PluginSettings - - - true - - - - ProjectExplorer.Project.Target.0 - - Desktop (x86-darwin-generic-mach_o-32bit) - Desktop (x86-darwin-generic-mach_o-32bit) - {f6611be0-def4-4474-824d-587e399e46ac} - 0 - 0 - 0 - - /Users/tiger/Documents/learning/cplusplus/cpp_lox - - - - all - - false - - - false - true - GenericProjectManager.GenericMakeStep - - 1 - Build - Build - ProjectExplorer.BuildSteps.Build - - - - - clean - - true - - - false - true - GenericProjectManager.GenericMakeStep - - 1 - Clean - Clean - ProjectExplorer.BuildSteps.Clean - - 2 - false - - Default - GenericProjectManager.GenericBuildConfiguration - - 1 - - - 0 - Deploy - Deploy - ProjectExplorer.BuildSteps.Deploy - - 1 - ProjectExplorer.DefaultDeployConfiguration - - 1 - - - dwarf - - cpu-cycles - - - 250 - - -e - cpu-cycles - --call-graph - dwarf,4096 - -F - 250 - - -F - true - 4096 - false - false - 1000 - - true - - false - false - false - false - true - 0.01 - 10 - true - kcachegrind - 1 - 25 - - 1 - true - false - true - valgrind - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - - 2 - - /Users/tiger/Documents/learning/cplusplus/cpp_lox/main - ProjectExplorer.CustomExecutableRunConfiguration - - test.lox - false - - false - true - false - false - true - /Users/tiger/Documents/learning/cplusplus/cpp_lox - - - 1 - - - - ProjectExplorer.Project.TargetCount - 1 - - - ProjectExplorer.Project.Updater.FileVersion - 22 - - - Version - 22 - - diff --git a/cpp_lox.files b/cpp_lox.files index 184e433..00e22e8 100644 --- a/cpp_lox.files +++ b/cpp_lox.files @@ -14,6 +14,10 @@ LoxFunction.cpp LoxFunction.hpp Resolver.hpp Resolver.cpp +LoxClass.cpp +LoxClass.hpp +LoxInstance.cpp +LoxInstance.hpp Scanner.cpp Scanner.hpp Stmt.hpp diff --git a/test b/test deleted file mode 100755 index 6dc4288..0000000 Binary files a/test and /dev/null differ diff --git a/test.lox b/test.lox index 9d74ecc..2b8ac60 100644 --- a/test.lox +++ b/test.lox @@ -1,9 +1,3 @@ -fun count(n) { - while (n < 10) { - if (n == 3) return n; - print n; - n = n + 1; - } -} - -count(1); \ No newline at end of file +class Bagel {} +var bagel = Bagel(); +print bagel; \ No newline at end of file diff --git a/token.cpp b/token.cpp index 6655bf9..6d56ce0 100644 --- a/token.cpp +++ b/token.cpp @@ -5,6 +5,8 @@ #include "./Token.hpp" #include "./LoxCallable.hpp" +#include "./LoxInstance.hpp" +#include "./LoxClass.hpp" using std::to_string; using std::string; @@ -20,6 +22,10 @@ string Object::toString() { return str; case Object_fun: return "func: "; + case Object_class: + return lox_class->toString(); + case Object_instance: + return instance->toString(); default: return to_string(num); } @@ -54,10 +60,24 @@ Object Object::make_nil_obj() { } Object Object::make_fun_obj(shared_ptr function_) { - Object nil_obj; - nil_obj.type = Object_fun; - nil_obj.function = function_; - return nil_obj; + Object fun_obj; + fun_obj.type = Object_fun; + fun_obj.function = function_; + return fun_obj; +} + +Object Object::make_instance_obj(shared_ptr instance_) { + Object class_obj; + class_obj.type = Object_instance; + class_obj.instance = instance_; + return class_obj; +} + +Object Object::make_class_obj(shared_ptr lox_class_) { + Object class_obj; + class_obj.type = Object_class; + class_obj.lox_class = lox_class_; + return class_obj; } Token::Token(TokenType type, string lexeme, Object literal, int line)