mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 12:59:04 +00:00
Use ArrayList instead of fixed array for auto_indenting_stream
This commit is contained in:
parent
7d950210a6
commit
50c8a53188
@ -1,26 +1,36 @@
|
||||
const std = @import("../std.zig");
|
||||
const io = std.io;
|
||||
const mem = std.mem;
|
||||
const Allocator = mem.Allocator;
|
||||
const ArrayList = std.ArrayList;
|
||||
const assert = std.debug.assert;
|
||||
|
||||
/// Automatically inserts indentation of written data by keeping
|
||||
/// track of the current indentation level
|
||||
pub fn AutoIndentingStream(comptime indent_delta: u8, comptime WriterType: type) type {
|
||||
pub fn AutoIndentingStream(comptime indent_delta: usize, comptime WriterType: type) type {
|
||||
return struct {
|
||||
const Self = @This();
|
||||
pub const Error = WriterType.Error;
|
||||
pub const PushError = Allocator.Error;
|
||||
pub const Writer = io.Writer(*Self, Error, write);
|
||||
const Stack = ArrayList(usize);
|
||||
|
||||
writer_pointer: *WriterType,
|
||||
current_line_empty: bool = true,
|
||||
indent_stack: [255]u8 = undefined,
|
||||
indent_stack_top: u8 = 0,
|
||||
indent_one_shot_count: u8 = 0, // automatically popped when applied
|
||||
applied_indent: u8 = 0, // the most recently applied indent
|
||||
indent_next_line: u8 = 0, // not used until the next line
|
||||
indent_stack: Stack,
|
||||
|
||||
pub fn init(writer_pointer: *WriterType) Self {
|
||||
return Self{ .writer_pointer = writer_pointer };
|
||||
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 init(writer_pointer: *WriterType, allocator: *Allocator) Self {
|
||||
var indent_stack = Stack.init(allocator);
|
||||
return Self{ .writer_pointer = writer_pointer, .indent_stack = indent_stack };
|
||||
}
|
||||
|
||||
/// Release all allocated memory.
|
||||
pub fn deinit(self: Self) void {
|
||||
self.indent_stack.deinit();
|
||||
}
|
||||
|
||||
pub fn writer(self: *Self) Writer {
|
||||
@ -39,7 +49,7 @@ pub fn AutoIndentingStream(comptime indent_delta: u8, comptime WriterType: type)
|
||||
if (bytes.len == 0)
|
||||
return @as(usize, 0);
|
||||
|
||||
try self.writer_pointer.outStream().writeAll(bytes);
|
||||
try self.writer_pointer.writer().writeAll(bytes);
|
||||
if (bytes[bytes.len - 1] == '\n')
|
||||
self.resetLine();
|
||||
return bytes.len;
|
||||
@ -61,53 +71,52 @@ pub fn AutoIndentingStream(comptime indent_delta: u8, comptime WriterType: type)
|
||||
}
|
||||
|
||||
/// 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.pushIndentN(indent_delta);
|
||||
pub fn pushIndent(self: *Self) PushError!void {
|
||||
// Doesn't actually write any indentation.
|
||||
// Just primes the stream to be able to write the correct indentation if it needs to.
|
||||
try self.pushIndentN(indent_delta);
|
||||
}
|
||||
|
||||
/// Push an indent of arbitrary width
|
||||
pub fn pushIndentN(self: *Self, n: u8) void {
|
||||
assert(self.indent_stack_top < std.math.maxInt(u8));
|
||||
self.indent_stack[self.indent_stack_top] = n;
|
||||
self.indent_stack_top += 1;
|
||||
pub fn pushIndentN(self: *Self, n: usize) PushError!void {
|
||||
try self.indent_stack.append(n);
|
||||
}
|
||||
|
||||
/// Push an indent that is automatically popped after being applied
|
||||
pub fn pushIndentOneShot(self: *Self) void {
|
||||
pub fn pushIndentOneShot(self: *Self) PushError!void {
|
||||
self.indent_one_shot_count += 1;
|
||||
self.pushIndent();
|
||||
try 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) u8 {
|
||||
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 {
|
||||
pub fn pushIndentNextLine(self: *Self) PushError!void {
|
||||
self.indent_next_line += 1;
|
||||
self.pushIndent();
|
||||
try self.pushIndent();
|
||||
}
|
||||
|
||||
pub fn popIndent(self: *Self) void {
|
||||
assert(self.indent_stack_top != 0);
|
||||
self.indent_stack_top -= 1;
|
||||
self.indent_next_line = std.math.min(self.indent_stack_top, self.indent_next_line); // Tentative indent may have been popped before there was a newline
|
||||
assert(self.indent_stack.items.len != 0);
|
||||
self.indent_stack.items.len -= 1;
|
||||
self.indent_next_line = std.math.min(self.indent_stack.items.len, self.indent_next_line); // Tentative indent may have been popped before there was a newline
|
||||
}
|
||||
|
||||
/// 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.writer_pointer.outStream().writeByteNTimes(' ', current_indent);
|
||||
try self.writer_pointer.writer().writeByteNTimes(' ', current_indent);
|
||||
self.applied_indent = current_indent;
|
||||
}
|
||||
|
||||
self.indent_stack_top -= self.indent_one_shot_count;
|
||||
self.indent_stack.items.len -= self.indent_one_shot_count;
|
||||
self.indent_one_shot_count = 0;
|
||||
self.current_line_empty = false;
|
||||
}
|
||||
@ -118,11 +127,11 @@ pub fn AutoIndentingStream(comptime indent_delta: u8, comptime WriterType: type)
|
||||
return self.applied_indent > self.currentIndent();
|
||||
}
|
||||
|
||||
fn currentIndent(self: *Self) u8 {
|
||||
var indent_current: u8 = 0;
|
||||
if (self.indent_stack_top > 0) {
|
||||
const stack_top = self.indent_stack_top - self.indent_next_line;
|
||||
for (self.indent_stack[0..stack_top]) |indent| {
|
||||
fn currentIndent(self: *Self) usize {
|
||||
var indent_current: usize = 0;
|
||||
if (self.indent_stack.items.len > 0) {
|
||||
const stack_top = self.indent_stack.items.len - self.indent_next_line;
|
||||
for (self.indent_stack.items[0..stack_top]) |indent| {
|
||||
indent_current += indent;
|
||||
}
|
||||
}
|
||||
@ -132,9 +141,10 @@ pub fn AutoIndentingStream(comptime indent_delta: u8, comptime WriterType: type)
|
||||
}
|
||||
|
||||
pub fn autoIndentingStream(
|
||||
comptime indent_delta: u8,
|
||||
comptime indent_delta: usize,
|
||||
underlying_stream: anytype,
|
||||
allocator: *Allocator,
|
||||
) AutoIndentingStream(indent_delta, @TypeOf(underlying_stream).Child) {
|
||||
comptime assert(@typeInfo(@TypeOf(underlying_stream)) == .Pointer);
|
||||
return AutoIndentingStream(indent_delta, @TypeOf(underlying_stream).Child).init(underlying_stream);
|
||||
return AutoIndentingStream(indent_delta, @TypeOf(underlying_stream).Child).init(underlying_stream, allocator);
|
||||
}
|
||||
|
||||
@ -8,7 +8,7 @@ pub fn FindByteOutStream(comptime WriterType: type) type {
|
||||
return struct {
|
||||
const Self = @This();
|
||||
pub const Error = WriterType.Error;
|
||||
pub const OutStream = io.OutStream(*Self, Error, write);
|
||||
pub const Writer = io.Writer(*Self, Error, write);
|
||||
|
||||
writer_pointer: *WriterType,
|
||||
byte_found: bool,
|
||||
@ -22,7 +22,7 @@ pub fn FindByteOutStream(comptime WriterType: type) type {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn outStream(self: *Self) OutStream {
|
||||
pub fn writer(self: *Self) Writer {
|
||||
return .{ .context = self };
|
||||
}
|
||||
|
||||
|
||||
@ -24,7 +24,8 @@ pub fn render(allocator: *mem.Allocator, stream: anytype, tree: *ast.Tree) (meta
|
||||
|
||||
var s = stream.*;
|
||||
var change_detection_stream = std.io.changeDetectionStream(tree.source, &s);
|
||||
var auto_indenting_stream = std.io.autoIndentingStream(indent_delta, &change_detection_stream);
|
||||
var auto_indenting_stream = std.io.autoIndentingStream(indent_delta, &change_detection_stream, allocator);
|
||||
defer auto_indenting_stream.deinit();
|
||||
|
||||
try renderRoot(allocator, &auto_indenting_stream, tree);
|
||||
|
||||
@ -388,11 +389,11 @@ fn renderExpression(
|
||||
}
|
||||
|
||||
if (block.statements.len == 0) {
|
||||
stream.pushIndentNextLine();
|
||||
try stream.pushIndentNextLine();
|
||||
defer stream.popIndent();
|
||||
try renderToken(tree, stream, block.lbrace, Space.None);
|
||||
} else {
|
||||
stream.pushIndentNextLine();
|
||||
try stream.pushIndentNextLine();
|
||||
defer stream.popIndent();
|
||||
|
||||
try renderToken(tree, stream, block.lbrace, Space.Newline);
|
||||
@ -462,7 +463,7 @@ fn renderExpression(
|
||||
try renderExpression(allocator, stream, tree, payload, Space.Space);
|
||||
}
|
||||
|
||||
stream.pushIndentOneShot();
|
||||
try stream.pushIndentOneShot();
|
||||
return renderExpression(allocator, stream, tree, infix_op_node.rhs, space);
|
||||
},
|
||||
|
||||
@ -523,7 +524,7 @@ fn renderExpression(
|
||||
};
|
||||
|
||||
try renderToken(tree, stream, infix_op_node.op_token, after_op_space);
|
||||
stream.pushIndentOneShot();
|
||||
try stream.pushIndentOneShot();
|
||||
return renderExpression(allocator, stream, tree, infix_op_node.rhs, space);
|
||||
},
|
||||
|
||||
@ -717,7 +718,7 @@ fn renderExpression(
|
||||
}
|
||||
|
||||
{
|
||||
stream.pushIndent();
|
||||
try stream.pushIndent();
|
||||
defer stream.popIndent();
|
||||
try renderToken(tree, stream, lbrace, Space.None);
|
||||
}
|
||||
@ -782,7 +783,8 @@ fn renderExpression(
|
||||
|
||||
// Null stream for counting the printed length of each expression
|
||||
var counting_stream = std.io.countingOutStream(std.io.null_out_stream);
|
||||
var auto_indenting_stream = std.io.autoIndentingStream(indent_delta, &counting_stream);
|
||||
var auto_indenting_stream = std.io.autoIndentingStream(indent_delta, &counting_stream, allocator);
|
||||
defer auto_indenting_stream.deinit();
|
||||
|
||||
for (exprs) |expr, i| {
|
||||
counting_stream.bytes_written = 0;
|
||||
@ -794,7 +796,7 @@ fn renderExpression(
|
||||
}
|
||||
|
||||
{
|
||||
stream.pushIndentNextLine();
|
||||
try stream.pushIndentNextLine();
|
||||
defer stream.popIndent();
|
||||
try renderToken(tree, stream, lbrace, Space.Newline);
|
||||
|
||||
@ -878,7 +880,7 @@ fn renderExpression(
|
||||
}
|
||||
|
||||
{
|
||||
stream.pushIndentNextLine();
|
||||
try stream.pushIndentNextLine();
|
||||
defer stream.popIndent();
|
||||
try renderToken(tree, stream, lbrace, Space.None);
|
||||
}
|
||||
@ -900,7 +902,8 @@ fn renderExpression(
|
||||
// render field expressions until a LF is found
|
||||
for (field_inits) |field_init| {
|
||||
var find_stream = std.io.findByteOutStream('\n', &std.io.null_out_stream);
|
||||
var auto_indenting_stream = std.io.autoIndentingStream(indent_delta, &find_stream);
|
||||
var auto_indenting_stream = std.io.autoIndentingStream(indent_delta, &find_stream, allocator);
|
||||
defer auto_indenting_stream.deinit();
|
||||
|
||||
try renderExpression(allocator, &auto_indenting_stream, tree, field_init, Space.None);
|
||||
if (find_stream.byte_found) break :blk false;
|
||||
@ -960,7 +963,7 @@ fn renderExpression(
|
||||
.node => |node| try renderExpression(allocator, stream, tree, node, Space.None),
|
||||
}
|
||||
|
||||
stream.pushIndentNextLine();
|
||||
try stream.pushIndentNextLine();
|
||||
defer stream.popIndent();
|
||||
|
||||
try renderToken(tree, stream, lbrace, Space.Newline);
|
||||
@ -1008,7 +1011,7 @@ fn renderExpression(
|
||||
|
||||
const params = call.params();
|
||||
for (params) |param_node, i| {
|
||||
stream.pushIndent();
|
||||
try stream.pushIndent();
|
||||
defer stream.popIndent();
|
||||
|
||||
if (i + 1 < params.len) {
|
||||
@ -1028,7 +1031,7 @@ fn renderExpression(
|
||||
|
||||
const params = call.params();
|
||||
for (params) |param_node, i| {
|
||||
if (param_node.*.tag == .MultilineStringLiteral) stream.pushIndentOneShot();
|
||||
if (param_node.*.tag == .MultilineStringLiteral) try stream.pushIndentOneShot();
|
||||
|
||||
try renderExpression(allocator, stream, tree, param_node, Space.None);
|
||||
|
||||
@ -1055,7 +1058,7 @@ fn renderExpression(
|
||||
{
|
||||
const new_space = if (ends_with_comment) Space.Newline else Space.None;
|
||||
|
||||
stream.pushIndent();
|
||||
try stream.pushIndent();
|
||||
defer stream.popIndent();
|
||||
try renderExpression(allocator, stream, tree, suffix_op.index_expr, new_space);
|
||||
}
|
||||
@ -1191,7 +1194,7 @@ fn renderExpression(
|
||||
|
||||
try renderToken(tree, stream, grouped_expr.lparen, Space.None);
|
||||
{
|
||||
stream.pushIndentOneShot();
|
||||
try stream.pushIndentOneShot();
|
||||
try renderExpression(allocator, stream, tree, grouped_expr.expr, Space.None);
|
||||
}
|
||||
return renderToken(tree, stream, grouped_expr.rparen, space);
|
||||
@ -1251,7 +1254,7 @@ fn renderExpression(
|
||||
|
||||
if (container_decl.fields_and_decls_len == 0) {
|
||||
{
|
||||
stream.pushIndentNextLine();
|
||||
try stream.pushIndentNextLine();
|
||||
defer stream.popIndent();
|
||||
try renderToken(tree, stream, container_decl.lbrace_token, Space.None); // {
|
||||
}
|
||||
@ -1286,7 +1289,7 @@ fn renderExpression(
|
||||
|
||||
if (src_has_trailing_comma or !src_has_only_fields) {
|
||||
// One declaration per line
|
||||
stream.pushIndentNextLine();
|
||||
try stream.pushIndentNextLine();
|
||||
defer stream.popIndent();
|
||||
try renderToken(tree, stream, container_decl.lbrace_token, .Newline); // {
|
||||
|
||||
@ -1302,7 +1305,7 @@ fn renderExpression(
|
||||
// their own line
|
||||
try renderToken(tree, stream, container_decl.lbrace_token, .Newline); // {
|
||||
|
||||
stream.pushIndent();
|
||||
try stream.pushIndent();
|
||||
defer stream.popIndent();
|
||||
|
||||
for (fields_and_decls) |decl, i| {
|
||||
@ -1358,7 +1361,7 @@ fn renderExpression(
|
||||
|
||||
if (src_has_trailing_comma) {
|
||||
{
|
||||
stream.pushIndent();
|
||||
try stream.pushIndent();
|
||||
defer stream.popIndent();
|
||||
|
||||
try renderToken(tree, stream, lbrace, Space.Newline); // {
|
||||
@ -1448,7 +1451,7 @@ fn renderExpression(
|
||||
}
|
||||
} else {
|
||||
// one param per line
|
||||
stream.pushIndent();
|
||||
try stream.pushIndent();
|
||||
defer stream.popIndent();
|
||||
try renderToken(tree, stream, lparen, Space.Newline); // (
|
||||
|
||||
@ -1527,7 +1530,7 @@ fn renderExpression(
|
||||
}
|
||||
} else {
|
||||
// one param per line
|
||||
stream.pushIndent();
|
||||
try stream.pushIndent();
|
||||
defer stream.popIndent();
|
||||
try renderToken(tree, stream, lparen, Space.Newline); // (
|
||||
|
||||
@ -1624,7 +1627,7 @@ fn renderExpression(
|
||||
try renderToken(tree, stream, rparen, Space.Space); // )
|
||||
|
||||
{
|
||||
stream.pushIndentNextLine();
|
||||
try stream.pushIndentNextLine();
|
||||
defer stream.popIndent();
|
||||
try renderToken(tree, stream, lbrace, Space.Newline); // {
|
||||
|
||||
@ -1708,7 +1711,7 @@ fn renderExpression(
|
||||
if (same_line) {
|
||||
return renderExpression(allocator, stream, tree, else_node.body, space);
|
||||
} else {
|
||||
stream.pushIndent();
|
||||
try stream.pushIndent();
|
||||
defer stream.popIndent();
|
||||
return renderExpression(allocator, stream, tree, else_node.body, space);
|
||||
}
|
||||
@ -1772,7 +1775,7 @@ fn renderExpression(
|
||||
}
|
||||
|
||||
{
|
||||
if (!body_is_block) stream.pushIndent();
|
||||
if (!body_is_block) try stream.pushIndent();
|
||||
defer if (!body_is_block) stream.popIndent();
|
||||
try renderExpression(allocator, stream, tree, while_node.body, after_body_space);
|
||||
}
|
||||
@ -1823,7 +1826,7 @@ fn renderExpression(
|
||||
};
|
||||
|
||||
{
|
||||
if (!body_on_same_line) stream.pushIndent();
|
||||
if (!body_on_same_line) try stream.pushIndent();
|
||||
defer if (!body_on_same_line) stream.popIndent();
|
||||
try renderExpression(allocator, stream, tree, for_node.body, space_after_body); // { body }
|
||||
}
|
||||
@ -1879,7 +1882,7 @@ fn renderExpression(
|
||||
const else_is_block = nodeIsBlock(@"else".body);
|
||||
|
||||
{
|
||||
stream.pushIndent();
|
||||
try stream.pushIndent();
|
||||
defer stream.popIndent();
|
||||
try renderExpression(allocator, stream, tree, if_node.body, Space.Newline);
|
||||
}
|
||||
@ -1900,12 +1903,12 @@ fn renderExpression(
|
||||
try renderExpression(allocator, stream, tree, payload, Space.Newline);
|
||||
}
|
||||
|
||||
stream.pushIndent();
|
||||
try stream.pushIndent();
|
||||
defer stream.popIndent();
|
||||
return renderExpression(allocator, stream, tree, @"else".body, space);
|
||||
}
|
||||
} else {
|
||||
stream.pushIndent();
|
||||
try stream.pushIndent();
|
||||
defer stream.popIndent();
|
||||
return renderExpression(allocator, stream, tree, if_node.body, space);
|
||||
}
|
||||
@ -1946,7 +1949,7 @@ fn renderExpression(
|
||||
}
|
||||
|
||||
asmblk: {
|
||||
stream.pushIndent();
|
||||
try stream.pushIndent();
|
||||
defer stream.popIndent();
|
||||
|
||||
if (asm_node.outputs.len == 0 and asm_node.inputs.len == 0 and asm_node.clobbers.len == 0) {
|
||||
@ -1965,7 +1968,7 @@ fn renderExpression(
|
||||
} else blk: {
|
||||
try renderToken(tree, stream, colon1, Space.Space); // :
|
||||
|
||||
stream.pushIndentN(2);
|
||||
try stream.pushIndentN(2);
|
||||
defer stream.popIndent();
|
||||
|
||||
for (asm_node.outputs) |*asm_output, i| {
|
||||
@ -1996,7 +1999,7 @@ fn renderExpression(
|
||||
break :blk tree.nextToken(colon2);
|
||||
} else blk: {
|
||||
try renderToken(tree, stream, colon2, Space.Space); // :
|
||||
stream.pushIndentN(2);
|
||||
try stream.pushIndentN(2);
|
||||
defer stream.popIndent();
|
||||
for (asm_node.inputs) |*asm_input, i| {
|
||||
if (i + 1 < asm_node.inputs.len) {
|
||||
@ -2022,7 +2025,7 @@ fn renderExpression(
|
||||
};
|
||||
|
||||
try renderToken(tree, stream, colon3, Space.Space); // :
|
||||
stream.pushIndentN(2);
|
||||
try stream.pushIndentN(2);
|
||||
defer stream.popIndent();
|
||||
for (asm_node.clobbers) |clobber_node, i| {
|
||||
if (i + 1 >= asm_node.clobbers.len) {
|
||||
@ -2075,7 +2078,7 @@ fn renderArrayType(
|
||||
const new_space = if (ends_with_comment) Space.Newline else Space.None;
|
||||
{
|
||||
const do_indent = (starts_with_comment or ends_with_comment);
|
||||
if (do_indent) stream.pushIndent();
|
||||
if (do_indent) try stream.pushIndent();
|
||||
defer if (do_indent) stream.popIndent();
|
||||
|
||||
try renderToken(tree, stream, lbracket, Space.None); // [
|
||||
@ -2209,7 +2212,7 @@ fn renderVarDecl(
|
||||
if (var_decl.getTrailer("init_node")) |init_node| {
|
||||
const s = if (init_node.tag == .MultilineStringLiteral) Space.None else Space.Space;
|
||||
try renderToken(tree, stream, var_decl.getTrailer("eq_token").?, s); // =
|
||||
stream.pushIndentOneShot();
|
||||
try stream.pushIndentOneShot();
|
||||
try renderExpression(allocator, stream, tree, init_node, Space.None);
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user