diff options
| author | Isaac Freund <ifreund@ifreund.xyz> | 2021-02-16 22:06:35 +0100 |
|---|---|---|
| committer | Isaac Freund <ifreund@ifreund.xyz> | 2021-02-16 23:20:46 +0100 |
| commit | 070e548acf8b5cb22459b779ce771b42157f49f7 (patch) | |
| tree | 2f5fbceac083172b52835db49429567278ca061b /lib/std | |
| parent | 4006a3afb31f89be28721bdcd50fa64de63d6cbb (diff) | |
| download | zig-070e548acf8b5cb22459b779ce771b42157f49f7.tar.gz zig-070e548acf8b5cb22459b779ce771b42157f49f7.zip | |
std: remove io.AutoIndentingStream
This type is not widely applicable enough to be a public part of the
public interface of the std.
The current implementation in only fully utilized by the zig fmt
implementation, which could benefit by even tighter integration as
will be demonstrated in the next commit. Therefore, move the current
io.AutoIndentingStream to lib/std/zig/render.zig.
The C backend of the self hosted compiler also use this type currently,
but it does not require anywhere near its full complexity. Therefore,
implement a greatly simplified version of this interface in
src/codegen/c.zig.
Diffstat (limited to 'lib/std')
| -rw-r--r-- | lib/std/io.zig | 3 | ||||
| -rw-r--r-- | lib/std/io/auto_indenting_stream.zig | 154 | ||||
| -rw-r--r-- | lib/std/zig/render.zig | 142 |
3 files changed, 139 insertions, 160 deletions
diff --git a/lib/std/io.zig b/lib/std/io.zig index 240faaa452..b529c57866 100644 --- a/lib/std/io.zig +++ b/lib/std/io.zig @@ -142,9 +142,6 @@ pub const bitReader = @import("io/bit_reader.zig").bitReader; pub const BitWriter = @import("io/bit_writer.zig").BitWriter; pub const bitWriter = @import("io/bit_writer.zig").bitWriter; -pub const AutoIndentingStream = @import("io/auto_indenting_stream.zig").AutoIndentingStream; -pub const autoIndentingStream = @import("io/auto_indenting_stream.zig").autoIndentingStream; - pub const ChangeDetectionStream = @import("io/change_detection_stream.zig").ChangeDetectionStream; pub const changeDetectionStream = @import("io/change_detection_stream.zig").changeDetectionStream; diff --git a/lib/std/io/auto_indenting_stream.zig b/lib/std/io/auto_indenting_stream.zig deleted file mode 100644 index 8f8b981b9b..0000000000 --- a/lib/std/io/auto_indenting_stream.zig +++ /dev/null @@ -1,154 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2015-2021 Zig Contributors -// This file is part of [zig](https://ziglang.org/), which is MIT licensed. -// The MIT license requires this copyright notice to be included in all copies -// and substantial portions of the software. - -const std = @import("../std.zig"); -const io = std.io; -const mem = std.mem; -const assert = std.debug.assert; - -/// Automatically inserts indentation of written data by keeping -/// track of the current indentation level -pub fn AutoIndentingStream(comptime UnderlyingWriter: type) type { - return struct { - const Self = @This(); - pub const Error = UnderlyingWriter.Error; - pub const Writer = io.Writer(*Self, Error, write); - - underlying_writer: UnderlyingWriter, - - indent_count: usize = 0, - indent_delta: usize, - current_line_empty: bool = true, - indent_one_shot_count: usize = 0, // automatically popped when applied - applied_indent: usize = 0, // the most recently applied indent - indent_next_line: usize = 0, // not used until the next line - - pub fn writer(self: *Self) Writer { - return .{ .context = self }; - } - - pub fn write(self: *Self, bytes: []const u8) Error!usize { - if (bytes.len == 0) - return @as(usize, 0); - - try self.applyIndent(); - return self.writeNoIndent(bytes); - } - - // Change the indent delta without changing the final indentation level - pub fn setIndentDelta(self: *Self, indent_delta: usize) void { - if (self.indent_delta == indent_delta) { - return; - } else if (self.indent_delta > indent_delta) { - assert(self.indent_delta % indent_delta == 0); - self.indent_count = self.indent_count * (self.indent_delta / indent_delta); - } else { - // assert that the current indentation (in spaces) in a multiple of the new delta - assert((self.indent_count * self.indent_delta) % indent_delta == 0); - self.indent_count = self.indent_count / (indent_delta / self.indent_delta); - } - self.indent_delta = indent_delta; - } - - fn writeNoIndent(self: *Self, bytes: []const u8) Error!usize { - if (bytes.len == 0) - return @as(usize, 0); - - try self.underlying_writer.writeAll(bytes); - if (bytes[bytes.len - 1] == '\n') - self.resetLine(); - return bytes.len; - } - - pub fn insertNewline(self: *Self) Error!void { - _ = try self.writeNoIndent("\n"); - } - - fn resetLine(self: *Self) void { - self.current_line_empty = true; - self.indent_next_line = 0; - } - - /// Insert a newline unless the current line is blank - pub fn maybeInsertNewline(self: *Self) Error!void { - if (!self.current_line_empty) - try self.insertNewline(); - } - - /// Push default indentation - pub fn pushIndent(self: *Self) void { - // Doesn't actually write any indentation. - // Just primes the stream to be able to write the correct indentation if it needs to. - self.indent_count += 1; - } - - /// Push an indent that is automatically popped after being applied - pub fn pushIndentOneShot(self: *Self) void { - self.indent_one_shot_count += 1; - self.pushIndent(); - } - - /// Turns all one-shot indents into regular indents - /// Returns number of indents that must now be manually popped - pub fn lockOneShotIndent(self: *Self) usize { - var locked_count = self.indent_one_shot_count; - self.indent_one_shot_count = 0; - return locked_count; - } - - /// Push an indent that should not take effect until the next line - pub fn pushIndentNextLine(self: *Self) void { - self.indent_next_line += 1; - self.pushIndent(); - } - - pub fn popIndent(self: *Self) void { - assert(self.indent_count != 0); - self.indent_count -= 1; - - if (self.indent_next_line > 0) - self.indent_next_line -= 1; - } - - /// Writes ' ' bytes if the current line is empty - fn applyIndent(self: *Self) Error!void { - const current_indent = self.currentIndent(); - if (self.current_line_empty and current_indent > 0) { - try self.underlying_writer.writeByteNTimes(' ', current_indent); - self.applied_indent = current_indent; - } - - self.indent_count -= self.indent_one_shot_count; - self.indent_one_shot_count = 0; - self.current_line_empty = false; - } - - /// Checks to see if the most recent indentation exceeds the currently pushed indents - pub fn isLineOverIndented(self: *Self) bool { - if (self.current_line_empty) return false; - return self.applied_indent > self.currentIndent(); - } - - fn currentIndent(self: *Self) usize { - var indent_current: usize = 0; - if (self.indent_count > 0) { - const indent_count = self.indent_count - self.indent_next_line; - indent_current = indent_count * self.indent_delta; - } - return indent_current; - } - }; -} - -pub fn autoIndentingStream( - indent_delta: usize, - underlying_writer: anytype, -) AutoIndentingStream(@TypeOf(underlying_writer)) { - return AutoIndentingStream(@TypeOf(underlying_writer)){ - .underlying_writer = underlying_writer, - .indent_delta = indent_delta, - }; -} diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig index 2d9c2ae9a9..e668c4d64d 100644 --- a/lib/std/zig/render.zig +++ b/lib/std/zig/render.zig @@ -15,12 +15,14 @@ const asm_indent_delta = 2; pub const Error = ast.Tree.RenderError; -const Writer = std.ArrayList(u8).Writer; -const Ais = std.io.AutoIndentingStream(Writer); +const Ais = AutoIndentingStream(std.ArrayList(u8).Writer); pub fn renderTree(buffer: *std.ArrayList(u8), tree: ast.Tree) Error!void { assert(tree.errors.len == 0); // Cannot render an invalid tree. - var auto_indenting_stream = std.io.autoIndentingStream(indent_delta, buffer.writer()); + var auto_indenting_stream = Ais{ + .indent_delta = indent_delta, + .underlying_writer = buffer.writer(), + }; const ais = &auto_indenting_stream; // Render all the line comments at the beginning of the file. @@ -2132,3 +2134,137 @@ fn nodeCausesSliceOpSpace(tag: ast.Node.Tag) bool { else => false, }; } + +/// Automatically inserts indentation of written data by keeping +/// track of the current indentation level +fn AutoIndentingStream(comptime UnderlyingWriter: type) type { + return struct { + const Self = @This(); + pub const Error = UnderlyingWriter.Error; + pub const Writer = std.io.Writer(*Self, Error, write); + + underlying_writer: UnderlyingWriter, + + indent_count: usize = 0, + indent_delta: usize, + current_line_empty: bool = true, + indent_one_shot_count: usize = 0, // automatically popped when applied + applied_indent: usize = 0, // the most recently applied indent + indent_next_line: usize = 0, // not used until the next line + + pub fn writer(self: *Self) Writer { + return .{ .context = self }; + } + + pub fn write(self: *Self, bytes: []const u8) Error!usize { + if (bytes.len == 0) + return @as(usize, 0); + + try self.applyIndent(); + return self.writeNoIndent(bytes); + } + + // Change the indent delta without changing the final indentation level + pub fn setIndentDelta(self: *Self, new_indent_delta: usize) void { + if (self.indent_delta == new_indent_delta) { + return; + } else if (self.indent_delta > new_indent_delta) { + assert(self.indent_delta % new_indent_delta == 0); + self.indent_count = self.indent_count * (self.indent_delta / new_indent_delta); + } else { + // assert that the current indentation (in spaces) in a multiple of the new delta + assert((self.indent_count * self.indent_delta) % new_indent_delta == 0); + self.indent_count = self.indent_count / (new_indent_delta / self.indent_delta); + } + self.indent_delta = new_indent_delta; + } + + fn writeNoIndent(self: *Self, bytes: []const u8) Error!usize { + if (bytes.len == 0) + return @as(usize, 0); + + try self.underlying_writer.writeAll(bytes); + if (bytes[bytes.len - 1] == '\n') + self.resetLine(); + return bytes.len; + } + + pub fn insertNewline(self: *Self) Error!void { + _ = try self.writeNoIndent("\n"); + } + + fn resetLine(self: *Self) void { + self.current_line_empty = true; + self.indent_next_line = 0; + } + + /// Insert a newline unless the current line is blank + pub fn maybeInsertNewline(self: *Self) Error!void { + if (!self.current_line_empty) + try self.insertNewline(); + } + + /// Push default indentation + pub fn pushIndent(self: *Self) void { + // Doesn't actually write any indentation. + // Just primes the stream to be able to write the correct indentation if it needs to. + self.indent_count += 1; + } + + /// Push an indent that is automatically popped after being applied + pub fn pushIndentOneShot(self: *Self) void { + self.indent_one_shot_count += 1; + self.pushIndent(); + } + + /// Turns all one-shot indents into regular indents + /// Returns number of indents that must now be manually popped + pub fn lockOneShotIndent(self: *Self) usize { + var locked_count = self.indent_one_shot_count; + self.indent_one_shot_count = 0; + return locked_count; + } + + /// Push an indent that should not take effect until the next line + pub fn pushIndentNextLine(self: *Self) void { + self.indent_next_line += 1; + self.pushIndent(); + } + + pub fn popIndent(self: *Self) void { + assert(self.indent_count != 0); + self.indent_count -= 1; + + if (self.indent_next_line > 0) + self.indent_next_line -= 1; + } + + /// Writes ' ' bytes if the current line is empty + fn applyIndent(self: *Self) Error!void { + const current_indent = self.currentIndent(); + if (self.current_line_empty and current_indent > 0) { + try self.underlying_writer.writeByteNTimes(' ', current_indent); + self.applied_indent = current_indent; + } + + self.indent_count -= self.indent_one_shot_count; + self.indent_one_shot_count = 0; + self.current_line_empty = false; + } + + /// Checks to see if the most recent indentation exceeds the currently pushed indents + pub fn isLineOverIndented(self: *Self) bool { + if (self.current_line_empty) return false; + return self.applied_indent > self.currentIndent(); + } + + fn currentIndent(self: *Self) usize { + var indent_current: usize = 0; + if (self.indent_count > 0) { + const indent_count = self.indent_count - self.indent_next_line; + indent_current = indent_count * self.indent_delta; + } + return indent_current; + } + }; +} |
