@@ -87,6 +87,7 @@ typedef struct ClassCompiler
8787{
8888 struct ClassCompiler * enclosing ;
8989 Token name ;
90+ bool has_super_class ;
9091} ClassCompiler ;
9192
9293static bool immutable_globals [UINT8_MAX ];
@@ -644,6 +645,28 @@ static void variable(bool can_assign)
644645 named_variable (parser .previous , can_assign );
645646}
646647
648+ static Token synthetic_token (const char * text )
649+ {
650+ return (Token ){.start = text ,
651+ .length = (int )strlen (text )};
652+ }
653+
654+ static void super_ (bool can_assign )
655+ {
656+ if (current_class == NULL )
657+ error ("Can't use 'super' outside of a class" );
658+ else if (!current_class -> has_super_class )
659+ error ("Can't use 'super' in a class with no superclass" );
660+
661+ consume (TOKEN_DOT , "Expect '.' after a super." );
662+ consume (TOKEN_IDENTIFIER , "Expect super class method name." );
663+ u8 name = identifier_constant (& parser .previous );
664+
665+ named_variable (synthetic_token ("this" ), false);
666+ named_variable (synthetic_token ("super" ), false);
667+ emit_bytes (OP_GET_SUPER , name );
668+ }
669+
647670static void this_ (bool can_assign )
648671{
649672 if (current_class == NULL )
@@ -707,8 +730,8 @@ ParseRule rules[] = {
707730 [TOKEN_OR ] = { NULL , or_ , PREC_OR },
708731 [TOKEN_PRINT ] = { NULL , NULL , PREC_NONE },
709732 [TOKEN_RETURN ] = { NULL , NULL , PREC_NONE },
710- [TOKEN_SUPER ] = { NULL , NULL , PREC_NONE },
711- [TOKEN_THIS ] = { this_ , NULL , PREC_NONE },
733+ [TOKEN_SUPER ] = { super_ , NULL , PREC_NONE },
734+ [TOKEN_THIS ] = { this_ , NULL , PREC_NONE },
712735 [TOKEN_TRUE ] = { literal , NULL , PREC_NONE },
713736 [TOKEN_VAR ] = { NULL , NULL , PREC_NONE },
714737 [TOKEN_WHILE ] = { NULL , NULL , PREC_NONE },
@@ -824,9 +847,28 @@ static void class_declaration()
824847 emit_bytes (OP_CLASS , name_constant );
825848 define_variable (name_constant , true);
826849
827- ClassCompiler class_compiler = {.name = parser .previous , .enclosing = current_class };
850+ ClassCompiler class_compiler = {.name = parser .previous ,
851+ .has_super_class = false,
852+ .enclosing = current_class };
828853 current_class = & class_compiler ;
829854
855+ if (match (TOKEN_COLON ))
856+ {
857+ consume (TOKEN_IDENTIFIER , "Expect super class name." );
858+ variable (false);
859+
860+ if (identifiers_equal (& class_name , & parser .previous ))
861+ error ("A class can't inherit from itself" );
862+
863+ begin_scope ();
864+ add_local (synthetic_token ("super" ), false);
865+ define_variable (0 , false);
866+
867+ named_variable (class_name , false);
868+ emit_byte (OP_INHERIT );
869+ class_compiler .has_super_class = true;
870+ }
871+
830872 named_variable (class_name , false);
831873 consume (TOKEN_LEFT_BRACE , "Expected '{' after class name" );
832874 while (!check (TOKEN_RIGHT_BRACE ) && !check (TOKEN_EOF ))
@@ -836,6 +878,9 @@ static void class_declaration()
836878 consume (TOKEN_RIGHT_BRACE , "Expected '}' after class body" );
837879 emit_byte (OP_POP );
838880
881+ if (class_compiler .has_super_class )
882+ end_scope ();
883+
839884 current_class = current_class -> enclosing ;
840885}
841886
0 commit comments