Skip to content

LispEngineer/dotcl-package-generator

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

31 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

DotCL C# Lisp Package Generator

Overview

dotcl-packagegen is a standalone CLI tool (packaged as a dotnet tool) that generates DotCL Common Lisp packages/bindings for arbitrary .NET assemblies. It is a hybrid C#/Common Lisp codebase: C# does .NET reflection and hosts the DotCL Lisp runtime; Lisp does the actual code generation via string templating.

A single invocation generates everything for one or more assemblies in one pass:

  • Metadata reflection (pure C#, no DotCL needed): for each --assembly, AssemblyToLispy.cs reflects over the .NET assembly (plus its sidecar .xml doc file, if present) and emits a single Lisp-reader-compatible s-expression list — one plist per public type — to a <AssemblyName>.lispy.metadata file in --out-dir. See doc/assembly-to-lispy.md for the complete, canonical schema of this format (keys, flags, parameter plists, documentation plists, default-value literal formatting, etc.)

  • Package generation (boots DotCL): once every assembly's metadata has been reflected, the metadata plus the requested classes are handed to assembly-package-generator.lisp (run-assembly-package-generator-batchgenerate-assembly-packages-batchgenerate-class-file), which emits a .lisp file per requested class defining a package with idiomatic Lisp wrapper functions for that C# type's constructors, methods, properties, and fields. The same invocation also writes packages.lisp (every generated package's cl:defpackage form, including a shared csharp-assembly-utils support package), csharp-assembly-utils.lisp (a small runtime-support condition type generated code depends on), and csharp-assembly-packages.asd (an ASDF system tying the whole batch together), so the output directory is self-contained and loadable with a single (asdf:load-system "csharp-assembly-packages"). All files generated by one invocation share a single creation timestamp.

An --assembly with no --class options is valid — it emits only that assembly's metadata file, generating no packages, e.g. to inspect an assembly's reflected metadata without generating any Lisp packages from it.

The metadata is a single Lisp s-expression.

Origin

This package was split out of my DotCL Dungeon Slime MonoGame proof of concept.

CLI Usage

dotcl-packagegen --out-dir ./cspackages \
    --assembly path/to/Some.Assembly.dll \
      --class Some.Namespace.Type1 --constant-properties "*" \
      --class Some.Namespace.Type2 \
    --assembly path/to/Some.Other.Assembly.dll \
      --class Some.Other.Namespace.Type3

--class attaches to the most recently given --assembly; --constant-properties attaches to the most recently given --class. --assembly may be repeated to process several assemblies in one invocation, and a --assembly with no --class options is valid (metadata-only).

--constant-properties (comma/semicolon-separated names, or "*" for all) forces static read-only properties to be emitted as defconstant instead of define-symbol-macro — safe only when the property genuinely never changes at runtime (e.g. Vector2.Zero), since reflection alone can't tell constants from properties that vary.

Nested C# types (a class/struct/enum declared inside another type) are addressed by their CIL name, which separates nesting levels with + rather than . — e.g. --class Microsoft.Xna.Framework.Graphics.SpriteFont+Glyph for the Glyph type nested inside SpriteFont. The generated Lisp package/file name flattens the + the same way it flattens namespace dots, so that example generates microsoft-xna-framework-graphics-sprite-font-glyph, not a name containing a literal +.

Assembly files are validated to exist, and requested classes are validated to exist in their assembly's metadata, before any output file is written; any error is reported in red to standard error. --version/--help and --test boot the DotCL host (DotclHost.Initialize()); the metadata-reflection portion of a --out-dir invocation intentionally does not, since it's pure reflection and runs before DotCL boots.

Building & Testing

A Makefile is provided with the following targets:

  • make build — Builds the project (dotnet build dotcl-packagegen.csproj -c Debug), compiling both the C# host and the DotCL Common Lisp sources into bin/Debug/net10.0/.

  • make test — Builds the project (via build), then runs the built executable in --test mode. This runs the generator's own Lisp unit tests (package-generator-tests.lisp, including the generated System.TimeSpan operator-overload checks) followed by the AssemblyToLispy metadata test suite against System.Runtime.dll, System.Console.dll, the synthetic AssemblyToLispyTestTarget.dll, and DotCL.Runtime.dll.

  • make package — Builds Release binaries for every configured RuntimeIdentifier (linux-x64, linux-arm64, win-x64, osx-x64, osx-arm64, any) and produces the installable NuGet package(s) (dotnet pack -c Release -o nupkg) in the nupkg/ directory: one package per RID plus a top-level meta-package that dispatches to them.

  • make deploy — Depends on package, then installs (or reinstalls, if already present) dotcl-packagegen as a global dotnet tool from the package(s) just built (dotnet tool install --global --add-source nupkg dotcl-packagegen), making the dotcl-packagegen command available on PATH from any directory.

  • make clean — Runs dotnet clean and removes the bin/, obj/, AssemblyToLispyTestTarget/bin/, AssemblyToLispyTestTarget/obj/, and nupkg/ directories.

Typical workflow: make build test while developing, make deploy to install a local build as the system-wide dotcl-packagegen command.

About

Creates Lisp packages that reflect C# class (struct, enum, etc.) functionality from a given .Net assembly

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages