Skip to content

The PWE Language

open1s edited this page Sep 25, 2026 · 1 revision

The PWE Language

The PWE language is the textual front end of pwe-reference (grammar src/lang.pest). A source program declares a world model and systems; it compiles to typed EIR and runs cross-backend — the interpreter and the CPU JIT must produce byte-identical writes on every step.

PWE source ──parse──▶ WorldModel + system decls ──lower──▶ EIR ──interpret/JIT──▶ writes

The full reference — lexical rules, every keyword, EBNF, operator precedence, and a complete intrinsic function table — lives in docs/lang-usage.md (中文).

Program structure

world {
    # world items (required section)
}
funcs {
    # optional: user-defined pure functions
}
systems {
    # optional: systems that act on the world
}

Comments run from # or // to end of line and are skipped as whitespace anywhere. Whitespace is otherwise insignificant; ; between statements is optional. A .pwe file is also a module.

world — what the world is

Statement Meaning
gravity = (x, y, z) Global uniform gravity vector.
params { G = 1.0; k = 3.0 } Runtime-settable parameters, overridable with --param G=2 on the same artifact.
title = "..." Human-readable run title, shown by pwe present.
entity <name> { … } A body.
shape <name> { part … } A user-defined custom shape (presentation only).
chan <name> { value = v } A channel entity; holds its latest value in state[0].
field <name> { width; height; dx } A deterministic scalar grid field — the PDE substrate.
pool <name>[n] { … } A block of pre-allocated, initially inactive entity slots.
import "pkg/mod" Python-style module import.

Entity fields

Entity ids are 1-based in declaration order; channels follow the bodies.

Field Meaning
position = (x, y, z) / velocity = (x, y, z) Initial position / velocity.
state = (v0, …) Positional state slots (max 16: s0…s15).
state = (x = 0, y = 0, …) Named slots; read via @self.x. Mixable with positional.
state = (vec3 pos, …) A vector element reserves N consecutive slots.
mass, dynamic = false, nbody = false Mass; static body; opt out of mutual nbody.
restitution, friction Contact bounciness / tangential friction.
box = (dx,dy,dz) / sphere = r / hull = [(x,y,z), …] Collider.
camera = true The viewer camera (excluded from simulation).

Presentation-only (color, shape, size, opacity, glow, label) never affect simulation state, determinism, or the state hash.

Grid fields — the 4D continuum substrate

field heat { width = 32; height = 32; depth = 32; dx = 1.0 } declares a 3-D grid. Cells are deterministic world state (snapshot/replayable). Space is 3D — with the simulation clock, fields are the 4D substrate.

  • fget(f, i, j[, k]) — read a cell (sees same-step writes).
  • fset(f, i, j[, k], v) — write a cell (bare call statement).
  • flap(f, i, j[, k]) — zero-flux discrete Laplacian scaled by 1/dx² (5-point 2D, 7-point 3D).

Custom shapes

Primitives, convex hulls, explicit-face polyhedra, and extruded SVG paths:

shape gem {
  part poly = [(0,0.9,0), (0.7,0,0.7), …] faces = [[0,1,2],[0,2,3], …];
}
shape star {
  part svg = "M 0,-1 L 0.224,-0.309 …" depth 0.22 scale 0.8;
}

systems — the behavior

slot = expr means slot += dt·expr (explicit Euler); rk4 integrates the same rules at 4th order. Rules are equations, not scripts.

System Purpose
gravity, integrate, damping, force, linear The everyday mechanics kernels.
ground_contact, wall Contact and bounded domains with restitution.
nbody { G, dt } Mutual inverse-square force (G>0 gravity, G<0 Coulomb).
update / rk4 User-defined ODE rules (Euler / Runge–Kutta 4).
diffuse, poisson, wave PDE sweeps on grid fields.
send / recv Go-style channel send/receive.
invariant Per-step assertion.
watch Zero-crossing detection.
spawn / despawn Activate / recycle pool slots.

Reading the world

  • Cross-entity reads: @other.state.x, properties @other.mass.
  • Spatial queries: neighbor_count, nearest_dist, neighbor_mean.
  • Constants: t (clock, s), pi, e.
  • Stochastic: random(), noise(), emit() — seeded and replay-stable.

Events & scheduling

at(T), periodic(P), schedule(gate, delay, …), emit / last_event — exact-once, deterministic, on the step grid.

Control flow, bounded

repeat / for / break / continue unroll to straight-line EIR; Newton iteration inside a step is a one-liner.

Modules

Python-style: import "std/forces", import "m" as x, from "m" import f. Packages are directories; circular imports resolve.

Units, checked

Opt-in [m/s^2] annotations with gradual dimensional analysis — unannotated stays a wildcard. Base units: m kg s A K mol cd.

Diagnostics that teach

Compile failures print the detail code and the offending line with a caret, javac-style.

Embedding it in Rust

let compiled = pwe_reference::lang::compile(SOURCE)?;      // parse → lower → EIR
let mut rt = pwe_reference::lang::LangRuntime::compile(SOURCE)?;
rt.step_cross()?;                                          // interpreter == JIT, asserted
rt.step_cross_n(30)?;

PWE Wiki


Repository


The world is the single source of truth. Program it. Prove it. Watch it move.

Clone this wiki locally