Liking cljdoc? Tell your friends :D

meme-clj — M-Expressions with Macro Expansion

CI Clojure License

M-expressions were McCarthy's original intended syntax for Lisp (1960). S-expressions were meant to be internal representation only — but they stuck. meme picks up where McCarthy left off: one rule that makes nesting self-evident, while preserving Clojure's semantics exactly.

The rule — head outside the parens: f(x y) => (f x y)

Quote and backtick' quotes the next meme form: 'f(x) is (quote (f x)). ` uses meme syntax inside for macro templates: `if(~test do(~@body))

Everything else is Clojure.

;; examples/stars.meme — bb meme run examples/stars.meme
require('[cheshire.core :as json])

defn(stars
  [owner repo]
  let(
    [
      url
      str("https://api.github.com/repos/" owner "/" repo)
      resp
      slurp(url)
      data
      json/parse-string(resp true)
      count
      :stargazers_count(data)
    ]
    println(str(owner "/" repo ": " count " ⭐"))))

stars("xpojure-lang" "meme-clj")

Installation

Add to deps.edn:

io.github.xpojure-lang/meme-clj {:mvn/version "4.0.0"}

Or clone and use directly:

git clone https://github.com/xpojure-lang/meme-clj.git
cd meme-clj

Getting Started

Run a .meme file:

$ bb meme run hello.meme                                # Babashka
$ clojure -T:meme run :file '"hello.meme"'              # Clojure JVM
Hello, world!

Interactive REPL:

$ bb meme repl                                          # Babashka
user=> +(1 2)
3
user=> map(inc [1 2 3])
(2 3 4)

Convert between meme and Clojure:

$ bb meme to-clj hello.meme                             # .meme → Clojure
$ bb meme to-meme hello.clj                             # .clj → meme
$ bb meme to-clj hello.meme --stdout                    # print to stdout

Format .meme files (normalize syntax via canonical formatter):

$ bb meme format hello.meme                             # in-place
$ bb meme format src/                                   # directory, recursive

Macros work naturally — backtick uses meme syntax inside:

;; define a macro
defmacro(unless [test & body]
  `if(not(~test) do(~@body)))

;; use it
unless(empty?(xs)
  println(first(xs)))

Namespace Loading

.meme files participate in Clojure's normal namespace machinery — no build plugin, no AOT step, no annotations:

;; src/myapp/core.meme exists on the classpath
require('[myapp.core :as core])
core/greet("world")

The loader intercepts clojure.core/load (JVM) and clojure.core/load-file (JVM + Babashka), so any .meme file under a registered extension is found and run on first reference. When both myapp/core.meme and myapp/core.clj exist, .meme wins.

Auto-installed. meme-lang.run/run-string, run-file, and the REPL install the loader before evaluating user code — programmatic embeddings get .meme require for free, not just the CLI. Hosts that own their own clojure.core/load interception opt out with :install-loader? false.

Lang-independent. The loader is registry-driven: it dispatches on extension to whatever lang is registered. Sibling langs (e.g. calc-lang) registered with :extensions and :run get the same require/load-file support without writing any loader code.

Safety. Core namespaces (clojure.*, java.*, javax.*, cljs.*, nrepl.*, cider.*) are on a denylist and cannot be shadowed by .meme files on the classpath.

Babashka limitation. Babashka's SCI does not dispatch require through clojure.core/load, so on Babashka require of .meme namespaces is not supported. load-file works on both platforms. For Babashka projects that need require, precompile to .clj:

$ bb meme compile src/                                  # output to target/classes/
$ bb meme compile src/ --out out/                       # custom output directory

Requires Babashka or Clojure.

Editor Support

EditorRepositoryFeatures
Zedzed-memeSyntax highlighting, brackets, indentation, symbol outline
VS Codevscode-memeSyntax highlighting, brackets, indentation, folding

Tree-sitter grammar: tree-sitter-meme

Documentation

Grouped by who the doc is for:

Writing .meme code

Embedding meme in a Clojure project

  • API Reference — public functions (meme->forms, forms->meme, format-meme-forms, run/repl helpers, registry)

Extending the formatter or building a sibling lang

Project tracking

Contributing

Can you improve this documentation?Edit on GitHub

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