Compare commits

..

No commits in common. "b522f05c8c4d89049532514084ccf21d067bdddf" and "c8cd24afbf1c606993166bd894e3473a8fc60d47" have entirely different histories.

10 changed files with 4 additions and 163 deletions

View File

@ -1,9 +0,0 @@
class Scone {
topping(first, second) {
return "scone with " + first + " and " + second;
}
}
var scone = Scone();
var result = scone.topping("berries", "cream");
print result;

View File

@ -1,8 +0,0 @@
class Brunch {
bacon() {}
eggs() {}
}
var brunch = Brunch();
print brunch;
brunch.bacon();

View File

@ -1,11 +0,0 @@
class Person {
sayName() {
print this.name;
}
}
var jane = Person();
jane.name = "Jane";
var method = jane.sayName;
method();

View File

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

View File

@ -151,7 +151,6 @@ pub const Chunk = struct {
@intFromEnum(OpCode.OP_CLASS) => return utils.constant_instruction("OP_CLASS", self, offset),
@intFromEnum(OpCode.OP_GET_PROPERTY) => return utils.constant_instruction("OP_GET_PROPERTY", self, offset),
@intFromEnum(OpCode.OP_SET_PROPERTY) => return utils.constant_instruction("OP_SET_PROPERTY", self, offset),
@intFromEnum(OpCode.OP_METHOD) => return utils.constant_instruction("OP_METHOD", self, offset),
else => {
debug.print("unknown opcode {d}\n", .{instruction});
return offset + 1;

View File

@ -35,10 +35,6 @@ const Precedence = enum {
const ParserFn = *const fn (*Parser, bool) ParsingError!void;
const ClassCompiler = struct {
enclosing: ?*ClassCompiler,
};
const ParserRule = struct {
prefix: ?ParserFn,
infix: ?ParserFn,
@ -53,7 +49,6 @@ pub const Parser = struct {
had_error: bool,
panic_mode: bool,
vm: *VM,
class_compiler: ?*ClassCompiler,
fn new(vm: *VM, compiler: *Compiler, scanner: *Scanner) Parser {
return Parser{
@ -64,7 +59,6 @@ pub const Parser = struct {
.had_error = false,
.panic_mode = false,
.vm = vm,
.class_compiler = null,
};
}
@ -72,10 +66,6 @@ pub const Parser = struct {
return self.compiler.function.chunk;
}
inline fn current_class_compiler(self: *Parser) ?*ClassCompiler {
return self.class_compiler;
}
fn advance(self: *Parser) void {
self.previous = self.current;
@ -288,7 +278,7 @@ pub const Parser = struct {
TokenType.PRINT => 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.THIS => ParserRule{ .prefix = this_, .infix = null, .precedence = Precedence.None },
TokenType.THIS => ParserRule{ .prefix = null, .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.WHILE => ParserRule{ .prefix = null, .infix = null, .precedence = Precedence.None },
@ -873,29 +863,14 @@ pub const Parser = struct {
fn class_declaration(self: *Parser) ParsingError!void {
self.consume(TokenType.IDENTIFIER, "Expect class name.");
const class_name = self.previous.?;
const name_constant = try self.identifier_constant(self.previous.?);
self.declare_variable();
try self.emit_bytes(@intFromEnum(OpCode.OP_CLASS), 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);
self.consume(TokenType.LEFT_BRACE, "Expect '{' before class body.");
while (!self.check(TokenType.RIGHT_BRACE) and !self.check(TokenType.EOF)) {
try self.method();
}
self.consume(TokenType.RIGHT_BRACE, "Expect '}' after class body.");
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 {
@ -909,30 +884,11 @@ pub const Parser = struct {
try self.emit_bytes(@intFromEnum(OpCode.OP_GET_PROPERTY), name);
}
}
fn method(self: *Parser) ParsingError!void {
self.consume(TokenType.IDENTIFIER, "Expect method name.");
const constant = try self.identifier_constant(self.previous.?);
try self.function(FunctionType.Method);
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 {
Function,
Script,
Method,
};
pub const Compiler = struct {
@ -959,8 +915,6 @@ pub const Compiler = struct {
.enclosing = enclosing,
};
compiler.local_count += 1;
compiler.locals[0].depth = 0;
compiler.locals[0].name = Token{
.token_type = TokenType.EOF,
@ -970,10 +924,7 @@ pub const Compiler = struct {
};
compiler.locals[0].is_captured = false;
if (function_type != FunctionType.Function) {
compiler.locals[0].name.start = "this";
compiler.locals[0].name.length = 4;
}
compiler.local_count += 1;
return compiler;
}

View File

@ -237,18 +237,12 @@ pub const ZloxAllocator = struct {
ObjType.Class => {
const class: *Obj.Class = obj.as_class();
self.mark_object(&class.name.obj);
self.mark_table(&class.methods);
},
ObjType.Instance => {
const instance: *Obj.Instance = obj.as_instance();
self.mark_object(&instance.class.obj);
self.mark_table(&instance.fields);
},
ObjType.BoundMethod => {
const bound_method: *Obj.BoundMethod = obj.as_bound_method();
self.mark_value(&bound_method.receiver);
self.mark_object(&bound_method.method.obj);
},
}
}

View File

@ -17,7 +17,6 @@ pub const ObjType = enum {
Upvalue,
Class,
Instance,
BoundMethod,
};
pub const NativeFn = *const fn (vm: *VM, arg_count: usize, args: []Value) Value;
@ -52,7 +51,6 @@ pub const Obj = struct {
ObjType.Upvalue => self.as_upvalue().destroy(),
ObjType.Class => self.as_class().destroy(),
ObjType.Instance => self.as_instance().destroy(),
ObjType.BoundMethod => self.as_bound_method().destroy(),
}
}
@ -168,19 +166,16 @@ pub const Obj = struct {
pub const Class = struct {
obj: Obj,
name: *Obj.String,
methods: Table,
pub fn new(vm: *VM, name: *Obj.String) *Class {
const class_obj = Obj.new(Class, vm, ObjType.Class);
class_obj.name = name;
class_obj.methods = Table.new(vm.allocator);
return class_obj;
}
pub fn destroy(self: *Class) void {
self.methods.destroy();
self.obj.allocator.destroy(self);
}
};
@ -205,25 +200,6 @@ pub const Obj = struct {
}
};
pub const BoundMethod = struct {
obj: Obj,
receiver: Value,
method: *Obj.Closure,
pub fn new(vm: *VM, receiver: Value, method: *Obj.Closure) *BoundMethod {
const bound_method = Obj.new(BoundMethod, vm, ObjType.BoundMethod);
bound_method.receiver = receiver;
bound_method.method = method;
return bound_method;
}
pub fn destroy(self: *BoundMethod) void {
self.obj.allocator.destroy(self);
}
};
pub fn is_type(self: *Obj, kind: ObjType) bool {
return self.kind == kind;
}
@ -256,10 +232,6 @@ pub const Obj = struct {
return self.is_type(ObjType.Instance);
}
pub fn is_bound_method(self: *Obj) bool {
return self.is_type(ObjType.BoundMethod);
}
pub fn print(self: *Obj) void {
switch (self.kind) {
ObjType.String => {
@ -292,10 +264,6 @@ pub const Obj = struct {
const obj = self.as_instance();
debug.print("{s} instance", .{obj.class.name.chars});
},
ObjType.BoundMethod => {
const obj = self.as_bound_method();
obj.method.function.obj.print();
},
}
}
@ -333,9 +301,4 @@ pub const Obj = struct {
std.debug.assert(self.kind == ObjType.Instance);
return @fieldParentPtr("obj", self);
}
pub fn as_bound_method(self: *Obj) *BoundMethod {
std.debug.assert(self.kind == ObjType.BoundMethod);
return @fieldParentPtr("obj", self);
}
};

View File

@ -31,5 +31,4 @@ pub const OpCode = enum(u8) {
OP_CLOSE_UPVALUE,
OP_RETURN,
OP_CLASS,
OP_METHOD,
};

View File

@ -311,9 +311,8 @@ pub const VM = struct {
continue;
}
if (!self.bind_method(instance.class, name)) {
return InterpretResult.RUNTIME_ERROR;
}
self.runtime_error("Undefined property"); // XXX to complete with name.chars
return InterpretResult.RUNTIME_ERROR;
},
@intFromEnum(OpCode.OP_SET_PROPERTY) => {
if (!self.peek(1).is_obj() or !self.peek(1).as_obj().is_instance()) {
@ -327,9 +326,6 @@ pub const VM = struct {
_ = self.pop();
_ = try self.push(value);
},
@intFromEnum(OpCode.OP_METHOD) => {
self.define_method(self.read_constant().as_string());
},
else => {
debug.print("Invalid instruction: {d}\n", .{instruction});
return InterpretResult.RUNTIME_ERROR;
@ -502,11 +498,6 @@ pub const VM = struct {
return true;
},
ObjType.BoundMethod => {
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);
},
else => {},
}
}
@ -514,21 +505,6 @@ pub const VM = struct {
return false;
}
pub fn bind_method(self: *VM, class: *Obj.Class, name: *Obj.String) bool {
var method: Value = Value.nil_val();
if (!class.methods.get(name, &method)) {
self.runtime_error("Undefined property."); // XXX add name.chars as '%s'.
return false;
}
const bound: *Obj.BoundMethod = Obj.BoundMethod.new(self, self.peek(0), method.as_obj().as_closure());
_ = self.pop();
try self.push(Value.obj_val(&bound.obj));
return true;
}
pub fn call(self: *VM, closure: *Obj.Closure, arg_count: usize) bool {
if (arg_count != closure.function.arity) {
self.runtime_error("Invalid argument count.");
@ -595,12 +571,4 @@ pub const VM = struct {
self.open_upvalues = upvalue.next;
}
}
fn define_method(self: *VM, name: *Obj.String) void {
const method = self.peek(0);
const class = self.peek(1).as_obj().as_class();
_ = class.methods.set(name, method);
_ = self.pop();
}
};