Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Symbols

!! · ## · ( ) · ** · . · // · /// · :: · => · [ ] · _ · · { }


!!

The WOMT operator — “Wait! One more thing!” After a keyword’s arguments, it starts its modifiers. A modifier is a function that returns a map, and I use the map’s keys to fill the keyword’s parameters by name. The keyword has to ALLOW each modifier.

Example

DRAW LINE path, red !! thickness(3) dashed

Chains statements on one line: I pass the value of each stage to the next as _. Every stage after the first has to use _ — otherwise that value would be lost. The one exception is a stage that is nothing but a function written in place: I call that with the value.

Examples

doubled = score_of("ada") ## _ * 2
count = load("level1") ## level => LEN(level.rooms)

( )

After a name, calls a function or reads from an array or a map. Around one value, groups it. Around two or more numbers, makes a coordinate.

Example

PRINT double(4), scores(0), (1 + 2) * 3, (10, 20)

**

At the start of an argument, spreads one value into several arguments. I lay out an array, a coordinate or a vector in order; a map fills parameters by name.

Example

DRAW **corners
grid(**pos) = 1
spawn(**{kind: "slime", hp: 5})

.

Reads or writes a field of an object or a map, calls a method, or reaches into a namespace. On a coordinate, .x, .y, .z and .w are its numbers; on a vector, .start and .stop are its ends. A reserved word is fine as a field name too: thing.type.

Example

hero.hp = hero.hp - 1
PRINT pos.x, Geometry.midpoint(a, b)

//

A comment: a note for people. I skip the rest of the line.

Example

lives = 3   // three tries

///

A documentation comment. It belongs to the FUNCTION, TYPE, field, NAMESPACE or any kind of BIND on the next line, and it’s what I show for it on pages like this one.

Above a function, lines starting with ! mean something special to me. !code: message declares an error the function can return, and !tip: under it adds advice. !returns: describes the result, !example: shows a use, !deprecated: has me warn anyone who still uses the function. !param name: says what one parameter is for. !category:, !status:, !since:, !see: and !label: say where the function belongs in the documentation and change nothing about what it does. !value turns the function into a value: you read it by its name alone, like a variable, and I call it each time you do. Two more are for host functions: !accepts-errors lets one be given error values, and !accepts-futures lets one be given futures that haven’t been resolved.

Example

/// Loads a saved game.
/// !save-missing: I can't find a save called `{name}`!
/// !tip: Saves live in the `saves` folder.
/// !returns: the saved game as a map
FUNCTION load_game(name)

::

In a function’s declaration, joins a type’s name to a method’s name.

Example

FUNCTION Player::Heal(amount)

=>

Makes a function out of one expression, right where it’s used. The names in front are its parameters and what follows is what it gives back: everything up to the next comma or closing bracket. It gets a copy of the locals around it, like any function written in place. When it needs more than one line, write FUNCTION(parameters) and END FUNCTION instead.

name => expression
(first, second) => expression

Examples

double = n => n * 2
alive = filter(squad, unit => unit.hp > 0)
total = fold(scores, 0, (sum, score) => sum + score)

[ ]

Makes an array. I count arrays from 0, and I’ll stop you if you read or write past the end.

Example

scores = [10, 20, 30]
scores(0) = 15

_

Inside a ## chain, the value of the stage before.

Example

load("level1") ## PRINT _

Text that can run over as many lines as you like. I take it exactly as you wrote it: a backslash is just a backslash, and two backticks together are how you write one. Start the text on the line after the opening backtick and I treat it as a block — I drop that first line break and the indentation all its lines share, so you can keep it lined up with your code.

Examples

query = `
    SELECT name
      FROM players
    `
path = `C:\games\saves`

Makes a map. A bare word as a key is the key’s name, not a variable; a key worked out from an expression goes in parentheses. I keep keys written as bare words in lowercase. Ask for a key the map doesn’t have and you get NULL. Even one of my reserved words works as a bare key, so {type: "enemy"} is fine.

Example

player = {name: "ada", hp: 100}
PRINT player.name, player("hp")