Kharat Bot Docs

KAL control flow

IF/ELSE, WHILE, FOR EACH, BREAK/CONTINUE, TRY/CATCH/FINALLY, THROW and ABORT — with their exact shapes.

IF / ELSE#

kal (fragment)
IF <condition> THEN {
    ...
} ELSE {
    ...
} END IF;
  • THEN, the braces and the closing END IF; are mandatory.
  • There are no parentheses around the condition.
  • There is no ELSE IF — nest a second IF inside the ELSE block.
kal
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#

kal (fragment)
WHILE <condition> DO {
    ...
} END WHILE;
kal
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):

kal (fragment)
FOR EACH <item> IN <array-or-map> DO {
    ...
} END FOR;
kal
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
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#

kal (fragment)
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
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#

kal (fragment)
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 — nest IF blocks instead.
  • No SWITCH/MATCH — chains of IF are the idiom.