Skip to content

ironkernel-lang/IronKernel

Repository files navigation

IronKernel

IronKernel is a dialect of John N. Shutt’s Kernel for .NET 10.

Kernel is Scheme-like but more homoiconic: combiners and environments are first-class, and the core abstraction is the operative (vau) rather than macros.

This tree is a hybrid CLR runtime: programs are analyzed to a Core IR and compiled to CLR delegates while preserving runtime combiner dispatch, with a trampolined CPS interpreter for full Kernel semantics (vau, first-class eval/environments, call/cc, shift/reset).

Build & test

dotnet build
dotnet test

Requires the .NET 10 SDK.

Benchmarks

Compiler, runtime, symbol lookup, and CLR resolution benchmarks use BenchmarkDotNet and must run in Release mode:

dotnet run --project IronKernel.Benchmarks -c Release -- --filter '*CompilerBenchmarks*'
dotnet run --project IronKernel.Benchmarks -c Release

Use --job Dry only to verify benchmark discovery and execution; its single iteration is not a performance measurement. Benchmark reports are written to BenchmarkDotNet.Artifacts/. Performance changes should include before/after results from the same machine and runtime.

CI & releases

  • CI (.github/workflows/ci.yml) runs dotnet test on Ubuntu for pushes/PRs to main/master.
  • Release (.github/workflows/release.yml) triggers on tags v* (e.g. v0.4.0): verifies the tag matches the root version file, tests on Linux, then publishes self-contained single-file binaries for linux-x64, win-x64, osx-arm64, and osx-x64, plus NuGet packages for IronKernel.Tool and IronKernel.Sdk. Binaries are attached as ironkernel-<rid>.tar.gz (binary + kernel.ikr / promises.ikr).
  • Versioning: edit the root version file (single source of truth via Directory.Build.props). Commit, then tag and push v$(tr -d '[:space:]' < version). The release job fails if the tag and file disagree. ik --version and the REPL banner read the assembly informational version produced from that file.

Website

The promotional site and docs live in website/ and target ironkernel.org (Iron = It runs on .NET; the .net TLD was taken).

# local preview
python3 -m http.server -d website 8080

GitHub Pages deploys from website/ via .github/workflows/pages.yml (enable Pages → “GitHub Actions” in repo settings, then point the domain’s DNS at GitHub).

Getting started

Preferred: install the ik global tool from NuGet.org (requires the .NET 10 SDK), then use the CLI directly. Self-contained binaries are also on GitHub Releases. Full steps and VS Code runtime discovery are in the getting-started guide.

dotnet tool install -g IronKernel.Tool
# Ensure ~/.dotnet/tools is on PATH
ik --version
ik new app hello

Packages on NuGet.org: IronKernel.Tool (ik) and IronKernel.Sdk (MSBuild SDK for .ikproj). If dotnet tool install reports a missing DotnetToolSettings.xml, install or select a .NET 10 SDK — that error is the usual symptom of an older SDK trying to install a net10.0 tool.

For contributors building this repository:

dotnet build
dotnet run --project IronKernel -- Examples/hello.ikr

See Examples/README.md for runnable programs.

Projects and packages

.ikproj files are MSBuild-compatible IronKernel projects. Use the ik tool (or the same subcommands on the IronKernel release binary):

ik new app hello
cd hello
ik run
ik test
ik restore
ik add Acme.IronKernel.Http 1.2.0
ik add Npgsql 9.0.0 --clr
ik tree
ik build
ik pack

Projects use standard NuGet PackageReference entries and commit packages.lock.json. Restored IronKernel package sources under ironkernel/src/**/*.ikr load before project source; declared CLR runtime assemblies are loaded for interop.

Public packages use NuGet.org initially. See docs/packages.md for package layout and ADR 0001 for the extension and ecosystem decision.

REPL

ik
# or: IronKernel

Loads kernel.ikr and promises.ikr, then presents an interactive prompt. Type quit to exit.

Run a script

ik path/to/program.ikr arg1 arg2
# Equivalent explicit form:
ik run path/to/program.ikr arg1 arg2

Script mode loads kernel.ikr and promises.ikr in a fresh environment, then binds command-line arguments to args. Evaluation and startup errors are written to stderr and produce a non-zero exit code.

Compile to an IKC package

ik compile path/to/program.ikr -o program.ikc
ik run program.ikc

Compilation parses and analyzes the source without executing it, then writes an architecture-neutral IKC2 package containing versioned Core IR and typed constants. At run time IronKernel loads the standard library, decodes the Core IR, compiles it to delegates, and executes it without parsing or analyzing the original source. Source locations and relevant lines remain as diagnostic metadata. IKC1 source packages must be rebuilt. Omitting -o writes <source-name>.ikc.

Use --help for all commands and --version for the runtime version.

Compile to a managed artifact

ik compile path/to/program.ikr --managed -o publish
dotnet publish/program.dll

Managed artifacts contain generated CLR entry points and typed constants rather than the original Kernel source. They require .NET 10, but startup does not parse the program or build expression-tree delegates. Published output references the parser-free IronKernel.Runtime library and excludes the compiler and FParsec. The static backend supports literals, variables, quoted values, statically named combinations, top-level definitions, lazy conditionals, and sequencing. Generated guards preserve primitive rebinding semantics, and embedded source spans retain runtime diagnostics. kernel.ikr and promises.ikr are compiled into artifact initialization functions, so standard-library features are available without shipping or parsing those files at startup; unsupported forms fail compilation. See ADR 0002 for the managed and NativeAOT roadmap.

Compile to a native artifact

ik --profile minimal compile path/to/program.ikr --native osx-arm64 -o publish
./publish/program

Native artifacts are RID-specific, self-contained executables produced with .NET NativeAOT. They require neither the dotnet host nor Kernel source at run time. The native backend supports the minimal and safe profiles and the same Core IR subset as managed artifacts. Safe artifacts include capability-checked, generated CLR bindings without enabling raw reflection. On macOS, publishing requires the Xcode command line tools plus Homebrew openssl@3 and brotli; IronKernel statically links those Homebrew libraries so the resulting executable has no Homebrew runtime dependency.

Diagnostics

Parse and runtime failures include the source path, line and column, offending line, and a caret range. CLI modes write diagnostics to stderr and return a non-zero exit code. Compiled source reports the narrowest retained span, such as an unbound operator or the selected branch of a guarded if:

program.ikr:2:2: Getting an unbound variable: 'missing'
(missing 42)
 ^^^^^^^

Syntax constructed as a runtime LispVal and passed to eval has no original source span. Errors from such code use the nearest enclosing source location when one is available.

Capability profiles and generated CLR bindings

IronKernel can construct root environments with different host authority:

Profile Host access
minimal Kernel evaluation and data primitives only
safe Minimal profile plus reviewed generated CLR wrappers
unrestricted Raw CLR reflection, source loading, and host I/O (default)
ik --profile safe path/to/safe-clr.ikr

Safe wrappers such as Console.write-line, String.concat, and Math.sqrt are generated from manifests/safe-clr-bindings.json. The generator resolves one exact public static signature and emits direct typed calls—there is no runtime overload selection or reflection in the generated path:

dotnet fsi tools/generate-clr-bindings.fsx \
  manifests/safe-clr-bindings.json IronKernel/Generated/Bindings.Safe.fs

Child environments intersect their parents' capability sets. Imported or stolen interop values still check the authority of the environment where they are invoked, so copying a binding cannot grant host access. See docs/capabilities.md for the security model and limits.

Tagged handlers and async

Prompt tags are unforgeable runtime values. Tagged shift selects the nearest matching reset, while prompt installs a deep effect handler:

(define request (make-prompt-tag))

(prompt request
  (lambda (value k) (resume k (+ value 1)))
  (+ 1 (perform request 40)))
; ⇒ 42

perform supplies the operation value and a one-shot resumption to the handler. Resuming reinstalls the same tagged handler; attempting to resume twice is an error. Existing untagged (reset body) and (shift handler) remain multi-shot and backward compatible.

The unrestricted profile also provides (task-delay milliseconds value) and (await-task task). Task callbacks only publish an outcome; Eval.runAsync resumes the trampoline serially rather than evaluating on a CLR callback thread. See Examples/effects-async.ikr.

Operative contracts and partial evaluation

Contracts are optional combiner metadata. They distinguish raw operative operands from evaluated applicative arguments and validate fixed value shapes:

(define double (lambda (x) (+ x x)))
(contract double applicative (number) number pure #t)

(define raw (vau operands _ operands))
(contract raw operative (any) any pure #t)

Supported shapes are any, number, integer, string, boolean, atom, list, prompt-tag, and resumption. The final fields declare the effect summary (pure or effectful) and whether the combiner is intended to be inlineable.

User contracts are asserted metadata and are never executed by the compiler. Reviewed primitive contracts are certified; pure literal calls such as (+ 20 22) may be folded behind a binding-cell/version/structural contract snapshot guard. Rebinding the operator selects the untouched generic combination before any operand effects occur. Dynamic eval, control effects, CLR calls, and async operations remain residual.

See Examples/contracts.ikr.

VS Code extension and playground

The extension in editors/vscode/ provides IronKernel syntax highlighting, snippets, run/compile commands, Problems diagnostics, and a playground backed by the real CLI. Build a local VSIX with:

cd editors/vscode
npm install
npm run package

The playground requires a trusted workspace because IronKernel programs can invoke .NET APIs. See the extension README for runtime discovery and .ikr file-association guidance.

CLR namespaces and Clojure-style calls

Under the unrestricted profile you can open namespaces and use short type names:

(clr-open System System.IO)
(clr-alias SB System.Text.StringBuilder)

(Guid/NewGuid)                 ; static method
(StringBuilder.)               ; constructor
(.Append sb "hi")              ; instance method
(.-Length sb)                  ; field / property
(clr-type Path)                ; first-class System.Type value

Full names such as System.Console remain valid. Ambiguous short names after clr-open raise an error; use clr-alias or a full name to disambiguate.

Syntax

IronKernel keeps a LISP / Kernel S-expression surface (parentheses are intentional). Notable surface forms:

Form Meaning
(…) Lists / combinations
[…] Vectors
(a & b) Improper / dotted lists (& instead of .)
:keyword Keywords
#t #f #inert Booleans and inert
λ / ϝ Aliases for lambda / vau

Source syntax may nest lists and vectors up to 256 levels. Deeper input is rejected with a located parse error before recursive parser processing begins; parentheses and brackets inside strings or comments do not count toward the limit.

Architecture

Module Role
Parser.fs FParsec → homoiconic LispVal
Ir.fs / Analyze.fs Core IR + binding-aware guarded analysis
Eval.fs Trampolined CPS interpreter (TCO-capable)
Compiler.fs Guarded Expression-tree compiler with generic fallback
Emit.fs IKC package emit / load
Runtime.fs Primitive operatives & applicatives
kernel.ikr Stdlib (lambda, let, modules, …)

Compiler fast paths are guarded by stable binding-cell identity and version. Rebinding or shadowing a primitive invalidates its guard before any specialized work begins, so execution falls back to ordinary Kernel combiner dispatch.

License

Apache 2.0 — see COPYING.

About

IronKernel is a dialect of the Kernel programming language for the .NET framework.

Topics

Resources

License

Stars

14 stars

Watchers

2 watching

Forks

Packages

 
 
 

Contributors