Protocol/interop fixes to run metosin/malli (jolt-ltwk) (#105)
* Protocol/interop fixes to run metosin/malli Bringing up malli (schema validation) surfaced a batch of protocol and host-interop gaps. m/validate now works across the schema vocabulary (predicates, :map incl. nested/optional, :vector, :tuple, :enum, :maybe, :and, bounded int/string). - extend-type and reify now accept MULTIPLE protocols in one form (each bare symbol switches the current protocol). reify records every protocol it implements, so instance?/satisfies? recognise all of them. - Protocol method params support destructuring: reify/extend-type/deftype/ defrecord emit (fn ...) (which desugars patterns) instead of raw fn*. - instance? of a PROTOCOL works like satisfies? for reify/record instances, matching short names across qualified/bare protocol references. - @x reads as the qualified clojure.core/deref, so it still derefs where a ns excludes and rebinds deref (malli does). Updated reader-test + the reader spec/grammar (S11, deref rule). - Java collection interop on jolt collections: .nth/.count/.valAt/.get/.seq/ .containsKey route to the clojure.core equivalent (1-arg and 0-arg paths). - java.util.HashMap capacity/load-factor constructors + .putAll. - A class used as a value resolves to its instances' type, so Pattern -> the regex type (malli keys class-schemas by it). - Shims for malli's load path: LazilyPersistentVector/createOwning and PersistentArrayMap/createWithCheck statics. m/explain not yet working (jolt-fjb1). Full gate green. * satisfies? recognizes reify, consistent with instance? A reify's protocol methods are instance-local, so they aren't in the global type registry that type-satisfies? consults — satisfies? returned false for a reify even when it implemented the protocol. Check the protocols the reify records on itself (the same :jolt/protocols list instance? uses), matching short names like instance? does. Covers single- and multi-protocol reify. --------- Co-authored-by: Yogthos <yogthos@gmail.com>
This commit is contained in:
parent
d1f73f1740
commit
910c4b6c99
9 changed files with 149 additions and 33 deletions
|
|
@ -109,7 +109,7 @@ map-entry = form , ws , form ; (* an even number of forms *)
|
|||
|
||||
(* --------------------------------------------------------------------------
|
||||
Reader macros (prefix sugar). Each expands to a 2-element form
|
||||
(op operand), e.g. 'x -> (quote x), @a -> (deref a).
|
||||
(op operand), e.g. 'x -> (quote x), @a -> (clojure.core/deref a).
|
||||
-------------------------------------------------------------------------- *)
|
||||
|
||||
reader-macro = quote | syntax-quote | unquote | unquote-splice
|
||||
|
|
@ -119,7 +119,8 @@ quote = "'" , form ; (* (quote form) *)
|
|||
syntax-quote = "`" , form ; (* (syntax-quote form) *)
|
||||
unquote-splice = "~@" , form ; (* (unquote-splicing form) *)
|
||||
unquote = "~" , form ; (* (unquote form) *)
|
||||
deref = "@" , form ; (* (deref form) *)
|
||||
deref = "@" , form ; (* (clojure.core/deref form) — qualified, *)
|
||||
(* so it derefs even where deref is shadowed *)
|
||||
metadata = "^" , meta-form , ws , form ; (* attach metadata to form *)
|
||||
meta-form = map | keyword | symbol | string ;
|
||||
(* Normalized like Clojure: a symbol or string is a type hint -> {:tag ...};
|
||||
|
|
|
|||
|
|
@ -74,12 +74,16 @@ checks → UNVERIFIED (rows to add).
|
|||
| Sugar | Reads as | |
|
||||
|---|---|---|
|
||||
| `'form` | `(quote form)` | S10 |
|
||||
| `@form` | `(deref form)` | S11 |
|
||||
| `@form` | `(clojure.core/deref form)` | S11 |
|
||||
| `^meta form` | form with metadata attached (see below) | S12 |
|
||||
| `#'sym` | `(var sym)` | S13 |
|
||||
| `` `form `` | syntax-quote (§2.4) | |
|
||||
| `~form`, `~@form` | unquote / unquote-splicing — only within syntax-quote (S14: MUST error outside) | |
|
||||
|
||||
- S11. `@form` reads as `(clojure.core/deref form)` — the operator is the
|
||||
fully-qualified `clojure.core/deref`, not a bare `deref`, so `@x` still
|
||||
dereferences in a namespace that excludes and rebinds `deref`
|
||||
(`(ns … (:refer-clojure :exclude [deref]))`), matching Clojure.
|
||||
- S12a. `^:kw form` ≡ `^{:kw true} form`; `^Sym form` ≡ `^{:tag Sym} form`;
|
||||
`^"str"` ≡ `^{:tag "str"} form`. Multiple `^` stack, rightmost innermost,
|
||||
merged left-over-right.
|
||||
|
|
@ -117,6 +121,10 @@ checks → UNVERIFIED (rows to add).
|
|||
- `#(body)` reads as `(fn [args…] (body))` with parameters derived from the
|
||||
`%`-symbols appearing in body: `%`≡`%1`, `%n` positional, `%&` the rest
|
||||
parameter. Arity = highest `%n` mentioned (plus rest if `%&`).
|
||||
- The `%`-symbols are collected from the WHOLE body, recursing through every
|
||||
nested form including vector, map and set literals — `#(assoc {} :k %)`,
|
||||
`#(hash-set % %2)` and `#(get {:t %} :t)` all see their `%`s. (A reader that
|
||||
scanned only call forms would miscompile `#(identity {:text %})` as a 0-arg fn.)
|
||||
- `#()` literals MUST NOT nest.
|
||||
|
||||
```clojure
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue