Skip to content

Commit f36e122

Browse files
committed
feat: implement 'this' compilation and runtime
1 parent 4149f27 commit f36e122

2 files changed

Lines changed: 41 additions & 9 deletions

File tree

src/compiler.c

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ typedef struct
6666
typedef enum
6767
{
6868
TYPE_FUNCTION,
69+
TYPE_METHOD,
6970
TYPE_SCRIPT,
7071
} FunctionType;
7172

@@ -81,10 +82,17 @@ typedef struct Compiler
8182
int scope_depth;
8283
} Compiler;
8384

85+
typedef struct ClassCompiler
86+
{
87+
struct ClassCompiler* enclosing;
88+
Token name;
89+
} ClassCompiler;
90+
8491
static bool immutable_globals[UINT8_MAX];
8592

86-
Parser parser;
87-
Compiler* current = NULL;
93+
Parser parser;
94+
Compiler* current = NULL;
95+
ClassCompiler* current_class = NULL;
8896

8997
static Chunk* current_chunk()
9098
{
@@ -241,8 +249,16 @@ static void init_compiler(Compiler* compiler, FunctionType type)
241249
local->depth = 0;
242250
local->is_captured = false;
243251
local->is_immutable = false;
244-
local->name.start = "";
245-
local->name.length = 0;
252+
if (type != TYPE_FUNCTION)
253+
{
254+
local->name.start = "this";
255+
local->name.length = 4;
256+
}
257+
else
258+
{
259+
local->name.start = "";
260+
local->name.length = 0;
261+
}
246262
}
247263

248264
static ObjFunction* end_compiler()
@@ -617,6 +633,16 @@ static void variable(bool can_assign)
617633
named_variable(parser.previous, can_assign);
618634
}
619635

636+
static void this_(bool can_assign)
637+
{
638+
if (current_class == NULL)
639+
{
640+
error("Can't use 'this' outside of a class");
641+
return;
642+
}
643+
variable(false);
644+
}
645+
620646
static void unary(bool can_assign)
621647
{
622648
TokenType operator_type = parser.previous.type;
@@ -642,7 +668,7 @@ ParseRule rules[] = {
642668
[TOKEN_LEFT_BRACE] = { NULL, NULL, PREC_NONE },
643669
[TOKEN_RIGHT_BRACE] = { NULL, NULL, PREC_NONE },
644670
[TOKEN_COMMA] = { NULL, NULL, PREC_NONE },
645-
[TOKEN_DOT] = { NULL, dot, PREC_NONE },
671+
[TOKEN_DOT] = { NULL, dot, PREC_NONE },
646672
[TOKEN_MINUS] = { unary, binary, PREC_TERM },
647673
[TOKEN_PLUS] = { NULL, binary, PREC_TERM },
648674
[TOKEN_SEMICOLON] = { NULL, NULL, PREC_NONE },
@@ -659,19 +685,19 @@ ParseRule rules[] = {
659685
[TOKEN_STRING] = { string, NULL, PREC_NONE },
660686
[TOKEN_NUMBER] = { number, NULL, PREC_NONE },
661687
[TOKEN_IDENTIFIER] = { variable, NULL, PREC_NONE },
662-
[TOKEN_AND] = { NULL, and_, PREC_AND },
688+
[TOKEN_AND] = { NULL, and_, PREC_AND },
663689
[TOKEN_CLASS] = { NULL, NULL, PREC_NONE },
664690
[TOKEN_ELSE] = { NULL, NULL, PREC_NONE },
665691
[TOKEN_FALSE] = { literal, NULL, PREC_NONE },
666692
[TOKEN_FOR] = { NULL, NULL, PREC_NONE },
667693
[TOKEN_FUN] = { NULL, NULL, PREC_NONE },
668694
[TOKEN_IF] = { NULL, NULL, PREC_NONE },
669695
[TOKEN_NIL] = { literal, NULL, PREC_NONE },
670-
[TOKEN_OR] = { NULL, or_, PREC_OR },
696+
[TOKEN_OR] = { NULL, or_, PREC_OR },
671697
[TOKEN_PRINT] = { NULL, NULL, PREC_NONE },
672698
[TOKEN_RETURN] = { NULL, NULL, PREC_NONE },
673699
[TOKEN_SUPER] = { NULL, NULL, PREC_NONE },
674-
[TOKEN_THIS] = { NULL, NULL, PREC_NONE },
700+
[TOKEN_THIS] = { this_, NULL, PREC_NONE },
675701
[TOKEN_TRUE] = { literal, NULL, PREC_NONE },
676702
[TOKEN_VAR] = { NULL, NULL, PREC_NONE },
677703
[TOKEN_WHILE] = { NULL, NULL, PREC_NONE },
@@ -769,7 +795,7 @@ static void method()
769795
consume(TOKEN_IDENTIFIER, "Expect method name.");
770796
u8 constant = identifier_constant(&parser.previous);
771797

772-
FunctionType type = TYPE_FUNCTION;
798+
FunctionType type = TYPE_METHOD;
773799
function(type);
774800

775801
emit_bytes(OP_METHOD, constant);
@@ -784,6 +810,9 @@ static void class_declaration()
784810
emit_bytes(OP_CLASS, name_constant);
785811
define_variable(name_constant, true);
786812

813+
ClassCompiler class_compiler = {.name = parser.previous, .enclosing = current_class};
814+
current_class = &class_compiler;
815+
787816
named_variable(class_name, false);
788817
consume(TOKEN_LEFT_BRACE, "Expected '{' after class name");
789818
while (!check(TOKEN_RIGHT_BRACE) && !check(TOKEN_EOF))
@@ -792,6 +821,8 @@ static void class_declaration()
792821
}
793822
consume(TOKEN_RIGHT_BRACE, "Expected '}' after class body");
794823
emit_byte(OP_POP);
824+
825+
current_class = current_class->enclosing;
795826
}
796827

797828
static void fun_declaration()

src/vm.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ static bool call_value(Value callee, int arg_count)
126126
{
127127
case OBJ_BOUND_METHOD:
128128
ObjBoundMethod* bound = AS_BOUND_METHOD(callee);
129+
vm.stack_top[-arg_count - 1] = bound->receiver;
129130
return call(bound->method, arg_count);
130131
case OBJ_INSTANCE:
131132
ObjClass* klass = AS_CLASS(callee);

0 commit comments

Comments
 (0)