Coverage report: /development/source/library/org/datagraph/spocq-shard/src/core/ssl/ssl-compiler.lisp
| Kind | Covered | All | % |
| expression | 0 | 428 | 0.0 |
| branch | 0 | 68 | 0.0 |
Key
Not instrumented
Conditionalized out
Executed
Not executed
Both branches taken
One branch taken
Neither branch taken
1
;;; -*- package: org.dataagraph.spocq.implementation -*-
3
;;; translate rdf graph representation for a script into s-expression form
5
(in-package :org.datagraph.spocq.implementation)
7
;;; (load (compile-file "/opt/spocq/patches/ssl/ssl-compiler.lisp"))
11
;;; -> parse-ssl-graph
12
;;; -> compute-ssl-graph
15
;;; load from a store or read the document and parse to triples, translate to an ssl code sequence with
16
;;; the top class in the graph as the initial operator. (just one permitted as no order is possible)
18
(defgeneric read-ssl-graph (document)
19
(:documentation "Given a location or a immediate document, read the graph either from
20
a remote location or from a local repository, both under access constraints.
21
The result is a concrete rdf graph - a collection of triples.
22
The may result from retrieving the graph from a local repository or from retrieving and
23
decoding an rdf document from a remote source.")
25
(:method ((value string))
26
"Given a string, interpret a singleton nquads iri as a location from which to load and return
27
the encoded graph. Otherwise return the string itself."
28
(setf value (string-trim #(#\newline #\return #\linefeed #\space #\tab) value))
29
(assert (>= (length value) 2) () "Invalid ssl graph: ~s." value)
30
(let ((start nil) (end nil))
31
(cond ((multiple-value-setq (start end)
32
(and (eql (char value 0) #\<)
33
(terminated-iri-scanner value 1 (length value))))
34
(if (eql end (length value))
35
(read-ssl-graph (intern-iri (subseq value 1 (1- (length value)))))
37
((multiple-value-setq (start end)
38
(iri-scanner value 0 (length value)))
39
(if (eql end (length value))
40
(read-ssl-graph (intern-iri value))
42
(t ; otherwise, the given value is the document
45
(:method ((location spocq:iri))
46
"Given an iri, if it designates a local repository, read that graph from the repository.
47
Otherwise, retrieve the remote document.
48
Exectise authorization for the active agent in the context of the current task."
49
(if (access-authorized-p location *agent* |acl|:|Execute|)
50
(multiple-value-bind (local-repository-id parsed-iri)
51
(iri-service-repository-id location)
52
(if local-repository-id
53
;; if the location is local, retrieve the designated graph
54
(let* ((location-query-parameters (parse-query-parameters (puri:uri-query parsed-iri)))
55
(revision-id (getf location-query-parameters :revision-id))
56
(repository (repository *class.repository* :id local-repository-id :external-name local-repository-id))
57
(revision (repository-revision (or revision-id "HEAD") :reference repository :if-does-not-exist :error))
58
(graph (or (getf location-query-parameters :revision-id)
59
(spocq.e:request-error "Invalid script graph location: (~s . ~s) -> ~s."
60
*task* *agent* location))))
61
(flet ((match-field (context subject predicate object)
62
(let ((field (repository-matrix-field *transaction* context subject predicate object)))
63
(prog1 (term-value-field field)
64
(release-field-data field)))))
65
(append (with-open-transaction (revision)
66
(match-field graph '?::s '?::p '?::o)))))
67
;; otherwise, read it from th eremote location
68
(let ((process (run-program "/opt/dydra/lib/exec/curl" (list (spocq:iri-lexical-form location))
71
(unwind-protect (read-stream (run-program-output process))
72
(run-program-close process)))))
73
(spocq.e:request-error "Access to process is not authorized: (~s . ~s) -> ~s."
74
*task* *agent* location)))
76
(:method ((location stream))
77
(read-stream location)))
80
(defgeneric parse-ssl-graph (graph)
81
(:method ((graph list))
85
(:method ((graph-string string))
86
(let ((*namespace-bindings* *namespace-bindings*)
87
(defaults `(("spin" . "http://spinrdf.org/spin#")
88
("ssl" . ,*ssl-namespace-name*)
89
("" . ,*ssl-namespace-name*))))
90
(loop for binding in defaults
91
unless (assoc (first binding) *namespace-bindings* :test #'string=)
92
do (push binding *namespace-bindings*))
93
(parse-ssl-graph (parse-turtle graph-string)))))
96
(defgeneric compute-ssl-tree (tree)
97
(:documentation "Transform a c-b-d field into the equivalent ssl form by
98
rearranging arguments according to whether positional, keyword, or code
99
replacing properties with keywords, and consolidating forms per typed node.")
101
(:method ((triples cons))
102
"given a list, extract the type as the operator and any steps as single argument
103
but fold everything else into the list"
104
(let ((extracting-ids ()))
105
(labels ((extract-value (value)
106
(loop for (nil s p o) in triples
107
when (equalp s value)
109
((|rdf|:|first| |rdf|:|rest|) (return (extract-list s)))
110
(|rdf|:|type| (return (extract-function s o))))
111
finally (return (typecase value
112
(spocq:blank-node (make-variable (spocq:blank-node-label value)))
115
(when (member id extracting-ids)
116
(error "Circular list reference in SSL: ~s: ~s." id triples))
119
(loop for (nil s p o) in triples
122
(|rdf|:|first| (setf first o))
123
(|rdf|:|rest| (setf rest o))))
124
(cond ((and first rest)
125
(setf first (extract-value first))
127
(|rdf|:|nil| (list first))
129
(push id extracting-ids)
130
(cons first (extract-list rest)))))
134
(type-as-function (type)
135
(when (and (symbolp type) (fboundp type))
136
(let ((function (fdefinition type)))
137
(when (typep function 'sslr:function) function))))
138
(type-as-reference (type)
139
(when (iri-p type) (load-ssl-graph type)))
140
(extract-function (id type)
141
;; (print (list :extract id type))
142
(when (member id extracting-ids)
143
(error "Circular function reference in SSL: ~s: ~s." id triples))
144
(push id extracting-ids)
145
(let ((function (type-as-function type)))
147
(let* ((signature (sslr:function-signature function))
152
(let ((properties (mapcar #'cddr (remove id triples :test-not #'equalp :key #'second))))
153
;; (print (list type properties))
154
(loop for (property value) in properties
156
with property-keyword = nil
157
do (cond ((eq property |rdf|:|type|)
158
(assert (equalp value type) ()
159
"Invalid ssl graph: duplicate type: ~s: ~s." id triples))
160
((setf position (when (symbolp property)
161
(position property (sslr:function-required-parameters signature)
162
:test #'string-equal)))
163
(push (cons position (extract-value value)) required))
164
((setf position (position (setf property-keyword (iri-keyword property))
165
(sslr:function-keyword-parameters signature)))
166
;; add keywords in apparent order to the code list
167
(push (list property-keyword (extract-value value)) keyword))
168
((setf position (when (symbolp property)
169
(position property (sslr:function-code-parameters signature)
170
:test #'string-equal)))
171
(push (cons position (extract-value value)) code))
173
(push property invalid))))
174
(assert (null invalid) ()
175
"Invalid ssl graph: invalid properties: ~s: ~s~% ~s." function invalid triples)
176
`(,@(reduce #'append (sort required #'< :key #'first) :key #'rest :from-end t)
177
,@(reduce #'append keyword :from-end t)
179
,@(mapcar #'rest (sort code #'< :key #'first)))))
180
(let ((reference (type-as-reference type)))
181
;; rearrange the retrieved reference to append any arguments and translate as above
183
(compute-ssl-tree (append reference (remove type (copy-list triples) :key #'fourth)))
184
(warn "Undefined script reference: ~s: ~s." id type)))))))
185
(let ((functions (loop for (nil object a type) in triples
186
when (eq a |rdf|:|type|)
187
unless (loop for (nil nil nil o-member) in triples
188
when (equalp object o-member)
190
collect (extract-function object type))))
191
(when (rest functions)
192
(warn "Multiple SSL operators: ~s." functions))
193
(first functions))))))
196
(defgeneric load-ssl-graph (location)
197
(:documentation "Given a location or an immediate document, parse the graph and
198
convert it into an ssl code sequence")
200
(:method ((location t))
201
(compute-ssl-tree (parse-ssl-graph (read-ssl-graph location)))))
205
;;; all aupplanted by the functions, above
207
(defgeneric flatten-ssl-tree (tree)
208
(:documentation "Transform a c-b-d tree into the equivalent ssl form by
209
rearranging arguments according to whether positional, keyword, or code
210
replacing properties with keywords, and flattening nested forms.")
212
(:method ((form cons))
213
"given a list, extract the type as the operator and any steps as single argument
214
but fold everything else into the list"
215
(let* ((type (or (getf form '|rdf|:|type|)
216
(error "Invalid ssl graph: no type: ~s." form)))
218
(cond ((setf reference (type-as-function type))
219
;; translate a form which references to native functions into the script expression
220
;; construct a code sequence with required, then keyword arguments, then the operator
221
;; followed by code argument(s)
222
(let* ((signature (sslr:function-signature function))
227
;; (print (cons type signature))
228
(loop for (property value) on form by #'cddr
230
with property-keyword = nil
231
do (cond ((eq property |rdf|:|type|)
232
(assert (eq value type) ()
233
"Invalid ssl graph: duplicate type: ~s." form))
234
((setf position (when (symbolp property)
236
(sslr:function-required-parameters signature)
237
:test #'string-equal)))
238
(push (cons position (flatten-ssl-tree value)) required))
239
((setf position (position (setf property-keyword (iri-keyword property))
240
(sslr:function-keyword-parameters signature)))
241
;; add keywords in apparent order to the code list
242
(push (list property-keyword (first (flatten-ssl-tree value))) keyword))
243
((setf position (when (symbolp property)
245
(sslr:function-code-parameters signature)
246
:test #'string-equal)))
247
(push (cons position (flatten-ssl-list value)) code))
249
(push property invalid))))
250
(assert (null invalid) ()
251
"Invalid ssl graph: invalid properties: ~s: ~s~% ~s." function invalid form)
252
`(,@(reduce #'append (sort required #'< :key #'first) :key #'rest :from-end t)
253
,@(reduce #'append keyword :from-end t)
255
,@(mapcar #'rest (sort code #'< :key #'first)))))
256
((setf (reference (type-as-reference type)))
257
;; rearrange the retrieved reference to append any arguments and translate as above
258
(setf form (copy-list form))
259
(remf form '|rdf|:|type|)
260
(flatten-ssl-form (append reference form)))
262
(warn "Undefined script reference: ~s." type)))))
264
(:method ((form spocq:blank-node))
265
(list (make-variable (spocq:blank-node-label form))))
271
(defgeneric flatten-ssl-list (tree)
272
(:method ((form list))
273
(reduce #'append form :key #'flatten-ssl-tree :from-end t)))
276
(defun compute-cspo-form (term statements)
277
"Given a subject term and a statement field, compute definition forms
278
- accumulate the values and initargs as a definition list "
280
(loop for (nil subject property object) in statements
281
when (equalp subject term)
282
do (let ((value (compute-cspo-object-form object statements)))
283
(setf (getf initargs property) value)))
286
(defun compute-cspo-object-form (term statements)
288
((or spocq:blank-node iri (satisfies variable-p))
289
(flet ((get-property (test-property)
290
;; (print test-property)
291
(loop for (nil subject property object) in statements
292
when (and (equalp subject term) (equalp property test-property))
294
(cond ((get-property |rdf|:|type|)
295
(compute-cspo-form term statements))
296
((get-property |rdf|:|first|)
297
(compute-spo-form-list term statements))
304
(defun compute-spo-form-list (term statements)
305
"given a graph as a list of statements and the term for the list head, compute the list of objects."
306
(if (eq term |rdf|:|nil|)
308
(loop with first = nil
312
for (nil subject predicate object) in statements
313
when (equal term subject)
316
(assert (null first) () "duplicate first in list graph: ~s" statements)
317
(setf first (compute-cspo-object-form object statements)
320
(assert (null rest) () "duplicate rest in list graph: ~s" statements)
321
(setf rest (compute-spo-form-list object statements)
324
(error "invalid predicate in list graph: ~s: ~s" predicate statements)))
325
when (and first-p rest-p)
326
return (cons first rest)
327
finally (error "head not in list graph: ~s: ~s" term statements))))