Add prelude, fix sugar macros, add README

ober

a71e472f159a666f17f6d3bb3876bafdd281ecbe

diff --git a/README.md b/README.md
index 5374fe0..e25b21a 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,172 @@
-# jerboa
+# Jerboa
+
+Gerbil Scheme's syntax and APIs, running on stock Chez Scheme.
+
+Jerboa implements Gerbil's user-facing language — `def`, `defstruct`, `match`, hash tables, `:std/*` libraries — as Chez Scheme macros and native libraries. No Gerbil expander, no Gambit compatibility layer, no patched Chez.
+
+## Quick Start
+
+```scheme
+(import (jerboa prelude))
+
+(def (main)
+  (defstruct point (x y))
+  (let ([p (make-point 3 4)])
+    (displayln (point-x p))           ;; 3
+    (displayln (sort [5 1 3] <))      ;; (1 3 5)
+    (displayln (string-join ["a" "b"] ","))  ;; a,b
+    (displayln (json-object->string [1 2 3]))))  ;; [1,2,3]
+
+(main)
+```
+
+Run with:
+```bash
+scheme --libdirs lib --script your-file.ss
+```
+
+## Architecture
+
+```
+┌──────────────────────────────────────────────┐
+│            User's Gerbil-like code           │
+│  (def (main) (displayln (sort [3 1 2] <)))  │
+└──────────────┬───────────────────────────────┘
+               │
+┌──────────────▼───────────────────────────────┐
+│  Reader: [...] → (list ...), {...} → (~ ..)  │
+│  :std/sort → (std sort) module paths         │
+├──────────────────────────────────────────────┤
+│  Core Macros: def, defstruct, match, try     │
+│  All expand to standard Chez Scheme          │
+├──────────────────────────────────────────────┤
+│  Runtime: hash tables, method dispatch       │
+├──────────────────────────────────────────────┤
+│  Standard Library: sort, JSON, paths, etc.   │
+├──────────────────────────────────────────────┤
+│  FFI: c-lambda → foreign-procedure           │
+├──────────────────────────────────────────────┤
+│  Stock Chez Scheme — no fork, no patches     │
+└──────────────────────────────────────────────┘
+```
+
+## What's Included
+
+### Core Macros (`(jerboa core)`)
+- `def` — functions with optional args, rest args
+- `def*` — case-lambda shorthand
+- `defstruct` — native Chez records with auto-generated accessors
+- `defclass` — records with inheritance
+- `defmethod` — method dispatch via `bind-method!`
+- `match` — pattern matching (lists, predicates, `and`/`or`/`not`, cons, wildcards)
+- `try`/`catch`/`finally` — exception handling
+- `defrule`/`defrules` — syntax-rules shortcuts
+- `while`/`until` — loop macros
+- `hash-literal`/`let-hash` — hash table construction and destructuring
+
+### Runtime (`(jerboa runtime)`)
+- Full Gerbil hash table API: `hash-ref`, `hash-put!`, `hash-get`, `hash-keys`, etc.
+- Method dispatch: `~`, `bind-method!`, `call-method`
+- Keywords: `string->keyword`, `keyword?`, `keyword->string`
+- Utilities: `displayln`, `iota`, `1+`, `1-`
+
+### Standard Library
+| Module | Provides |
+|--------|----------|
+| `(std sort)` | `sort`, `stable-sort` |
+| `(std format)` | `printf`, `fprintf`, `eprintf` |
+| `(std error)` | `Error`, `ContractViolation` |
+| `(std sugar)` | `chain`, `chain-and`, `assert!` |
+| `(std text json)` | `read-json`, `write-json`, `string->json-object`, `json-object->string` |
+| `(std os path)` | `path-join`, `path-directory`, `path-extension`, etc. |
+| `(std misc string)` | `string-split`, `string-join`, `string-trim`, `string-contains`, etc. |
+| `(std misc list)` | `flatten`, `unique`, `take`, `drop`, `every`, `any`, `filter-map`, `zip` |
+| `(std misc alist)` | `agetq`, `pgetq`, `alist->hash-table` |
+| `(std misc ports)` | `read-file-string`, `with-output-to-string`, etc. |
+| `(std misc channel)` | Thread-safe channels (Chez mutex/condvar) |
+
+### FFI (`(jerboa ffi)`)
+- `c-lambda` → `foreign-procedure` with automatic type translation
+- `define-c-lambda` — named FFI bindings
+- `begin-ffi`, `c-declare` — compatibility forms
+- Full Gambit-to-Chez type mapping
+
+### Reader (`(jerboa reader)`)
+- `[1 2 3]` → `(list 1 2 3)`
+- `{method obj}` → `(~ obj 'method)`
+- `keyword:` → keyword objects
+- `:std/sort` → `(std sort)` module paths
+- Heredoc strings, datum comments, block comments
+
+### Prelude (`(jerboa prelude)`)
+One import for everything:
+```scheme
+(import (jerboa prelude))
+```
+
+## Testing
+
+```bash
+make test
+```
+
+Runs 213 tests across reader, core macros, runtime, standard library, FFI, and module path mapping.
+
+## Requirements
+
+- [Chez Scheme](https://cisco.github.io/ChezScheme/) 10.x (stock, unmodified)
+
+## Project Structure
+
+```
+lib/
+  jerboa/
+    reader.sls      # Gerbil-compatible reader
+    core.sls         # Core syntax macros
+    runtime.sls      # Hash tables, method dispatch, keywords
+    ffi.sls          # FFI translation macros
+    prelude.sls      # All-in-one import
+  std/
+    sort.sls         # :std/sort
+    format.sls       # :std/format
+    error.sls        # :std/error
+    sugar.sls        # :std/sugar
+    text/json.sls    # :std/text/json
+    os/path.sls      # :std/os/path
+    misc/
+      string.sls     # :std/misc/string
+      list.sls        # :std/misc/list
+      alist.sls       # :std/misc/alist
+      ports.sls        # :std/misc/ports
+      channel.sls      # :std/misc/channel
+tests/
+  test-reader.ss     # 65 reader tests
+  test-core.ss       # 68 core macro tests
+  test-stdlib.ss     # 65 stdlib tests
+  test-ffi.ss        # 7 FFI tests
+  test-modules.ss    # 8 module path tests
+```
+
+## What Gerbil Code Works
+
+Most user-level Gerbil code works unchanged:
+
+```scheme
+(import :std/sugar :std/sort :std/format)
+
+(def (run-command cmd env)
+  (try
+    (let* ([tokens (tokenize cmd)]
+           [expanded (expand-aliases tokens env)])
+      (match expanded
+        ([prog . args] (exec-pipeline prog args env))
+        (else (displayln "empty command"))))
+    (catch (e) (displayln "error: " (error-message e)))))
+```
+
+## What Won't Work
+
+1. **Gerbil expander API** (`:gerbil/expander`) — not applicable
+2. **Gambit `##` primitives** — provide needed ones case-by-case
+3. **`(export #t)`** — re-export-everything needs explicit exports
+4. **Gerbil-specific `syntax-case` binding semantics** — uses Chez R6RS semantics
diff --git a/lib/jerboa/prelude.sls b/lib/jerboa/prelude.sls
new file mode 100644
index 0000000..1453c82
--- /dev/null
+++ b/lib/jerboa/prelude.sls
@@ -0,0 +1,114 @@
+#!chezscheme
+;;; jerboa/prelude -- One-import-to-rule-them-all
+;;;
+;;; (import (jerboa prelude)) gives you all of Gerbil's user-facing API:
+;;; - Core macros: def, defstruct, defmethod, match, try/catch, etc.
+;;; - Runtime: hash tables, method dispatch, keywords
+;;; - Standard library: sort, format, JSON, paths, strings, lists, etc.
+;;; - FFI: c-lambda, define-c-lambda
+
+(library (jerboa prelude)
+  (export
+    ;; ---- Core macros ----
+    def def* defrule defrules
+    defstruct defclass defmethod
+    match
+    try catch finally
+    while until
+
+    ;; hash constructors
+    hash-literal hash-eq-literal
+    let-hash
+
+    ;; ---- Runtime ----
+    ~ bind-method! call-method
+    make-hash-table make-hash-table-eq
+    hash-ref hash-get hash-put! hash-update! hash-remove!
+    hash-key? hash->list hash->plist hash-for-each hash-map hash-fold
+    hash-find hash-keys hash-values hash-copy hash-clear!
+    hash-merge hash-merge! hash-length hash-table?
+    list->hash-table plist->hash-table
+    keyword? keyword->string string->keyword make-keyword
+    error-message error-irritants error-trace
+    displayln 1+ 1-
+    iota last-pair
+    *method-tables*
+    register-struct-type! *struct-types*
+    struct-predicate struct-field-ref struct-field-set!
+    struct-type-info
+
+    ;; ---- std/sort ----
+    sort sort! stable-sort stable-sort!
+
+    ;; ---- std/format ----
+    format printf fprintf eprintf
+
+    ;; ---- std/error ----
+    Error ContractViolation
+
+    ;; ---- std/sugar ----
+    chain chain-and assert!
+
+    ;; ---- std/text/json ----
+    read-json write-json json-object->string string->json-object
+
+    ;; ---- std/os/path ----
+    path-expand path-normalize path-directory path-strip-directory
+    path-extension path-strip-extension
+    path-join path-absolute?
+
+    ;; ---- std/misc/string ----
+    string-split string-join string-trim
+    string-prefix? string-suffix?
+    string-contains string-index
+    string-empty?
+
+    ;; ---- std/misc/list ----
+    flatten unique snoc
+    take drop
+    every any
+    filter-map
+    group-by
+    zip
+
+    ;; ---- std/misc/alist ----
+    agetq agetv aget
+    asetq! asetv! aset!
+    pgetq pgetv pget
+    alist->hash-table
+
+    ;; ---- std/misc/ports ----
+    read-all-as-string read-all-as-lines
+    read-file-string read-file-lines
+    write-file-string
+    with-input-from-string with-output-to-string
+
+    ;; ---- FFI ----
+    c-lambda define-c-lambda
+    begin-ffi c-declare)
+
+  (import
+    (except (chezscheme)
+            make-hash-table hash-table?
+            sort sort!
+            printf fprintf
+            path-extension path-absolute?
+            with-input-from-string with-output-to-string
+            iota 1+ 1-)
+    (jerboa core)
+    (jerboa ffi)
+    (std sort)
+    (std format)
+    (except (std error) error-message error-irritants error-trace error?
+                       with-exception-handler)
+    (except (std sugar) try catch finally while until
+                       hash-literal hash-eq-literal let-hash
+                       defrule defrules)
+    (std text json)
+    (std os path)
+    (std misc string)
+    (std misc list)
+    (std misc alist)
+    (std misc ports))
+
+  ) ;; end library
diff --git a/lib/std/sugar.sls b/lib/std/sugar.sls
index b259381..710b3bc 100644
--- a/lib/std/sugar.sls
+++ b/lib/std/sugar.sls
@@ -28,17 +28,22 @@
 
   (define-syntax chain-apply
     (lambda (stx)
-      (syntax-case stx (_)
+      (syntax-case stx ()
         [(_ f val) #'(f val)]
-        [(_ f val _ arg ...) #'(f val arg ...)]
+        [(_ f val placeholder arg ...)
+         (and (identifier? #'placeholder) (eq? (syntax->datum #'placeholder) '_))
+         #'(f val arg ...)]
         [(_ f val arg1 rest ...)
          #'(chain-apply-tail f val (arg1) rest ...)])))
 
   (define-syntax chain-apply-tail
     (lambda (stx)
-      (syntax-case stx (_)
-        [(_ f val (args ...) _) #'(f args ... val)]
-        [(_ f val (args ...) _ rest ...)
+      (syntax-case stx ()
+        [(_ f val (args ...) placeholder)
+         (and (identifier? #'placeholder) (eq? (syntax->datum #'placeholder) '_))
+         #'(f args ... val)]
+        [(_ f val (args ...) placeholder rest ...)
+         (and (identifier? #'placeholder) (eq? (syntax->datum #'placeholder) '_))
          #'(chain-apply-tail f val (args ... val) rest ...)]
         [(_ f val (args ...) arg rest ...)
          #'(chain-apply-tail f val (args ... arg) rest ...)]