Skip to content

BuddhiLW/clojure-elisp

Repository files navigation

ClojureElisp

A Clojure dialect that compiles to Emacs Lisp — like ClojureScript targets JavaScript, ClojureElisp targets Emacs.

Write .cljel files using Clojure syntax, compile them to .el files that run natively in Emacs 28.1+.

Quick Start

(require '[clojure-elisp.core :as clel])

;; Compile a single form
(clel/emit '(defn greet [name] (str "Hello, " name "!")))
;; => "(defun greet (name)\n  (clel-str \"Hello, \" name \"!\"))"

;; Compile a string of code
(clel/compile-string "(defn inc2 [x] (+ x 2))")
;; => "(defun inc2 (x)\n  (+ x 2))"

;; Compile a .cljel file to .el
(clel/compile-file "src/my_package.cljel" "out/my-package.el")

;; Compile an entire project in dependency order
(clel/compile-project ["src"] "out")

Example

;; my-package.cljel
(ns my.package
  (:require [clojure.string :as str]))

(defn greet [name]
  (let [msg (str "Hello, " name "!")]
    (message msg)))

(defn process-buffer []
  (-> (buffer-string)
      str/upper-case
      insert))

Compiles to:

;;; my-package.el --- -*- lexical-binding: t; -*-
;; Generated by ClojureElisp

(require 'clojure-elisp-runtime)

;;; Code:

(defun my-package-greet (name)
  (let* ((msg (clel-str "Hello, " name "!")))
    (message msg)))

(defun my-package-process-buffer ()
  (insert (upcase (buffer-string))))

(provide 'my-package)
;;; my-package.el ends here

Features

Language

  • Functions: defn, fn (lambda), multi-arity, variadic (& rest), destructuring in params
  • Bindings: let with sequential bindings, vector/map destructuring, :keys, :as, :or
  • Control flow: if, when, cond, case, do, and, or
  • Looping: loop/recur, letfn with mutual recursion
  • Macros: defmacro (compile-time only), syntax-quote/unquote, macroexpand-1, macroexpand
  • Error handling: try/catch/finally, throw, ex-info
  • Namespaces: ns with :require, :as, :refer; namespace-prefixed definitions
  • Protocols & types: defprotocol, defrecord, deftype with ^:mutable fields, set!
  • Multimethods: defmulti/defmethod via cl-defgeneric/cl-defmethod
  • Lazy sequences: lazy-seq, realized?, doall, dorun
  • Atoms: atom, deref/@, reset!, swap!, add-watch, remove-watch
  • Elisp interop: .method dot-notation, elisp/fn namespace, .-property access

Core Functions (100+)

Clojure core functions mapped to Elisp equivalents:

Category Functions
Arithmetic +, -, *, /, mod, inc, dec
Comparison =, <, >, <=, >=, not=
Predicates nil?, string?, number?, zero?, pos?, neg?, even?, odd?, coll?, some?
Collections first, rest, next, cons, conj, count, nth, get, assoc, dissoc, keys, vals, into, seq, empty?
Sequences map, filter, remove, reduce, take, drop, concat, mapcat, sort, group-by, frequencies
Seq predicates every?, some, not-every?, not-any?
Strings str, subs, format, pr-str, println
Higher-order apply, identity, constantly, partial, comp

Compiler

  • 3-stage pipeline: Reader (Clojure's) → Analyzer (AST + env) → Emitter (codegen)
  • Source location tracking with optional ;;; L<line>:C<col> comments
  • Dependency-aware project compilation with topological sort
  • Name mangling: valid?valid-p, reset!reset-bang, my.ns/foomy-ns-foo

Architecture

┌─────────────┐    ┌──────────────┐    ┌─────────────┐    ┌──────────────┐
│   Reader    │───▶│   Analyzer   │───▶│   Emitter   │───▶│  Elisp Code  │
│ (Clojure's) │    │ (AST + env)  │    │ (codegen)   │    │   (.el)      │
└─────────────┘    └──────────────┘    └─────────────┘    └──────────────┘
Component File Role
Analyzer src/clojure_elisp/analyzer.clj Parse forms → AST nodes, macro expansion, destructuring, env tracking
Emitter src/clojure_elisp/emitter.clj AST nodes → Elisp source strings
Core src/clojure_elisp/core.clj Public API, file/project compilation, dependency resolution
Runtime resources/clojure-elisp/clojure-elisp-runtime.el 55+ Elisp functions implementing Clojure semantics
Emacs mode resources/clojure-elisp/clojure-elisp-mode.el Major mode for .cljel files
CIDER resources/clojure-elisp/cider-clojure-elisp.el nREPL middleware for CIDER integration

Development

# Start REPL with dev dependencies (nREPL, CIDER)
clojure -M:dev

# Run tests (Kaocha — 160 tests, 900+ assertions)
clojure -M:test

# Build
clojure -T:build

Requirements

  • Clojure 1.12+
  • Emacs 28.1+ (for compiled output)

License

MIT

About

A Clojure dialect that compiles to Emacs Lisp

Resources

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

  •  
  •