Source
pub fn firstToken(tree: Ast, node: Node.Index) TokenIndex {
var end_offset: u32 = 0;
var n = node;
while (true) switch (tree.nodeTag(n)) {
.root => return 0,
.test_decl,
.@"errdefer",
.@"defer",
.bool_not,
.negation,
.bit_not,
.negation_wrap,
.address_of,
.@"try",
.@"await",
.optional_type,
.@"switch",
.switch_comma,
.if_simple,
.@"if",
.@"suspend",
.@"resume",
.@"continue",
.@"break",
.@"return",
.anyframe_type,
.identifier,
.anyframe_literal,
.char_literal,
.number_literal,
.unreachable_literal,
.string_literal,
.multiline_string_literal,
.grouped_expression,
.builtin_call_two,
.builtin_call_two_comma,
.builtin_call,
.builtin_call_comma,
.error_set_decl,
.@"comptime",
.@"nosuspend",
.asm_simple,
.@"asm",
.array_type,
.array_type_sentinel,
.error_value,
=> return tree.nodeMainToken(n) - end_offset,
.array_init_dot,
.array_init_dot_comma,
.array_init_dot_two,
.array_init_dot_two_comma,
.struct_init_dot,
.struct_init_dot_comma,
.struct_init_dot_two,
.struct_init_dot_two_comma,
.enum_literal,
=> return tree.nodeMainToken(n) - 1 - end_offset,
.@"catch",
.equal_equal,
.bang_equal,
.less_than,
.greater_than,
.less_or_equal,
.greater_or_equal,
.assign_mul,
.assign_div,
.assign_mod,
.assign_add,
.assign_sub,
.assign_shl,
.assign_shl_sat,
.assign_shr,
.assign_bit_and,
.assign_bit_xor,
.assign_bit_or,
.assign_mul_wrap,
.assign_add_wrap,
.assign_sub_wrap,
.assign_mul_sat,
.assign_add_sat,
.assign_sub_sat,
.assign,
.merge_error_sets,
.mul,
.div,
.mod,
.array_mult,
.mul_wrap,
.mul_sat,
.add,
.sub,
.array_cat,
.add_wrap,
.sub_wrap,
.add_sat,
.sub_sat,
.shl,
.shl_sat,
.shr,
.bit_and,
.bit_xor,
.bit_or,
.@"orelse",
.bool_and,
.bool_or,
.slice_open,
.array_access,
.array_init_one,
.array_init_one_comma,
.switch_range,
.error_union,
=> n = tree.nodeData(n).node_and_node[0],
.for_range,
.call_one,
.call_one_comma,
.struct_init_one,
.struct_init_one_comma,
=> n = tree.nodeData(n).node_and_opt_node[0],
.field_access,
.unwrap_optional,
=> n = tree.nodeData(n).node_and_token[0],
.slice,
.slice_sentinel,
.array_init,
.array_init_comma,
.struct_init,
.struct_init_comma,
.call,
.call_comma,
=> n = tree.nodeData(n).node_and_extra[0],
.deref => n = tree.nodeData(n).node,
.assign_destructure => n = tree.assignDestructure(n).ast.variables[0],
.fn_decl,
.fn_proto_simple,
.fn_proto_multi,
.fn_proto_one,
.fn_proto,
=> {
var i = tree.nodeMainToken(n); // fn token
while (i > 0) {
i -= 1;
switch (tree.tokenTag(i)) {
.keyword_extern,
.keyword_export,
.keyword_pub,
.keyword_inline,
.keyword_noinline,
.string_literal,
=> continue,
else => return i + 1 - end_offset,
}
}
return i - end_offset;
},
.@"usingnamespace" => {
const main_token: TokenIndex = tree.nodeMainToken(n);
const has_visib_token = tree.isTokenPrecededByTags(main_token, &.{.keyword_pub});
end_offset += @intFromBool(has_visib_token);
return main_token - end_offset;
},
.async_call_one,
.async_call_one_comma,
=> {
end_offset += 1; // async token
n = tree.nodeData(n).node_and_opt_node[0];
},
.async_call,
.async_call_comma,
=> {
end_offset += 1; // async token
n = tree.nodeData(n).node_and_extra[0];
},
.container_field_init,
.container_field_align,
.container_field,
=> {
const name_token = tree.nodeMainToken(n);
const has_comptime_token = tree.isTokenPrecededByTags(name_token, &.{.keyword_comptime});
end_offset += @intFromBool(has_comptime_token);
return name_token - end_offset;
},
.global_var_decl,
.local_var_decl,
.simple_var_decl,
.aligned_var_decl,
=> {
var i = tree.nodeMainToken(n); // mut token
while (i > 0) {
i -= 1;
switch (tree.tokenTag(i)) {
.keyword_extern,
.keyword_export,
.keyword_comptime,
.keyword_pub,
.keyword_threadlocal,
.string_literal,
=> continue,
else => return i + 1 - end_offset,
}
}
return i - end_offset;
},
.block,
.block_semicolon,
.block_two,
.block_two_semicolon,
=> {
// Look for a label.
const lbrace = tree.nodeMainToken(n);
if (tree.isTokenPrecededByTags(lbrace, &.{ .identifier, .colon })) {
end_offset += 2;
}
return lbrace - end_offset;
},
.container_decl,
.container_decl_trailing,
.container_decl_two,
.container_decl_two_trailing,
.container_decl_arg,
.container_decl_arg_trailing,
.tagged_union,
.tagged_union_trailing,
.tagged_union_two,
.tagged_union_two_trailing,
.tagged_union_enum_tag,
.tagged_union_enum_tag_trailing,
=> {
const main_token = tree.nodeMainToken(n);
switch (tree.tokenTag(main_token -| 1)) {
.keyword_packed, .keyword_extern => end_offset += 1,
else => {},
}
return main_token - end_offset;
},
.ptr_type_aligned,
.ptr_type_sentinel,
.ptr_type,
.ptr_type_bit_range,
=> return tree.nodeMainToken(n) - end_offset,
.switch_case_one,
.switch_case_inline_one,
.switch_case,
.switch_case_inline,
=> {
const full_switch = tree.fullSwitchCase(n).?;
if (full_switch.inline_token) |inline_token| {
return inline_token;
} else if (full_switch.ast.values.len == 0) {
return full_switch.ast.arrow_token - 1 - end_offset; // else token
} else {
n = full_switch.ast.values[0];
}
},
.asm_output, .asm_input => {
assert(tree.tokenTag(tree.nodeMainToken(n) - 1) == .l_bracket);
return tree.nodeMainToken(n) - 1 - end_offset;
},
.while_simple,
.while_cont,
.@"while",
.for_simple,
.@"for",
=> {
// Look for a label and inline.
const main_token = tree.nodeMainToken(n);
var result = main_token;
if (tree.isTokenPrecededByTags(result, &.{.keyword_inline})) {
result = result - 1;
}
if (tree.isTokenPrecededByTags(result, &.{ .identifier, .colon })) {
result = result - 2;
}
return result - end_offset;
},
};
}