mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 04:48:20 +00:00
astgen: rework for loops
This commit is contained in:
parent
9f4ff80108
commit
de85c4ac42
187
src/astgen.zig
187
src/astgen.zig
@ -457,9 +457,9 @@ fn continueExpr(mod: *Module, parent_scope: *Scope, node: *ast.Node.ControlFlowE
|
||||
continue;
|
||||
}
|
||||
|
||||
return addZIRInst(mod, parent_scope, src, zir.Inst.BreakVoid, .{
|
||||
return addZirInstTag(mod, parent_scope, src, .break_void, .{
|
||||
.block = continue_block,
|
||||
}, .{});
|
||||
});
|
||||
},
|
||||
.local_val => scope = scope.cast(Scope.LocalVal).?.parent,
|
||||
.local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,
|
||||
@ -1908,22 +1908,13 @@ fn whileExpr(
|
||||
if (while_node.inline_token) |tok|
|
||||
return mod.failTok(scope, tok, "TODO inline while", .{});
|
||||
|
||||
var expr_scope: Scope.GenZIR = .{
|
||||
var loop_scope: Scope.GenZIR = .{
|
||||
.parent = scope,
|
||||
.decl = scope.ownerDecl().?,
|
||||
.arena = scope.arena(),
|
||||
.instructions = .{},
|
||||
};
|
||||
setBlockResultLoc(&expr_scope, rl);
|
||||
defer expr_scope.instructions.deinit(mod.gpa);
|
||||
|
||||
var loop_scope: Scope.GenZIR = .{
|
||||
.parent = &expr_scope.base,
|
||||
.decl = expr_scope.decl,
|
||||
.arena = expr_scope.arena,
|
||||
.instructions = .{},
|
||||
.break_result_loc = rl,
|
||||
};
|
||||
setBlockResultLoc(&loop_scope, rl);
|
||||
defer loop_scope.instructions.deinit(mod.gpa);
|
||||
|
||||
var continue_scope: Scope.GenZIR = .{
|
||||
@ -1957,11 +1948,21 @@ fn whileExpr(
|
||||
if (while_node.continue_expr) |cont_expr| {
|
||||
_ = try expr(mod, &loop_scope.base, .{ .ty = void_type }, cont_expr);
|
||||
}
|
||||
const loop = try addZIRInstLoop(mod, &expr_scope.base, while_src, .{
|
||||
.instructions = try expr_scope.arena.dupe(*zir.Inst, loop_scope.instructions.items),
|
||||
});
|
||||
const loop = try scope.arena().create(zir.Inst.Loop);
|
||||
loop.* = .{
|
||||
.base = .{
|
||||
.tag = .loop,
|
||||
.src = while_src,
|
||||
},
|
||||
.positionals = .{
|
||||
.body = .{
|
||||
.instructions = try scope.arena().dupe(*zir.Inst, loop_scope.instructions.items),
|
||||
},
|
||||
},
|
||||
.kw_args = .{},
|
||||
};
|
||||
const while_block = try addZIRInstBlock(mod, scope, while_src, .block, .{
|
||||
.instructions = try expr_scope.arena.dupe(*zir.Inst, expr_scope.instructions.items),
|
||||
.instructions = try scope.arena().dupe(*zir.Inst, &[1]*zir.Inst{&loop.base}),
|
||||
});
|
||||
loop_scope.break_block = while_block;
|
||||
loop_scope.continue_block = cond_block;
|
||||
@ -1984,8 +1985,8 @@ fn whileExpr(
|
||||
// declare payload to the then_scope
|
||||
const then_sub_scope = try cond_kind.thenSubScope(mod, &then_scope, then_src, while_node.payload);
|
||||
|
||||
expr_scope.break_count += 1;
|
||||
const then_result = try expr(mod, then_sub_scope, expr_scope.break_result_loc, while_node.body);
|
||||
loop_scope.break_count += 1;
|
||||
const then_result = try expr(mod, then_sub_scope, loop_scope.break_result_loc, while_node.body);
|
||||
|
||||
var else_scope: Scope.GenZIR = .{
|
||||
.parent = &continue_scope.base,
|
||||
@ -1996,17 +1997,15 @@ fn whileExpr(
|
||||
defer else_scope.instructions.deinit(mod.gpa);
|
||||
|
||||
var else_src: usize = undefined;
|
||||
var else_sub_scope: *Module.Scope = undefined;
|
||||
const else_result: ?*zir.Inst = if (while_node.@"else") |else_node| blk: {
|
||||
else_src = tree.token_locs[else_node.body.lastToken()].start;
|
||||
// declare payload to the then_scope
|
||||
else_sub_scope = try cond_kind.elseSubScope(mod, &else_scope, else_src, else_node.payload);
|
||||
const else_sub_scope = try cond_kind.elseSubScope(mod, &else_scope, else_src, else_node.payload);
|
||||
|
||||
expr_scope.break_count += 1;
|
||||
break :blk try expr(mod, else_sub_scope, expr_scope.break_result_loc, else_node.body);
|
||||
loop_scope.break_count += 1;
|
||||
break :blk try expr(mod, else_sub_scope, loop_scope.break_result_loc, else_node.body);
|
||||
} else blk: {
|
||||
else_src = tree.token_locs[while_node.lastToken()].start;
|
||||
else_sub_scope = &else_scope.base;
|
||||
break :blk null;
|
||||
};
|
||||
if (loop_scope.label) |some| {
|
||||
@ -2018,7 +2017,7 @@ fn whileExpr(
|
||||
mod,
|
||||
scope,
|
||||
rl,
|
||||
&expr_scope,
|
||||
&loop_scope,
|
||||
&then_scope,
|
||||
&else_scope,
|
||||
&condbr.positionals.then_body,
|
||||
@ -2037,9 +2036,6 @@ fn forExpr(
|
||||
rl: ResultLoc,
|
||||
for_node: *ast.Node.For,
|
||||
) InnerError!*zir.Inst {
|
||||
if (true) {
|
||||
@panic("TODO reimplement this");
|
||||
}
|
||||
if (for_node.label) |label| {
|
||||
try checkLabelRedefinition(mod, scope, label);
|
||||
}
|
||||
@ -2047,42 +2043,34 @@ fn forExpr(
|
||||
if (for_node.inline_token) |tok|
|
||||
return mod.failTok(scope, tok, "TODO inline for", .{});
|
||||
|
||||
var for_scope: Scope.GenZIR = .{
|
||||
// setup variables and constants
|
||||
const tree = scope.tree();
|
||||
const for_src = tree.token_locs[for_node.for_token].start;
|
||||
const index_ptr = blk: {
|
||||
const usize_type = try addZIRInstConst(mod, scope, for_src, .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.usize_type),
|
||||
});
|
||||
const index_ptr = try addZIRUnOp(mod, scope, for_src, .alloc, usize_type);
|
||||
// initialize to zero
|
||||
const zero = try addZIRInstConst(mod, scope, for_src, .{
|
||||
.ty = Type.initTag(.usize),
|
||||
.val = Value.initTag(.zero),
|
||||
});
|
||||
_ = try addZIRBinOp(mod, scope, for_src, .store, index_ptr, zero);
|
||||
break :blk index_ptr;
|
||||
};
|
||||
const array_ptr = try expr(mod, scope, .ref, for_node.array_expr);
|
||||
const cond_src = tree.token_locs[for_node.array_expr.firstToken()].start;
|
||||
const len = try addZIRUnOp(mod, scope, cond_src, .indexable_ptr_len, array_ptr);
|
||||
|
||||
var loop_scope: Scope.GenZIR = .{
|
||||
.parent = scope,
|
||||
.decl = scope.ownerDecl().?,
|
||||
.arena = scope.arena(),
|
||||
.instructions = .{},
|
||||
};
|
||||
defer for_scope.instructions.deinit(mod.gpa);
|
||||
|
||||
// setup variables and constants
|
||||
const tree = scope.tree();
|
||||
const for_src = tree.token_locs[for_node.for_token].start;
|
||||
const index_ptr = blk: {
|
||||
const usize_type = try addZIRInstConst(mod, &for_scope.base, for_src, .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.usize_type),
|
||||
});
|
||||
const index_ptr = try addZIRUnOp(mod, &for_scope.base, for_src, .alloc, usize_type);
|
||||
// initialize to zero
|
||||
const zero = try addZIRInstConst(mod, &for_scope.base, for_src, .{
|
||||
.ty = Type.initTag(.usize),
|
||||
.val = Value.initTag(.zero),
|
||||
});
|
||||
_ = try addZIRBinOp(mod, &for_scope.base, for_src, .store, index_ptr, zero);
|
||||
break :blk index_ptr;
|
||||
};
|
||||
const array_ptr = try expr(mod, &for_scope.base, .ref, for_node.array_expr);
|
||||
const cond_src = tree.token_locs[for_node.array_expr.firstToken()].start;
|
||||
const len = try addZIRUnOp(mod, &for_scope.base, cond_src, .indexable_ptr_len, array_ptr);
|
||||
|
||||
var loop_scope: Scope.GenZIR = .{
|
||||
.parent = &for_scope.base,
|
||||
.decl = for_scope.decl,
|
||||
.arena = for_scope.arena,
|
||||
.instructions = .{},
|
||||
.break_result_loc = rl,
|
||||
};
|
||||
setBlockResultLoc(&loop_scope, rl);
|
||||
defer loop_scope.instructions.deinit(mod.gpa);
|
||||
|
||||
var cond_scope: Scope.GenZIR = .{
|
||||
@ -2115,12 +2103,21 @@ fn forExpr(
|
||||
const index_plus_one = try addZIRBinOp(mod, &loop_scope.base, for_src, .add, index_2, one);
|
||||
_ = try addZIRBinOp(mod, &loop_scope.base, for_src, .store, index_ptr, index_plus_one);
|
||||
|
||||
// looping stuff
|
||||
const loop = try addZIRInstLoop(mod, &for_scope.base, for_src, .{
|
||||
.instructions = try for_scope.arena.dupe(*zir.Inst, loop_scope.instructions.items),
|
||||
});
|
||||
const loop = try scope.arena().create(zir.Inst.Loop);
|
||||
loop.* = .{
|
||||
.base = .{
|
||||
.tag = .loop,
|
||||
.src = for_src,
|
||||
},
|
||||
.positionals = .{
|
||||
.body = .{
|
||||
.instructions = try scope.arena().dupe(*zir.Inst, loop_scope.instructions.items),
|
||||
},
|
||||
},
|
||||
.kw_args = .{},
|
||||
};
|
||||
const for_block = try addZIRInstBlock(mod, scope, for_src, .block, .{
|
||||
.instructions = try for_scope.arena.dupe(*zir.Inst, for_scope.instructions.items),
|
||||
.instructions = try scope.arena().dupe(*zir.Inst, &[1]*zir.Inst{&loop.base}),
|
||||
});
|
||||
loop_scope.break_block = for_block;
|
||||
loop_scope.continue_block = cond_block;
|
||||
@ -2141,15 +2138,6 @@ fn forExpr(
|
||||
};
|
||||
defer then_scope.instructions.deinit(mod.gpa);
|
||||
|
||||
// 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
|
||||
// branches.
|
||||
const branch_rl: ResultLoc = switch (rl) {
|
||||
.discard, .none, .ty, .ptr, .ref => rl,
|
||||
.inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = for_block },
|
||||
};
|
||||
|
||||
var index_scope: Scope.LocalPtr = undefined;
|
||||
const then_sub_scope = blk: {
|
||||
const payload = for_node.payload.castTag(.PointerIndexPayload).?;
|
||||
@ -2178,16 +2166,8 @@ fn forExpr(
|
||||
break :blk &index_scope.base;
|
||||
};
|
||||
|
||||
const then_result = try expr(mod, then_sub_scope, branch_rl, for_node.body);
|
||||
if (!then_result.tag.isNoReturn()) {
|
||||
_ = try addZIRInst(mod, then_sub_scope, then_src, zir.Inst.Break, .{
|
||||
.block = cond_block,
|
||||
.operand = then_result,
|
||||
}, .{});
|
||||
}
|
||||
condbr.positionals.then_body = .{
|
||||
.instructions = try then_scope.arena.dupe(*zir.Inst, then_scope.instructions.items),
|
||||
};
|
||||
loop_scope.break_count += 1;
|
||||
const then_result = try expr(mod, then_sub_scope, loop_scope.break_result_loc, for_node.body);
|
||||
|
||||
// else branch
|
||||
var else_scope: Scope.GenZIR = .{
|
||||
@ -2198,30 +2178,35 @@ fn forExpr(
|
||||
};
|
||||
defer else_scope.instructions.deinit(mod.gpa);
|
||||
|
||||
if (for_node.@"else") |else_node| {
|
||||
const else_src = tree.token_locs[else_node.body.lastToken()].start;
|
||||
const else_result = try expr(mod, &else_scope.base, branch_rl, else_node.body);
|
||||
if (!else_result.tag.isNoReturn()) {
|
||||
_ = try addZIRInst(mod, &else_scope.base, else_src, zir.Inst.Break, .{
|
||||
.block = for_block,
|
||||
.operand = else_result,
|
||||
}, .{});
|
||||
}
|
||||
} else {
|
||||
const else_src = tree.token_locs[for_node.lastToken()].start;
|
||||
_ = try addZIRInst(mod, &else_scope.base, else_src, zir.Inst.BreakVoid, .{
|
||||
.block = for_block,
|
||||
}, .{});
|
||||
}
|
||||
condbr.positionals.else_body = .{
|
||||
.instructions = try else_scope.arena.dupe(*zir.Inst, else_scope.instructions.items),
|
||||
var else_src: usize = undefined;
|
||||
const else_result: ?*zir.Inst = if (for_node.@"else") |else_node| blk: {
|
||||
else_src = tree.token_locs[else_node.body.lastToken()].start;
|
||||
loop_scope.break_count += 1;
|
||||
break :blk try expr(mod, &else_scope.base, loop_scope.break_result_loc, else_node.body);
|
||||
} else blk: {
|
||||
else_src = tree.token_locs[for_node.lastToken()].start;
|
||||
break :blk null;
|
||||
};
|
||||
if (loop_scope.label) |some| {
|
||||
if (!some.used) {
|
||||
return mod.fail(scope, tree.token_locs[some.token].start, "unused for label", .{});
|
||||
}
|
||||
}
|
||||
return &for_block.base;
|
||||
return finishThenElseBlock(
|
||||
mod,
|
||||
scope,
|
||||
rl,
|
||||
&loop_scope,
|
||||
&then_scope,
|
||||
&else_scope,
|
||||
&condbr.positionals.then_body,
|
||||
&condbr.positionals.else_body,
|
||||
then_src,
|
||||
else_src,
|
||||
then_result,
|
||||
else_result,
|
||||
for_block,
|
||||
);
|
||||
}
|
||||
|
||||
fn getRangeNode(node: *ast.Node) ?*ast.Node.SimpleInfixOp {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user