diff --git a/lib/std/zig/Ast.zig b/lib/std/zig/Ast.zig index bfa73dc9ac..62a567387f 100644 --- a/lib/std/zig/Ast.zig +++ b/lib/std/zig/Ast.zig @@ -643,11 +643,23 @@ pub fn firstToken(tree: Ast, node: Node.Index) TokenIndex { n = datas[n].lhs; } }, + .switch_case_inline_one => { + if (datas[n].lhs == 0) { + return main_tokens[n] - 2 - end_offset; // else token + } else { + return firstToken(tree, datas[n].lhs) - 1; + } + }, .switch_case => { const extra = tree.extraData(datas[n].lhs, Node.SubRange); assert(extra.end - extra.start > 0); n = tree.extra_data[extra.start]; }, + .switch_case_inline => { + const extra = tree.extraData(datas[n].lhs, Node.SubRange); + assert(extra.end - extra.start > 0); + return firstToken(tree, tree.extra_data[extra.start]) - 1; + }, .asm_output, .asm_input => { assert(token_tags[main_tokens[n] - 1] == .l_bracket); @@ -763,7 +775,9 @@ pub fn lastToken(tree: Ast, node: Node.Index) TokenIndex { .ptr_type_bit_range, .array_type, .switch_case_one, + .switch_case_inline_one, .switch_case, + .switch_case_inline, .switch_range, => n = datas[n].rhs, @@ -1755,7 +1769,7 @@ pub fn switchCaseOne(tree: Ast, node: Node.Index) full.SwitchCase { .values = if (data.lhs == 0) values[0..0] else values[0..1], .arrow_token = tree.nodes.items(.main_token)[node], .target_expr = data.rhs, - }); + }, node); } pub fn switchCase(tree: Ast, node: Node.Index) full.SwitchCase { @@ -1765,7 +1779,7 @@ pub fn switchCase(tree: Ast, node: Node.Index) full.SwitchCase { .values = tree.extra_data[extra.start..extra.end], .arrow_token = tree.nodes.items(.main_token)[node], .target_expr = data.rhs, - }); + }, node); } pub fn asmSimple(tree: Ast, node: Node.Index) full.Asm { @@ -2038,15 +2052,21 @@ fn fullContainerDecl(tree: Ast, info: full.ContainerDecl.Components) full.Contai return result; } -fn fullSwitchCase(tree: Ast, info: full.SwitchCase.Components) full.SwitchCase { +fn fullSwitchCase(tree: Ast, info: full.SwitchCase.Components, node: Node.Index) full.SwitchCase { const token_tags = tree.tokens.items(.tag); + const node_tags = tree.nodes.items(.tag); var result: full.SwitchCase = .{ .ast = info, .payload_token = null, + .inline_token = null, }; if (token_tags[info.arrow_token + 1] == .pipe) { result.payload_token = info.arrow_token + 2; } + switch (node_tags[node]) { + .switch_case_inline, .switch_case_inline_one => result.inline_token = firstToken(tree, node), + else => {}, + } return result; } @@ -2454,6 +2474,7 @@ pub const full = struct { }; pub const SwitchCase = struct { + inline_token: ?TokenIndex, /// Points to the first token after the `|`. Will either be an identifier or /// a `*` (with an identifier immediately after it). payload_token: ?TokenIndex, @@ -2847,9 +2868,13 @@ pub const Node = struct { /// `lhs => rhs`. If lhs is omitted it means `else`. /// main_token is the `=>` switch_case_one, + /// Same ast `switch_case_one` but the case is inline + switch_case_inline_one, /// `a, b, c => rhs`. `SubRange[lhs]`. /// main_token is the `=>` switch_case, + /// Same ast `switch_case` but the case is inline + switch_case_inline, /// `lhs...rhs`. switch_range, /// `while (lhs) rhs`. diff --git a/lib/std/zig/parse.zig b/lib/std/zig/parse.zig index 43b6eda8e0..04b45ad20d 100644 --- a/lib/std/zig/parse.zig +++ b/lib/std/zig/parse.zig @@ -3100,7 +3100,7 @@ const Parser = struct { return identifier; } - /// SwitchProng <- SwitchCase EQUALRARROW PtrPayload? AssignExpr + /// SwitchProng <- KEYWORD_inline? SwitchCase EQUALRARROW PtrPayload? AssignExpr /// SwitchCase /// <- SwitchItem (COMMA SwitchItem)* COMMA? /// / KEYWORD_else @@ -3108,6 +3108,8 @@ const Parser = struct { const scratch_top = p.scratch.items.len; defer p.scratch.shrinkRetainingCapacity(scratch_top); + const is_inline = p.eatToken(.keyword_inline) != null; + if (p.eatToken(.keyword_else) == null) { while (true) { const item = try p.parseSwitchItem(); @@ -3115,7 +3117,10 @@ const Parser = struct { try p.scratch.append(p.gpa, item); if (p.eatToken(.comma) == null) break; } - if (scratch_top == p.scratch.items.len) return null_node; + if (scratch_top == p.scratch.items.len) { + if (is_inline) p.tok_i -= 1; + return null_node; + } } const arrow_token = try p.expectToken(.equal_angle_bracket_right); _ = try p.parsePtrPayload(); @@ -3123,7 +3128,7 @@ const Parser = struct { const items = p.scratch.items[scratch_top..]; switch (items.len) { 0 => return p.addNode(.{ - .tag = .switch_case_one, + .tag = if (is_inline) .switch_case_inline_one else .switch_case_one, .main_token = arrow_token, .data = .{ .lhs = 0, @@ -3131,7 +3136,7 @@ const Parser = struct { }, }), 1 => return p.addNode(.{ - .tag = .switch_case_one, + .tag = if (is_inline) .switch_case_inline_one else .switch_case_one, .main_token = arrow_token, .data = .{ .lhs = items[0], @@ -3139,7 +3144,7 @@ const Parser = struct { }, }), else => return p.addNode(.{ - .tag = .switch_case, + .tag = if (is_inline) .switch_case_inline else .switch_case, .main_token = arrow_token, .data = .{ .lhs = try p.addExtra(try p.listToSpan(items)), diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig index 6ef0cfcd6f..db4a092b2a 100644 --- a/lib/std/zig/render.zig +++ b/lib/std/zig/render.zig @@ -685,8 +685,8 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index, return renderToken(ais, tree, tree.lastToken(node), space); // rbrace }, - .switch_case_one => return renderSwitchCase(gpa, ais, tree, tree.switchCaseOne(node), space), - .switch_case => return renderSwitchCase(gpa, ais, tree, tree.switchCase(node), space), + .switch_case_one, .switch_case_inline_one => return renderSwitchCase(gpa, ais, tree, tree.switchCaseOne(node), space), + .switch_case, .switch_case_inline => return renderSwitchCase(gpa, ais, tree, tree.switchCase(node), space), .while_simple => return renderWhile(gpa, ais, tree, tree.whileSimple(node), space), .while_cont => return renderWhile(gpa, ais, tree, tree.whileCont(node), space), @@ -1509,6 +1509,11 @@ fn renderSwitchCase( break :blk hasComment(tree, tree.firstToken(switch_case.ast.values[0]), switch_case.ast.arrow_token); }; + // render inline keyword + if (switch_case.inline_token) |some| { + try renderToken(ais, tree, some, .space); + } + // Render everything before the arrow if (switch_case.ast.values.len == 0) { try renderToken(ais, tree, switch_case.ast.arrow_token - 1, .space); // else keyword diff --git a/src/AstGen.zig b/src/AstGen.zig index 8e6721d7bc..a516043bf2 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -386,7 +386,9 @@ fn lvalExpr(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Ins .simple_var_decl => unreachable, .aligned_var_decl => unreachable, .switch_case => unreachable, + .switch_case_inline => unreachable, .switch_case_one => unreachable, + .switch_case_inline_one => unreachable, .container_field_init => unreachable, .container_field_align => unreachable, .container_field => unreachable, @@ -600,7 +602,9 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr .@"errdefer" => unreachable, // Handled in `blockExpr`. .switch_case => unreachable, // Handled in `switchExpr`. + .switch_case_inline => unreachable, // Handled in `switchExpr`. .switch_case_one => unreachable, // Handled in `switchExpr`. + .switch_case_inline_one => unreachable, // Handled in `switchExpr`. .switch_range => unreachable, // Handled in `switchExpr`. .asm_output => unreachable, // Handled in `asmExpr`. @@ -6216,14 +6220,15 @@ fn switchExpr( var any_payload_is_ref = false; var scalar_cases_len: u32 = 0; var multi_cases_len: u32 = 0; + var inline_cases_len: u32 = 0; var special_prong: Zir.SpecialProng = .none; var special_node: Ast.Node.Index = 0; var else_src: ?Ast.TokenIndex = null; var underscore_src: ?Ast.TokenIndex = null; for (case_nodes) |case_node| { const case = switch (node_tags[case_node]) { - .switch_case_one => tree.switchCaseOne(case_node), - .switch_case => tree.switchCase(case_node), + .switch_case_one, .switch_case_inline_one => tree.switchCaseOne(case_node), + .switch_case, .switch_case_inline => tree.switchCase(case_node), else => unreachable, }; if (case.payload_token) |payload_token| { @@ -6318,6 +6323,9 @@ fn switchExpr( } else { multi_cases_len += 1; } + if (case.inline_token != null) { + inline_cases_len += 1; + } } const operand_rl: ResultLoc = if (any_payload_is_ref) .ref else .none; @@ -8436,7 +8444,9 @@ fn nodeMayNeedMemoryLocation(tree: *const Ast, start_node: Ast.Node.Index, have_ .@"usingnamespace", .test_decl, .switch_case, + .switch_case_inline, .switch_case_one, + .switch_case_inline_one, .container_field_init, .container_field_align, .container_field, @@ -8668,7 +8678,9 @@ fn nodeMayEvalToError(tree: *const Ast, start_node: Ast.Node.Index) BuiltinFn.Ev .@"usingnamespace", .test_decl, .switch_case, + .switch_case_inline, .switch_case_one, + .switch_case_inline_one, .container_field_init, .container_field_align, .container_field, @@ -8879,7 +8891,9 @@ fn nodeImpliesMoreThanOnePossibleValue(tree: *const Ast, start_node: Ast.Node.In .@"usingnamespace", .test_decl, .switch_case, + .switch_case_inline, .switch_case_one, + .switch_case_inline_one, .container_field_init, .container_field_align, .container_field, diff --git a/src/stage1/all_types.hpp b/src/stage1/all_types.hpp index 5f216fe388..d4a2abece9 100644 --- a/src/stage1/all_types.hpp +++ b/src/stage1/all_types.hpp @@ -1039,6 +1039,7 @@ struct AstNodeSwitchProng { AstNode *expr; bool var_is_ptr; bool any_items_are_range; + bool is_inline; }; struct AstNodeSwitchRange { diff --git a/src/stage1/parser.cpp b/src/stage1/parser.cpp index bd778484cb..b7cb6cb297 100644 --- a/src/stage1/parser.cpp +++ b/src/stage1/parser.cpp @@ -2306,7 +2306,7 @@ static Optional ast_parse_ptr_index_payload(ParseContext *pc) { return Optional::some(res); } -// SwitchProng <- SwitchCase EQUALRARROW PtrPayload? AssignExpr +// SwitchProng <- KEYWORD_inline? SwitchCase EQUALRARROW PtrPayload? AssignExpr static AstNode *ast_parse_switch_prong(ParseContext *pc) { AstNode *res = ast_parse_switch_case(pc); if (res == nullptr) @@ -2331,9 +2331,11 @@ static AstNode *ast_parse_switch_prong(ParseContext *pc) { // <- SwitchItem (COMMA SwitchItem)* COMMA? // / KEYWORD_else static AstNode *ast_parse_switch_case(ParseContext *pc) { + bool is_inline = eat_token_if(pc, TokenIdKeywordInline) != 0; AstNode *first = ast_parse_switch_item(pc); if (first != nullptr) { AstNode *res = ast_create_node_copy_line_info(pc, NodeTypeSwitchProng, first); + res->data.switch_prong.is_inline = is_inline; res->data.switch_prong.items.append(first); res->data.switch_prong.any_items_are_range = first->type == NodeTypeSwitchRange; @@ -2350,9 +2352,13 @@ static AstNode *ast_parse_switch_case(ParseContext *pc) { } TokenIndex else_token = eat_token_if(pc, TokenIdKeywordElse); - if (else_token != 0) - return ast_create_node(pc, NodeTypeSwitchProng, else_token); + if (else_token != 0) { + AstNode *res = ast_create_node(pc, NodeTypeSwitchProng, else_token); + res->data.switch_prong.is_inline = is_inline; + return res; + } + if (is_inline) pc->current_token -= 1; return nullptr; }