@@ -129,7 +129,7 @@ using lox::scanner::TokenType;
129129Parser::Parser (std::unique_ptr<Scanner> scanner, ObjFunction* fnptr, GC& gc)
130130 : scanner(std::move(scanner)), current(SENTINEL_EOF),
131131 previous (SENTINEL_EOF), errmsg(std::nullopt ), gc(gc),
132- compiler(std::make_unique<Compiler>(fnptr)) {}
132+ compiler(std::make_unique<Compiler>(fnptr, nullptr , false )) {}
133133
134134void Parser::advance () {
135135 previous = current;
@@ -139,7 +139,7 @@ void Parser::advance() {
139139 }
140140}
141141
142- void Parser::function (bool define ) {
142+ void Parser::function (bool is_class_method ) {
143143 // Parse the name and arity of the function: that will let us create the
144144 // ObjFunction object
145145 consume_or_error (TokenType::IDENTIFIER, " expected function name" );
@@ -150,8 +150,8 @@ void Parser::function(bool define) {
150150 size_t arity = 0 ;
151151 // TODO: This copies the string. Do we need to?
152152 auto new_fnptr = gc.alloc <ObjFunction>(fn_name, arity);
153- auto new_compiler =
154- std::make_unique<Compiler>(new_fnptr, std::move (compiler) );
153+ auto new_compiler = std::make_unique<Compiler>(new_fnptr, std::move (compiler),
154+ is_class_method );
155155 compiler = std::move (new_compiler);
156156 compiler->begin_scope ();
157157 // Parse parameters (if there are any).
@@ -194,7 +194,7 @@ void Parser::function(bool define) {
194194 emit (upvalue.is_local ? 1 : 0 );
195195 emit (static_cast <uint8_t >(upvalue.index ));
196196 }
197- if (define ) {
197+ if (!is_class_method ) {
198198 // This makes `fn_name` available either as a local variable (if it's in
199199 // an inner scope) or a global variable. However, we don't always want to
200200 // do that: for example if we're parsing a class method, then the
@@ -392,7 +392,7 @@ void Parser::declaration() {
392392 if (consume_if (TokenType::VAR)) {
393393 var_declaration ();
394394 } else if (consume_if (TokenType::FUN)) {
395- function (true );
395+ function (false );
396396 } else if (consume_if (TokenType::CLASS)) {
397397 class_declaration ();
398398 } else {
@@ -441,7 +441,7 @@ void Parser::class_declaration() {
441441void Parser::method () {
442442 // This parses the function body and emits code to create an ObjClosure and
443443 // put it at the top of the stack.
444- function (false );
444+ function (true );
445445 // We then need to tell the VM to read the ObjClosure at the top of the stack
446446 // and store it in the method table of the current class. The book just calls
447447 // this 'METHOD' but I've chosen to give it a more descriptive name.
@@ -723,6 +723,13 @@ void Parser::number(bool _) {
723723 emit_constant (value);
724724}
725725
726+ void Parser::this_ (bool _) {
727+ // 1. We can't assign to this, hence the false.
728+ // 2. We just treat 'this' like a local variable that happens to be at index
729+ // 0.
730+ variable (false );
731+ }
732+
726733void Parser::literal (bool _) {
727734 switch (previous.type ) {
728735 case TokenType::FALSE :
0 commit comments