Commit b1d8a0a5a6
Changed files (4)
lib
lib/std/zig/ast.zig
@@ -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,
+ };
};
lib/std/zig/parse.zig
@@ -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,
},
});
}
lib/std/zig/parser_test.zig
@@ -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 {
lib/std/zig/render.zig
@@ -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(" (");
-
- 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);
- },
+ 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];
+
+ 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);