Rune
Rune is a dynamically typed interpreted programming language inspired by Lox and built following concepts from the book Crafting Interpreters by Robert Nystrom. The interpreter is implemented in Go: the resolved AST is compiled to register bytecode run by a VM, and the whole thing ships as a single statically linked binary.
struct Point { x, y = 0 }
impl Point {
fun len(self) { return math.sqrt(self.x * self.x + self.y * self.y); }
}
let points = [Point { x: 3, y: 4 }, Point { x: 1 }];
for i, p in points {
print("{i}: {p} has length {p.len()}");
}
// 0: Point {x: 3, y: 4} has length 5
// 1: Point {x: 1, y: 0} has length 1
A Taste
Classifying the lines of an access log, with a struct, destructuring,
pattern matching and a map:
struct Request { method, path, status, ms }
fun parse(line) {
let [method, path, status, ms] = line.split(" ");
return Request { method, path, status: int(status), ms: number(ms) };
}
fun kind(r) {
return match r {
Request { status } if status >= 500 => "error",
Request { ms } if ms > 100 => "slow",
_ => "ok",
};
}
let log = """
GET /users 200 12.5
POST /orders 201 340
GET /health 503 1
GET /users 200 8
""";
let mut counts = map();
for line in log.split("\n") {
let k = kind(parse(line));
counts[k] = counts.get(k, 0) + 1;
}
print(counts); // map {"ok": 2, "slow": 1, "error": 1}
New here? Start with Getting Started, then read the Language chapters in order.
Features
- Dynamically typed language with a simple syntax
- Supports expressions, statements, variables, and functions
- Variables are immutable by default (
let);let mutmakes them mutable - Standard library in namespaces:
array,string,regex,math,json,http,time,fs,io,os - Modules with their own top level,
exportandimport a.b as m;, relativeimport ..lib.x; - Recursive descent parser; the resolved AST is compiled to register bytecode run by a VM
- Parser recovers from syntax errors and reports all of them in one run
- String escapes:
\n,\t,\r,\",\\,\{,\}; raw strings take neither:r"\d{3}" - Multi-line strings, dedented, with quotes inside:
"""...""", rawr"""...""" - String interpolation:
"x = {x}, sum = {a + b}" - 64-bit integers and floats, both of type
number:7 / 2is3.5,7 % 2is1, and overflow is an error - Number literals with exponents, hex, octal, binary and
_:1e3,0xff,0o17,0b1010,1_000_000 - Bitwise operators on integers:
&,|,^,~,<<,>> - Objects,
mapandsetkeep their keys in insertion order; amaporsetkey may be any hashable value bytes: immutable binary data, with literalsb"\x00\xff"- Streams: files and HTTP bodies read line by line or in chunks,
for line in fs.open(path) - Object property access with
obj.nameas sugar forobj["name"]; shorthand{ ip, hits }for{ ip: ip, hits: hits }, computed keys{ [name]: value } - Structs with required and default fields, values whose fields only their
mut selfmethods set:struct Point { x, y = 0 },Point { ...p, x: 1 } - Methods in
implblocks, on structs and built-in types:p.len(),Point.origin(),fun move(mut self); a function in a property is called as(o.f)() - Destructuring of objects, structs and arrays, in
let, parameters andfor, with defaults:let { x, y = 0 } = p;,let [head, ...tail] = xs; - Nil-safe access and defaults:
resp?.data?.items ?? [] - Conditional expressions:
n > 0 ? "pos" : "neg" - Spread and rest:
[...a, ...b],{...o, x: 1},Point { ...p, x: 1 },f(...args),fun log(level, ...parts) - Strings compare with
<,<=,>,>=and index by character:"héllo"[1]is"é"; a negative index counts from the end:xs[-1] - Pattern matching with
match, as an expression or a statement, on literals, types, structs, objects and arrays:[cmd, ...args] => - Logical operators
&&,||and!, type tests withis:v is Point,catch e is KeyError,p is Point => - Error handling with
try/catchandthrow, also as an expression:x ?? throw E { ... } return,breakandcontinueas expressions:let v = x ?? return nil;,row?.id ?? continue- Two loops only:
whileandfor x in ...over arrays, strings, objects and ranges (a..b) breakandcontinuein bothif/else,whileandforbodies are blocks, or a bare statement starting with a name or keyword:if v < 0 return;,for x in xs out.push(x);- Anonymous functions:
fun (x) { return x * 2; }, or arrow functions:x => x * 2 - Default parameters, evaluated at each call:
fun greet(name, greeting = "hi") - Modulo
%and compound assignment:+=,-=,*=,/=,%= - Increment and decrement, prefix and postfix:
++i,i++,--i,i--(on variables, array elements and properties) - Cross-platform, compiles to a single binary
References
- Crafting Interpreters by Robert Nystrom
- Lox Programming Language