Skip to content

Control Flow

Statement Purpose
if ... end if Conditional execution
if ... else ... end if Two-way branching
if ... else if ... end if Multi-way branching
while ... end while Condition-based loops
for ... to ... end for Counted loops (ascending)
for ... downto ... end for Counted loops (descending)
select ... case ... end select Multi-way value matching (no fall-through)

KSP has no break or continue statements. Use iterator manipulation for early exit.


Conditional Statements

if / else / else if

if condition
    // ...
end if

if condition
    // ...
else
    // ...
end if

if condition1
    // ...
else if condition2
    // ...
else
    // ...
end if
if ui.option.disp_active = TRUE and ui.disp_timestamp > -1
    if lib.get_last_touched() - ui.disp_timestamp > UI.PARAM_DISP_DELAY_MS
        set_text(ui.Display, "")
        ui.disp_timestamp := -1
    end if
end if
if not check_ref(Voice, vo_to_send)
    if vo_to_send = self
        message('Node ' & ivls.node_name(nenv) & ' tried to play passive input after release!')
    else
        message('Node ' & ivls.node_name(nenv) & ' tried to play invalid Voice!')
        cluster.Dump(Voice, self)
    end if
else if self_invalid = TRUE
    message('IVLS has been halted at node ' & ivls.node_name(nenv))
    Voice.delete(vo_to_send)
else if NodeEnv[nenv].info.path_cancelled = TRUE and not (Voice[vo_to_send].duration > 0)
    if vo_input = self
        Voice.delete(vo_to_send)
    end if
else
    if Voice[vo_to_send].stage < ivls.flow_lengths[Voice[vo_to_send].flow] - 1
        ivls._fire_new_child(vo_to_send, vo_as_parent)
        NodeEnv[nenv].sentVoice := vo_to_send
    else
        Voice.delete(vo_to_send)
    end if
end if

While Loop

while (condition)
    // ...
end while
while (Arp.Notes.count[thread] > 0)
    if Arp.step_counter[thread] >= Arp.Notes.count[thread]
        Arp.step_counter[thread] := 0
    end if

    declare arp_note := Voice.copy(tpl)
    Voice[arp_note].note := Arp.Notes[thread, Arp.step_counter[thread]]
    Voice[arp_note].vel := Arp.Velocities[thread, Arp.step_counter[thread]]
    Voice[arp_note].duration := STEPTIME * 1000

    ivls.play(arp_note)
    inc(Arp.step_counter[thread])
    ivls.wait_ms.unsafe(STEPTIME)
end while

Linked list traversal:

declare current := FIFO.peek_entry(Runtime[runtime].voiceList)
while(check_ref(Entry, current))
    declare next := Entry[current].next
    if Voice[Entry[current].data].note = note
        keys.KeyBuffer.delete_item(ch, Entry[current].data)
    end if
    current := next
end while

Multiple exit conditions:

while (path_exhausted = FALSE and user_continue = TRUE and self_invalid = FALSE)
    path_exhausted := TRUE
    user_continue := FALSE
    // ... processing that may set user_continue := TRUE ...
end while

For Loop

Ascending (to)

for iterator := start to end_value
    // ...
end for
for Voice.i := 0 to num_elements(#array#) - 1
    Voice.INIT[Voice.write_idx] := #array#[Voice.i]
    inc(Voice.write_idx)
end for

Nested loops:

for i := 0 to IVLS.MAX_FLOWS - 1
    sum := 0
    for j := 0 to IVLS.NODES_PER_FLOW - 1
        if ivls.flows[i, j] = -1
            j := IVLS.NODES_PER_FLOW  // early exit
        else
            inc(sum)
        end if
    end for
    ivls.flow_lengths[i] := sum
end for

Descending (downto)

for iterator := start downto end_value
    // ...
end for
function search_last(array, value) -> return
    return := -1
    for srch.i := num_elements(array) - 1 downto 0
        if array[srch.i] = value
            return := srch.i
            srch.i := -1  // early exit
        end if
    end for
end function

Select-Case

Multi-way value matching. Cases do not fall through.

select expression
    case value1
        // ...
    case value2
        // ...
end select
select Voice[self].delay_type
    case ivls.duration_type.MS
        ivls.wait_us(Voice[self].delay)
    case ivls.duration_type.TICKS
        ivls.wait_ticks(Voice[self].delay)
end select
select json.value.type
    case json.type.INT
        @value := f'<json.value.int_value>'
    case json.type.FLOAT
        @value := f'<json.value.float_value>'
    case json.type.STRING
        @value := f'\"<json.value.str_value>\"'
end select

Early Exit Patterns (No break/continue)

For loop: set iterator past bounds

for i := 0 to count - 1
    if found_target
        i := count  // exits ascending loop
    end if
end for

for i := max downto 0
    if found_target
        i := -1  // exits descending loop
    end if
end for

While loop: use flag or condition variable

declare done := FALSE
while (done = FALSE)
    if exit_condition
        done := TRUE
    else
        // processing
    end if
end while

See Also

  • Operators - Comparison and logical operators
  • Functions - Control flow within functions
  • Macros - Control flow in macro expansions