Skip to content

Statements

A script is a list of statements. This page covers the ones that control the flow. Assignment is on Variables and scope, blocks on Blocks and calls, and errors on Errors.

Every statement on this page has a body. You can write the body in either of two ways:

  • Natural: the statements, then end.
  • Standard: the statements between { and }. No end is needed.
set x to 3
if x is more than 2
printline "big"
end
big

A condition can be written with or without brackets. A body can also start on the same line as its condition. The two forms mix freely, even in one script:

set x to 3
if x is more than 2
printline "natural"
end
if (x is more than 2) {
printline "standard"
}
if x is more than 2 printline "one line"
natural
standard
one line
set x to 10
if x is less than 10
printline "under ten"
else if x is more than 10
printline "over ten"
else
printline "exactly ten"
end
exactly ten

else if can be written as elseif. In the standard form, else follows the closing brace on the same line:

set x to 20
if x is less than 10
printline "under"
else if x is more than 10
printline "over"
else
printline "ten"
end
over

The condition is read as a boolean, following the rules in Values and types. It can also be an assignment, which is then tested. See Variables and scope.

If working out the condition fails, the error is recorded and the condition is read as false. The else branch runs.

each runs its body once for every item of an array, dictionary, range or collection.

each ["a", "b"] as item
printline item
end
a
b

The forms are:

FormSets
each sourcevalue is the item
each source as itemitem is the item
each source as key, itemkey is the position or key, item is the item

Put the key first. For an array the key is the position, from 0. For a dictionary it is the key.

each 1...2
printline value
end
each ["a", "b"] as i, v
printline "{{i}}: {{v}}"
end
each {x: 1, y: 2} as k, v
printline "{{k}} = {{v}}"
end
1
2
0: a
1: b
x = 1
y = 2

The loop variables are ordinary variables and keep their last value after the loop. See Variables and scope.

each i in source and each k, v in source are the same as each source as i and each source as k, v. Use whichever reads better.

each i in 1...3
print i
end
printline ""
each k, v in {a: 1, b: 2}
printline "{{k}} = {{v}}"
end
123
a = 1
b = 2

each over a value that is not a list (a yes-or-no value, a number or a string) records the error Invalid argument supplied to each: <type>, not a list and runs no passes. each over null runs zero times and records nothing.

Each pass of a loop counts as one step towards the run’s time limit.

each 1...3 as n
print n
end
printline ""
each 3...1 as n
print n
end
printline ""
123
321

See Values and types for ..< and an empty list.

while runs its body as long as the condition is true. until runs its body as long as the condition is false. Both test before the first pass, so the body can run zero times.

set i to 0
while i is less than 3
print i
increment i by 1
end
printline ""
until i is 0
decrement i by 1
print i
end
printline ""
012
210

break leaves the nearest loop. next skips to the next pass.

each 1...10 as n
if n is 2
next
end
if n is more than 4
break
end
print n
end
printline ""
134

They also work inside a block passed to a method such as each. There break and next both end the current call of the block, because there is no loop to leave:

mash.collect([1, 2, 3]).each(block v
if v is 2
next
end
printline v
end)
1
3

ensure checks that something holds, and runs a different branch when it does not. Its body must contain return, next, break, fail or exit; the script does not compile without one.

The usual form is a check with an else that leaves:

block label n
ensure n is more than 0 else
return "must be positive"
end
return "ok"
end
printline label(5)
printline label(-1)
ok
must be positive

Several conditions can be separated with commas, and all must be true. The brackets around them are optional.

block check a b
ensure a is more than 0, b is more than 0 else
return "bad"
end
return "good"
end
printline check(1, 1)
printline check(1, 0)
good
bad

return value leaves the current block and gives the value back. return with no value gives null. At the top level of a script, return ends the script, and the value is the script’s result.

A block that ends without return gives the value of its last statement. See Blocks and calls.

exit ends the script and counts as success. exit value writes the value to the output first, with no line ending.

printline "a"
exit "bye"
printline "b"
a
bye
block stopper
printline "in the block"
exit
end
stopper()
printline "never printed"
in the block

fail "message" stops the script and marks the run as failed, with the message and the line. Nothing after it runs, and no error block catches it.

printline "before"
fail "stop here"
printline "never printed"

fail is the only statement that is certain to stop a run. Errors covers throw, which looks similar but does not stop anything.

throw "message" records an error and carries on. raise is the same statement. See Errors.

yield hands one value at a time to the code that called the block. See Blocks and calls.

StatementNaturalStandard
Conditionif c … else if c … else … endif (c) { } else if (c) { } else { }
Loop over itemseach src as k, v … endeach src as k, v { }
Loop on a testwhile c / until c … endwhile (c) { }
Leavebreak, nextsame
Guardensure c else … endensure c else { }
Stopexit, fail "m"same