Commit ff7c6e1e3c

Vexu <git@vexu.eu>
2020-08-28 13:35:13
stage2: astgen orelse
1 parent 9a59cdc
Changed files (1)
src-self-hosted
src-self-hosted/astgen.zig
@@ -277,10 +277,10 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
         .ArrayAccess => return arrayAccess(mod, scope, rl, node.castTag(.ArrayAccess).?),
         .Catch => return catchExpr(mod, scope, rl, node.castTag(.Catch).?),
         .Comptime => return comptimeKeyword(mod, scope, rl, node.castTag(.Comptime).?),
+        .OrElse => return orelseExpr(mod, scope, rl, node.castTag(.OrElse).?),
 
         .Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}),
         .Range => return mod.failNode(scope, node, "TODO implement astgen.expr for .Range", .{}),
-        .OrElse => return mod.failNode(scope, node, "TODO implement astgen.expr for .OrElse", .{}),
         .Await => return mod.failNode(scope, node, "TODO implement astgen.expr for .Await", .{}),
         .Resume => return mod.failNode(scope, node, "TODO implement astgen.expr for .Resume", .{}),
         .Try => return mod.failNode(scope, node, "TODO implement astgen.expr for .Try", .{}),
@@ -790,13 +790,31 @@ fn errorType(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) InnerError!*
 }
 
 fn catchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Catch) InnerError!*zir.Inst {
+    return orelseCatchExpr(mod, scope, rl, node.lhs, node.op_token, .iserr, .unwrap_err_unsafe, node.rhs, node.payload);
+}
+
+fn orelseExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.SimpleInfixOp) InnerError!*zir.Inst {
+    return orelseCatchExpr(mod, scope, rl, node.lhs, node.op_token, .isnull, .unwrap_optional_unsafe, node.rhs, null);
+}
+
+fn orelseCatchExpr(
+    mod: *Module,
+    scope: *Scope,
+    rl: ResultLoc,
+    lhs: *ast.Node,
+    op_token: ast.TokenIndex,
+    cond_op: zir.Inst.Tag,
+    unwrap_op: zir.Inst.Tag,
+    rhs: *ast.Node,
+    payload_node: ?*ast.Node,
+) InnerError!*zir.Inst {
     const tree = scope.tree();
-    const src = tree.token_locs[node.op_token].start;
+    const src = tree.token_locs[op_token].start;
 
-    const err_union_ptr = try expr(mod, scope, .ref, node.lhs);
-    // TODO we could avoid an unnecessary copy if .iserr took a pointer
-    const err_union = try addZIRUnOp(mod, scope, src, .deref, err_union_ptr);
-    const cond = try addZIRUnOp(mod, scope, src, .iserr, err_union);
+    const operand_ptr = try expr(mod, scope, .ref, lhs);
+    // TODO we could avoid an unnecessary copy if .iserr, .isnull took a pointer
+    const err_union = try addZIRUnOp(mod, scope, src, .deref, operand_ptr);
+    const cond = try addZIRUnOp(mod, scope, src, cond_op, err_union);
 
     var block_scope: Scope.GenZIR = .{
         .parent = scope,
@@ -825,55 +843,55 @@ fn catchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Catch)
         .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = block },
     };
 
-    var err_scope: Scope.GenZIR = .{
+    var then_scope: Scope.GenZIR = .{
         .parent = scope,
         .decl = block_scope.decl,
         .arena = block_scope.arena,
         .instructions = .{},
     };
-    defer err_scope.instructions.deinit(mod.gpa);
+    defer then_scope.instructions.deinit(mod.gpa);
 
     var err_val_scope: Scope.LocalVal = undefined;
-    const err_sub_scope = blk: {
-        const payload = node.payload orelse
-            break :blk &err_scope.base;
+    const then_sub_scope = blk: {
+        const payload = payload_node orelse
+            break :blk &then_scope.base;
 
         const err_name = tree.tokenSlice(payload.castTag(.Payload).?.error_symbol.firstToken());
         if (mem.eql(u8, err_name, "_"))
-            break :blk &err_scope.base;
+            break :blk &then_scope.base;
 
-        const unwrapped_err_ptr = try addZIRUnOp(mod, &err_scope.base, src, .unwrap_err_code, err_union_ptr);
+        const unwrapped_err_ptr = try addZIRUnOp(mod, &then_scope.base, src, .unwrap_err_code, operand_ptr);
         err_val_scope = .{
-            .parent = &err_scope.base,
-            .gen_zir = &err_scope,
+            .parent = &then_scope.base,
+            .gen_zir = &then_scope,
             .name = err_name,
-            .inst = try addZIRUnOp(mod, &err_scope.base, src, .deref, unwrapped_err_ptr),
+            .inst = try addZIRUnOp(mod, &then_scope.base, src, .deref, unwrapped_err_ptr),
         };
         break :blk &err_val_scope.base;
     };
 
-    _ = try addZIRInst(mod, &err_scope.base, src, zir.Inst.Break, .{
+    _ = try addZIRInst(mod, &then_scope.base, src, zir.Inst.Break, .{
         .block = block,
-        .operand = try expr(mod, err_sub_scope, branch_rl, node.rhs),
+        .operand = try expr(mod, then_sub_scope, branch_rl, rhs),
     }, .{});
 
-    var not_err_scope: Scope.GenZIR = .{
+    var else_scope: Scope.GenZIR = .{
         .parent = scope,
         .decl = block_scope.decl,
         .arena = block_scope.arena,
         .instructions = .{},
     };
-    defer not_err_scope.instructions.deinit(mod.gpa);
+    defer else_scope.instructions.deinit(mod.gpa);
 
-    const unwrapped_payload = try addZIRUnOp(mod, &not_err_scope.base, src, .unwrap_err_unsafe, err_union_ptr);
-    _ = try addZIRInst(mod, &not_err_scope.base, src, zir.Inst.Break, .{
+    const unwrapped_payload = try addZIRUnOp(mod, &else_scope.base, src, unwrap_op, operand_ptr);
+    _ = try addZIRInst(mod, &else_scope.base, src, zir.Inst.Break, .{
         .block = block,
         .operand = unwrapped_payload,
     }, .{});
 
-    condbr.positionals.then_body = .{ .instructions = try err_scope.arena.dupe(*zir.Inst, err_scope.instructions.items) };
-    condbr.positionals.else_body = .{ .instructions = try not_err_scope.arena.dupe(*zir.Inst, not_err_scope.instructions.items) };
-    return rlWrap(mod, scope, rl, &block.base);
+    condbr.positionals.then_body = .{ .instructions = try then_scope.arena.dupe(*zir.Inst, then_scope.instructions.items) };
+    condbr.positionals.else_body = .{ .instructions = try else_scope.arena.dupe(*zir.Inst, else_scope.instructions.items) };
+    return rlWrapPtr(mod, scope, rl, &block.base);
 }
 
 /// Return whether the identifier names of two tokens are equal. Resolves @"" tokens without allocating.