Reacting to events, timers, and messages

Programming guides

An event tells your program something happened, such as a key being pressed. A handler, or event script, is the indented block that reacts to it. The header is its first line, such as when started():. The part after when is an event descriptor: it says what to react to. It belongs in that header, not in an ordinary function call.

Top-level means outside functions, loops, and other blocks. Pliro first runs the ordinary top-level instructions to prepare the program. This is setup, or initialization. Then it gives event scripts their turns. Ready scripts wait in a queue, like people waiting in line. Cooperative means a script lets another ready script take a turn at agreed points, such as a positive wait. See the event-loop example.

Event scripts are top-level when statements:

when started():
    say "Ready"
    broadcast("go")

when after(1):
    say "One second later"

when messageReceived("go"):
    say "Go!"

when keyPressed("space"):
    say "Jump!"

when pointerPressed("primary"):
    say "Pressed at", pointerX(), pointerY()

when pointerReleased("primary"):
    say "Released at", pointerX(), pointerY()

when pointerClicked("primary"):
    say "Clicked at", pointerX(), pointerY()

Timer and scheduling words

A literal is a value written directly in the code, such as 1 or "go". An event header that requires a literal cannot use a variable in its place. Case-sensitive means "go" and "Go" are different messages.

To arm a timer is to start its wait. A one-shot timer becomes ready once; it does not repeat. A deadline is the earliest time it may run. All after timers measure from the same moment after setup. Their monotonic clock measures elapsed time without jumping when the computer’s time-of-day setting changes. Equal deadlines keep their order in the source file. Becoming ready does not interrupt another script in the middle of an instruction.

An invocation is one run of a handler. It gets fresh local variables, its own names inside the block. Global variables, created at program level, are shared. Dispatch means delivering an event and queuing the matching work. To yield is to hand over a turn. A persistent handler keeps a suitable running program ready for future key or pointer input, even when it is doing nothing at that moment. Cancellation stops pending work from running.

The trigger after when must be exactly started(), after(seconds),
messageReceived("message"), keyPressed("key"),
pointerPressed("primary"), pointerReleased("primary"), or
pointerClicked("primary"). after
requires one direct finite Number literal
from 0 through 10 seconds and starts its script exactly once. A positive value
below one millisecond is represented as one millisecond. Message and key
descriptors require one
non-empty text literal written directly in the header. Message matching is
exact and case-sensitive. Key names use the same portable normalization as
keyDown; a handler starts only when the key changes from released to
pressed, and operating-system repeats are ignored until key-up.
pointerPressed, pointerReleased, and pointerClicked accept only the
exact direct literal "primary". A press runs when an eligible primary down
occurs inside the logical scene and the host claims that pointer. It carries
the immutable bounded whole-number down point. A real up from the same claimed
pointer next runs a release handler, even outside the scene, using a signed
32-bit logical-plane point. If the up is inside, it also runs a separate click
handler with the existing bounded release point. Additional or duplicate downs
do not start another press or release. pointerX() and pointerY() report
the immutable point owned by that pointer-event task.
Event descriptors are valid only directly after a top-level when; they are
not ordinary callable functions. Periodic timers, pointer move/drag, GPIO-edge,
and sprite event descriptors are not
implemented yet.

Ordinary top-level statements initialize shared globals before event scripts
run. Started scripts are queued first. All after scripts are then armed once
from one shared post-setup monotonic anchor; a zero-delay timer stays behind
started work, and equal deadlines retain source order. Ready scripts use
deterministic FIFO order, one script at a time. Every
invocation has fresh local variables but may read and update shared globals.
Inside a script, wait parks only that script and broadcast queues matching
message scripts in source order before yielding. A run without persistent
descriptors finishes after no ready or sleeping script remains. A
keyPressed, pointerPressed, pointerReleased, or pointerClicked
script keeps a capable run in state
running while idle; Stop, exitApp, failure, or host closure ends it. A
runtime without a required keyboard/pointer event capability fails with
E4019. See
Section 17.

Positive wait calls and completed input requests are cooperative checkpoints.
They keep Stop and graphical event processing responsive and start a fresh
instruction-budget slice. In an event script, wait parks only the active
script. broadcast queues exactly matching message scripts and yields the
active script so the deterministic FIFO scheduler can continue other ready
work. Put a persistent animation loop in when started(): when other event
handlers need to run during its waits; ordinary top-level setup must finish
before the event-scheduler phase begins.

# language: en
let running = true

while running:
    if keyDown("space"):
        exitApp()

    # Update and draw one frame here.
    wait(0.04)

Syntax and values · Built-ins · Programming guides