diff --git a/docs/host-interop.md b/docs/host-interop.md index 5d687dc..880e5e4 100644 --- a/docs/host-interop.md +++ b/docs/host-interop.md @@ -19,6 +19,36 @@ reflection and no class hierarchy. `(class x)` returns the JVM class name for th scalar/collection types Clojure programs compare against (`"java.lang.Long"`, `"java.lang.String"`, and so on). +## Source layering: JVM-specific code lives in the java layer + +Keep anything JVM-specific in `host/chez/java/`. The rest of the runtime stays +JVM-free, and the compiler in `jolt-core/` is JVM-free by construction. + +- `host/chez/java/` holds the JVM model: the `java.*` mirrors, the class tokens + and class hierarchy, `(class x)`/`(type x)`/`instance?`, exception classes, the + interop dispatch for `.method`/`Class/static`/`(Class.)`. If a value or name + only means something because the JVM has it, it belongs here. +- The rest of `host/chez/` is the host-neutral runtime — the value model + (`values.ss`, `collections.ss`, `seq.ss`), reader, vars, multimethods, meta. It + speaks jolt's own taxonomy (`:string`, `:vector`, `:jolt/inst`), never JVM class + names. +- `jolt-core/` (the Clojure compiler + `clojure.core` overlay) emits and reasons + in that taxonomy only. The JVM mapping happens *after*, in the java layer. + +The worked example is `type`. The core layer (`natives-meta.ss`) computes the +keyword taxonomy and binds it as `__type-tag` — that's what `print-method` and the +reader dispatch on, with no JVM in scope. The java layer (`java/host-class.ss`) +then rebinds the public `clojure.core/type` to Clojure's `(or (:type meta) (class +x))`, mapping `:jolt/inst` → `java.util.Date` and so on, right next to `(class +…)`. So the compiler keeps emitting `:jolt/inst`; the java layer remaps it. + +When you add interop behaviour, prefer registering it through the generic hooks a +java-layer file already uses — `register-class-arm!` for `(class x)`, +`register-instance-check-arm!` for `instance?`, `register-eq-arm!` for value +equality — rather than threading a JVM concept back into a host-neutral file. A +new `java.*` shim is a new file under `host/chez/java/` loaded from `rt.ss`, not a +branch added to `collections.ss` or `seq.ss`. + ## What's shimmed This is the surface today, not the whole JVM. Methods not listed generally diff --git a/host/chez/regex.ss b/host/chez/regex.ss index 4436017..f38d0b7 100644 --- a/host/chez/regex.ss +++ b/host/chez/regex.ss @@ -33,6 +33,14 @@ (apply %chez-error args))) (load "vendor/irregex/irregex.scm") +;; irregex rejects a quantifier applied to anything that already contains one — +;; including a GROUP like (a+)* — because sre-repeater? recurses through submatch. +;; Java only rejects a DANGLING double quantifier (a**); it allows a quantifier on +;; a group whose body is quantified. Restrict the check to a bare leading * / + so +;; a** still errors but (a+)* parses (cuerdas's format tokenizer needs this). +(set! sre-repeater? + (lambda (sre) (and (pair? sre) (memq (car sre) '(* +)) #t))) + ;; Unicode property classes \p{...}: irregex's string syntax has no ;; \p{...}, so translate a fixed set of property names ;; to ASCII char classes before compiling. ASCII-only — \p{L} would need @@ -92,6 +100,36 @@ (write-char c out) (loop (fx+ i 1) #f)) (else (write-char c out) (loop (fx+ i 1) in-class)))))))) +;; Inside a [...] class, irregex reads a '-' that follows a shorthand class +;; (\w \d \s \W \D \S) as the start of a range and errors ("bad char-set"); Java +;; reads it as a literal hyphen (a shorthand can't be a range endpoint). Escape +;; such a '-' to \- so the class parses. Only a '-' right after a shorthand and +;; not the class terminator is touched; a '-' after a plain char (a real range +;; like [a-z]) is left alone. +(define (escape-class-shorthand-dash src) + (let ((len (string-length src)) (out (open-output-string))) + (let loop ((i 0) (in-class #f) (after-shorthand #f)) + (if (fx>=? i len) + (get-output-string out) + (let ((c (string-ref src i))) + (cond + ;; an escape pair: \w-style shorthand sets after-shorthand inside a class + ((and (char=? c #\\) (fx