git.fiddlerwoaroof.com
Browse code

(init)

Ed Langley authored on 17/06/2018 23:47:56
Showing 5 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1 @@
1
+*~
0 2
new file mode 100644
... ...
@@ -0,0 +1,27 @@
1
+;;; -*- Mode:Lisp; Syntax:ANSI-Common-Lisp; Package: ASDF-USER -*-
2
+(in-package :asdf-user)
3
+
4
+(defsystem :cl-edn 
5
+    :description ""
6
+    :author "Ed L <edward@elangley.org>"
7
+    :license "MIT"
8
+    :depends-on (#:alexandria
9
+                 #:uiop
10
+                 #:serapeum
11
+                 #:smug)
12
+    :serial t
13
+    :in-order-to ((test-op (test-op :cl-edn/test)))
14
+    :components ((:file "edn")
15
+                 ))
16
+
17
+(defsystem :cl-edn/fset
18
+  :depends-on (#:cl-edn
19
+               #:fset)
20
+  :components ((:file "fset-synthesize")))
21
+
22
+(defsystem :cl-edn/test
23
+  :depends-on (#:should-test)
24
+  :perform (test-op (o s)
25
+                    (uiop:symbol-call :st '#:test
26
+                                      :package :edn-test))
27
+  :components ((:file "test")))
0 28
new file mode 100644
... ...
@@ -0,0 +1,302 @@
1
+(defpackage :edn
2
+  (:use :cl :smug)
3
+  (:export ))
4
+(defpackage :edn-primitives
5
+  (:use)
6
+  (:export :nil :true :false))
7
+
8
+(defconstant edn-primitives:nil 'edn-primitives:nil)
9
+(defconstant edn-primitives:true 'edn-primitives:true)
10
+(defconstant edn-primitives:false 'edn-primitives:false)
11
+
12
+(in-package :edn)
13
+
14
+(defun .satisfies (predicate &rest args)
15
+  (.bind (.item)
16
+         (lambda (x)
17
+           (if (apply predicate x args)
18
+               (.identity x)
19
+               (.fail)))))
20
+
21
+(defun .zero-or-more (parser)
22
+  (.plus (.let* ((x parser)
23
+                 (xs (.zero-or-more parser)))
24
+           (.identity (cons x xs)))
25
+         (.identity ())))
26
+
27
+(defun .one-or-more (parser)
28
+  (.let* ((x parser)
29
+          (y (.zero-or-more parser)))
30
+    (.identity (cons x y))))
31
+
32
+(defun .elements ()
33
+  (.zero-or-more (.progn (.s)
34
+                         (.element))))
35
+
36
+(defun .s ()
37
+  (.zero-or-more
38
+   (.or (.whitespace)
39
+        (.comment)
40
+        (.discarded-element))))
41
+
42
+(defun .whitespace ()
43
+  (.or (.char= #\space)
44
+       (.char= #\tab)
45
+       (.char= #\return)
46
+       (.char= #\newline)
47
+       (.char= #\,)))
48
+
49
+(defun .comment ()
50
+  (.let* ((result (.prog2 (.char= #\;)
51
+                          (.zero-or-more (.and (.not (.or (.char= #\newline)
52
+                                                          (.char= #\nul)))
53
+                                               (.item)))
54
+                          (.or (.char= #\newline)
55
+                               (.not (.item))))))
56
+    (.identity (list :comment (coerce result 'string)))))
57
+
58
+(defun .discarded-element ()
59
+  (.progn (.string= "#_")
60
+          (.s)
61
+          (.element)))
62
+
63
+(defun .alt (&rest r)
64
+  (reduce '.plus r))
65
+
66
+(defun .element ()
67
+  (.or (.or (.nil)
68
+            (.boolean))
69
+       (.alt (.symbol)
70
+             (.keyword)
71
+             (.number)
72
+             (.character)
73
+             (.string)
74
+             
75
+             (.let* ((pairs
76
+                      (.prog2 (.char= #\{)
77
+                              (.progn (.s)
78
+                                      (.zero-or-more (.let* ((first (.prog1 (.element) (.s)))
79
+                                                             (second (.prog1 (.element) (.s))))
80
+                                                       (.identity (list :pair first second)))))
81
+                              (.char= #\}))))
82
+               (.identity (cons :map pairs)))
83
+             (.let* ((pairs
84
+                      (.prog2 (.string= "#{")
85
+                              (.elements)
86
+                              (.s)
87
+                              (.char= #\}))))
88
+               (.identity (cons :set pairs)))
89
+             (.let* ((pairs
90
+                      (.prog2 (.char= #\[)
91
+                              (.elements)
92
+                              (.s)
93
+                              (.char= #\]))))
94
+               (.identity (cons :vector pairs)))
95
+             (.let* ((pairs
96
+                      (.prog2 (.char= #\()
97
+                              (.elements)
98
+                              (.s)
99
+                              (.char= #\)))))
100
+               (.identity (cons :list pairs)))
101
+             (.let* ((tag (.progn (.char= #\#) (.tag-symbol)))
102
+                     (element (.progn (.s) (.element))))
103
+               (.identity (list :tagged tag element)))
104
+             )))
105
+
106
+(defun .nil ()
107
+  (.and (.string= "nil")
108
+        (.identity edn-primitives:nil)))
109
+
110
+(defun .boolean ()
111
+  (.let* ((r (.or (.string= "true")
112
+                  (.string= "false"))))
113
+    (string-case:string-case (r)
114
+      ("true" (.identity edn-primitives:true))
115
+      ("false" (.identity edn-primitives:false)))))
116
+
117
+(defun .symbol ()
118
+  (.plus (.char= #\/)
119
+         (.let* ((ns (.optional (.prog1 (.name) (.char= #\/))))
120
+                 (name (.name)))
121
+           (.identity (list :symbol ns name)))))
122
+
123
+(defun .tag-symbol ()
124
+  (.let* ((first (.satisfies #'alpha-char-p))
125
+          (rest (.let* ((ns (.or (.char= #\/)
126
+                                 (.optional (.prog1 (.name) (.char= #\/)))))
127
+                        (name (.name)))
128
+                  (.identity (list ns name)))))
129
+    (destructuring-bind (ns name) rest
130
+      (if ns
131
+          (if (eql ns #\/)
132
+              (.identity (list :symbol (format nil "~c" first) name))
133
+              (.identity (list :symbol (format nil "~c~a" first ns) name)))
134
+          (.identity (list :symbol nil (format nil "~c~a" first name)))))))
135
+
136
+(defun .keyword ()
137
+  (.progn (.char= #\:)
138
+          (.let* ((ns (.optional (.prog1 (.name) (.char= #\/))))
139
+                  (name (.name)))
140
+            (.identity (list :keyword ns name)))))
141
+
142
+(defun .name ()
143
+  (.first (.plus (.let* ((first (.name-start-1))
144
+                         (rest (.zero-or-more (.name-constituent))))
145
+                   (.identity (format nil "~c~{~c~}" first rest)))
146
+                 (.let* ((first (.name-start-2))
147
+                         (second (.satisfies #'alpha-char-p))
148
+                         (rest (.zero-or-more (.name-constituent))))
149
+                   (.identity (format nil "~c~c~{~c~}" first second rest))))))
150
+
151
+(defun .name-start-1 ()
152
+  (.satisfies (lambda (x)
153
+                (or (alpha-char-p x)
154
+                    (member x '(#\! #\* #\? #\_ #\$ #\% #\& #\=))))))
155
+
156
+(defun .name-start-2 ()
157
+  (.satisfies (lambda (x)
158
+                (or (alpha-char-p x)
159
+                    (member x '(#\. #\- #\+))))))
160
+
161
+(defun .name-constituent ()
162
+  (.or (.name-start-1)
163
+       (.name-start-2)
164
+       (.satisfies (lambda (x)
165
+                     (or (digit-char-p x)
166
+                         (member x '(#\# #\:)))))))
167
+(defun .number ()
168
+  (.or (.float)
169
+       (.integer)))
170
+
171
+(defun apply-sign (sign num)
172
+  (if sign
173
+      (ecase sign
174
+        (#\+ num)
175
+        (#\- (* -1 num)))
176
+      num))
177
+
178
+(defun .integer ()
179
+  (.let* ((sign (.optional
180
+                 (.or (.char= #\+)
181
+                      (.char= #\-))))
182
+          (num (.cardinal))
183
+          (flag (.optional (.char= #\N))))
184
+    flag
185
+    (.identity (apply-sign sign num))))
186
+
187
+(defun .float ()
188
+  (.let* ((sign (.optional
189
+                 (.or (.char= #\+)
190
+                      (.char= #\-))))
191
+          (num (.cardinal))
192
+          (frac (.frac-exp)))
193
+    (destructuring-bind (mant exp) frac
194
+      (.identity (apply-sign sign (* (+ num mant)
195
+                                     (if exp
196
+                                         (expt 10 exp)
197
+                                         1)))))))
198
+
199
+(defun .frac-exp ()
200
+  (.alt (.let* ((frac (.frac))
201
+                (exp (.optional (.exp)))
202
+                (flag (.optional (.char= #\M))))
203
+          flag
204
+          (.identity (list frac exp)))
205
+        (.let* ((exp (.exp))
206
+                (flag (.optional (.char= #\M))))
207
+          flag
208
+          (.identity (list 0 exp)))
209
+        (.let* ((flag (.optional (.char= #\M))))
210
+          flag
211
+          (.identity (list 0 0)))))
212
+
213
+(defun .frac ()
214
+  (declare (optimize debug))
215
+  (.let* ((nums (.first
216
+                 (.progn (.char= #\.)
217
+                         (.zero-or-more (.digit))))))
218
+    (.identity
219
+     (if nums
220
+         (let ((num (parse-integer (coerce nums 'string))))
221
+           (coerce (if (= num 0)
222
+                       0
223
+                       (/ num
224
+                          (expt 10
225
+                                (floor
226
+                                 (1+ (log num
227
+                                          10))))))
228
+                   'float))
229
+         0))))
230
+
231
+(defun .exp ()
232
+  (.progn (.char-equal #\e)
233
+          (.let* ((sign (.optional
234
+                         (.or (.char= #\+)
235
+                              (.char= #\-))))
236
+                  (num (.cardinal)))
237
+            (.identity (apply-sign sign num)))))
238
+
239
+(defun .cardinal ()
240
+  (.let* ((nums (.first
241
+                 (.or (.let* ((first (.non-zero-digit))
242
+                              (rest (.zero-or-more (.digit))))
243
+                        (.identity (list* first rest)))
244
+                      (.let* ((c (.digit)))
245
+                        (.identity (list c)))))))
246
+    (.identity (parse-integer (coerce nums 'string)))))
247
+
248
+(defun .digit ()
249
+  (.satisfies #'digit-char-p))
250
+
251
+(defun .non-zero-digit ()
252
+  (.satisfies (lambda (x)
253
+                (and (digit-char-p x)
254
+                     (not (eql #\0 x))))))
255
+
256
+(defun .printable-character ()
257
+  (.or (.satisfies (lambda (x) (char>= #\~ x #\!)))
258
+       (.satisfies (lambda (x) (>= (char-code x) #xA1)))))
259
+
260
+(defun .character-name ()
261
+  (.or (.string= "newline")
262
+       (.string= "space")
263
+       (.string= "tab")
264
+       (.string= "return")
265
+       (.string= "backspace")
266
+       (.string= "formfeed")))
267
+
268
+(defun .character ()
269
+  (.let* ((char (.progn (.char= #\\)
270
+                        (.or (.character-name)
271
+                             (.printable-character)))))
272
+    (.identity (list :character char))))
273
+
274
+(defun .string-char ()
275
+  (.and (.not (.char= #\nul))
276
+        (.not (.char= #\"))
277
+        (.not (.char= #\\))
278
+        (.item)))
279
+
280
+(defun .string-escape ()
281
+  (.let* ((esc (.or (.char= #\")
282
+                    (.char= #\b)
283
+                    (.char= #\t)
284
+                    (.char= #\n)
285
+                    (.char= #\f)
286
+                    (.char= #\r)
287
+                    (.char= #\\))))
288
+    (.identity (format nil "\\~c" esc))))
289
+
290
+(defun combine (list)
291
+  (format nil "~{~a~}" list))
292
+
293
+(defun .string ()
294
+  (.let* ((string (.prog2 (.char= #\")
295
+                          (.zero-or-more (.or (.string-char)
296
+                                              (.progn (.char= #\\)
297
+                                                      (.string-escape))))
298
+                          (.char= #\"))))
299
+    (.identity (list :string (combine string)))))
300
+
301
+(defgeneric synthesize-compound (implementation discriminator args))
302
+(defgeneric synthesize (implementation args))
0 303
new file mode 100644
... ...
@@ -0,0 +1,47 @@
1
+(in-package :edn)
2
+
3
+(defmethod synthesize ((implementation (eql 'fset)) thing)
4
+  (typecase thing
5
+    (list (synthesize-compound implementation (car thing) (cdr thing)))
6
+    (t thing)))
7
+
8
+
9
+(defmethod synthesize-compound ((implementation (eql 'fset)) (discriminator (eql :map)) args)
10
+  (fset:convert 'fset:map
11
+                (mapcar (fw.lu:destructuring-lambda ((p k v))
12
+                          (declare (ignore p))
13
+                          (cons (synthesize implementation k)
14
+                                (synthesize implementation v)))
15
+                        args)))
16
+
17
+(defmethod synthesize-compound ((implementation (eql 'fset)) (discriminator (eql :set)) args)
18
+  (fset:convert 'fset:set
19
+                (mapcar (lambda (a)
20
+                          (synthesize implementation a))
21
+                        args)))
22
+
23
+(defmethod synthesize-compound ((implementation (eql 'fset)) (discriminator (eql :vector)) args)
24
+  (fset:convert 'fset:seq
25
+                (mapcar (lambda (a)
26
+                          (synthesize implementation a))
27
+                        args)))
28
+
29
+(defmethod synthesize-compound ((implementation (eql 'fset)) (discriminator (eql :list)) args)
30
+  (mapcar (lambda (a)
31
+            (synthesize implementation a))
32
+          args))
33
+
34
+(defmethod synthesize-compound (implementation (discriminator (eql :keyword)) args)
35
+  (destructuring-bind (ns name) args
36
+    (alexandria:make-keyword (if ns
37
+                                 (format nil "~a/~a" ns name)
38
+                                 (format nil "~a" name)))))
39
+
40
+(defmethod synthesize-compound (implementation (discriminator (eql :string)) args)
41
+  (car args))
42
+
43
+(defmethod synthesize-compound (implementation (discriminator (eql :symbol)) args)
44
+  (destructuring-bind (ns name) args
45
+    (make-symbol (if ns
46
+                     (format nil "~a/~a" ns name)
47
+                     (format nil "~a" name)))))
0 48
new file mode 100644
... ...
@@ -0,0 +1,27 @@
1
+(defpackage :edn-test
2
+  (:use :cl :st)
3
+  (:export ))
4
+(in-package :edn-test)
5
+
6
+(deftest edn-parser ()
7
+  (should be equal
8
+          '((:map (:pair 1 1)))
9
+          (smug:parse (edn::.elements) "{ 1 1 }"))
10
+  (should be equal
11
+          '((:vector 1 1))
12
+          (smug:parse (edn::.elements) "[ 1 1 ]"))
13
+  (should be equal
14
+          '((:set 1 1))
15
+          (smug:parse (edn::.elements) "#{ 1   1 }"))
16
+  (should be equal
17
+          '((:tagged (:symbol nil "foobar") (:vector 1 1)))
18
+          (smug:parse (edn::.elements) "#foobar [ 1 1 ]"))
19
+  (should be equal
20
+          '(:list
21
+            (:set
22
+             (:vector
23
+              (:map (:pair edn-primitives:nil edn-primitives:true)
24
+                    (:pair edn-primitives:false edn-primitives:nil)))))
25
+          (car (smug:parse (smug:.prog1 (edn::.elements) (smug:.not (smug:.item)))
26
+                           "(#{[{nil true,false nil}]})")))
27
+  )