Logic Block
A logic block tests values rather than text. It reads no input and moves no cursor: it succeeds or it fails, and consumes nothing either way. That is what lets a grammar decide something instead of merely matching it.
It is written between curly braces.
A = {5 * 5 == 20};
B = (char => numvar x) . (char => numvar y) . {y = 15; x * y == 65};
A fails, because 5 * 5 == 20 is false. In B two characters are captured,
y is set to 15, and the block succeeds only if x * y == 65.
What a block answers
A logic block answers true or false, and true is the default.
Statements are separated by ;, and the last one’s value is the block’s
answer. A statement that produced no value — an assignment, a cleared set —
is a deed rather than an answer, and a deed is no reason to fail. So a block
whose last statement is an assignment holds.
{x == "cat"} # answers the comparison
{y = 15; x * y == 65} # a deed, then an answer
{y = 15} # only a deed -- holds
The final block
{{ ... }} is a final block. It runs for what it does, and its result is
not checked — it always holds.
B := "a" . {{9 => n}};
Use it when the point is the effect rather than the verdict: setting a variable, clearing a set, counting something. Nothing may follow a final block in the grammar, because there is no outcome for the rest to depend on.
The difference in one line: an ordinary block can fail the action it sits in, a final block cannot.
Operators
Precedence follows C, tightest binding first: NOT, then * /, then +
-, then < <= > >=, then == !=, then AND, then OR. Brackets
override it.
NOT a
a * b a / b # division by zero is 0
a + b a - b # a - b clamps at 0 rather than wrapping
a < b a <= b a > b a >= b
a == b a != b
a AND b
a OR b
TRUE FALSE # one and zero
AND and OR short-circuit, the way C’s && and || do: the right side
is not evaluated when the left has already settled the answer.
Text compares by bytes, and == and != are the only operators it has —
arithmetic over text is refused when the grammar is validated, not at run time.
Asking about a semvar
set::is(t) # is t a member?
set::not(t) # is it not?
set::clear # empty the set -- a deed, so it holds
See also
A logic block is also the condition of an IF statement, and
it reads values put into Variables with =>. To stop the parse
outright rather than fail a match, see System Functions.