|
97 | 97 | (-distribute-to-children [this f options])) |
98 | 98 |
|
99 | 99 | (defprotocol ParserInfo |
100 | | - (-parser-info [this])) |
| 100 | + (-parser-info [this opts])) |
101 | 101 |
|
102 | 102 | (defn -ref-schema? [x] (#?(:clj instance?, :cljs implements?) malli.core.RefSchema x)) |
103 | 103 | (defn -entry-parser? [x] (#?(:clj instance?, :cljs implements?) malli.core.EntryParser x)) |
|
119 | 119 | (throw (ex-info "Not distributive" {:schema this}))) |
120 | 120 |
|
121 | 121 | ParserInfo |
122 | | - (-parser-info [this] |
| 122 | + (-parser-info [this opts] |
123 | 123 | (when (-ref-schema? this) |
124 | | - (-parser-info (-deref this)))) |
| 124 | + (-parser-info (-deref this) opts))) |
125 | 125 |
|
126 | 126 | RegexSchema |
127 | 127 | (-regex-op? [_] false) |
|
344 | 344 |
|
345 | 345 | (defn -create-cache [_options] (atom {})) |
346 | 346 |
|
| 347 | +(defn -lookup-or-update-cache [c k f] |
| 348 | + (or (@c k) |
| 349 | + (let [r (f)] |
| 350 | + (swap! c assoc k r) |
| 351 | + r))) |
| 352 | + |
347 | 353 | (defn -cached [s k f] |
348 | 354 | (if (-cached? s) |
| 355 | + ;; inlined (-lookup-or-update-cache (-cache s) k #(f s)) to avoid extra thunk |
349 | 356 | (let [c (-cache s)] |
350 | | - (or (@c k) ((swap! c assoc k (f s)) k))) |
| 357 | + (or (@c k) |
| 358 | + (let [r (f s)] |
| 359 | + (swap! c assoc k r) |
| 360 | + r))) |
351 | 361 | (f s))) |
352 | 362 |
|
353 | 363 | ;; |
|
787 | 797 | (-get [_ _ default] default) |
788 | 798 | (-set [this key _] (-fail! ::non-associative-schema {:schema this, :key key})) |
789 | 799 | ParserInfo |
790 | | - (-parser-info [_] {:simple-parser true}) |
| 800 | + (-parser-info [_ _] {:simple-parser true}) |
791 | 801 | #?@(:cljs [IPrintWithWriter (-pr-writer [this writer opts] (pr-writer-schema this writer opts))]))))) |
792 | 802 | #?@(:cljs [IPrintWithWriter (-pr-writer [this writer opts] (pr-writer-into-schema this writer opts))]))))) |
793 | 803 |
|
|
817 | 827 | (let [children (-vmap #(schema % options) children) |
818 | 828 | form (delay (-simple-form parent properties children -form options)) |
819 | 829 | cache (-create-cache options) |
820 | | - transforming-parser (delay |
821 | | - (let [transforming-parsers (or (when-some [[_ i] (find properties :parse/transforming-child)] |
822 | | - (cond |
823 | | - (= :none i) [] |
824 | | - (and (nat-int? i) (< i (count children))) [i] |
825 | | - :else (-fail! ::and-schema-invalid-parse-property {:schema @form}))) |
826 | | - (into [] |
827 | | - (keep-indexed |
828 | | - (fn [i c] |
829 | | - (when-not (-> c -parser-info :simple-parser) |
830 | | - i))) |
831 | | - children))] |
832 | | - (when (next transforming-parsers) |
833 | | - (-fail! ::and-schema-multiple-transforming-parsers {:schema @form})) |
834 | | - (peek transforming-parsers))) |
835 | | - ->parsers (fn [f] (into [] (map-indexed (fn [i c] (if (= @transforming-parser i) (f c) (-simple-parser c)))) children))] |
| 830 | + ->transforming-parser-idx (fn [opts] |
| 831 | + (let [transforming-parsers (or (when-some [[_ i] (find properties :parse/transforming-child)] |
| 832 | + (cond |
| 833 | + (= :none i) [] |
| 834 | + (and (nat-int? i) (< i (count children))) [i] |
| 835 | + :else (-fail! ::and-schema-invalid-parse-property {:schema @form}))) |
| 836 | + (into [] |
| 837 | + (keep-indexed |
| 838 | + (fn [i c] |
| 839 | + (when-not (-> c (-parser-info opts) :simple-parser) |
| 840 | + i))) |
| 841 | + children))] |
| 842 | + (when (next transforming-parsers) |
| 843 | + (-fail! ::and-schema-multiple-transforming-parsers {:schema @form})) |
| 844 | + (peek transforming-parsers))) |
| 845 | + cached-transforming-parser-idx (delay (-lookup-or-update-cache cache ::transforming-parser-idx #(->transforming-parser-idx nil))) |
| 846 | + ->parsers (fn [f] |
| 847 | + (let [transforming-parser-idx @cached-transforming-parser-idx] |
| 848 | + (into [] (map-indexed |
| 849 | + (fn [i c] |
| 850 | + (if (= i transforming-parser-idx) |
| 851 | + (f c) |
| 852 | + (-simple-parser c)))) |
| 853 | + children)))] |
836 | 854 | ^{:type ::schema} |
837 | 855 | (reify |
838 | 856 | Schema |
|
843 | 861 | (fn explain [x in acc] (reduce (fn [acc' explainer] (explainer x in acc')) acc explainers)))) |
844 | 862 | (-parser [this] |
845 | 863 | ;; non-iteratively parse x left-to-right. return result of transforming parser, or x. |
846 | | - (let [pi @transforming-parser |
| 864 | + (let [pi @cached-transforming-parser-idx |
847 | 865 | parsers (->parsers -parser) |
848 | 866 | nchildren (count children)] |
849 | 867 | (fn [x] |
|
858 | 876 | (-unparser [this] |
859 | 877 | ;; unparse x' with transforming parser (if any), then non-iteratively unparse x with remaining parsers, left-to-right |
860 | 878 | ;; return x if all results are equal. |
861 | | - (let [pi @transforming-parser |
| 879 | + (let [pi @cached-transforming-parser-idx |
862 | 880 | unparsers (->parsers -unparser) |
863 | 881 | unparser (get unparsers pi identity) |
864 | 882 | nchildren (count children)] |
|
887 | 905 | (-get [_ key default] (get children key default)) |
888 | 906 | (-set [this key value] (-set-assoc-children this key value)) |
889 | 907 | ParserInfo |
890 | | - (-parser-info [_] (if-some [i @transforming-parser] |
891 | | - (-parser-info (nth children i)) |
892 | | - {:simple-parser true})) |
| 908 | + (-parser-info [_ opts] (if-some [i (->transforming-parser-idx opts)] |
| 909 | + (-parser-info (nth children i) opts) |
| 910 | + {:simple-parser true})) |
893 | 911 | #?@(:cljs [IPrintWithWriter (-pr-writer [this writer opts] (pr-writer-schema this writer opts))])))) |
894 | 912 | #?@(:cljs [IPrintWithWriter (-pr-writer [this writer opts] (pr-writer-into-schema this writer opts))]))) |
895 | 913 |
|
|
1012 | 1030 | (-get [_ key default] (get children key default)) |
1013 | 1031 | (-set [this key value] (-set-assoc-children this key value)) |
1014 | 1032 | ParserInfo |
1015 | | - (-parser-info [_] {:simple-parser (every? (-comp :simple-parser -parser-info) children)}) |
| 1033 | + (-parser-info [_ opts] {:simple-parser (every? (-comp :simple-parser #(-parser-info % opts)) children)}) |
1016 | 1034 | #?@(:cljs [IPrintWithWriter (-pr-writer [this writer opts] (pr-writer-schema this writer opts))])))) |
1017 | 1035 | #?@(:cljs [IPrintWithWriter (-pr-writer [this writer opts] (pr-writer-into-schema this writer opts))]))) |
1018 | 1036 |
|
|
1121 | 1139 | (-get [_ key default] (get children key default)) |
1122 | 1140 | (-set [this key value] (-set-assoc-children this key value)) |
1123 | 1141 | ParserInfo |
1124 | | - (-parser-info [_] {:simple-parser true}) |
| 1142 | + (-parser-info [_ _] {:simple-parser true}) |
1125 | 1143 | #?@(:cljs [IPrintWithWriter (-pr-writer [this writer opts] (pr-writer-schema this writer opts))])))) |
1126 | 1144 | #?@(:cljs [IPrintWithWriter (-pr-writer [this writer opts] (pr-writer-into-schema this writer opts))]))) |
1127 | 1145 |
|
|
1197 | 1215 | cache (-create-cache options) |
1198 | 1216 | default-schema (delay (some-> entry-parser (-entry-children) (-default-entry-schema) (schema options))) |
1199 | 1217 | explicit-children (delay (cond->> (-entry-children entry-parser) @default-schema (remove -default-entry))) |
| 1218 | + simple-default-parser? (fn [opts] (-> @default-schema (-parser-info opts) :simple-parser boolean)) |
1200 | 1219 | ->parser (fn [this f] |
1201 | 1220 | (let [keyset (-entry-keyset (-entry-parser this)) |
1202 | 1221 | default-parser (some-> @default-schema (f)) |
|
1215 | 1234 | (if optional m (reduced ::invalid)))))) |
1216 | 1235 | @explicit-children) |
1217 | 1236 | default-parser |
1218 | | - (cons (let [simple (-> @default-schema -parser-info :simple-parser boolean)] |
| 1237 | + (cons (let [simple (-lookup-or-update-cache cache ::simple-default-parser? #(simple-default-parser? nil))] |
1219 | 1238 | (fn [m] |
1220 | 1239 | (let [m' (default-parser |
1221 | 1240 | (reduce (fn [acc k] (dissoc acc k)) m (keys keyset)))] |
|
1319 | 1338 | (-get [this key default] (-get-entries this key default)) |
1320 | 1339 | (-set [this key value] (-set-entries this key value)) |
1321 | 1340 | ParserInfo |
1322 | | - (-parser-info [_] {:simple-parser (every? (-comp :simple-parser -parser-info peek) (-entry-children entry-parser))}) |
| 1341 | + (-parser-info [_ opts] {:simple-parser (every? #(-> % peek (-parser-info opts) :simple-parser) (-entry-children entry-parser))}) |
1323 | 1342 | #?@(:cljs [IPrintWithWriter (-pr-writer [this writer opts] (pr-writer-schema this writer opts))])))) |
1324 | 1343 | #?@(:cljs [IPrintWithWriter (-pr-writer [this writer opts] (pr-writer-into-schema this writer opts))])))) |
1325 | 1344 |
|
|
1343 | 1362 | form (delay (-simple-form parent properties children -form options)) |
1344 | 1363 | cache (-create-cache options) |
1345 | 1364 | validate-limits (-validate-limits min max) |
1346 | | - simple-parser (delay (every? (-comp :simple-parser -parser-info) children)) |
| 1365 | + simple-parser? (fn [opts] (every? (-comp :simple-parser #(-parser-info % opts)) children)) |
1347 | 1366 | ->parser (fn [f] (let [key-parser (f key-schema) |
1348 | 1367 | value-parser (f value-schema) |
1349 | | - simple @simple-parser] |
| 1368 | + simple (-lookup-or-update-cache cache ::simple-parser? #(simple-parser? nil))] |
1350 | 1369 | (fn [x] |
1351 | 1370 | (if (map? x) |
1352 | 1371 | (reduce-kv (fn [acc k v] |
|
1415 | 1434 | (-get [_ key default] (get children key default)) |
1416 | 1435 | (-set [this key value] (-set-assoc-children this key value)) |
1417 | 1436 | ParserInfo |
1418 | | - (-parser-info [_] {:simple-parser @simple-parser}) |
| 1437 | + (-parser-info [_ opts] {:simple-parser (simple-parser? opts)}) |
1419 | 1438 | #?@(:cljs [IPrintWithWriter (-pr-writer [this writer opts] (pr-writer-schema this writer opts))])))) |
1420 | 1439 | #?@(:cljs [IPrintWithWriter (-pr-writer [this writer opts] (pr-writer-into-schema this writer opts))])))) |
1421 | 1440 |
|
|
1464 | 1483 | validate-limits (if bounded |
1465 | 1484 | (-validate-bounded-limits (c/min bounded (or max bounded)) min max) |
1466 | 1485 | (-validate-limits min max)) |
| 1486 | + simple-parser? (fn [opts] |
| 1487 | + (or (boolean bounded) |
| 1488 | + (-> schema (-parser-info opts) :simple-parser boolean))) |
1467 | 1489 | ->parser (fn [f g] (let [child-parser (f schema) |
1468 | | - simple (-> schema -parser-info :simple-parser boolean)] |
| 1490 | + simple (-lookup-or-update-cache cache ::simple-parser? #(simple-parser? nil))] |
1469 | 1491 | (fn [x] |
1470 | 1492 | (cond |
1471 | 1493 | (not (fpred x)) ::invalid |
|
1544 | 1566 | (-get [_ _ _] schema) |
1545 | 1567 | (-set [this _ value] (-set-children this [value])) |
1546 | 1568 | ParserInfo |
1547 | | - (-parser-info [_] (cond-> (-parser-info schema) |
1548 | | - bounded (assoc :simple-parser true))) |
| 1569 | + (-parser-info [_ opts] {:simple-parser (simple-parser? opts)}) |
1549 | 1570 | #?@(:cljs [IPrintWithWriter (-pr-writer [this writer opts] (pr-writer-schema this writer opts))])))))) |
1550 | 1571 | #?@(:cljs [IPrintWithWriter (-pr-writer [this writer opts] (pr-writer-into-schema this writer opts))])))) |
1551 | 1572 |
|
|
1621 | 1642 | (-get [_ key default] (get children key default)) |
1622 | 1643 | (-set [this key value] (-set-assoc-children this key value)) |
1623 | 1644 | ParserInfo |
1624 | | - (-parser-info [_] {:simple-parser (every? (-comp :simple-parser -parser-info) children)}) |
| 1645 | + (-parser-info [_ opts] {:simple-parser (every? #(-> % (-parser-info opts) :simple-parser) children)}) |
1625 | 1646 | #?@(:cljs [IPrintWithWriter (-pr-writer [this writer opts] (pr-writer-schema this writer opts))])))) |
1626 | 1647 | #?@(:cljs [IPrintWithWriter (-pr-writer [this writer opts] (pr-writer-into-schema this writer opts))])))) |
1627 | 1648 |
|
|
1668 | 1689 | (-get [_ key default] (get children key default)) |
1669 | 1690 | (-set [this key value] (-set-assoc-children this key value)) |
1670 | 1691 | ParserInfo |
1671 | | - (-parser-info [_] {:simple-parser true}) |
| 1692 | + (-parser-info [_ _] {:simple-parser true}) |
1672 | 1693 | #?@(:cljs [IPrintWithWriter (-pr-writer [this writer opts] (pr-writer-schema this writer opts))])))) |
1673 | 1694 | #?@(:cljs [IPrintWithWriter (-pr-writer [this writer opts] (pr-writer-into-schema this writer opts))]))) |
1674 | 1695 |
|
|
1722 | 1743 | (-get [_ key default] (get children key default)) |
1723 | 1744 | (-set [this key value] (-set-assoc-children this key value)) |
1724 | 1745 | ParserInfo |
1725 | | - (-parser-info [_] {:simple-parser true}) |
| 1746 | + (-parser-info [_ _] {:simple-parser true}) |
1726 | 1747 | #?@(:cljs [IPrintWithWriter (-pr-writer [this writer opts] (pr-writer-schema this writer opts))])))) |
1727 | 1748 | #?@(:cljs [IPrintWithWriter (-pr-writer [this writer opts] (pr-writer-into-schema this writer opts))]))) |
1728 | 1749 |
|
|
1771 | 1792 | (-get [_ key default] (get children key default)) |
1772 | 1793 | (-set [this key value] (-set-assoc-children this key value)) |
1773 | 1794 | ParserInfo |
1774 | | - (-parser-info [_] {:simple-parser true}) |
| 1795 | + (-parser-info [_ _] {:simple-parser true}) |
1775 | 1796 | #?@(:cljs [IPrintWithWriter (-pr-writer [this writer opts] (pr-writer-schema this writer opts))])))) |
1776 | 1797 | #?@(:cljs [IPrintWithWriter (-pr-writer [this writer opts] (pr-writer-into-schema this writer opts))]))) |
1777 | 1798 |
|
|
1822 | 1843 | (-set-children this [value]) |
1823 | 1844 | (-fail! ::index-out-of-bounds {:schema this, :key key}))) |
1824 | 1845 | ParserInfo |
1825 | | - (-parser-info [_] (-parser-info schema)) |
| 1846 | + (-parser-info [_ opts] (-parser-info schema opts)) |
1826 | 1847 | #?@(:cljs [IPrintWithWriter (-pr-writer [this writer opts] (pr-writer-schema this writer opts))])))) |
1827 | 1848 | #?@(:cljs [IPrintWithWriter (-pr-writer [this writer opts] (pr-writer-into-schema this writer opts))]))) |
1828 | 1849 |
|
|
1905 | 1926 | #?@(:cljs [IPrintWithWriter (-pr-writer [this writer opts] (pr-writer-schema this writer opts))])))) |
1906 | 1927 | #?@(:cljs [IPrintWithWriter (-pr-writer [this writer opts] (pr-writer-into-schema this writer opts))])))) |
1907 | 1928 |
|
| 1929 | +;; returns an identifier for the :ref schema in the context of its dynamic scope. |
| 1930 | +;; useful for detecting cycles. |
1908 | 1931 | (defn -identify-ref-schema [schema] |
1909 | 1932 | {:scope (-> schema -options -registry mr/-schemas) |
1910 | 1933 | :name (-ref schema)}) |
|
2006 | 2029 | (-regex-unparser [this] (-fail! ::potentially-recursive-seqex this)) |
2007 | 2030 | (-regex-transformer [this _ _ _] (-fail! ::potentially-recursive-seqex this)) |
2008 | 2031 | (-regex-min-max [this _] (-fail! ::potentially-recursive-seqex this)) |
| 2032 | + ParserInfo |
| 2033 | + (-parser-info [this opts] |
| 2034 | + (let [cycles (::parser-info-cycles opts #{}) |
| 2035 | + ref-id (-identify-ref-schema this)] |
| 2036 | + (if (cycles ref-id) |
| 2037 | + {:simple-parser true} |
| 2038 | + (-parser-info (-deref this) (assoc opts ::parser-info-cycles (conj cycles ref-id)))))) |
2009 | 2039 | #?@(:cljs [IPrintWithWriter (-pr-writer [this writer opts] (pr-writer-schema this writer opts))])))) |
2010 | 2040 | #?@(:cljs [IPrintWithWriter (-pr-writer [this writer opts] (pr-writer-into-schema this writer opts))])))) |
2011 | 2041 |
|
|
2188 | 2218 | (-get [_ key default] (get children key default)) |
2189 | 2219 | (-set [this key value] (-set-assoc-children this key value)) |
2190 | 2220 | ParserInfo |
2191 | | - (-parser-info [_] {:simple-parser true}) |
| 2221 | + (-parser-info [_ _] {:simple-parser true}) |
2192 | 2222 | #?@(:cljs [IPrintWithWriter (-pr-writer [this writer opts] (pr-writer-schema this writer opts))])))) |
2193 | 2223 | #?@(:cljs [IPrintWithWriter (-pr-writer [this writer opts] (pr-writer-into-schema this writer opts))]))) |
2194 | 2224 |
|
|
2262 | 2292 | (-get [_ key default] (get children key default)) |
2263 | 2293 | (-set [this key value] (-set-assoc-children this key value)) |
2264 | 2294 | ParserInfo |
2265 | | - (-parser-info [_] {:simple-parser true}) |
| 2295 | + (-parser-info [_ _] {:simple-parser true}) |
2266 | 2296 | #?@(:cljs [IPrintWithWriter (-pr-writer [this writer opts] (pr-writer-schema this writer opts))])))) |
2267 | 2297 | #?@(:cljs [IPrintWithWriter (-pr-writer [this writer opts] (pr-writer-into-schema this writer opts))]))) |
2268 | 2298 |
|
|
0 commit comments