Liking cljdoc? Tell your friends :D

meme.core

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)

Stages: meme.stages/run — scan + parse stages with intermediate state (no expand/rewrite)

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)

Stages:
  meme.stages/run — scan + parse stages with intermediate state (no expand/rewrite)
raw docstring

meme.emit.formatter.canon

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.
raw docstring

meme.emit.formatter.flat

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).
raw docstring

meme.emit.printer

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.
raw docstring

meme.emit.render

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.
raw docstring

meme.errors

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.
raw docstring

meme.lang

Lang registry, resolution, and EDN loading.

A lang is a map of command functions: :run (fn [source opts] → result) — run a file :repl (fn [opts] → nil) — interactive loop :format (fn [source opts] → text) — format a file :to-clj (fn [source] → clj-text) — convert meme→clj (self-contained) :to-meme (fn [source] → meme-text) — convert clj→meme (JVM only, self-contained)

Plus optional metadata: :extension ".ext" — file extension for auto-detection

Every key is optional. A lang supports exactly the commands it has keys for. The CLI dispatches by looking up the command key in the lang map.

All lang definitions — built-in and user-defined — are EDN: {:run meme.runtime.run/run-string :format meme.lang.meme-classic/format-meme :to-clj meme.lang.meme-classic/to-clj :to-meme meme.lang.meme-classic/to-meme}

User langs can also use: {:extension ".calc" ;; file extension for auto-detection :run "core.meme" ;; string → .meme file to eval before user file :rules "rules.meme" ;; string → .meme file returning rewrite rules :parser my.ns/parser-fn ;; symbol → custom parser function :format :meme-classic} ;; keyword → inherit command from built-in lang

Built-in langs (resources/meme/lang/): :meme-classic (default), :meme-rewrite, :meme-trs

Lang registry, resolution, and EDN loading.

A lang is a map of command functions:
  :run      (fn [source opts] → result)  — run a file
  :repl     (fn [opts] → nil)            — interactive loop
  :format   (fn [source opts] → text)    — format a file
  :to-clj   (fn [source] → clj-text)     — convert meme→clj (self-contained)
  :to-meme  (fn [source] → meme-text)    — convert clj→meme (JVM only, self-contained)

Plus optional metadata:
  :extension  ".ext"   — file extension for auto-detection

Every key is optional. A lang supports exactly the commands it has keys for.
The CLI dispatches by looking up the command key in the lang map.

All lang definitions — built-in and user-defined — are EDN:
  {:run      meme.runtime.run/run-string
   :format   meme.lang.meme-classic/format-meme
   :to-clj   meme.lang.meme-classic/to-clj
   :to-meme  meme.lang.meme-classic/to-meme}

User langs can also use:
  {:extension ".calc"        ;; file extension for auto-detection
   :run "core.meme"          ;; string → .meme file to eval before user file
   :rules "rules.meme"       ;; string → .meme file returning rewrite rules
   :parser my.ns/parser-fn    ;; symbol → custom parser function
   :format :meme-classic}     ;; keyword → inherit command from built-in lang

Built-in langs (resources/meme/lang/):
  :meme-classic (default), :meme-rewrite, :meme-trs
raw docstring

meme.lang.meme-classic

meme-classic: recursive-descent parser + Wadler-Lindig printer.

The default lang. Supports all commands: :run, :repl, :format, :to-clj, :to-meme.

meme-classic: recursive-descent parser + Wadler-Lindig printer.

The default lang. Supports all commands: :run, :repl, :format, :to-clj, :to-meme.
raw docstring

meme.lang.meme-rewrite

meme-rewrite: tree builder + rewrite rules.

Alternative parser that builds explicit m-call/bracket/brace tagged trees, then applies rewrite rules to transform to S-expressions. Supports all commands: :run, :repl, :format, :to-clj, :to-meme.

meme-rewrite: tree builder + rewrite rules.

Alternative parser that builds explicit m-call/bracket/brace tagged trees,
then applies rewrite rules to transform to S-expressions.
Supports all commands: :run, :repl, :format, :to-clj, :to-meme.
raw docstring

meme.lang.meme-trs

meme-trs: token-stream term rewriting.

Operates at the token level: tokenize → nest → rewrite → flatten → text. Bypasses the recursive-descent parser entirely for the meme→clj direction. Supports :run, :format, :to-clj, :to-meme. No :repl yet.

meme-trs: token-stream term rewriting.

Operates at the token level: tokenize → nest → rewrite → flatten → text.
Bypasses the recursive-descent parser entirely for the meme→clj direction.
Supports :run, :format, :to-clj, :to-meme. No :repl yet.
raw docstring

meme.parse.expander

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).
raw docstring

meme.parse.reader

meme reader: recursive-descent parser. Transforms meme tokens into Clojure forms.

meme reader: recursive-descent parser.
Transforms meme tokens into Clojure forms.
raw docstring

meme.parse.resolve

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.
raw docstring

meme.rewrite

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
raw docstring

meme.rewrite.emit

Serialize m-call tagged trees to meme text. Companion to meme.rewrite.rules — renders the output of S→M rules.

Serialize m-call tagged trees to meme text.
Companion to meme.rewrite.rules — renders the output of S→M rules.
raw docstring

meme.rewrite.rules

Rewrite rule sets for S→M and M→S transformations. Each direction is a vector of rules for meme.rewrite/rewrite.

Rewrite rule sets for S→M and M→S transformations.
Each direction is a vector of rules for meme.rewrite/rewrite.
raw docstring

meme.rewrite.tree

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.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.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.
raw docstring

meme.runtime.cli

Unified CLI. Commands dispatch through lang maps.

Unified CLI. Commands dispatch through lang maps.
raw docstring

meme.runtime.repl

meme REPL: read meme, eval as Clojure, print result.

meme REPL: read meme, eval as Clojure, print result.
raw docstring

meme.runtime.resolve

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.
raw docstring

meme.runtime.run

Run .meme files: read, eval, return last result.

Run .meme files: read, eval, return last result.
raw docstring

meme.scan.source

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.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.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.
raw docstring

meme.scan.tokenizer

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.
raw docstring

meme.stages

Explicit stage 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:

KeyTypeWritten byRead by
:sourceStringcallerscan, parse
:optsMap or nilcallerparse, expand
:raw-tokensVectorscan(tooling)
:tokensVectorscanparse
:formsVectorparse, expandexpand, 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.stages.contract for formal clojure.spec definitions of the context map at each stage boundary. Enable runtime validation with: (binding [meme.stages.contract/validate true] (stages/run source))

Explicit stage 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.stages.contract for formal clojure.spec definitions of
the context map at each stage boundary. Enable runtime validation with:
  (binding [meme.stages.contract/*validate* true]
    (stages/run source))
raw docstring

meme.stages.contract

Formal contract for the meme stage context map.

Defines clojure.spec.alpha specs for the context at each stage boundary, a toggleable runtime validator, and explain functions for debugging.

Composable ctx → ctx stages:

scan → parse → expand

Context map contract:

KeyTypeWritten byRead by
:sourceStringcallerscan, parse
:optsMap or nilcallerparse, expand
:raw-tokensVectorscan(tooling)
:tokensVectorscanparse
:formsVectorparse, expandexpand, 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] (stages/run source))

Formal contract for the meme stage context map.

Defines clojure.spec.alpha specs for the context at each stage boundary,
a toggleable runtime validator, and explain functions for debugging.

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]
    (stages/run source))
raw docstring

meme.trs

Token-stream term rewriting system.

Three stages:

  1. Nest: group balanced delimiters into nested vectors
  2. Rewrite: apply declarative rules on nested structure
  3. Flatten: unnest back to flat token vector for emission

Rules are pure data — patterns and replacements that the engine interprets. No lambdas in rule definitions.

Pattern language (matches consecutive sibling nodes): {:bind :name} — match any node, bind {:bind :name :pred fn} — match node satisfying fn, bind {:bind :name :paren-group true :adj true} — match adjacent paren group, bind

Replacement language (produces sibling nodes): {:ref :name} — emit bound node {:ref :name :strip-ws true} — emit bound node, strip :ws {:paren-group [...] :ws-from :name} — build paren group from parts {:body-of :name} — emit inner children of bound group {:body-of :name :ensure-ws str} — emit inner children, ensure :ws on first

Token-stream term rewriting system.

Three stages:
1. Nest: group balanced delimiters into nested vectors
2. Rewrite: apply declarative rules on nested structure
3. Flatten: unnest back to flat token vector for emission

Rules are pure data — patterns and replacements that the engine
interprets. No lambdas in rule definitions.

Pattern language (matches consecutive sibling nodes):
  {:bind :name}                          — match any node, bind
  {:bind :name :pred fn}                 — match node satisfying fn, bind
  {:bind :name :paren-group true :adj true} — match adjacent paren group, bind

Replacement language (produces sibling nodes):
  {:ref :name}                           — emit bound node
  {:ref :name :strip-ws true}            — emit bound node, strip :ws
  {:paren-group [...] :ws-from :name}    — build paren group from parts
  {:body-of :name}                       — emit inner children of bound group
  {:body-of :name :ensure-ws str}        — emit inner children, ensure :ws on first
raw docstring

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close