Control blocks are an indented sequence of statements that are wrapped together in a shared control context and lexical scope for local variable declarations. Acorn offers several types of control blocks:

Control clauses are a concise version of three of these control blocks (if, while, each). Control clauses make it possible for a single line to contain both a statement (such as an expression statement, break, continue, return or yield) and a control clause that operates on just that statement as if it were a one statement block. Multiple clauses may be specified on a statement; they are handled in reverse order (see each clause for examples). Any expression statement that uses a control clause should avoid declaring local variables; its variables are lexically scoped within the control clauses that follow.

'do'

A 'do' block without specified values may be used to separate out an indented sequence of statements that have a lexical scope for local variables.

do
	local max = a<b ? b : a
	Vm.Print(max)

A 'do' block that specifies one or more comma-separated expressions acts as a context manager (similar to Python's 'with' statement). Acorn will invoke the .Begin method on all those values before performing the first statement in the block. It will also invoke the .End method on all those values after performing the last statement in the block.

do timer
	# timer.Begin automatically performed here
	biglist.Sort
	# timer.End automatically performed here

'do' offers a safe, convenient way to handle resources that have a specific usage life-time, such as files, i/o, timers, transactions (where .End performs a commit), processes, locks, or yielders. It is perfectly fine for a resource's type to implement an 'End' method but not a 'Begin' method.

'if'

Acorn provides three techniques for using conditional expressions to determine which value to use or which code block to perform: the '?' operator, the 'if' clause, and the 'if' code block.

? operator

The ? operator is a concise way to pick one of two values within an expression. If the expression before the ? operator is true, the value after the '?' is picked. Otherwise the value after the 'else' is chosen:

x = val<5.0 ? 5.0 else val   # sets x to the higher between 5.0 and val

Note: To avoid the possibility of a question-mark being treated as part of a method or property name, always be sure to put a space before the ? operator.

if clause

If you have a single statement that should execute (or not) based on a condition, append the statement with 'if' followed by the condition:

val = 5.0 if val<5.0   # if val is less than 5, set it to 5

if block

For more complex scenarios, use the 'if' block. The statements to perform on a true condition are tab-indented as a block.

if cmd=='snow'
	sky.weather = cmd
	$$.ambient Color.Gray

Use the 'else' block whenever you have alternative set of statements to perform should the condition evaluate as false.

if actor.mood == 'happy'
	actor.action = 'dance'
else
	actor.eyes = 'cry'

One can insert one or more 'elif' blocks to sequentially check other conditions and perform the associated statement block if true. 'else', if specified, should always be last.

moving = true
if x<=0.0
	speed = 0.0
	moving = false
elif y<3.0
	speed = 1.0
else
	speed = 5.0

match

The match block is similar to, but more powerful than, the 'switch' block found in other languages. The 'match' block is used to sequentially match a single value against multiple patterns. It will perform the first code block associated with a successful match, or the 'else' block, if there are no matches.

match term_speed
with 0.0 .. 1.5  # equivalent to: if +Range(0.,1.5).'~~'(term_speed)
	ship.state = 'landing'
with 1.5 .. 4.0  # equivalent to: if +Range(1.5,4.0).'~~'(term_speed)
	ship.state = 'crashing'
else
	ship.state = 'flattened'

By default, the 'match' block uses the '~~' method to match each successive pattern against the value of the 'match' statement's expression, as the comments demonstrate. A match happens if the return value is anything other than false or null. The first 'with' matches if the value term_speed lies between 0 and 1.5. If it matches, the ship's state is set to 'landing'.

Several of Acorn's core types implement the '~~' method:

Additional pattern matching types can be easily defined that implement the '~~' method, thereby extending the pattern matching capability of Acorn.

The 'using' clause

Append a 'using' clause to the 'match' statement to specify a specific method to use for matching (as opposed to using the default '~~'):

match number using '=='
with 0
	.turn
with 1
	.jump

The using clause can specify any method symbol (including the default '==' and '===' provided by All). Any executable method, closure or yielder may also be specified.

Multiple patterns on a 'when'

A 'with' statement can list multiple match patterns, separated by commas. A match on any of those match patterns activates that code block.

match number using '=='
with 0,1
	.turn
with 2,3,4
	.jump

Extracting match results

Some patterns do more than matching. They also extract or transform matched elements within a successfully matched source value, returning one or more new digested value (so long as the first returned value is not false or null, which indicates a match failure). Specify the variables names that hold these returned values with an 'into' clause at the end of the 'match' statement:

# Cmd is a custom-built pattern for decoding commands
match command into thing
with +Regex"fight [*]"
	combat: true
	opponent: thing
with +Regex"use [*]"
	.use(thing)

Regex returns the portion of the Text that lies within the square brackets. So, if command was "fight Lux", the first match would succeed and thing would be set to "Lux".

Alternatively, the return variable name(s) may be specified on any specific 'with' statement:

match command
with +Regex"fight [*]" into npc
	combat: true
	opponent: npc
with +Regex"use [*]" into item
	.use(item)

while

while executes the same statement(s) over and over as long as its condition remains true. The condition is checked right away and every time after the statement(s) have been performed.

This example uses a while block:

x = 0
while x<=5
	$.log "WARNING, WARNING! Will Robinson"
	x+=1

while may be used as a control clause:

$$.show(list.extract) while !list.empty?

The break statement, placed anywhere within a while block, provides a way to instantly and explicitly stop performance of the 'while' block statements. break is typically used with an 'if' control clause:

while true    # without the break, this loop would run forever
	actor.walkstep  # will happen at least once
	break if keypress=='space' # stops whenever the space bar is pressed

By contrast, the continue statement ignores all subsequent statements in the 'while' block, returning control back to the top of the while block where the conditional expression is re-evaluated.

_