Skip to content

Commit

Permalink
stage1+2: parse inline switch cases
Browse files Browse the repository at this point in the history
  • Loading branch information
Vexu committed Sep 27, 2022
1 parent 8849792 commit b4d8185
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 15 deletions.
31 changes: 28 additions & 3 deletions lib/std/zig/Ast.zig
Expand Up @@ -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);
Expand Down Expand Up @@ -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,

Expand Down Expand Up @@ -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 {
Expand All @@ -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 {
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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`.
Expand Down
15 changes: 10 additions & 5 deletions lib/std/zig/parse.zig
Expand Up @@ -3100,46 +3100,51 @@ const Parser = struct {
return identifier;
}

/// SwitchProng <- SwitchCase EQUALRARROW PtrPayload? AssignExpr
/// SwitchProng <- KEYWORD_inline? SwitchCase EQUALRARROW PtrPayload? AssignExpr
/// SwitchCase
/// <- SwitchItem (COMMA SwitchItem)* COMMA?
/// / KEYWORD_else
fn parseSwitchProng(p: *Parser) !Node.Index {
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();
if (item == 0) break;
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();

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,
.rhs = try p.expectAssignExpr(),
},
}),
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],
.rhs = try p.expectAssignExpr(),
},
}),
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)),
Expand Down
9 changes: 7 additions & 2 deletions lib/std/zig/render.zig
Expand Up @@ -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),
Expand Down Expand Up @@ -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
Expand Down
18 changes: 16 additions & 2 deletions src/AstGen.zig
Expand Up @@ -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,
Expand Down Expand Up @@ -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`.
Expand Down Expand Up @@ -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| {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions src/stage1/all_types.hpp
Expand Up @@ -1039,6 +1039,7 @@ struct AstNodeSwitchProng {
AstNode *expr;
bool var_is_ptr;
bool any_items_are_range;
bool is_inline;
};

struct AstNodeSwitchRange {
Expand Down
12 changes: 9 additions & 3 deletions src/stage1/parser.cpp
Expand Up @@ -2306,7 +2306,7 @@ static Optional<PtrIndexPayload> ast_parse_ptr_index_payload(ParseContext *pc) {
return Optional<PtrIndexPayload>::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)
Expand All @@ -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;

Expand All @@ -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;
}

Expand Down

0 comments on commit b4d8185

Please sign in to comment.