The syntax v2 surface, which is what .lk and .luke files use. Every form here is drawn from
SYNTAX_V2_SPEC.md, which is machine-checked against code generation —
if the two disagree, the spec is right and this page is the bug.
The conversational v1 surface is documented in the spec's mapping tables and remains available
behind luke --syntax=1 for the deprecation window.
1. Values and bindings
let binds a value you will not reassign. var binds one you will.
let name = "Luke"var count = 0count = count + 1
Types are optional where the compiler can infer them and required where it cannot — most often
around +, which is both arithmetic and concatenation:
let a: int = 21var total: float = 0let greeting: str = "hello"let ready: bool = false
| Type | Holds |
|---|---|
int |
Exact integer — see INTEGER.md for the exactness rules |
float |
Double-precision number |
str |
Text |
bool |
true / false |
list |
Ordered values |
map |
Key to value |
json |
Parsed JSON tree |
Server, Request, Db |
Standard library handles |
Foo |
Any struct you declared |
A declaration without an initialiser is mutable and needs its type:
var buffer: strvar items: list = []var index: map = {}
2. Operators
| Kind | Operators |
|---|---|
| Arithmetic | + - * / % |
| Comparison | == != < > <= >= |
| Logical | && \|\| ! |
| Compound assignment | += -= |
| Concatenation | + on str |
+ needs to know whether it is adding or concatenating. If neither operand's type is known,
the compiler asks you to annotate rather than guessing:
fn describe(n: float) -> str { return "n=" + n // str + float — concatenation}
% has no Build-mode equivalent yet and is rejected with an error.
3. Control flow
if count > 10 { print("many")} else if count > 0 { print("some")} else { print("none")}
while count > 0 { print(count) count = count - 1}
for item in items { print(item)}
Range loops (for i in 0..n) are not part of the surface — use while. break leaves the
nearest loop.
4. Functions
fn add(a: float, b: float) -> float { return a + b}fn greet(name: str) { print("Hello, " + name)}print(add(21, 21))greet("Luke")
The return type is optional; omit -> when the function returns nothing. Parameters carry
types wherever Build mode needs them, which is most places.
Functions nest, and an inner function captures the enclosing scope:
fn makeAdder(x: float) { fn add(y: float) -> float { return x + y } return add}
5. Structs
A struct is a blueprint: fields, an init constructor, and methods. self is the instance.
struct Animal { name: str sound = "…" init(name: str) { self.name = name } fn speak() { print(self.name + " says " + self.sound) }}
Fields declare a type (name: str) or an initialiser (sound = "…"), and private keeps a
field or method out of reach from outside:
struct Vault { secret: str private fn raw() -> str { return self.secret } fn reveal() -> str { return self.raw() }}
Inheritance
struct Dog : Animal { sound = "Woof!" fn speak() { super.speak() print(self.name + " wags happily.") }}
super.m() calls the parent's implementation. Construct with the struct name:
let buddy = Dog("Rex")buddy.speak()
Instances live in an arena released at scope exit — there is no garbage collector on the Build
path. drop(x) releases one early.
Multiple inheritance and trait contracts exist only on the Play VM path today, using the
conversational surface; see advanced_topics.md.
6. Collections
var xs: list = []xs.push("Ada")print(xs[0])print(xs.len())print(xs.last())xs.remove(0)
var m: map = {}m["name"] = "Ada"print(m["name"])if m.has("name") { print("present")}
7. Errors
try { risky()} catch (e) { print("caught: " + e)}throw "not allowed"assert count == 5
8. Reactive cells
Cells are language, not a library. This is the part of LukeLang that is genuinely different, so
REACTIVE.md covers it in depth.
signal price = 100signal quantity = 3derived total = price * quantityeffect on total { print("total=" + total)}price = 200 // total=600batch { price = 120 quantity = 5 // still one flush}
| Form | Means |
|---|---|
signal c = e |
A cell |
secret signal c = e |
A cell the compiler refuses to bind into a page |
derived t = expr |
Recomputed when its inputs change |
effect on c { … } |
Runs when c changes |
effect background on c { … } |
Same, at background priority |
effect weak on c { … } |
Same, without keeping c alive |
batch { … } |
Many writes, one flush |
c.value() |
Read without subscribing |
c.deps() / c.subs() / c.id() |
Graph introspection |
why(c) |
Trace what last wrote to c |
9. Modules
import std/server // standard libraryimport "./critter.lk" // sibling fileimport luke/greeter // package from luke_modules/
std/* resolves from vm/stdlib/. Relative paths resolve next to the importing file. See
standard_library.md for the module list and
BUILD_MODE.md for package resolution.
10. Live Graph
The same cell model crosses the network. A server cell can be backed by a database row and pushed to clients; a client cell can be backed by that stream and bound to an element.
// serverwatch user from db where "id = 1"push watch user on req for 50 beats every 50 ms// clientsignal user = ""bind("name", user)watch user from "http://127.0.0.1:8798/watch"
An external UPDATE becomes one push, one reactive write, and exactly one repainted region.
LIVE_GRAPH.md has the wire format, incremental view maintenance and
resume-from-log.
11. Memory
arena { let big = buildSomething() print(big)} // released here
Build mode allocates from an arena and frees at scope exit. Nothing is reference-counted and
nothing is collected in the background. BUILD_MODE.md covers the details.
12. Tests and benchmarks
test "addition" { assert add(2, 3) == 5}bench.sample(elapsed)
Run with luke TEST file.lk.
13. Escaping to the conversational surface
Some forms — contracts, statics, layout phrases — are not on the v2 surface yet. raw passes a
line through untouched:
raw "CONTRACT Eater DO"raw "MUST METHOD eat WITH food"raw "END CONTRACT"raw """WHEN "cta" IS CLICKED DO OPEN THE MODAL "dlg"END WHEN"""
luke MIGRATE old.luke rewrites a conversational source into v2 and marks anything it could
not translate with TODO(migrate).
Next: BUILD_MODE.md for the language of record ·
SYNTAX_V2_SPEC.md for the normative surface ·
REACTIVE.md for the reactive engine