@@ -130,7 +130,8 @@ Parser::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),
132132 compiler(
133- std::make_unique<Compiler>(fnptr, nullptr , FunctionType::TOPLEVEL)) {}
133+ std::make_unique<Compiler>(fnptr, nullptr , FunctionType::TOPLEVEL)),
134+ current_class(nullptr ) {}
134135
135136void Parser::advance () {
136137 previous = current;
@@ -151,9 +152,12 @@ void Parser::function(bool is_class_method) {
151152 size_t arity = 0 ;
152153 // TODO: This copies the string. Do we need to?
153154 auto new_fnptr = gc.alloc <ObjFunction>(fn_name, arity);
154- auto new_compiler = std::make_unique<Compiler>(
155- new_fnptr, std::move (compiler),
156- (is_class_method ? FunctionType::CLASSMETHOD : FunctionType::FUNCTION));
155+ FunctionType fn_type = is_class_method
156+ ? (fn_name == " init" ? FunctionType::CLASSINIT
157+ : FunctionType::CLASSMETHOD)
158+ : FunctionType::FUNCTION;
159+ auto new_compiler =
160+ std::make_unique<Compiler>(new_fnptr, std::move (compiler), fn_type);
157161 compiler = std::move (new_compiler);
158162 compiler->begin_scope ();
159163 // Parse parameters (if there are any).
@@ -257,9 +261,10 @@ ObjFunction* Parser::finalise_function() {
257261 << " \n " ;
258262 return nullptr ;
259263 } else {
260- // If there's no explicit return statement, we tack one on the end that
261- // returns nil.
262- emit_constant (std::monostate ());
264+ // Just tack a return at the end of the function body. If there was already
265+ // one, it won't matter that we do this: it'll be unreachable. But if we
266+ // fall off the end of a function body, this will catch us.
267+ emit_auto_return_value ();
263268 emit (lox::OpCode::RETURN);
264269 // Get the function object from the current compiler, and pop it off the
265270 // compiler stack.
@@ -413,7 +418,7 @@ void Parser::class_declaration() {
413418 emit (lox::OpCode::CLASS);
414419 emit (name_constant_index);
415420
416- compiler-> push_current_class ();
421+ push_current_class ();
417422
418423 // This call will emit code to read from the top of the stack and create
419424 // either a local or global variable with the class.
@@ -437,7 +442,7 @@ void Parser::class_declaration() {
437442 // any more.
438443 emit (lox::OpCode::POP);
439444
440- compiler-> pop_current_class ();
445+ pop_current_class ();
441446}
442447
443448void Parser::method () {
@@ -596,15 +601,34 @@ void Parser::statement() {
596601 }
597602}
598603
604+ // This function is hit whenever we have a plain `return;` (inside
605+ // `return_statement`) or if we fall off the end of a function without an
606+ // explicit return (inside `finalise_function`). It pushes the implicit return
607+ // value onto the stack (but does not emit the RETURN instruction).
608+ void Parser::emit_auto_return_value () {
609+ if (compiler->get_function_type () == FunctionType::CLASSINIT) {
610+ // return the instance, which is happily always at local slot 0.
611+ emit (lox::OpCode::GET_LOCAL);
612+ emit (static_cast <uint8_t >(0 ));
613+ } else {
614+ // No return value; return nil
615+ emit_constant (std::monostate ());
616+ }
617+ }
618+
599619void Parser::return_statement () {
600620 if (compiler->get_function_type () == FunctionType::TOPLEVEL) {
601621 error (" cannot return from top-level code" , previous.line );
602622 }
603623 // Return value
604624 if (consume_if (TokenType::SEMICOLON)) {
605- // No return value; return nil
606- emit_constant ( std::monostate () );
625+ // No explicit return value.
626+ emit_auto_return_value ( );
607627 } else {
628+ // Explicit return value.
629+ if (compiler->get_function_type () == FunctionType::CLASSINIT) {
630+ error (" cannot return a value from an initializer" , previous.line );
631+ }
608632 expression ();
609633 consume_or_error (TokenType::SEMICOLON, " expected ';' after return value" );
610634 }
@@ -726,13 +750,17 @@ void Parser::number(bool _) {
726750}
727751
728752void Parser::this_ (bool _) {
729- // 1. We can't assign to this, hence the false.
730- // 2. We just treat 'this' like a local variable that happens to be at index
731- // zero.
732- if (!compiler->is_in_class ()) {
753+ // Note that we can't just check if the current function is CLASSMETHOD ||
754+ // CLASSINIT, because we might be e.g. inside a nested function inside a
755+ // class method. That's why we have a separate bit of info in the Parser that
756+ // tracks whether we're currently allowed to use `this` or not.
757+ if (!is_in_class ()) {
733758 error (" cannot use 'this' outside of a class" , previous.line );
734759 return ;
735760 }
761+ // We can't assign to this, hence the false. But apart from that, we just
762+ // treat 'this' like a local variable that happens to be at index 0 (which the
763+ // constructor of Compiler does for us).
736764 variable (false );
737765}
738766
0 commit comments