Wend

the language that can walk back the way it came

slowfast
Editor
Output
Call stack
Nothing is running.
Bindings in scope
Run, then drag the timeline to any moment.
Every value each variable ever held
Run the program first — every assignment is remembered. Click any entry to travel to that exact moment.

What is Wend?

A small scripting language where time is a feature. Every run is recorded and deterministic — drag the timeline to any step, watch the stack and bindings as they were, and open History to see every value a variable ever held. Built from scratch: lexer, parser, interpreter, all in this one file.

Values & variables

let n = 42
let ok = true
let nothing = nil
let s = "interpolation: {n + 1}"   // escape a brace with \{

Control flow

if is an expression; blocks yield their last value. Only false and nil are falsy.

let mood = if n > 10 { "plenty" } else { "few" }
for i in 1..5 { print(i) }        // inclusive ranges
while n > 0 { n -= 1 }

Pattern matching

match value {
  0 -> "zero"
  1..9 -> "a digit"
  [x, ...rest] -> "starts with {x}"
  { name, age } -> "{name} is {age}"
  _ -> "anything else"
}
let [a, b] = [1, 2]               // destructuring
let { name } = { name: "Ada" }

Functions & pipelines

a |> f(b) means f(a, b). Last expression returns implicitly.

fn double(x) { x * 2 }
1..10 |> filter(fn (n) { n % 2 == 0 })
     |> map(double)
     |> sum() |> print()

Data wrangling

The Data tab feeds your program as input (JSON or CSV, parsed automatically).

input |> filter(fn (o) { o.status == "paid" })
      |> group_by(fn (o) { o.region })
table(rows)     // pretty table in the output
to_csv(rows)    // and back out again

Built-ins

print table len push pop keys values has map filter reduce sum avg sort sort_by group_by count_by unique flatten zip take drop first last find any all slice reverse join split chars replace starts_with ends_with upper lower trim parse_json to_json parse_csv to_csv abs floor ceil round sqrt pow min max random num str type

Time travel

Runs are deterministic (even random() is seeded per run), which is what makes perfect replay possible. The timeline scrubber replays the recorded run to any step; History indexes every assignment. If a run exceeds 200,000 steps the timeline switches off and it just runs.

Timeline
not recorded yet