Thanks to visit codestin.com
Credit goes to lib.rs

2 releases

Uses new Rust 2024

0.1.1 Jan 29, 2026
0.1.0 Jan 29, 2026

#317 in Memory management


Used in pwn_arena_embedded

MIT/Apache

58KB
812 lines

Grift

Crates.io Documentation License

A minimal no_std, no_alloc Scheme implementation built on a custom arena allocator. Grift demonstrates that you can build a feature-rich, garbage-collected language without requiring heap allocation — perfect for embedded systems, WebAssembly, or environments where std is unavailable.

📦 Installation

# Install the REPL
cargo install grift --features std

# Or add to your Cargo.toml for library use (no_std by default)
[dependencies]
grift = "1.2"

🚀 Quick Start

As a Library (no_std)

use grift::{Lisp, Evaluator, Value};

// Create an interpreter with a 10,000-cell arena
let lisp: Lisp<10000> = Lisp::new();
let mut eval = Evaluator::new(&lisp).unwrap();

// Evaluate expressions
let result = eval.eval_str("(+ 1 2 3)").unwrap();

Interactive REPL

# Run directly
cargo run -p grift --features std

# Or after installing
grift
Grift Lisp
> (define (factorial n)
    (if (= n 0) 1
        (* n (factorial (- n 1)))))
> (factorial 10)
3628800

> (map (lambda (x) (* x x)) '(1 2 3 4 5))
(1 4 9 16 25)

> (arena-stats)
(50000 127 49873 0)  ; (capacity allocated free usage%)

🎯 Project Overview

This repository contains:

Crate Description no_std
grift Unified re-export crate (primary entry point) ✅ default
grift_arena Arena allocator with mark-and-sweep GC
grift_parser Lisp parser with symbol interning
grift_eval Trampolined evaluator with proper TCO
grift_repl Interactive REPL ❌ (uses std)
grift_macros Proc macros for stdlib generation N/A
grift_arena_embedded Hardware access for embedded targets

✨ Lisp Features

Core Language

Feature Description
Proper Tail Calls Full TCO via trampolining — no stack overflow on deep recursion
Strict Evaluation Call-by-value semantics; arguments evaluated before function application
Lexical Closures First-class functions with captured environments
Quasiquote quasiquote/unquote for template-based code generation
Pattern Matching case for value matching, cond for conditionals
Mutation set!, set-car!, set-cdr! for imperative programming
Garbage Collection Mark-and-sweep GC controllable from Lisp code

Built-in Functions

; List operations
(car '(1 2 3))         ; => 1
(cdr '(1 2 3))         ; => (2 3)
(cons 1 '(2 3))        ; => (1 2 3)
(list 1 2 3)           ; => (1 2 3)

; Predicates
(null? '())            ; => #t
(pair? '(1 . 2))       ; => #t
(number? 42)           ; => #t
(symbol? 'foo)         ; => #t
(procedure? car)       ; => #t

; Arithmetic
(+ 1 2 3 4)            ; => 10
(- 10 3)               ; => 7
(* 2 3 4)              ; => 24
(/ 100 5)              ; => 20
(modulo 17 5)          ; => 2

; Comparison
(< 1 2)                ; => #t
(= 5 5)                ; => #t
(eq? 'a 'a)            ; => #t

; Memory management
(gc)                   ; => (marked collected before)
(gc-enable)            ; Enable automatic GC
(gc-disable)           ; Disable automatic GC
(gc-enabled?)          ; => #t or #f
(arena-stats)          ; => (capacity allocated free usage%)

; Vectors (R7RS Section 6.8)
(define vec (vector 1 2 3))    ; Create vector with elements
(vector-ref vec 1)             ; => 2 (get element at index 1)
(vector-set! vec 1 42)         ; Set element at index 1
(vector-length vec)            ; => 3
(vector? vec)                  ; => #t
#(1 2 3)                       ; Vector literal syntax
(make-vector 5 0)              ; Create vector of 5 zeros

Special Forms

; Conditionals
(if condition then-expr else-expr)
(cond (test1 result1) (test2 result2) (else default))
(case key ((datum1) result1) ((datum2 datum3) result2) (else default))

; Definitions
(define x 42)
(define (square x) (* x x))

; Local bindings
(let ((x 1) (y 2)) (+ x y))
(let* ((x 1) (y (+ x 1))) y)

; Sequences
(begin expr1 expr2 ... exprN)

; Short-circuit boolean
(and expr1 expr2 ...)
(or expr1 expr2 ...)

; Iteration
(do ((i 0 (+ i 1)) (sum 0 (+ sum i)))
    ((= i 10) sum))

; Template-based code generation
(quasiquote (a b (unquote x)))  ; With x=5 => (a b 5)

; Runtime evaluation
(eval '(+ 1 2))        ; => 3
(apply + '(1 2 3))     ; => 6

🔥 Design Philosophy

1. No Heap, No Problem

The entire Lisp runs on a fixed-size arena allocated at compile time. No malloc, no Box, no Vec in the core. This makes it:

  • Predictable — Memory usage is bounded and known upfront
  • Portable — Works on bare metal, WASM, or any no_std target
  • Safe — No undefined behavior from memory allocation failures

2. Strict Evaluation with TCO

All arguments are evaluated before function application (call-by-value), with full tail-call optimization:

; Arguments evaluated before function call
(define (add x y) (+ x y))
(add (+ 1 2) (* 3 4))  ; => 15 (both args evaluated first)

; Side effects happen immediately
(define count 0)
(cons (begin (set! count 1) 'a) '())
count  ; => 1 (side effect happened during cons)

; Tail-call optimization works for deep recursion
(define (sum n acc)
  (if (= n 0) acc
      (sum (- n 1) (+ acc n))))  ; Args evaluated before call
(sum 10000 0)                    ; => 50005000 (no stack overflow)

3. Only #f is False

Unlike many Lisps, we follow Scheme's truthiness model:

(if nil 'yes 'no)     ; => yes (nil is truthy!)
(if '() 'yes 'no)     ; => yes (empty list is truthy!)
(if 0 'yes 'no)       ; => yes (zero is truthy!)
(if #f 'yes 'no)      ; => no  (only #f is false)

📊 Memory Management from Lisp

Control the garbage collector directly from your Lisp code:

; Check arena status
(arena-stats)          ; => (50000 234 49766 0)
                       ;     ^ capacity
                       ;           ^ allocated
                       ;               ^ free
                       ;                     ^ usage%

; Manual GC control
(gc-disable)           ; Pause GC for performance-critical section
; ... allocate many objects ...
(gc-enable)
(gc)                   ; Force collection now
                       ; => (marked collected before)

🏗️ Architecture

See the detailed architecture documents:

📚 Standard Library

The standard library is defined as static Lisp code, parsed on-demand:

; List manipulation
(length '(a b c))      ; => 3
(append '(1 2) '(3 4)) ; => (1 2 3 4)
(reverse '(1 2 3))     ; => (3 2 1)
(nth 2 '(a b c d))     ; => c

; Higher-order functions
(map (lambda (x) (* x x)) '(1 2 3 4))  ; => (1 4 9 16)
(filter (lambda (x) (> x 0)) '(-1 2 -3 4))  ; => (2 4)
(fold + 0 '(1 2 3 4 5))  ; => 15

; List generation
(range 0 5)            ; => (0 1 2 3 4)
(take 3 '(a b c d e))  ; => (a b c)

; Utilities
(identity 42)          ; => 42
(constantly 5)         ; Returns a function that always returns 5

⚠️ Gotchas and Pitfalls

Nil is NOT False!

; WRONG: Don't use nil/empty list as a false value
(if (filter (lambda (x) (> x 10)) '(1 2 3)) 'has-items 'empty)
; If filter finds nothing, it returns '() (nil), which is TRUTHY!
; This will always print 'has-items even when the list is empty!

; RIGHT: Explicitly check for #f or use null?
(if (null? (filter (lambda (x) (> x 10)) '(1 2 3))) 'empty 'has-items)
; Now it correctly checks if the result is empty

; Note: member returns #f (not nil) when not found, so this works:
(if (member 'x '(a b c)) 'found 'not-found)  ; This is correct!

Arena Capacity is Fixed

; If you run out of arena space, you get an error
; Solution: Use a larger arena or trigger GC more often
(gc)  ; Reclaim unreachable objects

🔧 Project Structure

grift/
├── crates/
│   ├── grift/           # Unified re-export crate (primary entry point)
│   ├── grift_arena/     # Core arena allocator (no_std, no_alloc)
│   ├── grift_parser/    # Lisp parser and value types (no_std)
│   ├── grift_eval/      # Trampolined evaluator (no_std)
│   ├── grift_repl/      # Interactive REPL (uses std for I/O)
│   ├── grift_macros/    # Proc macros for stdlib generation
│   └── grift_arena_embedded/  # Hardware access for embedded targets
├── docs/
│   ├── ARENA_ARCHITECTURE.md
│   ├── LISP_ARCHITECTURE.md
│   └── SCHEME_R7RS_CONFORMANCE.md
└── README.md

🛠️ Development

# Build all crates
cargo build --workspace

# Run tests
cargo test --workspace

# Run the REPL in development
cargo run -p grift --features std

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

📄 License

Licensed under either of:

at your option.

No runtime deps