Fix fuel implementation in PHP

This commit is contained in:
2026-05-10 09:10:27 -05:00
parent e9eb2daaf2
commit fa58f4ef3a
3 changed files with 20 additions and 27 deletions

View File

@@ -2,7 +2,7 @@
> For AI agents and contributors working in this repository. > For AI agents and contributors working in this repository.
## 0. TDD ## 0. Test Driven Development
Write and discuss tests with the user before implementing any implementation code. Write and discuss tests with the user before implementing any implementation code.
@@ -178,27 +178,7 @@ tricu/
└── AGENTS.md # This file └── AGENTS.md # This file
``` ```
## 9. JS Arboricx Runtime ## 9. Content Store Workflow (Custom DB)
A JavaScript implementation of the Arboricx portable bundle runtime lives in `ext/js/`.
It is a reference implementation — not a tricu source parser. It reads `.arboricx` files produced by the Haskell toolchain, verifies Merkle node hashes, reconstructs tree values, and reduces them.
From project root:
```bash
node ext/js/src/cli.js inspect test/fixtures/id.arboricx
node ext/js/src/cli.js run test/fixtures/true.arboricx
```
The JS runtime implements:
- Bundle binary format parsing (header, section directory, manifest, nodes)
- SHA-256 Merkle node hash verification against canonical payloads
- Closure verification (all child references present)
- Tree reconstruction from node DAG
- Core `apply` reduction rules
- Basic codecs (decodeResult)
- CLI: `inspect` and `run` commands
## 10. Content Store Workflow (Custom DB)
The content store location is controlled by the `TRICU_DB_PATH` environment variable. When set, `eval` mode automatically loads all stored terms into the initial environment, so you can call any previously imported/evaluated term by name. The content store location is controlled by the `TRICU_DB_PATH` environment variable. When set, `eval` mode automatically loads all stored terms into the initial environment, so you can call any previously imported/evaluated term by name.
@@ -226,14 +206,14 @@ t> !definitions
Without `TRICU_DB_PATH` set, `eval` uses only the terms defined in the input file(s). Without `TRICU_DB_PATH` set, `eval` uses only the terms defined in the input file(s).
## 11. Development Tips ## 10. Development Tips
- **REPL:** `nix run .#` starts the interactive tricu REPL. - **REPL:** `nix run .#` starts the interactive tricu REPL.
- **Evaluate files:** `nix run .# -- eval -f demos/equality.tri` - **Evaluate files:** `nix run .# -- eval -f demos/equality.tri`
- **GHC options:** `-threaded -rtsopts -with-rtsopts=-N` for parallel runtime. Use `-N` RTS flag for multi-core. - **GHC options:** `-threaded -rtsopts -with-rtsopts=-N` for parallel runtime. Use `-N` RTS flag for multi-core.
- **Upx** is in the devShell for binary compression if needed. - **Upx** is in the devShell for binary compression if needed.
## 12. Viewing Haskell Dependency Docs from Nix ## 11. Viewing Haskell Dependency Docs from Nix
When you need Haddock documentation for a Haskell dependency available in Nixpkgs, build the package's `doc` output directly with `^doc`. When you need Haddock documentation for a Haskell dependency available in Nixpkgs, build the package's `doc` output directly with `^doc`.

View File

@@ -87,7 +87,7 @@ function cmdRun(string $bundlePath, array $args): void
debugTime('built expression'); debugTime('built expression');
fwrite(STDERR, "Reducing kernel application...\n"); fwrite(STDERR, "Reducing kernel application...\n");
$result = reduce($expr, 1_000_000); $result = reduce($expr, 1_000_000_000);
debugTime('reduced kernel application'); debugTime('reduced kernel application');
[$kind, $value, $rest] = unwrapResult($result); [$kind, $value, $rest] = unwrapResult($result);

View File

@@ -21,6 +21,14 @@ $GLOBALS['ARB_B'] = [0 => 0];
$GLOBALS['ARB_NEXT'] = 1; $GLOBALS['ARB_NEXT'] = 1;
$GLOBALS['ARB_CONS_CACHE'] = []; $GLOBALS['ARB_CONS_CACHE'] = [];
function spendFuel(int &$fuel): void
{
if ($fuel <= 0) {
throw new \RuntimeException('fuel exhausted');
}
$fuel--;
}
function newNode(int $tag, int $a, int $b = 0): int function newNode(int $tag, int $a, int $b = 0): int
{ {
$id = $GLOBALS['ARB_NEXT']++; $id = $GLOBALS['ARB_NEXT']++;
@@ -100,12 +108,12 @@ function newAppFast(int $f, int $x, array &$TAG, array &$A, array &$B): int
return $id; return $id;
} }
function apply_(int $a, int $b, int $fuel = 1_000_000): int function apply_(int $a, int $b, int $fuel = 100_000_000_000_000_000): int
{ {
return reduce(app($a, $b), $fuel); return reduce(app($a, $b), $fuel);
} }
function reduce(int $term, int $fuel = 1_000_000): int function reduce(int $term, int $fuel = 100_000_000_000_000_000): int
{ {
return whnf($term, $fuel); return whnf($term, $fuel);
} }
@@ -167,6 +175,7 @@ function whnf(int $term, int &$fuel): int
if ($left === 0) { if ($left === 0) {
$term = $right; $term = $right;
if ($orig !== $term) { $TAG[$orig] = 4; $A[$orig] = $term; $B[$orig] = 0; } if ($orig !== $term) { $TAG[$orig] = 4; $A[$orig] = $term; $B[$orig] = 0; }
spendFuel($fuel);
continue; continue;
} }
@@ -178,6 +187,7 @@ function whnf(int $term, int &$fuel): int
$TAG, $A, $B $TAG, $A, $B
); );
if ($orig !== $term) { $TAG[$orig] = 4; $A[$orig] = $term; $B[$orig] = 0; } if ($orig !== $term) { $TAG[$orig] = 4; $A[$orig] = $term; $B[$orig] = 0; }
spendFuel($fuel);
continue; continue;
} }
@@ -195,6 +205,7 @@ function whnf(int $term, int &$fuel): int
if ($arg === 0) { if ($arg === 0) {
$term = $A[$left]; $term = $A[$left];
if ($orig !== $term) { $TAG[$orig] = 4; $A[$orig] = $term; $B[$orig] = 0; } if ($orig !== $term) { $TAG[$orig] = 4; $A[$orig] = $term; $B[$orig] = 0; }
spendFuel($fuel);
continue; continue;
} }
@@ -202,6 +213,7 @@ function whnf(int $term, int &$fuel): int
if ($atag === 1) { if ($atag === 1) {
$term = newAppFast($B[$left], $A[$arg], $TAG, $A, $B); $term = newAppFast($B[$left], $A[$arg], $TAG, $A, $B);
if ($orig !== $term) { $TAG[$orig] = 4; $A[$orig] = $term; $B[$orig] = 0; } if ($orig !== $term) { $TAG[$orig] = 4; $A[$orig] = $term; $B[$orig] = 0; }
spendFuel($fuel);
continue; continue;
} }
@@ -213,6 +225,7 @@ function whnf(int $term, int &$fuel): int
$TAG, $A, $B $TAG, $A, $B
); );
if ($orig !== $term) { $TAG[$orig] = 4; $A[$orig] = $term; $B[$orig] = 0; } if ($orig !== $term) { $TAG[$orig] = 4; $A[$orig] = $term; $B[$orig] = 0; }
spendFuel($fuel);
continue; continue;
} }