Control Structures
Single Line and Multi-Line Commands
- if, while, and forEach support single line commands as well as multi-line commands.
- If a control structure has commands on the same line after the condition, it is taken to be a single line statement - all commands on that line (separated by semi-colons) are part of the body and no terminal end marker is required.
- If a control structure doesn't have commands immediately following the condition, it's considered a multi-line command and an appropriate "end" command is looked for.
- A multi-part if/elseIf/else cannot mix and match single and multi-line blocks. They must all be single or all be multi (otherwise nested if statements could be ambiguous).
- Single line statements may not have any nested control structures.
If
Syntax:
if (condition) ... elseIf (condition) ... else ... endIf if (condition) single; line; commands elseIf (condition) single; line; commands else single; line; commands
Examples:
if (x > 0) println( "$ is positive" (x) ) elseIf (x < 0) println( "$ is negative" (x) ) else println( "0 is zero" )
- Like all conditionals in Slag, if requires parentheses around the condition.
- escapeIf skips to the command after the enclosing endIf.
Which
Examples:
which (ch)
case 9: return "TAB"
case 10, 13: return "EOL" # well, kinda...
case 27: return "ESC"
case 32..126: return ""+Char(ch)
others: return "^" + Char(ch+64)
endWhich
forEach (a in 1..2)
forEach (b in 1..2)
which (a,b)
case (1,1): println( "R" )
case (1,2): println( "S" )
case (2,1): println( "T" )
case (2,2): println( "U" )
endWhich
endForEach
endForEach
- The which structure replaces the switch or select of other languages.
- Its cases may be any expressions, not just constants.
- Internally which statements are converted into if statements. The expression is saved in a local variable and then compared to each case value.
- No "break" commands are necessary.
- "others:" replaces "default:"
- Independent values can be part of the same case when separated by commas ("case a,b,c:" ).
- A case may contain a simple range of values, e.g. "case 1..10:". This is converted into a two-part conditional ("if (temp_value >= 1 and temp_value <= 10)").
- escapeWhich skips to the command after the enclosing endWhich.
Contingent
Syntax:
contingent # body (regular commands) ... necessary (condition) ... sufficient (condition) ... satisfied # commands if execution reaches end of body or any 'sufficient' cmd true unsatisfied # commands if any 'necessary' tests false. endContingent
Example:
method print_primes( Int32 low, Int32 high ):
forEach (n in low..high)
contingent
necessary (n >= 2)
sufficient (n == 2)
forEach (d in {2,3..sqrt(n) step 2})
necessary (n % d != 0)
endForEach
satisfied
println( "$ is a prime number" (n) )
endContingent
endForEach
- Slag introduces contingents as a new kind of conditional. They are similar in flow to a try/catch block but they deal with positive and negative logic tests rather than error generation.
- They are useful when it will take several consecutive commands to determine whether to execute "success" or "failure" code.
- Any commands may be placed in the body. These commands can include necessary() and sufficient() logic tests.
- If a necessary condition is true, execution proceeds to the next command. If false, execution jumps to the unsatisfied clause.
- If a sufficient condition is false, execution proceeds. If true, execution jumps to the satisfied clause.
- If all the body code is executed with no necessary conditions being false and no sufficient conditions being true, execution proceeds with the satisfied clause.
- If the satisfied clause executes, the unsatisfied clause is skipped.
- The satisfied and unsatisfied clauses are both optional. If not present the contingent behaves as if they were empty.
- escapeContingent skips to the command after the enclosing endContingent.
While
Syntax:
while (condition) ... endWhile while (condition) single; line; commands
Example:
# Sum together the digits of a non-negative integer until one digit is left. while (n > 0) n = n/10 + n%10 endWhile
- escapeWhile skips to the command after the enclosing endWhile.
- nextIteration skips the remainder of the current iteration and proceeds onto the next iteration.
Loop
Syntax:
loop ... endLoop
Example:
# Keep reading in numbers from some reader until a zero is read. loop local var n = reader.read if (n == 0) escapeLoop list.add(n) endLoop
- loop loops indefinitely and is a convenient alternative to "while (true) ...".
- escapeLoop skips to the command after the enclosing endLoop.
- nextIteration skips the remainder of the current iteration and proceeds onto the next iteration.
ForEach
Syntax:
# multi-line variants forEach (range) ... endForEach forEach (var_name in range) ... endForEach forEach (var_name of range) ... endForEach # single line variants forEach (range) single; line; commands forEach (var_name in range) single; line; commands forEach (var_name of range) single; line; commands
Examples:
forEach (1..100) println("I will use iteration to make my life easier.")
forEach (line in LineReader(File("settings.txt"))) println(line)
forEach (ch in "nilbog".reverse_order) print(ch)
println
forEach (entity in mobs)
entity.update
if (entity.is_dead) removeCurrent entity
endForEach
method index_of( Real64 n ).Int32:
forEach (index of data)
if (data[index] == n) return index
endForEach
return -1
- escapeForEach skips to the command after the enclosing endForEach.
- nextIteration skips the remainder of the current iteration and proceeds onto the next iteration.
- Read the notes on advanced forEach usage to learn about:
- How forEach loops are processed internally.
- How to write classes that are compatible with forEach.
- What causes concurrent modification errors and how to avoid them.
- How the removeCurrent command works.
Try/Catch & Throw
Syntax:
try
...
catch (MostSpecificType err)
...
catch (LessSpecificType err)
...
catch (MostGeneralType err)
...
endTry
...
throw Error("badwrong")
Example:
try
load_save_data( File("save.txt") )
catch (FileError err)
set_up_default_data()
endTry- The throw command takes an Exception (or subclass) object and unwinds the call stack to the most recently-defined catch of the correct type, no matter many nested calls you're currently in.
- try/catch and throw operate with objects extended from class Exception.
- Class Error extends class Exception and all built-in exceptions are extended from type Error.
- There are no checked exceptions in Slag - errors may be thrown at any time (without writing a declaration in the method signature) and enclosing try/catch blocks are entirely optional.
- Exception objects that are instanceOf the first catch type are handled by that catch and the other catches are skipped.
- Slag does not have a finally clause.
- Login to post comments
