Files
tricu/ext/php/run.php

174 lines
5.4 KiB
PHP

#!/usr/bin/env php
<?php
declare(strict_types=1);
/**
* run.php — Self-hosted Arboricx PHP host shell.
*
* Usage:
* php run.php run <bundle.arboricx> <arg> [arg ...]
* php run.php inspect <bundle.arboricx>
*
* 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 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);
// 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): int
{
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 <bundle.arboricx> [args...]\n";
echo " php run.php inspect <bundle.arboricx>\n";
exit(0);
}
$command = $argv[1];
switch ($command) {
case 'run':
if ($argc < 3) {
fwrite(STDERR, "Usage: php run.php run <bundle.arboricx> [args...]\n");
exit(1);
}
cmdRun($argv[2], array_slice($argv, 3));
break;
case 'inspect':
if ($argc < 3) {
fwrite(STDERR, "Usage: php run.php inspect <bundle.arboricx>\n");
exit(1);
}
cmdInspect($argv[2]);
break;
default:
echo "Unknown command: $command\n";
echo "Usage: php run.php run|inspect ...\n";
exit(1);
}