Files
tricu/docs/host-abi.md

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 / err result 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:

  1. unwraps ok,
  2. checks hostStringTag,
  3. 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.tri or lib/arboricx.tri, depending on final organization

First-pass invariants

Tests should cover these invariants:

  1. Each constructor stores the correct tag and payload.
  2. hostValueTag and hostValuePayload destructure values correctly.
  3. runArboricxToTree always wraps successful raw results as hostTree.
  4. runArboricxToString wraps string-like results as hostString.
  5. runArboricxToNumber wraps number-like results as hostNumber.
  6. runArboricxToBool wraps canonical booleans as hostBool.
  7. A typed runner returns errHostCodecFailed when validation fails.
  8. Named-export typed runners select the requested export before wrapping.