Overview of Frame Control Flow Mechanisms
Frame is an evolving language and the current version (v0.3.23 at this instant) only supports branching syntax of various flavors. So at the moment you can’t loop (no for, while or any other way to spin around), but that limitation turns out not to be critical for the problem domain Frame is intended to address.
The two flavors of branching are a boolean if-then-else syntax and a similar pattern matching syntax, both loosely inspired by the ternary operator which I always thought came from
C but apparently was stolen from
CPL (one of the many languages I’ve never programmed in).
The basic syntax for both classes of test are:
1 x ?<type> <branches> : <else clause> ::
: token is “else” and
:: terminates the statement for all branching statement types.
Let’s explore the boolean test first.
The basic boolean test in Frame is:
1 x ? callIfTrue() : callIfFalse() ::
This generates this in
To reinforce the point that branching in Frame is not an expression evaluation, see how we can call multiple statements inside each branch:
1 2 3 4 5 6 7 x ? a() b() : c() d() ::
To negate the test use the
1 x ?! callIfFalse() : callIfTrue() ::
Next we will explore the Frame equivalent of the switch statement for string matching.
Pattern Matching Statements
Frame uses a novel but easy to understand notation for switch-like statements:
1 2 3 4 test ?<type> /pattern1/ statements :> /pattern2/ statements : statements ::
The currently supported operators are
?~ for string matching and
?# for number/range matching. The
: token indicates else/default and
:: terminates the pattern matching statement.
The string matching statement looks like this:
1 2 3 4 name() ?~ /Elizabeth/ hiElizabeth() :> /Robert/ hiRobert() : whoAreYou() ::
And results in this code:
Frame also permits multiple string matches per pattern:
1 2 3 4 name() ?~ /Elizabeth|Beth/ hiElizabeth() :> /Robert|Bob/ hiRobert() : whoAreYou() ::
With this output:
Number matching is very similar to string pattern matching:
1 2 3 4 n ?# /1/ print("It's a 1") :> /2/ print("It's a 2") : print("It's a lot") ::
The output is:
Frame can also pattern match multiple numbers to a single branch as well as compare decimals:
1 2 3 4 n ?# /1|2/ print("It's a 1 or 2") :> /101.1|100.1/ print("It's over 100") : print("It's a lot") ::
The output is:
Branches and Transitions
The default behavior of Frame is to label transitions with the message that generated the transition. This is fine when an event handler only contains a single transition:
1 2 3 4 5 6 7 8 9 10 #GottaBranch -machine- $A |e1| -> $B ^ $B ##
However this leads to ambiguity with two or more transitions from the same event handler:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #GottaBranch_v2 -machine- $Uncertain |inspect| foo() ? -> $True : -> $False :: ^ $True $False ##
Transition labels provide clarity as to which transition is which:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #GottaBranch_v3 -machine- $Uncertain |inspect| foo() ? -> "true foo" $True : -> "foo not true" $False :: ^ $True $False ##
The three core branching statements - boolean test, string pattern match and number pattern match - provide a surprisingly useful set of functionality for most common branching needs despite currently being rather limited in expressive power. Look for advancement in the robustness and capability of the pattern matching statements in the future.