php: run a first conformance program on 5.6, 7.4 and 8.4 (step 2 of #64) #727

Closed
opened 2026-11-13 00:55:43 +00:00 by orion · 5 comments
Collaborator

Context

Step 2 of #64 (backend: PHP). Step 1 (#702, PR #707) landed docs/design/PHP.md; its section 6 names this as slice 1 of the implementation: the smallest slice that runs a real program under PHP 5.6, 7.4 and 8.4. It is the sibling of #678 (slice 1 of the JavaScript back end), whose pieces it copies where the IR, not the host, decides: compiler/src/backend/javascript/, runtime/javascript/, tools/conformance.sh --js, tests/conformance/js.allow, the job conformance-js, .forgejo/actions/node.

Source

  • docs/design/PHP.md section 1 (layout, target, shape of the output, CI), section 2.1 to 2.3, 2.5 and 2.7 (control flow with goto, functions, integers, text, panics and guards), section 6 row 1 and "The first slice, precisely enough to file it", section 7 (the statements slice 1 must pin).
  • docs/design/JAVASCRIPT-AND-PHP.md sections 2a (the Int helpers), 2b (capability table), 2d (floor 5.6, fallback 7.4; decided in #62).

What

php: run a first conformance program on 5.6, 7.4 and 8.4. Add Architecture.Php to std/core and TargetArchitecture.Php to project/target.trb (the architectures of Linux become [.X64, .Arm64, .Php]; everyTarget(), targetNamed, the tables of docs/tooling/torb-build.md), so that linux-php is a BuildTarget. Create compiler/src/backend/php/{emit,body,type,natives,writer}.trb and runtime/php/{core,int64}.php. Emit the constructs of the slice-1 row with one goto label per block: Integer (8 to 64 bits except UInt64), Boolean, Void, records and tuples, Constant, Move, Copy, Branch, Jump, Return, Panic, TextConcat, PrintParts, ExitWithCode; the text of section 2.5; the startup guards and hooks of section 2.7; the stack counter of section 1.4 for functions in a recursive cycle. Make torb build, torb run and torb check accept the target without --emit-c. Add tests/conformance/php_first.trb with its .expected, .stderr and .exit files, tests/conformance/php.allow, tools/conformance.sh --php (interpreters from CONFORMANCE_PHP), the action .forgejo/actions/php (pinned versions and SHA-256, commands php5.6, php7.4, php8.4) and a job conformance-php in gates.yml.

Decided by the loop

  • How the three interpreters come to the runner (a build of the source tarball with only Core and standard, or official images by digest) is the implementer's to settle by trying in forge CI, as section 1.4 says; the requirement is a pinned version, a checked checksum and php -d memory_limit=... file.php. Reasoning: a technical choice with no outward effect (recommendation test); a build needs no account or cost.
  • The stack limit of the counter is a number set from running the deepest conformance program on 5.6 (section 1.4); the implementer records it in runtime/php/core.php and in section 7.
  • The open items of section 8 (the entry point of a web request, the reference libm, raising the floor, a coarser stack counter, the execution-time exit code) do not block this slice: the first two belong to slices 8 and 5, the floor was decided in #62, the last two are internal. No owner question is open for this issue.
  • The statements of section 7 marked "slice 1" are the first tests of the leg and must fail loudly; a failure reopens the decision in the record (amend the record in the same PR) before more code depends on it.

Files

  • compiler/src/backend/php/{emit,body,type,natives,writer}.trb; compiler/src/project/target.trb, compiler/src/cli/ (declaration, build, run, check).
  • std/core (Architecture.Php).
  • runtime/php/{core,int64}.php.
  • tests/conformance/php_first.trb and its expected files, tests/conformance/php.allow, tools/conformance.sh.
  • .forgejo/actions/php, .forgejo/workflows/gates.yml (job conformance-php).
  • docs/tooling/torb-build.md, docs/design/PHP.md (row 1 marked done, a "What slice 1 left out" paragraph, section 7 figures); docs regenerated as torb docs requires.

Tests

  1. php_first.trb covers integers of every width with an overflow that panics, a zero divisor, the smallest value divided by -1, functions and recursion, a struct, print of text with numeric-looking strings compared, and a deep recursion that panics at the stack limit.
  2. The guards are tested by running the output with -d mbstring.func_overload=... where the interpreter has it, and with a forged PHP_INT_SIZE through a test harness.
  3. Existing programs that use only the slice-1 constructs and build and run with the same expected files join php.allow.

Acceptance criteria

  • torb build --target linux-php builds php_first.trb without --emit-c and the output runs on 5.6.40, 7.4.33 and the newest 8.4 patch release with the same .expected, .stderr and .exit files as the C, VM and JavaScript legs
  • The overflow, zero-divisor, MIN / -1 and stack-limit cases of php_first.trb exit 101 with the message of the other legs; the guards refuse a forged PHP_INT_SIZE and a forged byte order
  • php.allow holds php_first and every existing program that uses only slice-1 constructs; programs left off are not listed as failures
  • The output is one file starting with <?php, with no closing tag, no namespace and no declare(strict_types=1)
  • The action .forgejo/actions/php pins each version and checks its SHA-256; the job conformance-php runs tools/conformance.sh --php in forge CI
  • A program that fails a statement of section 7 marked "slice 1" fails the leg loudly (the record is amended in the same PR)
  • Row 1 of docs/design/PHP.md marked done; torb format --check and torb docs check green
  • tools/check-commits.sh clean; sh tools/gates.sh a and the conformance-php job green in forge CI (CI only, no local bootstrap or gates)

Seed

Touches it by name: a new Architecture case and a new target that the build looks up. Expect two commits as docs/design/PHP.md section 6 says: the case of Architecture and the target first, the back end after; confirm with tools/check-commits.sh. No syntax change, no new native, no new std name looked up by string. The seed refresh itself stays Torben's.

Size

One PR, two Conventional Commits, as #678 was. If a review cannot hold it, the implementer cuts the CI action and tools/conformance.sh --php with the job into the second commit's follow-up inside this issue; nothing larger is carved out here. What remains is slices 2 to 8 of the record (steps 3 to 9 of #64).

Out of scope

Everything in the rows of slices 2 to 8 of section 6 (variants, switch, arrays, closures, cells, lazy, witnesses, objects, counts, UInt64, the manifest walk, floats and libm, tasks, limits, .nophp markers, torb test), a minifier, the Composer package (#66), the capability table (#65, closed).

Dependencies

Part of #64 (epic; do not close it).

## Context Step 2 of #64 (backend: PHP). Step 1 (#702, PR #707) landed `docs/design/PHP.md`; its section 6 names this as slice 1 of the implementation: the smallest slice that runs a real program under PHP 5.6, 7.4 and 8.4. It is the sibling of #678 (slice 1 of the JavaScript back end), whose pieces it copies where the IR, not the host, decides: `compiler/src/backend/javascript/`, `runtime/javascript/`, `tools/conformance.sh --js`, `tests/conformance/js.allow`, the job `conformance-js`, `.forgejo/actions/node`. ## Source - `docs/design/PHP.md` section 1 (layout, target, shape of the output, CI), section 2.1 to 2.3, 2.5 and 2.7 (control flow with `goto`, functions, integers, text, panics and guards), section 6 row 1 and "The first slice, precisely enough to file it", section 7 (the statements slice 1 must pin). - `docs/design/JAVASCRIPT-AND-PHP.md` sections 2a (the `Int` helpers), 2b (capability table), 2d (floor 5.6, fallback 7.4; decided in #62). ## What *php: run a first conformance program on 5.6, 7.4 and 8.4.* Add `Architecture.Php` to `std/core` and `TargetArchitecture.Php` to `project/target.trb` (the architectures of `Linux` become `[.X64, .Arm64, .Php]`; `everyTarget()`, `targetNamed`, the tables of `docs/tooling/torb-build.md`), so that `linux-php` is a `BuildTarget`. Create `compiler/src/backend/php/{emit,body,type,natives,writer}.trb` and `runtime/php/{core,int64}.php`. Emit the constructs of the slice-1 row with one `goto` label per block: `Integer` (8 to 64 bits except `UInt64`), `Boolean`, `Void`, records and tuples, `Constant`, `Move`, `Copy`, `Branch`, `Jump`, `Return`, `Panic`, `TextConcat`, `PrintParts`, `ExitWithCode`; the text of section 2.5; the startup guards and hooks of section 2.7; the stack counter of section 1.4 for functions in a recursive cycle. Make `torb build`, `torb run` and `torb check` accept the target without `--emit-c`. Add `tests/conformance/php_first.trb` with its `.expected`, `.stderr` and `.exit` files, `tests/conformance/php.allow`, `tools/conformance.sh --php` (interpreters from `CONFORMANCE_PHP`), the action `.forgejo/actions/php` (pinned versions and SHA-256, commands `php5.6`, `php7.4`, `php8.4`) and a job `conformance-php` in `gates.yml`. ## Decided by the loop - How the three interpreters come to the runner (a build of the source tarball with only `Core` and `standard`, or official images by digest) is the implementer's to settle by trying in forge CI, as section 1.4 says; the requirement is a pinned version, a checked checksum and `php -d memory_limit=... file.php`. Reasoning: a technical choice with no outward effect (recommendation test); a build needs no account or cost. - The stack limit of the counter is a number set from running the deepest conformance program on 5.6 (section 1.4); the implementer records it in `runtime/php/core.php` and in section 7. - The open items of section 8 (the entry point of a web request, the reference libm, raising the floor, a coarser stack counter, the execution-time exit code) do not block this slice: the first two belong to slices 8 and 5, the floor was decided in #62, the last two are internal. No owner question is open for this issue. - The statements of section 7 marked "slice 1" are the first tests of the leg and must fail loudly; a failure reopens the decision in the record (amend the record in the same PR) before more code depends on it. ## Files - `compiler/src/backend/php/{emit,body,type,natives,writer}.trb`; `compiler/src/project/target.trb`, `compiler/src/cli/` (declaration, build, run, check). - `std/core` (`Architecture.Php`). - `runtime/php/{core,int64}.php`. - `tests/conformance/php_first.trb` and its expected files, `tests/conformance/php.allow`, `tools/conformance.sh`. - `.forgejo/actions/php`, `.forgejo/workflows/gates.yml` (job `conformance-php`). - `docs/tooling/torb-build.md`, `docs/design/PHP.md` (row 1 marked done, a "What slice 1 left out" paragraph, section 7 figures); docs regenerated as `torb docs` requires. ## Tests 1. `php_first.trb` covers integers of every width with an overflow that panics, a zero divisor, the smallest value divided by `-1`, functions and recursion, a struct, `print` of text with numeric-looking strings compared, and a deep recursion that panics at the stack limit. 2. The guards are tested by running the output with `-d mbstring.func_overload=...` where the interpreter has it, and with a forged `PHP_INT_SIZE` through a test harness. 3. Existing programs that use only the slice-1 constructs and build and run with the same expected files join `php.allow`. ## Acceptance criteria - [ ] `torb build --target linux-php` builds `php_first.trb` without `--emit-c` and the output runs on 5.6.40, 7.4.33 and the newest 8.4 patch release with the same `.expected`, `.stderr` and `.exit` files as the C, VM and JavaScript legs - [ ] The overflow, zero-divisor, `MIN / -1` and stack-limit cases of `php_first.trb` exit 101 with the message of the other legs; the guards refuse a forged `PHP_INT_SIZE` and a forged byte order - [ ] `php.allow` holds `php_first` and every existing program that uses only slice-1 constructs; programs left off are not listed as failures - [ ] The output is one file starting with `<?php`, with no closing tag, no namespace and no `declare(strict_types=1)` - [ ] The action `.forgejo/actions/php` pins each version and checks its SHA-256; the job `conformance-php` runs `tools/conformance.sh --php` in forge CI - [ ] A program that fails a statement of section 7 marked "slice 1" fails the leg loudly (the record is amended in the same PR) - [ ] Row 1 of `docs/design/PHP.md` marked done; `torb format --check` and `torb docs check` green - [ ] `tools/check-commits.sh` clean; `sh tools/gates.sh a` and the `conformance-php` job green in forge CI (CI only, no local bootstrap or gates) ## Seed Touches it by name: a new `Architecture` case and a new target that the build looks up. Expect two commits as `docs/design/PHP.md` section 6 says: the case of `Architecture` and the target first, the back end after; confirm with `tools/check-commits.sh`. No syntax change, no new native, no new std name looked up by string. The seed refresh itself stays Torben's. ## Size One PR, two Conventional Commits, as #678 was. If a review cannot hold it, the implementer cuts the CI action and `tools/conformance.sh --php` with the job into the second commit's follow-up inside this issue; nothing larger is carved out here. What remains is slices 2 to 8 of the record (steps 3 to 9 of #64). ## Out of scope Everything in the rows of slices 2 to 8 of section 6 (variants, switch, arrays, closures, cells, lazy, witnesses, objects, counts, `UInt64`, the manifest walk, floats and `libm`, tasks, limits, `.nophp` markers, `torb test`), a minifier, the Composer package (#66), the capability table (#65, closed). ## Dependencies - #702 (closed, record landed in PR #707); #62 and #52 (closed). Part of #64 (epic; do not close it).
Author
Collaborator

[loop:torbscript] refine: meets the definition of ready (goal, testable criteria, design reference into PHP.md and JAVASCRIPT-AND-PHP.md, seed impact stated, one PR in two commits). No owner question: the open items of PHP.md section 8 do not block slice 1 (see "Decided by the loop").
next: implementation of #727

[loop:torbscript] refine: meets the definition of ready (goal, testable criteria, design reference into PHP.md and JAVASCRIPT-AND-PHP.md, seed impact stated, one PR in two commits). No owner question: the open items of PHP.md section 8 do not block slice 1 (see "Decided by the loop"). next: implementation of #727
Author
Collaborator

[loop:torbscript] claim implement by session:loop-torbscript-20261113 until 2026-11-13T07:00:00Z

[loop:torbscript] claim implement by session:loop-torbscript-20261113 until 2026-11-13T07:00:00Z
Author
Collaborator

[loop:torbscript] release implement: worker timed out after 6 h with no report; PR #730 exists (head bd928fdc) with a red 'commit messages' check (type 'style' is not allowed). next: fix round on the same branch (reword/squash the style commit) when a worker slot is free

[loop:torbscript] release implement: worker timed out after 6 h with no report; PR #730 exists (head bd928fdc) with a red 'commit messages' check (type 'style' is not allowed). next: fix round on the same branch (reword/squash the style commit) when a worker slot is free
Author
Collaborator

[loop:torbscript] claim review by session:loop-torbscript-20261113 until 2026-11-13T10:42:00Z

[loop:torbscript] claim review by session:loop-torbscript-20261113 until 2026-11-13T10:42:00Z
Author
Collaborator

[loop:torbscript] release review: fix worker hit the anthropic:notahumanmate weekly limit (reset 2026-11-15T20:00Z) without a report; it pushed 36684a6 to PR #730 first ('commit messages' no longer red, format --check on body.trb still to confirm). next: fix round on the same branch when a worker slot on another profile is free

[loop:torbscript] release review: fix worker hit the anthropic:notahumanmate weekly limit (reset 2026-11-15T20:00Z) without a report; it pushed 36684a6 to PR #730 first ('commit messages' no longer red, format --check on body.trb still to confirm). next: fix round on the same branch when a worker slot on another profile is free
argus closed this issue 2026-11-13 09:19:51 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
torbscript/language#727
No description provided.