mirror of
https://github.com/ziglang/zig.git
synced 2024-11-27 07:32:44 +00:00
zig fmt: implement struct init
This commit is contained in:
parent
8e46d06650
commit
7069459a76
@ -214,8 +214,6 @@ pub const Tree = struct {
|
||||
.OptionalType,
|
||||
.ArrayInitDotTwo,
|
||||
.ArrayInitDot,
|
||||
.StructInitDotTwo,
|
||||
.StructInitDot,
|
||||
.Switch,
|
||||
.IfSimple,
|
||||
.If,
|
||||
@ -252,6 +250,11 @@ pub const Tree = struct {
|
||||
.FnProto,
|
||||
=> return main_tokens[n],
|
||||
|
||||
.StructInitDotTwo,
|
||||
.StructInitDotTwoComma,
|
||||
.StructInitDot,
|
||||
=> return main_tokens[n] - 1,
|
||||
|
||||
.Catch,
|
||||
.FieldAccess,
|
||||
.UnwrapOptional,
|
||||
@ -403,6 +406,7 @@ pub const Tree = struct {
|
||||
.Resume,
|
||||
.Break,
|
||||
.Return,
|
||||
.Nosuspend,
|
||||
=> n = datas[n].lhs,
|
||||
|
||||
.TestDecl,
|
||||
@ -451,7 +455,6 @@ pub const Tree = struct {
|
||||
.AnyFrameType,
|
||||
.ErrorUnion,
|
||||
.Comptime,
|
||||
.Nosuspend,
|
||||
.IfSimple,
|
||||
.WhileSimple,
|
||||
=> n = datas[n].rhs,
|
||||
@ -503,27 +506,97 @@ pub const Tree = struct {
|
||||
n = datas[n].rhs;
|
||||
},
|
||||
|
||||
.BuiltinCallTwo, .BlockTwo => {
|
||||
.BuiltinCallTwo,
|
||||
.BlockTwo,
|
||||
.StructInitDotTwo,
|
||||
=> {
|
||||
end_offset += 1; // for the rparen/rbrace
|
||||
if (datas[n].rhs == 0) {
|
||||
if (datas[n].lhs == 0) {
|
||||
return main_tokens[n] + end_offset;
|
||||
} else {
|
||||
n = datas[n].lhs;
|
||||
}
|
||||
} else {
|
||||
if (datas[n].rhs != 0) {
|
||||
n = datas[n].rhs;
|
||||
} else if (datas[n].lhs != 0) {
|
||||
n = datas[n].lhs;
|
||||
} else {
|
||||
return main_tokens[n] + end_offset;
|
||||
}
|
||||
},
|
||||
.StructInitDotTwoComma => {
|
||||
end_offset += 2; // for the comma + rbrace
|
||||
if (datas[n].rhs != 0) {
|
||||
n = datas[n].rhs;
|
||||
} else if (datas[n].lhs != 0) {
|
||||
n = datas[n].lhs;
|
||||
} else {
|
||||
unreachable;
|
||||
}
|
||||
},
|
||||
.SimpleVarDecl => {
|
||||
if (datas[n].rhs != 0) {
|
||||
n = datas[n].rhs;
|
||||
} else if (datas[n].lhs != 0) {
|
||||
n = datas[n].lhs;
|
||||
} else {
|
||||
end_offset += 1; // from mut token to name
|
||||
return main_tokens[n] + end_offset;
|
||||
}
|
||||
},
|
||||
.AlignedVarDecl => {
|
||||
if (datas[n].rhs != 0) {
|
||||
n = datas[n].rhs;
|
||||
} else if (datas[n].lhs != 0) {
|
||||
end_offset += 1; // for the rparen
|
||||
n = datas[n].lhs;
|
||||
} else {
|
||||
end_offset += 1; // from mut token to name
|
||||
return main_tokens[n] + end_offset;
|
||||
}
|
||||
},
|
||||
.GlobalVarDecl => {
|
||||
if (datas[n].rhs != 0) {
|
||||
n = datas[n].rhs;
|
||||
} else {
|
||||
const extra = tree.extraData(datas[n].lhs, Node.GlobalVarDecl);
|
||||
if (extra.section_node != 0) {
|
||||
end_offset += 1; // for the rparen
|
||||
n = extra.section_node;
|
||||
} else if (extra.align_node != 0) {
|
||||
end_offset += 1; // for the rparen
|
||||
n = extra.align_node;
|
||||
} else if (extra.type_node != 0) {
|
||||
n = extra.type_node;
|
||||
} else {
|
||||
end_offset += 1; // from mut token to name
|
||||
return main_tokens[n] + end_offset;
|
||||
}
|
||||
}
|
||||
},
|
||||
.LocalVarDecl => {
|
||||
if (datas[n].rhs != 0) {
|
||||
n = datas[n].rhs;
|
||||
} else {
|
||||
const extra = tree.extraData(datas[n].lhs, Node.LocalVarDecl);
|
||||
if (extra.align_node != 0) {
|
||||
end_offset += 1; // for the rparen
|
||||
n = extra.align_node;
|
||||
} else if (extra.type_node != 0) {
|
||||
n = extra.type_node;
|
||||
} else {
|
||||
end_offset += 1; // from mut token to name
|
||||
return main_tokens[n] + end_offset;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// These are not supported by lastToken() because implementation would
|
||||
// require recursion due to the optional comma followed by rbrace.
|
||||
// TODO follow the pattern set by StructInitDotTwoComma which will allow
|
||||
// lastToken to work for all of these.
|
||||
.StructInitDot => unreachable,
|
||||
.ContainerFieldInit => unreachable,
|
||||
.ContainerFieldAlign => unreachable,
|
||||
.ContainerField => unreachable,
|
||||
|
||||
.ArrayInitDotTwo => unreachable, // TODO
|
||||
.ArrayInitDot => unreachable, // TODO
|
||||
.StructInitDotTwo => unreachable, // TODO
|
||||
.StructInitDot => unreachable, // TODO
|
||||
.Switch => unreachable, // TODO
|
||||
.If => unreachable, // TODO
|
||||
.Continue => unreachable, // TODO
|
||||
@ -539,10 +612,6 @@ pub const Tree = struct {
|
||||
.SwitchCaseOne => unreachable, // TODO
|
||||
.SwitchRange => unreachable, // TODO
|
||||
.FnDecl => unreachable, // TODO
|
||||
.GlobalVarDecl => unreachable, // TODO
|
||||
.LocalVarDecl => unreachable, // TODO
|
||||
.SimpleVarDecl => unreachable, // TODO
|
||||
.AlignedVarDecl => unreachable, // TODO
|
||||
.ArrayType => unreachable, // TODO
|
||||
.ArrayTypeSentinel => unreachable, // TODO
|
||||
.PtrTypeAligned => unreachable, // TODO
|
||||
@ -743,6 +812,57 @@ pub const Tree = struct {
|
||||
});
|
||||
}
|
||||
|
||||
pub fn structInitOne(tree: Tree, buffer: *[1]Node.Index, node: Node.Index) Full.StructInit {
|
||||
assert(tree.nodes.items(.tag)[node] == .StructInitOne);
|
||||
const data = tree.nodes.items(.data)[node];
|
||||
buffer[0] = data.rhs;
|
||||
const fields = if (data.rhs == 0) buffer[0..0] else buffer[0..1];
|
||||
return tree.fullStructInit(.{
|
||||
.lbrace = tree.nodes.items(.main_token)[node],
|
||||
.fields = fields,
|
||||
.type_expr = data.lhs,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn structInitDotTwo(tree: Tree, buffer: *[2]Node.Index, node: Node.Index) Full.StructInit {
|
||||
assert(tree.nodes.items(.tag)[node] == .StructInitDotTwo or
|
||||
tree.nodes.items(.tag)[node] == .StructInitDotTwoComma);
|
||||
const data = tree.nodes.items(.data)[node];
|
||||
buffer.* = .{ data.lhs, data.rhs };
|
||||
const fields = if (data.rhs != 0)
|
||||
buffer[0..2]
|
||||
else if (data.lhs != 0)
|
||||
buffer[0..1]
|
||||
else
|
||||
buffer[0..0];
|
||||
return tree.fullStructInit(.{
|
||||
.lbrace = tree.nodes.items(.main_token)[node],
|
||||
.fields = fields,
|
||||
.type_expr = 0,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn structInitDot(tree: Tree, node: Node.Index) Full.StructInit {
|
||||
assert(tree.nodes.items(.tag)[node] == .StructInitDot);
|
||||
const data = tree.nodes.items(.data)[node];
|
||||
return tree.fullStructInit(.{
|
||||
.lbrace = tree.nodes.items(.main_token)[node],
|
||||
.fields = tree.extra_data[data.lhs..data.rhs],
|
||||
.type_expr = 0,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn structInit(tree: Tree, node: Node.Index) Full.StructInit {
|
||||
assert(tree.nodes.items(.tag)[node] == .StructInit);
|
||||
const data = tree.nodes.items(.data)[node];
|
||||
const fields_range = tree.extraData(data.rhs, Node.SubRange);
|
||||
return tree.fullStructInit(.{
|
||||
.lbrace = tree.nodes.items(.main_token)[node],
|
||||
.fields = tree.extra_data[fields_range.start..fields_range.end],
|
||||
.type_expr = data.lhs,
|
||||
});
|
||||
}
|
||||
|
||||
fn fullVarDecl(tree: Tree, info: Full.VarDecl.Ast) Full.VarDecl {
|
||||
const token_tags = tree.tokens.items(.tag);
|
||||
var result: Full.VarDecl = .{
|
||||
@ -814,6 +934,14 @@ pub const Tree = struct {
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
fn fullStructInit(tree: Tree, info: Full.StructInit.Ast) Full.StructInit {
|
||||
const token_tags = tree.tokens.items(.tag);
|
||||
var result: Full.StructInit = .{
|
||||
.ast = info,
|
||||
};
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
/// Fully assembled AST node information.
|
||||
@ -877,6 +1005,16 @@ pub const Full = struct {
|
||||
callconv_expr: Node.Index,
|
||||
};
|
||||
};
|
||||
|
||||
pub const StructInit = struct {
|
||||
ast: Ast,
|
||||
|
||||
pub const Ast = struct {
|
||||
lbrace: TokenIndex,
|
||||
fields: []const Node.Index,
|
||||
type_expr: Node.Index,
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
pub const Error = union(enum) {
|
||||
@ -1288,13 +1426,20 @@ pub const Node = struct {
|
||||
/// `lhs{a, b}`. `sub_range_list[rhs]`. lhs can be omitted which means `.{a, b}`.
|
||||
ArrayInit,
|
||||
/// `lhs{.a = rhs}`. rhs can be omitted making it empty.
|
||||
/// main_token is the lbrace.
|
||||
StructInitOne,
|
||||
/// `.{.a = lhs, .b = rhs}`. lhs and rhs can be omitted.
|
||||
/// main_token is the lbrace.
|
||||
StructInitDotTwo,
|
||||
/// Same as `StructInitDotTwo` except there is known to be a trailing comma
|
||||
/// before the final rbrace.
|
||||
StructInitDotTwoComma,
|
||||
/// `.{.a = b, .c = d}`. `sub_list[lhs..rhs]`.
|
||||
/// main_token is the lbrace.
|
||||
StructInitDot,
|
||||
/// `lhs{.a = b, .c = d}`. `sub_range_list[rhs]`.
|
||||
/// lhs can be omitted which means `.{.a = b, .c = d}`.
|
||||
/// main_token is the lbrace.
|
||||
StructInit,
|
||||
/// `lhs(rhs)`. rhs can be omitted.
|
||||
CallOne,
|
||||
@ -1421,10 +1566,10 @@ pub const Node = struct {
|
||||
/// `nosuspend lhs`. rhs unused.
|
||||
Nosuspend,
|
||||
/// `{lhs; rhs;}`. rhs or lhs can be omitted.
|
||||
/// main_token points at the `{`.
|
||||
/// main_token points at the lbrace.
|
||||
BlockTwo,
|
||||
/// `{}`. `sub_list[lhs..rhs]`.
|
||||
/// main_token points at the `{`.
|
||||
/// main_token points at the lbrace.
|
||||
Block,
|
||||
/// `asm(lhs)`. rhs unused.
|
||||
AsmSimple,
|
||||
|
@ -2447,8 +2447,12 @@ const Parser = struct {
|
||||
if (field_init_one != 0) {
|
||||
const comma_one = p.eatToken(.Comma);
|
||||
if (p.eatToken(.RBrace)) |_| {
|
||||
const tag: Node.Tag = if (comma_one != null)
|
||||
.StructInitDotTwoComma
|
||||
else
|
||||
.StructInitDotTwo;
|
||||
return p.addNode(.{
|
||||
.tag = .StructInitDotTwo,
|
||||
.tag = tag,
|
||||
.main_token = lbrace,
|
||||
.data = .{
|
||||
.lhs = field_init_one,
|
||||
@ -2464,8 +2468,12 @@ const Parser = struct {
|
||||
const field_init_two = try p.expectFieldInit();
|
||||
const comma_two = p.eatToken(.Comma);
|
||||
if (p.eatToken(.RBrace)) |_| {
|
||||
const tag: Node.Tag = if (comma_two != null)
|
||||
.StructInitDotTwoComma
|
||||
else
|
||||
.StructInitDotTwo;
|
||||
return p.addNode(.{
|
||||
.tag = .StructInitDotTwo,
|
||||
.tag = tag,
|
||||
.main_token = lbrace,
|
||||
.data = .{
|
||||
.lhs = field_init_one,
|
||||
|
@ -138,17 +138,17 @@ test "zig fmt: errdefer with payload" {
|
||||
);
|
||||
}
|
||||
|
||||
//test "zig fmt: nosuspend block" {
|
||||
// try testCanonical(
|
||||
// \\pub fn main() anyerror!void {
|
||||
// \\ nosuspend {
|
||||
// \\ var foo: Foo = .{ .bar = 42 };
|
||||
// \\ }
|
||||
// \\}
|
||||
// \\
|
||||
// );
|
||||
//}
|
||||
//
|
||||
test "zig fmt: nosuspend block" {
|
||||
try testCanonical(
|
||||
\\pub fn main() anyerror!void {
|
||||
\\ nosuspend {
|
||||
\\ var foo: Foo = .{ .bar = 42 };
|
||||
\\ }
|
||||
\\}
|
||||
\\
|
||||
);
|
||||
}
|
||||
|
||||
//test "zig fmt: nosuspend await" {
|
||||
// try testCanonical(
|
||||
// \\fn foo() void {
|
||||
@ -1505,11 +1505,11 @@ test "zig fmt: errdefer with payload" {
|
||||
//}
|
||||
|
||||
test "zig fmt: ptr deref operator and unwrap optional operator" {
|
||||
try testCanonical(
|
||||
\\const a = b.*;
|
||||
\\const a = b.?;
|
||||
\\
|
||||
);
|
||||
try testCanonical(
|
||||
\\const a = b.*;
|
||||
\\const a = b.?;
|
||||
\\
|
||||
);
|
||||
}
|
||||
|
||||
//test "zig fmt: comment after if before another if" {
|
||||
|
@ -719,145 +719,16 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
|
||||
// return renderToken(ais, tree, rtoken, space);
|
||||
//},
|
||||
|
||||
.StructInitOne => unreachable, // TODO
|
||||
.StructInitDotTwo => unreachable, // TODO
|
||||
.StructInitDot => unreachable, // TODO
|
||||
.StructInit => unreachable, // TODO
|
||||
//.StructInitializer, .StructInitializerDot => {
|
||||
// var rtoken: ast.TokenIndex = undefined;
|
||||
// var field_inits: []ast.Node.Index = undefined;
|
||||
// const lhs: union(enum) { dot: ast.TokenIndex, node: ast.Node.Index } = switch (base.tag) {
|
||||
// .StructInitializerDot => blk: {
|
||||
// const casted = @fieldParentPtr(ast.Node.StructInitializerDot, "base", base);
|
||||
// rtoken = casted.rtoken;
|
||||
// field_inits = casted.list();
|
||||
// break :blk .{ .dot = casted.dot };
|
||||
// },
|
||||
// .StructInitializer => blk: {
|
||||
// const casted = @fieldParentPtr(ast.Node.StructInitializer, "base", base);
|
||||
// rtoken = casted.rtoken;
|
||||
// field_inits = casted.list();
|
||||
// break :blk .{ .node = casted.lhs };
|
||||
// },
|
||||
// else => unreachable,
|
||||
// };
|
||||
|
||||
// const lbrace = switch (lhs) {
|
||||
// .dot => |dot| tree.nextToken(dot),
|
||||
// .node => |node| tree.nextToken(node.lastToken()),
|
||||
// };
|
||||
|
||||
// if (field_inits.len == 0) {
|
||||
// switch (lhs) {
|
||||
// .dot => |dot| try renderToken(ais, tree, dot, Space.None),
|
||||
// .node => |node| try renderExpression(ais, tree, node, Space.None),
|
||||
// }
|
||||
|
||||
// {
|
||||
// ais.pushIndentNextLine();
|
||||
// defer ais.popIndent();
|
||||
// try renderToken(ais, tree, lbrace, Space.None);
|
||||
// }
|
||||
|
||||
// return renderToken(ais, tree, rtoken, space);
|
||||
// }
|
||||
|
||||
// const src_has_trailing_comma = blk: {
|
||||
// const maybe_comma = tree.prevToken(rtoken);
|
||||
// break :blk tree.token_tags[maybe_comma] == .Comma;
|
||||
// };
|
||||
|
||||
// const src_same_line = blk: {
|
||||
// const loc = tree.tokenLocation(tree.token_locs[lbrace].end, rtoken);
|
||||
// break :blk loc.line == 0;
|
||||
// };
|
||||
|
||||
// const expr_outputs_one_line = blk: {
|
||||
// // render field expressions until a LF is found
|
||||
// for (field_inits) |field_init| {
|
||||
// var find_stream = std.io.findByteWriter('\n', std.io.null_writer);
|
||||
// var auto_indenting_stream = std.io.autoIndentingStream(indent_delta, find_stream.writer());
|
||||
|
||||
// try renderExpression(allocator, &auto_indenting_stream, tree, field_init, Space.None);
|
||||
// if (find_stream.byte_found) break :blk false;
|
||||
// }
|
||||
// break :blk true;
|
||||
// };
|
||||
|
||||
// if (field_inits.len == 1) blk: {
|
||||
// if (field_inits[0].cast(ast.Node.FieldInitializer)) |field_init| {
|
||||
// switch (field_init.expr.tag) {
|
||||
// .StructInitializer,
|
||||
// .StructInitializerDot,
|
||||
// => break :blk,
|
||||
// else => {},
|
||||
// }
|
||||
// }
|
||||
|
||||
// // if the expression outputs to multiline, make this struct multiline
|
||||
// if (!expr_outputs_one_line or src_has_trailing_comma) {
|
||||
// break :blk;
|
||||
// }
|
||||
|
||||
// switch (lhs) {
|
||||
// .dot => |dot| try renderToken(ais, tree, dot, Space.None),
|
||||
// .node => |node| try renderExpression(ais, tree, node, Space.None),
|
||||
// }
|
||||
// try renderToken(ais, tree, lbrace, Space.Space);
|
||||
// try renderExpression(ais, tree, field_inits[0], Space.Space);
|
||||
// return renderToken(ais, tree, rtoken, space);
|
||||
// }
|
||||
|
||||
// if (!src_has_trailing_comma and src_same_line and expr_outputs_one_line) {
|
||||
// // render all on one line, no trailing comma
|
||||
// switch (lhs) {
|
||||
// .dot => |dot| try renderToken(ais, tree, dot, Space.None),
|
||||
// .node => |node| try renderExpression(ais, tree, node, Space.None),
|
||||
// }
|
||||
// try renderToken(ais, tree, lbrace, Space.Space);
|
||||
|
||||
// for (field_inits) |field_init, i| {
|
||||
// if (i + 1 < field_inits.len) {
|
||||
// try renderExpression(ais, tree, field_init, Space.None);
|
||||
|
||||
// const comma = tree.nextToken(field_init.lastToken());
|
||||
// try renderToken(ais, tree, comma, Space.Space);
|
||||
// } else {
|
||||
// try renderExpression(ais, tree, field_init, Space.Space);
|
||||
// }
|
||||
// }
|
||||
|
||||
// return renderToken(ais, tree, rtoken, space);
|
||||
// }
|
||||
|
||||
// {
|
||||
// switch (lhs) {
|
||||
// .dot => |dot| try renderToken(ais, tree, dot, Space.None),
|
||||
// .node => |node| try renderExpression(ais, tree, node, Space.None),
|
||||
// }
|
||||
|
||||
// ais.pushIndentNextLine();
|
||||
// defer ais.popIndent();
|
||||
|
||||
// try renderToken(ais, tree, lbrace, Space.Newline);
|
||||
|
||||
// for (field_inits) |field_init, i| {
|
||||
// if (i + 1 < field_inits.len) {
|
||||
// const next_field_init = field_inits[i + 1];
|
||||
// try renderExpression(ais, tree, field_init, Space.None);
|
||||
|
||||
// const comma = tree.nextToken(field_init.lastToken());
|
||||
// try renderToken(ais, tree, comma, Space.Newline);
|
||||
|
||||
// try renderExtraNewline(ais, tree, next_field_init);
|
||||
// } else {
|
||||
// try renderExpression(ais, tree, field_init, Space.Comma);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// return renderToken(ais, tree, rtoken, space);
|
||||
//},
|
||||
.StructInitOne => {
|
||||
var fields: [1]ast.Node.Index = undefined;
|
||||
return renderStructInit(ais, tree, tree.structInitOne(&fields, node), space);
|
||||
},
|
||||
.StructInitDotTwo, .StructInitDotTwoComma => {
|
||||
var fields: [2]ast.Node.Index = undefined;
|
||||
return renderStructInit(ais, tree, tree.structInitDotTwo(&fields, node), space);
|
||||
},
|
||||
.StructInitDot => return renderStructInit(ais, tree, tree.structInitDot(node), space),
|
||||
.StructInit => return renderStructInit(ais, tree, tree.structInit(node), space),
|
||||
|
||||
.CallOne => unreachable, // TODO
|
||||
.Call => {
|
||||
@ -1078,9 +949,9 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
|
||||
// {
|
||||
// ais.pushIndentNextLine();
|
||||
// defer ais.popIndent();
|
||||
// try renderToken(ais, tree, container_decl.lbrace_token, Space.None); // {
|
||||
// try renderToken(ais, tree, container_decl.lbrace_token, Space.None); // lbrace
|
||||
// }
|
||||
// return renderToken(ais, tree, container_decl.rbrace_token, space); // }
|
||||
// return renderToken(ais, tree, container_decl.rbrace_token, space); // rbrace
|
||||
// }
|
||||
|
||||
// const src_has_trailing_comma = blk: {
|
||||
@ -1113,7 +984,7 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
|
||||
// // One declaration per line
|
||||
// ais.pushIndentNextLine();
|
||||
// defer ais.popIndent();
|
||||
// try renderToken(ais, tree, container_decl.lbrace_token, .Newline); // {
|
||||
// try renderToken(ais, tree, container_decl.lbrace_token, .Newline); // lbrace
|
||||
|
||||
// for (fields_and_decls) |decl, i| {
|
||||
// try renderContainerDecl(allocator, ais, tree, decl, .Newline);
|
||||
@ -1125,7 +996,7 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
|
||||
// } else if (src_has_newline) {
|
||||
// // All the declarations on the same line, but place the items on
|
||||
// // their own line
|
||||
// try renderToken(ais, tree, container_decl.lbrace_token, .Newline); // {
|
||||
// try renderToken(ais, tree, container_decl.lbrace_token, .Newline); // lbrace
|
||||
|
||||
// ais.pushIndent();
|
||||
// defer ais.popIndent();
|
||||
@ -1136,14 +1007,14 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
|
||||
// }
|
||||
// } else {
|
||||
// // All the declarations on the same line
|
||||
// try renderToken(ais, tree, container_decl.lbrace_token, .Space); // {
|
||||
// try renderToken(ais, tree, container_decl.lbrace_token, .Space); // lbrace
|
||||
|
||||
// for (fields_and_decls) |decl| {
|
||||
// try renderContainerDecl(allocator, ais, tree, decl, .Space);
|
||||
// }
|
||||
// }
|
||||
|
||||
// return renderToken(ais, tree, container_decl.rbrace_token, space); // }
|
||||
// return renderToken(ais, tree, container_decl.rbrace_token, space); // rbrace
|
||||
//},
|
||||
|
||||
.ErrorSetDecl => unreachable, // TODO
|
||||
@ -1170,9 +1041,9 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
|
||||
// }
|
||||
|
||||
// try renderToken(ais, tree, err_set_decl.error_token, Space.None); // error
|
||||
// try renderToken(ais, tree, lbrace, Space.None); // {
|
||||
// try renderToken(ais, tree, lbrace, Space.None); // lbrace
|
||||
// try renderExpression(ais, tree, node, Space.None);
|
||||
// return renderToken(ais, tree, err_set_decl.rbrace_token, space); // }
|
||||
// return renderToken(ais, tree, err_set_decl.rbrace_token, space); // rbrace
|
||||
// }
|
||||
|
||||
// try renderToken(ais, tree, err_set_decl.error_token, Space.None); // error
|
||||
@ -1187,7 +1058,7 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
|
||||
// ais.pushIndent();
|
||||
// defer ais.popIndent();
|
||||
|
||||
// try renderToken(ais, tree, lbrace, Space.Newline); // {
|
||||
// try renderToken(ais, tree, lbrace, Space.Newline); // lbrace
|
||||
// const decls = err_set_decl.decls();
|
||||
// for (decls) |node, i| {
|
||||
// if (i + 1 < decls.len) {
|
||||
@ -1201,9 +1072,9 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
|
||||
// }
|
||||
// }
|
||||
|
||||
// return renderToken(ais, tree, err_set_decl.rbrace_token, space); // }
|
||||
// return renderToken(ais, tree, err_set_decl.rbrace_token, space); // rbrace
|
||||
// } else {
|
||||
// try renderToken(ais, tree, lbrace, Space.Space); // {
|
||||
// try renderToken(ais, tree, lbrace, Space.Space); // lbrace
|
||||
|
||||
// const decls = err_set_decl.decls();
|
||||
// for (decls) |node, i| {
|
||||
@ -1219,7 +1090,7 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
|
||||
// }
|
||||
// }
|
||||
|
||||
// return renderToken(ais, tree, err_set_decl.rbrace_token, space); // }
|
||||
// return renderToken(ais, tree, err_set_decl.rbrace_token, space); // rbrace
|
||||
// }
|
||||
//},
|
||||
|
||||
@ -1277,8 +1148,8 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
|
||||
// if (switch_node.cases_len == 0) {
|
||||
// try renderExpression(ais, tree, switch_node.expr, Space.None);
|
||||
// try renderToken(ais, tree, rparen, Space.Space); // )
|
||||
// try renderToken(ais, tree, lbrace, Space.None); // {
|
||||
// return renderToken(ais, tree, switch_node.rbrace, space); // }
|
||||
// try renderToken(ais, tree, lbrace, Space.None); // lbrace
|
||||
// return renderToken(ais, tree, switch_node.rbrace, space); // rbrace
|
||||
// }
|
||||
|
||||
// try renderExpression(ais, tree, switch_node.expr, Space.None);
|
||||
@ -1287,7 +1158,7 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
|
||||
// {
|
||||
// ais.pushIndentNextLine();
|
||||
// defer ais.popIndent();
|
||||
// try renderToken(ais, tree, lbrace, Space.Newline); // {
|
||||
// try renderToken(ais, tree, lbrace, Space.Newline); // lbrace
|
||||
|
||||
// const cases = switch_node.cases();
|
||||
// for (cases) |node, i| {
|
||||
@ -1299,7 +1170,7 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
|
||||
// }
|
||||
// }
|
||||
|
||||
// return renderToken(ais, tree, switch_node.rbrace, space); // }
|
||||
// return renderToken(ais, tree, switch_node.rbrace, space); // rbrace
|
||||
//},
|
||||
|
||||
.SwitchCaseOne => unreachable, // TODO
|
||||
@ -1379,7 +1250,7 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
|
||||
|
||||
// if (body_is_block) {
|
||||
// block_start_space = Space.BlockStart;
|
||||
// after_body_space = if (while_node.@"else" == null) space else Space.SpaceOrOutdent;
|
||||
// after_body_space = if (while_node.@"else" == null) space else Space.Space;
|
||||
// } else if (tree.tokensOnSameLine(cond_rparen, while_node.body.lastToken())) {
|
||||
// block_start_space = Space.Space;
|
||||
// after_body_space = if (while_node.@"else" == null) space else Space.Space;
|
||||
@ -1782,10 +1653,7 @@ fn renderVarDecl(ais: *Ais, tree: ast.Tree, var_decl: ast.Full.VarDecl) Error!vo
|
||||
ais.popIndent();
|
||||
}
|
||||
ais.pushIndentOneShot();
|
||||
try renderExpression(ais, tree, var_decl.ast.init_node, Space.None);
|
||||
|
||||
const semicolon = tree.lastToken(var_decl.ast.init_node) + 1;
|
||||
return renderToken(ais, tree, semicolon, Space.Newline);
|
||||
try renderExpression(ais, tree, var_decl.ast.init_node, .Semicolon);
|
||||
}
|
||||
|
||||
fn renderIf(ais: *Ais, tree: ast.Tree, if_node: ast.Full.If, space: Space) Error!void {
|
||||
@ -1820,7 +1688,7 @@ fn renderIf(ais: *Ais, tree: ast.Tree, if_node: ast.Full.If, space: Space) Error
|
||||
try renderToken(ais, tree, rparen, .BlockStart); // )
|
||||
}
|
||||
if (if_node.ast.else_expr != 0) {
|
||||
try renderExpression(ais, tree, if_node.ast.then_expr, Space.SpaceOrOutdent);
|
||||
try renderExpression(ais, tree, if_node.ast.then_expr, Space.Space);
|
||||
try renderToken(ais, tree, if_node.else_token, .Space); // else
|
||||
if (if_node.error_token) |error_token| {
|
||||
try renderToken(ais, tree, error_token - 1, .None); // |
|
||||
@ -2197,6 +2065,7 @@ fn renderBlock(
|
||||
) Error!void {
|
||||
const token_tags = tree.tokens.items(.tag);
|
||||
const node_tags = tree.nodes.items(.tag);
|
||||
const nodes_data = tree.nodes.items(.data);
|
||||
|
||||
if (token_tags[lbrace - 1] == .Colon and
|
||||
token_tags[lbrace - 2] == .Identifier)
|
||||
@ -2204,50 +2073,88 @@ fn renderBlock(
|
||||
try renderToken(ais, tree, lbrace - 2, .None);
|
||||
try renderToken(ais, tree, lbrace - 1, .Space);
|
||||
}
|
||||
const nodes_data = tree.nodes.items(.data);
|
||||
|
||||
if (statements.len == 0) {
|
||||
ais.pushIndentNextLine();
|
||||
try renderToken(ais, tree, lbrace, .None);
|
||||
ais.popIndent();
|
||||
const rbrace = lbrace + 1;
|
||||
return renderToken(ais, tree, rbrace, space);
|
||||
return renderToken(ais, tree, lbrace + 1, space); // rbrace
|
||||
}
|
||||
|
||||
ais.pushIndent();
|
||||
try renderToken(ais, tree, lbrace, .Newline);
|
||||
for (statements) |stmt, i| {
|
||||
switch (node_tags[stmt]) {
|
||||
.GlobalVarDecl => try renderVarDecl(ais, tree, tree.globalVarDecl(stmt)),
|
||||
.LocalVarDecl => try renderVarDecl(ais, tree, tree.localVarDecl(stmt)),
|
||||
.SimpleVarDecl => try renderVarDecl(ais, tree, tree.simpleVarDecl(stmt)),
|
||||
.AlignedVarDecl => try renderVarDecl(ais, tree, tree.alignedVarDecl(stmt)),
|
||||
else => try renderExpression(ais, tree, stmt, .Semicolon),
|
||||
}
|
||||
if (i + 1 < statements.len) {
|
||||
try renderExtraNewline(ais, tree, statements[i + 1]);
|
||||
}
|
||||
}
|
||||
ais.popIndent();
|
||||
// The rbrace could be +1 or +2 from the last token of the last
|
||||
// statement in the block because lastToken() does not count semicolons.
|
||||
const maybe_rbrace = tree.lastToken(statements[statements.len - 1]) + 1;
|
||||
if (token_tags[maybe_rbrace] == .RBrace) {
|
||||
return renderToken(ais, tree, maybe_rbrace, space);
|
||||
} else {
|
||||
ais.pushIndentNextLine();
|
||||
assert(token_tags[maybe_rbrace + 1] == .RBrace);
|
||||
return renderToken(ais, tree, maybe_rbrace + 1, space);
|
||||
}
|
||||
}
|
||||
|
||||
try renderToken(ais, tree, lbrace, .Newline);
|
||||
fn renderStructInit(
|
||||
ais: *Ais,
|
||||
tree: ast.Tree,
|
||||
struct_init: ast.Full.StructInit,
|
||||
space: Space,
|
||||
) Error!void {
|
||||
const token_tags = tree.tokens.items(.tag);
|
||||
if (struct_init.ast.type_expr == 0) {
|
||||
try renderToken(ais, tree, struct_init.ast.lbrace - 1, .None); // .
|
||||
} else {
|
||||
try renderExpression(ais, tree, struct_init.ast.type_expr, .None); // T
|
||||
}
|
||||
if (struct_init.ast.fields.len == 0) {
|
||||
try renderToken(ais, tree, struct_init.ast.lbrace, .None); // lbrace
|
||||
return renderToken(ais, tree, struct_init.ast.lbrace + 1, space); // rbrace
|
||||
}
|
||||
const last_field = struct_init.ast.fields[struct_init.ast.fields.len - 1];
|
||||
const last_field_token = tree.lastToken(last_field);
|
||||
if (token_tags[last_field_token + 1] == .Comma) {
|
||||
// Render one field init per line.
|
||||
ais.pushIndent();
|
||||
try renderToken(ais, tree, struct_init.ast.lbrace, .Newline);
|
||||
|
||||
for (statements) |stmt, i| {
|
||||
switch (node_tags[stmt]) {
|
||||
.GlobalVarDecl => try renderVarDecl(ais, tree, tree.globalVarDecl(stmt)),
|
||||
.LocalVarDecl => try renderVarDecl(ais, tree, tree.localVarDecl(stmt)),
|
||||
.SimpleVarDecl => try renderVarDecl(ais, tree, tree.simpleVarDecl(stmt)),
|
||||
.AlignedVarDecl => try renderVarDecl(ais, tree, tree.alignedVarDecl(stmt)),
|
||||
else => {
|
||||
const semicolon = tree.lastToken(stmt) + 1;
|
||||
if (token_tags[semicolon] == .Semicolon) {
|
||||
try renderExpression(ais, tree, stmt, .None);
|
||||
try renderToken(ais, tree, semicolon, .Newline);
|
||||
} else {
|
||||
try renderExpression(ais, tree, stmt, .Newline);
|
||||
}
|
||||
},
|
||||
}
|
||||
try renderToken(ais, tree, struct_init.ast.lbrace + 1, .None); // .
|
||||
try renderToken(ais, tree, struct_init.ast.lbrace + 2, .Space); // name
|
||||
try renderToken(ais, tree, struct_init.ast.lbrace + 3, .Space); // =
|
||||
try renderExpression(ais, tree, struct_init.ast.fields[0], .Comma);
|
||||
|
||||
if (i + 1 < statements.len) {
|
||||
try renderExtraNewline(ais, tree, statements[i + 1]);
|
||||
}
|
||||
for (struct_init.ast.fields[1..]) |field_init| {
|
||||
const init_token = tree.firstToken(field_init);
|
||||
try renderToken(ais, tree, init_token - 3, .None); // .
|
||||
try renderToken(ais, tree, init_token - 2, .Space); // name
|
||||
try renderToken(ais, tree, init_token - 1, .Space); // =
|
||||
try renderExpressionNewlined(ais, tree, field_init, .Comma);
|
||||
}
|
||||
ais.popIndent();
|
||||
// The rbrace could be +1 or +2 from the last token of the last
|
||||
// statement in the block because lastToken() does not count semicolons.
|
||||
const maybe_rbrace = tree.lastToken(statements[statements.len - 1]) + 1;
|
||||
if (token_tags[maybe_rbrace] == .RBrace) {
|
||||
return renderToken(ais, tree, maybe_rbrace, space);
|
||||
} else {
|
||||
assert(token_tags[maybe_rbrace + 1] == .RBrace);
|
||||
return renderToken(ais, tree, maybe_rbrace + 1, space);
|
||||
return renderToken(ais, tree, last_field_token + 2, space); // rbrace
|
||||
} else {
|
||||
// Render all on one line, no trailing comma.
|
||||
try renderToken(ais, tree, struct_init.ast.lbrace, .Space);
|
||||
|
||||
for (struct_init.ast.fields) |field_init| {
|
||||
const init_token = tree.firstToken(field_init);
|
||||
try renderToken(ais, tree, init_token - 3, .None); // .
|
||||
try renderToken(ais, tree, init_token - 2, .Space); // name
|
||||
try renderToken(ais, tree, init_token - 1, .Space); // =
|
||||
try renderExpression(ais, tree, field_init, .CommaSpace);
|
||||
}
|
||||
|
||||
return renderToken(ais, tree, last_field_token + 1, space); // rbrace
|
||||
}
|
||||
}
|
||||
|
||||
@ -2263,6 +2170,22 @@ fn renderExpressionComma(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space:
|
||||
}
|
||||
}
|
||||
|
||||
/// Render an expression, but first insert an extra newline if the previous token is 2 or
|
||||
/// more lines away.
|
||||
fn renderExpressionNewlined(
|
||||
ais: *Ais,
|
||||
tree: ast.Tree,
|
||||
node: ast.Node.Index,
|
||||
space: Space,
|
||||
) Error!void {
|
||||
const token_starts = tree.tokens.items(.start);
|
||||
const first_token = tree.firstToken(node);
|
||||
if (tree.tokenLocation(token_starts[first_token - 1], first_token).line >= 2) {
|
||||
try ais.insertNewline();
|
||||
}
|
||||
return renderExpression(ais, tree, node, space);
|
||||
}
|
||||
|
||||
fn renderTokenComma(ais: *Ais, tree: ast.Tree, token: ast.TokenIndex, space: Space) Error!void {
|
||||
const token_tags = tree.tokens.items(.tag);
|
||||
const maybe_comma = token + 1;
|
||||
@ -2275,22 +2198,32 @@ fn renderTokenComma(ais: *Ais, tree: ast.Tree, token: ast.TokenIndex, space: Spa
|
||||
}
|
||||
|
||||
const Space = enum {
|
||||
/// Output the token lexeme only.
|
||||
None,
|
||||
Newline,
|
||||
/// `renderToken` will additionally consume the next token if it is a comma.
|
||||
Comma,
|
||||
/// Output the token lexeme followed by a single space.
|
||||
Space,
|
||||
SpaceOrOutdent,
|
||||
NoNewline,
|
||||
/// Output the token lexeme followed by a newline.
|
||||
Newline,
|
||||
/// Additionally consume the next token if it is a comma.
|
||||
/// In either case, a newline will be inserted afterwards.
|
||||
Comma,
|
||||
/// Additionally consume the next token if it is a comma.
|
||||
/// In either case, a space will be inserted afterwards.
|
||||
CommaSpace,
|
||||
/// Additionally consume the next token if it is a semicolon.
|
||||
/// In either case, a newline will be inserted afterwards.
|
||||
Semicolon,
|
||||
/// Skips writing the possible line comment after the token.
|
||||
NoComment,
|
||||
/// Intended when rendering lbrace tokens. Depending on whether the line is
|
||||
/// "over indented", will output a newline or a single space afterwards.
|
||||
/// See `std.io.AutoIndentingStream` for the definition of "over indented".
|
||||
BlockStart,
|
||||
};
|
||||
|
||||
fn renderToken(ais: *Ais, tree: ast.Tree, token_index: ast.TokenIndex, space: Space) Error!void {
|
||||
if (space == Space.BlockStart) {
|
||||
// If placing the lbrace on the current line would cause an ugly gap then put the lbrace on the next line.
|
||||
const new_space = if (ais.isLineOverIndented()) Space.Newline else Space.Space;
|
||||
const new_space: Space = if (ais.isLineOverIndented()) .Newline else .Space;
|
||||
return renderToken(ais, tree, token_index, new_space);
|
||||
}
|
||||
|
||||
@ -2313,7 +2246,6 @@ fn renderToken(ais: *Ais, tree: ast.Tree, token_index: ast.TokenIndex, space: Sp
|
||||
|
||||
switch (space) {
|
||||
.NoComment => {},
|
||||
.NoNewline => {},
|
||||
.None => {},
|
||||
.Comma => {
|
||||
const count = try renderComments(ais, tree, token_start + lexeme.len, token_starts[token_index + 1], ", ");
|
||||
@ -2326,10 +2258,25 @@ fn renderToken(ais: *Ais, tree: ast.Tree, token_index: ast.TokenIndex, space: Sp
|
||||
try ais.insertNewline();
|
||||
}
|
||||
},
|
||||
.SpaceOrOutdent => @panic("what does this even do"),
|
||||
.CommaSpace => {
|
||||
_ = try renderComments(ais, tree, token_start + lexeme.len, token_starts[token_index + 1], "");
|
||||
if (token_tags[token_index + 1] == .Comma) {
|
||||
return renderToken(ais, tree, token_index + 1, .Space);
|
||||
} else {
|
||||
return ais.writer().writeByte(' ');
|
||||
}
|
||||
},
|
||||
.Semicolon => {
|
||||
_ = try renderComments(ais, tree, token_start + lexeme.len, token_starts[token_index + 1], "");
|
||||
if (token_tags[token_index + 1] == .Semicolon) {
|
||||
return renderToken(ais, tree, token_index + 1, .Newline);
|
||||
} else {
|
||||
return ais.insertNewline();
|
||||
}
|
||||
},
|
||||
.Space => {
|
||||
_ = try renderComments(ais, tree, token_start + lexeme.len, token_starts[token_index + 1], "");
|
||||
try ais.writer().writeByte(' ');
|
||||
return ais.writer().writeByte(' ');
|
||||
},
|
||||
.Newline => {
|
||||
if (token_tags[token_index + 1] != .MultilineStringLiteralLine) {
|
||||
@ -2437,10 +2384,11 @@ fn nodeCausesSliceOpSpace(base: ast.Node.Index) bool {
|
||||
}
|
||||
|
||||
fn copyFixingWhitespace(ais: *Ais, slice: []const u8) @TypeOf(ais.*).Error!void {
|
||||
const writer = ais.writer();
|
||||
for (slice) |byte| switch (byte) {
|
||||
'\t' => try ais.writer().writeAll(" "),
|
||||
'\t' => try writer.writeAll(" "),
|
||||
'\r' => {},
|
||||
else => try ais.writer().writeByte(byte),
|
||||
else => try writer.writeByte(byte),
|
||||
};
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user