stage2: astgen for if and while with optionals

This commit is contained in:
Vexu 2020-08-15 19:17:50 +03:00
parent 012fac255f
commit db77b6b4e7
No known key found for this signature in database
GPG Key ID: 59AEB8936E16A6AC

View File

@ -594,12 +594,55 @@ fn simpleBinOp(
return rlWrap(mod, scope, rl, result);
}
fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) InnerError!*zir.Inst {
if (if_node.payload) |payload| {
return mod.failNode(scope, payload, "TODO implement astgen.IfExpr for optionals", .{});
const CondKind = union(enum) {
bool,
optional: ?*zir.Inst,
err_union: ?*zir.Inst,
fn cond(self: *CondKind, mod: *Module, block_scope: *Scope.GenZIR, src: usize, cond_node: *ast.Node) !*zir.Inst {
switch (self.*) {
.bool => {
const bool_type = try addZIRInstConst(mod, &block_scope.base, src, .{
.ty = Type.initTag(.type),
.val = Value.initTag(.bool_type),
});
return try expr(mod, &block_scope.base, .{ .ty = bool_type }, cond_node);
},
.optional => {
const cond_ptr = try expr(mod, &block_scope.base, .lvalue, cond_node);
self.* = .{ .optional = cond_ptr };
const result = try addZIRUnOp(mod, &block_scope.base, src, .deref, cond_ptr);
return try addZIRUnOp(mod, &block_scope.base, src, .isnonnull, result);
},
.err_union => unreachable,
}
}
fn thenSubScope(self: CondKind, mod: *Module, then_scope: *Scope.GenZIR, payload_node: ?*ast.Node) !*Scope {
if (self == .bool) return &then_scope.base;
const payload = payload_node.?.castTag(.PointerPayload).?;
const is_ptr = payload.ptr_token != null;
const ident_node = payload.value_symbol.castTag(.Identifier).?;
const ident_name = try identifierTokenString(mod, &then_scope.base, ident_node.token);
if (mem.eql(u8, ident_name, "_")) {
if (is_ptr)
return mod.failTok(&then_scope.base, payload.ptr_token.?, "pointer modifier invalid on discard", .{});
return &then_scope.base;
}
return mod.failNode(&then_scope.base, payload.value_symbol, "TODO implement payload symbols", .{});
}
};
fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) InnerError!*zir.Inst {
var cond_kind: CondKind = .bool;
if (if_node.payload) |_| cond_kind = .{ .optional = null };
if (if_node.@"else") |else_node| {
if (else_node.payload) |payload| {
if (cond_kind != .optional) {
return mod.failNode(scope, payload, "else payload invalid on bool conditions", .{});
}
return mod.failNode(scope, payload, "TODO implement astgen.IfExpr for error unions", .{});
}
}
@ -613,11 +656,7 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn
const tree = scope.tree();
const if_src = tree.token_locs[if_node.if_token].start;
const bool_type = try addZIRInstConst(mod, scope, if_src, .{
.ty = Type.initTag(.type),
.val = Value.initTag(.bool_type),
});
const cond = try expr(mod, &block_scope.base, .{ .ty = bool_type }, if_node.condition);
const cond = try cond_kind.cond(mod, &block_scope, if_src, if_node.condition);
const condbr = try addZIRInstSpecial(mod, &block_scope.base, if_src, zir.Inst.CondBr, .{
.condition = cond,
@ -636,6 +675,9 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn
};
defer then_scope.instructions.deinit(mod.gpa);
// declare payload to the then_scope
const then_sub_scope = try cond_kind.thenSubScope(mod, &then_scope, if_node.payload);
// Most result location types can be forwarded directly; however
// if we need to write to a pointer which has an inferred type,
// proper type inference requires peer type resolution on the if's
@ -645,10 +687,10 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn
.inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = block },
};
const then_result = try expr(mod, &then_scope.base, branch_rl, if_node.body);
const then_result = try expr(mod, then_sub_scope, branch_rl, if_node.body);
if (!then_result.tag.isNoReturn()) {
const then_src = tree.token_locs[if_node.body.lastToken()].start;
_ = try addZIRInst(mod, &then_scope.base, then_src, zir.Inst.Break, .{
_ = try addZIRInst(mod, then_sub_scope, then_src, zir.Inst.Break, .{
.block = block,
.operand = then_result,
}, .{});
@ -690,11 +732,13 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn
}
fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.While) InnerError!*zir.Inst {
if (while_node.payload) |payload| {
return mod.failNode(scope, payload, "TODO implement astgen.whileExpr for optionals", .{});
}
var cond_kind: CondKind = .bool;
if (while_node.payload) |_| cond_kind = .{ .optional = null };
if (while_node.@"else") |else_node| {
if (else_node.payload) |payload| {
if (cond_kind != .optional) {
return mod.failNode(scope, payload, "else payload invalid on bool conditions", .{});
}
return mod.failNode(scope, payload, "TODO implement astgen.whileExpr for error unions", .{});
}
}
@ -725,15 +769,11 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W
const tree = scope.tree();
const while_src = tree.token_locs[while_node.while_token].start;
const bool_type = try addZIRInstConst(mod, scope, while_src, .{
.ty = Type.initTag(.type),
.val = Value.initTag(.bool_type),
});
const void_type = try addZIRInstConst(mod, scope, while_src, .{
.ty = Type.initTag(.type),
.val = Value.initTag(.void_type),
});
const cond = try expr(mod, &continue_scope.base, .{ .ty = bool_type }, while_node.condition);
const cond = try cond_kind.cond(mod, &continue_scope, while_src, while_node.condition);
const condbr = try addZIRInstSpecial(mod, &continue_scope.base, while_src, zir.Inst.CondBr, .{
.condition = cond,
@ -764,6 +804,9 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W
};
defer then_scope.instructions.deinit(mod.gpa);
// declare payload to the then_scope
const then_sub_scope = try cond_kind.thenSubScope(mod, &then_scope, while_node.payload);
// Most result location types can be forwarded directly; however
// if we need to write to a pointer which has an inferred type,
// proper type inference requires peer type resolution on the while's
@ -773,10 +816,10 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W
.inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = while_block },
};
const then_result = try expr(mod, &then_scope.base, branch_rl, while_node.body);
const then_result = try expr(mod, then_sub_scope, branch_rl, while_node.body);
if (!then_result.tag.isNoReturn()) {
const then_src = tree.token_locs[while_node.body.lastToken()].start;
_ = try addZIRInst(mod, &then_scope.base, then_src, zir.Inst.Break, .{
_ = try addZIRInst(mod, then_sub_scope, then_src, zir.Inst.Break, .{
.block = cond_block,
.operand = then_result,
}, .{});