Composable, type-safe AST and compiler-pass generation for MoonBit.
Dependencies
moon add YumeXi/nanocake@0.3.3moon install YumeXi/nanocake/cmd/nanocake@0.3.3
nanocake --helpgit clone https://github.com/PrairieFire2b/nanocake.git
cd nanocake
moon update
moon check
moon test ┌─────────────┐
.cake / attributes│ meta_parser │ parse metadata, resolve extends chains,
└──────┬──────┘ apply removals, resolve entries/.mbti
│ NanoLangDef[]
▼
┌─────────────┐
│ language │ expand inheritance -> a layout, then
└──────┬──────┘ generate the unified Tree + wrappers
│ GeneratedLanguageLayout
┌───────────┼───────────┐
▼ ▼
┌─────────────┐ ┌─────────────┐
│unparser/gen │ │ pass │ transform/fold scaffolding,
└──────┬──────┘ └─────────────┘ smart constructors, PassM
│ from_sexp / to_sexp_doc
▼
┌─────────────┐
│unparser/sexp│ S-expression runtime: parse, doc render, form matching
└─────────────┘nanocake generate \
--spec schema/arithmetic.cake \
--language Arithmetic \
--module user/compiler \
--pkg schema \
--out-dir generatedmoon run cmd/nanocake -- generate \
--spec examples/nanocake-demo/schema/arithmetic.cake \
--language Arithmetic \
--module YumeXi/nanocake-demo \
--pkg examples/nanocake-demo/schema \
--out-dir examples/nanocake-demo/generatedgenerated/
ast.mbt
codec.mbt
pass.mbt
moon.pkg| File | Contents |
|---|---|
| ast.mbt | Shared Tree, language wrappers, extension enums, external type aliases, and language entry stubs |
| codec.mbt | from_sexp, parse_sexp, to_sexp_doc, and unparse_sexp implementations |
| pass.mbt | Smart constructors, flat views, pure cata semantics, and effectful rewrite APIs |
| moon.pkg | Imports, generated-source formatter exclusions, and warning policy for the generated package |
| Option | Required | Meaning |
|---|---|---|
| --spec <file.cake> | Yes | Metadata sidecar; its (source ...) path is resolved relative to this file |
| --language <name> | Yes | Root language to generate, including its derived language group |
| --module <name> | Yes | MoonBit module containing the source enums |
| --pkg <path> | No | Package containing pkg.generated.mbti; use this for nested or external packages |
| --out-dir <path> | No | Generated package directory; defaults to generated |
| --check | No | Compare expected output with disk without writing |
moon run cmd/nanocake -- generate \
--spec examples/nanocake-demo/schema/arithmetic.cake \
--language Arithmetic \
--module YumeXi/nanocake-demo \
--pkg examples/nanocake-demo/schema \
--out-dir examples/nanocake-demo/generated \
--checkmoon -C examples/nanocake-demo run .moon install ./examples/nanocake-demo
nanocake-demo///|
pub type LambdaVar = String
///|
#nanopasslanguage(name="Lambda")
pub(all) enum Expr {
Int(Int)
LambdaVar(LambdaVar)
Lam(LambdaVar, Expr)
App(Expr, Expr)
}
///|
#nanopasslanguage(name="SimplyTypedLambda", extends="Lambda")
enum TypedExpr {
True
False
Int(Int)
LambdaVar(LambdaVar)
If(cond~ : TypedExpr, TypedExpr, TypedExpr)
Lam(LambdaVar, Type, TypedExpr)
App(TypedExpr, TypedExpr)
} #nanoform("(lambda ($0 : $1) $2)")
#nanoform_only
Lam(LambdaVar, Type, TypedExpr)
#nanoinline // renders as ($0 $1) — no constructor head
App(TypedExpr, TypedExpr)#nanopasslanguage(name="NoApp", extends="Lambda")
#nanoremove("App")
enum NoAppExpr {
// only Lam, Int, LambdaVar are inherited; App is dropped
}let lang = @language.Language::from_file(
name="Lambda", path="poc/lang_def.mbt", mod="YumeXi/nanocake",
)
let impls = lang.gen()
@fmt.impls_to_string(impls) // format and write to filelet lang = @language.Language::from_file(...)
// Generate from_sexp / parse_sexp / to_sexp_doc / unparse_sexp per type.
let codec_impls = @gen.gen(lang)moon check --deny-warn
moon build
moon test --deny-warn
moon fmt --check
moon info
git diff --exit-code| Path | Purpose |
|---|---|
| meta_parser/ | Parse and validate #nanopass / #nano annotations |
| language/ | Expand language inheritance and generate typed AST layouts |
| unparser/sexp/ | S-expression runtime, form matching, rendering, and errors |
| unparser/gen/ | Generate S-expression codecs from a language layout |
| pass/ | Generate transformation APIs and provide pass composition runtime |
| poc/ | Language definitions used by interface-backed integration tests |
| examples/nanocake-demo/ | Independent installable constant-folding module |
| API | Description |
|---|---|
| find_languages_by_spec_file(path) | Parse and lower a .cake sidecar with its referenced MoonBit source |
| parse_nano_spec(source) | Parse .cake text into the schema-level NanoSpec model |
| find_languages(src) | Parse #nanopass.language annotations from a SourceLocRepr |
| find_languages_by_file(path) | Parse language annotations from a file path |
| normalize_language_defs(langs) | Validate and resolve entries; returns langs with resolved_entry populated |
| resolve(loc) | Convert a SourceLoc to a structured SourceLocRepr |
| resolve_mbti(repr) | Parse the .mbti interface for a package |
| NanoLangDef::diff(base, deriv) | Compute the structural diff between two language definitions |
| NanoLangDef::with_constructors(self, constrs) | Return a copy with a new constructor set (rebuilds production_defs) |
| API | Description |
|---|---|
| Language::from_spec(name?, path~, mod~, pkg?) | Resolve a language group from a .cake sidecar |
| Language::def(name?, loc~) | Resolve languages from the callsite file |
| Language::from_file(name?, path~, mod~) | Resolve languages from an explicit file |
| Language::gen() | Generate AST definitions (Tree, wrappers, ext enums, terminals, entry stubs) |
| Language::layout() | Compute GeneratedLanguageLayout (shared by gen and codec generator) |
| Language::expand() | Expand the group into ExpandedLanguageGroup (inheritance + remove applied) |
| expand_language_group(raw) | Standalone expansion without a Language object |
| API | Description |
|---|---|
| parse(src) | Parse a StringView into a Sexp |
| match_form(sexp, pattern, field_count) | Match a sexp against a $0/$1-placeholder pattern |
| form_doc(pattern, fields) | Render field docs into a surface form |
| expect_atom / expect_list / expect_arity | Structural decode helpers |
| hook_error / decode_error / literal_failure | Structured error constructors |
| SexpDoc::render(self, width?) | Pretty-print a doc to a string |
| API | Description |
|---|---|
| gen(lang) | Generate Array[@syntax.Impl] codecs for all types in a language group |
| gen_source(lang) | Return the generated source as a String (for inspection/snapshotting) |
| Command | Description |
|---|---|
| nanocake generate ... | Generate ast.mbt, codec.mbt, pass.mbt, and moon.pkg from a .cake sidecar |
| nanocake generate ... --check | Verify checked-in generated files without modifying them |
| Capability | API |
|---|---|
| Stable AST construction and inspection | Smart constructors, flat view enums, and view() |
| Pure bottom-up folds and transforms | {Lang}Semantics[Repr] and cata |
| Scope-sensitive effectful rewrites | {Lang}RewriteAlg and rewrite_m |
| Focused pass templates | Diff-driven rewrite stub generation |
| Stateful and logged pipelines | PassM, pipeline_m, when_m, and traced |
Composable, type-safe AST and compiler-pass generation for MoonBit.
Dependencies