PatLang IDE
For new readers
A real, in-browser code editor for PatLang: write a program, press Run, see it execute โ no install required. "Tokens" and "AST" are two extra views showing what the compiler sees internally at earlier stages (its token stream, then its parsed tree structure), useful if you're curious how source text becomes something runnable, but not required to just try writing PatLang code.
The self-hosted compiler (lexer, parser, lowerer), compiled to WebAssembly once and reused for every run in this page. Run executes your program; Tokens and AST show the compiler's own intermediate representations for the same source, with no rustc involved for any of the three. Ctrl+Enter runs. Your code is kept in this browser's local storage.
# Edit me, then press Run. This compiles and executes in your browser.
make a function called fib takes n returns r
if n < 2 then
return n
else
return fib(n - 1) + fib(n - 2)
end
end
when greeting do
print("event says: " + event_data)
end
let xs = [3, 1, 4, 1, 5, 9, 2, 6]
let total = 0
let i = 0
while i < xs.length do
let total = total + xs[i]
let i = i + 1
end
print("sum of " + xs + " is " + total)
print("fib(20) = " + fib(20))
emit("greeting", "hello from the browser")
# Feature demo in the Stage 1 self-hosted language.
# Exercises: functions + recursion, control flow, lists, member access,
# events (when/emit), logic (fact/query), OO (new/send/get), and
# functional style (map/filter over named functions via apply).
make a function called fib takes n returns r
if n < 2 then
return n
else
return fib(n - 1) + fib(n - 2)
end
end
make a function called sum_list takes xs returns total
let total = 0
let i = 0
while i < xs.length do
let total = total + xs[i]
let i = i + 1
end
return total
end
when greeting do
print("event received: " + event_data)
end
let nums = [1, 2, 3, 4]
print("fib(10) = " + fib(10))
print("sum = " + sum_list(nums))
if sum_list(nums) == 10 then
print("sum ok")
else
print("sum wrong")
end
emit("greeting", "hello events")
fact("parent", "alice", "bob")
fact("parent", "alice", "carol")
print("alice children: " + query("parent", "alice", 0))
new("Person", "kim")
send("kim", "set", "age", 42)
print("kim age: " + get("kim", "age"))
# functional style: higher-order map/filter over named functions
make a function called double takes x returns r
return x * 2
end
make a function called is_even takes x returns r
return x % 2 == 0
end
make a function called map_list takes xs, fname returns out
let out = []
let i = 0
while i < xs.length do
let out = list_push(out, apply(fname, xs[i]))
let i = i + 1
end
return out
end
make a function called filter_list takes xs, fname returns out
let out = []
let i = 0
while i < xs.length do
if apply(fname, xs[i]) then
let out = list_push(out, xs[i])
end
let i = i + 1
end
return out
end
print("doubled: " + map_list(nums, "double"))
print("evens: " + filter_list(nums, "is_even"))
# Self-timing benchmark in the Stage 1 self-hosted language.
# Reports its own elapsed time via now_ms(), so the same program measures
# itself natively, on WASM, and under the interpreter.
make a function called fib takes n returns r
if n < 2 then
return n
else
return fib(n - 1) + fib(n - 2)
end
end
make a function called sum_to takes n returns total
let total = 0
let i = 1
while i <= n do
let total = total + i
let i = i + 1
end
return total
end
let t0 = now_ms()
let f = fib(27)
let t1 = now_ms()
print("fib(27) = " + f + " [" + (t1 - t0) + " ms]")
let t2 = now_ms()
let s = sum_to(2000000)
let t3 = now_ms()
print("sum 1..2000000 = " + s + " [" + (t3 - t2) + " ms]")
let t4 = now_ms()
let xs = vec_new()
let k = 0
while k < 200000 do
vec_push(xs, k * 2)
let k = k + 1
end
let t5 = now_ms()
print("built vector of " + vec_len(xs) + " [" + (t5 - t4) + " ms]")
print("total: " + (t5 - t0) + " ms")
# Design-by-contract demo in the Stage 1 self-hosted language.
# `require` checks a precondition, `ensure` a postcondition (checked wherever
# it's written โ usually right before the value it names is returned), and
# `assert` is the same primitive used standalone. All three lower to the
# same contract_check(func, kind, text, ok) host call, so enforcement is
# identical whether interpreted, run via run_ir (no rustc), or compiled
# natively. The last line deliberately violates a precondition, to show
# what enforcement actually looks like.
make a function called safe_divide takes a, b returns r
require b != 0
let r = a / b
ensure (r * b) == a
return r
end
make a function called clamp takes x, lo, hi returns r
require lo <= hi
if x < lo then
let r = lo
else
if x > hi then
let r = hi
else
let r = x
end
end
ensure (r >= lo) and (r <= hi)
return r
end
make a function called factorial takes n returns r
require n >= 0
if n < 2 then
let r = 1
else
let r = n * factorial(n - 1)
end
ensure r >= 1
return r
end
print("safe_divide(10, 2) = " + safe_divide(10, 2))
print("clamp(15, 0, 10) = " + clamp(15, 0, 10))
print("clamp(-5, 0, 10) = " + clamp(-5, 0, 10))
print("factorial(6) = " + factorial(6))
assert (1 + 1) == 2
print("standalone assert passed")
print("--- now deliberately violating a precondition ---")
print("safe_divide(1, 0) = " + safe_divide(1, 0))
print("(unreachable: the line above aborts the program)")
(not run yet)