zig fmt: asm expressions

This commit is contained in:
Andrew Kelley
2021-02-08 22:03:23 -07:00
parent d869133a9f
commit b1d8a0a5a6
4 changed files with 402 additions and 259 deletions

View File

@@ -419,13 +419,16 @@ pub const Tree = struct {
n = extra.start;
},
.AsmOutput, .AsmInput => {
assert(token_tags[main_tokens[n] - 1] == .LBracket);
return main_tokens[n] - 1;
},
.WhileSimple => unreachable, // TODO
.WhileCont => unreachable, // TODO
.While => unreachable, // TODO
.ForSimple => unreachable, // TODO
.For => unreachable, // TODO
.AsmOutput => unreachable, // TODO
.AsmInput => unreachable, // TODO
.ErrorValue => unreachable, // TODO
};
}
@@ -515,6 +518,9 @@ pub const Tree = struct {
.GroupedExpression,
.StringLiteral,
.ErrorSetDecl,
.AsmSimple,
.AsmOutput,
.AsmInput,
=> return datas[n].rhs + end_offset,
.AnyType,
@@ -566,6 +572,10 @@ pub const Tree = struct {
n = tree.extra_data[members.end - 1]; // last parameter
}
},
.Asm => {
const extra = tree.extraData(datas[n].rhs, Node.Asm);
return extra.rparen + end_offset;
},
.ContainerDeclArgComma,
.SwitchComma,
=> {
@@ -765,8 +775,6 @@ pub const Tree = struct {
.TaggedUnionEnumTagComma => unreachable, // TODO
.If => unreachable, // TODO
.Continue => unreachable, // TODO
.AsmSimple => unreachable, // TODO
.Asm => unreachable, // TODO
.SwitchRange => unreachable, // TODO
.ArrayType => unreachable, // TODO
.ArrayTypeSentinel => unreachable, // TODO
@@ -778,8 +786,6 @@ pub const Tree = struct {
.FnProtoMulti => unreachable, // TODO
.FnProtoOne => unreachable, // TODO
.FnProto => unreachable, // TODO
.AsmOutput => unreachable, // TODO
.AsmInput => unreachable, // TODO
.ErrorValue => unreachable, // TODO
};
}
@@ -790,7 +796,7 @@ pub const Tree = struct {
return mem.indexOfScalar(u8, source, '\n') == null;
}
pub fn globalVarDecl(tree: Tree, node: Node.Index) Full.VarDecl {
pub fn globalVarDecl(tree: Tree, node: Node.Index) full.VarDecl {
assert(tree.nodes.items(.tag)[node] == .GlobalVarDecl);
const data = tree.nodes.items(.data)[node];
const extra = tree.extraData(data.lhs, Node.GlobalVarDecl);
@@ -803,7 +809,7 @@ pub const Tree = struct {
});
}
pub fn localVarDecl(tree: Tree, node: Node.Index) Full.VarDecl {
pub fn localVarDecl(tree: Tree, node: Node.Index) full.VarDecl {
assert(tree.nodes.items(.tag)[node] == .LocalVarDecl);
const data = tree.nodes.items(.data)[node];
const extra = tree.extraData(data.lhs, Node.LocalVarDecl);
@@ -816,7 +822,7 @@ pub const Tree = struct {
});
}
pub fn simpleVarDecl(tree: Tree, node: Node.Index) Full.VarDecl {
pub fn simpleVarDecl(tree: Tree, node: Node.Index) full.VarDecl {
assert(tree.nodes.items(.tag)[node] == .SimpleVarDecl);
const data = tree.nodes.items(.data)[node];
return tree.fullVarDecl(.{
@@ -828,7 +834,7 @@ pub const Tree = struct {
});
}
pub fn alignedVarDecl(tree: Tree, node: Node.Index) Full.VarDecl {
pub fn alignedVarDecl(tree: Tree, node: Node.Index) full.VarDecl {
assert(tree.nodes.items(.tag)[node] == .AlignedVarDecl);
const data = tree.nodes.items(.data)[node];
return tree.fullVarDecl(.{
@@ -840,7 +846,7 @@ pub const Tree = struct {
});
}
pub fn ifSimple(tree: Tree, node: Node.Index) Full.If {
pub fn ifSimple(tree: Tree, node: Node.Index) full.If {
assert(tree.nodes.items(.tag)[node] == .IfSimple);
const data = tree.nodes.items(.data)[node];
return tree.fullIf(.{
@@ -851,7 +857,7 @@ pub const Tree = struct {
});
}
pub fn ifFull(tree: Tree, node: Node.Index) Full.If {
pub fn ifFull(tree: Tree, node: Node.Index) full.If {
assert(tree.nodes.items(.tag)[node] == .If);
const data = tree.nodes.items(.data)[node];
const extra = tree.extraData(data.rhs, Node.If);
@@ -863,7 +869,7 @@ pub const Tree = struct {
});
}
pub fn containerField(tree: Tree, node: Node.Index) Full.ContainerField {
pub fn containerField(tree: Tree, node: Node.Index) full.ContainerField {
assert(tree.nodes.items(.tag)[node] == .ContainerField);
const data = tree.nodes.items(.data)[node];
const extra = tree.extraData(data.rhs, Node.ContainerField);
@@ -875,7 +881,7 @@ pub const Tree = struct {
});
}
pub fn containerFieldInit(tree: Tree, node: Node.Index) Full.ContainerField {
pub fn containerFieldInit(tree: Tree, node: Node.Index) full.ContainerField {
assert(tree.nodes.items(.tag)[node] == .ContainerFieldInit);
const data = tree.nodes.items(.data)[node];
return tree.fullContainerField(.{
@@ -886,7 +892,7 @@ pub const Tree = struct {
});
}
pub fn containerFieldAlign(tree: Tree, node: Node.Index) Full.ContainerField {
pub fn containerFieldAlign(tree: Tree, node: Node.Index) full.ContainerField {
assert(tree.nodes.items(.tag)[node] == .ContainerFieldAlign);
const data = tree.nodes.items(.data)[node];
return tree.fullContainerField(.{
@@ -897,7 +903,7 @@ pub const Tree = struct {
});
}
pub fn fnProtoSimple(tree: Tree, buffer: *[1]Node.Index, node: Node.Index) Full.FnProto {
pub fn fnProtoSimple(tree: Tree, buffer: *[1]Node.Index, node: Node.Index) full.FnProto {
assert(tree.nodes.items(.tag)[node] == .FnProtoSimple);
const data = tree.nodes.items(.data)[node];
buffer[0] = data.lhs;
@@ -912,7 +918,7 @@ pub const Tree = struct {
});
}
pub fn fnProtoMulti(tree: Tree, node: Node.Index) Full.FnProto {
pub fn fnProtoMulti(tree: Tree, node: Node.Index) full.FnProto {
assert(tree.nodes.items(.tag)[node] == .FnProtoMulti);
const data = tree.nodes.items(.data)[node];
const params_range = tree.extraData(data.lhs, Node.SubRange);
@@ -927,7 +933,7 @@ pub const Tree = struct {
});
}
pub fn fnProtoOne(tree: Tree, buffer: *[1]Node.Index, node: Node.Index) Full.FnProto {
pub fn fnProtoOne(tree: Tree, buffer: *[1]Node.Index, node: Node.Index) full.FnProto {
assert(tree.nodes.items(.tag)[node] == .FnProtoOne);
const data = tree.nodes.items(.data)[node];
const extra = tree.extraData(data.lhs, Node.FnProtoOne);
@@ -943,7 +949,7 @@ pub const Tree = struct {
});
}
pub fn fnProto(tree: Tree, node: Node.Index) Full.FnProto {
pub fn fnProto(tree: Tree, node: Node.Index) full.FnProto {
assert(tree.nodes.items(.tag)[node] == .FnProto);
const data = tree.nodes.items(.data)[node];
const extra = tree.extraData(data.lhs, Node.FnProto);
@@ -958,7 +964,7 @@ pub const Tree = struct {
});
}
pub fn structInitOne(tree: Tree, buffer: *[1]Node.Index, node: Node.Index) Full.StructInit {
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;
@@ -970,7 +976,7 @@ pub const Tree = struct {
});
}
pub fn structInitDotTwo(tree: Tree, buffer: *[2]Node.Index, node: Node.Index) Full.StructInit {
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];
@@ -988,7 +994,7 @@ pub const Tree = struct {
});
}
pub fn structInitDot(tree: Tree, node: Node.Index) Full.StructInit {
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(.{
@@ -998,7 +1004,7 @@ pub const Tree = struct {
});
}
pub fn structInit(tree: Tree, node: Node.Index) Full.StructInit {
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);
@@ -1009,7 +1015,7 @@ pub const Tree = struct {
});
}
pub fn arrayInitOne(tree: Tree, buffer: *[1]Node.Index, node: Node.Index) Full.ArrayInit {
pub fn arrayInitOne(tree: Tree, buffer: *[1]Node.Index, node: Node.Index) full.ArrayInit {
assert(tree.nodes.items(.tag)[node] == .ArrayInitOne);
const data = tree.nodes.items(.data)[node];
buffer[0] = data.rhs;
@@ -1023,7 +1029,7 @@ pub const Tree = struct {
};
}
pub fn arrayInitDotTwo(tree: Tree, buffer: *[2]Node.Index, node: Node.Index) Full.ArrayInit {
pub fn arrayInitDotTwo(tree: Tree, buffer: *[2]Node.Index, node: Node.Index) full.ArrayInit {
assert(tree.nodes.items(.tag)[node] == .ArrayInitDotTwo or
tree.nodes.items(.tag)[node] == .ArrayInitDotTwoComma);
const data = tree.nodes.items(.data)[node];
@@ -1043,7 +1049,7 @@ pub const Tree = struct {
};
}
pub fn arrayInitDot(tree: Tree, node: Node.Index) Full.ArrayInit {
pub fn arrayInitDot(tree: Tree, node: Node.Index) full.ArrayInit {
assert(tree.nodes.items(.tag)[node] == .ArrayInitDot);
const data = tree.nodes.items(.data)[node];
return .{
@@ -1055,7 +1061,7 @@ pub const Tree = struct {
};
}
pub fn arrayInit(tree: Tree, node: Node.Index) Full.ArrayInit {
pub fn arrayInit(tree: Tree, node: Node.Index) full.ArrayInit {
assert(tree.nodes.items(.tag)[node] == .ArrayInit);
const data = tree.nodes.items(.data)[node];
const elem_range = tree.extraData(data.rhs, Node.SubRange);
@@ -1068,7 +1074,7 @@ pub const Tree = struct {
};
}
pub fn arrayType(tree: Tree, node: Node.Index) Full.ArrayType {
pub fn arrayType(tree: Tree, node: Node.Index) full.ArrayType {
assert(tree.nodes.items(.tag)[node] == .ArrayType);
const data = tree.nodes.items(.data)[node];
return .{
@@ -1081,7 +1087,7 @@ pub const Tree = struct {
};
}
pub fn arrayTypeSentinel(tree: Tree, node: Node.Index) Full.ArrayType {
pub fn arrayTypeSentinel(tree: Tree, node: Node.Index) full.ArrayType {
assert(tree.nodes.items(.tag)[node] == .ArrayTypeSentinel);
const data = tree.nodes.items(.data)[node];
const extra = tree.extraData(data.rhs, Node.ArrayTypeSentinel);
@@ -1095,7 +1101,7 @@ pub const Tree = struct {
};
}
pub fn ptrTypeAligned(tree: Tree, node: Node.Index) Full.PtrType {
pub fn ptrTypeAligned(tree: Tree, node: Node.Index) full.PtrType {
assert(tree.nodes.items(.tag)[node] == .PtrTypeAligned);
const data = tree.nodes.items(.data)[node];
return tree.fullPtrType(.{
@@ -1108,7 +1114,7 @@ pub const Tree = struct {
});
}
pub fn ptrTypeSentinel(tree: Tree, node: Node.Index) Full.PtrType {
pub fn ptrTypeSentinel(tree: Tree, node: Node.Index) full.PtrType {
assert(tree.nodes.items(.tag)[node] == .PtrTypeSentinel);
const data = tree.nodes.items(.data)[node];
return tree.fullPtrType(.{
@@ -1121,7 +1127,7 @@ pub const Tree = struct {
});
}
pub fn ptrType(tree: Tree, node: Node.Index) Full.PtrType {
pub fn ptrType(tree: Tree, node: Node.Index) full.PtrType {
assert(tree.nodes.items(.tag)[node] == .PtrType);
const data = tree.nodes.items(.data)[node];
const extra = tree.extraData(data.lhs, Node.PtrType);
@@ -1135,7 +1141,7 @@ pub const Tree = struct {
});
}
pub fn ptrTypeBitRange(tree: Tree, node: Node.Index) Full.PtrType {
pub fn ptrTypeBitRange(tree: Tree, node: Node.Index) full.PtrType {
assert(tree.nodes.items(.tag)[node] == .PtrTypeBitRange);
const data = tree.nodes.items(.data)[node];
const extra = tree.extraData(data.lhs, Node.PtrTypeBitRange);
@@ -1149,7 +1155,7 @@ pub const Tree = struct {
});
}
pub fn sliceOpen(tree: Tree, node: Node.Index) Full.Slice {
pub fn sliceOpen(tree: Tree, node: Node.Index) full.Slice {
assert(tree.nodes.items(.tag)[node] == .SliceOpen);
const data = tree.nodes.items(.data)[node];
return .{
@@ -1163,7 +1169,7 @@ pub const Tree = struct {
};
}
pub fn slice(tree: Tree, node: Node.Index) Full.Slice {
pub fn slice(tree: Tree, node: Node.Index) full.Slice {
assert(tree.nodes.items(.tag)[node] == .Slice);
const data = tree.nodes.items(.data)[node];
const extra = tree.extraData(data.rhs, Node.Slice);
@@ -1178,7 +1184,7 @@ pub const Tree = struct {
};
}
pub fn sliceSentinel(tree: Tree, node: Node.Index) Full.Slice {
pub fn sliceSentinel(tree: Tree, node: Node.Index) full.Slice {
assert(tree.nodes.items(.tag)[node] == .SliceSentinel);
const data = tree.nodes.items(.data)[node];
const extra = tree.extraData(data.rhs, Node.SliceSentinel);
@@ -1193,7 +1199,7 @@ pub const Tree = struct {
};
}
pub fn containerDeclTwo(tree: Tree, buffer: *[2]Node.Index, node: Node.Index) Full.ContainerDecl {
pub fn containerDeclTwo(tree: Tree, buffer: *[2]Node.Index, node: Node.Index) full.ContainerDecl {
assert(tree.nodes.items(.tag)[node] == .ContainerDeclTwo or
tree.nodes.items(.tag)[node] == .ContainerDeclTwoComma);
const data = tree.nodes.items(.data)[node];
@@ -1212,7 +1218,7 @@ pub const Tree = struct {
});
}
pub fn containerDecl(tree: Tree, node: Node.Index) Full.ContainerDecl {
pub fn containerDecl(tree: Tree, node: Node.Index) full.ContainerDecl {
assert(tree.nodes.items(.tag)[node] == .ContainerDecl or
tree.nodes.items(.tag)[node] == .ContainerDeclComma);
const data = tree.nodes.items(.data)[node];
@@ -1224,7 +1230,7 @@ pub const Tree = struct {
});
}
pub fn containerDeclArg(tree: Tree, node: Node.Index) Full.ContainerDecl {
pub fn containerDeclArg(tree: Tree, node: Node.Index) full.ContainerDecl {
assert(tree.nodes.items(.tag)[node] == .ContainerDeclArg or
tree.nodes.items(.tag)[node] == .ContainerDeclArgComma);
const data = tree.nodes.items(.data)[node];
@@ -1237,7 +1243,7 @@ pub const Tree = struct {
});
}
pub fn taggedUnionTwo(tree: Tree, buffer: *[2]Node.Index, node: Node.Index) Full.ContainerDecl {
pub fn taggedUnionTwo(tree: Tree, buffer: *[2]Node.Index, node: Node.Index) full.ContainerDecl {
assert(tree.nodes.items(.tag)[node] == .TaggedUnionTwo or
tree.nodes.items(.tag)[node] == .TaggedUnionTwoComma);
const data = tree.nodes.items(.data)[node];
@@ -1257,7 +1263,7 @@ pub const Tree = struct {
});
}
pub fn taggedUnion(tree: Tree, node: Node.Index) Full.ContainerDecl {
pub fn taggedUnion(tree: Tree, node: Node.Index) full.ContainerDecl {
assert(tree.nodes.items(.tag)[node] == .TaggedUnion or
tree.nodes.items(.tag)[node] == .TaggedUnionComma);
const data = tree.nodes.items(.data)[node];
@@ -1270,7 +1276,7 @@ pub const Tree = struct {
});
}
pub fn taggedUnionEnumTag(tree: Tree, node: Node.Index) Full.ContainerDecl {
pub fn taggedUnionEnumTag(tree: Tree, node: Node.Index) full.ContainerDecl {
assert(tree.nodes.items(.tag)[node] == .TaggedUnionEnumTag or
tree.nodes.items(.tag)[node] == .TaggedUnionEnumTagComma);
const data = tree.nodes.items(.data)[node];
@@ -1284,7 +1290,7 @@ pub const Tree = struct {
});
}
pub fn switchCaseOne(tree: Tree, node: Node.Index) Full.SwitchCase {
pub fn switchCaseOne(tree: Tree, node: Node.Index) full.SwitchCase {
const data = &tree.nodes.items(.data)[node];
return tree.fullSwitchCase(.{
.values = if (data.lhs == 0) &.{} else @ptrCast([*]Node.Index, &data.lhs)[0..1],
@@ -1293,7 +1299,7 @@ pub const Tree = struct {
});
}
pub fn switchCase(tree: Tree, node: Node.Index) Full.SwitchCase {
pub fn switchCase(tree: Tree, node: Node.Index) full.SwitchCase {
const data = tree.nodes.items(.data)[node];
const extra = tree.extraData(data.lhs, Node.SubRange);
return tree.fullSwitchCase(.{
@@ -1303,9 +1309,30 @@ pub const Tree = struct {
});
}
fn fullVarDecl(tree: Tree, info: Full.VarDecl.Ast) Full.VarDecl {
pub fn asmSimple(tree: Tree, node: Node.Index) full.Asm {
const data = tree.nodes.items(.data)[node];
return tree.fullAsm(.{
.asm_token = tree.nodes.items(.main_token)[node],
.template = data.lhs,
.items = &.{},
.rparen = data.rhs,
});
}
pub fn asmFull(tree: Tree, node: Node.Index) full.Asm {
const data = tree.nodes.items(.data)[node];
const extra = tree.extraData(data.rhs, Node.Asm);
return tree.fullAsm(.{
.asm_token = tree.nodes.items(.main_token)[node],
.template = data.lhs,
.items = tree.extra_data[extra.items_start..extra.items_end],
.rparen = extra.rparen,
});
}
fn fullVarDecl(tree: Tree, info: full.VarDecl.Ast) full.VarDecl {
const token_tags = tree.tokens.items(.tag);
var result: Full.VarDecl = .{
var result: full.VarDecl = .{
.ast = info,
.visib_token = null,
.extern_export_token = null,
@@ -1328,9 +1355,9 @@ pub const Tree = struct {
return result;
}
fn fullIf(tree: Tree, info: Full.If.Ast) Full.If {
fn fullIf(tree: Tree, info: full.If.Ast) full.If {
const token_tags = tree.tokens.items(.tag);
var result: Full.If = .{
var result: full.If = .{
.ast = info,
.payload_token = null,
.error_token = null,
@@ -1353,9 +1380,9 @@ pub const Tree = struct {
return result;
}
fn fullContainerField(tree: Tree, info: Full.ContainerField.Ast) Full.ContainerField {
fn fullContainerField(tree: Tree, info: full.ContainerField.Ast) full.ContainerField {
const token_tags = tree.tokens.items(.tag);
var result: Full.ContainerField = .{
var result: full.ContainerField = .{
.ast = info,
.comptime_token = null,
};
@@ -1367,27 +1394,27 @@ pub const Tree = struct {
return result;
}
fn fullFnProto(tree: Tree, info: Full.FnProto.Ast) Full.FnProto {
fn fullFnProto(tree: Tree, info: full.FnProto.Ast) full.FnProto {
const token_tags = tree.tokens.items(.tag);
var result: Full.FnProto = .{
var result: full.FnProto = .{
.ast = info,
};
return result;
}
fn fullStructInit(tree: Tree, info: Full.StructInit.Ast) Full.StructInit {
fn fullStructInit(tree: Tree, info: full.StructInit.Ast) full.StructInit {
const token_tags = tree.tokens.items(.tag);
var result: Full.StructInit = .{
var result: full.StructInit = .{
.ast = info,
};
return result;
}
fn fullPtrType(tree: Tree, info: Full.PtrType.Ast) Full.PtrType {
fn fullPtrType(tree: Tree, info: full.PtrType.Ast) full.PtrType {
const token_tags = tree.tokens.items(.tag);
// TODO: looks like stage1 isn't quite smart enough to handle enum
// literals in some places here
const Kind = Full.PtrType.Kind;
const Kind = full.PtrType.Kind;
const kind: Kind = switch (token_tags[info.main_token]) {
.Asterisk => switch (token_tags[info.main_token + 1]) {
.RBracket => .many,
@@ -1402,7 +1429,7 @@ pub const Tree = struct {
},
else => unreachable,
};
var result: Full.PtrType = .{
var result: full.PtrType = .{
.kind = kind,
.allowzero_token = null,
.const_token = null,
@@ -1441,9 +1468,9 @@ pub const Tree = struct {
return result;
}
fn fullContainerDecl(tree: Tree, info: Full.ContainerDecl.Ast) Full.ContainerDecl {
fn fullContainerDecl(tree: Tree, info: full.ContainerDecl.Ast) full.ContainerDecl {
const token_tags = tree.tokens.items(.tag);
var result: Full.ContainerDecl = .{
var result: full.ContainerDecl = .{
.ast = info,
.layout_token = null,
};
@@ -1454,9 +1481,9 @@ pub const Tree = struct {
return result;
}
fn fullSwitchCase(tree: Tree, info: Full.SwitchCase.Ast) Full.SwitchCase {
fn fullSwitchCase(tree: Tree, info: full.SwitchCase.Ast) full.SwitchCase {
const token_tags = tree.tokens.items(.tag);
var result: Full.SwitchCase = .{
var result: full.SwitchCase = .{
.ast = info,
.payload_token = null,
};
@@ -1465,10 +1492,67 @@ pub const Tree = struct {
}
return result;
}
fn fullAsm(tree: Tree, info: full.Asm.Ast) full.Asm {
const token_tags = tree.tokens.items(.tag);
const node_tags = tree.nodes.items(.tag);
var result: full.Asm = .{
.ast = info,
.volatile_token = null,
.inputs = &.{},
.outputs = &.{},
.first_clobber = null,
};
if (token_tags[info.asm_token + 1] == .Keyword_volatile) {
result.volatile_token = info.asm_token + 1;
}
const outputs_end: usize = for (info.items) |item, i| {
switch (node_tags[item]) {
.AsmOutput => continue,
else => break i,
}
} else info.items.len;
result.outputs = info.items[0..outputs_end];
result.inputs = info.items[outputs_end..];
if (info.items.len == 0) {
// asm ("foo" ::: "a", "b");
const template_token = tree.lastToken(info.template);
if (token_tags[template_token + 1] == .Colon and
token_tags[template_token + 2] == .Colon and
token_tags[template_token + 3] == .Colon and
token_tags[template_token + 4] == .StringLiteral)
{
result.first_clobber = template_token + 4;
}
} else if (result.inputs.len != 0) {
// asm ("foo" :: [_] "" (y) : "a", "b");
const last_input = result.inputs[result.inputs.len - 1];
const rparen = tree.lastToken(last_input);
if (token_tags[rparen + 1] == .Colon and
token_tags[rparen + 2] == .StringLiteral)
{
result.first_clobber = rparen + 2;
}
} else {
// asm ("foo" : [_] "" (x) :: "a", "b");
const last_output = result.outputs[result.outputs.len - 1];
const rparen = tree.lastToken(last_output);
if (token_tags[rparen + 1] == .Colon and
token_tags[rparen + 2] == .Colon and
token_tags[rparen + 3] == .StringLiteral)
{
result.first_clobber = rparen + 3;
}
}
return result;
}
};
/// Fully assembled AST node information.
pub const Full = struct {
pub const full = struct {
pub const VarDecl = struct {
visib_token: ?TokenIndex,
extern_export_token: ?TokenIndex,
@@ -1624,6 +1708,21 @@ pub const Full = struct {
target_expr: Node.Index,
};
};
pub const Asm = struct {
ast: Ast,
volatile_token: ?TokenIndex,
first_clobber: ?TokenIndex,
outputs: []const Node.Index,
inputs: []const Node.Index,
pub const Ast = struct {
asm_token: TokenIndex,
template: Node.Index,
items: []const Node.Index,
rparen: TokenIndex,
};
};
};
pub const Error = union(enum) {
@@ -2234,15 +2333,15 @@ pub const Node = struct {
Block,
/// Same as BlockTwo but there is known to be a semicolon before the rbrace.
BlockSemicolon,
/// `asm(lhs)`. rhs unused.
/// `asm(lhs)`. rhs is the token index of the rparen.
AsmSimple,
/// `asm(lhs, a)`. `sub_range_list[rhs]`.
/// `asm(lhs, a)`. `Asm[rhs]`.
Asm,
/// `[a] "b" (c)`. lhs is string literal token index, rhs is 0.
/// `[a] "b" (-> rhs)`. lhs is the string literal token index, rhs is type expr.
/// `[a] "b" (c)`. lhs is 0, rhs is token index of the rparen.
/// `[a] "b" (-> lhs)`. rhs is token index of the rparen.
/// main_token is `a`.
AsmOutput,
/// `[a] "b" (rhs)`. lhs is string literal token index.
/// `[a] "b" (lhs)`. rhs is token index of the rparen.
/// main_token is `a`.
AsmInput,
/// `error.a`. lhs is token index of `.`. rhs is token index of `a`.
@@ -2355,4 +2454,11 @@ pub const Node = struct {
/// Populated if callconv(A) is present.
callconv_expr: Index,
};
pub const Asm = struct {
items_start: Index,
items_end: Index,
/// Needed to make lastToken() work.
rparen: TokenIndex,
};
};

View File

@@ -472,7 +472,7 @@ const Parser = struct {
/// TestDecl <- KEYWORD_test STRINGLITERALSINGLE? Block
fn expectTestDecl(p: *Parser) !Node.Index {
const test_token = try p.expectToken(.Keyword_test);
const test_token = p.assertToken(.Keyword_test);
const name_token = p.eatToken(.StringLiteral);
const block_node = try p.parseBlock();
if (block_node == 0) return p.fail(.{ .ExpectedLBrace = .{ .token = p.tok_i } });
@@ -739,7 +739,7 @@ const Parser = struct {
/// ContainerField <- KEYWORD_comptime? IDENTIFIER (COLON TypeExpr ByteAlign?)? (EQUAL Expr)?
fn expectContainerField(p: *Parser) !Node.Index {
const comptime_token = p.eatToken(.Keyword_comptime);
const name_token = try p.expectToken(.Identifier);
const name_token = p.assertToken(.Identifier);
var align_expr: Node.Index = 0;
var type_expr: Node.Index = 0;
@@ -1846,7 +1846,7 @@ const Parser = struct {
/// / CurlySuffixExpr
fn parsePrimaryExpr(p: *Parser) !Node.Index {
switch (p.token_tags[p.tok_i]) {
.Keyword_asm => return p.parseAsmExpr(),
.Keyword_asm => return p.expectAsmExpr(),
.Keyword_if => return p.parseIfExpr(),
.Keyword_break => {
p.tok_i += 1;
@@ -2910,19 +2910,19 @@ const Parser = struct {
/// StringList <- (STRINGLITERAL COMMA)* STRINGLITERAL?
/// AsmOutputList <- (AsmOutputItem COMMA)* AsmOutputItem?
/// AsmInputList <- (AsmInputItem COMMA)* AsmInputItem?
fn parseAsmExpr(p: *Parser) !Node.Index {
fn expectAsmExpr(p: *Parser) !Node.Index {
const asm_token = p.assertToken(.Keyword_asm);
_ = p.eatToken(.Keyword_volatile);
_ = try p.expectToken(.LParen);
const template = try p.expectExpr();
if (p.eatToken(.RParen)) |_| {
if (p.eatToken(.RParen)) |rparen| {
return p.addNode(.{
.tag = .AsmSimple,
.main_token = asm_token,
.data = .{
.lhs = template,
.rhs = undefined,
.rhs = rparen,
},
});
}
@@ -2981,16 +2981,17 @@ const Parser = struct {
}
}
}
_ = try p.expectToken(.RParen);
const rparen = try p.expectToken(.RParen);
const span = try p.listToSpan(list.items);
return p.addNode(.{
.tag = .Asm,
.main_token = asm_token,
.data = .{
.lhs = template,
.rhs = try p.addExtra(Node.SubRange{
.start = span.start,
.end = span.end,
.rhs = try p.addExtra(Node.Asm{
.items_start = span.start,
.items_end = span.end,
.rparen = rparen,
}),
},
});
@@ -3001,16 +3002,23 @@ const Parser = struct {
_ = p.eatToken(.LBracket) orelse return null_node;
const identifier = try p.expectToken(.Identifier);
_ = try p.expectToken(.RBracket);
const constraint = try p.expectToken(.StringLiteral);
_ = try p.expectToken(.StringLiteral);
_ = try p.expectToken(.LParen);
const rhs: Node.Index = if (p.eatToken(.Arrow)) |_| try p.expectTypeExpr() else null_node;
_ = try p.expectToken(.RParen);
const type_expr: Node.Index = blk: {
if (p.eatToken(.Arrow)) |_| {
break :blk try p.expectTypeExpr();
} else {
_ = try p.expectToken(.Identifier);
break :blk null_node;
}
};
const rparen = try p.expectToken(.RParen);
return p.addNode(.{
.tag = .AsmOutput,
.main_token = identifier,
.data = .{
.lhs = constraint,
.rhs = rhs,
.lhs = type_expr,
.rhs = rparen,
},
});
}
@@ -3020,16 +3028,16 @@ const Parser = struct {
_ = p.eatToken(.LBracket) orelse return null_node;
const identifier = try p.expectToken(.Identifier);
_ = try p.expectToken(.RBracket);
const constraint = try p.expectToken(.StringLiteral);
_ = try p.expectToken(.StringLiteral);
_ = try p.expectToken(.LParen);
const expr = try p.expectExpr();
_ = try p.expectToken(.RParen);
const rparen = try p.expectToken(.RParen);
return p.addNode(.{
.tag = .AsmInput,
.main_token = identifier,
.data = .{
.lhs = constraint,
.rhs = expr,
.lhs = expr,
.rhs = rparen,
},
});
}

View File

@@ -313,30 +313,30 @@ test "zig fmt: builtin call with trailing comma" {
);
}
//test "zig fmt: asm expression with comptime content" {
// try testCanonical(
// \\comptime {
// \\ asm ("foo" ++ "bar");
// \\}
// \\pub fn main() void {
// \\ asm volatile ("foo" ++ "bar");
// \\ asm volatile ("foo" ++ "bar"
// \\ : [_] "" (x)
// \\ );
// \\ asm volatile ("foo" ++ "bar"
// \\ : [_] "" (x)
// \\ : [_] "" (y)
// \\ );
// \\ asm volatile ("foo" ++ "bar"
// \\ : [_] "" (x)
// \\ : [_] "" (y)
// \\ : "h", "e", "l", "l", "o"
// \\ );
// \\}
// \\
// );
//}
//
test "zig fmt: asm expression with comptime content" {
try testCanonical(
\\comptime {
\\ asm ("foo" ++ "bar");
\\}
\\pub fn main() void {
\\ asm volatile ("foo" ++ "bar");
\\ asm volatile ("foo" ++ "bar"
\\ : [_] "" (x)
\\ );
\\ asm volatile ("foo" ++ "bar"
\\ : [_] "" (x)
\\ : [_] "" (y)
\\ );
\\ asm volatile ("foo" ++ "bar"
\\ : [_] "" (x)
\\ : [_] "" (y)
\\ : "h", "e", "l", "l", "o"
\\ );
\\}
\\
);
}
//test "zig fmt: anytype struct field" {
// try testCanonical(
// \\pub const Pointer = struct {

View File

@@ -816,118 +816,8 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
.IfSimple => return renderIf(ais, tree, tree.ifSimple(node), space),
.If => return renderIf(ais, tree, tree.ifFull(node), space),
.Asm => unreachable, // TODO
.AsmSimple => unreachable, // TODO
.AsmOutput => unreachable, // TODO
.AsmInput => unreachable, // TODO
//.Asm => {
// const asm_node = @fieldParentPtr(ast.Node.Asm, "base", base);
// try renderToken(ais, tree, asm_node.asm_token, Space.Space); // asm
// if (asm_node.volatile_token) |volatile_token| {
// try renderToken(ais, tree, volatile_token, Space.Space); // volatile
// try renderToken(ais, tree, tree.nextToken(volatile_token), Space.None); // (
// } else {
// try renderToken(ais, tree, tree.nextToken(asm_node.asm_token), Space.None); // (
// }
// asmblk: {
// ais.pushIndent();
// defer ais.popIndent();
// if (asm_node.outputs.len == 0 and asm_node.inputs.len == 0 and asm_node.clobbers.len == 0) {
// try renderExpression(ais, tree, asm_node.template, Space.None);
// break :asmblk;
// }
// try renderExpression(ais, tree, asm_node.template, Space.Newline);
// ais.setIndentDelta(asm_indent_delta);
// defer ais.setIndentDelta(indent_delta);
// const colon1 = tree.nextToken(asm_node.template.lastToken());
// const colon2 = if (asm_node.outputs.len == 0) blk: {
// try renderToken(ais, tree, colon1, Space.Newline); // :
// break :blk tree.nextToken(colon1);
// } else blk: {
// try renderToken(ais, tree, colon1, Space.Space); // :
// ais.pushIndent();
// defer ais.popIndent();
// for (asm_node.outputs) |*asm_output, i| {
// if (i + 1 < asm_node.outputs.len) {
// const next_asm_output = asm_node.outputs[i + 1];
// try renderAsmOutput(allocator, ais, tree, asm_output, Space.None);
// const comma = tree.prevToken(next_asm_output.firstToken());
// try renderToken(ais, tree, comma, Space.Newline); // ,
// try renderExtraNewlineToken(ais, tree, next_asm_output.firstToken());
// } else if (asm_node.inputs.len == 0 and asm_node.clobbers.len == 0) {
// try renderAsmOutput(allocator, ais, tree, asm_output, Space.Newline);
// break :asmblk;
// } else {
// try renderAsmOutput(allocator, ais, tree, asm_output, Space.Newline);
// const comma_or_colon = tree.nextToken(asm_output.lastToken());
// break :blk switch (tree.token_tags[comma_or_colon]) {
// .Comma => tree.nextToken(comma_or_colon),
// else => comma_or_colon,
// };
// }
// }
// unreachable;
// };
// const colon3 = if (asm_node.inputs.len == 0) blk: {
// try renderToken(ais, tree, colon2, Space.Newline); // :
// break :blk tree.nextToken(colon2);
// } else blk: {
// try renderToken(ais, tree, colon2, Space.Space); // :
// ais.pushIndent();
// defer ais.popIndent();
// for (asm_node.inputs) |*asm_input, i| {
// if (i + 1 < asm_node.inputs.len) {
// const next_asm_input = &asm_node.inputs[i + 1];
// try renderAsmInput(allocator, ais, tree, asm_input, Space.None);
// const comma = tree.prevToken(next_asm_input.firstToken());
// try renderToken(ais, tree, comma, Space.Newline); // ,
// try renderExtraNewlineToken(ais, tree, next_asm_input.firstToken());
// } else if (asm_node.clobbers.len == 0) {
// try renderAsmInput(allocator, ais, tree, asm_input, Space.Newline);
// break :asmblk;
// } else {
// try renderAsmInput(allocator, ais, tree, asm_input, Space.Newline);
// const comma_or_colon = tree.nextToken(asm_input.lastToken());
// break :blk switch (tree.token_tags[comma_or_colon]) {
// .Comma => tree.nextToken(comma_or_colon),
// else => comma_or_colon,
// };
// }
// }
// unreachable;
// };
// try renderToken(ais, tree, colon3, Space.Space); // :
// ais.pushIndent();
// defer ais.popIndent();
// for (asm_node.clobbers) |clobber_node, i| {
// if (i + 1 >= asm_node.clobbers.len) {
// try renderExpression(ais, tree, clobber_node, Space.Newline);
// break :asmblk;
// } else {
// try renderExpression(ais, tree, clobber_node, Space.None);
// const comma = tree.nextToken(clobber_node.lastToken());
// try renderToken(ais, tree, comma, Space.Space); // ,
// }
// }
// }
// return renderToken(ais, tree, asm_node.rparen, space);
//},
.AsmSimple => return renderAsm(ais, tree, tree.asmSimple(node), space),
.Asm => return renderAsm(ais, tree, tree.asmFull(node), space),
.EnumLiteral => {
try renderToken(ais, tree, main_tokens[node] - 1, .None); // .
@@ -945,6 +835,8 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
.AlignedVarDecl => unreachable,
.UsingNamespace => unreachable,
.TestDecl => unreachable,
.AsmOutput => unreachable,
.AsmInput => unreachable,
}
}
@@ -952,7 +844,7 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
fn renderArrayType(
ais: *Ais,
tree: ast.Tree,
array_type: ast.Full.ArrayType,
array_type: ast.full.ArrayType,
space: Space,
) Error!void {
try renderToken(ais, tree, array_type.ast.lbracket, .None); // lbracket
@@ -968,7 +860,7 @@ fn renderArrayType(
fn renderPtrType(
ais: *Ais,
tree: ast.Tree,
ptr_type: ast.Full.PtrType,
ptr_type: ast.full.PtrType,
space: Space,
) Error!void {
switch (ptr_type.kind) {
@@ -1040,7 +932,7 @@ fn renderPtrType(
fn renderSlice(
ais: *Ais,
tree: ast.Tree,
slice: ast.Full.Slice,
slice: ast.full.Slice,
space: Space,
) Error!void {
const node_tags = tree.nodes.items(.tag);
@@ -1072,48 +964,56 @@ fn renderSlice(
}
fn renderAsmOutput(
allocator: *mem.Allocator,
ais: *Ais,
tree: ast.Tree,
asm_output: *const ast.Node.Asm.Output,
asm_output: ast.Node.Index,
space: Space,
) Error!void {
try ais.writer().writeAll("[");
try renderExpression(ais, tree, asm_output.symbolic_name, Space.None);
try ais.writer().writeAll("] ");
try renderExpression(ais, tree, asm_output.constraint, Space.None);
try ais.writer().writeAll(" (");
const token_tags = tree.tokens.items(.tag);
const node_tags = tree.nodes.items(.tag);
const main_tokens = tree.nodes.items(.main_token);
const datas = tree.nodes.items(.data);
assert(node_tags[asm_output] == .AsmOutput);
const symbolic_name = main_tokens[asm_output];
switch (asm_output.kind) {
.Variable => |variable_name| {
try renderExpression(ais, tree, &variable_name.base, Space.None);
},
.Return => |return_type| {
try ais.writer().writeAll("-> ");
try renderExpression(ais, tree, return_type, Space.None);
},
try renderToken(ais, tree, symbolic_name - 1, .None); // lbracket
try renderToken(ais, tree, symbolic_name, .None); // ident
try renderToken(ais, tree, symbolic_name + 1, .Space); // rbracket
try renderToken(ais, tree, symbolic_name + 2, .Space); // "constraint"
try renderToken(ais, tree, symbolic_name + 3, .None); // lparen
if (token_tags[symbolic_name + 4] == .Arrow) {
try renderToken(ais, tree, symbolic_name + 4, .Space); // ->
try renderExpression(ais, tree, datas[asm_output].lhs, Space.None);
return renderToken(ais, tree, datas[asm_output].rhs, space); // rparen
} else {
try renderToken(ais, tree, symbolic_name + 4, .None); // ident
return renderToken(ais, tree, symbolic_name + 5, space); // rparen
}
return renderToken(ais, tree, asm_output.lastToken(), space); // )
}
fn renderAsmInput(
allocator: *mem.Allocator,
ais: *Ais,
tree: ast.Tree,
asm_input: *const ast.Node.Asm.Input,
asm_input: ast.Node.Index,
space: Space,
) Error!void {
try ais.writer().writeAll("[");
try renderExpression(ais, tree, asm_input.symbolic_name, Space.None);
try ais.writer().writeAll("] ");
try renderExpression(ais, tree, asm_input.constraint, Space.None);
try ais.writer().writeAll(" (");
try renderExpression(ais, tree, asm_input.expr, Space.None);
return renderToken(ais, tree, asm_input.lastToken(), space); // )
const node_tags = tree.nodes.items(.tag);
const main_tokens = tree.nodes.items(.main_token);
const datas = tree.nodes.items(.data);
assert(node_tags[asm_input] == .AsmInput);
const symbolic_name = main_tokens[asm_input];
try renderToken(ais, tree, symbolic_name - 1, .None); // lbracket
try renderToken(ais, tree, symbolic_name, .None); // ident
try renderToken(ais, tree, symbolic_name + 1, .Space); // rbracket
try renderToken(ais, tree, symbolic_name + 2, .Space); // "constraint"
try renderToken(ais, tree, symbolic_name + 3, .None); // lparen
try renderExpression(ais, tree, datas[asm_input].lhs, Space.None);
return renderToken(ais, tree, datas[asm_input].rhs, space); // rparen
}
fn renderVarDecl(ais: *Ais, tree: ast.Tree, var_decl: ast.Full.VarDecl) Error!void {
fn renderVarDecl(ais: *Ais, tree: ast.Tree, var_decl: ast.full.VarDecl) Error!void {
if (var_decl.visib_token) |visib_token| {
try renderToken(ais, tree, visib_token, Space.Space); // pub
}
@@ -1200,7 +1100,7 @@ fn renderVarDecl(ais: *Ais, tree: ast.Tree, var_decl: ast.Full.VarDecl) Error!vo
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 {
fn renderIf(ais: *Ais, tree: ast.Tree, if_node: ast.full.If, space: Space) Error!void {
const node_tags = tree.nodes.items(.tag);
const token_tags = tree.tokens.items(.tag);
@@ -1334,7 +1234,7 @@ fn renderIf(ais: *Ais, tree: ast.Tree, if_node: ast.Full.If, space: Space) Error
fn renderContainerField(
ais: *Ais,
tree: ast.Tree,
field: ast.Full.ContainerField,
field: ast.full.ContainerField,
space: Space,
) Error!void {
const main_tokens = tree.nodes.items(.main_token);
@@ -1430,7 +1330,7 @@ fn renderBuiltinCall(
}
}
fn renderFnProto(ais: *Ais, tree: ast.Tree, fn_proto: ast.Full.FnProto, space: Space) Error!void {
fn renderFnProto(ais: *Ais, tree: ast.Tree, fn_proto: ast.full.FnProto, space: Space) Error!void {
const token_tags = tree.tokens.items(.tag);
const token_starts = tree.tokens.items(.start);
@@ -1618,7 +1518,7 @@ fn renderFnProto(ais: *Ais, tree: ast.Tree, fn_proto: ast.Full.FnProto, space: S
fn renderSwitchCase(
ais: *Ais,
tree: ast.Tree,
switch_case: ast.Full.SwitchCase,
switch_case: ast.full.SwitchCase,
space: Space,
) Error!void {
const token_tags = tree.tokens.items(.tag);
@@ -1709,7 +1609,7 @@ fn renderBlock(
fn renderStructInit(
ais: *Ais,
tree: ast.Tree,
struct_init: ast.Full.StructInit,
struct_init: ast.full.StructInit,
space: Space,
) Error!void {
const token_tags = tree.tokens.items(.tag);
@@ -1763,7 +1663,7 @@ fn renderStructInit(
fn renderArrayInit(
ais: *Ais,
tree: ast.Tree,
array_init: ast.Full.ArrayInit,
array_init: ast.full.ArrayInit,
space: Space,
) Error!void {
const token_tags = tree.tokens.items(.tag);
@@ -1809,7 +1709,7 @@ fn renderArrayInit(
fn renderContainerDecl(
ais: *Ais,
tree: ast.Tree,
container_decl: ast.Full.ContainerDecl,
container_decl: ast.full.ContainerDecl,
space: Space,
) Error!void {
const token_tags = tree.tokens.items(.tag);
@@ -1894,6 +1794,135 @@ fn renderContainerDecl(
return renderToken(ais, tree, rbrace, space); // rbrace
}
fn renderAsm(
ais: *Ais,
tree: ast.Tree,
asm_node: ast.full.Asm,
space: Space,
) Error!void {
const token_tags = tree.tokens.items(.tag);
try renderToken(ais, tree, asm_node.ast.asm_token, .Space); // asm
if (asm_node.volatile_token) |volatile_token| {
try renderToken(ais, tree, volatile_token, .Space); // volatile
try renderToken(ais, tree, volatile_token + 1, .None); // lparen
} else {
try renderToken(ais, tree, asm_node.ast.asm_token + 1, .None); // lparen
}
if (asm_node.ast.items.len == 0) {
try renderExpression(ais, tree, asm_node.ast.template, .None);
if (asm_node.first_clobber) |first_clobber| {
// asm ("foo" ::: "a", "b")
var tok_i = first_clobber;
while (true) : (tok_i += 1) {
try renderToken(ais, tree, tok_i, .None);
tok_i += 1;
switch (token_tags[tok_i]) {
.RParen => return renderToken(ais, tree, tok_i, space),
.Comma => try renderToken(ais, tree, tok_i, .Space),
else => unreachable,
}
}
} else {
// asm ("foo")
return renderToken(ais, tree, asm_node.ast.rparen, space); // rparen
}
}
ais.pushIndent();
try renderExpression(ais, tree, asm_node.ast.template, .Newline);
ais.setIndentDelta(asm_indent_delta);
const colon1 = tree.lastToken(asm_node.ast.template) + 1;
const colon2 = if (asm_node.outputs.len == 0) colon2: {
try renderToken(ais, tree, colon1, .Newline); // :
break :colon2 colon1 + 1;
} else colon2: {
try renderToken(ais, tree, colon1, .Space); // :
ais.pushIndent();
for (asm_node.outputs) |asm_output, i| {
if (i + 1 < asm_node.outputs.len) {
const next_asm_output = asm_node.outputs[i + 1];
try renderAsmOutput(ais, tree, asm_output, .None);
const comma = tree.firstToken(next_asm_output) - 1;
try renderToken(ais, tree, comma, .Newline); // ,
try renderExtraNewlineToken(ais, tree, tree.firstToken(next_asm_output));
} else if (asm_node.inputs.len == 0 and asm_node.first_clobber == null) {
try renderAsmOutput(ais, tree, asm_output, .Newline);
ais.popIndent();
ais.setIndentDelta(indent_delta);
ais.popIndent();
return renderToken(ais, tree, asm_node.ast.rparen, space); // rparen
} else {
try renderAsmOutput(ais, tree, asm_output, .Newline);
const comma_or_colon = tree.lastToken(asm_output) + 1;
ais.popIndent();
break :colon2 switch (token_tags[comma_or_colon]) {
.Comma => comma_or_colon + 1,
else => comma_or_colon,
};
}
} else unreachable;
};
const colon3 = if (asm_node.inputs.len == 0) colon3: {
try renderToken(ais, tree, colon2, .Newline); // :
break :colon3 colon2 + 1;
} else colon3: {
try renderToken(ais, tree, colon2, .Space); // :
ais.pushIndent();
for (asm_node.inputs) |asm_input, i| {
if (i + 1 < asm_node.inputs.len) {
const next_asm_input = asm_node.inputs[i + 1];
try renderAsmInput(ais, tree, asm_input, .None);
const first_token = tree.firstToken(next_asm_input);
try renderToken(ais, tree, first_token - 1, .Newline); // ,
try renderExtraNewlineToken(ais, tree, first_token);
} else if (asm_node.first_clobber == null) {
try renderAsmInput(ais, tree, asm_input, .Newline);
ais.popIndent();
ais.setIndentDelta(indent_delta);
ais.popIndent();
return renderToken(ais, tree, asm_node.ast.rparen, space); // rparen
} else {
try renderAsmInput(ais, tree, asm_input, .Newline);
const comma_or_colon = tree.lastToken(asm_input) + 1;
ais.popIndent();
break :colon3 switch (token_tags[comma_or_colon]) {
.Comma => comma_or_colon + 1,
else => comma_or_colon,
};
}
}
unreachable;
};
try renderToken(ais, tree, colon3, .Space); // :
const first_clobber = asm_node.first_clobber.?;
var tok_i = first_clobber;
while (true) {
switch (token_tags[tok_i + 1]) {
.RParen => {
ais.setIndentDelta(indent_delta);
ais.popIndent();
try renderToken(ais, tree, tok_i, .Newline);
return renderToken(ais, tree, tok_i + 1, space);
},
.Comma => {
try renderToken(ais, tree, tok_i, .None);
try renderToken(ais, tree, tok_i + 1, .Space);
tok_i += 2;
},
else => unreachable,
}
} else unreachable; // TODO shouldn't need this on while(true)
}
/// Render an expression, and the comma that follows it, if it is present in the source.
fn renderExpressionComma(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Space) Error!void {
const token_tags = tree.tokens.items(.tag);