From f349e66ae6a832fdc25eec508a90f44b59d24c96 Mon Sep 17 00:00:00 2001 From: Benoit Giannangeli Date: Wed, 15 Oct 2025 16:05:38 +0200 Subject: [PATCH 1/4] chore: zig 0.16.0-dev.728+87c18945c --- build.zig | 7 +++ src/Ast.zig | 9 +-- src/Codegen.zig | 12 ++-- src/FFI.zig | 24 +++---- src/GC.zig | 8 +-- src/Jit.zig | 119 +++++++++++++++++++---------------- src/Parser.zig | 101 ++++++++++++++--------------- src/Reporter.zig | 78 +++++++++++------------ src/behavior.zig | 10 +-- src/builtin/list.zig | 11 ++-- src/builtin/str.zig | 9 ++- src/buzz_api.zig | 6 +- src/io.zig | 45 +++++++------ src/lib/buzz_buffer.zig | 67 +++++++++++++------- src/lib/buzz_ffi.zig | 28 ++++++--- src/lib/buzz_io.zig | 52 ++++++++------- src/lib/buzz_os.zig | 99 ++++++++++++++++------------- src/lsp.zig | 47 ++++++++------ src/obj.zig | 16 ++--- src/renderer.zig | 61 +++++++++--------- src/repl.zig | 31 ++++----- src/tests/fmt.zig | 5 +- src/value.zig | 10 +-- src/vm.zig | 12 ++-- src/wasm_repl.zig | 18 +++--- src/writeable_array_list.zig | 47 -------------- 26 files changed, 490 insertions(+), 442 deletions(-) delete mode 100644 src/writeable_array_list.zig diff --git a/build.zig b/build.zig index 60cf6582..d97ace16 100644 --- a/build.zig +++ b/build.zig @@ -382,6 +382,11 @@ pub fn build(b: *Build) !void { }, ); + exe_check.root_module.addImport( + "clap", + clap.module("clap"), + ); + exe.root_module.sanitize_c = .off; if (behavior_exe) |bexe| bexe.root_module.sanitize_c = .off; if (!is_wasm) lsp_exe.?.root_module.sanitize_c = .off; @@ -659,6 +664,7 @@ pub fn buildPcre2(b: *Build, target: Build.ResolvedTarget, optimize: std.builtin .{ .target = target, .optimize = optimize, + .sanitize_c = .off, }, ), }, @@ -782,6 +788,7 @@ pub fn buildLinenoise(b: *Build, target: Build.ResolvedTarget, optimize: std.bui .{ .target = target, .optimize = optimize, + .sanitize_c = .off, }, ), }, diff --git a/src/Ast.zig b/src/Ast.zig index cc9cf897..53af31d7 100644 --- a/src/Ast.zig +++ b/src/Ast.zig @@ -819,13 +819,14 @@ pub const Slice = struct { .String => string: { const elements = self.nodes.items(.components)[node].String; - var string = std.ArrayList(u8).empty; - const writer = &string.writer(gc.allocator); + var string = std.Io.Writer.Allocating.init(gc.allocator); + defer string.deinit(); + for (elements) |element| { - try (try self.toValue(element, gc)).toString(writer); + try (try self.toValue(element, gc)).toString(&string.writer); } - break :string (try gc.copyString(try string.toOwnedSlice(gc.allocator))).toValue(); + break :string (try gc.copyString(string.written())).toValue(); }, .Subscript => subscript: { const components = self.nodes.items(.components)[node].Subscript; diff --git a/src/Codegen.zig b/src/Codegen.zig index 08ba2893..10762622 100644 --- a/src/Codegen.zig +++ b/src/Codegen.zig @@ -24,6 +24,7 @@ pub const Error = error{ UnwrappedNull, OutOfBound, ReachedMaximumMemoryUsage, + WriteFailed, } || std.mem.Allocator.Error || std.fmt.BufPrintError; pub const Frame = struct { @@ -1246,10 +1247,11 @@ fn generateCall(self: *Self, node: Ast.Node.Index, breaks: ?*Breaks) Error!?*obj } if (missing_arguments.count() > 0) { - var missing = std.ArrayList(u8).empty; - const missing_writer = missing.writer(self.gc.allocator); + var missing = std.Io.Writer.Allocating.init(self.gc.allocator); + defer missing.deinit(); + for (missing_arguments.keys(), 0..) |key, i| { - try missing_writer.print( + try missing.writer.print( "{s}{s}", .{ key, @@ -1260,7 +1262,7 @@ fn generateCall(self: *Self, node: Ast.Node.Index, breaks: ?*Breaks) Error!?*obj }, ); } - defer missing.deinit(self.gc.allocator); + self.reporter.reportErrorFmt( .call_arguments, self.ast.tokens.get(locations[node]), @@ -1271,7 +1273,7 @@ fn generateCall(self: *Self, node: Ast.Node.Index, breaks: ?*Breaks) Error!?*obj "s" else "", - missing.items, + missing.written(), }, ); } diff --git a/src/FFI.zig b/src/FFI.zig index bdff3803..67e2d391 100644 --- a/src/FFI.zig +++ b/src/FFI.zig @@ -212,15 +212,15 @@ pub fn parseTypeExpr(self: *Self, ztype: []const u8) !?*Zdef { return zdef; } - var full = std.ArrayList(u8).empty; - defer full.deinit(self.gc.allocator); + var full = std.Io.Writer.Allocating.init(self.gc.allocator); + defer full.deinit(); - full.writer(self.gc.allocator).print("const zig_type: {s};", .{ztype}) catch @panic("Out of memory"); + full.writer.print("const zig_type: {s};", .{ztype}) catch @panic("Out of memory"); const zdef = try self.parse( null, 0, - full.items, + full.written(), ); std.debug.assert(zdef == null or zdef.?.len == 1); @@ -527,10 +527,10 @@ fn unionContainer(self: *Self, name: []const u8, container: Ast.full.ContainerDe }, }; - var qualified_name = std.ArrayList(u8).empty; - defer qualified_name.deinit(self.gc.allocator); + var qualified_name = std.Io.Writer.Allocating.init(self.gc.allocator); + defer qualified_name.deinit(); - try qualified_name.writer(self.gc.allocator).print( + try qualified_name.writer.print( "{s}.{s}", .{ self.state.?.script, @@ -548,7 +548,7 @@ fn unionContainer(self: *Self, name: []const u8, container: Ast.full.ContainerDe .location = self.state.?.source, .name = try self.gc.copyString(name), // FIXME - .qualified_name = try self.gc.copyString(qualified_name.items), + .qualified_name = try self.gc.copyString(qualified_name.written()), .zig_type = zig_type, .buzz_type = buzz_fields, .fields = get_set_fields, @@ -918,16 +918,16 @@ fn fnProto(self: *Self, tag: Ast.Node.Tag, decl_index: Ast.Node.Index) anyerror! } fn reportZigError(self: *Self, err: Ast.Error) void { - var message = std.ArrayList(u8).empty; - defer message.deinit(self.gc.allocator); + var message = std.Io.Writer.Allocating.init(self.gc.allocator); + defer message.deinit(); - message.writer(self.gc.allocator).print("zdef could not be parsed: {}", .{err.tag}) catch unreachable; + message.writer.print("zdef could not be parsed: {}", .{err.tag}) catch unreachable; const location = self.state.?.buzz_ast.?.tokens.get(self.state.?.source); self.reporter.report( .zdef, location, location, - message.items, + message.written(), ); } diff --git a/src/GC.zig b/src/GC.zig index 52f64365..3364b590 100644 --- a/src/GC.zig +++ b/src/GC.zig @@ -944,10 +944,10 @@ pub const Debugger = struct { var items = std.ArrayList(Reporter.ReportItem).empty; defer items.deinit(self.allocator); - var message = std.ArrayList(u8).empty; - defer message.deinit(self.allocator); + var message = std.Io.Writer.Allocating.init(self.allocator); + defer message.deinit(); - message.writer(self.allocator).print( + message.writer.print( "Access to already collected {} {*}", .{ tracked.what, @@ -961,7 +961,7 @@ pub const Debugger = struct { .location = at.?, .end_location = at.?, .kind = .@"error", - .message = message.items, + .message = message.written(), }, ) catch unreachable; diff --git a/src/Jit.zig b/src/Jit.zig index cbdb0c1e..bc09a3a6 100644 --- a/src/Jit.zig +++ b/src/Jit.zig @@ -20,6 +20,7 @@ pub const Error = error{ UnwrappedNull, OutOfBound, ReachedMaximumMemoryUsage, + WriteFailed, } || std.mem.Allocator.Error || std.fmt.BufPrintError; const OptJump = struct { @@ -5140,16 +5141,16 @@ fn getQualifiedName(self: *Self, node: Ast.Node.Index, raw: bool) ![]const u8 { const function_type = function_def.function_type; const name = function_def.name.string; - var qualified_name = std.ArrayList(u8){}; + var qualified_name = std.Io.Writer.Allocating.init(self.vm.gc.allocator); - try qualified_name.appendSlice(self.vm.gc.allocator, name); + try qualified_name.writer.writeAll(name); // Main and script are not allowed to be compiled std.debug.assert(function_type != .ScriptEntryPoint and function_type != .Script); // Don't qualify extern functions if (function_type != .Extern) { - try qualified_name.writer(self.vm.gc.allocator).print( + try qualified_name.writer.print( ".{}.n{}", .{ components.id, @@ -5158,20 +5159,20 @@ fn getQualifiedName(self: *Self, node: Ast.Node.Index, raw: bool) ![]const u8 { ); } if (function_type != .Extern and raw) { - try qualified_name.appendSlice(self.vm.gc.allocator, ".raw"); + try qualified_name.writer.writeAll(".raw"); } - try qualified_name.append(self.vm.gc.allocator, 0); + try qualified_name.writer.writeByte(0); - return qualified_name.toOwnedSlice(self.vm.gc.allocator); + return qualified_name.toOwnedSlice(); }, .For, .ForEach, .While, => { - var qualified_name = std.ArrayList(u8){}; + var qualified_name = std.Io.Writer.Allocating.init(self.vm.gc.allocator); - try qualified_name.writer(self.vm.gc.allocator).print( + try qualified_name.writer.print( "{s}#{d}\x00", .{ @tagName(tag), @@ -5179,7 +5180,7 @@ fn getQualifiedName(self: *Self, node: Ast.Node.Index, raw: bool) ![]const u8 { }, ); - return qualified_name.toOwnedSlice(self.vm.gc.allocator); + return qualified_name.toOwnedSlice(); }, else => { @@ -5198,12 +5199,20 @@ fn getQualifiedName(self: *Self, node: Ast.Node.Index, raw: bool) ![]const u8 { } pub fn compileZdefContainer(self: *Self, ast: Ast.Slice, zdef_element: Ast.Zdef.ZdefElement) Error!void { - var wrapper_name = std.ArrayList(u8){}; - defer wrapper_name.deinit(self.vm.gc.allocator); + var wrapper_name = std.Io.Writer.Allocating.init(self.vm.gc.allocator); + defer wrapper_name.deinit(); - try wrapper_name.writer(self.vm.gc.allocator).print("zdef_{s}\x00", .{zdef_element.zdef.name}); + try wrapper_name.writer.print( + "zdef_{s}\x00", + .{ + zdef_element.zdef.name, + }, + ); - const module = m.MIR_new_module(self.ctx, @ptrCast(wrapper_name.items.ptr)); + const module = m.MIR_new_module( + self.ctx, + @ptrCast(wrapper_name.written().ptr), + ); defer m.MIR_finish_module(self.ctx); if (BuildOptions.jit_debug) { @@ -5477,10 +5486,10 @@ fn buildZigValueToBuzzValue(self: *Self, buzz_type: *o.ObjTypeDef, zig_type: Zig } pub fn compileZdef(self: *Self, buzz_ast: Ast.Slice, zdef: Ast.Zdef.ZdefElement) Error!*o.ObjNative { - var wrapper_name = std.ArrayList(u8){}; - defer wrapper_name.deinit(self.vm.gc.allocator); + var wrapper_name = std.Io.Writer.Allocating.init(self.vm.gc.allocator); + defer wrapper_name.deinit(); - try wrapper_name.writer(self.vm.gc.allocator).print("zdef_{s}\x00", .{zdef.zdef.name}); + try wrapper_name.writer.print("zdef_{s}\x00", .{zdef.zdef.name}); const dupped_symbol = self.vm.gc.allocator.dupeZ(u8, zdef.zdef.name) catch { self.vm.panic("Out of memory"); @@ -5488,7 +5497,7 @@ pub fn compileZdef(self: *Self, buzz_ast: Ast.Slice, zdef: Ast.Zdef.ZdefElement) }; defer self.vm.gc.allocator.free(dupped_symbol); - const module = m.MIR_new_module(self.ctx, @ptrCast(wrapper_name.items.ptr)); + const module = m.MIR_new_module(self.ctx, @ptrCast(wrapper_name.written().ptr)); defer m.MIR_finish_module(self.ctx); if (BuildOptions.jit_debug) { @@ -5516,7 +5525,7 @@ pub fn compileZdef(self: *Self, buzz_ast: Ast.Slice, zdef: Ast.Zdef.ZdefElement) // Build wrapper const wrapper_item = try self.buildZdefWrapper(zdef); - _ = m.MIR_new_export(self.ctx, @ptrCast(wrapper_name.items.ptr)); + _ = m.MIR_new_export(self.ctx, @ptrCast(wrapper_name.written().ptr)); if (BuildOptions.jit_debug) { self.outputModule(zdef.zdef.name, module); @@ -5607,15 +5616,15 @@ fn zigToMIRRegType(zig_type: ZigType) m.MIR_type_t { } fn buildZdefWrapper(self: *Self, zdef_element: Ast.Zdef.ZdefElement) Error!m.MIR_item_t { - var wrapper_name = std.ArrayList(u8){}; - defer wrapper_name.deinit(self.vm.gc.allocator); + var wrapper_name = std.Io.Writer.Allocating.init(self.vm.gc.allocator); + defer wrapper_name.deinit(); - try wrapper_name.writer(self.vm.gc.allocator).print("zdef_{s}\x00", .{zdef_element.zdef.name}); + try wrapper_name.writer.print("zdef_{s}\x00", .{zdef_element.zdef.name}); - var wrapper_protocol_name = std.ArrayList(u8){}; - defer wrapper_protocol_name.deinit(self.vm.gc.allocator); + var wrapper_protocol_name = std.Io.Writer.Allocating.init(self.vm.gc.allocator); + defer wrapper_protocol_name.deinit(); - try wrapper_protocol_name.writer(self.vm.gc.allocator).print("p_zdef_{s}\x00", .{zdef_element.zdef.name}); + try wrapper_protocol_name.writer.print("p_zdef_{s}\x00", .{zdef_element.zdef.name}); const dupped_symbol = self.vm.gc.allocator.dupeZ(u8, zdef_element.zdef.name) catch { self.vm.panic("Out of memory"); @@ -5631,7 +5640,7 @@ fn buildZdefWrapper(self: *Self, zdef_element: Ast.Zdef.ZdefElement) Error!m.MIR defer self.vm.gc.allocator.free(ctx_name); const function = m.MIR_new_func_arr( self.ctx, - @ptrCast(wrapper_name.items.ptr), + @ptrCast(wrapper_name.written().ptr), 1, &[_]m.MIR_type_t{m.MIR_T_U64}, 1, @@ -5731,7 +5740,7 @@ fn buildZdefWrapper(self: *Self, zdef_element: Ast.Zdef.ZdefElement) Error!m.MIR self.ctx, m.MIR_new_proto_arr( self.ctx, - @ptrCast(wrapper_protocol_name.items.ptr), + @ptrCast(wrapper_protocol_name.written().ptr), if (return_mir_type != null) 1 else 0, if (return_mir_type) |rmt| &[_]m.MIR_type_t{rmt} else null, arg_types.items.len, @@ -5823,10 +5832,10 @@ fn buildZdefUnionGetter( buzz_type: *o.ObjTypeDef, zig_type: *const ZigType, ) Error!m.MIR_item_t { - var getter_name = std.ArrayList(u8){}; - defer getter_name.deinit(self.vm.gc.allocator); + var getter_name = std.Io.Writer.Allocating.init(self.vm.gc.allocator); + defer getter_name.deinit(); - try getter_name.writer(self.vm.gc.allocator).print( + try getter_name.writer.print( "zdef_union_{s}_{s}_getter\x00", .{ union_name, @@ -5847,7 +5856,7 @@ fn buildZdefUnionGetter( defer self.vm.gc.allocator.free(data_name); const function = m.MIR_new_func_arr( self.ctx, - @ptrCast(getter_name.items.ptr), + @ptrCast(getter_name.written().ptr), 1, &[_]m.MIR_type_t{m.MIR_T_U64}, 2, @@ -5921,7 +5930,7 @@ fn buildZdefUnionGetter( m.MIR_finish_func(self.ctx); - _ = m.MIR_new_export(self.ctx, @ptrCast(getter_name.items.ptr)); + _ = m.MIR_new_export(self.ctx, @ptrCast(getter_name.written().ptr)); return function; } @@ -5933,10 +5942,10 @@ fn buildZdefUnionSetter( buzz_type: *o.ObjTypeDef, zig_type: *const ZigType, ) Error!m.MIR_item_t { - var setter_name = std.ArrayList(u8){}; - defer setter_name.deinit(self.vm.gc.allocator); + var setter_name = std.Io.Writer.Allocating.init(self.vm.gc.allocator); + defer setter_name.deinit(); - try setter_name.writer(self.vm.gc.allocator).print( + try setter_name.writer.print( "zdef_union_{s}_{s}_setter\x00", .{ union_name, @@ -5962,7 +5971,7 @@ fn buildZdefUnionSetter( defer self.vm.gc.allocator.free(new_value_name); const function = m.MIR_new_func_arr( self.ctx, - @ptrCast(setter_name.items.ptr), + @ptrCast(setter_name.written().ptr), 0, null, 3, @@ -6036,7 +6045,7 @@ fn buildZdefUnionSetter( m.MIR_finish_func(self.ctx); - _ = m.MIR_new_export(self.ctx, @ptrCast(setter_name.items.ptr)); + _ = m.MIR_new_export(self.ctx, @ptrCast(setter_name.written().ptr)); return function; } @@ -6049,10 +6058,10 @@ fn buildZdefContainerGetter( buzz_type: *o.ObjTypeDef, zig_type: *const ZigType, ) Error!m.MIR_item_t { - var getter_name = std.ArrayList(u8){}; - defer getter_name.deinit(self.vm.gc.allocator); + var getter_name = std.Io.Writer.Allocating.init(self.vm.gc.allocator); + defer getter_name.deinit(); - try getter_name.writer(self.vm.gc.allocator).print( + try getter_name.writer.print( "zdef_struct_{s}_{s}_getter\x00", .{ struct_name, @@ -6073,7 +6082,7 @@ fn buildZdefContainerGetter( defer self.vm.gc.allocator.free(data_name); const function = m.MIR_new_func_arr( self.ctx, - @ptrCast(getter_name.items.ptr), + @ptrCast(getter_name.written().ptr), 1, &[_]m.MIR_type_t{m.MIR_T_U64}, 2, @@ -6130,7 +6139,7 @@ fn buildZdefContainerGetter( m.MIR_finish_func(self.ctx); - _ = m.MIR_new_export(self.ctx, @ptrCast(getter_name.items.ptr)); + _ = m.MIR_new_export(self.ctx, @ptrCast(getter_name.written().ptr)); return function; } @@ -6143,10 +6152,10 @@ fn buildZdefContainerSetter( buzz_type: *o.ObjTypeDef, zig_type: *const ZigType, ) Error!m.MIR_item_t { - var setter_name = std.ArrayList(u8){}; - defer setter_name.deinit(self.vm.gc.allocator); + var setter_name = std.Io.Writer.Allocating.init(self.vm.gc.allocator); + defer setter_name.deinit(); - try setter_name.writer(self.vm.gc.allocator).print( + try setter_name.writer.print( "zdef_struct_{s}_{s}_setter\x00", .{ struct_name, @@ -6172,7 +6181,7 @@ fn buildZdefContainerSetter( defer self.vm.gc.allocator.free(new_value_name); const function = m.MIR_new_func_arr( self.ctx, - @ptrCast(setter_name.items.ptr), + @ptrCast(setter_name.written().ptr), 0, null, 3, @@ -6225,7 +6234,7 @@ fn buildZdefContainerSetter( m.MIR_finish_func(self.ctx); - _ = m.MIR_new_export(self.ctx, @ptrCast(setter_name.items.ptr)); + _ = m.MIR_new_export(self.ctx, @ptrCast(setter_name.written().ptr)); return function; } @@ -7116,21 +7125,21 @@ inline fn BEND(self: *Self, from: m.MIR_reg_t) void { } fn REG(self: *Self, name: [*:0]const u8, reg_type: m.MIR_type_t) !m.MIR_reg_t { - var actual_name = std.ArrayList(u8){}; - defer actual_name.deinit(self.vm.gc.allocator); + var actual_name = std.Io.Writer.Allocating.init(self.vm.gc.allocator); + defer actual_name.deinit(); const count = self.state.?.registers.get(name) orelse 0; if (count > 0) { - try actual_name.writer(self.vm.gc.allocator).print("{s}{d}\u{0}", .{ name, count + 1 }); + try actual_name.writer.print("{s}{d}\u{0}", .{ name, count + 1 }); } else { - try actual_name.writer(self.vm.gc.allocator).print("{s}\u{0}", .{name}); + try actual_name.writer.print("{s}\u{0}", .{name}); } const reg = m.MIR_new_func_reg( self.ctx, self.state.?.function.?.u.func, reg_type, - @ptrCast(actual_name.items.ptr), + @ptrCast(actual_name.written().ptr), ); try self.state.?.registers.put( @@ -7144,10 +7153,10 @@ fn REG(self: *Self, name: [*:0]const u8, reg_type: m.MIR_type_t) !m.MIR_reg_t { fn outputModule(self: *Self, name: []const u8, module: m.MIR_module_t) void { // Output MIR code to .mir file - var debug_path = std.ArrayList(u8){}; - defer debug_path.deinit(self.vm.gc.allocator); + var debug_path = std.Io.Writer.Allocating.init(self.vm.gc.allocator); + defer debug_path.deinit(); - debug_path.writer(self.vm.gc.allocator).print( + debug_path.writer.print( "./dist/gen/{s}.mod.mir\x00", .{ name, @@ -7155,7 +7164,7 @@ fn outputModule(self: *Self, name: []const u8, module: m.MIR_module_t) void { ) catch unreachable; const debug_file = std.c.fopen( - @ptrCast(debug_path.items.ptr), + @ptrCast(debug_path.written().ptr), "w", ).?; defer _ = std.c.fclose(debug_file); diff --git a/src/Parser.zig b/src/Parser.zig index 19b53d79..1bc4eb69 100644 --- a/src/Parser.zig +++ b/src/Parser.zig @@ -446,6 +446,7 @@ pub const Error = error{ UnwrappedNull, OutOfBound, ReachedMaximumMemoryUsage, + WriteFailed, } || std.mem.Allocator.Error || std.fmt.BufPrintError || CompileError; const ParseFn = *const fn (*Self, bool) Error!Ast.Node.Index; @@ -3474,14 +3475,14 @@ fn parseObjType(self: *Self, generic_types: ?std.AutoArrayHashMapUnmanaged(*obj. const qualifier = try std.mem.replaceOwned(u8, self.gc.allocator, self.script_name, "/", "."); defer self.gc.allocator.free(qualifier); - var qualified_name = std.ArrayList(u8).empty; - defer qualified_name.deinit(self.gc.allocator); - try qualified_name.writer(self.gc.allocator).print("{s}.anonymous", .{qualifier}); + var qualified_name = std.Io.Writer.Allocating.init(self.gc.allocator); + defer qualified_name.deinit(); + try qualified_name.writer.print("{s}.anonymous", .{qualifier}); const object_def = obj.ObjObject.ObjectDef.init( start_location, try self.gc.copyString("anonymous"), - try self.gc.copyString(qualified_name.items), + try self.gc.copyString(qualified_name.written()), true, ); @@ -4576,16 +4577,22 @@ fn anonymousObjectInit(self: *Self, _: bool) Error!Ast.Node.Index { const start_location = self.current_token.? - 1; try self.consume(.LeftBrace, "Expected `{` after `.`"); - const qualifier = try std.mem.replaceOwned(u8, self.gc.allocator, self.script_name, "/", "."); + const qualifier = try std.mem.replaceOwned( + u8, + self.gc.allocator, + self.script_name, + "/", + ".", + ); defer self.gc.allocator.free(qualifier); - var qualified_name = std.ArrayList(u8).empty; - defer qualified_name.deinit(self.gc.allocator); - try qualified_name.writer(self.gc.allocator).print("{s}.anonymous", .{qualifier}); + var qualified_name = std.Io.Writer.Allocating.init(self.gc.allocator); + defer qualified_name.deinit(); + try qualified_name.writer.print("{s}.anonymous", .{qualifier}); const object_def = obj.ObjObject.ObjectDef.init( start_location, try self.gc.copyString("anonymous"), - try self.gc.copyString(qualified_name.items), + try self.gc.copyString(qualified_name.written()), true, ); @@ -7343,9 +7350,9 @@ fn objectDeclaration(self: *Self) Error!Ast.Node.Index { // Qualified name to avoid cross script collision const qualifier = try std.mem.replaceOwned(u8, self.gc.allocator, self.script_name, "/", "\\"); defer self.gc.allocator.free(qualifier); - var qualified_object_name = std.ArrayList(u8).empty; - defer qualified_object_name.deinit(self.gc.allocator); - try qualified_object_name.writer(self.gc.allocator).print( + var qualified_object_name = std.Io.Writer.Allocating.init(self.gc.allocator); + defer qualified_object_name.deinit(); + try qualified_object_name.writer.print( "{s}.{s}", .{ qualifier, @@ -7360,7 +7367,7 @@ fn objectDeclaration(self: *Self) Error!Ast.Node.Index { var object_def = obj.ObjObject.ObjectDef.init( object_name_token, try self.gc.copyString(object_name_lexeme), - try self.gc.copyString(qualified_object_name.items), + try self.gc.copyString(qualified_object_name.written()), false, ); @@ -7828,9 +7835,9 @@ fn protocolDeclaration(self: *Self) Error!Ast.Node.Index { // Qualified name to avoid cross script collision const qualifier = try std.mem.replaceOwned(u8, self.gc.allocator, self.script_name, "/", "\\"); defer self.gc.allocator.free(qualifier); - var qualified_protocol_name = std.ArrayList(u8).empty; - defer qualified_protocol_name.deinit(self.gc.allocator); - try qualified_protocol_name.writer(self.gc.allocator).print( + var qualified_protocol_name = std.Io.Writer.Allocating.init(self.gc.allocator); + defer qualified_protocol_name.deinit(); + try qualified_protocol_name.writer.print( "{s}.{s}", .{ qualifier, @@ -7849,7 +7856,7 @@ fn protocolDeclaration(self: *Self) Error!Ast.Node.Index { .Protocol = obj.ObjObject.ProtocolDef.init( protocol_name, try self.gc.copyString(self.ast.tokens.items(.lexeme)[protocol_name]), - try self.gc.copyString(qualified_protocol_name.items), + try self.gc.copyString(qualified_protocol_name.written()), ), }, }; @@ -8002,9 +8009,9 @@ fn enumDeclaration(self: *Self) Error!Ast.Node.Index { // Qualified name to avoid cross script collision const qualifier = try std.mem.replaceOwned(u8, self.gc.allocator, self.script_name, "/", "."); defer self.gc.allocator.free(qualifier); - var qualified_name = std.ArrayList(u8).empty; - defer qualified_name.deinit(self.gc.allocator); - try qualified_name.writer(self.gc.allocator).print( + var qualified_name = std.Io.Writer.Allocating.init(self.gc.allocator); + defer qualified_name.deinit(); + try qualified_name.writer.print( "{s}.{s}", .{ qualifier, enum_name_lexeme }, ); @@ -8012,7 +8019,7 @@ fn enumDeclaration(self: *Self) Error!Ast.Node.Index { const enum_def = obj.ObjEnum.EnumDef{ .name = try self.gc.copyString(enum_name_lexeme), .location = enum_name, - .qualified_name = try self.gc.copyString(qualified_name.items), + .qualified_name = try self.gc.copyString(qualified_name.written()), .enum_type = enum_case_type, .cases = undefined, .cases_locations = undefined, @@ -8539,9 +8546,9 @@ fn searchLibPaths(self: *Self, file_name: []const u8) ![][]const u8 { } for (user_library_paths orelse &[_][]const u8{}) |path| { - var filled = std.ArrayList(u8).empty; + var filled = std.Io.Writer.Allocating.init(self.gc.allocator); - try filled.writer(self.gc.allocator).print( + try filled.writer.print( "{s}{s}{s}.{s}", .{ path, @@ -8561,11 +8568,11 @@ fn searchLibPaths(self: *Self, file_name: []const u8) ![][]const u8 { }, ); - try paths.append(self.gc.allocator, try filled.toOwnedSlice(self.gc.allocator)); + try paths.append(self.gc.allocator, try filled.toOwnedSlice()); - var prefixed_filled = std.ArrayList(u8).empty; + var prefixed_filled = std.Io.Writer.Allocating.init(self.gc.allocator); - try prefixed_filled.writer(self.gc.allocator).print( + try prefixed_filled.writer.print( "{s}{s}lib{s}.{s}", .{ path, @@ -8587,7 +8594,7 @@ fn searchLibPaths(self: *Self, file_name: []const u8) ![][]const u8 { try paths.append( self.gc.allocator, - try prefixed_filled.toOwnedSlice(self.gc.allocator), + try prefixed_filled.toOwnedSlice(), ); } @@ -8628,9 +8635,9 @@ fn searchZdefLibPaths(self: *Self, file_name: []const u8) ![][]const u8 { } for (Self.user_library_paths orelse &[_][]const u8{}) |path| { - var filled = std.ArrayList(u8).empty; + var filled = std.Io.Writer.Allocating.init(self.gc.allocator); - try filled.writer(self.gc.allocator).print( + try filled.writer.print( "{s}{s}{s}.{s}", .{ path, @@ -8650,11 +8657,11 @@ fn searchZdefLibPaths(self: *Self, file_name: []const u8) ![][]const u8 { }, ); - try paths.append(self.gc.allocator, try filled.toOwnedSlice(self.gc.allocator)); + try paths.append(self.gc.allocator, try filled.toOwnedSlice()); - var prefixed_filled = std.ArrayList(u8).empty; + var prefixed_filled = std.Io.Writer.Allocating.init(self.gc.allocator); - try prefixed_filled.writer(self.gc.allocator).print( + try prefixed_filled.writer.print( "{s}{s}lib{s}.{s}", .{ path, @@ -8676,7 +8683,7 @@ fn searchZdefLibPaths(self: *Self, file_name: []const u8) ![][]const u8 { try paths.append( self.gc.allocator, - try prefixed_filled.toOwnedSlice(self.gc.allocator), + try prefixed_filled.toOwnedSlice(), ); } @@ -8783,12 +8790,10 @@ fn readScript(self: *Self, file_name: []const u8) !?[2][]const u8 { } if (file == null) { - var search_report = std.ArrayList(u8).empty; - defer search_report.deinit(self.gc.allocator); - var writer = search_report.writer(self.gc.allocator); - + var search_report = std.Io.Writer.Allocating.init(self.gc.allocator); + defer search_report.deinit(); for (paths) |path| { - try writer.print(" no file `{s}`\n", .{path}); + try search_report.writer.print(" no file `{s}`\n", .{path}); } const location = self.ast.tokens.get(self.current_token.? - 1); @@ -8799,7 +8804,7 @@ fn readScript(self: *Self, file_name: []const u8) !?[2][]const u8 { "buzz script `{s}` not found:\n{s}", .{ file_name, - search_report.items, + search_report.written(), }, ); @@ -9104,12 +9109,11 @@ fn importLibSymbol( ); } - var search_report = std.ArrayList(u8).empty; - defer search_report.deinit(self.gc.allocator); - var writer = search_report.writer(self.gc.allocator); + var search_report = std.Io.Writer.Allocating.init(self.gc.allocator); + defer search_report.deinit(); for (paths) |path| { - try writer.print(" no file `{s}`\n", .{path}); + try search_report.writer.print(" no file `{s}`\n", .{path}); } self.reporter.reportErrorFmt( @@ -9123,7 +9127,7 @@ fn importLibSymbol( std.mem.sliceTo(dlerror(), 0) else "", - search_report.items, + search_report.written(), }, ); @@ -9347,12 +9351,11 @@ fn zdefStatement(self: *Self) Error!Ast.Node.Index { fn_ptr = opaque_symbol_method; } else { - var search_report = std.ArrayList(u8).empty; - defer search_report.deinit(self.gc.allocator); - var writer = search_report.writer(self.gc.allocator); + var search_report = std.Io.Writer.Allocating.init(self.gc.allocator); + defer search_report.deinit(); for (paths) |path| { - try writer.print(" no file `{s}`\n", .{path}); + try search_report.writer.print(" no file `{s}`\n", .{path}); } const location = self.ast.tokens.get(lib_name); @@ -9367,7 +9370,7 @@ fn zdefStatement(self: *Self) Error!Ast.Node.Index { std.mem.sliceTo(dlerror(), 0) else "", - search_report.items, + search_report.written(), }, ); } diff --git a/src/Reporter.zig b/src/Reporter.zig index cbde0dba..428d5ea1 100644 --- a/src/Reporter.zig +++ b/src/Reporter.zig @@ -643,15 +643,14 @@ pub fn warnAt(self: *Self, error_type: Error, location: Token, end_location: Tok pub fn reportErrorFmt(self: *Self, error_type: Error, location: Token, end_location: Token, comptime fmt: []const u8, args: anytype) void { @branchHint(.cold); - var message = std.ArrayList(u8).empty; + var message = std.Io.Writer.Allocating.init(self.allocator); defer { if (!self.collect) { - message.deinit(self.allocator); + message.deinit(); } } - var writer = message.writer(self.allocator); - writer.print(fmt, args) catch @panic("Unable to report error"); + message.writer.print(fmt, args) catch @panic("Unable to report error"); if (self.panic_mode) { return; @@ -661,25 +660,24 @@ pub fn reportErrorFmt(self: *Self, error_type: Error, location: Token, end_locat error_type, location, end_location, - message.toOwnedSlice(self.allocator) catch @panic("Untable to report error"), + message.written(), ); } pub fn warnFmt(self: *Self, error_type: Error, location: Token, end_location: Token, comptime fmt: []const u8, args: anytype) void { - var message = std.ArrayList(u8).empty; + var message = std.Io.Writer.Allocating.init(self.allocator); defer { if (!self.collect) { - message.deinit(self.allocator); + message.deinit(); } } - var writer = message.writer(self.allocator); - writer.print(fmt, args) catch @panic("Unable to report error"); + message.writer.print(fmt, args) catch @panic("Unable to report error"); self.warn( error_type, location, end_location, - message.toOwnedSlice(self.allocator) catch @panic("Unable to report error"), + message.written(), ); } @@ -696,22 +694,21 @@ pub fn reportWithOrigin( ) void { @branchHint(.cold); - var message = std.ArrayList(u8).empty; + var message = std.Io.Writer.Allocating.init(self.allocator); defer { if (!self.collect) { - message.deinit(self.allocator); + message.deinit(); } } - var writer = message.writer(self.allocator); - writer.print(fmt, args) catch @panic("Unable to report error"); + message.writer.print(fmt, args) catch @panic("Unable to report error"); const items = [_]ReportItem{ .{ .location = location, .end_location = end_location, .kind = .@"error", - .message = message.items, + .message = message.written(), }, .{ .location = decl_location, @@ -722,7 +719,7 @@ pub fn reportWithOrigin( }; var decl_report = Report{ - .message = message.items, + .message = message.written(), .error_type = error_type, // When collecting errors for LSP, those can't live on the stack .items = items: { @@ -757,50 +754,49 @@ pub fn reportTypeCheck( ) void { @branchHint(.cold); - var actual_message = std.ArrayList(u8).empty; + var actual_message = std.Io.Writer.Allocating.init(self.allocator); defer { if (!self.collect) { - actual_message.deinit(self.allocator); + actual_message.deinit(); } } - var writer = &actual_message.writer(self.allocator); + actual_message.writer.print("{s}: got type `", .{message}) catch @panic("Unable to report error"); + actual_type.toString(&actual_message.writer, false) catch @panic("Unable to report error"); + actual_message.writer.writeAll("`") catch @panic("Unable to report error"); - writer.print("{s}: got type `", .{message}) catch @panic("Unable to report error"); - actual_type.toString(writer, false) catch @panic("Unable to report error"); - writer.writeAll("`") catch @panic("Unable to report error"); - - var expected_message = std.ArrayList(u8).empty; + var expected_message = std.Io.Writer.Allocating.init(self.allocator); defer { if (!self.collect) { - expected_message.deinit(self.allocator); + expected_message.deinit(); } } - if (expected_location != null) { - writer = &expected_message.writer(self.allocator); - } + var following_message = if (expected_location != null) + expected_message + else + actual_message; - writer.writeAll("expected `") catch @panic("Unable to report error"); + following_message.writer.writeAll("expected `") catch @panic("Unable to report error"); - expected_type.toString(writer, false) catch @panic("Unable to report error"); - writer.writeAll("`") catch @panic("Unable to report error"); + expected_type.toString(&following_message.writer, false) catch @panic("Unable to report error"); + following_message.writer.writeAll("`") catch @panic("Unable to report error"); var full_message = if (expected_location == null) actual_message else - std.ArrayList(u8).empty; + std.Io.Writer.Allocating.init(self.allocator); defer { if (!self.collect and expected_location != null) { - full_message.deinit(self.allocator); + full_message.deinit(); } } if (expected_location != null) { - full_message.writer(self.allocator).print( + full_message.writer.print( "{s}, {s}", .{ - actual_message.toOwnedSlice(self.allocator) catch @panic("Unable to report error"), - expected_message.toOwnedSlice(self.allocator) catch @panic("Unable to report error"), + actual_message.written(), + expected_message.written(), }, ) catch @panic("Unable to report error"); } @@ -812,18 +808,18 @@ pub fn reportTypeCheck( .location = actual_location, .end_location = actual_end_location, .kind = .@"error", - .message = actual_message.items, + .message = actual_message.written(), }, .{ .location = location, .end_location = expected_end_location.?, .kind = .hint, - .message = expected_message.items, + .message = expected_message.written(), }, }; break :rpt Report{ - .message = full_message.items, + .message = full_message.written(), .error_type = error_type, // When collecting errors for LSP, those can't live on the stack .items = items: { @@ -844,12 +840,12 @@ pub fn reportTypeCheck( .location = actual_location, .end_location = actual_end_location, .kind = .hint, - .message = actual_message.items, + .message = actual_message.written(), }, }; break :rpt Report{ - .message = full_message.items, + .message = full_message.written(), .error_type = error_type, // When collecting errors for LSP, those can't live on the stack .items = items: { diff --git a/src/behavior.zig b/src/behavior.zig index 18655134..90e466e5 100644 --- a/src/behavior.zig +++ b/src/behavior.zig @@ -103,11 +103,13 @@ fn testCompileErrors(allocator: std.mem.Allocator) !Result { ); var buffer = [_]u8{0} ** 255; var file_reader = test_file.reader(buffer[0..]); - var reader = io.AllocatedReader{ - .reader = &file_reader.interface, - }; + var reader = io.AllocatedReader.init( + allocator, + &file_reader.interface, + null, + ); - const first_line = (try reader.readUntilDelimiterOrEof(allocator, '\n')).?; + const first_line = (try reader.readUntilDelimiterOrEof('\n')).?; defer allocator.free(first_line); test_file.close(); diff --git a/src/builtin/list.zig b/src/builtin/list.zig index e265c61e..3e86e62c 100644 --- a/src/builtin/list.zig +++ b/src/builtin/list.zig @@ -216,17 +216,16 @@ pub fn join(ctx: *o.NativeCtx) callconv(.c) c_int { const self = o.ObjList.cast(ctx.vm.peek(1).obj()).?; const separator = o.ObjString.cast(ctx.vm.peek(0).obj()).?; - var result = std.ArrayList(u8).empty; - var writer = result.writer(ctx.vm.gc.allocator); - defer result.deinit(ctx.vm.gc.allocator); + var result = std.Io.Writer.Allocating.init(ctx.vm.gc.allocator); + defer result.deinit(); for (self.items.items, 0..) |item, i| { - item.toString(&writer) catch { + item.toString(&result.writer) catch { ctx.vm.panic("Out of memory"); unreachable; }; if (i + 1 < self.items.items.len) { - writer.writeAll(separator.string) catch { + result.writer.writeAll(separator.string) catch { ctx.vm.panic("Out of memory"); unreachable; }; @@ -234,7 +233,7 @@ pub fn join(ctx: *o.NativeCtx) callconv(.c) c_int { } ctx.vm.push( - (ctx.vm.gc.copyString(result.items) catch { + (ctx.vm.gc.copyString(result.written()) catch { ctx.vm.panic("Out of memory"); unreachable; }).toValue(), diff --git a/src/builtin/str.zig b/src/builtin/str.zig index fc072c91..af59084d 100644 --- a/src/builtin/str.zig +++ b/src/builtin/str.zig @@ -440,18 +440,17 @@ pub fn hex(ctx: *o.NativeCtx) callconv(.c) c_int { return 1; } - var result = std.ArrayList(u8).empty; - defer result.deinit(ctx.vm.gc.allocator); - var writer = result.writer(ctx.vm.gc.allocator); + var result = std.Io.Writer.Allocating.init(ctx.vm.gc.allocator); + defer result.deinit(); for (str.string) |char| { - writer.print("{x:0>2}", .{char}) catch { + result.writer.print("{x:0>2}", .{char}) catch { ctx.vm.panic("Out of memory"); unreachable; }; } - var obj_string = ctx.vm.gc.copyString(result.items) catch { + var obj_string = ctx.vm.gc.copyString(result.written()) catch { ctx.vm.panic("Out of memory"); unreachable; }; diff --git a/src/buzz_api.zig b/src/buzz_api.zig index df34a234..663832c9 100644 --- a/src/buzz_api.zig +++ b/src/buzz_api.zig @@ -1497,14 +1497,14 @@ export fn bz_zigTypeAlignment(self: *ZigType) callconv(.c) u16 { } export fn bz_zigTypeToCString(self: *ZigType, vm: *VM) callconv(.c) [*:0]const u8 { - var out = std.ArrayList(u8).empty; + var out = std.Io.Writer.Allocating.init(vm.gc.allocator); - out.writer(vm.gc.allocator).print("{}\x00", .{self.*}) catch { + out.writer.print("{}\x00", .{self.*}) catch { vm.panic("Out of memory"); unreachable; }; - return @ptrCast(out.items.ptr); + return @ptrCast(out.written().ptr); } export fn bz_serialize(vm: *VM, value: v.Value, error_value: *v.Value) callconv(.c) v.Value { diff --git a/src/io.zig b/src/io.zig index fe1dd36d..54e94908 100644 --- a/src/io.zig +++ b/src/io.zig @@ -1,5 +1,5 @@ -// Because of https://ziglang.org/download/0.12.0/release-notes.html#Bring-Your-Own-OS-API-Layer-Regressed -// we have to add this abstraction layer to avoid using io.getStdIn/Err/Out +//! Because of https://ziglang.org/download/0.12.0/release-notes.html#Bring-Your-Own-OS-API-Layer-Regressed +//! we have to add this abstraction layer to avoid using io.getStdIn/Err/Out const std = @import("std"); const builtin = @import("builtin"); @@ -62,24 +62,35 @@ pub fn print(comptime fmt: []const u8, args: anytype) void { pub const AllocatedReader = struct { pub const Error = error{ ReadFailed, + WriteFailed, OutOfMemory, }; - buffer: std.ArrayList(u8) = .empty, + buffer: std.Io.Writer.Allocating, max_size: ?usize = null, reader: *std.Io.Reader, - pub fn readUntilDelimiterOrEof(self: *AllocatedReader, allocator: std.mem.Allocator, delimiter: u8) Error!?[]u8 { - std.debug.assert(self.reader.buffer.len > 0); + pub fn init(allocator: std.mem.Allocator, reader: *std.Io.Reader, max_size: ?usize) @This() { + return .{ + .buffer = .init(allocator), + .reader = reader, + .max_size = max_size, + }; + } + + pub fn deinit(self: *@This()) void { + self.buffer.deinit(); + } - var writer = self.buffer.writer(allocator); + pub fn readUntilDelimiterOrEof(self: *AllocatedReader, delimiter: u8) Error!?[]u8 { + std.debug.assert(self.reader.buffer.len > 0); var count: usize = 0; while (self.max_size == null or count < self.max_size.?) : (count += 1) { const byte = self.reader.takeByte() catch |err| { switch (err) { error.EndOfStream => return if (count > 0) - try self.buffer.toOwnedSlice(allocator) + try self.buffer.toOwnedSlice() else null, error.ReadFailed => return error.ReadFailed, @@ -90,17 +101,15 @@ pub const AllocatedReader = struct { break; } - try writer.writeByte(byte); + try self.buffer.writer.writeByte(byte); } - return try self.buffer.toOwnedSlice(allocator); + return try self.buffer.toOwnedSlice(); } - pub fn readAll(self: *AllocatedReader, allocator: std.mem.Allocator) Error![]u8 { + pub fn readAll(self: *AllocatedReader) Error![]u8 { std.debug.assert(self.reader.buffer.len > 0); - var writer = self.buffer.writer(allocator); - while (true) { const byte = self.reader.takeByte() catch |err| { switch (err) { @@ -109,17 +118,15 @@ pub const AllocatedReader = struct { } }; - try writer.writeByte(byte); + try self.buffer.writer.writeByte(byte); } - return try self.buffer.toOwnedSlice(allocator); + return try self.buffer.toOwnedSlice(); } - pub fn readN(self: *AllocatedReader, allocator: std.mem.Allocator, n: usize) Error![]u8 { + pub fn readN(self: *AllocatedReader, n: usize) Error![]u8 { std.debug.assert(self.reader.buffer.len > 0); - var writer = self.buffer.writer(allocator); - var count: usize = 0; while (count < n and (self.max_size == null or count < self.max_size.?)) : (count += 1) { const byte = self.reader.takeByte() catch |err| { @@ -129,9 +136,9 @@ pub const AllocatedReader = struct { } }; - try writer.writeByte(byte); + try self.buffer.writer.writeByte(byte); } - return try self.buffer.toOwnedSlice(allocator); + return try self.buffer.toOwnedSlice(); } }; diff --git a/src/lib/buzz_buffer.zig b/src/lib/buzz_buffer.zig index ae2bb03e..0daa4e76 100644 --- a/src/lib/buzz_buffer.zig +++ b/src/lib/buzz_buffer.zig @@ -138,10 +138,9 @@ const Buffer = struct { return null; } - var buffer_stream = std.io.fixedBufferStream(self.buffer.items[self.cursor..self.buffer.items.len]); - var reader = buffer_stream.reader(); + var buffer_stream = std.Io.Reader.fixed(self.buffer.items[self.cursor..self.buffer.items.len]); - const number = try reader.readInt(api.Integer, builtin.cpu.arch.endian()); + const number = try buffer_stream.takeInt(api.Integer, builtin.cpu.arch.endian()); self.cursor += @divExact(@typeInfo(api.Integer).int.bits, 8); @@ -153,10 +152,12 @@ const Buffer = struct { return Error.WriteWhileReading; } - var writer = self.buffer.writer(api.VM.allocator); + var buffer = std.Io.Writer.Allocating.fromArrayList(api.VM.allocator, &self.buffer); // Flag so we know it an integer - try writer.writeInt(api.Integer, integer, native_endian); + try buffer.writer.writeInt(api.Integer, integer, native_endian); + + self.buffer = buffer.toArrayList(); } pub fn readUserData(self: *Self, vm: *api.VM) !?api.Value { @@ -164,10 +165,9 @@ const Buffer = struct { return null; } - var buffer_stream = std.io.fixedBufferStream(self.buffer.items[self.cursor..self.buffer.items.len]); - var reader = buffer_stream.reader(); + var buffer_stream = std.Io.Reader.fixed(self.buffer.items[self.cursor..self.buffer.items.len]); - const number = try reader.readInt(u64, builtin.cpu.arch.endian()); + const number = try buffer_stream.takeInt(u64, builtin.cpu.arch.endian()); self.cursor += @sizeOf(u64); @@ -179,14 +179,16 @@ const Buffer = struct { return Error.WriteWhileReading; } - var writer = self.buffer.writer(api.VM.allocator); + var buffer = std.Io.Writer.Allocating.fromArrayList(api.VM.allocator, &self.buffer); // Flag so we know it an integer - try writer.writeInt( + try buffer.writer.writeInt( u64, userdata.bz_getUserDataPtr(), native_endian, ); + + self.buffer = buffer.toArrayList(); } pub fn readDouble(self: *Self) !?api.Double { @@ -194,10 +196,9 @@ const Buffer = struct { return null; } - var buffer_stream = std.io.fixedBufferStream(self.buffer.items[self.cursor..self.buffer.items.len]); - var reader = buffer_stream.reader(); + var buffer_stream = std.Io.Reader.fixed(self.buffer.items[self.cursor..self.buffer.items.len]); - const number = try reader.readInt(u64, builtin.cpu.arch.endian()); + const number = try buffer_stream.takeInt(u64, builtin.cpu.arch.endian()); self.cursor += @divExact(@typeInfo(u64).int.bits, 8); @@ -209,13 +210,15 @@ const Buffer = struct { return Error.WriteWhileReading; } - var writer = self.buffer.writer(api.VM.allocator); + var buffer = std.Io.Writer.Allocating.fromArrayList(api.VM.allocator, &self.buffer); - try writer.writeInt( + try buffer.writer.writeInt( u64, @as(u64, @bitCast(double)), native_endian, ); + + self.buffer = buffer.toArrayList(); } pub fn empty(self: *Self) void { @@ -327,6 +330,10 @@ pub export fn BufferReadInt(ctx: *api.NativeCtx) callconv(.c) c_int { return 1; }, + error.ReadFailed => { + ctx.vm.pushErrorEnum("errors.ReadWriteError", @errorName(err)); + return -1; + }, } }) |value| { ctx.vm.bz_push(api.Value.fromInteger(value)); @@ -348,6 +355,10 @@ pub export fn BufferReadUserData(ctx: *api.NativeCtx) callconv(.c) c_int { return 1; }, + error.ReadFailed => { + ctx.vm.pushErrorEnum("errors.ReadWriteError", @errorName(err)); + return -1; + }, } }) |value| { ctx.vm.bz_push(value); @@ -369,6 +380,10 @@ pub export fn BufferReadDouble(ctx: *api.NativeCtx) callconv(.c) c_int { return 1; }, + error.ReadFailed => { + ctx.vm.pushErrorEnum("errors.ReadWriteError", @errorName(err)); + return -1; + }, } }) |value| { ctx.vm.bz_push(api.Value.fromDouble(value)); @@ -387,7 +402,7 @@ pub export fn BufferWriteInt(ctx: *api.NativeCtx) callconv(.c) c_int { buffer.writeInteger(number.integer()) catch |err| { switch (err) { Buffer.Error.WriteWhileReading => ctx.vm.pushError("buffer.WriteWhileReadingError", null), - error.OutOfMemory => { + error.WriteFailed => { ctx.vm.bz_panic("Out of memory", "Out of memory".len); unreachable; }, @@ -406,7 +421,7 @@ pub export fn BufferWriteUserData(ctx: *api.NativeCtx) callconv(.c) c_int { buffer.writeUserData(userdata) catch |err| { switch (err) { Buffer.Error.WriteWhileReading => ctx.vm.pushError("buffer.WriteWhileReadingError", null), - error.OutOfMemory => { + error.WriteFailed => { ctx.vm.bz_panic("Out of memory", "Out of memory".len); unreachable; }, @@ -425,7 +440,7 @@ pub export fn BufferWriteDouble(ctx: *api.NativeCtx) callconv(.c) c_int { buffer.writeFloat(number.double()) catch |err| { switch (err) { Buffer.Error.WriteWhileReading => ctx.vm.pushError("buffer.WriteWhileReadingError", null), - error.OutOfMemory => { + error.WriteFailed => { ctx.vm.bz_panic("Out of memory", "Out of memory".len); unreachable; }, @@ -508,10 +523,10 @@ fn checkBuzzType( btype: api.Value, ) bool { if (!value.bz_valueIs(btype).boolean()) { - var err = std.ArrayList(u8).empty; - defer err.deinit(api.VM.allocator); + var err = std.Io.Writer.Allocating.init(api.VM.allocator); + defer err.deinit(); - err.writer(api.VM.allocator).print( + err.writer.print( "Expected buzz value of type `{s}` to match FFI type `{s}`", .{ btype.bz_valueCastToString(vm).bz_valueToCString().?, @@ -523,11 +538,17 @@ fn checkBuzzType( unreachable; }; + const err_owned = err.toOwnedSlice() catch { + const msg = "Out of memory"; + vm.bz_panic(msg.ptr, msg.len); + unreachable; + }; + vm.bz_pushError( "ffi.FFITypeMismatchError", "ffi.FFITypeMismatchError".len, - err.items.ptr, - err.items.len, + err_owned.ptr, + err_owned.len, ); return false; diff --git a/src/lib/buzz_ffi.zig b/src/lib/buzz_ffi.zig index 92706ff7..f00f1d48 100644 --- a/src/lib/buzz_ffi.zig +++ b/src/lib/buzz_ffi.zig @@ -11,10 +11,10 @@ pub export fn alignOf(ctx: *api.NativeCtx) callconv(.c) c_int { if (zig_type) |ztype| { ctx.vm.bz_push(api.Value.fromInteger(@intCast(ztype.bz_zigTypeAlignment()))); } else { - var msg = std.ArrayList(u8).empty; - defer msg.deinit(api.VM.allocator); + var msg = std.Io.Writer.Allocating.init(api.VM.allocator); + defer msg.deinit(); - msg.writer(api.VM.allocator).print( + msg.writer.print( "Could not parse zig type `{s}`", .{ zig_type_str[0..len], @@ -24,7 +24,13 @@ pub export fn alignOf(ctx: *api.NativeCtx) callconv(.c) c_int { unreachable; }; - ctx.vm.pushError("ffi.FFIZigTypeParseError", msg.items); + ctx.vm.pushError( + "ffi.FFIZigTypeParseError", + msg.toOwnedSlice() catch { + ctx.vm.bz_panic("Out of memory", "Out of memory".len); + unreachable; + }, + ); return -1; } @@ -42,10 +48,10 @@ pub export fn sizeOf(ctx: *api.NativeCtx) callconv(.c) c_int { if (zig_type) |ztype| { ctx.vm.bz_push(api.Value.fromInteger(@intCast(ztype.bz_zigTypeSize()))); } else { - var msg = std.ArrayList(u8).empty; - defer msg.deinit(api.VM.allocator); + var msg = std.Io.Writer.Allocating.init(api.VM.allocator); + defer msg.deinit(); - msg.writer(api.VM.allocator).print( + msg.writer.print( "Could not parse zig type `{s}`", .{ zig_type_str[0..len], @@ -55,7 +61,13 @@ pub export fn sizeOf(ctx: *api.NativeCtx) callconv(.c) c_int { unreachable; }; - ctx.vm.pushError("ffi.FFIZigTypeParseError", msg.items); + ctx.vm.pushError( + "ffi.FFIZigTypeParseError", + msg.toOwnedSlice() catch { + ctx.vm.bz_panic("Out of memory", "Out of memory".len); + unreachable; + }, + ); return -1; } diff --git a/src/lib/buzz_io.zig b/src/lib/buzz_io.zig index 5e1249ca..6778a590 100644 --- a/src/lib/buzz_io.zig +++ b/src/lib/buzz_io.zig @@ -56,10 +56,11 @@ const File = struct { self.reader_buffer = try allocator.alloc(u8, 255); self.io_reader = self.file.reader(self.reader_buffer.?); - self.reader = .{ - .reader = &self.io_reader.?.interface, - .max_size = max_size, - }; + self.reader = .init( + api.VM.allocator, + &self.io_reader.?.interface, + max_size, + ); return &self.reader.?; } @@ -253,13 +254,13 @@ pub export fn FileReadAll(ctx: *api.NativeCtx) callconv(.c) c_int { unreachable; }; - const content = reader.readAll(api.VM.allocator) catch |err| { + const content = reader.readAll() catch |err| { switch (err) { error.ReadFailed => { ctx.vm.pushErrorEnum("errors.ReadWriteError", @errorName(err)); return -1; }, - error.OutOfMemory => { + error.OutOfMemory, error.WriteFailed => { ctx.vm.bz_panic("Out of memory", "Out of memory".len); unreachable; }, @@ -291,13 +292,13 @@ pub export fn FileReadLine(ctx: *api.NativeCtx) callconv(.c) c_int { unreachable; }; - if (reader.readUntilDelimiterOrEof(api.VM.allocator, '\n') catch |err| { + if (reader.readUntilDelimiterOrEof('\n') catch |err| { switch (err) { error.ReadFailed => { ctx.vm.pushErrorEnum("errors.ReadWriteError", @errorName(err)); return -1; }, - error.OutOfMemory => { + error.OutOfMemory, error.WriteFailed => { ctx.vm.bz_panic("Out of memory", "Out of memory".len); unreachable; }, @@ -333,13 +334,13 @@ pub export fn FileRead(ctx: *api.NativeCtx) callconv(.c) c_int { unreachable; }; - const content = reader.readN(api.VM.allocator, @intCast(n)) catch |err| { + const content = reader.readN(@intCast(n)) catch |err| { switch (err) { error.ReadFailed => { ctx.vm.pushErrorEnum("errors.ReadWriteError", @errorName(err)); return -1; }, - error.OutOfMemory => { + error.OutOfMemory, error.WriteFailed => { ctx.vm.bz_panic("Out of memory", "Out of memory".len); unreachable; }, @@ -415,12 +416,12 @@ const FileEnum = enum { pub export fn FileGetPoller(ctx: *api.NativeCtx) callconv(.c) c_int { const file = File.fromUserData(ctx.vm.bz_peek(0).bz_getUserDataPtr()); - const poller = api.VM.allocator.create(std.io.Poller(FileEnum)) catch { + const poller = api.VM.allocator.create(std.Io.Poller(FileEnum)) catch { ctx.vm.bz_panic("Out of memory", "Out of memory".len); unreachable; }; - poller.* = std.io.poll( + poller.* = std.Io.poll( api.VM.allocator, FileEnum, .{ .file = file.file }, @@ -435,7 +436,7 @@ pub export fn FileGetPoller(ctx: *api.NativeCtx) callconv(.c) c_int { return 1; } -fn pollerFromUserData(userdata: u64) *std.io.Poller(FileEnum) { +fn pollerFromUserData(userdata: u64) *std.Io.Poller(FileEnum) { return @ptrCast(@alignCast(@as(*anyopaque, @ptrFromInt(@as(usize, @truncate(userdata)))))); } @@ -465,16 +466,19 @@ pub export fn PollerPoll(ctx: *api.NativeCtx) callconv(.c) c_int { if (got_something) { const poll_reader = poller.reader(.file); - var reader = io.AllocatedReader{ - .reader = poll_reader, - }; - const read = reader.readAll(api.VM.allocator) catch |err| { + var reader = io.AllocatedReader.init( + api.VM.allocator, + poll_reader, + null, + ); + + const read = reader.readAll() catch |err| { switch (err) { error.ReadFailed => { ctx.vm.pushErrorEnum("errors.ReadWriteError", @errorName(err)); return -1; }, - error.OutOfMemory => { + error.OutOfMemory, error.WriteFailed => { ctx.vm.bz_panic("Out of memory", "Out of memory".len); unreachable; }, @@ -565,17 +569,19 @@ pub export fn runFile(ctx: *api.NativeCtx) callconv(.c) c_int { var reader_buffer = [_]u8{0}; var file_reader = file.reader(reader_buffer[0..]); - var reader = io.AllocatedReader{ - .reader = &file_reader.interface, - }; + var reader = io.AllocatedReader.init( + api.VM.allocator, + &file_reader.interface, + null, + ); - const source = reader.readAll(api.VM.allocator) catch |err| { + const source = reader.readAll() catch |err| { switch (err) { error.ReadFailed => { ctx.vm.pushErrorEnum("errors.ReadWriteError", @errorName(err)); return -1; }, - error.OutOfMemory => { + error.WriteFailed, error.OutOfMemory => { ctx.vm.bz_panic("Out of memory", "Out of memory".len); unreachable; }, diff --git a/src/lib/buzz_os.zig b/src/lib/buzz_os.zig index 3f96b782..2fdcef0c 100644 --- a/src/lib/buzz_os.zig +++ b/src/lib/buzz_os.zig @@ -88,16 +88,17 @@ pub export fn tmpFilename(ctx: *api.NativeCtx) callconv(.c) c_int { const prefix_slice = if (prefix_len == 0) "" else prefix.?[0..prefix_len]; - var random_part = std.ArrayList(u8).empty; - defer random_part.deinit(api.VM.allocator); - random_part.writer(api.VM.allocator).print("{x}", .{std.crypto.random.int(api.Integer)}) catch { + var random_part = std.Io.Writer.Allocating.init(api.VM.allocator); + defer random_part.deinit(); + + random_part.writer.print("{x}", .{std.crypto.random.int(api.Integer)}) catch { ctx.vm.bz_panic("Out of memory", "Out of memory".len); unreachable; }; var random_part_b64 = std.ArrayList(u8).initCapacity( api.VM.allocator, - std.base64.standard.Encoder.calcSize(random_part.items.len), + std.base64.standard.Encoder.calcSize(random_part.written().len), ) catch { ctx.vm.bz_panic("Out of memory", "Out of memory".len); unreachable; @@ -105,12 +106,18 @@ pub export fn tmpFilename(ctx: *api.NativeCtx) callconv(.c) c_int { random_part_b64.expandToCapacity(); defer random_part_b64.deinit(api.VM.allocator); - _ = std.base64.standard.Encoder.encode(random_part_b64.items, random_part.items); + _ = std.base64.standard.Encoder.encode(random_part_b64.items, random_part.written()); - var final = std.ArrayList(u8).empty; - defer final.deinit(api.VM.allocator); + var final = std.Io.Writer.Allocating.init(api.VM.allocator); - final.writer(api.VM.allocator).print("{s}{s}-{s}", .{ sysTempDir(), prefix_slice, random_part_b64.items }) catch { + final.writer.print( + "{s}{s}-{s}", + .{ + sysTempDir(), + prefix_slice, + random_part_b64.items, + }, + ) catch { ctx.vm.bz_panic("Out of memory", "Out of memory".len); unreachable; }; @@ -118,11 +125,11 @@ pub export fn tmpFilename(ctx: *api.NativeCtx) callconv(.c) c_int { ctx.vm.bz_push( api.VM.bz_stringToValue( ctx.vm, - if (final.items.len > 0) - @as([*]const u8, @ptrCast(final.items)) + if (final.written().len > 0) + @as([*]const u8, @ptrCast(final.written())) else null, - final.items.len, + final.written().len, ), ); @@ -311,6 +318,7 @@ fn handleConnectUnixError(ctx: *api.NativeCtx, err: anytype) void { error.AddressFamilyNotSupported, error.AddressInUse, error.AddressNotAvailable, + error.AlreadyConnected, error.ConnectionPending, error.ConnectionRefused, error.ConnectionResetByPeer, @@ -432,33 +440,38 @@ pub export fn SocketRead(ctx: *api.NativeCtx) callconv(.c) c_int { ); const stream: std.net.Stream = .{ .handle = handle }; - var reader_buffer = [_]u8{0}; + var reader_buffer: [1024]u8 = undefined; var stream_reader = stream.reader(reader_buffer[0..]); - var reader = io.AllocatedReader{ - .reader = stream_reader.interface(), - }; + var reader = stream_reader.interface(); + + var content = std.Io.Writer.Allocating.init(api.VM.allocator); + defer content.deinit(); + + while (content.written().len <= n) { + const byte = reader.takeByte() catch |err| { + switch (err) { + error.EndOfStream => break, + error.ReadFailed => { + ctx.vm.pushErrorEnum("errors.ReadWriteError", @errorName(err)); + return -1; + }, + } + }; - const content = reader.readN(api.VM.allocator, @intCast(n)) catch |err| { - switch (err) { - error.ReadFailed => { - ctx.vm.pushErrorEnum("errors.ReadWriteError", @errorName(err)); - return -1; - }, - error.OutOfMemory => { - ctx.vm.bz_panic("Out of memory", "Out of memory".len); - unreachable; - }, - } - }; + content.writer.writeByte(byte) catch |err| { + ctx.vm.pushErrorEnum("errors.ReadWriteError", @errorName(err)); + return -1; + }; + } ctx.vm.bz_push( api.VM.bz_stringToValue( ctx.vm, - if (content.len > 0) - @as([*]const u8, @ptrCast(content)) + if (content.written().len > 0) + @as([*]const u8, @ptrCast(content.written())) else null, - content.len, + content.written().len, ), ); @@ -513,18 +526,19 @@ pub export fn SocketReadLine(ctx: *api.NativeCtx) callconv(.c) c_int { const stream: std.net.Stream = .{ .handle = handle }; var reader_buffer = [_]u8{0}; var stream_reader = stream.reader(reader_buffer[0..]); - var reader = io.AllocatedReader{ - .reader = stream_reader.interface(), - .max_size = if (max_size.isInteger()) @intCast(max_size.integer()) else null, - }; + var reader = io.AllocatedReader.init( + api.VM.allocator, + stream_reader.interface(), + if (max_size.isInteger()) @intCast(max_size.integer()) else null, + ); - if (reader.readUntilDelimiterOrEof(api.VM.allocator, '\n') catch |err| { + if (reader.readUntilDelimiterOrEof('\n') catch |err| { switch (err) { error.ReadFailed => { ctx.vm.pushErrorEnum("errors.ReadWriteError", @errorName(err)); return -1; }, - error.OutOfMemory => { + error.WriteFailed, error.OutOfMemory => { ctx.vm.bz_panic("Out of memory", "Out of memory".len); unreachable; }, @@ -556,18 +570,19 @@ pub export fn SocketReadAll(ctx: *api.NativeCtx) callconv(.c) c_int { const stream = std.net.Stream{ .handle = handle }; var reader_buffer = [_]u8{0}; var stream_reader = stream.reader(reader_buffer[0..]); - var reader = io.AllocatedReader{ - .reader = stream_reader.interface(), - .max_size = if (max_size.isInteger()) @intCast(max_size.integer()) else null, - }; + var reader = io.AllocatedReader.init( + api.VM.allocator, + stream_reader.interface(), + if (max_size.isInteger()) @intCast(max_size.integer()) else null, + ); - const content = reader.readAll(api.VM.allocator) catch |err| { + const content = reader.readAll() catch |err| { switch (err) { error.ReadFailed => { ctx.vm.pushErrorEnum("errors.ReadWriteError", @errorName(err)); return -1; }, - error.OutOfMemory => { + error.WriteFailed, error.OutOfMemory => { ctx.vm.bz_panic("Out of memory", "Out of memory".len); unreachable; }, diff --git a/src/lsp.zig b/src/lsp.zig index 1e6e7267..2f245be4 100644 --- a/src/lsp.zig +++ b/src/lsp.zig @@ -11,7 +11,6 @@ const Reporter = @import("Reporter.zig"); const CodeGen = @import("Codegen.zig"); const Token = @import("Token.zig"); const Renderer = @import("renderer.zig").Renderer; -const WriteableArrayList = @import("writeable_array_list.zig").WriteableArrayList; const log = std.log.scoped(.buzz_lsp); @@ -317,7 +316,12 @@ const Document = struct { const InlayHintsContext = struct { document: *Document, - pub fn processNode(self: *InlayHintsContext, allocator: std.mem.Allocator, ast: Ast.Slice, node: Ast.Node.Index) (std.mem.Allocator.Error || std.fmt.BufPrintError)!bool { + pub fn processNode( + self: *InlayHintsContext, + allocator: std.mem.Allocator, + ast: Ast.Slice, + node: Ast.Node.Index, + ) (std.mem.Allocator.Error || std.fmt.BufPrintError || error{WriteFailed})!bool { switch (ast.nodes.items(.tag)[node]) { .VarDeclaration => { const comp = ast.nodes.items(.components)[node].VarDeclaration; @@ -326,11 +330,10 @@ const Document = struct { // If type was omitted, provide it if (!comp.implicit and comp.type == null and type_def != null) { - var inlay = std.ArrayList(u8){}; - var writer = inlay.writer(allocator); + var inlay = std.Io.Writer.Allocating.init(allocator); - try writer.writeAll(": "); - try type_def.?.toString(writer, false); + try inlay.writer.writeAll(": "); + try type_def.?.toString(&inlay.writer, false); try self.document.inlay_hints.append( allocator, @@ -340,7 +343,7 @@ const Document = struct { .character = @intCast(@max(1, name.column + name.lexeme.len) - 1), }, .label = .{ - .string = try inlay.toOwnedSlice(allocator), + .string = try inlay.toOwnedSlice(), }, .kind = .Type, }, @@ -425,9 +428,9 @@ const Handler = struct { }, ); - var version = std.ArrayList(u8).empty; + var version = std.Io.Writer.Allocating.init(allocator); - try version.writer(allocator).print( + try version.writer.print( "{f}-{s}", .{ BuildOptions.version, @@ -438,7 +441,7 @@ const Handler = struct { return .{ .serverInfo = .{ .name = "Buzz LSP", - .version = version.items, + .version = version.written(), }, .capabilities = .{ .positionEncoding = switch (self.offset_encoding) { @@ -702,7 +705,12 @@ const Handler = struct { const DocumentSymbolContext = struct { document: *Document, - pub fn processNode(self: DocumentSymbolContext, _: std.mem.Allocator, ast: Ast.Slice, node: Ast.Node.Index) (std.mem.Allocator.Error || std.fmt.BufPrintError)!bool { + pub fn processNode( + self: DocumentSymbolContext, + _: std.mem.Allocator, + ast: Ast.Slice, + node: Ast.Node.Index, + ) (std.mem.Allocator.Error || std.fmt.BufPrintError || error{WriteFailed})!bool { const lexemes = ast.tokens.items(.lexeme); const locations = ast.nodes.items(.location); const end_locations = ast.nodes.items(.end_location); @@ -947,8 +955,7 @@ const Handler = struct { const markupEntry = try document.node_hover.getOrPut(allocator, origin); if (!markupEntry.found_existing) { - var markup = std.ArrayList(u8).empty; - const writer = markup.writer(self.allocator); + var markup = std.Io.Writer.Allocating.init(self.allocator); const def = try document.definition(origin); if (def) |udef| { @@ -957,18 +964,18 @@ const Handler = struct { var it = std.mem.tokenizeSequence(u8, doc, "/// "); while (it.next()) |text| { - try writer.print("{s}\n", .{text}); + try markup.writer.print("{s}\n", .{text}); } } } - try writer.writeAll("```buzz\n"); - td.toString(&writer, false) catch |err| { + try markup.writer.writeAll("```buzz\n"); + td.toString(&markup.writer, false) catch |err| { log.err("textDocument/hover: {any}", .{err}); }; - try writer.writeAll("\n```"); + try markup.writer.writeAll("\n```"); - markupEntry.value_ptr.* = try markup.toOwnedSlice(self.allocator); + markupEntry.value_ptr.* = try markup.toOwnedSlice(); } return .{ @@ -1032,7 +1039,7 @@ const Handler = struct { notification: lsp.types.getRequestMetadata("textDocument/formatting").?.Params.?, ) !lsp.types.getRequestMetadata("textDocument/formatting").?.Result { if (self.documents.get(notification.textDocument.uri)) |document| { - var result = WriteableArrayList(u8).init(self.allocator); + var result = std.Io.Writer.Allocating.init(self.allocator); Renderer.render( self.allocator, @@ -1055,7 +1062,7 @@ const Handler = struct { self.allocator, .{ .range = document.wholeDocumentRange(), - .newText = result.list.items, + .newText = result.written(), }, ); diff --git a/src/obj.zig b/src/obj.zig index 8e1b18fa..29840a4b 100644 --- a/src/obj.zig +++ b/src/obj.zig @@ -509,7 +509,7 @@ pub const Obj = struct { } } - pub fn toString(obj: *Obj, writer: *const std.ArrayList(u8).Writer) (Allocator.Error || std.fmt.BufPrintError)!void { + pub fn toString(obj: *Obj, writer: *std.Io.Writer) (Allocator.Error || std.fmt.BufPrintError || error{WriteFailed})!void { return switch (obj.obj_type) { .String => { const str = ObjString.cast(obj).?.string; @@ -4892,23 +4892,23 @@ pub const ObjTypeDef = struct { // FIXME } - pub fn toStringAlloc(self: *const Self, allocator: Allocator, qualified: bool) (Allocator.Error || std.fmt.BufPrintError)![]const u8 { - var str = std.ArrayList(u8).empty; + pub fn toStringAlloc(self: *const Self, allocator: Allocator, qualified: bool) (Allocator.Error || std.fmt.BufPrintError || error{WriteFailed})![]const u8 { + var str = std.Io.Writer.Allocating.init(allocator); - try self.toString(&str.writer(allocator), qualified); + try self.toString(&str.writer, qualified); - return try str.toOwnedSlice(allocator); + return try str.toOwnedSlice(); } - pub fn toString(self: *const Self, writer: anytype, qualified: bool) (Allocator.Error || std.fmt.BufPrintError)!void { + pub fn toString(self: *const Self, writer: anytype, qualified: bool) (Allocator.Error || std.fmt.BufPrintError || error{WriteFailed})!void { try self.toStringRaw(writer, qualified); } - pub fn toStringUnqualified(self: *const Self, writer: anytype) (Allocator.Error || std.fmt.BufPrintError)!void { + pub fn toStringUnqualified(self: *const Self, writer: anytype) (Allocator.Error || std.fmt.BufPrintError || error{WriteFailed})!void { try self.toStringRaw(writer, false); } - fn toStringRaw(self: *const Self, writer: anytype, qualified: bool) (Allocator.Error || std.fmt.BufPrintError)!void { + fn toStringRaw(self: *const Self, writer: anytype, qualified: bool) (Allocator.Error || std.fmt.BufPrintError || error{WriteFailed})!void { switch (self.def_type) { .Generic => try writer.print( "generic type #{}-{}", diff --git a/src/renderer.zig b/src/renderer.zig index 0a6b0d6b..a8f2bc78 100644 --- a/src/renderer.zig +++ b/src/renderer.zig @@ -3,7 +3,6 @@ const assert = std.debug.assert; const builtin = @import("builtin"); const Ast = @import("Ast.zig"); const Token = @import("Token.zig"); -const WriteableArrayList = @import("writeable_array_list.zig").WriteableArrayList; pub const Renderer = struct { const Self = @This(); @@ -189,7 +188,7 @@ pub const Renderer = struct { try self.renderToken(token, if (is_last) space else .None); if (!is_last) { - try self.ais.writer().writeByte('\\'); + try self.ais.writeByte('\\'); } } } @@ -252,14 +251,14 @@ pub const Renderer = struct { const lexeme = self.ast.tokens.items(.lexeme)[token]; if (self.ast.tokens.items(.tag)[token] == .Identifier and isAtIdentifier(lexeme)) { - try self.ais.writer().print( + try self.ais.print( "@\"{s}\"", .{ lexeme, }, ); } else { - try self.ais.writer().writeAll(lexeme); + try self.ais.writeAll(lexeme); } try self.renderSpace( @@ -315,7 +314,7 @@ pub const Renderer = struct { const next_token_tag = self.ast.tokens.items(.tag)[next_token]; if (space == .Comma and next_token_tag != .Comma) { - try self.ais.writer().writeByte(','); + try self.ais.writeByte(','); } if (space == .Semicolon or space == .Comma) self.ais.enableSpaceMode(space); @@ -352,7 +351,7 @@ pub const Renderer = struct { switch (space) { .None => {}, - .Space => if (!comment) try self.ais.writer().writeByte(' '), + .Space => if (!comment) try self.ais.writeByte(' '), .Newline => if (!comment) try self.ais.insertNewline(), .Comma => if (next_token_tag == .Comma) { @@ -364,7 +363,7 @@ pub const Renderer = struct { .CommaSpace => if (next_token_tag == .Comma) { try self.renderToken(next_token, .Space); } else if (!comment) { - try self.ais.writer().writeByte(' '); + try self.ais.writeByte(' '); }, .Semicolon => if (next_token_tag == .Semicolon) { @@ -376,7 +375,7 @@ pub const Renderer = struct { .SemicolonSpace => if (next_token_tag == .Semicolon) { try self.renderToken(next_token, .Space); } else if (!comment) { - try self.ais.writer().writeByte(' '); + try self.ais.writeByte(' '); }, .Skip => unreachable, @@ -412,7 +411,7 @@ pub const Renderer = struct { } else if (index == start and comment.len > 0) { // Otherwise if the first comment is on the same line as // the token before it, prefix it with a single space. - try self.ais.writer().writeByte(' '); + try self.ais.writeByte(' '); } } @@ -428,11 +427,11 @@ pub const Renderer = struct { self.ais.disabled_offset = null; } else if (self.ais.disabled_offset == null and std.mem.eql(u8, comment, "buzz fmt: off")) { // Write with the canonical single space. - try self.ais.writer().writeAll("// buzz fmt: off\n"); + try self.ais.writeAll("// buzz fmt: off\n"); self.ais.disabled_offset = index; } else { // Write the comment minus trailing whitespace. - try self.ais.writer().print( + try self.ais.print( "//{s}{s}\n", .{ if (comment.len > 1 and !std.mem.startsWith(u8, comment, " ")) @@ -1040,12 +1039,12 @@ pub const Renderer = struct { }; if (string_literal.delimiter == '`') { - var buffer = WriteableArrayList(u8).init(self.allocator); + var buffer = std.Io.Writer.Allocating.init(self.allocator); defer buffer.deinit(); try formatter.format(&buffer.writer); - try self.ais.writeFixingWhitespace(buffer.list.items); + try self.ais.writeFixingWhitespace(buffer.written()); } else { try formatter.format(self.ais.underlying_writer); } @@ -1064,22 +1063,22 @@ pub const Renderer = struct { const string_lexeme = self.ast.tokens.items(.lexeme)[locations[node]]; // " or ` - try self.ais.writer().writeAll(string_lexeme[0..1]); + try self.ais.writeAll(string_lexeme[0..1]); for (self.ast.nodes.items(.components)[node].String) |part| { if (tags[part] != .StringLiteral) { - try self.ais.writer().writeByte('{'); + try self.ais.writeByte('{'); try self.renderNode(part, .None); - try self.ais.writer().writeByte('}'); + try self.ais.writeByte('}'); } else { try self.renderNode(part, .None); } } // " or ` - try self.ais.writer().writeByte(string_lexeme[string_lexeme.len - 1]); + try self.ais.writeByte(string_lexeme[string_lexeme.len - 1]); try self.renderSpace( locations[node], string_lexeme.len, @@ -3477,13 +3476,6 @@ pub const Renderer = struct { const AutoIndentingStream = struct { const SelfAis = @This(); - pub const WriteError = std.io.Writer.Error; - pub const Writer = std.io.GenericWriter( - *SelfAis, - WriteError, - write, - ); - pub const IndentType = enum { normal, after_equals, @@ -3530,15 +3522,28 @@ pub const Renderer = struct { self.space_stack.deinit(allocator); } - pub fn writer(self: *SelfAis) Writer { - return .{ .context = self }; - } - pub fn write(self: *SelfAis, bytes: []const u8) std.Io.Writer.Error!usize { try self.applyIndent(); return try self.writeNoIndent(bytes); } + pub fn writeByte(self: *SelfAis, byte: u8) std.Io.Writer.Error!void { + _ = try self.write(&.{byte}); + } + + pub fn print(self: *SelfAis, comptime fmt: []const u8, args: anytype) std.Io.Writer.Error!void { + try self.applyIndent(); + if (self.disabled_offset == null) try self.underlying_writer.print(fmt, args); + if (fmt[fmt.len - 1] == '\n') self.resetLine(); + } + + pub fn writeAll(self: *SelfAis, bytes: []const u8) Error!void { + if (bytes.len == 0) return; + try self.applyIndent(); + if (self.disabled_offset == null) try self.underlying_writer.writeAll(bytes); + if (bytes[bytes.len - 1] == '\n') self.resetLine(); + } + // Change the indent delta without changing the final indentation level pub fn setIndentDelta(self: *SelfAis, new_indent_delta: usize) !void { if (self.indent_delta == new_indent_delta) { diff --git a/src/repl.zig b/src/repl.zig index 3c344371..2add2972 100644 --- a/src/repl.zig +++ b/src/repl.zig @@ -117,17 +117,17 @@ pub fn repl(allocator: std.mem.Allocator) !void { var stderr = io.stderrWriter; printBanner(stdout, false); - var buzz_history_path = std.ArrayList(u8).empty; - defer buzz_history_path.deinit(allocator); + var buzz_history_path = std.Io.Writer.Allocating.init(allocator); + defer buzz_history_path.deinit(); - try buzz_history_path.writer(allocator).print( + try buzz_history_path.writer.print( "{s}/.buzz_history\x00", .{envMap.get("HOME") orelse "."}, ); if (builtin.os.tag != .windows) { _ = ln.linenoiseHistorySetMaxLen(100); - _ = ln.linenoiseHistoryLoad(@ptrCast(buzz_history_path.items.ptr)); + _ = ln.linenoiseHistoryLoad(@ptrCast(buzz_history_path.written().ptr)); } // Import std and debug as commodity @@ -148,9 +148,11 @@ pub fn repl(allocator: std.mem.Allocator) !void { var reader_buffer = [_]u8{0}; var stdin_reader = std.fs.File.stdin().reader(reader_buffer[0..]); - var reader = io.AllocatedReader{ - .reader = &stdin_reader.interface, - }; + var reader = io.AllocatedReader.init( + allocator, + &stdin_reader.interface, + null, + ); while (true) { if (builtin.os.tag == .windows) { @@ -170,7 +172,7 @@ pub fn repl(allocator: std.mem.Allocator) !void { PROMPT, ) else // FIXME: in that case, at least use an arena? - reader.readUntilDelimiterOrEof(allocator, '\n') catch @panic("Could not read stdin"); + reader.readUntilDelimiterOrEof('\n') catch @panic("Could not read stdin"); if (read_source == null) { std.process.exit(0); @@ -235,7 +237,7 @@ pub fn repl(allocator: std.mem.Allocator) !void { if (parser.reporter.last_error == null and codegen.reporter.last_error == null) { if (builtin.os.tag != .windows) { _ = ln.linenoiseHistoryAdd(source); - _ = ln.linenoiseHistorySave(@ptrCast(buzz_history_path.items.ptr)); + _ = ln.linenoiseHistorySave(@ptrCast(buzz_history_path.written().ptr)); } // FIXME: why can't I deinit those? // previous_parser_globals.deinit(); @@ -251,22 +253,23 @@ pub fn repl(allocator: std.mem.Allocator) !void { const value = expr orelse vm.globals.items[previous_global_top]; - var value_str = std.ArrayList(u8).empty; - defer value_str.deinit(vm.gc.allocator); + var value_str = std.Io.Writer.Allocating.init(vm.gc.allocator); + defer value_str.deinit(); + var state = disassembler.DumpState{ .vm = &vm, }; state.valueDump( value, - value_str.writer(vm.gc.allocator), + &value_str.writer, false, ); var scanner = Scanner.init( gc.allocator, "REPL", - value_str.items, + value_str.written(), ); scanner.highlight(stdout, true_color); @@ -291,7 +294,7 @@ pub fn repl(allocator: std.mem.Allocator) !void { std.mem.copyForwards(u8, previous_input.?, source); } else if (builtin.os.tag != .windows) { _ = ln.linenoiseHistoryAdd(source); - _ = ln.linenoiseHistorySave(@ptrCast(buzz_history_path.items.ptr)); + _ = ln.linenoiseHistorySave(@ptrCast(buzz_history_path.written().ptr)); } } diff --git a/src/tests/fmt.zig b/src/tests/fmt.zig index 3cf60d20..251594d0 100644 --- a/src/tests/fmt.zig +++ b/src/tests/fmt.zig @@ -5,7 +5,6 @@ const Parser = @import("../Parser.zig"); const GC = @import("../GC.zig"); const TypeRegistry = @import("../TypeRegistry.zig"); const Renderer = @import("../renderer.zig").Renderer; -const WriteableArrayList = @import("../writeable_array_list.zig").WriteableArrayList; const ignore = std.StaticStringMap(void).initComptime( .{ @@ -71,7 +70,7 @@ fn testFmt(prefix: []const u8, entry: std.fs.Dir.Entry) !void { .Fmt, ); - var result = WriteableArrayList(u8).init(allocator); + var result = std.Io.Writer.Allocating.init(allocator); if (parser.parse(source, file_name, file_name) catch null) |ast| { try Renderer.render( @@ -82,7 +81,7 @@ fn testFmt(prefix: []const u8, entry: std.fs.Dir.Entry) !void { try std.testing.expectEqualStrings( source, - result.list.items, + result.written(), ); } else { try std.testing.expect(false); diff --git a/src/value.zig b/src/value.zig index 6a164272..6b40e4b0 100644 --- a/src/value.zig +++ b/src/value.zig @@ -159,16 +159,16 @@ pub const Value = packed struct { return self; } - pub fn toStringAlloc(value: Value, allocator: Allocator) (Allocator.Error || std.fmt.BufPrintError)![]const u8 { - var str = std.ArrayList(u8).empty; + pub fn toStringAlloc(value: Value, allocator: Allocator) (Allocator.Error || std.fmt.BufPrintError || error{WriteFailed})![]const u8 { + var str = std.Io.Writer.Allocating.init(allocator); - try value.toString(&str.writer(allocator)); + try value.toString(&str.writer); - return try str.toOwnedSlice(allocator); + return try str.toOwnedSlice(); } // FIXME: should be a std.io.Writer once it exists for ArrayLists - pub fn toString(self: Value, writer: *const std.ArrayList(u8).Writer) (Allocator.Error || std.fmt.BufPrintError)!void { + pub fn toString(self: Value, writer: *std.Io.Writer) (Allocator.Error || std.fmt.BufPrintError || error{WriteFailed})!void { if (self.isObj()) { try self.obj().toString(writer); diff --git a/src/vm.zig b/src/vm.zig index fbffe933..83af1176 100644 --- a/src/vm.zig +++ b/src/vm.zig @@ -421,6 +421,7 @@ pub const VM = struct { ReachedMaximumMemoryUsage, ReachedMaximumCPUUsage, ReachedMaximumRecursiveCall, + WriteFailed, Custom, // TODO: remove when user can use this set directly in buzz code } || std.mem.Allocator.Error || std.fmt.BufPrintError; @@ -4616,12 +4617,11 @@ pub const VM = struct { for (stack, 0..) |frame, i| { const next = if (i < stack.len - 1) stack[i + 1] else null; - var msg = std.ArrayList(u8).empty; - var writer = msg.writer(self.gc.allocator); + var msg = std.Io.Writer.Allocating.init(self.gc.allocator); if (next) |unext| { const function_name = unext.closure.function.type_def.resolved_type.?.Function.name.string; - writer.print( + msg.writer.print( if (builtin.os.tag != .windows) "\t{s} in \x1b[36m{s}\x1b[0m at {s}" else @@ -4641,7 +4641,7 @@ pub const VM = struct { }, ) catch @panic("Could not report error"); } else { - writer.print( + msg.writer.print( "\t{s} in {s}", .{ if (i == 0) @@ -4660,7 +4660,7 @@ pub const VM = struct { if (frame.call_site) |call_site| { if (frame.closure.function.type_def.resolved_type.?.Function.function_type != .ScriptEntryPoint) { - writer.print( + msg.writer.print( ":{d}:{d}", .{ self.current_ast.tokens.items(.line)[call_site] + 1, @@ -4673,7 +4673,7 @@ pub const VM = struct { notes.append( self.gc.allocator, .{ - .message = msg.toOwnedSlice(self.gc.allocator) catch @panic("Could not report error"), + .message = msg.toOwnedSlice() catch @panic("Could not report error"), .show_prefix = false, }, ) catch @panic("Could not report error"); diff --git a/src/wasm_repl.zig b/src/wasm_repl.zig index 179c36f7..2055aa8c 100644 --- a/src/wasm_repl.zig +++ b/src/wasm_repl.zig @@ -96,16 +96,18 @@ pub export fn runLine(ctx: *ReplCtx) void { var reader_buffer = [_]u8{0}; var stdin_reader = io.stdinReader(reader_buffer[0..]); - var stdin = io.AllocatedReader{ - .reader = &stdin_reader, - }; + var stdin = io.AllocatedReader.init( + ctx.vm.gc.allocator, + &stdin_reader, + null, + ); var previous_global_top = ctx.vm.globals_count; var previous_parser_globals = ctx.parser.globals.clone(ctx.parser.gc.allocator) catch unreachable; var previous_globals = ctx.vm.globals.clone(ctx.parser.gc.allocator) catch unreachable; var previous_type_registry = ctx.vm.gc.type_registry.registry.clone(ctx.parser.gc.allocator) catch unreachable; - const source = stdin.readAll(ctx.vm.gc.allocator) catch unreachable; + const source = stdin.readAll() catch unreachable; errdefer ctx.vm.gc.allocator.free(source); if (source.len == 0) { @@ -142,22 +144,22 @@ pub export fn runLine(ctx: *ReplCtx) void { const value = expr orelse ctx.vm.globals.items[previous_global_top]; - var value_str = std.ArrayList(u8).empty; - defer value_str.deinit(ctx.vm.gc.allocator); + var value_str = std.Io.Writer.Allocating.init(ctx.vm.gc.allocator); + defer value_str.deinit(); var state = DumpState{ .vm = ctx.vm, }; state.valueDump( value, - value_str.writer(ctx.vm.gc.allocator), + &value_str.writer, false, ); var scanner = Scanner.init( ctx.vm.gc.allocator, "REPL", - value_str.items, + value_str.written(), ); scanner.highlight(stdout, false); diff --git a/src/writeable_array_list.zig b/src/writeable_array_list.zig deleted file mode 100644 index 296ce802..00000000 --- a/src/writeable_array_list.zig +++ /dev/null @@ -1,47 +0,0 @@ -const std = @import("std"); - -/// Wraps std.ArrayList to provide a std.Io.Writer until its provided by std lib -pub fn WriteableArrayList(comptime T: type) type { - return struct { - const Self = @This(); - - list: std.array_list.Managed(T), - writer: std.Io.Writer = .{ - .buffer = &.{}, - .vtable = &.{ - .drain = drain, - }, - }, - - pub fn init(allocator: std.mem.Allocator) Self { - return .{ - .list = .init(allocator), - }; - } - - pub fn deinit(self: *Self) void { - self.list.deinit(); - } - - fn drain(w: *std.Io.Writer, data: []const []const u8, splat: usize) std.Io.Writer.Error!usize { - var self: *Self = @alignCast(@fieldParentPtr("writer", w)); - - if (w.buffer.len > 0) { - self.list.appendSlice(w.buffer) catch return error.WriteFailed; - } - - var written: usize = 0; - for (data[0 .. data.len - 1]) |element| { - self.list.appendSlice(element) catch return error.WriteFailed; - written += element.len; - } - - const last = data[data.len - 1]; - for (0..splat) |_| { - self.list.appendSlice(last) catch return error.WriteFailed; - } - - return written + last.len * splat; - } - }; -} From b6f52eff95574c4b07b0066fd888e7464351cc27 Mon Sep 17 00:00:00 2001 From: Benoit Giannangeli Date: Thu, 16 Oct 2025 11:18:04 +0200 Subject: [PATCH 2/4] fix(vm): Crazy bug catched by new safety check probably in ArrayList.pop We were accessing a ptr to a popped value of the stack ArrayList. Seems like now zig's freeing that spot in Debug mode. --- src/Reporter.zig | 5 ++--- src/disassembler.zig | 3 ++- src/vm.zig | 25 ++++++++++++++----------- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/Reporter.zig b/src/Reporter.zig index 428d5ea1..94c10eab 100644 --- a/src/Reporter.zig +++ b/src/Reporter.zig @@ -773,12 +773,11 @@ pub fn reportTypeCheck( } var following_message = if (expected_location != null) - expected_message + &expected_message else - actual_message; + &actual_message; following_message.writer.writeAll("expected `") catch @panic("Unable to report error"); - expected_type.toString(&following_message.writer, false) catch @panic("Unable to report error"); following_message.writer.writeAll("`") catch @panic("Unable to report error"); diff --git a/src/disassembler.zig b/src/disassembler.zig index 47715b04..55f532c3 100644 --- a/src/disassembler.zig +++ b/src/disassembler.zig @@ -175,7 +175,8 @@ pub fn dumpStack(vm: *VM) void { print(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n", .{}); var value: [*]Value = @ptrCast(vm.current_fiber.stack[0..]); - while (@intFromPtr(value) < @intFromPtr(vm.current_fiber.stack_top)) { + var count: usize = 0; + while (@intFromPtr(value) < @intFromPtr(vm.current_fiber.stack_top) and count < vm.current_fiber.stack.len) : (count += 1) { var value_str = value[0].toStringAlloc(global_allocator) catch unreachable; defer global_allocator.free(value_str); diff --git a/src/vm.zig b/src/vm.zig index 83af1176..7d354414 100644 --- a/src/vm.zig +++ b/src/vm.zig @@ -133,7 +133,7 @@ pub const Fiber = struct { .parent_fiber = parent_fiber, .stack = try allocator.alloc(Value, BuildOptions.stack_size), .stack_top = undefined, - .frames = std.ArrayList(CallFrame){}, + .frames = .empty, .open_upvalues = null, .instruction = instruction, .extra_instruction = extra_instruction, @@ -547,6 +547,8 @@ pub const VM = struct { } pub inline fn currentFrame(self: *Self) ?*CallFrame { + std.debug.assert(self.current_fiber.frame_count <= self.current_fiber.frames.items.len); + if (self.current_fiber.frame_count == 0) { return null; } @@ -2064,7 +2066,7 @@ pub const VM = struct { inline fn returnFrame(self: *Self) bool { const result = self.pop(); - const frame = self.currentFrame().?; + const frame = self.currentFrame().?.*; self.closeUpValues(&frame.slots[0]); @@ -4509,25 +4511,26 @@ pub const VM = struct { null; while (self.current_fiber.frame_count > 0 or self.current_fiber.parent_fiber != null) { - const frame = self.currentFrame(); + const frame_ptr = self.currentFrame(); + const frame_val = if (frame_ptr) |ptr| ptr.* else null; if (self.current_fiber.frame_count > 0) { - const function_type = frame.?.closure.function.type_def.resolved_type.?.Function.function_type; + const function_type = frame_ptr.?.closure.function.type_def.resolved_type.?.Function.function_type; if (function_type != .ScriptEntryPoint and function_type != .Repl) { - try stack.append(self.gc.allocator, frame.?.*); + try stack.append(self.gc.allocator, frame_val.?); } // Are we in a try-catch? - if (frame.?.try_ip) |try_ip| { + if (frame_ptr.?.try_ip) |try_ip| { // Push error and jump to start of the catch clauses self.push(payload); - frame.?.ip = try_ip; + frame_ptr.?.ip = try_ip; return; } // Pop frame - self.closeUpValues(&frame.?.slots[0]); + self.closeUpValues(&frame_ptr.?.slots[0]); self.current_fiber.frame_count -= 1; _ = self.current_fiber.frames.pop(); } @@ -4582,10 +4585,10 @@ pub const VM = struct { return; } - if (frame != null) { - self.current_fiber.stack_top = frame.?.slots; + if (frame_val != null) { + self.current_fiber.stack_top = frame_val.?.slots; - if (frame.?.error_value) |error_value| { + if (frame_val.?.error_value) |error_value| { // Push error_value as failed function return value self.push(error_value); From 2907fc9508972b17a58f6ef4e606478e38b3692b Mon Sep 17 00:00:00 2001 From: Benoit Giannangeli Date: Thu, 16 Oct 2025 11:49:00 +0200 Subject: [PATCH 3/4] fix(ci): Simplified ci.yaml Using `strategy` instead of copying for each OS --- .github/workflows/ci.yaml | 106 ++++++-------------------------------- README.md | 2 +- build.zig | 2 +- 3 files changed, 17 insertions(+), 93 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 75c997f6..3bd0bbfc 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -5,51 +5,16 @@ on: branches: [main] jobs: - # test-windows: - # runs-on: windows-latest - # steps: - # - name: Checkout project - # uses: actions/checkout@v3.0.0 - # - name: Checkout submodules - # run: git submodule update --init --recursive - # - name: Setup nightly Zig - # uses: mlugg/setup-zig@v2 - # with: - # version: 0.15.1 - # - name: Build test ffi lib - # run: zig build-lib -dynamic tests/utils/foreign.zig && mv foreign.* tests/utils/ - - # - name: Build - # run: zig build && ls ./zig-out/lib/buzz - - # - name: Run behavior tests Debug - # run: zig build test-behavior - # - name: Cleanup - # run: rm -rf zig-out zig-cache - # - name: Run behavior tests Debug with JIT always on - # run: zig build -Djit_always_on test && zig build -Djit_always_on test-behavior - # - name: Cleanup - # run: rm -rf zig-out zig-cache - - # - name: Run behavior tests ReleaseSafe - # run: zig build -Doptimize=ReleaseSafe test && zig build -Doptimize=ReleaseSafe test-behavior - # - name: Cleanup - # run: rm -rf zig-out zig-cache - # - name: Run behavior tests ReleaseSafe with JIT always on - # run: zig build -Doptimize=ReleaseSafe -Djit_always_on test && zig build -Doptimize=ReleaseSafe -Djit_always_on test-behavior - # - name: Cleanup - # run: rm -rf zig-out zig-cache - - # - name: Run behavior tests ReleaseFast - # run: zig build -Doptimize=ReleaseFast test && zig build -Doptimize=ReleaseFast test-behavior - # - name: Cleanup - # run: rm -rf zig-out zig-cache - # - name: Run behavior tests ReleaseFast with JIT always on - # run: zig build -Doptimize=ReleaseFast -Djit_always_on test && zig build -Doptimize=ReleaseFast -Djit_always_on test-behavior - # - name: Cleanup - # run: rm -rf zig-out zig-cache - test-macos: - runs-on: macos-latest + tests: + runs-on: ${{ matrix.operating-system }} + + strategy: + fail-fast: false + matrix: + zig-version: + - "master" + operating-system: [ ubuntu-latest, macos-latest ] + steps: - name: Install homebrew run: /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" @@ -60,50 +25,7 @@ jobs: - name: Setup nightly Zig uses: mlugg/setup-zig@v2 with: - version: 0.15.1 - - name: Build test ffi lib - run: zig build-lib -dynamic tests/utils/foreign.zig && mv libforeign.* tests/utils/ - - - name: Run behavior tests Debug - run: zig build test && zig build test-behavior - - name: Cleanup - run: rm -rf zig-out zig-cache - - - name: Run behavior tests Debug with JIT always on - run: zig build -Djit_always_on test && zig build -Djit_always_on test-behavior - - name: Cleanup - run: rm -rf zig-out zig-cache - - - name: Run behavior tests ReleaseSafe - run: zig build -Doptimize=ReleaseSafe test && zig build -Doptimize=ReleaseSafe test-behavior - - name: Cleanup - run: rm -rf zig-out zig-cache - - - name: Run behavior tests ReleaseSafe with JIT always on - run: zig build -Doptimize=ReleaseSafe -Djit_always_on test && zig build -Doptimize=ReleaseSafe -Djit_always_on test-behavior - - name: Cleanup - run: rm -rf zig-out zig-cache - - - name: Run behavior tests ReleaseFast - run: zig build -Doptimize=ReleaseFast test && zig build -Doptimize=ReleaseFast test-behavior - - name: Cleanup - run: rm -rf zig-out zig-cache - - - name: Run behavior tests ReleaseFast with JIT always on - run: zig build -Doptimize=ReleaseFast -Djit_always_on test && zig build -Doptimize=ReleaseFast -Djit_always_on test-behavior - - name: Cleanup - run: rm -rf zig-out zig-cache - test-linux: - runs-on: ubuntu-latest - steps: - - name: Checkout project - uses: actions/checkout@v3.0.0 - - name: Checkout submodules - run: git submodule update --init --recursive - - name: Setup nightly Zig - uses: mlugg/setup-zig@v2 - with: - version: 0.15.1 + version: ${{ matrix.zig-version }} - name: Build test ffi lib run: zig build-lib -dynamic tests/utils/foreign.zig && mv libforeign.* tests/utils/ @@ -136,6 +58,7 @@ jobs: run: zig build -Doptimize=ReleaseFast -Djit_always_on test && zig build -Doptimize=ReleaseFast -Djit_always_on test-behavior - name: Cleanup run: rm -rf zig-out zig-cache + wasm-build: runs-on: ubuntu-latest steps: @@ -146,11 +69,12 @@ jobs: - name: Setup nightly Zig uses: mlugg/setup-zig@v2 with: - version: 0.15.1 + version: master - name: Build for wasm run: zig build -Dtarget=wasm32-freestanding -freference-trace -Doptimize=ReleaseSmall - name: Cleanup run: rm -rf zig-out zig-cache + lint: runs-on: macos-latest steps: @@ -158,5 +82,5 @@ jobs: - name: Setup nightly Zig uses: mlugg/setup-zig@v2 with: - version: 0.15.1 + version: master - run: zig fmt --check src/*.zig src/**/*.zig diff --git a/README.md b/README.md index e075da4a..421c369f 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ A small/lightweight statically typed scripting language written in Zig ## How to build and install ### Requirements -- Zig 0.15.1 +- Zig 0.16.0-dev.732+2f3234c76 - Since this is built with Zig, you should be able to build buzz on a wide variety of architectures even though this has only been tested on x86/M1. - Linux or macOS (Windows support [is coming](https://github.com/buzz-language/buzz/issues/74)) - libc diff --git a/build.zig b/build.zig index d97ace16..44a0f7a4 100644 --- a/build.zig +++ b/build.zig @@ -101,7 +101,7 @@ pub fn build(b: *Build) !void { // Check minimum zig version const current_zig = builtin.zig_version; - const min_zig = std.SemanticVersion.parse("0.15.1") catch return; + const min_zig = std.SemanticVersion.parse("0.16.0-dev.732+2f3234c76") catch return; if (current_zig.order(min_zig).compare(.lt)) { @panic(b.fmt("Your Zig version v{f} does not meet the minimum build requirement of v{f}", .{ current_zig, min_zig })); } From 677616ab49e6f05844c5afc6106d84e02210b786 Mon Sep 17 00:00:00 2001 From: Benoit Giannangeli Date: Thu, 16 Oct 2025 12:06:42 +0200 Subject: [PATCH 4/4] fix: Value, Obj and ObjTypeDef had all a toString function but not a format function `format` is used when doing `.print("{f}", .{value})` --- src/Reporter.zig | 19 ++++++++++++------ src/lib/buzz_api.zig | 38 ++++++++++++++++++------------------ src/obj.zig | 32 ++++++++++++++++++++---------- src/value.zig | 46 ++++++++++++++++++++++++-------------------- 4 files changed, 79 insertions(+), 56 deletions(-) diff --git a/src/Reporter.zig b/src/Reporter.zig index 94c10eab..f533bf8f 100644 --- a/src/Reporter.zig +++ b/src/Reporter.zig @@ -761,9 +761,13 @@ pub fn reportTypeCheck( } } - actual_message.writer.print("{s}: got type `", .{message}) catch @panic("Unable to report error"); - actual_type.toString(&actual_message.writer, false) catch @panic("Unable to report error"); - actual_message.writer.writeAll("`") catch @panic("Unable to report error"); + actual_message.writer.print( + "{s}: got type `{f}`", + .{ + message, + actual_type, + }, + ) catch @panic("Unable to report error"); var expected_message = std.Io.Writer.Allocating.init(self.allocator); defer { @@ -777,9 +781,12 @@ pub fn reportTypeCheck( else &actual_message; - following_message.writer.writeAll("expected `") catch @panic("Unable to report error"); - expected_type.toString(&following_message.writer, false) catch @panic("Unable to report error"); - following_message.writer.writeAll("`") catch @panic("Unable to report error"); + following_message.writer.print( + "expected `{f}`", + .{ + expected_type, + }, + ) catch @panic("Unable to report error"); var full_message = if (expected_location == null) actual_message diff --git a/src/lib/buzz_api.zig b/src/lib/buzz_api.zig index f70c9477..70928272 100644 --- a/src/lib/buzz_api.zig +++ b/src/lib/buzz_api.zig @@ -56,71 +56,71 @@ pub const Value = packed struct { // We only need this so that an NativeFn can see the error returned by its raw function pub const Error = Value{ .val = ErrorMask }; - pub inline fn fromBoolean(val: bool) Value { + pub fn fromBoolean(val: bool) Value { return if (val) True else False; } - pub inline fn fromInteger(val: Integer) Value { + pub fn fromInteger(val: Integer) Value { return .{ .val = IntegerMask | @as(u48, @bitCast(val)) }; } - pub inline fn fromDouble(val: Double) Value { + pub fn fromDouble(val: Double) Value { return .{ .val = @as(u64, @bitCast(val)) }; } - pub inline fn fromObj(val: *anyopaque) Value { + pub fn fromObj(val: *anyopaque) Value { return .{ .val = PointerMask | @intFromPtr(val) }; } - pub inline fn getTag(self: Value) u3 { + pub fn getTag(self: Value) u3 { return @intCast(@as(u32, @intCast(self.val >> 32)) & TagMask); } - pub inline fn isBool(self: Value) bool { + pub fn isBool(self: Value) bool { return self.val & (TaggedPrimitiveMask | SignMask) == BooleanMask; } - pub inline fn isInteger(self: Value) bool { + pub fn isInteger(self: Value) bool { return self.val & (TaggedUpperValueMask | SignMask) == IntegerMask; } - pub inline fn isFloat(self: Value) bool { + pub fn isFloat(self: Value) bool { return self.val & TaggedValueMask != TaggedValueMask; } - pub inline fn isNumber(self: Value) bool { + pub fn isNumber(self: Value) bool { return self.isFloat() or self.isInteger(); } - pub inline fn isObj(self: Value) bool { + pub fn isObj(self: Value) bool { return self.val & PointerMask == PointerMask; } - pub inline fn isNull(self: Value) bool { + pub fn isNull(self: Value) bool { return self.val == NullMask; } - pub inline fn isVoid(self: Value) bool { + pub fn isVoid(self: Value) bool { return self.val == VoidMask; } - pub inline fn isError(self: Value) bool { + pub fn isError(self: Value) bool { return self.val == ErrorMask; } - pub inline fn boolean(self: Value) bool { + pub fn boolean(self: Value) bool { return self.val == TrueMask; } - pub inline fn integer(self: Value) Integer { + pub fn integer(self: Value) Integer { return @bitCast(@as(u48, @intCast(self.val & 0xffffffffffff))); } - pub inline fn double(self: Value) Double { + pub fn double(self: Value) Double { return @bitCast(self.val); } - pub inline fn obj(self: Value) *anyopaque { + pub fn obj(self: Value) *anyopaque { return @ptrFromInt(@as(usize, @truncate(self.val & ~PointerMask))); } @@ -213,7 +213,7 @@ pub const VM = opaque { pub extern fn bz_stringToValue(vm: *VM, string: ?[*]const u8, len: usize) callconv(.c) Value; pub extern fn bz_stringToValueZ(vm: *VM, string: ?[*:0]const u8) callconv(.c) Value; pub extern fn bz_newUserData(vm: *VM, userdata: u64) callconv(.c) Value; - pub inline fn pushError(self: *VM, qualified_name: []const u8, message: ?[]const u8) void { + pub fn pushError(self: *VM, qualified_name: []const u8, message: ?[]const u8) void { self.bz_pushError( qualified_name.ptr, qualified_name.len, @@ -221,7 +221,7 @@ pub const VM = opaque { if (message) |m| m.len else 0, ); } - pub inline fn pushErrorEnum(self: *VM, qualified_name: []const u8, case: []const u8) void { + pub fn pushErrorEnum(self: *VM, qualified_name: []const u8, case: []const u8) void { self.bz_pushErrorEnum( qualified_name.ptr, qualified_name.len, diff --git a/src/obj.zig b/src/obj.zig index 29840a4b..7f617c8d 100644 --- a/src/obj.zig +++ b/src/obj.zig @@ -509,6 +509,10 @@ pub const Obj = struct { } } + pub fn format(obj: *Obj, w: *std.Io.Writer) std.Io.Writer.Error!void { + obj.toString(w) catch return error.WriteFailed; + } + pub fn toString(obj: *Obj, writer: *std.Io.Writer) (Allocator.Error || std.fmt.BufPrintError || error{WriteFailed})!void { return switch (obj.obj_type) { .String => { @@ -675,18 +679,22 @@ pub const Obj = struct { if (bound.closure) |closure| { const closure_name: []const u8 = closure.function.type_def.resolved_type.?.Function.name.string; - try writer.writeAll("bound method: "); - - try (bound.receiver).toString(writer); - - try writer.print(" to {s}", .{closure_name}); + try writer.print( + "bound method: {f} to {s}", + .{ + bound.receiver, + closure_name, + }, + ); } else { assert(bound.native != null); - try writer.writeAll("bound method: "); - - try (bound.receiver).toString(writer); - - try writer.print(" to native 0x{}", .{@intFromPtr(bound.native.?)}); + try writer.print( + "bound method: {f} to native 0x{}", + .{ + bound.receiver, + @intFromPtr(bound.native.?), + }, + ); } }, .Native => { @@ -4900,6 +4908,10 @@ pub const ObjTypeDef = struct { return try str.toOwnedSlice(); } + pub fn format(self: *Self, w: *std.Io.Writer) std.Io.Writer.Error!void { + self.toString(w, false) catch return error.WriteFailed; + } + pub fn toString(self: *const Self, writer: anytype, qualified: bool) (Allocator.Error || std.fmt.BufPrintError || error{WriteFailed})!void { try self.toStringRaw(writer, qualified); } diff --git a/src/value.zig b/src/value.zig index 6b40e4b0..0931ae64 100644 --- a/src/value.zig +++ b/src/value.zig @@ -47,87 +47,87 @@ pub const Value = packed struct { // We only need this so that an NativeFn can see the error returned by its raw function pub const Error = Value{ .val = ErrorMask }; - pub inline fn fromBoolean(val: bool) Value { + pub fn fromBoolean(val: bool) Value { return if (val) True else False; } - pub inline fn fromInteger(val: Integer) Value { + pub fn fromInteger(val: Integer) Value { return .{ .val = IntegerMask | @as(u48, @bitCast(val)) }; } - pub inline fn fromDouble(val: Double) Value { + pub fn fromDouble(val: Double) Value { return .{ .val = @as(u64, @bitCast(val)) }; } - pub inline fn fromObj(val: *o.Obj) Value { + pub fn fromObj(val: *o.Obj) Value { return .{ .val = PointerMask | @intFromPtr(val) }; } - pub inline fn getTag(self: Value) Tag { + pub fn getTag(self: Value) Tag { return @as(Tag, @intCast(@as(u32, @intCast(self.val >> 32)) & TagMask)); } - pub inline fn isBool(self: Value) bool { + pub fn isBool(self: Value) bool { return self.val & (TaggedPrimitiveMask | SignMask) == BooleanMask; } - pub inline fn isInteger(self: Value) bool { + pub fn isInteger(self: Value) bool { return self.val & (TaggedUpperValueMask | SignMask) == IntegerMask; } - pub inline fn isDouble(self: Value) bool { + pub fn isDouble(self: Value) bool { return !self.isBool() and !self.isError() and !self.isInteger() and !self.isNull() and !self.isObj() and !self.isVoid(); } - pub inline fn isNumber(self: Value) bool { + pub fn isNumber(self: Value) bool { return self.isDouble() or self.isInteger(); } - pub inline fn isObj(self: Value) bool { + pub fn isObj(self: Value) bool { return self.val & PointerMask == PointerMask; } - pub inline fn isNull(self: Value) bool { + pub fn isNull(self: Value) bool { return self.val == NullMask; } - pub inline fn isVoid(self: Value) bool { + pub fn isVoid(self: Value) bool { return self.val == VoidMask; } - pub inline fn isError(self: Value) bool { + pub fn isError(self: Value) bool { return self.val == ErrorMask; } - pub inline fn boolean(self: Value) bool { + pub fn boolean(self: Value) bool { return self.val == TrueMask; } - pub inline fn integer(self: Value) Integer { + pub fn integer(self: Value) Integer { return @bitCast(@as(u48, @intCast(self.val & 0xffffffffffff))); } - pub inline fn double(self: Value) Double { + pub fn double(self: Value) Double { return @bitCast(self.val); } - pub inline fn obj(self: Value) *o.Obj { + pub fn obj(self: Value) *o.Obj { return @ptrFromInt(@as(usize, @truncate(self.val & ~PointerMask))); } - pub inline fn booleanOrNull(self: Value) ?bool { + pub fn booleanOrNull(self: Value) ?bool { return if (self.isBool()) self.boolean() else null; } - pub inline fn integerOrNull(self: Value) ?Integer { + pub fn integerOrNull(self: Value) ?Integer { return if (self.isInteger()) self.integer() else null; } - pub inline fn doubleOrNull(self: Value) ?Double { + pub fn doubleOrNull(self: Value) ?Double { return if (self.isDouble()) self.double() else null; } - pub inline fn objOrNull(self: Value) ?*o.Obj { + pub fn objOrNull(self: Value) ?*o.Obj { return if (self.isObj()) self.obj() else null; } @@ -159,6 +159,10 @@ pub const Value = packed struct { return self; } + pub fn format(value: Value, w: *std.Io.Writer) std.Io.Writer.Error!void { + value.toString(w) catch return error.WriteFailed; + } + pub fn toStringAlloc(value: Value, allocator: Allocator) (Allocator.Error || std.fmt.BufPrintError || error{WriteFailed})![]const u8 { var str = std.Io.Writer.Allocating.init(allocator);