No description
  • C 88.9%
  • JavaScript 2.9%
  • Shell 2.2%
  • Emacs Lisp 2.2%
  • C++ 1.8%
  • Other 2%
Find a file
2026-07-30 15:47:36 -06:00
.builds Build with JERBOA_NATIVE_FEATURES=tls (smaller, avoids OOM) 2026-07-21 18:39:51 -06:00
.jerboa Add ts-mode reproducibility report gate 2026-06-25 18:53:32 -06:00
docs fix: close security audit findings 2026-07-11 17:26:45 -06:00
queries Initial tree-sitter grammar and Emacs mode for Jerboa Scheme 2026-03-27 18:01:08 -06:00
scripts fix: close security audit findings 2026-07-11 17:26:45 -06:00
src Security hardening and release readiness 2026-06-23 10:51:51 -06:00
support fix: close security audit findings 2026-07-11 17:26:45 -06:00
test/corpus Initial tree-sitter grammar and Emacs mode for Jerboa Scheme 2026-03-27 18:01:08 -06:00
.gitignore Security hardening and release readiness 2026-06-23 10:51:51 -06:00
.gitsafe.json fix: close security audit findings 2026-07-11 17:26:45 -06:00
AGENTS.md docs: remove jerboa-emacs restriction 2026-07-30 15:47:36 -06:00
grammar.js Initial tree-sitter grammar and Emacs mode for Jerboa Scheme 2026-03-27 18:01:08 -06:00
jerboa-ts-mode.el fix: close security audit findings 2026-07-11 17:26:45 -06:00
LICENSE Switch to MIT license 2026-07-21 13:42:20 -06:00
Makefile build: add lint target 2026-07-21 11:52:59 -06:00
package-lock.json fix: close security audit findings 2026-07-11 17:26:45 -06:00
package.json fix: close security audit findings 2026-07-11 17:26:45 -06:00
README.md Move project links to SourceHut 2026-07-30 15:41:00 -06:00
SECURITY.md fix: close security audit findings 2026-07-11 17:26:45 -06:00
toolchain-lock.tsv fix: close security audit findings 2026-07-11 17:26:45 -06:00
tree-sitter.json fix: close security audit findings 2026-07-11 17:26:45 -06:00

jerboa-ts-mode

Tree-sitter grammar and Emacs major mode for Jerboa Scheme, a Chez Scheme dialect with Jerboa-specific syntax extensions.

What's Included

File Purpose
grammar.js Tree-sitter grammar definition
src/scanner.c External scanner for heredocs (#<<DELIM) and nested block comments (#|...|#)
src/parser.c Generated parser (checked in for compilation)
jerboa-ts-mode.el Emacs 29+ tree-sitter major mode
queries/highlights.scm Highlight queries (Emacs, Neovim, Helix, etc.)
test/corpus/basics.txt Parser test corpus
support/adversarial-corpus-evidence.js Deterministic hostile-input parser evidence harness

Language Features Supported

  • Definition forms: def, def*, define, defstruct, defclass, defrecord, defmethod, defgeneric, defrule, defsyntax, define-enum
  • Reader syntax: [...] bracket lists, {...} method dispatch, name: keywords, #:name keywords
  • Heredoc strings: #<<DELIM\n...\nDELIM (via external C scanner)
  • Block comments: #|...|# with nesting support (via external C scanner)
  • Directives: #!/usr/bin/env scheme-script, #!chezscheme, #!r6rs
  • Quote variants: ', `, ,, ,@, #', #`, #,, #,@
  • Datum comments: #;
  • All Chez Scheme: numbers (radix, exact/inexact, rationals), characters (#\space), booleans, vectors, bytevectors

Installation in GNU Emacs (29+)

Prerequisites

Your Emacs must be compiled with tree-sitter support. Verify:

(treesit-available-p)  ;; Must return t

If it returns nil, you need an Emacs build with --with-tree-sitter. On most package managers this is the default for Emacs 29+.

You also need a C compiler (gcc or clang) available -- Emacs compiles the grammar from source.

Step 1: Install the tree-sitter grammar

Add the grammar source to Emacs and compile it:

;; In your init.el, early-init.el, or evaluate interactively:
(add-to-list 'treesit-language-source-alist
             '(jerboa
               "https://git.sr.ht/~lisp/jerboa-ts-mode"
               "6f5abe9b27b4dc23e5b150efc430a3570245e212"
               "src"))

;; Then install (only needed once, or after grammar updates):
(treesit-install-language-grammar 'jerboa)

This downloads the repo, compiles src/parser.c and src/scanner.c into a shared library, and installs it into ~/.emacs.d/tree-sitter/ (or wherever treesit-extra-load-path points).

To verify the grammar is installed:

(treesit-language-available-p 'jerboa)  ;; Should return t

Step 2: Install the Emacs mode

mkdir -p ~/src
cd ~/src
git clone https://git.sr.ht/~lisp/jerboa-ts-mode
cd jerboa-ts-mode
git checkout --detach 6f5abe9b27b4dc23e5b150efc430a3570245e212

Then in your Emacs init:

(add-to-list 'load-path "/path/to/jerboa-ts-mode")
(require 'jerboa-ts-mode)

Option B: use-package with local path

(use-package jerboa-ts-mode
  :load-path "/path/to/jerboa-ts-mode"
  :mode ("\\.ss\\'" "\\.sls\\'"))

Option C: use-package with vc (Emacs 30+)

(use-package jerboa-ts-mode
  :vc (:url "https://git.sr.ht/~lisp/jerboa-ts-mode"
       :rev "6f5abe9b27b4dc23e5b150efc430a3570245e212")
  :mode ("\\.ss\\'" "\\.sls\\'"))

Option D: straight.el

(straight-use-package
 '(jerboa-ts-mode
   :type git
   :repo "https://git.sr.ht/~lisp/jerboa-ts-mode"
   :commit "6f5abe9b27b4dc23e5b150efc430a3570245e212"))

Step 3: Verify

Open any .ss file. The mode line should show Jerboa. You should see syntax highlighting for all Jerboa forms.

If .ss files open in a different mode, ensure jerboa-ts-mode is loaded after the other mode, or explicitly set the association:

(add-to-list 'auto-mode-alist '("\\.ss\\'" . jerboa-ts-mode))
(add-to-list 'auto-mode-alist '("\\.sls\\'" . jerboa-ts-mode))

Customization

;; Change the REPL command (default: "scheme")
(setq jerboa-ts-program-name "scheme")

;; Change REPL arguments (default: ("--libdirs" "lib"))
(setq jerboa-ts-program-args '("--libdirs" "lib"))

;; Adjust font-lock level (1 = minimal, 4 = maximum)
;; Level 1: comments, strings
;; Level 2: + keywords, definitions
;; Level 3: + builtins, constants, properties
;; Level 4: + types, brackets, function calls, operators
(setq treesit-font-lock-level 4)

Updating the grammar

When a new grammar revision has been reviewed, replace the pinned commit in your Emacs configuration and local checkout. Do not switch the release install path to a mutable branch:

cd /path/to/jerboa-ts-mode
git fetch origin
git checkout --detach NEW_REVIEWED_COMMIT

Then in Emacs:

(treesit-install-language-grammar 'jerboa)  ;; Recompile

Restart Emacs or re-evaluate (require 'jerboa-ts-mode).

Integration with jerboa-emacs

jerboa-emacs is a Chez Scheme text editor that can consume the tree-sitter grammar directly for syntax highlighting of .ss and .sls buffers.

Using the compiled grammar shared library

After installing the grammar via GNU Emacs (Step 1 above), a compiled shared library exists at:

~/.emacs.d/tree-sitter/libtree-sitter-jerboa.so    # Linux
~/.emacs.d/tree-sitter/libtree-sitter-jerboa.dylib  # macOS

jerboa-emacs can load this library via its FFI to get access to the parser. The key C entry point is:

const TSLanguage *tree_sitter_jerboa(void);

Using the highlight queries

The file queries/highlights.scm contains highlight queries in the standard tree-sitter query format. jerboa-emacs can read this file at runtime:

;; In jerboa-emacs Scheme code:
(import (std text file))

(def highlights-query
  (read-file-string "/path/to/jerboa-ts-mode/queries/highlights.scm"))

Building the shared library directly (without GNU Emacs)

If you need the .so/.dylib without going through Emacs:

cd /path/to/jerboa-ts-mode

# Install the exact lock, verify the downloaded native CLI, and generate.
npm ci
make toolchain
./node_modules/tree-sitter-cli/tree-sitter generate

# Compile the shared library
cc -shared -fPIC -O2 \
   -I src \
   src/parser.c src/scanner.c \
   -o libtree-sitter-jerboa.so

Then point jerboa-emacs at the resulting libtree-sitter-jerboa.so:

;; Load via Chez FFI
(def ts-jerboa
  (load-shared-object "/path/to/jerboa-ts-mode/libtree-sitter-jerboa.so"))

Adding to jerboa-emacs LIBDIRS

If jerboa-emacs needs the grammar at build time, add to the Makefile:

TS_JERBOA = /path/to/jerboa-ts-mode

Query format reference

The highlight queries use tree-sitter's S-expression pattern syntax. Each capture maps a node type to a highlight group:

Capture Meaning Example nodes
@keyword Language keywords def, match, try, for/collect
@function Function definitions name in (def (name ...) ...)
@function.method Method definitions name in (defmethod (name ...) ...)
@function.macro Macro definitions name in (defrule (name ...) ...)
@function.builtin Prelude builtins cons, map, hash-put!
@function.call Function calls head symbol of any list
@type Type definitions name in defstruct, defclass, define-enum
@keyword.import Import/export import, export
@keyword.conditional Conditionals if, when, unless, cond
@keyword.repeat Iteration for, for/collect, for/fold
@keyword.exception Exception handling try
@keyword.directive Directives #!chezscheme, shebang
@string Strings and heredocs "hello", #<<EOF...EOF
@number Numeric literals 42, 3.14, #xff
@boolean Boolean constants #t, #f
@character Character literals #\a, #\space
@comment Comments ; ..., #|...|#, #;
@property Keywords name:, #:name
@punctuation.bracket Brackets (), [], {}
@operator Special symbols =>, ..., _, <>
@module Module names name in (module name ...)

Using with other editors

Neovim

Copy the queries directory into your Neovim tree-sitter config:

mkdir -p ~/.config/nvim/queries/jerboa
cp /path/to/jerboa-ts-mode/queries/highlights.scm ~/.config/nvim/queries/jerboa/

Then register the parser in your Neovim config (lua):

local parser_config = require("nvim-treesitter.parsers").get_parser_configs()
parser_config.jerboa = {
  install_info = {
    url = "/path/to/jerboa-ts-mode",
    files = { "src/parser.c", "src/scanner.c" },
  },
  filetype = "jerboa",
}

vim.filetype.add({
  extension = { ss = "jerboa", sls = "jerboa" },
})

Helix

mkdir -p ~/.config/helix/runtime/queries/jerboa
cp /path/to/jerboa-ts-mode/queries/highlights.scm ~/.config/helix/runtime/queries/jerboa/

Add to ~/.config/helix/languages.toml:

[[language]]
name = "jerboa"
scope = "source.jerboa"
file-types = ["ss", "sls"]
comment-token = ";;"
indent = { tab-width = 2, unit = "  " }

[language.auto-pairs]
'(' = ')'
'[' = ']'
'{' = '}'
'"' = '"'

[[grammar]]
name = "jerboa"
source = { path = "/path/to/jerboa-ts-mode" }

Development

Modifying the grammar

cd /path/to/jerboa-ts-mode

# Edit grammar.js and/or src/scanner.c

# Install and authenticate the exact development toolchain.
npm ci
make toolchain

# Regenerate the parser and run the test corpus.
make generate
make test-grammar

# Run the deterministic hostile-input corpus
make adversarial-corpus

# Record hosted/review-only release blockers
make target-evidence

# Test against a real file
./node_modules/tree-sitter-cli/tree-sitter parse /path/to/jerboa/jerbuild.ss

# Recompile for Emacs
# (in Emacs) M-x eval-expression RET (treesit-install-language-grammar 'jerboa) RET

Adding test cases

Add tests to test/corpus/basics.txt in tree-sitter's test format:

================
Test name
================

(source code here)

---

(expected S-expression tree here)

Run make test-grammar to validate with the locked executable.

Coexisting with jerboa-mode (regex-based)

The Jerboa repo also ships a regex-based jerboa-mode at /path/to/jerboa/etc/jerboa-mode.el for Emacs versions < 29 or systems without tree-sitter. Only load one:

;; Prefer tree-sitter when available, fall back to regex
(if (and (fboundp 'treesit-available-p)
         (treesit-available-p)
         (treesit-language-available-p 'jerboa))
    (progn
      (add-to-list 'load-path "/path/to/jerboa-ts-mode")
      (require 'jerboa-ts-mode))
  (add-to-list 'load-path "/path/to/jerboa/etc")
  (require 'jerboa-mode))

License

Apache-2.0. See LICENSE.