4. The interpreter#

A settled library can run straight away, without generating any code. That's what tempest test does by default, what the playground's Run button shows, and how the functional tests check the frontend. The interpreter is small, and it's built to run code with errors in it too: an error node fails when it runs, with its message, as generated code would, and a value that's only of the wrong type runs as written, as in the dynamically typed backends (typing).

a callSettled libraryLower a function on itsfirst callCode: flat ops,numbered slotsFrame loop runs the opsOutput, failures, testresults
a callSettled libraryLower a function on itsfirst callCode: flat ops,numbered slotsFrame loop runs the opsOutput, failures, testresults
Diagram source
flowchart LR
  settled["Settled library"] --> lower["Lower a function on its first call"]
  lower --> code["Code: flat ops, numbered slots"]
  code --> frame["Frame loop runs the ops"]
  frame --> results["Output, failures, test results"]
  frame -->|"a call"| lower

How it runs#

Why each of these, and what else was considered: decisions, in detail.

Host code (@connected functions) runs only where the interpreter implements it: std's Date.today(), regex, and net, for now (builtins and connected code).

Worked example#

When triple.temper's top level calls triple(14), the body n * 3 is lowered on that first call to ops roughly like these (a sketch, not printed output; run-temper can't print ops yet):

Const(builtin *)   push the multiplication
Local(0)           push n, the first slot
Const(3)
Call { args: 2 }   n * 3
Return

The top level then concatenates the result into the string and logs it. run-temper triple.temper prints:

triple(14) = 42

Running tests#

test("name") { … } blocks become test cases during settling. run_tests runs a library's top level, then each module's tests, and reports them as JUnit XML, the same report std's test runner gives in every language. tempest test reads those results into one summary (the CLI page says more). What tests pin the interpreter itself: its tests, in detail.

Where in the code#

Later, the same interpreter is meant to evaluate constants and macros written in Temper during settling (notes/compile-time.md).

In detail#

The interpreter, in detail: each design decision with its alternatives and trade-offs, the main types, the tests, speed, and known weaknesses.