implementing this
This commit is contained in:
		
							
								
								
									
										5
									
								
								samples/ch28_this_outside.lox
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								samples/ch28_this_outside.lox
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					print this;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fun invalid() {
 | 
				
			||||||
 | 
					    print this;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -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;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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 => {},
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user