From e77bb3a9ecd746a3126766b6ce7afb855553d183 Mon Sep 17 00:00:00 2001 From: Benoit Giannangeli Date: Fri, 17 May 2024 10:37:05 +0200 Subject: [PATCH] fix: Don't stop the REPL on runtime errors closes #286 --- src/Parser.zig | 99 ++++++++-------- src/obj.zig | 1 + src/vm.zig | 304 ++++++++++++++++++++++++++++++++++++------------- 3 files changed, 276 insertions(+), 128 deletions(-) diff --git a/src/Parser.zig b/src/Parser.zig index c20b5793..07753ec7 100644 --- a/src/Parser.zig +++ b/src/Parser.zig @@ -784,20 +784,6 @@ pub fn parse(self: *Self, source: []const u8, file_name: []const u8) !?Ast { else => "???", }; - const function_def = obj.ObjFunction.FunctionDef{ - .id = obj.ObjFunction.FunctionDef.nextId(), - .name = try self.gc.copyString(function_name), - .script_name = try self.gc.copyString(file_name), - .return_type = self.gc.type_registry.void_type, - .yield_type = self.gc.type_registry.void_type, - .parameters = std.AutoArrayHashMap(*obj.ObjString, *obj.ObjTypeDef).init(self.gc.allocator), - .defaults = std.AutoArrayHashMap(*obj.ObjString, Value).init(self.gc.allocator), - .function_type = function_type, - .generic_types = std.AutoArrayHashMap(*obj.ObjString, *obj.ObjTypeDef).init(self.gc.allocator), - }; - - const function_type_def = obj.ObjTypeDef.TypeUnion{ .Function = function_def }; - const body_node = try self.ast.appendNode( .{ .tag = .Block, @@ -817,7 +803,19 @@ pub fn parse(self: *Self, source: []const u8, file_name: []const u8) !?Ast { .type_def = try self.gc.type_registry.getTypeDef( .{ .def_type = .Function, - .resolved_type = function_type_def, + .resolved_type = .{ + .Function = .{ + .id = obj.ObjFunction.FunctionDef.nextId(), + .name = try self.gc.copyString(function_name), + .script_name = try self.gc.copyString(file_name), + .return_type = self.gc.type_registry.void_type, + .yield_type = self.gc.type_registry.void_type, + .parameters = std.AutoArrayHashMap(*obj.ObjString, *obj.ObjTypeDef).init(self.gc.allocator), + .defaults = std.AutoArrayHashMap(*obj.ObjString, Value).init(self.gc.allocator), + .function_type = function_type, + .generic_types = std.AutoArrayHashMap(*obj.ObjString, *obj.ObjTypeDef).init(self.gc.allocator), + }, + }, }, ), .components = .{ @@ -985,17 +983,15 @@ fn beginFrame(self: *Self, function_type: obj.ObjFunction.FunctionType, function }, .EntryPoint, .ScriptEntryPoint => { // `args` is [str] - const list_def = obj.ObjList.ListDef.init( - self.gc.allocator, - self.gc.type_registry.str_type, - ); - - const list_union: obj.ObjTypeDef.TypeUnion = .{ .List = list_def }; - local.type_def = try self.gc.type_registry.getTypeDef( - obj.ObjTypeDef{ + .{ .def_type = .List, - .resolved_type = list_union, + .resolved_type = .{ + .List = obj.ObjList.ListDef.init( + self.gc.allocator, + self.gc.type_registry.str_type, + ), + }, }, ); }, @@ -1409,7 +1405,7 @@ fn declaration(self: *Self) Error!?Ast.Node.Index { // `prefix.Type variable` or try self.checkSequenceAhead(&[_]?Token.Type{ .Identifier, .Dot, .Identifier, .Identifier }, 4) // `prefix.Type? variable` - or try self.checkSequenceAhead(&[_]?Token.Type{ .Identifier, .Dot, .Identifier, .Question, .Identifier }, 4) + or try self.checkSequenceAhead(&[_]?Token.Type{ .Identifier, .Dot, .Identifier, .Question, .Identifier }, 5) // `Type? variable` or try self.checkSequenceAhead(&[_]?Token.Type{ .Identifier, .Question, .Identifier }, 3) // `Type::<...> variable` @@ -1575,7 +1571,7 @@ fn addGlobal(self: *Self, name: Ast.TokenIndex, global_type: *obj.ObjTypeDef, co } try self.globals.append( - Global{ + .{ .prefix = self.namespace, .name_token = name, .name = try self.gc.copyString(lexemes[name]), @@ -2618,14 +2614,6 @@ fn parseFiberType(self: *Self, generic_types: ?std.AutoArrayHashMap(*obj.ObjStri try self.consume(.Greater, "Expected `>` after fiber yield type"); - const fiber_def = obj.ObjFiber.FiberDef{ - .return_type = self.ast.nodes.items(.type_def)[return_type].?, - .yield_type = self.ast.nodes.items(.type_def)[yield_type].?, - }; - const resolved_type = obj.ObjTypeDef.TypeUnion{ - .Fiber = fiber_def, - }; - return self.ast.appendNode( .{ .tag = .FiberType, @@ -2635,7 +2623,12 @@ fn parseFiberType(self: *Self, generic_types: ?std.AutoArrayHashMap(*obj.ObjStri obj.ObjTypeDef{ .optional = try self.match(.Question), .def_type = .Fiber, - .resolved_type = resolved_type, + .resolved_type = .{ + .Fiber = .{ + .return_type = self.ast.nodes.items(.type_def)[return_type].?, + .yield_type = self.ast.nodes.items(.type_def)[yield_type].?, + }, + }, }, ), .components = .{ @@ -2654,15 +2647,16 @@ fn parseListType(self: *Self, generic_types: ?std.AutoArrayHashMap(*obj.ObjStrin try self.consume(.RightBracket, "Expected `]` after list type."); - const list_def = obj.ObjList.ListDef.init(self.gc.allocator, self.ast.nodes.items(.type_def)[item_type].?); - const resolved_type = obj.ObjTypeDef.TypeUnion{ - .List = list_def, - }; const list_type_def = try self.gc.type_registry.getTypeDef( .{ .optional = try self.match(.Question), .def_type = .List, - .resolved_type = resolved_type, + .resolved_type = .{ + .List = obj.ObjList.ListDef.init( + self.gc.allocator, + self.ast.nodes.items(.type_def)[item_type].?, + ), + }, }, ); @@ -2693,24 +2687,25 @@ fn parseMapType(self: *Self, generic_types: ?std.AutoArrayHashMap(*obj.ObjString try self.consume(.RightBrace, "Expected `}` after value type."); const type_defs = self.ast.nodes.items(.type_def); - const map_def = obj.ObjMap.MapDef.init(self.gc.allocator, type_defs[key_type].?, type_defs[value_type].?); - const resolved_type = obj.ObjTypeDef.TypeUnion{ - .Map = map_def, - }; - const map_type_def = try self.gc.type_registry.getTypeDef( - .{ - .optional = try self.match(.Question), - .def_type = .Map, - .resolved_type = resolved_type, - }, - ); return try self.ast.appendNode( .{ .tag = .MapType, .location = start_location, .end_location = self.current_token.? - 1, - .type_def = map_type_def, + .type_def = try self.gc.type_registry.getTypeDef( + .{ + .optional = try self.match(.Question), + .def_type = .Map, + .resolved_type = .{ + .Map = obj.ObjMap.MapDef.init( + self.gc.allocator, + type_defs[key_type].?, + type_defs[value_type].?, + ), + }, + }, + ), .components = .{ .MapType = .{ .key_type = key_type, diff --git a/src/obj.zig b/src/obj.zig index 2bff9f4f..edbd55f4 100644 --- a/src/obj.zig +++ b/src/obj.zig @@ -3511,6 +3511,7 @@ pub const ObjBoundMethod = struct { pub const ObjTypeDef = struct { const Self = @This(); + // WARN: order is important pub const Type = enum(u8) { Any, Bool, diff --git a/src/vm.zig b/src/vm.zig index 0a2efa47..f90180f8 100644 --- a/src/vm.zig +++ b/src/vm.zig @@ -268,7 +268,7 @@ pub const Fiber = struct { } } - pub fn resolve_(self: *Self, vm: *VM) !void { + pub fn resolve(self: *Self, vm: *VM) !void { self.resolved = true; switch (self.status) { @@ -290,7 +290,7 @@ pub const Fiber = struct { } } - pub fn finish(self: *Self, vm: *VM, result: Value) !void { + pub fn finish(self: *Self, vm: *VM, result: Value) void { // Fiber is now over self.status = .Over; const resolved = self.resolved; @@ -1305,9 +1305,14 @@ pub const VM = struct { fn OP_RESUME(self: *Self, _: *CallFrame, _: u32, _: OpCode, _: u24) void { const obj_fiber = self.pop().obj().access(ObjFiber, .Fiber, self.gc).?; - obj_fiber.fiber.@"resume"(self) catch { - self.panic("Out of memory"); - unreachable; + obj_fiber.fiber.@"resume"(self) catch |err| { + switch (err) { + Error.RuntimeError => return, + else => { + self.panic("Out of memory"); + unreachable; + }, + } }; const next_full_instruction: u32 = self.readInstruction(); @@ -1326,9 +1331,14 @@ pub const VM = struct { fn OP_RESOLVE(self: *Self, _: *CallFrame, _: u32, _: OpCode, _: u24) void { const obj_fiber = self.pop().obj().access(ObjFiber, .Fiber, self.gc).?; - obj_fiber.fiber.resolve_(self) catch { - self.panic("Out of memory"); - unreachable; + obj_fiber.fiber.resolve(self) catch |err| { + switch (err) { + Error.RuntimeError => return, + else => { + self.panic("Out of memory"); + unreachable; + }, + } }; const next_full_instruction: u32 = self.readInstruction(); @@ -1374,9 +1384,14 @@ pub const VM = struct { arg_count, catch_value, false, - ) catch { - self.panic("Out of memory"); - unreachable; + ) catch |err| { + switch (err) { + Error.RuntimeError => return, + else => { + self.panic("Out of memory"); + unreachable; + }, + } }; const next_full_instruction: u32 = self.readInstruction(); @@ -1405,9 +1420,14 @@ pub const VM = struct { arg_count, catch_value, false, - ) catch { - self.panic("Out of memory"); - unreachable; + ) catch |err| { + switch (err) { + Error.RuntimeError => return, + else => { + self.panic("Out of memory"); + unreachable; + }, + } }; const next_full_instruction: u32 = self.readInstruction(); @@ -1438,9 +1458,19 @@ pub const VM = struct { if (instance.fields.get(method)) |field| { (self.current_fiber.stack_top - arg_count - 1)[0] = field; - self.callValue(field, arg_count, catch_value, false) catch { - self.panic("Out of memory"); - unreachable; + self.callValue( + field, + arg_count, + catch_value, + false, + ) catch |err| { + switch (err) { + Error.RuntimeError => return, + else => { + self.panic("Out of memory"); + unreachable; + }, + } }; } else { _ = self.invokeFromObject( @@ -1450,9 +1480,14 @@ pub const VM = struct { catch_value, false, false, - ) catch { - self.panic("Out of memory"); - unreachable; + ) catch |err| { + switch (err) { + Error.RuntimeError => return, + else => { + self.panic("Out of memory"); + unreachable; + }, + } }; } @@ -1484,9 +1519,19 @@ pub const VM = struct { if (instance.fields.get(method)) |field| { (self.current_fiber.stack_top - arg_count - 1)[0] = field; - self.tailCall(field, arg_count, catch_value, false) catch { - self.panic("Out of memory"); - unreachable; + self.tailCall( + field, + arg_count, + catch_value, + false, + ) catch |err| { + switch (err) { + Error.RuntimeError => return, + else => { + self.panic("Out of memory"); + unreachable; + }, + } }; } else { _ = self.invokeFromObject( @@ -1496,9 +1541,14 @@ pub const VM = struct { catch_value, false, true, - ) catch { - self.panic("Out of memory"); - unreachable; + ) catch |err| { + switch (err) { + Error.RuntimeError => return, + else => { + self.panic("Out of memory"); + unreachable; + }, + } }; } @@ -1530,9 +1580,19 @@ pub const VM = struct { const member_value: Value = member.toValue(); (self.current_fiber.stack_top - arg_count - 1)[0] = member_value; - self.callValue(member_value, arg_count, catch_value, false) catch { - self.panic("Out of memory"); - unreachable; + self.callValue( + member_value, + arg_count, + catch_value, + false, + ) catch |err| { + switch (err) { + Error.RuntimeError => return, + else => { + self.panic("Out of memory"); + unreachable; + }, + } }; const next_full_instruction: u32 = self.readInstruction(); @@ -1563,9 +1623,19 @@ pub const VM = struct { const member_value: Value = member.toValue(); (self.current_fiber.stack_top - arg_count - 1)[0] = member_value; - self.callValue(member_value, arg_count, catch_value, false) catch { - self.panic("Out of memory"); - unreachable; + self.callValue( + member_value, + arg_count, + catch_value, + false, + ) catch |err| { + switch (err) { + Error.RuntimeError => return, + else => { + self.panic("Out of memory"); + unreachable; + }, + } }; const next_full_instruction: u32 = self.readInstruction(); @@ -1596,9 +1666,19 @@ pub const VM = struct { const member_value: Value = member.toValue(); (self.current_fiber.stack_top - arg_count - 1)[0] = member_value; - self.callValue(member_value, arg_count, catch_value, false) catch { - self.panic("Out of memory"); - unreachable; + self.callValue( + member_value, + arg_count, + catch_value, + false, + ) catch |err| { + switch (err) { + Error.RuntimeError => return, + else => { + self.panic("Out of memory"); + unreachable; + }, + } }; const next_full_instruction: u32 = self.readInstruction(); @@ -1628,9 +1708,19 @@ pub const VM = struct { }).?; const member_value: Value = member.toValue(); (self.current_fiber.stack_top - arg_count - 1)[0] = member_value; - self.callValue(member_value, arg_count, catch_value, false) catch { - self.panic("Out of memory"); - unreachable; + self.callValue( + member_value, + arg_count, + catch_value, + false, + ) catch |err| { + switch (err) { + Error.RuntimeError => return, + else => { + self.panic("Out of memory"); + unreachable; + }, + } }; const next_full_instruction: u32 = self.readInstruction(); @@ -1662,9 +1752,19 @@ pub const VM = struct { const member_value: Value = member.toValue(); (self.current_fiber.stack_top - arg_count - 1)[0] = member_value; - self.callValue(member_value, arg_count, catch_value, false) catch { - self.panic("Out of memory"); - unreachable; + self.callValue( + member_value, + arg_count, + catch_value, + false, + ) catch |err| { + switch (err) { + Error.RuntimeError => return, + else => { + self.panic("Out of memory"); + unreachable; + }, + } }; const next_full_instruction: u32 = self.readInstruction(); @@ -1696,9 +1796,19 @@ pub const VM = struct { const member_value: Value = member.toValue(); (self.current_fiber.stack_top - arg_count - 1)[0] = member_value; - self.callValue(member_value, arg_count, catch_value, false) catch { - self.panic("Out of memory"); - unreachable; + self.callValue( + member_value, + arg_count, + catch_value, + false, + ) catch |err| { + switch (err) { + Error.RuntimeError => return, + else => { + self.panic("Out of memory"); + unreachable; + }, + } }; const next_full_instruction: u32 = self.readInstruction(); @@ -1730,10 +1840,7 @@ pub const VM = struct { if (self.current_fiber.frame_count == 0) { // We're in a fiber if (self.current_fiber.parent_fiber != null) { - self.current_fiber.finish(self, result) catch { - self.panic("Out of memory"); - unreachable; - }; + self.current_fiber.finish(self, result); // Don't stop the VM return false; @@ -1835,9 +1942,14 @@ pub const VM = struct { // defer gn.deinit(); // } - vm.interpret(self.current_ast, closure.function, null) catch { - self.panic("Out of memory"); - unreachable; + vm.interpret(self.current_ast, closure.function, null) catch |err| { + switch (err) { + Error.RuntimeError => return, + else => { + self.panic("Out of memory"); + unreachable; + }, + } }; // Top of stack is how many export we got @@ -1927,9 +2039,14 @@ pub const VM = struct { self.pop(), null, null, - ) catch { - self.panic("Out of memory"); - unreachable; + ) catch |err| { + switch (err) { + Error.RuntimeError => return, + else => { + self.panic("Out of memory"); + unreachable; + }, + } }; const next_full_instruction: u32 = self.readInstruction(); @@ -2107,9 +2224,14 @@ pub const VM = struct { }).toValue(), null, null, - ) catch { - self.panic("Out of memory"); - unreachable; + ) catch |err| { + switch (err) { + Error.RuntimeError => return, + else => { + self.panic("Out of memory"); + unreachable; + }, + } }; } @@ -2124,9 +2246,14 @@ pub const VM = struct { }).toValue(), null, null, - ) catch { - self.panic("Out of memory"); - unreachable; + ) catch |err| { + switch (err) { + Error.RuntimeError => return, + else => { + self.panic("Out of memory"); + unreachable; + }, + } }; return; @@ -2197,9 +2324,14 @@ pub const VM = struct { }).toValue(), null, null, - ) catch { - self.panic("Out of memory"); - unreachable; + ) catch |err| { + switch (err) { + Error.RuntimeError => return, + else => { + self.panic("Out of memory"); + unreachable; + }, + } }; } @@ -2226,9 +2358,14 @@ pub const VM = struct { }).toValue(), null, null, - ) catch { - self.panic("Out of memory"); - unreachable; + ) catch |err| { + switch (err) { + Error.RuntimeError => return, + else => { + self.panic("Out of memory"); + unreachable; + }, + } }; } @@ -2260,9 +2397,14 @@ pub const VM = struct { }).toValue(), null, null, - ) catch { - self.panic("Out of memory"); - unreachable; + ) catch |err| { + switch (err) { + Error.RuntimeError => return, + else => { + self.panic("Out of memory"); + unreachable; + }, + } }; } @@ -2290,9 +2432,14 @@ pub const VM = struct { }).toValue(), null, null, - ) catch { - self.panic("Out of memory"); - unreachable; + ) catch |err| { + switch (err) { + Error.RuntimeError => return, + else => { + self.panic("Out of memory"); + unreachable; + }, + } }; } @@ -3808,9 +3955,14 @@ pub const VM = struct { }).toValue(), null, null, - ) catch { - self.panic("Out of memory"); - unreachable; + ) catch |err| { + switch (err) { + Error.RuntimeError => return, + else => { + self.panic("Out of memory"); + unreachable; + }, + } }; } @@ -4062,7 +4214,7 @@ pub const VM = struct { stack.items, ); - if (!is_wasm) { + if (!is_wasm and self.flavor != .Repl) { std.process.exit(1); } else { return Error.RuntimeError;