feat: execute collection and index iteration

This commit is contained in:
2026-10-27 15:08:37 +01:00
parent 0f5d3c222a
commit 0aca64a77e
9 changed files with 546 additions and 17 deletions
+80 -5
View File
@@ -482,13 +482,17 @@ predeclare_locals proc(state @mut State, block ast.NodeId) void ! (mem.AllocErro
}
.for_stmt: {
loop :: ast.for_stmt(state.tree, statement)
is_range :: ast.expr_kind(state.tree, loop.iterable) == .range
family :: typecheck.type_of(state.checked, loop.iterable).range_element
type :: lower_type(state, typecheck.Type{ kind = family })
type ir.Type :: if (is_range) lower_type(state, typecheck.Type{ kind = family }) else .usize
slot :: try ir.add_local(state.module, ir.FunctionId(state.function), type, ir.no_array)
state.storage[usize(statement)] = Storage{ kind = .local, index = u32(slot) }
if (loop.capture) |capture| state.storage[usize(capture)] = state.storage[usize(statement)]
if (loop.capture) |capture| {
if (is_range) state.storage[usize(capture)] = state.storage[usize(statement)]
else try predeclare_capture(state, capture)
}
if (loop.index) |index| {
index_slot :: try ir.add_local(state.module, ir.FunctionId(state.function), .int, ir.no_array)
index_slot :: try ir.add_local(state.module, ir.FunctionId(state.function), .usize, ir.no_array)
state.storage[usize(index)] = Storage{ kind = .local, index = u32(index_slot) }
}
try predeclare_locals(state, loop.body)
@@ -705,8 +709,7 @@ lower_while proc(state @mut State, id ast.NodeId) void ! (mem.AllocError | diagn
lower_for proc(state @mut State, id ast.NodeId) void ! (mem.AllocError | diagnostics.CapacityError) {
loop :: ast.for_stmt(state.tree, id)
if (ast.expr_kind(state.tree, loop.iterable) != .range) {
_ = try lower_expression(state, loop.iterable)
if (!state.terminated) _ = trap_type(state, id)
try lower_collection_for(state, id)
return
}
interval :: ast.range_expr(state.tree, loop.iterable)
@@ -765,6 +768,78 @@ lower_for proc(state @mut State, id ast.NodeId) void ! (mem.AllocError | diagnos
state.terminated = false
}
@hide:file
lower_collection_for proc(state @mut State, id ast.NodeId) void ! (mem.AllocError | diagnostics.CapacityError) {
loop :: ast.for_stmt(state.tree, id)
parts :: try slice_parts(state, loop.iterable)
if (state.terminated or trap_type(state, loop.iterable) or trap_type(state, id)) return
slot :: state.storage[usize(id)].index
zero :: try usize_constant(state, 0, loop.span)
_ = try emit(state, ir.Instruction{ op = .store_local, type = .usize, left = zero, slot = slot, span = loop.span })
origin :: state.block
condition :: try add_block(state)
body :: try add_block(state)
update :: try add_block(state)
exit :: try add_block(state)
state.module.functions.items[state.function].blocks.items[usize(origin)].terminator = ir.Terminator{
kind = .jump, target = condition, span = loop.span,
}
state.block = condition
current :: try emit(state, ir.Instruction{ op = .load_local, type = .usize, slot = slot, span = loop.span })
condition_value :: try emit(state, ir.Instruction{ op = .less, type = .bool, left = current, right = parts.bound, span = loop.span })
state.module.functions.items[state.function].blocks.items[usize(state.block)].terminator = ir.Terminator{
kind = .branch, value = condition_value, target = body, alternative = exit, span = loop.span,
}
previous_loop :: state.loop
state.loop = LoopTargets{ continue_target = update, exit = exit, cleanup_depth = state.cleanups.items.len }
defer state.loop = previous_loop
state.block = body
if (loop.capture) |capture| {
if (!trap_binding(state, capture) and !trap_type(state, capture)) {
runtime :: lower_type(state, parts.element)
shape :: try array_shape(state, parts.element)
pointer :: try emit(state, ir.Instruction{
op = .pointer_offset, type = .pointer, left = parts.pointer, right = current,
pointee = runtime, array_type = shape, span = loop.span,
})
value := pointer
if (!loop.pointer_capture) {
address :: try pointer_address(state, pointer, parts.element, loop.span)
value = try emit(state, ir.Instruction{
op = .load_address, type = runtime, array_type = shape, left = address, span = loop.span,
})
}
checked :: typecheck.type_of(state.checked, capture)
_ = try emit(state, ir.Instruction{
op = .store_local, type = lower_type(state, checked), array_type = try array_shape(state, checked),
left = value, slot = state.storage[usize(capture)].index, span = loop.span,
})
}
}
if (loop.index) |index| {
if (!state.terminated and !trap_binding(state, index) and !trap_type(state, index)) {
_ = try emit(state, ir.Instruction{
op = .store_local, type = .usize, left = current, slot = state.storage[usize(index)].index, span = loop.span,
})
}
}
if (!state.terminated) try lower_block(state, loop.body, true)
if (!state.terminated) state.module.functions.items[state.function].blocks.items[usize(state.block)].terminator = ir.Terminator{
kind = .jump, target = update, span = loop.span,
}
state.block = update
state.terminated = false
last :: try emit(state, ir.Instruction{ op = .load_local, type = .usize, slot = slot, span = loop.span })
one :: try usize_constant(state, 1, loop.span)
next :: try emit(state, ir.Instruction{ op = .add, type = .usize, left = last, right = one, span = loop.span })
_ = try emit(state, ir.Instruction{ op = .store_local, type = .usize, left = next, slot = slot, span = loop.span })
state.module.functions.items[state.function].blocks.items[usize(state.block)].terminator = ir.Terminator{
kind = .jump, target = condition, span = loop.span,
}
state.block = exit
state.terminated = false
}
@hide:file
lower_statement proc(state @mut State, id ast.NodeId) void ! (mem.AllocError | diagnostics.CapacityError) {
tree :: state.tree