implementing this

This commit is contained in:
Patrick MARIE 2024-08-31 11:17:01 +02:00
parent 3c1c37799c
commit b522f05c8c
3 changed files with 42 additions and 4 deletions

View File

@ -0,0 +1,5 @@
print this;
fun invalid() {
print this;
}

View File

@ -35,6 +35,10 @@ const Precedence = enum {
const ParserFn = *const fn (*Parser, bool) ParsingError!void; const ParserFn = *const fn (*Parser, bool) ParsingError!void;
const ClassCompiler = struct {
enclosing: ?*ClassCompiler,
};
const ParserRule = struct { const ParserRule = struct {
prefix: ?ParserFn, prefix: ?ParserFn,
infix: ?ParserFn, infix: ?ParserFn,
@ -49,6 +53,7 @@ pub const Parser = struct {
had_error: bool, had_error: bool,
panic_mode: bool, panic_mode: bool,
vm: *VM, vm: *VM,
class_compiler: ?*ClassCompiler,
fn new(vm: *VM, compiler: *Compiler, scanner: *Scanner) Parser { fn new(vm: *VM, compiler: *Compiler, scanner: *Scanner) Parser {
return Parser{ return Parser{
@ -59,6 +64,7 @@ pub const Parser = struct {
.had_error = false, .had_error = false,
.panic_mode = false, .panic_mode = false,
.vm = vm, .vm = vm,
.class_compiler = null,
}; };
} }
@ -66,6 +72,10 @@ pub const Parser = struct {
return self.compiler.function.chunk; return self.compiler.function.chunk;
} }
inline fn current_class_compiler(self: *Parser) ?*ClassCompiler {
return self.class_compiler;
}
fn advance(self: *Parser) void { fn advance(self: *Parser) void {
self.previous = self.current; self.previous = self.current;
@ -278,7 +288,7 @@ pub const Parser = struct {
TokenType.PRINT => ParserRule{ .prefix = null, .infix = null, .precedence = Precedence.None }, TokenType.PRINT => ParserRule{ .prefix = null, .infix = null, .precedence = Precedence.None },
TokenType.RETURN => ParserRule{ .prefix = null, .infix = null, .precedence = Precedence.None }, TokenType.RETURN => ParserRule{ .prefix = null, .infix = null, .precedence = Precedence.None },
TokenType.SUPER => ParserRule{ .prefix = null, .infix = null, .precedence = Precedence.None }, TokenType.SUPER => ParserRule{ .prefix = null, .infix = null, .precedence = Precedence.None },
TokenType.THIS => ParserRule{ .prefix = null, .infix = null, .precedence = Precedence.None }, TokenType.THIS => ParserRule{ .prefix = this_, .infix = null, .precedence = Precedence.None },
TokenType.TRUE => ParserRule{ .prefix = literal, .infix = null, .precedence = Precedence.None }, TokenType.TRUE => ParserRule{ .prefix = literal, .infix = null, .precedence = Precedence.None },
TokenType.VAR => ParserRule{ .prefix = null, .infix = null, .precedence = Precedence.None }, TokenType.VAR => ParserRule{ .prefix = null, .infix = null, .precedence = Precedence.None },
TokenType.WHILE => ParserRule{ .prefix = null, .infix = null, .precedence = Precedence.None }, TokenType.WHILE => ParserRule{ .prefix = null, .infix = null, .precedence = Precedence.None },
@ -871,6 +881,11 @@ pub const Parser = struct {
try self.emit_bytes(@intFromEnum(OpCode.OP_CLASS), name_constant); try self.emit_bytes(@intFromEnum(OpCode.OP_CLASS), name_constant);
try self.define_variable(name_constant); try self.define_variable(name_constant);
var class_compiler = ClassCompiler{
.enclosing = self.current_class_compiler(),
};
self.class_compiler = &class_compiler;
try self.named_variable(class_name, false); try self.named_variable(class_name, false);
self.consume(TokenType.LEFT_BRACE, "Expect '{' before class body."); self.consume(TokenType.LEFT_BRACE, "Expect '{' before class body.");
@ -879,6 +894,8 @@ pub const Parser = struct {
} }
self.consume(TokenType.RIGHT_BRACE, "Expect '}' after class body."); self.consume(TokenType.RIGHT_BRACE, "Expect '}' after class body.");
try self.emit_byte(@intFromEnum(OpCode.OP_POP)); try self.emit_byte(@intFromEnum(OpCode.OP_POP));
self.class_compiler = self.current_class_compiler().?.enclosing;
} }
fn dot(self: *Parser, can_assign: bool) ParsingError!void { fn dot(self: *Parser, can_assign: bool) ParsingError!void {
@ -897,14 +914,25 @@ pub const Parser = struct {
self.consume(TokenType.IDENTIFIER, "Expect method name."); self.consume(TokenType.IDENTIFIER, "Expect method name.");
const constant = try self.identifier_constant(self.previous.?); const constant = try self.identifier_constant(self.previous.?);
try self.function(FunctionType.Function); try self.function(FunctionType.Method);
try self.emit_bytes(@intFromEnum(OpCode.OP_METHOD), constant); try self.emit_bytes(@intFromEnum(OpCode.OP_METHOD), constant);
} }
fn this_(self: *Parser, can_assign: bool) ParsingError!void {
if (self.current_class_compiler() == null) {
self.error_msg("Can't use 'this' outside of a class.");
return;
}
_ = can_assign;
try self.variable(false);
}
}; };
const FunctionType = enum { const FunctionType = enum {
Function, Function,
Script, Script,
Method,
}; };
pub const Compiler = struct { pub const Compiler = struct {
@ -931,6 +959,8 @@ pub const Compiler = struct {
.enclosing = enclosing, .enclosing = enclosing,
}; };
compiler.local_count += 1;
compiler.locals[0].depth = 0; compiler.locals[0].depth = 0;
compiler.locals[0].name = Token{ compiler.locals[0].name = Token{
.token_type = TokenType.EOF, .token_type = TokenType.EOF,
@ -940,7 +970,10 @@ pub const Compiler = struct {
}; };
compiler.locals[0].is_captured = false; compiler.locals[0].is_captured = false;
compiler.local_count += 1; if (function_type != FunctionType.Function) {
compiler.locals[0].name.start = "this";
compiler.locals[0].name.length = 4;
}
return compiler; return compiler;
} }

View File

@ -504,7 +504,7 @@ pub const VM = struct {
}, },
ObjType.BoundMethod => { ObjType.BoundMethod => {
const bound_method = callee.as_obj().as_bound_method(); const bound_method = callee.as_obj().as_bound_method();
self.stack[self.stack_top - arg_count - 1] = bound_method.receiver;
return self.call(bound_method.method, arg_count); return self.call(bound_method.method, arg_count);
}, },
else => {}, else => {},