#!/usr/bin/env php [arg ...] * php run.php inspect * * The "run" command: * 1. Reads the .arboricx bundle as raw bytes * 2. Encodes bundle bytes as a Tree Calculus byte list * 3. Encodes each host argument (string or number) * 4. Calls runArboricxToString via the hardcoded kernel * 5. Unwraps ok/err, then Host ABI envelope * 6. Decodes the string payload * * This is a minimal host shell — it does NOT parse Arboricx bundles itself. * The kernel handles bundle parsing internally. */ require __DIR__ . '/src/functions.php'; require __DIR__ . '/src/codecs.php'; require __DIR__ . '/src/kernel.php'; use Arboricx\Node; use function Arboricx\{app, reduce, ofString, ofNumber, ofBytes, ofList, formatTree, unwrapResult, unwrapHostValue, decodeHostPayload, getRunArboricxToString}; // ── Commands ───────────────────────────────────────────────────────────────── function readBundle(string $path): string { if (!file_exists($path)) { fwrite(STDERR, "Error: bundle not found: $path\n"); exit(1); } $bytes = file_get_contents($path); if ($bytes === false) { fwrite(STDERR, "Error: could not read bundle: $path\n"); exit(1); } return $bytes; } function cmdRun(string $bundlePath, array $args): void { $bundleBytes = readBundle($bundlePath); $kernel = getRunArboricxToString(); if ($kernel === null) { fwrite(STDERR, "Error: runArboricxToString kernel not configured\n"); exit(1); } $bundleTree = ofBytes($bundleBytes); $argTrees = []; foreach ($args as $arg) { $argTrees[] = encodeArg($arg); } $argsTree = ofList($argTrees); // Kernel application: runArboricxToString bundle args $expr = app(app($kernel, $bundleTree), $argsTree); fwrite(STDERR, "Reducing kernel application...\n"); $result = reduce($expr, 1_000_000_000_000); // The kernel returns an ok/err pair. On ok, the value is a // Host ABI envelope: Fork(tag_number, payload_tree). [$kind, $value, $rest] = unwrapResult($result); if ($kind === 'error') { fwrite(STDERR, "Error detail: $rest\n"); exit(1); } if ($kind === 'err') { [$ok2, $code] = Arboricx\toNumber($value); $codeStr = $ok2 ? (string)$code : formatTree($value); fwrite(STDERR, "Arboricx error code: $codeStr\n"); fwrite(STDERR, "Rest: " . formatTree($rest) . "\n"); exit(1); } [$tag, $payload] = unwrapHostValue($value); try { $decoded = decodeHostPayload($tag, $payload); echo $decoded['value'] . "\n"; } catch (\Throwable $e) { fwrite(STDERR, "Host ABI decode error: " . $e->getMessage() . "\n"); fwrite(STDERR, "Raw tag: $tag, payload: " . formatTree($payload) . "\n"); exit(1); } } function encodeArg(string $arg): Node { return ctype_digit($arg) ? ofNumber((int)$arg) : ofString($arg); } function cmdInspect(string $bundlePath): void { $bundleBytes = readBundle($bundlePath); $bytes = strlen($bundleBytes); echo "Bundle: $bundlePath\n"; echo "Size: $bytes bytes\n"; // Run with no arguments to see the default export $kernel = getRunArboricxToString(); if ($kernel === null) { fwrite(STDERR, "Warning: kernel not configured, skipping execution\n"); return; } $bundleTree = ofBytes($bundleBytes); $emptyArgs = ofList([]); $result = reduce(app(app($kernel, $bundleTree), $emptyArgs), 10_000); [$kind, $value, $rest] = unwrapResult($result); if ($kind === 'ok') { echo "\nResult (ok):\n"; try { [$tag, $payload] = unwrapHostValue($value); $decoded = decodeHostPayload($tag, $payload); echo " Tag: $tag (type: " . $decoded['type'] . ")\n"; echo " Value: " . $decoded['value'] . "\n"; } catch (\Throwable $e) { echo " Raw: " . formatTree($value) . "\n"; } } else { echo "\nResult (err):\n"; [$ok, $code] = Arboricx\toNumber($value); echo " Code: " . ($ok ? (string)$code : formatTree($value)) . "\n"; } } // ── Main ───────────────────────────────────────────────────────────────────── $argv = $_SERVER['argv'] ?? []; $argc = $_SERVER['argc'] ?? 0; if ($argc < 2) { echo "Arboricx PHP Host Shell\n"; echo "\nUsage:\n"; echo " php run.php run [args...]\n"; echo " php run.php inspect \n"; exit(0); } $command = $argv[1]; switch ($command) { case 'run': if ($argc < 3) { fwrite(STDERR, "Usage: php run.php run [args...]\n"); exit(1); } cmdRun($argv[2], array_slice($argv, 3)); break; case 'inspect': if ($argc < 3) { fwrite(STDERR, "Usage: php run.php inspect \n"); exit(1); } cmdInspect($argv[2]); break; default: echo "Unknown command: $command\n"; echo "Usage: php run.php run|inspect ...\n"; exit(1); }