6.0 KiB
tricu Host ABI
This document specifies the first host-facing ABI for self-hosted Arboricx execution.
The ABI is intentionally small. A host language should only need to implement Tree Calculus construction/reduction plus a tiny set of canonical payload codecs. Higher-level execution policy lives in Tree Calculus.
Goals
- Keep host-language implementations small and auditable.
- Preserve canonical Tree Calculus representations for payloads.
- Provide a stable tagged envelope so hosts do not need per-application result conventions.
- Reuse the existing
ok/errresult protocol. - Support typed execution wrappers for common return types.
Non-goals
- This ABI does not remove the need for host codecs entirely.
- This ABI does not define every possible application protocol.
- This ABI does not require auto-detecting arbitrary result types.
Outer result protocol
Host ABI runners return the existing tricu result shape from lib/binary.tri:
ok value rest = pair true (pair value rest)
err code rest = pair false (pair code rest)
On success, value is a host ABI value.
On failure, code is a canonical Tree Calculus number. The host may report the numeric code and optionally inspect rest for debugging.
Host ABI value shape
A host ABI value is:
pair tag payload
The tag says how the host should interpret payload.
The payload is always the canonical/raw Tree Calculus representation for that type. The ABI envelope tags the payload; it does not replace or recursively wrap canonical Tree Calculus data.
Tags
Initial tags:
hostTreeTag = 0
hostStringTag = 1
hostNumberTag = 2
hostBoolTag = 3
hostListTag = 4
hostBytesTag = 5
Planned/error tag, if needed later:
hostErrorTag = 6
The first implementation keeps errors in the outer err result protocol rather than returning hostError inside ok.
Constructors
The ABI constructors are:
hostTree value
hostString bytes
hostNumber n
hostBool b
hostList xs
hostBytes bytes
Each constructor returns:
pair tag payload
Examples:
hostString "hello"
hostNumber 42
hostBool true
hostList [1 2 3]
hostTree (t t t)
Payload conventions
Payloads use existing canonical tricu encodings:
| ABI value | Payload |
|---|---|
hostTree |
arbitrary raw Tree Calculus value |
hostString |
canonical string/byte-list representation |
hostNumber |
canonical tricu number |
hostBool |
canonical tricu bool (false = t, true = t t) |
hostList |
canonical tricu list (t empty, pair head tail cons) |
hostBytes |
canonical byte list |
hostList payloads are raw canonical lists, not lists of host ABI values.
Accessors / matching
The first ABI should expose simple accessors:
hostValueTag hostValue
hostValuePayload hostValue
A host can decode the envelope by destructuring the pair directly, but these helpers make the ABI explicit and testable.
Validation predicates
Typed runners should validate that the raw application result can be interpreted as the requested type before wrapping it.
Initial predicates:
hostNumber? value
hostBool? value
hostList? value
hostString? value
hostBytes? value
These predicates are structural checks over canonical encodings. They are not general semantic type inference.
Important ambiguity note:
Tree Calculus encodings are not globally disjoint. For example, t is also false, 0, and []. Typed runners intentionally interpret values according to the requested type.
Error behavior
Typed ABI runners return an error if the application result does not match the requested type.
Initial error code:
errHostCodecFailed = 14
Example:
runArboricxToString bundle args
returns:
ok (hostString resultBytes) rest
if resultBytes is string-like, otherwise:
err errHostCodecFailed result
where result is the raw application result that failed validation.
Execution wrappers
The base self-hosted Arboricx runners are defined in lib/arboricx.tri:
runArboricxArgs bundleBytes args
runArboricxArgsByName nameBytes bundleBytes args
Host ABI wrappers layer typed output envelopes on top:
runArboricxToTree bundleBytes args
runArboricxToString bundleBytes args
runArboricxToNumber bundleBytes args
runArboricxToBool bundleBytes args
runArboricxToList bundleBytes args
runArboricxToBytes bundleBytes args
Named-export variants:
runArboricxByNameToTree nameBytes bundleBytes args
runArboricxByNameToString nameBytes bundleBytes args
runArboricxByNameToNumber nameBytes bundleBytes args
runArboricxByNameToBool nameBytes bundleBytes args
runArboricxByNameToList nameBytes bundleBytes args
runArboricxByNameToBytes nameBytes bundleBytes args
Host usage
For a bundle whose default export is an unapplied function:
append "hello "
A host that expects a string result evaluates:
runArboricxToString bundleBytes ["james"]
On success, the result is:
ok (hostString "hello james") rest
The host then:
- unwraps
ok, - checks
hostStringTag, - decodes the canonical string payload.
Implementation reference
- Tree constructors, numbers, strings, and lists:
src/Research.hs - Result protocol:
lib/binary.tri - Arboricx parser/executor:
lib/arboricx.tri - Host ABI implementation:
lib/host-abi.triorlib/arboricx.tri, depending on final organization
First-pass invariants
Tests should cover these invariants:
- Each constructor stores the correct tag and payload.
hostValueTagandhostValuePayloaddestructure values correctly.runArboricxToTreealways wraps successful raw results ashostTree.runArboricxToStringwraps string-like results ashostString.runArboricxToNumberwraps number-like results ashostNumber.runArboricxToBoolwraps canonical booleans ashostBool.- A typed runner returns
errHostCodecFailedwhen validation fails. - Named-export typed runners select the requested export before wrapping.