Process interfaces

JSON lines

Run bpl --worker. Send one JSON request per line. Each request gets one flushed JSON reply, in order. Names persist between requests.

{"code":"v←⍳10"}
{"id":2,"code":"+/v"}

The second reply is:

{"id":2,"result":{"value":45.0,"output":[{"kind":"display","data":{"text/plain":"45"}}],"error":null}}

id is optional. A reply carries its request’s id, or null for a request without one. Give an id to any request you might interrupt: {"interrupt":2} cancels request 2 and gets no reply of its own. Keep one evaluation outstanding.

Build each request with a JSON encoder, such as Python’s json.dumps or JavaScript’s JSON.stringify, and end it with a newline. The encoder escapes newlines in the source. Stdout contains only replies. EOF ends the session.

Malformed JSON, an invalid field or an invalid encoded array gives an error of kind REQUEST in that request’s result. The session continues.

Requests

code evaluates BPL source. timeout_ms sets a deadline. "echo":false suppresses implicit display, but not explicit output.

{"id":1,"code":"+/⍳10","timeout_ms":2000,"echo":false}

bindings maps names to encoded values. call applies a function to one or two encoded args, without generating BPL source.

{"id":2,"call":"+","args":[2,3],"echo":false}

Results

output holds the events in order. Each event’s kind is display or explicit, and its data is a MIME bundle with text/plain. A value with a renderer adds the renderer’s types, such as image/svg+xml. Returned values carry contents and axis labels, without renderers. Keyed entries that hold functions are omitted. Any other function in a result gives a null value, and output holds its display.

Atoms are encoded directly. Arrays carry shape, row-major data and prototype, including rank-zero arrays. Nested items use the same encoding. A keyed array adds axis_keys: one string list or null per axis. All-unkeyed arrays omit it.

Named dimensions add axis_names: one string or null per axis, e.g. ["city", "month"]. Arrays with no named axes omit it. Encoded arrays in requests take both fields too.

Atom JSON
Exact integer Integer, including arbitrary precision
Approximate real Number with decimal point or exponent
Character String
Rational {"rational":["1","3"]}
Complex {"complex":[1.0,2.0]}
Infinity {"infinity":1} or {"infinity":-1}
NaN {"nan":1}

Use the tags for infinities and NaN, never raw NaN or Infinity tokens. Integer inputs stay exact. JavaScript’s JSON.parse rounds integers larger than 2⁵³. Use a parser that keeps integers exact. Error spans are UTF-8 byte ranges into the supplied source. Call sites accompany the original location.

Python worker

Python’s Worker manages a persistent bpl --worker subprocess with deadlines and a hard-kill fallback.

from basedpl.worker import Worker

with Worker() as w:
    w.eval('v←⍳10')
    r = w.eval('+/v', timeout=2)
    assert r['value'] == 45

w.interrupt() cancels from another thread. Ctrl-C requests cancellation too. Cooperative cancellation preserves the session and completed assignments. If the process doesn’t respond within the grace period, one second by default, Worker kills it and the session is lost. Worker never replays a request. w.diagnostics holds recent stderr. Worker.request(payload, timeout=...) sends any request and supplies its id.