Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

10. Execution model

How a Korrin program runs, once it has lexed, parsed, and resolved without error.

10.1 Program start

A program is a list of top-level statements. They execute in order, top to bottom, in the global scope. fn and class statements bind their names when reached, so a function must be defined above its first call at the top level (though mutual recursion between functions works, because the calls happen later, at run time).

fn even(n):
    if n == 0:
        return true
    return odd(n - 1)

fn odd(n):
    if n == 0:
        return false
    return even(n - 1)

print(even(10))
# => true

10.2 Scopes and environments

There are exactly two kinds of scope: the global scope, and a function-call scope (ADR 0011). if, while, and for do not create scopes. Each call gets a fresh scope whose parent is the scope where the function was defined (not where it was called) — this is what makes closures work.

Name resolution — for both reads and the target of = — searches the current scope, then each enclosing scope, out to global. = updates the nearest binding found, or creates one in the current scope if there is none.

10.3 Evaluation order

  • Binary operators evaluate the left operand, then the right, then combine.
  • A call evaluates the callee, then each argument left to right, then calls.
  • and / or evaluate the left operand, and the right only if needed.
  • List and map literals evaluate their elements in source order (for a map, each key before its value).

10.4 Value semantics

Scalars (nil, bool, int, float) and str are effectively immutable — operations produce new values. list, map, and instance are reference types: the same object can be reached through several names, and a mutation through one is visible through all (§3.4).

A for loop iterates over a snapshot of a list taken when the loop starts, so appending to the list inside the loop does not extend the iteration.

xs = [1, 2, 3]
for x in xs:
    xs.push(x)
print(xs.len())
# => 6

10.5 Runtime limits

Function-call nesting is bounded. The interpreter grows its working stack on demand, but a call depth beyond its limit (currently 10 000) is reported as E0313 rather than aborting the process. This turns an infinite recursion into a diagnostic.

10.6 Termination

A program ends when its last top-level statement finishes, or at the point a runtime error is raised. There is no explicit exit function in Milestone 1.