samples/iyi/calc.iyi
A language, in the language — the biggest program this prelude can hold.
# A language, in the language — the biggest program this prelude can hold. # # echo "x = 2 + 3 * 4 # x * 10" | ./bin/iyi run samples/iyi/calc.iyi # # The other samples each document a rule. This one documents nothing and is # here for a different reason: everything else in `samples/iyi` is a page long, # and a language that has only been used for pages has not been used. This is # three modules and a scanner, a parser and an evaluator, the shape of every # real program that reads something, written against iyi's own 21,567-line # library and nothing else. # # What it cost to write is recorded where it landed. `String#[]`, `String#[](start, # count)`, `String#to_i` and `read_input` are in the prelude because this file # asked for them, which is the rule the prelude grows by (SPEC.md "0.1.0", # item 3). Nothing else was missing. module samples/calc import calc/lexer::{scan, BadCharacter} import calc/parser::{parse, Statement, SyntaxError} import calc/ast::{Number, Name, Binary, UnknownName, DividedByZero} # What runs when nothing is piped in, so that the sample is a program rather # than a prompt. CI runs it this way. Its last two lines are errors on # purpose, and the demo exits 0 with them. DEMO = "x = 2 + 3 * 4 y = (x - 4) / 2 x + y * 10 missing + 1 1 / 0" # Whether every statement answered. An error goes to standard error, and # input with one makes the program exit 1: all of them went to standard # output at exit 0, so `echo 1 / 0 | iyi run samples/iyi/calc.iyi && next` # ran `next`. pub def run(source : String) : Bool tokens = scan(source) if tokens.is_a?(BadCharacter) stderr.puts "error: #{tokens.message}" return false end program = parse(tokens) if program.is_a?(SyntaxError) stderr.puts "error: #{program.message}" return false end answered = true scope = {} of String => Int32 program.each do |statement| value = statement.body.evaluate(scope) if value.is_a?(Int32) if statement.target.empty? puts value else scope[statement.target] = value end else # `value` is an error member of the union, and every one of them answers # `message` because they implement `Error` (SPEC.md III.1). stderr.puts "error: #{value.message}" answered = false end end answered end # Input that is only line ends is nothing piped in: PowerShell's `"" |` # sends a CRLF. And its pipe starts what it sends with a byte order mark, # which is not part of the program: "unexpected character at 0". typed = read_input.lchop('\uFEFF') if typed.strip.empty? run(DEMO) elsif !run(typed) exit 1 end
Press Run.
The pane no longer holds samples/iyi/calc.iyi. Run executes iyi-calc.wasm, the module the compiler built from the recorded file, so your edit is not in this run: there is no iyi compiler in this page. How this works
recorded with iyi 0.18.0 (built on Crystal 1.22.0-dev [2a9653052] (2026-10-18)) · Linux 7.0.0-38-generic x86_64, QEMU Virtual CPU version 2.5+ · 2026-10-19
You can type in the pane: nothing here compiles, so what you type cannot run, and the page says which bytes it is running the moment the text stops being the recorded file. There is no standard input, no filesystem and no threads on this target, and one sample fails on purpose for exactly that reason.
Run executes iyi-calc.wasm, the module the compiler built from this file, in your browser. How this works
Try it on your machine
Copy the program into calc.iyi, change something, and run it. Only a compiler on your own machine can run what you wrote.
$ iyi run calc.iyi