Handlers in TypeScript or Python
A project says the language its behaviour is written in: project { handlers typescript }
(what archec new writes), python, or arche (the action language, translated).
TypeScript bodies get self and, when a message triggered them, msg ({ name, …fields });
the API is Arche's (await wait(ms(10)), send(self.out, MSG({ f: 1 })), await goto("Run")).
archec reads TypeScript without TypeScript installed, runs it in archec sim, writes
arche.d.ts for the editor (archec stubs), and tells Arche the language
(simulation.yaml). The contract with Arche: handlers.md; an example:
examples/ts-handlers.
TypeScript that keeps to what the action language says (assignments, if, while,
counted for, send, goto, wait, log, Math, the part's functions, msg.field)
is portable: archec gen --target c|embassy|go translates it as it translates
```arche, and archec difftest compares it with its C. Outside that, archec check
names the construct (ts-portable) and the generated code has a TODO
(handlers.md).
To move a model from one language to another, archec convert-handlers main.arche --to typescript (or python, arche) rewrites its blocks, code files and guards in place:
exact from ```arche, statement by statement from Python and TypeScript, what does
not translate kept as a TODO(convert) comment that archec check keeps reporting.
Code in .py and .ts files#
Python bodies kept in .py files beside the model, and the way back from the
Arche app and the simulator. (A body that the action language can say reads
better as a ```arche block: see concepts.)
Longer code reads better in a .ts or .py file, with your editor's tooling (a .ts
file binds the same way, its functions export function main(self: Ctrl) { … }):
component ctrl {
code "ctrl.py"
fn main // ← def main(self) in ctrl.py
in sense: i2c receives SAMPLE { on-receive on_sense }
states { state Off; state On { on-enter enter_on } } // on-exit: def on_exit_On, by its name
}
A fn with no block takes the def of the same name; every code property (on-enter,
on-exit, on-receive, on-write, body, a transition's / action) takes the def it
names; on_enter_<State>, on_exit_<State>, on_receive_<port> and on_write_<MEMORY>
bind with nothing written. code on the project or a system shares a file: its defs bind
only when named. A def's parameters are self and the fn's arguments, or the names Arche
gives that hook (msg, rise, from_, writer…); a docstring becomes the description.
Arche keeps Python inside its project files, so archec copies each body in: the Arche
project is the one the same code written inline gives (archec fmt --extract-code --write
moves existing blocks out — one file per component, or --extract-code=behaviour.py for one
file — and is tested to change nothing). Imports, constants and helper functions at the top
of the file are copied into the bodies that use them; a copy per body, so a top-level name
cannot keep state between calls — a function that changes one is an error; keep state on the
component (var n, self.n). from arche import * is for the editor only:
archec stubs (or the extension, on its own) writes arche.py with Arche's helpers and the
model's messages and constants, so Pylance or pyright complete and check the code.
The way back: code edited in Arche, and simulator errors#
Every build writes .archec/sourcemap.json into the project: where each piece of code
comes from, and the text it had.
- Code edited in the Arche app goes back to its source.
archec pull main.arche --writecompares what the last build wrote, what the Arche project holds now, and what your sources give now: code changed only in Arche is written into the def of the.pyfile (or the ``` block of the.archefile) it came from —defbecomesasync defif the new body awaits. Changed on both sides is a conflict, left for you; so is a change to the top-level code copied into a body (edit that in the.pyfile). A build refuses to overwrite code edited in Arche and not pulled (--forcedrops it). In VS Code, saving in Arche offers the pull (arche.pullOnChange: ask, always, never), applied as one undoable edit; Arche: Pull Code Changes does it by hand. Only code comes back: positions, names and other edits made in the app are still overwritten by the next build. - Simulator errors point at your lines. Arche says
ZeroDivisionError (Controller › Control loop, line 4)— line 4 of the copy.archec testandarchec runbuild, run arche-cli and add the source line:(Controller › Control loop, line 4 → ctrl.py:32);archec where main.arche "<error>"(orarche-cli test out | archec where main.arche -) does it for any text. In VS Code, Arche: Run Tests puts each error on its line in the Problems view, and Arche: Go to Simulator Error… takes an error pasted from the Arche app. A state's on-enter and on-exit share a label in Arche's messages: both lines are offered.