1. Getting started
Building korrin
You need a recent stable Rust toolchain. From the repository root:
cargo build --release
The binary is target/release/korrin.
Running a file
Put this in hello.kor:
name = "world"
print("hello, {name}")
# => hello, world
Run it:
korrin run hello.kor
Korrin source files use the .kor extension. Anything after the file name is
passed to the program, readable with io.args() (see
Modules):
korrin run report.kor data.csv --verbose
The REPL
Run korrin with no arguments for an interactive prompt:
$ korrin
Korrin 0.0.0 — Ctrl-D to exit
korrin> 2 + 3
5
korrin> greeting = "hi"
korrin> greeting + " there"
hi there
A bare expression has its value echoed. An assignment does not print anything. To enter a block, the REPL keeps reading until you leave a blank line:
korrin> fn double(n):
... return n * 2
...
korrin> double(21)
42
Press Ctrl-D to leave.
Reading errors
When something is wrong, Korrin points at it:
$ korrin run broken.kor
[E0301] Error: cannot find `nam` in this scope
╭─[broken.kor:2:19]
│
2 │ print("hello, " + nam)
│ ─┬─
│ ╰── not defined here
───╯
Every error has a code like E0301. The error reference
lists them all.
Debugging aids
Three subcommands show how Korrin sees a program on its way to running:
korrin tokens hello.kor # the token stream
korrin ast hello.kor # the parsed syntax tree
korrin bytecode hello.kor # the compiled instructions
Two engines
Korrin has two ways of running a program, and they are meant to be
indistinguishable. korrin run uses a tree-walking interpreter, which walks
the syntax tree directly. korrin run --vm compiles the program to bytecode
first and runs that, which is faster for code that makes a lot of calls.
korrin run --vm hello.kor
You should never need to care which one you use. The interpreter is kept deliberately, as the reference the virtual machine is checked against: every program in Korrin's test suite runs both ways, and the two have to produce the same output. If you ever find a program where they disagree, that is a bug worth reporting.