-
Notifications
You must be signed in to change notification settings - Fork 4
/
path.cljc
99 lines (76 loc) · 2.83 KB
/
path.cljc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
(ns com.yetanalytics.flint.spec.path
(:require [clojure.spec.alpha :as s]
[com.yetanalytics.flint.spec.axiom :as ax]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Path Terminal
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def path-terminal-spec
(s/and
(comp not list?)
(s/or :ax/iri ax/iri-spec
:ax/prefix-iri ax/prefix-iri-spec
:ax/rdf-type ax/rdf-type-spec)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Negated Path
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; A "negated path" (PathNegatedPropertySet in the SPARQL grammar) can
;; only contain a bunch of alternates of more negated paths.
;; Multi-spec is kind of pointless given that there's only one choice here,
;; but this makes it symmetrical to the main path spec.
(defmulti path-neg-spec-mm first)
(defmethod path-neg-spec-mm 'alt [_]
(s/cat :path/op #{'alt}
:path/paths (s/* ::path-neg)))
(def path-neg-multi-spec
(s/multi-spec path-neg-spec-mm identity))
(s/def ::path-neg
(s/or :path/terminal
path-terminal-spec
:path/branch
(s/and list?
path-neg-multi-spec
;; Since we never get a singular `:path/path` there is
;; no need for extra conforming.
(s/conformer #(into [] %)))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Path
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Specs
(def varardic-spec
(s/cat :path/op #{'alt 'cat}
:path/paths (s/* ::path)))
(def unary-spec
(s/cat :path/op #{'inv '? '* '+}
:path/path ::path))
(def unary-neg-spec
(s/cat :path/op #{'not}
:path/path ::path-neg))
;; Multimethods
;; Note: we could use expr/defexprspec here, but given the limited number of
;; ops that would be a bit overkill.
(defmulti path-spec-mm first)
(defmethod path-spec-mm 'alt [_] varardic-spec)
(defmethod path-spec-mm 'cat [_] varardic-spec)
(defmethod path-spec-mm 'inv [_] unary-spec)
(defmethod path-spec-mm '? [_] unary-spec)
(defmethod path-spec-mm '* [_] unary-spec)
(defmethod path-spec-mm '+ [_] unary-spec)
(defmethod path-spec-mm 'not [_] unary-neg-spec)
(def path-multi-spec
(s/multi-spec path-spec-mm identity))
;; Putting it all together
(defn- path-conformer
"Conform the result of a regex spec by converting any `:path/path` keys
into `:path/paths`."
[{op :path/op
path :path/path
paths :path/paths}]
[[:path/op op]
[:path/paths (if path [path] paths)]])
(s/def ::path
(s/or :path/terminal
path-terminal-spec
:path/branch
(s/and list?
path-multi-spec
(s/conformer path-conformer))))