PHPurs turns the typed CoreFn (TAST / tcorefn) of the PureScript fork,
optimized by PBO, into PHP, then publishes modules, entrypoints and bundles.
This page is the overview; detailed contracts live in compiler.md,
ffi-boundaries.md and the audit reports.
typed TAST / CoreFn (output/*/corefn.json)
-> PBO, directives and FFI contracts
-> optimized BackendModule
-> CodeGen (TCO analysis, bindings, expressions)
-> PhpFile / PhpDecl / PhpExpr
-> Printer (expressions, declarations, runtime, module)
-> module index.php / main.mod.php / main.bundle.php / bundle.php
-> output manifest, cache and Composer
Mainloads CoreFn, selects main modules and computes the import closure (Main.Selection).Main.Optionsnormalizes flags and budgets.Main.Prepareresolves Spago/FFI roots, captures FFI sources, prepares callbacks and the cache.- PBO (
buildModules) optimizes the selected modules and returnsBackendModulevalues.
CodeGenorders the passes and the proofs that authorize specializations.CodeGen.Exprtranslates expressions recursively;CodeGen.Declarationsemits the module's constructors, functions and values.CodeGen.Contextcarries lexical state, loops and effect position.CodeGen.Tcoowns labels, tail jumps and direct registers.CodeGen.Effectsdistinguishes a deferred action from an already executed value.CodeGen.Bindingsanalyzes recursive groups and initialization order.- Local passes (
PartialBindings,ThunkFusion,StateFusion,CallbackSpecialization,ArrayCallbacks,EnumRegions,TailInline,CompactLoops,NullableConstructors,CopyCleanup,ArrayRefs) transform the TAST or the PHP AST before printing.
Passes that rewrite the TAST share the Phpurs.Pass protocol: a pure
BackendModule -> { module_, privateNames } function with shared size guards,
binding traversal and scan budget. Each pass keeps its proofs, budgets and
fallback.
Safety valves (module size, scanned nodes, fuel, workers, copies, depth and
width) live in Phpurs.Budget; a pass does not hard-code one.
Optimize.NeutralExpr, Optimize.Names and Optimize.ScalarWorker share the
common constructions.
ArrayRefs.CallSites finds call sites, ArrayRefs.Decision checks per-site
safety, and ArrayRefs.Fixpoint solves the promotion sets; Analysis exposes
the aggregate entry points.
Ownership tracks aliases and field reads of an owner; Rebuild applies the
authorized rewrite. Support provides the shared traversals and accessors.
Printer.Exprrenders expressions, captures, currying and PHP names.Printer.Declrenders declarations, exact bodies and the complete module.Printer.Runtimeprovides the single global definitions (curry, effect, references); canonical names live inRuntimeNames.- Modules use
runtime.php; bundles embed the runtime once inside anamespace { ... }block.
ModuleStatepublishes fresh or restored modules in the same order.BuildCacheconnects content keys to module state; incomplete or ambiguous entries disable the cache.OutputManifestowns the PHP/Composer files, preserves user modifications and removes obsolete outputs after finalization.Main.Outputswrites entrypoints and bundles, then finalizes the manifest.
- Modular mode:
main.mod.phploads the reachable modules. - Explicit bundle:
main.bundle.phpcontains the CoreFn closure and the runtime. - Automatic bundle: union of the exported mains' closures.
- No main: every loaded module is kept.
Tests are classified in tests/codegen/README.md:
- direct generator/AST tests;
- CLI/cache/emission tests (
tests/codegen/cli); - FFI/runtime tests (
tests/codegen/ffi).
npm run test:codegen is the single entry point. Fixture and PHP execution
helpers live in tests/codegen/fixtures/cli.mjs.
- The optimized TAST is not mutated: passes build new nodes.
- FFI boundaries and PHP errors are preserved.
- Extracting a module must not change the PHP produced for an unchanged input.
- The cache and the manifest stay coherent across cold, partial and restored builds.