Skip to content

maxdeliso/typed-ski

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

192 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SKI in TS

An implementation of a parser, evaluator, printer, and visualizer for SKI.

Project Dependencies

  • TypeScript
  • Node.js as a bootstrap for the repo-pinned toolchain
  • C (compiled to WebAssembly)
  • Bazelisk, which downloads the hermetic Zig-based C/C++ toolchain on first native build

Quick Start

This project uses Bazelisk for common development tasks:

bazelisk build //:thanatos //:release_wasm
bazelisk test //:native_tests
bazelisk test //:node_tests
bazelisk run //:build
bazelisk run //:test
bazelisk run //:coverage
bazelisk run //:ci
bazelisk run //:serve_hephaestus
bazelisk run //:vs_project

The Bazel graph now includes hermetic native thanatos and wasm/release.wasm targets alongside the Node.js-based build, lint, coverage, and packaging flows, without requiring WSL, Nix, or Visual Studio Build Tools on Windows.

If Bazelisk is installed as bazel on your machine, the same commands work with bazel in place of bazelisk. The Bazel version is pinned in .bazelversion.

Development Setup

Installation

  1. Install Node.js
  2. Install Bazelisk
  3. Clone the repository
  4. Run bazelisk build //:thanatos //:release_wasm
  5. Run bazelisk run //:build
  6. Open the project in VS Code

The required Node.js toolchain version is pinned in the repository configuration. Bazelisk commands use your installed Node.js only as a bootstrap shim, then run the repo-pinned Node.js version for the actual build/test command. If your system Node.js does not match, the first Bazelisk run will install the exact pinned binary into a local toolchain cache. Set TYPED_SKI_NODE_TOOLCHAIN_DIR if you want that cache in a specific location.

Running Tests

Run the test suite with:

bazelisk test //:node_tests

For a local single-process workspace run of the same Node.js suite, you can still use:

bazelisk run //:test

On Windows, pass --enable_runfiles to bazelisk test //:node_tests if your Bazel setup does not expose a runfiles tree by default.

Run the native C targets with:

bazelisk build //:thanatos //:release_wasm
bazelisk test //:native_tests

Check which repo-pinned Node.js version Bazelisk will use with:

bazelisk run //:verify_version

Other useful commands:

  • bazelisk run //:build builds generated metadata and distributable artifacts
  • bazelisk run //:typecheck runs TypeScript type checking over the test suite
  • bazelisk run //:coverage runs the tests with coverage output
  • bazelisk run //:ci runs formatting, lint, type checking, build, and a single coverage-producing local test pass
  • bazelisk run //:vs_project writes compile_commands.json, CppProperties.json, .vs/tasks.vs.json, .vs/launch.vs.json, typed-ski-thanatos.sln, and typed-ski-thanatos.vcxproj for Visual Studio workflows

Visual Studio

To generate Visual Studio Open Folder metadata from the Bazel C targets, run:

bazelisk run //:vs_project

Then open the repository directory in Visual Studio with File > Open > Folder. The generated metadata gives Visual Studio:

  • CppProperties.json for Bazel-derived include paths and defines
  • .vs/tasks.vs.json for Bazel build and test tasks
  • .vs/launch.vs.json with a starter thanatos debug configuration
  • typed-ski-thanatos.sln and typed-ski-thanatos.vcxproj for the classic solution/project workflow, including one project for thanatos and one for each native test target

The launch configuration uses gdb (type: "cppdbg"). If gdb.exe is not on your PATH, edit .vs/launch.vs.json and set miDebuggerPath to your local GDB installation before starting a debug session.

If you want the old-school Visual Studio debugger or profiler, open typed-ski-native.sln. The generated projects are Makefile-style C++ projects: Visual Studio invokes Bazel for build/rebuild/clean, and each startup project launches its Bazel-built binary directly. The generated solution includes:

  • typed-ski-thanatos
  • typed-ski-dag-codec-test
  • typed-ski-performance-test
  • typed-ski-session-test
  • typed-ski-ski-io-test
  • typed-ski-util-test

The generated typed-ski-performance-test project includes a starter debugger argument preset tuned for faster iteration inside Visual Studio. Edit the project's Debugging properties if you want to switch back to a larger arena or workload.

The generated Visual Studio metadata is local-only and gitignored, including compile_commands.json, CppProperties.json, .vs/, typed-ski-native.sln, typed-ski-*.vcxproj, typed-ski-*.vcxproj.filters, and *.vcxproj.user. Regenerate them at any time with bazelisk run //:vs_project.

Running Hephaestus

Build the browser assets for the workbench with:

bazelisk run //:hephaestus_assets

Start the server with:

bazelisk run //:serve_hephaestus

Then open http://127.0.0.1:8080/workbench.html.

To use a different port:

PORT=9000 bazelisk run //:serve_hephaestus

On PowerShell:

$env:PORT = "9000"
bazelisk run //:serve_hephaestus

Notes:

  • //:serve_hephaestus builds dist/workbench.js, dist/webglForest.js, and dist/arenaWorker.js before starting the server.
  • bazelisk build //:release_wasm writes the hermetic wasm artifact to bazel-bin/wasm/release.wasm. The Node.js-side build flow stages that artifact into wasm/release.wasm when present so browser and publish paths can use the Bazel-built module.

Artifacts

Build System

This project uses Bazel as the primary build entrypoint. The supported workflow for this branch is Bazel plus Node.js, with generated metadata, packaging, linting, coverage, and the test suite exposed through Bazel commands.

Canonicalization

The TypeScript bootstrap pipeline treats compiler artifacts as canonical, ASCII-only outputs:

  • Top-level Trip unparse preserves the original source-level definition kind and emits parseable canonical syntax such as poly rec and combinator, while internal lowering stages use lambda during linking and execution.
  • .tripc object files are emitted with canonical import/export/definition ordering and recursively sorted object keys.
  • Link-time dependency traversal and SCC processing use explicit ASCII ordering instead of incidental Map/Set iteration order.
  • Final SKI output is the fully parenthesized canonical unparseSKI form and should be compared as UTF-8 bytes.

Performance and Parallelism

This project implements a high-performance, multi-threaded SKI reducer:

  • Parallel Request Execution: Multiple Web Workers reduce independent requests against a shared arena.
  • Preemptive Yielding: Workers yield suspended computations so long-running jobs do not monopolize execution.
  • Lock-Free Communication: io_uring-style submission and completion rings enable low-latency communication between the main thread and workers.
  • Structural Sharing: Global hash-consing ensures that identical sub-expressions share the same memory, significantly reducing the memory footprint of large reductions.

Thanatos (Native Orchestrator)

Thanatos is the native C11/pthreads orchestrator for compute-heavy reductions. The same C core (arena and reduction logic) is compiled in two ways: as the native thanatos binary for CLI/batch use, and to WebAssembly (wasm/release.wasm) for use by the parallel arena evaluator in Node.js. The native binary keeps the SKI evaluator on-metal by managing worker dispatch and completion queues directly, which avoids Node.js/WASM bridge overhead and improves throughput and runtime stability for long-running workloads.

Works Referenced

Books

Papers

  • D. A. Turner, "A new implementation technique for applicative languages," Software: Practice and Experience, vol. 9, no. 1, pp. 31-49, 1979. DOI: 10.1002/spe.4380090105
  • W. Stoye, T. J. W. Clarke, and A. C. Norman, "Some practical methods for rapid combinator reduction," in Proceedings of the 1984 ACM Symposium on LISP and Functional Programming (LFP '84), ACM, New York, NY, USA, pp. 159-166, 1984. DOI: 10.1145/800055.802038
  • H. G. Baker, "CONS should not CONS its arguments, or, a lazy alloc is a smart alloc," ACM SIGPLAN Notices, vol. 27, no. 3, pp. 24-34, 1992. DOI: 10.1145/130854.130858

CI/CD

GitHub Actions use Bazel on both Ubuntu and native Windows. Native C targets run through ordinary Bazel build/test steps, and the Node.js suite runs through the sharded //:node_tests Bazel test target so each shard owns its own Thanatos session. See the workflow files in .github/workflows/ for details.

Status

Bazel CI COC

About

Combinatory logic runtime.

Topics

Resources

License

Code of conduct

Security policy

Stars

Watchers

Forks

Sponsor this project

 

Contributors