4.1 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
WoofWare.PawPrint is an experimental .NET runtime implementation written in F#. It's an IL interpreter designed to be:
- Fully deterministic (supporting time-travel debugging and fuzzing over thread execution order)
- Fully managed (reimplementing P/Invoke methods to avoid native code)
- Fully in-memory except for explicit filesystem operations
This is NOT a high-performance runtime - it's a very slow IL interpreter prioritizing determinism over speed.
Common Commands
Building
# Build the entire solution
dotnet build
# Build a specific project
dotnet build WoofWare.PawPrint/WoofWare.PawPrint.fsproj
Testing
# Run all tests
dotnet test
# Run tests for a specific project
dotnet test WoofWare.PawPrint.Test/WoofWare.PawPrint.Test.fsproj
# Run a specific test
dotnet test --filter "FullyQualifiedName~TestCases"
Formatting
# Format F# code using Fantomas
dotnet tool restore
dotnet fantomas .
Running the Application
dotnet publish --self-contained --runtime-id osx-arm64 CSharpExample/ && dotnet run --project WoofWare.PawPrint.App/WoofWare.PawPrint.App.fsproj -- CSharpExample/bin/Debug/net9.0/osx-arm64/publish/CSharpExample.dll
Architecture
Core Components
WoofWare.PawPrint (Main Library)
AbstractMachine.fs
: Core IL interpreter execution engine, knitting togetherUnaryConstIlOp.fs
,UnaryMetadataIlOp.fs
,UnaryStringTokenIlOp.fs
, andNullaryIlOp.fs
IlMachineState.fs
: Manages the complete state of the abstract machineMethodState.fs
: Tracks execution state of individual methodsManagedHeap.fs
: Implements the managed memory modelAssembly.fs
: Handles reading and parsing .NET assembliesTypeInfo.fs
,TypeDefn.fs
,TypeRef.fs
: Type system implementationIlOp.fs
: IL instruction definitions and mungingEvalStack.fs
: Evaluation stack implementationCorelib.fs
: Core library type definitions (String, Array, etc.)
WoofWare.PawPrint.Test
- Uses NUnit as the test framework
- Test cases are defined in
TestCases.fs
- C# source files in
sources/
are compiled and executed by the runtime as test cases TestHarness.fs
provides infrastructure for running test assemblies through the interpreter
WoofWare.PawPrint.App
- Entry point application for running the interpreter
Key Design Patterns
- Immutable State: The interpreter uses immutable F# records for all state, with state transitions returning new state objects
- Assembly Loading: Assemblies are loaded on-demand as types are referenced
- Thread Management: Each thread has its own execution state, managed through the
IlMachineState
- Type Initialization: Classes are initialized lazily when first accessed, following .NET semantics
Code style
- Functions should be fully type-annotated, to give the most helpful error messages on type mismatches.
- Generally, prefer to fully-qualify discriminated union cases in
match
statements. - When writing a "TODO"
failwith
, specify in the error message what the condition is that triggers the failure, so that a failing run can easily be traced back to its cause.
Development Workflow
When adding new IL instruction support:
- Add the instruction to
IlOp.fs
- Implement execution logic in
AbstractMachine.fs
- Add a test case in
sources/
(C# file) that exercises the instruction - Add the test case to
TestCases.fs
- Run tests to verify implementation
The project uses deterministic builds and treats warnings as errors to maintain code quality. It strongly prefers to avoid special-casing to get around problems, but instead to implement general correct solutions; cases where this has failed to happen are considered to be tech debt and at some point in the future we'll be cleaning them up.
Common Gotchas
- I've named several types in such a way as to overlap with built-in types, e.g. MethodInfo is in both WoofWare.PawPrint and System.Reflection.Metadata namespaces. Build errors can usually be fixed by fully-qualifying the type.