From 9f9debc67c034dbc2a68264f5c66b8333f418d36 Mon Sep 17 00:00:00 2001 From: Carter Snook Date: Thu, 7 Nov 2024 17:09:27 -0600 Subject: [PATCH] fix: invalid capture cache If a capture was specified in a different branch of an if statement, then we would incorrectly think that we had already loaded it in the parent environment. --- examples/regression/regression1.tl | 5 +++++ examples/regression/regression2.tl | 2 ++ examples/test.zig | 5 +++++ src/CodeGen.zig | 8 ++++---- src/Executable.zig | 6 ++++++ src/Vm.zig | 2 +- 6 files changed, 23 insertions(+), 5 deletions(-) create mode 100644 examples/regression/regression1.tl create mode 100644 examples/regression/regression2.tl diff --git a/examples/regression/regression1.tl b/examples/regression/regression1.tl new file mode 100644 index 0000000..04fd6ea --- /dev/null +++ b/examples/regression/regression1.tl @@ -0,0 +1,5 @@ +(let + ((b: num 41)) + ((if #f + (lambda () (let ((k: num b)) k)) + (lambda () b)))) diff --git a/examples/regression/regression2.tl b/examples/regression/regression2.tl new file mode 100644 index 0000000..80d1e82 --- /dev/null +++ b/examples/regression/regression2.tl @@ -0,0 +1,2 @@ + (let ((a: (-> (-> num)) (lambda () (lambda () (- 16 ((lambda () 5))))))(b: (-> bool) (lambda () #f))(c: num 156)(d: List (list: bool #f (= (if #t (let ((a: num (/ 24 (* (- (+ 40 (if #f 89 316)) 95) (+ (* 470 194) (let ((a: num (- 46 293))(b: num (/ 374 217))) a)))))(b: num 15)) (((let ((c: num b)(d: num (+ (/ 56 122) (* 7 60)))) (lambda () (lambda () 6)))))) (+ 32 (- 398 24))) 62)))) (let ((e: Ref num (ref: num 19))(f: List (list: num 169))(g: (-> num) (lambda () (if #t ((lambda () (if #t (let ((e: num (if #f 143 (/ 104 205)))(f: num 235)(g: num (let ((e: num ((lambda () 189)))(f: num ((lambda () 8)))(g: num 152)(h: num 21)) (let ((i: num 98)(j: num 92)) 326)))) 122) (* 90 (/ 11 (let ((e: num 26)(f: num 155)(g: num 11)(h: num 66)(i: num 124)) 20)))))) (* 384 102))))(h: num (/ (if (< 56 (- 75 58)) (if ((lambda () (= (let ((e: num c)(f: num 108)(g: num (* 141 65))(h: num 2)) 65) (- c 13)))) c 31) 38) ((lambda () (+ (if ((lambda () (= 49 75))) 208 38) (- (if (> 58 110) 14 c) 335))))))) 20)) + \ No newline at end of file diff --git a/examples/test.zig b/examples/test.zig index e93b140..0ccfe1b 100644 --- a/examples/test.zig +++ b/examples/test.zig @@ -195,6 +195,11 @@ test "identifiers" { try expectResult(@embedFile("identifiers.dl"), .definelang, "41.0"); } +test "regression" { + try expectResult(@embedFile("regression/regression1.tl"), .typelang, "41.0"); + try expectResult(@embedFile("regression/regression2.tl"), .typelang, "20.0"); +} + fn fuzzCodegen(initial_source: []const u8) !void { const source = std.testing.allocator.dupeZ(u8, initial_source) catch return; defer std.testing.allocator.free(source); diff --git a/src/CodeGen.zig b/src/CodeGen.zig index 78a8969..a3e693b 100644 --- a/src/CodeGen.zig +++ b/src/CodeGen.zig @@ -339,11 +339,11 @@ fn genIdentifier(cg: *CodeGen, exe: *Executable, identifier: []const u8, comptim }); if (!gop.found_existing) { gop.value_ptr.* = try cg.allocCapture(); - try parent.emit(.move_capture, .{ - .local = local, - .capture = @intCast(gop.value_ptr.*), - }, null); } + try parent.emit(.move_capture, .{ + .local = local, + .capture = @intCast(gop.value_ptr.*), + }, null); try exe.emit(.load_capture, @intCast(exe.captures.items.len), null); try exe.captures.append(cg.gpa, gop.value_ptr.*); if (is_typed) return parent.local_types.items[local]; diff --git a/src/Executable.zig b/src/Executable.zig index f764fed..6df0920 100644 --- a/src/Executable.zig +++ b/src/Executable.zig @@ -54,6 +54,10 @@ pub const Instruction = union(enum(u8)) { local: u16, capture: u16, }, + move_capture_u8: struct { + local: u8, + capture: u8, + }, load_local: u16, load_local_u8: u8, load_define: u16, @@ -105,6 +109,8 @@ pub fn emit( return exe.emit(.move_local_u8, @intCast(payload), source_hint); } else if (tag == .move_define and payload <= std.math.maxInt(u8)) { return exe.emit(.move_define_u8, @intCast(payload), source_hint); + } else if (tag == .move_capture and payload.local <= std.math.maxInt(u8) and payload.capture <= std.math.maxInt(u8)) { + return exe.emit(.move_capture_u8, .{ .local = @intCast(payload.local), .capture = @intCast(payload.capture) }, source_hint); } else if (tag == .push_list and payload <= std.math.maxInt(u8)) { return exe.emit(.push_list_u8, @intCast(payload), source_hint); } else if (tag == .call and payload <= std.math.maxInt(u8)) { diff --git a/src/Vm.zig b/src/Vm.zig index 568c27b..c57bf60 100644 --- a/src/Vm.zig +++ b/src/Vm.zig @@ -397,7 +397,7 @@ fn executeInner(vm: *Vm, cur: *StackInfo, program: *const Executable) ![]Value { .move_define, .move_define_u8 => { vm.stack.items[payload] = vm.stack.pop(); }, - .move_capture => { + .move_capture, .move_capture_u8 => { vm.stack.items[vm.captures_start + payload.capture] = vm.stack.items[cur.stack_start + payload.local]; }, .jump => {