KAL control flow
IF/ELSE, WHILE, FOR EACH, BREAK/CONTINUE, TRY/CATCH/FINALLY, THROW and ABORT — with their exact shapes.
IF / ELSE#
IF <condition> THEN {
...
} ELSE {
...
} END IF;
THEN, the braces and the closingEND IF;are mandatory.- There are no parentheses around the condition.
- There is no
ELSE IF— nest a secondIFinside theELSEblock.
KAL VERSION 2.0;
AUTOMATION size_report {
WHEN COMMAND size (n AS NUMBER) {
IF n > 100 THEN {
REPLY "huge";
} ELSE {
IF n > 10 THEN {
REPLY "big";
} ELSE {
REPLY "small";
} END IF;
} END IF;
}
}
WHILE#
WHILE <condition> DO {
...
} END WHILE;
KAL VERSION 2.0;
AUTOMATION countdown {
WHEN COMMAND countdown {
DECLARE i = 5;
WHILE i > 0 DO {
SET i -= 1;
} END WHILE;
REPLY "Liftoff after " + ("" + i) + " … counted 5 down";
}
}
FOR EACH#
Iterates arrays and maps (for maps, the loop variable receives each key):
FOR EACH <item> IN <array-or-map> DO {
...
} END FOR;
KAL VERSION 2.0;
AUTOMATION loop_demo {
WHEN COMMAND announce_all {
DECLARE channels_of_interest = ["general", "off-topic"];
FOR EACH name IN channels_of_interest DO {
LOG "Mentioning channel " + name;
} END FOR;
}
}
BREAK and CONTINUE#
Both work in WHILE and FOR EACH. Using them outside a loop is a compile error. Combining them with the membership operators keeps filters readable:
KAL VERSION 2.0;
AUTOMATION filter_demo {
WHEN COMMAND pick_first {
DECLARE candidates = ["skip", "keep", "also-skip", "stop"];
DECLARE chosen = "";
FOR EACH candidate IN candidates DO {
IF candidate == "skip" OR candidate == "also-skip" THEN {
CONTINUE;
} END IF;
IF candidate == "stop" THEN {
BREAK;
} END IF;
SET chosen = candidate;
} END FOR;
REPLY "Chose: " + chosen;
}
}
TRY / CATCH / FINALLY#
TRY {
...
} CATCH err {
...
} FINALLY {
...
} END TRY;
CATCH binds the error value (use err.message); FINALLY runs either way; all three parts are optional except TRY itself.
KAL VERSION 2.0;
AUTOMATION safe_divide {
WHEN COMMAND divide (a AS NUMBER, b AS NUMBER) {
TRY {
REPLY "" + (a / b);
} CATCH err {
REPLY "Could not divide: " + err.message;
} FINALLY {
LOG "division attempted";
} END TRY;
}
}
THROW and ABORT#
THROW <expression>; // raise an error (catchable upstream)
ABORT [WITH <expression>]; // stop the whole run immediately
ABORT ends the run right there — nothing after it executes; use it for "not allowed, stop processing" checks.
Two things that do not exist#
- No
ELSE IF— nestIFblocks instead. - No
SWITCH/MATCH— chains ofIFare the idiom.