173 lines
5.0 KiB
PHP
173 lines
5.0 KiB
PHP
#!/usr/bin/env php
|
|
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
/**
|
|
* run.php — Arboricx PHP host shell via libarboricx C ABI.
|
|
*
|
|
* Usage:
|
|
* php run.php run <bundle.arboricx> [args...]
|
|
* php run.php inspect <bundle.arboricx>
|
|
*/
|
|
|
|
require __DIR__ . '/src/ffi.php';
|
|
|
|
use function Arboricx\{ctx_init, ctx_free, loadBundleDefault, ofNumber, ofString, app, reduce, toString, toBool, toNumber};
|
|
|
|
// ── Locate libarboricx.so ──────────────────────────────────────────────────
|
|
|
|
function findLib(): string
|
|
{
|
|
$env = getenv('ARBORICX_LIB');
|
|
if ($env !== false && file_exists($env)) {
|
|
return $env;
|
|
}
|
|
|
|
$paths = [
|
|
__DIR__ . '/../../zig/zig-out/lib/libarboricx.so',
|
|
'/usr/local/lib/libarboricx.so',
|
|
'/usr/lib/libarboricx.so',
|
|
'./libarboricx.so',
|
|
];
|
|
foreach ($paths as $p) {
|
|
if (file_exists($p)) {
|
|
return $p;
|
|
}
|
|
}
|
|
|
|
fwrite(STDERR, "Error: libarboricx.so not found.\nSet ARBORICX_LIB to its full path.\n");
|
|
exit(1);
|
|
}
|
|
|
|
// ── Decode helpers ─────────────────────────────────────────────────────────
|
|
|
|
function decode(\FFI\CData $ctx, int $root): string
|
|
{
|
|
// Bool first: false is Leaf, which is also a valid empty string/list.
|
|
try {
|
|
return toBool($ctx, $root) ? 'true' : 'false';
|
|
} catch (\Throwable $e) {
|
|
try {
|
|
return toString($ctx, $root);
|
|
} catch (\Throwable $e2) {
|
|
try {
|
|
return (string) toNumber($ctx, $root);
|
|
} catch (\Throwable $e3) {
|
|
throw new \RuntimeException('could not decode result');
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function decodeType(\FFI\CData $ctx, int $root): string
|
|
{
|
|
try {
|
|
toBool($ctx, $root);
|
|
return 'bool';
|
|
} catch (\Throwable $e) {
|
|
try {
|
|
toString($ctx, $root);
|
|
return 'string';
|
|
} catch (\Throwable $e2) {
|
|
try {
|
|
toNumber($ctx, $root);
|
|
return 'number';
|
|
} catch (\Throwable $e3) {
|
|
return 'unknown (raw tree)';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ── 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 $libPath, string $bundlePath, array $args): void
|
|
{
|
|
$ctx = ctx_init($libPath);
|
|
try {
|
|
$term = loadBundleDefault($ctx, readBundle($bundlePath));
|
|
|
|
foreach ($args as $arg) {
|
|
$argTree = preg_match('/^\d+$/', $arg) ? ofNumber($ctx, (int)$arg) : ofString($ctx, $arg);
|
|
$term = app($ctx, $term, $argTree);
|
|
}
|
|
|
|
$result = reduce($ctx, $term, 1_000_000_000);
|
|
echo decode($ctx, $result) . "\n";
|
|
} finally {
|
|
ctx_free($ctx);
|
|
}
|
|
}
|
|
|
|
function cmdInspect(string $libPath, string $bundlePath): void
|
|
{
|
|
$ctx = ctx_init($libPath);
|
|
try {
|
|
$bundle = readBundle($bundlePath);
|
|
echo "Bundle: $bundlePath\nSize: " . strlen($bundle) . " bytes\n\nResult:\n";
|
|
|
|
$term = loadBundleDefault($ctx, $bundle);
|
|
$result = reduce($ctx, $term, 1_000_000_000);
|
|
|
|
$type = decodeType($ctx, $result);
|
|
try {
|
|
$value = decode($ctx, $result);
|
|
} catch (\RuntimeException $e) {
|
|
$value = '(raw tree)';
|
|
}
|
|
echo " Type: $type\n Value: $value\n";
|
|
} finally {
|
|
ctx_free($ctx);
|
|
}
|
|
}
|
|
|
|
// ── Main ─────────────────────────────────────────────────────────────────────
|
|
|
|
$argv = $_SERVER['argv'] ?? [];
|
|
$argc = $_SERVER['argc'] ?? 0;
|
|
|
|
if ($argc < 2) {
|
|
echo "Arboricx PHP Host Shell (via libarboricx C ABI)\n\nUsage:\n";
|
|
echo " php run.php run <bundle.arboricx> [args...]\n";
|
|
echo " php run.php inspect <bundle.arboricx>\n";
|
|
exit(0);
|
|
}
|
|
|
|
$libPath = findLib();
|
|
$command = $argv[1];
|
|
|
|
switch ($command) {
|
|
case 'run':
|
|
if ($argc < 3) {
|
|
fwrite(STDERR, "Usage: php run.php run <bundle.arboricx> [args...]\n");
|
|
exit(1);
|
|
}
|
|
cmdRun($libPath, $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($libPath, $argv[2]);
|
|
break;
|
|
default:
|
|
fwrite(STDERR, "Unknown command: $command\nUsage: php run.php run|inspect ...\n");
|
|
exit(1);
|
|
}
|