Meme lang composition: lossless pipeline with Pratt parser.
Pipeline: scanner → trivia-attacher → pratt-parser → cst-reader The Pratt parser produces a lossless CST; the CST reader lowers it to Clojure forms.
Meme lang composition: lossless pipeline with Pratt parser. Pipeline: scanner → trivia-attacher → pratt-parser → cst-reader The Pratt parser produces a lossless CST; the CST reader lowers it to Clojure forms.
CST reader: walks CST nodes from the Pratt parser and produces Clojure forms.
This is the lowering step: CST → Clojure forms. It mirrors the classic parser's output (same forms, same metadata, same AST node types) but reads from a lossless tree instead of a token stream.
Pipeline: scanner → trivia-attacher → pratt-parser → cst-reader
CST reader: walks CST nodes from the Pratt parser and produces Clojure forms. This is the lowering step: CST → Clojure forms. It mirrors the classic parser's output (same forms, same metadata, same AST node types) but reads from a lossless tree instead of a token stream. Pipeline: scanner → trivia-attacher → pratt-parser → **cst-reader**
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.
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).
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).
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.
Meme language grammar spec.
Maps characters to scanlets — the complete syntactic specification of M-expression syntax as data. Lexlets provide the scanning layer, parselets provide the compound constructs, and the parser engine provides generic factories.
Meme language grammar spec. Maps characters to scanlets — the complete syntactic specification of M-expression syntax as data. Lexlets provide the scanning layer, parselets provide the compound constructs, and the parser engine provides generic factories.
Meme lexical scanlets: character predicates, consume helpers, and trivia consumers.
This file provides the lexical layer for the meme language. The grammar spec in meme-grammar references these functions by name. Generic scanlet builders (atom-scanlet, single-char-scanlet, delimited-scanlet) live in meme.tools.lexer.
Meme lexical scanlets: character predicates, consume helpers, and trivia consumers. This file provides the lexical layer for the meme language. The grammar spec in meme-grammar references these functions by name. Generic scanlet builders (atom-scanlet, single-char-scanlet, delimited-scanlet) live in meme.tools.lexer.
Meme-specific parselets for the Pratt parser.
Contains the compound parselets that handle meme's unique constructs: call adjacency detection, dispatch (#) sub-routing, tilde (~/@), and the M-expression call rule.
Meme-specific parselets for the Pratt parser. Contains the compound parselets that handle meme's unique constructs: call adjacency detection, dispatch (#) sub-routing, tilde (~/@), and the M-expression call rule.
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.
Meme-specific REPL. Wires meme stages, error formatting, keyword resolution, and syntax-quote resolution into the generic REPL infrastructure. JVM/Babashka only.
Meme-specific REPL. Wires meme stages, error formatting, keyword resolution, and syntax-quote resolution into the generic REPL infrastructure. JVM/Babashka only.
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.
Meme-specific eval pipeline. Wires meme stages, syntax-quote resolution, and BOM stripping into the generic run infrastructure. JVM/Babashka only.
Meme-specific eval pipeline. Wires meme stages, syntax-quote resolution, and BOM stripping into the generic run infrastructure. JVM/Babashka only.
Composable pipeline stages for the lossless reader.
Pipeline: step-parse → step-read
Each stage is a ctx → ctx function operating on a shared context map:
| Key | Type | Written by | Read by |
|---|---|---|---|
| :source | String | caller | parse |
| :opts | Map or nil | caller | parse, read |
| :cst | Vector | parse | read, (tooling) |
| :forms | Vector | read | caller |
Stages are independent. Compose in any order respecting dependencies. Skip step-read for tooling that works with CST directly.
Composable pipeline stages for the lossless reader. Pipeline: step-parse → step-read Each stage is a ctx → ctx function operating on a shared context map: | Key | Type | Written by | Read by | |--------------|----------------|-------------|------------------| | :source | String | caller | parse | | :opts | Map or nil | caller | parse, read | | :cst | Vector | parse | read, (tooling) | | :forms | Vector | read | caller | Stages are independent. Compose in any order respecting dependencies. Skip step-read for tooling that works with CST directly.
Shared value → string serialization for the printer and rewrite emitter. Handles atomic Clojure values (strings, numbers, chars, regex, etc.) that both emit paths must render identically.
Shared value → string serialization for the printer and rewrite emitter. Handles atomic Clojure values (strings, numbers, chars, regex, etc.) that both emit paths must render identically.
Unified CLI. Commands dispatch through lang maps.
Unified CLI. Commands dispatch through lang maps.
Namespace loader for registered languages. Intercepts clojure.core/load to search for source files with registered extensions on the classpath. When found, the source is loaded through the lang's :run function.
Any lang registered via meme.registry with an :extension and :run function gets require support automatically.
Installed implicitly by run-file and the REPL — no manual setup.
Security: a denylist prevents interception of core infrastructure namespaces (clojure., java., etc.). Only user/library namespaces are eligible for lang-based loading.
Namespace loader for registered languages. Intercepts clojure.core/load to search for source files with registered extensions on the classpath. When found, the source is loaded through the lang's :run function. Any lang registered via meme.registry with an :extension and :run function gets require support automatically. Installed implicitly by run-file and the REPL — no manual setup. Security: a denylist prevents interception of core infrastructure namespaces (clojure.*, java.*, etc.). Only user/library namespaces are eligible for lang-based loading.
Lang registry: registration, resolution, and EDN loading. JVM/Babashka only.
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 :to-meme (fn [source] → meme-text) — convert clj→meme
Plus optional metadata: :extension ".ext" — file extension (string or vector) :extensions [".ext" ".e"] — file extensions (string or vector) Both forms are accepted and normalized to :extensions [...].
Every key is optional. A lang supports exactly the commands it has keys for.
Built-in langs are self-describing: each defines a lang-map in its own namespace. User langs can be registered via register! with EDN-style config maps.
Lang registry: registration, resolution, and EDN loading. JVM/Babashka only. 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 :to-meme (fn [source] → meme-text) — convert clj→meme Plus optional metadata: :extension ".ext" — file extension (string or vector) :extensions [".ext" ".e"] — file extensions (string or vector) Both forms are accepted and normalized to :extensions [...]. Every key is optional. A lang supports exactly the commands it has keys for. Built-in langs are self-describing: each defines a lang-map in its own namespace. User langs can be registered via register! with EDN-style config maps.
Generic scanlet builders for the Pratt parser engine.
Scanlet builders wrap language-specific consume functions into parselets that the grammar spec can reference. They bridge the gap between 'consume characters from source' and 'produce a CST node'.
Any language can use these builders with its own consume functions.
Generic scanlet builders for the Pratt parser engine. Scanlet builders wrap language-specific consume functions into parselets that the grammar spec can reference. They bridge the gap between 'consume characters from source' and 'produce a CST node'. Any language can use these builders with its own consume functions.
Unified scanlet-parselet Pratt parser.
The engine reads directly from a source string. The grammar spec defines everything language-specific: character dispatch (scanlets), trivia classification, prefix parselets (nud), and postfix rules (led).
A scanlet is (fn [engine] → CST node). It consumes characters from the source string using engine primitives and produces a CST node.
Grammar spec shape: {:nud {char → scanlet-fn} :nud-pred [[pred scanlet-fn] ...] :trivia {char → trivia-consumer-fn} :trivia-pred [[pred trivia-consumer-fn] ...] :led [{:char c :bp n :when pred :fn scanlet-fn} ...]}
Parselet factories (nud-atom, nud-prefix, nud-delimited, etc.) generate common patterns. Custom parselets are plain functions.
Unified scanlet-parselet Pratt parser.
The engine reads directly from a source string. The grammar spec defines
everything language-specific: character dispatch (scanlets), trivia
classification, prefix parselets (nud), and postfix rules (led).
A scanlet is (fn [engine] → CST node). It consumes characters from the
source string using engine primitives and produces a CST node.
Grammar spec shape:
{:nud {char → scanlet-fn}
:nud-pred [[pred scanlet-fn] ...]
:trivia {char → trivia-consumer-fn}
:trivia-pred [[pred trivia-consumer-fn] ...]
:led [{:char c :bp n :when pred :fn scanlet-fn} ...]}
Parselet factories (nud-atom, nud-prefix, nud-delimited, etc.) generate
common patterns. Custom parselets are plain functions.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.
Generic interactive eval loop. Language-agnostic. All language-specific behavior is injected via opts: :run-fn — (fn [source opts] → ctx-with-:forms) :expand-forms — (fn [forms opts] → expanded-forms) :format-error — (fn [exception input] → error-string) :eval — eval function (default: clojure.core/eval) :read-line — line reader fn (default: read-line) :banner — REPL banner string :reader-opts — opts map passed to run-fn :prelude — vector of forms to eval before REPL loop JVM/Babashka only.
Generic interactive eval loop. Language-agnostic. All language-specific behavior is injected via opts: :run-fn — (fn [source opts] → ctx-with-:forms) :expand-forms — (fn [forms opts] → expanded-forms) :format-error — (fn [exception input] → error-string) :eval — eval function (default: clojure.core/eval) :read-line — line reader fn (default: read-line) :banner — REPL banner string :reader-opts — opts map passed to run-fn :prelude — vector of forms to eval before REPL loop JVM/Babashka only.
Generic eval pipeline: source → parse → expand → eval. Language-agnostic. All language-specific behavior is injected via opts: :run-fn — (fn [source opts] → ctx-with-:forms) :expand-forms — (fn [forms opts] → expanded-forms) :eval — eval function (default: clojure.core/eval) :prelude — vector of forms to eval before user code JVM/Babashka only.
Generic eval pipeline: source → parse → expand → eval. Language-agnostic. All language-specific behavior is injected via opts: :run-fn — (fn [source opts] → ctx-with-:forms) :expand-forms — (fn [forms opts] → expanded-forms) :eval — eval function (default: clojure.core/eval) :prelude — vector of forms to eval before user code JVM/Babashka only.
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 |