meme public API: read and print meme syntax.
Three tracks: text-to-form: meme->forms, forms->meme (all platforms) form-to-text: forms->clj (all platforms), clj->forms (JVM only) text-to-text: meme->clj (all platforms), clj->meme (JVM only)
Pipeline: meme.alpha.pipeline/run — full ctx->ctx pipeline with intermediate state
meme public API: read and print meme syntax. Three tracks: text-to-form: meme->forms, forms->meme (all platforms) form-to-text: forms->clj (all platforms), clj->forms (JVM only) text-to-text: meme->clj (all platforms), clj->meme (JVM only) Pipeline: meme.alpha.pipeline/run — full ctx->ctx pipeline with intermediate state
Canonical formatter: width-aware meme output.
Composes printer (form → Doc) with render (layout @ target width).
Used by meme format CLI command.
Canonical formatter: width-aware meme output. Composes printer (form → Doc) with render (layout @ target width). Used by `meme format` CLI command.
Flat formatter: single-line meme output. Composes printer (form → Doc) with render (layout @ infinite width).
Flat formatter: single-line meme output. Composes printer (form → Doc) with render (layout @ infinite width).
Meme printer: Clojure forms → Doc trees. Builds Wadler-Lindig Doc trees from Clojure forms, handling meme syntax (call notation, sugar, metadata, comments) and Clojure output mode. Delegates to render for Doc algebra and layout.
Meme printer: Clojure forms → Doc trees. Builds Wadler-Lindig Doc trees from Clojure forms, handling meme syntax (call notation, sugar, metadata, comments) and Clojure output mode. Delegates to render for Doc algebra and layout.
Wadler-Lindig document algebra and layout engine. Generic — no meme-specific knowledge. Reusable for any pretty-printing task.
Doc types form a small algebra: DocText — literal string DocLine — newline+indent (or flat-alt when flat) DocCat — concatenation DocNest — increase indent DocGroup — try flat, break if too wide DocIfBreak — conditional on flat/break mode
layout renders a Doc tree to a string at a given page width. Use ##Inf for single-line (flat) rendering.
Wadler-Lindig document algebra and layout engine. Generic — no meme-specific knowledge. Reusable for any pretty-printing task. Doc types form a small algebra: DocText — literal string DocLine — newline+indent (or flat-alt when flat) DocCat — concatenation DocNest — increase indent DocGroup — try flat, break if too wide DocIfBreak — conditional on flat/break mode layout renders a Doc tree to a string at a given page width. Use ##Inf for single-line (flat) rendering.
Consistent error infrastructure for the meme reader/tokenizer.
All error throw sites should use meme-error to ensure uniform
location tracking and message formatting.
Consistent error infrastructure for the meme reader/tokenizer. All error throw sites should use `meme-error` to ensure uniform location tracking and message formatting.
Shared form-level predicates and constructors. Cross-stage contracts that both the parser and printer depend on.
Shared form-level predicates and constructors. Cross-stage contracts that both the parser and printer depend on.
Syntax-quote expansion: MemeSyntaxQuote AST nodes → plain Clojure forms. Called by runtime paths (run, repl) before eval. Not needed for tooling (tooling works with AST nodes directly).
Syntax-quote expansion: MemeSyntaxQuote AST nodes → plain Clojure forms. Called by runtime paths (run, repl) before eval. Not needed for tooling (tooling works with AST nodes directly).
meme reader: recursive-descent parser. Transforms meme tokens into Clojure forms.
meme reader: recursive-descent parser. Transforms meme tokens into Clojure forms.
Value resolution: converts raw token text to Clojure values. All resolution is native — no delegation to read-string.
Value resolution: converts raw token text to Clojure values. All resolution is native — no delegation to read-string.
Explicit pipeline composition: source → step-scan → step-parse → step-expand-syntax-quotes → forms. Each stage is a ctx → ctx function operating on a shared context map.
Context map contract:
| Key | Type | Written by | Read by |
|---|---|---|---|
| :source | String | caller | scan, parse |
| :opts | Map or nil | caller | parse, expand |
| :raw-tokens | Vector | scan | (tooling) |
| :tokens | Vector | scan | parse |
| :forms | Vector | parse, expand | expand, caller |
:raw-tokens and :tokens are identical. Both keys are written by scan; :raw-tokens is retained so tooling that reads it continues to work.
Stages are independent functions. Compose them in any order that respects the read/write dependencies above. Guest languages can:
See meme.alpha.pipeline.contract for formal clojure.spec definitions of the context map at each stage boundary. Enable runtime validation with: (binding [meme.alpha.pipeline.contract/validate true] (pipeline/run source))
Explicit pipeline composition: source → step-scan → step-parse → step-expand-syntax-quotes → forms.
Each stage is a ctx → ctx function operating on a shared context map.
Context map contract:
| Key | Type | Written by | Read by |
|--------------|----------------|---------------|----------------------|
| :source | String | caller | scan, parse |
| :opts | Map or nil | caller | parse, expand |
| :raw-tokens | Vector | scan | (tooling) |
| :tokens | Vector | scan | parse |
| :forms | Vector | parse, expand | expand, caller |
:raw-tokens and :tokens are identical. Both keys are written by scan;
:raw-tokens is retained so tooling that reads it continues to work.
Stages are independent functions. Compose them in any order that respects
the read/write dependencies above. Guest languages can:
- Replace stages (e.g. a custom parser that reads :tokens, writes :forms)
- Add stages (e.g. a rewrite stage that reads :forms, writes :forms)
- Skip stages (e.g. skip expand for tooling that works with AST nodes)
- Read intermediate state (e.g. :raw-tokens for syntax highlighting)
See meme.alpha.pipeline.contract for formal clojure.spec definitions of
the context map at each stage boundary. Enable runtime validation with:
(binding [meme.alpha.pipeline.contract/*validate* true]
(pipeline/run source))Formal contract for the meme pipeline context map.
Defines clojure.spec.alpha specs for the context at each stage boundary, a toggleable runtime validator, and explain functions for debugging.
The pipeline is composable ctx → ctx stages:
scan → parse → expand
Context map contract:
| Key | Type | Written by | Read by |
|---|---|---|---|
| :source | String | caller | scan, parse |
| :opts | Map or nil | caller | parse, expand |
| :raw-tokens | Vector | scan | (tooling) |
| :tokens | Vector | scan | parse |
| :forms | Vector | parse, expand | expand, caller |
Guest languages that replace stages (e.g. a custom parser that reads :tokens and writes :forms) must produce context maps conforming to the relevant stage-output spec. Enable runtime validation during development:
(binding [contract/validate true] (pipeline/run source))
Formal contract for the meme pipeline context map.
Defines clojure.spec.alpha specs for the context at each stage boundary,
a toggleable runtime validator, and explain functions for debugging.
The pipeline is composable ctx → ctx stages:
scan → parse → expand
Context map contract:
| Key | Type | Written by | Read by |
|--------------|----------------|---------------|----------------------|
| :source | String | caller | scan, parse |
| :opts | Map or nil | caller | parse, expand |
| :raw-tokens | Vector | scan | (tooling) |
| :tokens | Vector | scan | parse |
| :forms | Vector | parse, expand | expand, caller |
Guest languages that replace stages (e.g. a custom parser that reads
:tokens and writes :forms) must produce context maps conforming to
the relevant stage-output spec. Enable runtime validation during
development:
(binding [contract/*validate* true]
(pipeline/run source))Guest language registry. Maps language names to configurations. A guest language is: a name, a file extension, an optional prelude, and optional rewrite rules.
(register! :pattern {:extension ".pat" :prelude-file "langs/pattern/core.meme" :rules-file "langs/pattern/rules.meme"})
(resolve-lang "app.pat") → :pattern (lang-config :pattern) → {:extension ... :prelude ... :rules ...}
Guest language registry. Maps language names to configurations.
A guest language is: a name, a file extension, an optional prelude,
and optional rewrite rules.
(register! :pattern {:extension ".pat"
:prelude-file "langs/pattern/core.meme"
:rules-file "langs/pattern/rules.meme"})
(resolve-lang "app.pat") → :pattern
(lang-config :pattern) → {:extension ... :prelude ... :rules ...}Term rewriting engine.
Patterns: ?x — match anything, bind to x ??x — match zero or more (splice), bind to x (f ?x ?y) — match a list with head f, bind x and y _ — match anything, don't bind
Rules: (defrule name pattern => replacement)
Engine: (rewrite rules expr) — apply rules bottom-up to fixed point (rewrite-once rules expr) — one bottom-up pass (rewrite-top rules expr) — top-level only to fixed point
Term rewriting engine. Patterns: ?x — match anything, bind to x ??x — match zero or more (splice), bind to x (f ?x ?y) — match a list with head f, bind x and y _ — match anything, don't bind Rules: (defrule name pattern => replacement) Engine: (rewrite rules expr) — apply rules bottom-up to fixed point (rewrite-once rules expr) — one bottom-up pass (rewrite-top rules expr) — top-level only to fixed point
Serialize m-call tagged trees to meme text. Companion to meme.alpha.rewrite.rules — renders the output of S→M rules.
Serialize m-call tagged trees to meme text. Companion to meme.alpha.rewrite.rules — renders the output of S→M rules.
Rewrite rule sets for S→M and M→S transformations. Each direction is a vector of rules for meme.alpha.rewrite/rewrite.
Rewrite rule sets for S→M and M→S transformations. Each direction is a vector of rules for meme.alpha.rewrite/rewrite.
Token vector → tagged tree for the rewrite-based M→S pipeline. Produces a tree with explicit m-call nodes for adjacency-based calls, structural tags (bracket, brace, set-lit, anon-fn), and prefix markers (meme/quote, meme/deref, etc.).
This is the bridge between the shared tokenizer and the rewrite engine. The existing parser (meme.alpha.parse.reader) does tree-building and M→S transformation in one pass. This module separates them: build a raw tagged tree here, then let rewrite rules handle the rest.
Token vector → tagged tree for the rewrite-based M→S pipeline. Produces a tree with explicit m-call nodes for adjacency-based calls, structural tags (bracket, brace, set-lit, anon-fn), and prefix markers (meme/quote, meme/deref, etc.). This is the bridge between the shared tokenizer and the rewrite engine. The existing parser (meme.alpha.parse.reader) does tree-building and M→S transformation in one pass. This module separates them: build a raw tagged tree here, then let rewrite rules handle the rest.
Unified CLI. Functions accept a map — works with both clj -T and bb.
Unified CLI. Functions accept a map — works with both clj -T and bb.
meme REPL: read meme, eval as Clojure, print result.
meme REPL: read meme, eval as Clojure, print result.
Default symbol resolution for syntax-quote expansion. Matches Clojure's SyntaxQuoteReader behavior: special forms stay unqualified, vars resolve to their defining namespace, unresolved symbols get current-namespace qualification. JVM/Babashka only — CLJS callers must provide their own resolver.
Default symbol resolution for syntax-quote expansion. Matches Clojure's SyntaxQuoteReader behavior: special forms stay unqualified, vars resolve to their defining namespace, unresolved symbols get current-namespace qualification. JVM/Babashka only — CLJS callers must provide their own resolver.
Run .meme files: read, eval, return last result.
Run .meme files: read, eval, return last result.
Scanner-level source-position utilities. Defines the character-level line/col model used by the tokenizer. Only \n advances the line counter — \r is a regular character that occupies a column. This matches sadvance! in the tokenizer.
Note: this is the scanner line model, not a universal line definition. The error display module (meme.alpha.errors/source-context) uses str/split-lines which has different line-ending semantics (splits on both \n and \r\n). The two models agree for LF sources but diverge for CRLF. See format-error for how the bridge is handled.
Scanner-level source-position utilities. Defines the character-level line/col model used by the tokenizer. Only \n advances the line counter — \r is a regular character that occupies a column. This matches sadvance! in the tokenizer. Note: this is the *scanner* line model, not a universal line definition. The error display module (meme.alpha.errors/source-context) uses str/split-lines which has different line-ending semantics (splits on both \n and \r\n). The two models agree for LF sources but diverge for CRLF. See format-error for how the bridge is handled.
meme tokenizer: character scanning and token production. Transforms meme source text into a flat vector of typed tokens.
meme tokenizer: character scanning and token production. Transforms meme source text into a flat vector of typed tokens.
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |