diff options
| author | jacob gw <jacoblevgw@gmail.com> | 2021-04-19 17:03:52 -0400 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2021-04-20 13:16:08 -0400 |
| commit | ee3c1c763c8201d31321643f72cd1506c369dd71 (patch) | |
| tree | a2d8e6470cf0735912aba56dfcdc1e1dae2df415 /src | |
| parent | e315120b79f98163dd6413e62684d6ad148295ee (diff) | |
| download | zig-ee3c1c763c8201d31321643f72cd1506c369dd71.tar.gz zig-ee3c1c763c8201d31321643f72cd1506c369dd71.zip | |
stage2: astgen `try`
Diffstat (limited to 'src')
| -rw-r--r-- | src/AstGen.zig | 106 |
1 files changed, 105 insertions, 1 deletions
diff --git a/src/AstGen.zig b/src/AstGen.zig index 7a22420d76..767564c6da 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -820,7 +820,7 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn .@"defer" => return astgen.failNode(node, "TODO implement astgen.expr for .defer", .{}), .@"errdefer" => return astgen.failNode(node, "TODO implement astgen.expr for .errdefer", .{}), - .@"try" => return astgen.failNode(node, "TODO implement astgen.expr for .Try", .{}), + .@"try" => return tryExpr(gz, scope, rl, node_datas[node].lhs), .array_init_one, .array_init_one_comma => { var elements: [1]ast.Node.Index = undefined; @@ -3154,6 +3154,110 @@ fn errorSetDecl( return rvalue(gz, scope, rl, result, node); } +fn tryExpr( + parent_gz: *GenZir, + scope: *Scope, + rl: ResultLoc, + node: ast.Node.Index, +) InnerError!Zir.Inst.Ref { + const astgen = parent_gz.astgen; + const tree = &astgen.file.tree; + const main_tokens = tree.nodes.items(.main_token); + const token_tags = tree.tokens.items(.tag); + const node_datas = tree.nodes.items(.data); + const node_tags = tree.nodes.items(.tag); + + var block_scope: GenZir = .{ + .parent = scope, + .decl_node_index = parent_gz.decl_node_index, + .astgen = parent_gz.astgen, + .force_comptime = parent_gz.force_comptime, + .instructions = .{}, + }; + block_scope.setBreakResultLoc(rl); + defer block_scope.instructions.deinit(astgen.gpa); + + // This could be a pointer or value depending on the `operand_rl` parameter. + // We cannot use `block_scope.break_result_loc` because that has the bare + // type, whereas this expression has the optional type. Later we make + // up for this fact by calling rvalue on the else branch. + block_scope.break_count += 1; + + const operand_rl: ResultLoc = switch (block_scope.break_result_loc) { + .ref => .ref, + .discard, .none, .none_or_ref, .block_ptr, .inferred_ptr => .none, + .ty => |elem_ty| { + @panic("TODO"); + }, + .ptr => |ptr_ty| { + @panic("TODO"); + }, + }; + const ops = switch (rl) { + .ref => [3]Zir.Inst.Tag{ .is_err_ptr, .err_union_code_ptr, .err_union_payload_unsafe_ptr }, + else => [3]Zir.Inst.Tag{ .is_err, .err_union_code, .err_union_payload_unsafe }, + }; + const operand = try expr(&block_scope, &block_scope.base, operand_rl, node); + const cond = try block_scope.addUnNode(ops[0], operand, node); + const condbr = try block_scope.addCondBr(.condbr, node); + + const block = try parent_gz.addBlock(.block, node); + try parent_gz.instructions.append(astgen.gpa, block); + try block_scope.setBlockBody(block); + + var then_scope: GenZir = .{ + .parent = scope, + .decl_node_index = parent_gz.decl_node_index, + .astgen = parent_gz.astgen, + .force_comptime = block_scope.force_comptime, + .instructions = .{}, + }; + defer then_scope.instructions.deinit(astgen.gpa); + + const then_result = try then_scope.addUnNode(ops[1], operand, node); + const to_return = try then_scope.addUnNode(.ret_node, then_result, node); + + block_scope.break_count += 1; + // We hold off on the break instructions as well as copying the then/else + // instructions into place until we know whether to keep store_to_block_ptr + // instructions or not. + + var else_scope: GenZir = .{ + .parent = scope, + .decl_node_index = parent_gz.decl_node_index, + .astgen = parent_gz.astgen, + .force_comptime = block_scope.force_comptime, + .instructions = .{}, + }; + defer else_scope.instructions.deinit(astgen.gpa); + + // This could be a pointer or value depending on `unwrap_op`. + const unwrapped_payload = try else_scope.addUnNode(ops[2], operand, node); + const else_result = switch (rl) { + .ref => unwrapped_payload, + else => try rvalue(&else_scope, &else_scope.base, block_scope.break_result_loc, unwrapped_payload, node), + }; + + return finishThenElseBlock( + parent_gz, + scope, + rl, + node, + &block_scope, + &then_scope, + &else_scope, + condbr, + cond, + node, + node, + to_return, + else_result, + block, + block, + .@"break", + ); +} + fn orelseCatchExpr( parent_gz: *GenZir, scope: *Scope, |
