commit b2f59867f59d26a2dbdf0a10b0142057053d4849
parent bdf60511df5e35856bb557b5d5946b7b2349f8d4
Author: Szymon Mikulicz <szymon.mikulicz@aptiv.com>
Date: Sun, 11 Aug 2024 12:17:27 +0200
Function declaration
Diffstat:
4 files changed, 78 insertions(+), 27 deletions(-)
diff --git a/zlox/src/compiler.zig b/zlox/src/compiler.zig
@@ -33,7 +33,6 @@ const Precedence = enum {
}
};
-
pub fn Compiler(size: comptime_int) type {
return struct {
current: scanner.Token,
@@ -42,7 +41,7 @@ pub fn Compiler(size: comptime_int) type {
lastError: CompilerError,
hadError: bool,
panicMode: bool,
- function: *Obj.Function,
+ currentFunction: *Obj.Function,
objects: *Obj.List,
locals: [size]Local,
localCount: usize,
@@ -151,7 +150,7 @@ pub fn Compiler(size: comptime_int) type {
}
fn currentChunk(self: *Self) *Chunk {
- return self.function.chunk;
+ return self.currentFunction.chunk;
}
fn emitByte(self: *Self, byte: u8) void {
@@ -180,7 +179,7 @@ pub fn Compiler(size: comptime_int) type {
fn end(self: *Self) *Obj.Function {
self.emitReturn();
- return self.function;
+ return self.currentFunction;
}
fn emitReturn(self: *Self) void {
@@ -203,7 +202,7 @@ pub fn Compiler(size: comptime_int) type {
const canAssign = precedence.lessOrEq(Precedence.ASSIGNMENT);
self.advance();
- if (getRule(self.previous.type catch unreachable).prefix) |prefixRule| {
+ if (getRule(self.previous.type catch return).prefix) |prefixRule| {
prefixRule(self, canAssign);
} else {
self.lastError = CompilerError.NotAnExpression;
@@ -303,12 +302,11 @@ pub fn Compiler(size: comptime_int) type {
}
fn parseLiteralString(self: *Self) !Value {
- return Value.init(try self.objects.emplace(.String, &.{self.previous.lexeme[1 .. self.previous.lexeme.len - 1]}));
+ return Value.init(try self.objects.emplace_cast(.String, &.{self.previous.lexeme[1 .. self.previous.lexeme.len - 1]}));
}
fn parseLiteralTable(self: *Self) CompilerError!Value {
- var ret = try self.objects.emplace(.Table, {});
- var tabl = ret.cast(.Table) catch unreachable;
+ var tabl = try self.objects.emplace(.Table, {});
while (!self.match(Token.RIGHT_BRACKET)) {
const key = try self.parseLiteralValue();
self.consume(Token.COLON, "Expect ':' after key in table initalizer");
@@ -325,7 +323,7 @@ pub fn Compiler(size: comptime_int) type {
break;
self.consume(Token.COMMA, "Expect ',' after value in table initalizer");
}
- return Value.init(ret);
+ return Value.init(tabl.cast());
}
fn table(self: *Self, _: bool) void {
@@ -477,7 +475,9 @@ pub fn Compiler(size: comptime_int) type {
}
fn declaration(self: *Self) void {
- if (self.match(Token.VAR)) {
+ if (self.match(Token.FUN)) {
+ self.funDeclaration();
+ } else if (self.match(Token.VAR)) {
self.varDeclaration();
} else if (self.match(Token.CON)) {
self.conDeclaration();
@@ -488,6 +488,55 @@ pub fn Compiler(size: comptime_int) type {
if (self.panicMode) self.synchronize();
}
+ fn funDeclaration(self: *Self) void {
+ const global = self.parseVariable("Expect function name.", true) catch return;
+ self.markInitialized();
+ self.function(self.previous.lexeme, Obj.Function.Type.Function);
+ self.defineVariable(global, true);
+ }
+
+ fn function(self: *Self, name: []const u8, tp: Obj.Function.Type) void {
+ var fun = self.objects.emplace(Obj.Type.Function, tp) catch |err| {
+ self.errorAtPrevious("Couldn't allocate function");
+ self.lastError = err;
+ return;
+ };
+ fun.name = self.objects.emplace(Obj.Type.String, &.{name}) catch |err| {
+ self.errorAtPrevious("Couldn't allocate function name");
+ self.lastError = err;
+ return;
+ };
+
+ var compiler = Self.init(self.scanner, self.objects, fun);
+ compiler.current = self.current;
+ compiler.beginScope();
+
+ compiler.consume(Token.LEFT_PAREN, "Expect '(' after function name");
+ if (!compiler.check(Token.RIGHT_PAREN)) {
+ while (true) {
+ if (fun.arity == std.math.maxInt(@TypeOf(fun.arity))) {
+ self.errorAtCurrent("Too many arguments to a function");
+ return;
+ }
+ fun.arity += 1;
+ compiler.defineVariable(compiler.parseVariable("Expect parameter name.", true) catch return, true);
+ if (!compiler.match(Token.COMMA)) break;
+ }
+ }
+ compiler.consume(Token.RIGHT_PAREN, "Expect ')' after parameters");
+ compiler.consume(Token.LEFT_BRACE, "Expect '{' before function body");
+
+ compiler.block();
+
+ self.current = compiler.current;
+
+ if (compiler.hadError) {
+ self.lastError = compiler.lastError;
+ } else {
+ self.emit(OP.CONSTANT, self.makeConstant(Value.init(compiler.end().cast())));
+ }
+ }
+
fn varDeclaration(self: *Self) void {
const global = self.parseVariable("Expect variable name.", false) catch return;
@@ -524,7 +573,7 @@ pub fn Compiler(size: comptime_int) type {
}
fn identifierConstant(self: *Self, tok: scanner.Token) !u8 {
- return self.makeConstant(Value.init(self.objects.emplace(.String, &.{tok.lexeme}) catch |err| {
+ return self.makeConstant(Value.init(self.objects.emplace_cast(.String, &.{tok.lexeme}) catch |err| {
self.lastError = err;
self.errorAtPrevious("Couldn't allocate identifier");
return err;
@@ -563,6 +612,7 @@ pub fn Compiler(size: comptime_int) type {
}
fn markInitialized(self: *Self) void {
+ if(self.scopeDepth == 0) return;
self.locals[self.localCount-1].depth = self.scopeDepth;
}
@@ -614,12 +664,11 @@ pub fn Compiler(size: comptime_int) type {
fn switchStatement(self: *Self) void {
self.consume(Token.LEFT_PAREN, "Expect '(' after 'switch'.");
- var ret = self.objects.emplace(.Table, {}) catch |err| {
+ var tabl = self.objects.emplace(.Table, {}) catch |err| {
self.lastError = err;
return;
};
- var tabl = ret.cast(.Table) catch unreachable;
- self.emitConstant(Value.init(ret));
+ self.emitConstant(Value.init(tabl.cast()));
self.expression();
@@ -841,7 +890,7 @@ pub fn Compiler(size: comptime_int) type {
self.emitOP(OP.PRINT);
}
- fn init(scan: *scanner.Scanner, objects: *Obj.List, function: *Obj.Function) Self {
+ fn init(scan: *scanner.Scanner, objects: *Obj.List, fun: *Obj.Function) Self {
return Self{
.scanner = scan,
.current = scanner.Token.Empty,
@@ -849,7 +898,7 @@ pub fn Compiler(size: comptime_int) type {
.panicMode = false,
.hadError = false,
.lastError = scanner.ScannerError.EmptyToken,
- .function = function,
+ .currentFunction = fun,
.objects = objects,
.locals = [_]Local{Local{.name = scanner.Token.Empty, .depth = 0, .con = true}} ** size,
.localCount = 1,
@@ -859,8 +908,8 @@ pub fn Compiler(size: comptime_int) type {
pub fn compile(source: []const u8, objects: *Obj.List) CompilerError!*Obj.Function {
var scan = try scanner.Scanner.init(source);
- var function = try objects.emplace(Obj.Type.Function, Obj.Function.Type.Script);
- var self = Self.init(&scan, objects, function.cast(.Function) catch unreachable);
+ const fun = try objects.emplace(Obj.Type.Function, Obj.Function.Type.Script);
+ var self = Self.init(&scan, objects, fun);
self.advance();
diff --git a/zlox/src/obj/function.zig b/zlox/src/obj/function.zig
@@ -17,7 +17,7 @@ pub const Function = packed struct {
obj: Super,
arity: u8,
chunk: *chunk.Chunk,
- name: ?*String,
+ name: ?*const String,
type: Type,
pub fn init(tp: Arg, allocator: std.mem.Allocator) Error!*Self {
@@ -52,9 +52,7 @@ pub const Function = packed struct {
_ = try writer.writeAll(">");
}
- pub fn eql(self: *const Self, other: *const Self) bool {
- _ = self;
- _ = other;
+ pub fn eql(_: *const Self, _: *const Self) bool {
return false;
}
diff --git a/zlox/src/obj/list.zig b/zlox/src/obj/list.zig
@@ -27,16 +27,20 @@ pub const List = struct {
self.tip = new_tip;
}
- pub fn emplace(self: *Self, comptime tp: Type, arg: tp.get().Arg) Error!*Super {
+ pub fn emplace(self: *Self, comptime tp: Type, arg: tp.get().Arg) Error!*tp.get() {
var newObj = true;
const obj = switch (tp) {
- .String => (try String.intern(arg, &self.table, &newObj, self.allocator)).cast(),
- else => try Super.init(tp, arg, self.allocator),
+ .String => try String.intern(arg, &self.table, &newObj, self.allocator),
+ else => try tp.get().init(arg, self.allocator),
};
- if (newObj) try self.push(obj);
+ if (newObj) try self.push(obj.cast());
return obj;
}
+ pub fn emplace_cast(self: *Self, comptime tp: Type, arg: tp.get().Arg) Error!*Super {
+ return (try self.emplace(tp, arg)).cast();
+ }
+
pub fn pop(self: *Self) ?*Element {
if (self.tip) |tip| {
self.tip = tip.next;
diff --git a/zlox/src/vm/callbacks.zig b/zlox/src/vm/callbacks.zig
@@ -27,7 +27,7 @@ pub fn concatenate(objects: *Obj.List) Type(Obj.Type.String, Obj.Type.String) {
const Ret = Type(Obj.Type.String, Obj.Type.String);
const ret = Ret{ .objects = objects, ._call = struct {
pub fn concatenate(self: *const Ret, lhs: *Obj, rhs: *Obj) Error!*Obj {
- return try self.objects.emplace(.String, &.{ (lhs.cast(.String) catch unreachable).slice(), (rhs.cast(.String) catch unreachable).slice() });
+ return try self.objects.emplace_cast(.String, &.{ (lhs.cast(.String) catch unreachable).slice(), (rhs.cast(.String) catch unreachable).slice() });
}
}.concatenate };
return ret;