From f90a0a3114a311793e5af2d5206dddd8ae780085 Mon Sep 17 00:00:00 2001 From: Jan200101 Date: Thu, 16 Oct 2025 22:29:53 +0200 Subject: [PATCH] update to zig 0.15.2 --- .github/workflows/pull-request.yml | 4 +- build.zig | 85 ++----------- src/Document.zig | 6 +- src/Spec.zig | 35 +++--- src/Workspace.zig | 16 +-- src/analysis.zig | 50 ++++---- src/cli.zig | 17 ++- src/format.zig | 16 +-- src/lsp.zig | 4 +- src/main.zig | 192 ++++++++++++++++++----------- src/parse.zig | 45 +++---- src/syntax.zig | 9 +- src/util.zig | 2 +- 13 files changed, 237 insertions(+), 244 deletions(-) diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 92ebaf2..c35921b 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -21,7 +21,7 @@ jobs: - name: Setup Zig uses: mlugg/setup-zig@v2 with: - version: 0.14.1 + version: 0.15.2 - name: Build run: zig build -Dtarget=${{ matrix.target }} test-pull-request: @@ -37,7 +37,7 @@ jobs: - name: Setup Zig uses: mlugg/setup-zig@v2 with: - version: 0.14.1 + version: 0.15.2 - name: Test run: zig build test diff --git a/build.zig b/build.zig index cb16dea..a3c3ba7 100644 --- a/build.zig +++ b/build.zig @@ -24,9 +24,11 @@ pub fn build(b: *std.Build) !void { { const unit_tests = b.addTest(.{ .name = "unit-tests", - .root_source_file = b.path("src/main.zig"), - .target = target, - .optimize = optimize, + .root_module = b.createModule(.{ + .root_source_file = b.path("src/main.zig"), + .target = target, + .optimize = optimize, + }), }); try attachModules(unit_tests); @@ -75,9 +77,11 @@ fn addExecutable(b: *std.Build, options: struct { }) !*std.Build.Step.Compile { const exe = b.addExecutable(.{ .name = "glsl_analyzer", - .root_source_file = b.path("src/main.zig"), - .target = options.target, - .optimize = options.optimize, + .root_module = b.createModule(.{ + .root_source_file = b.path("src/main.zig"), + .target = options.target, + .optimize = options.optimize, + }), }); try attachModules(exe); return exe; @@ -88,8 +92,7 @@ fn attachModules(step: *std.Build.Step.Compile) !void { step.linkLibC(); - const compressed_spec = try CompressStep.create(b, "spec.json.zlib", b.path("spec/spec.json")); - step.root_module.addAnonymousImport("glsl_spec.json.zlib", .{ .root_source_file = compressed_spec.getOutput() }); + step.root_module.addAnonymousImport("glsl_spec.json", .{ .root_source_file = b.path("spec/spec.json") }); const options = b.addOptions(); const build_root_path = try std.fs.path.resolve( @@ -100,69 +103,3 @@ fn attachModules(step: *std.Build.Step.Compile) !void { options.addOption([]const u8, "version", b.run(&.{ "git", "describe", "--tags", "--always" })); step.root_module.addOptions("build_options", options); } - -const CompressStep = struct { - step: std.Build.Step, - generated_file: std.Build.GeneratedFile, - input: std.Build.LazyPath, - - pub fn create(b: *std.Build, name: []const u8, path: std.Build.LazyPath) !*@This() { - const self = try b.allocator.create(@This()); - self.* = .{ - .step = std.Build.Step.init(.{ - .id = .custom, - .name = name, - .owner = b, - .makeFn = &make, - }), - .generated_file = .{ .step = &self.step }, - .input = path, - }; - path.addStepDependencies(&self.step); - return self; - } - - pub fn getOutput(self: *@This()) std.Build.LazyPath { - return .{ .generated = .{ .file = &self.generated_file } }; - } - - fn make(step: *std.Build.Step, _: std.Build.Step.MakeOptions) anyerror!void { - const b = step.owner; - const self: *@This() = @fieldParentPtr("step", step); - const input_path = self.input.getPath(b); - - var man = b.graph.cache.obtain(); - defer man.deinit(); - - man.hash.add(@as(u32, 0x00000002)); - const input_index = try man.addFile(input_path, 16 << 20); - - const is_hit = try step.cacheHit(&man); - - const digest = man.final(); - - const output_path = try b.cache_root.join(b.allocator, &.{ "o", &digest, step.name }); - self.generated_file.path = output_path; - - if (is_hit) return; - - const input_contents = man.files.keys()[input_index].contents.?; - - if (std.fs.path.dirname(output_path)) |dir| try b.cache_root.handle.makePath(dir); - var output_file = b.cache_root.handle.createFile(output_path, .{}) catch |err| { - std.log.err("could not open {s}: {s}", .{ output_path, @errorName(err) }); - return err; - }; - defer output_file.close(); - - var output_buffered = std.io.bufferedWriter(output_file.writer()); - { - var compress_stream = try std.compress.zlib.compressor(output_buffered.writer(), .{}); - try compress_stream.writer().writeAll(input_contents); - try compress_stream.finish(); - } - try output_buffered.flush(); - - try step.writeManifest(&man); - } -}; diff --git a/src/Document.zig b/src/Document.zig index a8c4418..0efd662 100644 --- a/src/Document.zig +++ b/src/Document.zig @@ -152,9 +152,9 @@ pub const CompleteParseTree = struct { var arena = std.heap.ArenaAllocator.init(parent_allocator); errdefer arena.deinit(); - var diagnostics = std.ArrayList(parse.Diagnostic).init(arena.allocator()); + var diagnostics = std.array_list.Managed(parse.Diagnostic).init(arena.allocator()); - var ignored = std.ArrayList(parse.Token).init(parent_allocator); + var ignored = std.array_list.Managed(parse.Token).init(parent_allocator); defer ignored.deinit(); const tree = try parse.parse(arena.allocator(), text, .{ @@ -162,7 +162,7 @@ pub const CompleteParseTree = struct { .diagnostics = &diagnostics, }); - var extensions = std.ArrayList([]const u8).init(arena.allocator()); + var extensions = std.array_list.Managed([]const u8).init(arena.allocator()); errdefer extensions.deinit(); for (ignored.items) |token| { diff --git a/src/Spec.zig b/src/Spec.zig index ae9f345..25ad02f 100644 --- a/src/Spec.zig +++ b/src/Spec.zig @@ -53,16 +53,11 @@ pub const Function = struct { }; }; -const compressed_bytes = @embedFile("glsl_spec.json.zlib"); +const spec_bytes = @embedFile("glsl_spec.json"); pub fn load(allocator: std.mem.Allocator) !@This() { - var compressed_stream = std.io.fixedBufferStream(compressed_bytes); - var decompress_stream = std.compress.zlib.decompressor(compressed_stream.reader()); - - const bytes = try decompress_stream.reader().readAllAlloc(allocator, 16 << 20); - var diagnostic = std.json.Diagnostics{}; - var scanner = std.json.Scanner.initCompleteInput(allocator, bytes); + var scanner = std.json.Scanner.initCompleteInput(allocator, spec_bytes); defer scanner.deinit(); scanner.enableDiagnostics(&diagnostic); @@ -71,7 +66,7 @@ pub fn load(allocator: std.mem.Allocator) !@This() { "could not parse GLSL spec: {}:{}: {s}", .{ diagnostic.getLine(), diagnostic.getColumn(), @errorName(err) }, ); - std.log.err("{?s}", .{util.getJsonErrorContext(diagnostic, bytes)}); + std.log.err("{s}", .{util.getJsonErrorContext(diagnostic, spec_bytes)}); return err; }; } @@ -101,30 +96,34 @@ pub const Modifiers = packed struct(u3) { return modifiers; } - const FormatBuffer = std.BoundedArray(u8, blk: { + const buffer_len = blk: { var max_len: usize = std.meta.fieldNames(@This()).len; for (std.meta.fieldNames(@This())) |name| max_len += name.len; break :blk max_len; - }); + }; + + const FormatBuffer = std.ArrayListUnmanaged(u8); fn toString(self: @This(), buffer: *FormatBuffer) void { inline for (comptime std.meta.fieldNames(@This())) |name| { if (@field(self, name)) { - if (buffer.len != 0) buffer.appendAssumeCapacity(' '); + if (buffer.items.len != 0) buffer.appendAssumeCapacity(' '); buffer.appendSliceAssumeCapacity(name); } } } pub fn jsonStringify(self: @This(), jw: anytype) !void { - var buffer = FormatBuffer{}; - self.toString(&buffer); - try jw.write(buffer.slice()); + var buffer: [buffer_len]u8 = undefined; + var format_buffer = FormatBuffer.initBuffer(&buffer); + self.toString(&format_buffer); + try jw.write(format_buffer.items); } - pub fn format(self: @This(), _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void { - var buffer = FormatBuffer{}; - self.toString(&buffer); - try writer.writeAll(buffer.slice()); + pub fn format(self: @This(), writer: *std.Io.Writer) !void { + var buffer: [buffer_len]u8 = undefined; + var format_buffer = FormatBuffer.initBuffer(&buffer); + self.toString(&format_buffer); + try writer.writeAll(format_buffer.items); } }; diff --git a/src/Workspace.zig b/src/Workspace.zig index 17130ce..43bec67 100644 --- a/src/Workspace.zig +++ b/src/Workspace.zig @@ -117,7 +117,7 @@ pub fn getOrLoadDocument( } fn builtinCompletions(arena: std.mem.Allocator, spec: *const Spec) ![]lsp.CompletionItem { - var completions = std.ArrayList(lsp.CompletionItem).init(arena); + var completions = std.array_list.Managed(lsp.CompletionItem).init(arena); try completions.ensureUnusedCapacity( spec.types.len + spec.variables.len + spec.functions.len, @@ -156,10 +156,10 @@ fn builtinCompletions(arena: std.mem.Allocator, spec: *const Spec) ![]lsp.Comple } for (spec.variables) |variable| { - var anonymous_signature = std.ArrayList(u8).init(arena); + var anonymous_signature = std.array_list.Managed(u8).init(arena); try writeVariableSignature(variable, anonymous_signature.writer(), .{ .names = false }); - var named_signature = std.ArrayList(u8).init(arena); + var named_signature = std.array_list.Managed(u8).init(arena); try writeVariableSignature(variable, named_signature.writer(), .{ .names = true }); try completions.append(.{ @@ -172,10 +172,10 @@ fn builtinCompletions(arena: std.mem.Allocator, spec: *const Spec) ![]lsp.Comple } for (spec.functions) |function| { - var anonymous_signature = std.ArrayList(u8).init(arena); + var anonymous_signature = std.array_list.Managed(u8).init(arena); try writeFunctionSignature(function, anonymous_signature.writer(), .{ .names = false }); - var named_signature = std.ArrayList(u8).init(arena); + var named_signature = std.array_list.Managed(u8).init(arena); try writeFunctionSignature(function, named_signature.writer(), .{ .names = true }); try completions.append(.{ @@ -191,7 +191,7 @@ fn builtinCompletions(arena: std.mem.Allocator, spec: *const Spec) ![]lsp.Comple } fn itemDocumentation(arena: std.mem.Allocator, item: anytype) !lsp.MarkupContent { - var documentation = std.ArrayList(u8).init(arena); + var documentation = std.array_list.Managed(u8).init(arena); for (item.description orelse &.{}) |paragraph| { try documentation.appendSlice(paragraph); @@ -215,7 +215,7 @@ fn writeVariableSignature( options: struct { names: bool }, ) !void { if (!std.meta.eql(variable.modifiers, .{ .in = true })) { - try writer.print("{}", .{variable.modifiers}); + try writer.print("{f}", .{variable.modifiers}); try writer.writeAll(" "); } @@ -247,7 +247,7 @@ fn writeFunctionSignature( if (i != 0) try writer.writeAll(", "); if (param.optional) try writer.writeAll("["); if (param.modifiers) |modifiers| { - try writer.print("{}", .{modifiers}); + try writer.print("{f}", .{modifiers}); try writer.writeAll(" "); } if (options.names) { diff --git a/src/analysis.zig b/src/analysis.zig index 6088190..1ace3df 100644 --- a/src/analysis.zig +++ b/src/analysis.zig @@ -35,7 +35,9 @@ pub const Type = struct { arrays: ?syntax.ListIterator(syntax.Array) = null, parameters: ?syntax.ParameterList = null, - pub fn format(self: @This(), tree: Tree, source: []const u8) std.fmt.Formatter(formatType) { + const FormatContainer = struct { tree: Tree, source: []const u8, type: Type }; + + pub fn format(self: @This(), tree: Tree, source: []const u8) std.fmt.Alt(FormatContainer, @This().formatType) { return .{ .data = .{ .tree = tree, .source = source, .type = self } }; } @@ -44,10 +46,8 @@ pub const Type = struct { } fn formatType( - data: struct { tree: Tree, source: []const u8, type: Type }, - _: anytype, - _: anytype, - writer: anytype, + data: FormatContainer, + writer: *std.Io.Writer, ) !void { const prettify = @import("format.zig").format; @@ -80,7 +80,7 @@ pub const Type = struct { while (iterator.next(data.tree)) |parameter| : (i += 1) { const parameter_type = parameterType(parameter, data.tree); if (i != 0) try writer.writeAll(", "); - try writer.print("{}", .{parameter_type.format(data.tree, data.source)}); + try @This().formatType(.{ .tree = data.tree, .source = data.source, .type = parameter_type }, writer); } try writer.writeAll(")"); } @@ -168,7 +168,7 @@ fn expectTypeFormat(source: []const u8, types: []const []const u8) !void { if (cursors.count() != types.len) return error.InvalidCursorCount; for (types, cursors.values()) |expected, cursor| { - var references = std.ArrayList(Reference).init(allocator); + var references = std.array_list.Managed(Reference).init(allocator); defer references.deinit(); try findDefinition(allocator, document, cursor.node, &references); @@ -177,7 +177,7 @@ fn expectTypeFormat(source: []const u8, types: []const []const u8) !void { const typ = try typeOf(ref) orelse return error.InvalidType; - const found = try std.fmt.allocPrint(allocator, "{}", .{typ.format(tree, document.source())}); + const found = try std.fmt.allocPrint(allocator, "{f}", .{typ.format(tree, document.source())}); defer allocator.free(found); try std.testing.expectEqualStrings(expected, found); @@ -189,14 +189,14 @@ pub fn findDefinition( arena: std.mem.Allocator, document: *Document, node: u32, - references: *std.ArrayList(Reference), + references: *std.array_list.Managed(Reference), ) anyerror!void { const parse_tree = try document.parseTree(); const tree = parse_tree.tree; const name = nodeName(tree, node, document.source()) orelse return; - var symbols = std.ArrayList(Reference).init(arena); + var symbols = std.array_list.Managed(Reference).init(arena); defer symbols.deinit(); try visibleFields(arena, document, node, &symbols); @@ -225,7 +225,7 @@ pub fn visibleFields( arena: std.mem.Allocator, document: *Document, start_node: u32, - symbols: *std.ArrayList(Reference), + symbols: *std.array_list.Managed(Reference), ) !void { const lhs = lhs: { const parsed = try document.parseTree(); @@ -253,10 +253,10 @@ pub fn visibleFields( return; } - var name_definitions = std.ArrayList(Reference).init(arena); + var name_definitions = std.array_list.Managed(Reference).init(arena); try findDefinition(arena, document, lhs, &name_definitions); - var references = std.ArrayList(Reference).init(document.workspace.allocator); + var references = std.array_list.Managed(Reference).init(document.workspace.allocator); defer references.deinit(); for (name_definitions.items) |name_definition| { @@ -369,7 +369,7 @@ pub const Scope = struct { pub fn getVisible( self: *const @This(), - symbols: *std.ArrayList(Reference), + symbols: *std.array_list.Managed(Reference), options: struct { /// An allocator used to detect duplicates. duplicate_allocator: std.mem.Allocator, @@ -420,7 +420,7 @@ pub const Scope = struct { const func = syntax.ExtractorMixin(syntax.FunctionDeclaration).tryExtract(tree, decl_node) orelse return null; const parameters = func.get(.parameters, tree) orelse return null; - var signature = std.ArrayList(u8).init(allocator); + var signature = std.array_list.Managed(u8).init(allocator); errdefer signature.deinit(); try signature.appendSlice("("); @@ -430,7 +430,7 @@ pub const Scope = struct { while (iterator.next(tree)) |parameter| : (i += 1) { if (i != 0) try signature.appendSlice(", "); const typ = parameterType(parameter, tree); - try signature.writer().print("{}", .{typ.format(tree, document.source())}); + try signature.writer().print("{f}", .{typ.format(tree, document.source())}); } try signature.appendSlice(")"); @@ -444,7 +444,7 @@ pub fn visibleSymbols( arena: std.mem.Allocator, start_document: *Document, start_node: u32, - symbols: *std.ArrayList(Reference), + symbols: *std.array_list.Managed(Reference), ) !void { var scope = Scope{ .allocator = arena }; try scope.begin(); @@ -452,7 +452,7 @@ pub fn visibleSymbols( // collect global symbols: { - var documents = try std.ArrayList(*Document).initCapacity(arena, 8); + var documents = try std.array_list.Managed(*Document).initCapacity(arena, 8); defer documents.deinit(); try documents.append(start_document); @@ -667,7 +667,7 @@ fn registerVariables( /// Appends the set of documents which are visible (recursively) from any of the documents in the list. fn findIncludedDocumentsRecursive( arena: std.mem.Allocator, - documents: *std.ArrayList(*Document), + documents: *std.array_list.Managed(*Document), ) !void { var i: usize = 0; while (i < documents.items.len) : (i += 1) { @@ -679,7 +679,7 @@ fn findIncludedDocumentsRecursive( fn findIncludedDocuments( arena: std.mem.Allocator, start: *Document, - documents: *std.ArrayList(*Document), + documents: *std.array_list.Managed(*Document), ) !void { const parsed = try start.parseTree(); @@ -702,8 +702,8 @@ fn findIncludedDocuments( defer arena.free(uri); const included_document = start.workspace.getOrLoadDocument(.{ .uri = uri }) catch |err| { - std.log.err("could not open '{'}': {s}", .{ - std.zig.fmtEscapes(uri), + std.log.err("could not open '{f}': {s}", .{ + std.zig.fmtString(uri), @errorName(err), }); continue; @@ -941,7 +941,7 @@ fn expectDefinition( const usage = cursors.get(case.source) orelse std.debug.panic("invalid cursor: {s}", .{case.source}); const definition = cursors.get(case.target) orelse std.debug.panic("invalid cursor: {s}", .{case.source}); - var references = std.ArrayList(Reference).init(workspace.allocator); + var references = std.array_list.Managed(Reference).init(workspace.allocator); defer references.deinit(); try findDefinition(arena.allocator(), document, usage.node, &references); @@ -991,8 +991,8 @@ fn findCursors(document: *Document) !std.StringArrayHashMap(Cursor) { break; } } else { - std.debug.panic("cursor not found: \"{}\"", .{ - std.zig.fmtEscapes(document.source()[cursor.start..cursor.end]), + std.debug.panic("cursor not found: \"{f}\"", .{ + std.zig.fmtString(document.source()[cursor.start..cursor.end]), }); } } diff --git a/src/cli.zig b/src/cli.zig index e9656f8..9e09c2a 100644 --- a/src/cli.zig +++ b/src/cli.zig @@ -2,6 +2,8 @@ const std = @import("std"); pub const NAME = "glsl_analyzer"; +var stdout_buffer: [1024]u8 = undefined; + pub const Arguments = struct { version: bool = false, channel: ChannelKind = .stdio, @@ -36,17 +38,26 @@ pub const Arguments = struct { ; fn printHelp() noreturn { - std.io.getStdOut().writer().writeAll(usage) catch {}; + var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer); + const stdout = &stdout_writer.interface; + stdout.writeAll(usage) catch {}; + stdout.flush() catch {}; std.process.exit(1); } fn printVersion() noreturn { - std.io.getStdOut().writer().writeAll(@import("build_options").version) catch {}; + var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer); + const stdout = &stdout_writer.interface; + stdout.writeAll(@import("build_options").version) catch {}; + stdout.flush() catch {}; std.process.exit(0); } fn fail(comptime fmt: []const u8, args: anytype) noreturn { - std.io.getStdErr().writer().writeAll(usage) catch {}; + var stderr_writer = std.fs.File.stderr().writer(&stdout_buffer); + const stderr = &stderr_writer.interface; + stderr.writeAll(usage) catch {}; + stderr.flush() catch {}; std.log.err(fmt ++ "\n", args); std.process.exit(1); } diff --git a/src/format.zig b/src/format.zig index 9d30c2c..2db4f1b 100644 --- a/src/format.zig +++ b/src/format.zig @@ -11,7 +11,7 @@ pub const FormatOptions = struct { pub fn format( tree: parse.Tree, source: []const u8, - writer: anytype, + writer: *std.Io.Writer, options: FormatOptions, ) !void { var inner_writer = Writer(@TypeOf(writer)){ @@ -157,7 +157,7 @@ fn Writer(comptime ChildWriter: type) type { } pub fn emitIndent(self: *Self) !void { - try self.child_writer.writeByteNTimes(' ', self.indentation * self.tab_size); + _ = try self.child_writer.splatByteAll(' ', self.indentation * self.tab_size); if (self.indentation > 0) self.preceded_by_space = true; } @@ -679,10 +679,10 @@ fn expectIsFormatted(source: []const u8) !void { } fn expectFormat(source: []const u8, expected: []const u8) !void { - var ignored = std.ArrayList(parse.Token).init(std.testing.allocator); + var ignored = std.array_list.Managed(parse.Token).init(std.testing.allocator); defer ignored.deinit(); - var diagnostics = std.ArrayList(parse.Diagnostic).init(std.testing.allocator); + var diagnostics = std.array_list.Managed(parse.Diagnostic).init(std.testing.allocator); defer diagnostics.deinit(); var tree = try parse.parse(std.testing.allocator, source, .{ @@ -691,13 +691,13 @@ fn expectFormat(source: []const u8, expected: []const u8) !void { }); defer tree.deinit(std.testing.allocator); - var buffer = std.ArrayList(u8).init(std.testing.allocator); + var buffer: std.Io.Writer.Allocating = .init(std.testing.allocator); defer buffer.deinit(); - try format(tree, source, buffer.writer(), .{ .ignored = ignored.items }); + try format(tree, source, &buffer.writer, .{ .ignored = ignored.items }); - std.testing.expectEqualStrings(expected, buffer.items) catch |err| { - std.debug.print("\n========= parse tree ==========\n{}", .{tree.format(source)}); + std.testing.expectEqualStrings(expected, buffer.written()) catch |err| { + std.debug.print("\n========= parse tree ==========\n{f}", .{tree.format(source)}); if (diagnostics.items.len > 0) { std.debug.print("\n========= diagnostics ==========\n", .{}); diff --git a/src/lsp.zig b/src/lsp.zig index dff43cc..0cefb0a 100644 --- a/src/lsp.zig +++ b/src/lsp.zig @@ -70,7 +70,7 @@ pub const Range = struct { start: Position, end: Position, - pub fn format(self: @This(), comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void { + pub fn format(self: @This(), writer: *std.Io.Writer) !void { try writer.print("{}..{}", .{ self.start, self.end }); } }; @@ -79,7 +79,7 @@ pub const Position = struct { line: u32, character: u32, - pub fn format(self: @This(), comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void { + pub fn format(self: @This(), writer: *std.Io.Writer) !void { try writer.print("{}:{}", .{ self.line, self.character }); } }; diff --git a/src/main.zig b/src/main.zig index 55072b0..147456b 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1,6 +1,7 @@ const std = @import("std"); const builtin = @import("builtin"); const build_options = @import("build_options"); +const File = std.fs.File; const util = @import("util.zig"); const lsp = @import("lsp.zig"); @@ -17,6 +18,8 @@ pub const std_options: std.Options = .{ .log_level = .debug, }; +var stdout_buffer: [1024]u8 = undefined; + fn enableDevelopmentMode(stderr_target: []const u8) !void { if (builtin.os.tag == .linux) { // redirect stderr to the build root @@ -61,10 +64,10 @@ pub fn main() !u8 { }; defer allocator.free(source); - var ignored = std.ArrayList(parse.Token).init(allocator); + var ignored = std.array_list.Managed(parse.Token).init(allocator); defer ignored.deinit(); - var diagnostics = std.ArrayList(parse.Diagnostic).init(allocator); + var diagnostics = std.array_list.Managed(parse.Diagnostic).init(allocator); defer diagnostics.deinit(); var tree = try parse.parse(allocator, source, .{ @@ -76,7 +79,9 @@ pub fn main() !u8 { if (diagnostics.items.len != 0) { for (diagnostics.items) |diagnostic| { const position = diagnostic.position(source); - try std.io.getStdErr().writer().print( + var stderr_writer = std.fs.File.stderr().writer(&stdout_buffer); + const stderr = &stderr_writer.interface; + try stderr.print( "{s}:{}:{}: {s}\n", .{ path, position.line + 1, position.character + 1, diagnostic.message }, ); @@ -84,11 +89,13 @@ pub fn main() !u8 { return 1; } - var buffered_stdout = std.io.bufferedWriter(std.io.getStdOut().writer()); - try @import("format.zig").format(tree, source, buffered_stdout.writer(), .{ + var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer); + const stdout = &stdout_writer.interface; + + try @import("format.zig").format(tree, source, stdout, .{ .ignored = ignored.items, }); - try buffered_stdout.flush(); + try stdout.flush(); return 0; } @@ -100,25 +107,30 @@ pub fn main() !u8 { }; defer allocator.free(source); - var diagnostics = std.ArrayList(parse.Diagnostic).init(allocator); + var diagnostics = std.array_list.Managed(parse.Diagnostic).init(allocator); defer diagnostics.deinit(); var tree = try parse.parse(allocator, source, .{ .diagnostics = &diagnostics }); defer tree.deinit(allocator); if (args.print_ast) { - var buffered_stdout = std.io.bufferedWriter(std.io.getStdOut().writer()); - try buffered_stdout.writer().print("{}", .{tree.format(source)}); - try buffered_stdout.flush(); + var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer); + const stdout = &stdout_writer.interface; + + try stdout.print("{f}", .{tree.format(source)}); + try stdout.flush(); } if (diagnostics.items.len != 0) { for (diagnostics.items) |diagnostic| { const position = diagnostic.position(source); - try std.io.getStdErr().writer().print( + var stderr_writer = std.fs.File.stderr().writer(&stdout_buffer); + const stderr = &stderr_writer.interface; + try stderr.print( "{s}:{}:{}: {s}\n", .{ path, position.line + 1, position.character + 1, diagnostic.message }, ); + try stderr.flush(); } return 1; } @@ -128,8 +140,8 @@ pub fn main() !u8 { var channel: Channel = switch (args.channel) { .stdio => .{ .stdio = .{ - .stdout = std.io.getStdOut(), - .stdin = std.io.getStdIn(), + .stdout = std.fs.File.stdout(), + .stdin = std.fs.File.stdin(), } }, .socket => |port| blk: { if (builtin.os.tag == .wasi) { @@ -142,27 +154,28 @@ pub fn main() !u8 { defer server.deinit(); const connection = try server.accept(); - std.log.info("incoming connection from {}", .{connection.address}); + std.log.info("incoming connection from {f}", .{connection.address}); break :blk .{ .socket = connection.stream }; }, }; defer channel.close(); - var buffered_writer = std.io.bufferedWriter(channel.writer()); + var channel_buffer: [1024]u8 = undefined; + var channel_writer = channel.writer(&channel_buffer); var state = State{ .allocator = allocator, - .channel = &buffered_writer, + .channel = channel_writer.interface(), .workspace = try Workspace.init(allocator), }; defer state.deinit(); - var buffered_reader = std.io.bufferedReader(channel.reader()); - const reader = buffered_reader.reader(); + var reader_buffer: [1024]u8 = undefined; + var reader = channel.reader(&reader_buffer); var header_buffer: [1024]u8 = undefined; - var header_stream = std.io.fixedBufferStream(&header_buffer); + var header_stream = std.Io.Writer.fixed(&header_buffer); - var content_buffer = std.ArrayList(u8).init(allocator); + var content_buffer = std.array_list.Managed(u8).init(allocator); defer content_buffer.deinit(); var parse_arena = std.heap.ArenaAllocator.init(allocator); @@ -175,22 +188,24 @@ pub fn main() !u8 { // read headers const headers = blk: { - header_stream.reset(); - while (!std.mem.endsWith(u8, header_buffer[0..header_stream.pos], "\r\n\r\n")) { - reader.streamUntilDelimiter(header_stream.writer(), '\n', null) catch |err| { + header_stream.end = 0; + while (!std.mem.endsWith(u8, header_buffer[0..header_stream.end], "\r\n\r\n")) { + _ = reader.interface().streamDelimiter(&header_stream, '\n') catch |err| { if (err == error.EndOfStream) break :outer; return err; }; + + reader.interface().toss(1); _ = try header_stream.write("\n"); } - break :blk try parseHeaders(header_buffer[0..header_stream.pos]); + break :blk try parseHeaders(header_buffer[0..header_stream.end]); }; // read content const contents = blk: { if (headers.content_length > max_content_length) return error.MessageTooLong; try content_buffer.resize(headers.content_length); - const actual_length = try reader.readAll(content_buffer.items); + const actual_length = try reader.interface().readSliceShort(content_buffer.items); if (actual_length < headers.content_length) return error.UnexpectedEof; break :blk content_buffer.items; }; @@ -225,11 +240,11 @@ pub fn main() !u8 { } fn logJsonError(err: []const u8, diagnostics: std.json.Diagnostics, bytes: []const u8) void { - std.log.err("{}:{}: {s}: '{'}'", .{ + std.log.err("{}:{}: {s}: '{f}'", .{ diagnostics.getLine(), diagnostics.getColumn(), err, - std.zig.fmtEscapes(util.getJsonErrorContext(diagnostics, bytes)), + std.zig.fmtString(util.getJsonErrorContext(diagnostics, bytes)), }); } @@ -279,39 +294,75 @@ pub const Channel = union(enum) { } } - pub const Reader = std.io.Reader(*Channel, ReadError, read); - pub const ReadError = std.fs.File.ReadError || std.net.Stream.ReadError; + pub const ReadError = std.fs.File.ReadError || std.net.Stream.ReadError || std.io.Reader.Error; + pub const Reader = struct { + channel: *Channel, - pub fn read(self: *Channel, buffer: []u8) ReadError!usize { - switch (self.*) { - .stdio => |stdio| return stdio.stdin.read(buffer), - .socket => |stream| return stream.read(buffer), + stdin_reader: std.fs.File.Reader = undefined, + socket_reader: std.net.Stream.Reader = undefined, + + pub fn init(channel: *Channel, buffer: []u8) Reader { + var r: Reader = .{ + .channel = channel, + }; + + switch (r.channel.*) { + .stdio => |stdio| r.stdin_reader = stdio.stdin.reader(buffer), + .socket => |stream| r.socket_reader = stream.reader(buffer), + } + + return r; } - } - pub fn reader(self: *Channel) Reader { - return .{ .context = self }; + pub fn interface(r: *Reader) *std.io.Reader { + return switch (r.channel.*) { + .stdio => &r.stdin_reader.interface, + .socket => r.socket_reader.interface(), + }; + } + }; + + pub fn reader(self: *Channel, buffer: []u8) Reader { + return .init(self, buffer); } - pub const Writer = std.io.Writer(*Channel, WriteError, write); - pub const WriteError = std.fs.File.WriteError || std.net.Stream.WriteError; + pub const WriteError = std.fs.File.WriteError || std.net.Stream.WriteError || std.io.Writer.Error; + pub const Writer = struct { + channel: *Channel, - pub fn write(self: *Channel, bytes: []const u8) WriteError!usize { - switch (self.*) { - .stdio => |stdio| return stdio.stdout.write(bytes), - .socket => |stream| return stream.write(bytes), + stdout_writer: std.fs.File.Writer = undefined, + socket_writer: std.net.Stream.Writer = undefined, + + pub fn init(channel: *Channel, buffer: []u8) Writer { + var w: Writer = .{ + .channel = channel, + }; + + switch (w.channel.*) { + .stdio => |stdio| w.stdout_writer = stdio.stdout.writer(buffer), + .socket => |stream| w.socket_writer = stream.writer(buffer), + } + + return w; } - } - pub fn writer(self: *Channel) Writer { - return .{ .context = self }; + pub fn interface(w: *Writer) *std.Io.Writer { + return switch (w.channel.*) { + .stdio => &w.stdout_writer.interface, + .socket => &w.socket_writer.interface, + }; + } + }; + + pub fn writer(self: *Channel, buffer: []u8) Writer { + return .init(self, buffer); } }; const State = struct { allocator: std.mem.Allocator, - channel: *std.io.BufferedWriter(4096, Channel.Writer), + channel: *std.io.Writer, running: bool = true, initialized: bool = false, parent_pid: ?c_int = null, @@ -339,7 +390,7 @@ const State = struct { .message = "invalid jsonrpc version", }); - std.log.debug("method: '{'}'", .{std.zig.fmtEscapes(request.method)}); + std.log.debug("method: '{f}'", .{std.zig.fmtString(request.method)}); if (!self.initialized and !std.mem.eql(u8, request.method, "initialize")) return self.fail(request.id, .{ @@ -356,7 +407,7 @@ const State = struct { // ignore unknown notifications if (request.id == .null) { - std.log.debug("ignoring unknown '{'}' notification", .{std.zig.fmtEscapes(request.method)}); + std.log.debug("ignoring unknown '{f}' notification", .{std.zig.fmtString(request.method)}); return; } @@ -369,19 +420,18 @@ const State = struct { const SendError = Channel.WriteError; fn sendResponse(self: *State, response: *const Response) SendError!void { - const format_options = std.json.StringifyOptions{ + const format_options = std.json.Stringify.Options{ .emit_null_optional_fields = false, }; // get the size of the encoded message - var counting = std.io.countingWriter(std.io.null_writer); - try std.json.stringify(response, format_options, counting.writer()); - const content_length = counting.bytes_written; + var counting: std.Io.Writer.Discarding = .init(&.{}); + try std.json.Stringify.value(response, format_options, &counting.writer); + const content_length = counting.count; // send the message to the client - const writer = self.channel.writer(); - try writer.print("Content-Length: {}\r\n\r\n", .{content_length}); - try std.json.stringify(response, format_options, writer); + try self.channel.print("Content-Length: {}\r\n\r\n", .{content_length}); + try std.json.Stringify.value(response, format_options, self.channel); try self.channel.flush(); } @@ -395,7 +445,7 @@ const State = struct { } pub fn success(self: *State, id: Request.Id, data: anytype) !void { - const bytes = try std.json.stringifyAlloc(self.allocator, data, .{}); + const bytes = try std.json.Stringify.valueAlloc(self.allocator, data, .{}); defer self.allocator.free(bytes); try self.sendResponse(&Response{ .id = id, .result = .{ .success = .{ .raw = bytes } } }); } @@ -582,11 +632,11 @@ pub const Dispatch = struct { const params = try parseParams(CompletionParams, state, request); defer params.deinit(); - std.log.debug("complete: {} {s}", .{ params.value.position, params.value.textDocument.uri }); + std.log.debug("complete: {f} {s}", .{ params.value.position, params.value.textDocument.uri }); const document = try getDocumentOrFail(state, request, params.value.textDocument); - var completions = std.ArrayList(lsp.CompletionItem).init(state.allocator); + var completions = std.array_list.Managed(lsp.CompletionItem).init(state.allocator); defer completions.deinit(); var symbol_arena = std.heap.ArenaAllocator.init(state.allocator); @@ -616,13 +666,13 @@ pub const Dispatch = struct { state: *State, document: *Workspace.Document, start_token: ?u32, - completions: *std.ArrayList(lsp.CompletionItem), + completions: *std.array_list.Managed(lsp.CompletionItem), arena: std.mem.Allocator, options: struct { ignore_current: bool }, ) !void { var has_fields = false; - var symbols = std.ArrayList(analysis.Reference).init(arena); + var symbols = std.array_list.Managed(analysis.Reference).init(arena); if (start_token) |token| { try analysis.visibleFields(arena, document, token, &symbols); @@ -642,7 +692,7 @@ pub const Dispatch = struct { const symbol_type = try analysis.typeOf(symbol); const type_signature = if (symbol_type) |typ| - try std.fmt.allocPrint(arena, "{}", .{ + try std.fmt.allocPrint(arena, "{f}", .{ typ.format(parsed.tree, symbol.document.source()), }) else if (parsed.tree.tag(symbol.node) == .preprocessor) blk: { @@ -687,7 +737,7 @@ pub const Dispatch = struct { const params = try parseParams(HoverParams, state, request); defer params.deinit(); - std.log.debug("hover: {} {s}", .{ params.value.position, params.value.textDocument.uri }); + std.log.debug("hover: {f} {s}", .{ params.value.position, params.value.textDocument.uri }); const document = try getDocumentOrFail(state, request, params.value.textDocument); const parsed = try document.parseTree(); @@ -703,7 +753,7 @@ pub const Dispatch = struct { const token_span = parsed.tree.token(token); const token_text = document.source()[token_span.start..token_span.end]; - var completions = std.ArrayList(lsp.CompletionItem).init(state.allocator); + var completions = std.array_list.Managed(lsp.CompletionItem).init(state.allocator); defer completions.deinit(); var symbol_arena = std.heap.ArenaAllocator.init(state.allocator); @@ -733,7 +783,7 @@ pub const Dispatch = struct { try result.value_ptr.append(symbol_arena.allocator(), completion); } - var text = std.ArrayList(u8).init(symbol_arena.allocator()); + var text = std.array_list.Managed(u8).init(symbol_arena.allocator()); defer text.deinit(); for (groups.keys(), groups.values()) |description, group| { @@ -780,19 +830,19 @@ pub const Dispatch = struct { pub fn @"textDocument/formatting"(state: *State, request: *Request) !void { const params = try parseParams(FormattingParams, state, request); defer params.deinit(); - std.log.debug("format: {s} tabSize: {}", .{params.value.textDocument.uri, params.value.options.tabSize}); + std.log.debug("format: {s} tabSize: {}", .{ params.value.textDocument.uri, params.value.options.tabSize }); const document = try state.workspace.getOrLoadDocument(params.value.textDocument); const parsed = try document.parseTree(); - var buffer = std.ArrayList(u8).init(state.allocator); + var buffer: std.Io.Writer.Allocating = .init(state.allocator); defer buffer.deinit(); try @import("format.zig").format( parsed.tree, document.contents.items, - buffer.writer(), - .{ + &buffer.writer, + .{ .ignored = parsed.ignored, .tab_size = params.value.options.tabSize, }, @@ -801,7 +851,7 @@ pub const Dispatch = struct { try state.success(request.id, .{ .{ .range = document.wholeRange(), - .newText = buffer.items, + .newText = buffer.written(), }, }); } @@ -814,7 +864,7 @@ pub const Dispatch = struct { pub fn @"textDocument/definition"(state: *State, request: *Request) !void { const params = try parseParams(DefinitionParams, state, request); defer params.deinit(); - std.log.debug("goto definition: {} {s}", .{ + std.log.debug("goto definition: {f} {s}", .{ params.value.position, params.value.textDocument.uri, }); @@ -825,7 +875,7 @@ pub const Dispatch = struct { return state.success(request.id, null); }; - var references = std.ArrayList(analysis.Reference).init(state.allocator); + var references = std.array_list.Managed(analysis.Reference).init(state.allocator); defer references.deinit(); var arena = std.heap.ArenaAllocator.init(state.allocator); diff --git a/src/parse.zig b/src/parse.zig index 9ef3743..70c13d4 100644 --- a/src/parse.zig +++ b/src/parse.zig @@ -4,8 +4,8 @@ const util = @import("util.zig"); pub const ParseOptions = struct { /// Append any ignored tokens (comments or preprocessor directives) to this list. - ignored: ?*std.ArrayList(Span) = null, - diagnostics: ?*std.ArrayList(Diagnostic) = null, + ignored: ?*std.array_list.Managed(Span) = null, + diagnostics: ?*std.array_list.Managed(Diagnostic) = null, }; pub fn parse( @@ -290,7 +290,7 @@ pub const Tree = struct { } } - pub fn format(tree: @This(), source: []const u8) std.fmt.Formatter(formatWithSource) { + pub fn format(tree: @This(), source: []const u8) std.fmt.Alt(WithSource, @This().formatWithSource) { return .{ .data = .{ .tree = tree, .source = source, @@ -304,17 +304,9 @@ pub const Tree = struct { fn formatWithSource( data: WithSource, - comptime fmt: []const u8, - _: anytype, - writer: anytype, + writer: *std.Io.Writer, ) !void { - comptime var with_spans = false; - - if (comptime std.mem.eql(u8, fmt, "..")) { - with_spans = true; - } else if (fmt.len != 0) { - @compileError("expected `{}` or `{..}`"); - } + const with_spans = false; const Formatter = struct { tree: Tree, @@ -328,13 +320,13 @@ pub const Tree = struct { const node = self.tree.nodes.get(index); const name = @tagName(node.tag); - try self.writer.writeByteNTimes(' ', indent); + _ = try self.writer.splatByteAll(' ', indent); if (node.getToken()) |tok| { const text = self.source[tok.start..tok.end]; if (std.ascii.isAlphabetic(name[0])) { try self.writer.writeAll(name); - try self.writer.print(" '{'}'", .{std.zig.fmtEscapes(text)}); + try self.writer.print(" '{f}'", .{std.zig.fmtString(text)}); } else { try self.writer.writeAll(name); } @@ -1580,7 +1572,10 @@ pub const Tokenizer = struct { const tags = std.meta.tags(Tag); - var table = std.BoundedArray(struct { []const u8, Tag }, tags.len){}; + const TagMap = struct { []const u8, Tag }; + + var buffer: [tags.len]TagMap = undefined; + var table = std.ArrayListUnmanaged(TagMap).initBuffer(&buffer); for (tags) |tag| { if (stripPrefix(@tagName(tag), "keyword_")) |name| { @@ -1588,7 +1583,7 @@ pub const Tokenizer = struct { } } - break :blk std.StaticStringMap(Tag).initComptime(table.slice()); + break :blk std.StaticStringMap(Tag).initComptime(table.items); }; return map.get(identifier) orelse .identifier; @@ -1793,10 +1788,10 @@ test "parse and write" { var tree = try parse(std.testing.allocator, source, .{}); defer tree.deinit(std.testing.allocator); - var buffer = std.ArrayList(u8).init(std.testing.allocator); + var buffer = std.array_list.Managed(u8).init(std.testing.allocator); defer buffer.deinit(); - try buffer.writer().print("{}", .{tree.format(source)}); + try buffer.writer().print("{f}", .{tree.format(source)}); try std.testing.expectEqualStrings( \\file @@ -1827,10 +1822,10 @@ test "parse infix op" { var tree = try parse(std.testing.allocator, source, .{}); defer tree.deinit(std.testing.allocator); - var buffer = std.ArrayList(u8).init(std.testing.allocator); + var buffer = std.array_list.Managed(u8).init(std.testing.allocator); defer buffer.deinit(); - try buffer.writer().print("{}", .{tree.format(source)}); + try buffer.writer().print("{f}", .{tree.format(source)}); try std.testing.expectEqualStrings( \\file @@ -1856,10 +1851,10 @@ test "parse logical operator" { var tree = try parse(std.testing.allocator, source, .{}); defer tree.deinit(std.testing.allocator); - var buffer = std.ArrayList(u8).init(std.testing.allocator); + var buffer = std.array_list.Managed(u8).init(std.testing.allocator); defer buffer.deinit(); - try buffer.writer().print("{}", .{tree.format(source)}); + try buffer.writer().print("{f}", .{tree.format(source)}); try std.testing.expectEqualStrings( \\file @@ -1917,14 +1912,14 @@ test "parse field selector" { } fn expectParsesOkay(source: []const u8) !void { - var diagnostics = std.ArrayList(Diagnostic).init(std.testing.allocator); + var diagnostics = std.array_list.Managed(Diagnostic).init(std.testing.allocator); defer diagnostics.deinit(); var tree = try parse(std.testing.allocator, source, .{ .diagnostics = &diagnostics }); defer tree.deinit(std.testing.allocator); errdefer std.debug.print("======== source ========\n{s}\n========================\n", .{source}); - errdefer std.log.err("tree:\n{}", .{tree.format(source)}); + errdefer std.log.err("tree:\n{f}", .{tree.format(source)}); if (diagnostics.items.len != 0) { for (diagnostics.items) |diagnostic| { diff --git a/src/syntax.zig b/src/syntax.zig index 5276afe..55e398b 100644 --- a/src/syntax.zig +++ b/src/syntax.zig @@ -271,11 +271,11 @@ pub fn Extractor(comptime expected_tag: Tag, comptime T: type) type { return tree.children(self.node).start + node_offset; } - pub fn get(self: @This(), comptime field: FieldEnum, tree: Tree) ?std.meta.FieldType(T, field) { + pub fn get(self: @This(), comptime field: FieldEnum, tree: Tree) ?@FieldType(T, @tagName(field)) { const field_match = @field(self.matches, @tagName(field)); const node_offset = field_match.node_offset orelse return null; const node = tree.children(self.node).start + node_offset; - return MixinType(std.meta.FieldType(T, field)).extract(tree, node, field_match.result); + return MixinType(@FieldType(T, @tagName(field))).extract(tree, node, field_match.result); } }; } @@ -383,10 +383,11 @@ pub fn UnionExtractorMixin(comptime Self: type) type { var match_fields: [fields.len]std.builtin.Type.UnionField = undefined; for (&match_fields, fields) |*match_field, field| { + const Result = MatchResult(field.type); match_field.* = .{ .name = field.name, - .type = MatchResult(field.type), - .alignment = 0, + .type = Result, + .alignment = @alignOf(Result), }; } diff --git a/src/util.zig b/src/util.zig index acc0a1a..b4e7c1b 100644 --- a/src/util.zig +++ b/src/util.zig @@ -27,7 +27,7 @@ pub fn getJsonErrorContext(diagnostics: std.json.Diagnostics, bytes: []const u8) } pub fn normalizePath(allocator: std.mem.Allocator, path: []const u8) ![]u8 { - var buffer = try std.ArrayList(u8).initCapacity(allocator, path.len); + var buffer = try std.array_list.Managed(u8).initCapacity(allocator, path.len); errdefer buffer.deinit(); var components = try std.fs.path.componentIterator(path);