clucumber 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +1 -1
- data/README.md +4 -9
- data/lib/clucumber/clucumber-bootstrap.lisp +32 -0
- data/lib/clucumber/vendor/cl-interpol/alias.lisp +55 -0
- data/lib/clucumber/vendor/cl-interpol/cl-interpol.asd +56 -0
- data/lib/clucumber/vendor/cl-interpol/load.lisp +53 -0
- data/lib/clucumber/vendor/cl-interpol/packages.lisp +40 -0
- data/lib/clucumber/vendor/cl-interpol/read.lisp +716 -0
- data/lib/clucumber/vendor/cl-interpol/specials.lisp +113 -0
- data/lib/clucumber/vendor/cl-interpol/test/packages.lisp +34 -0
- data/lib/clucumber/vendor/cl-interpol/test/tests.lisp +128 -0
- data/lib/clucumber/vendor/cl-interpol/test.lisp +177 -0
- data/lib/clucumber/vendor/cl-interpol/test2.lisp +6254 -0
- data/lib/clucumber/vendor/cl-interpol/unicode.lisp +13912 -0
- data/lib/clucumber/vendor/cl-interpol/util.lisp +122 -0
- data/lib/clucumber/vendor/cl-ppcre/api.lisp +1262 -0
- data/lib/clucumber/vendor/cl-ppcre/charmap.lisp +152 -0
- data/lib/clucumber/vendor/cl-ppcre/charset.lisp +242 -0
- data/lib/clucumber/vendor/cl-ppcre/chartest.lisp +98 -0
- data/lib/clucumber/vendor/cl-ppcre/cl-ppcre-test.asd +34 -0
- data/lib/clucumber/vendor/cl-ppcre/cl-ppcre-unicode/packages.lisp +38 -0
- data/lib/clucumber/vendor/cl-ppcre/cl-ppcre-unicode/resolver.lisp +61 -0
- data/lib/clucumber/vendor/cl-ppcre/cl-ppcre-unicode.asd +58 -0
- data/lib/clucumber/vendor/cl-ppcre/cl-ppcre.asd +79 -0
- data/lib/clucumber/vendor/cl-ppcre/closures.lisp +471 -0
- data/lib/clucumber/vendor/cl-ppcre/convert.lisp +875 -0
- data/lib/clucumber/vendor/cl-ppcre/errors.lisp +84 -0
- data/lib/clucumber/vendor/cl-ppcre/lexer.lisp +737 -0
- data/lib/clucumber/vendor/cl-ppcre/lispworks-defsystem.lisp +57 -0
- data/lib/clucumber/vendor/cl-ppcre/load.lisp +67 -0
- data/lib/clucumber/vendor/cl-ppcre/optimize.lisp +578 -0
- data/lib/clucumber/vendor/cl-ppcre/packages.lisp +68 -0
- data/lib/clucumber/vendor/cl-ppcre/parser.lisp +319 -0
- data/lib/clucumber/vendor/cl-ppcre/ppcre-tests.lisp +269 -0
- data/lib/clucumber/vendor/cl-ppcre/regex-class-util.lisp +555 -0
- data/lib/clucumber/vendor/cl-ppcre/regex-class.lisp +259 -0
- data/lib/clucumber/vendor/cl-ppcre/repetition-closures.lisp +833 -0
- data/lib/clucumber/vendor/cl-ppcre/scanner.lisp +506 -0
- data/lib/clucumber/vendor/cl-ppcre/specials.lisp +172 -0
- data/lib/clucumber/vendor/cl-ppcre/test/packages.lisp +37 -0
- data/lib/clucumber/vendor/cl-ppcre/test/perl-tests.lisp +150 -0
- data/lib/clucumber/vendor/cl-ppcre/test/tests.lisp +159 -0
- data/lib/clucumber/vendor/cl-ppcre/test/unicode-tests.lisp +80 -0
- data/lib/clucumber/vendor/cl-ppcre/util.lisp +201 -0
- data/lib/clucumber/vendor/cl-unicode/alias.lisp +135 -0
- data/lib/clucumber/vendor/cl-unicode/api.lisp +412 -0
- data/lib/clucumber/vendor/cl-unicode/build/char-info.lisp +133 -0
- data/lib/clucumber/vendor/cl-unicode/build/dump.lisp +239 -0
- data/lib/clucumber/vendor/cl-unicode/build/read.lisp +280 -0
- data/lib/clucumber/vendor/cl-unicode/build/util.lisp +182 -0
- data/lib/clucumber/vendor/cl-unicode/cl-unicode.asd +90 -0
- data/lib/clucumber/vendor/cl-unicode/conditions.lisp +54 -0
- data/lib/clucumber/vendor/cl-unicode/derived.lisp +120 -0
- data/lib/clucumber/vendor/cl-unicode/hash-tables.lisp +20 -0
- data/lib/clucumber/vendor/cl-unicode/lists.lisp +10 -0
- data/lib/clucumber/vendor/cl-unicode/methods.lisp +15 -0
- data/lib/clucumber/vendor/cl-unicode/packages.lisp +76 -0
- data/lib/clucumber/vendor/cl-unicode/specials.lisp +135 -0
- data/lib/clucumber/vendor/cl-unicode/test/packages.lisp +34 -0
- data/lib/clucumber/vendor/cl-unicode/test/tests.lisp +150 -0
- data/lib/clucumber/vendor/cl-unicode/test-functions.lisp +94 -0
- data/lib/clucumber/vendor/cl-unicode/util.lisp +274 -0
- data/lib/clucumber/vendor/lift/compare/fiveam-tests.lisp +14 -0
- data/lib/clucumber/vendor/lift/compare/lift-tests.lisp +13 -0
- data/lib/clucumber/vendor/lift/compare/rt-tests.lisp +16 -0
- data/lib/clucumber/vendor/lift/compare/xlunit-tests.lisp +15 -0
- data/lib/clucumber/vendor/lift/dev/changes.lisp +61 -0
- data/lib/clucumber/vendor/lift/dev/config.lisp +354 -0
- data/lib/clucumber/vendor/lift/dev/copy-file.lisp +117 -0
- data/lib/clucumber/vendor/lift/dev/introspection.lisp +232 -0
- data/lib/clucumber/vendor/lift/dev/lift-interface.lisp +56 -0
- data/lib/clucumber/vendor/lift/dev/lift-notes.lisp +202 -0
- data/lib/clucumber/vendor/lift/dev/lift-randomized.lisp +45 -0
- data/lib/clucumber/vendor/lift/dev/lift.lisp +2383 -0
- data/lib/clucumber/vendor/lift/dev/macros.lisp +229 -0
- data/lib/clucumber/vendor/lift/dev/measuring.lisp +156 -0
- data/lib/clucumber/vendor/lift/dev/packages.lisp +161 -0
- data/lib/clucumber/vendor/lift/dev/port.lisp +151 -0
- data/lib/clucumber/vendor/lift/dev/prototypes.lisp +282 -0
- data/lib/clucumber/vendor/lift/dev/random-testing.lisp +124 -0
- data/lib/clucumber/vendor/lift/dev/report-locations.lisp +13 -0
- data/lib/clucumber/vendor/lift/dev/reports.lisp +916 -0
- data/lib/clucumber/vendor/lift/dev/utilities.lisp +242 -0
- data/lib/clucumber/vendor/lift/docs/package.lisp +6 -0
- data/lib/clucumber/vendor/lift/docs/setup.lisp +17 -0
- data/lib/clucumber/vendor/lift/examples/basic-examples.lisp +289 -0
- data/lib/clucumber/vendor/lift/examples/random-testing.lisp +32 -0
- data/lib/clucumber/vendor/lift/lift-documentation.asd +28 -0
- data/lib/clucumber/vendor/lift/lift-test.asd +35 -0
- data/lib/clucumber/vendor/lift/lift.asd +77 -0
- data/lib/clucumber/vendor/lift/test/equality-tests.lisp +40 -0
- data/lib/clucumber/vendor/lift/test/finding-tests.lisp +32 -0
- data/lib/clucumber/vendor/lift/test/lift-test.lisp +783 -0
- data/lib/clucumber/vendor/lift/test/order-of-operations.lisp +54 -0
- data/lib/clucumber/vendor/lift/test/packages.lisp +17 -0
- data/lib/clucumber/vendor/lift/test/test-config-files.lisp +20 -0
- data/lib/clucumber/vendor/lift/test/test-dynamic-variables.lisp +57 -0
- data/lib/clucumber/vendor/lift/test/test-maximum-problems.lisp +74 -0
- data/lib/clucumber/vendor/lift/test/test-prototypes.lisp +278 -0
- data/lib/clucumber/vendor/lift/test/test-timeout.lisp +37 -0
- data/lib/clucumber/vendor/lift/test/tests-in-progress.lisp +62 -0
- data/lib/clucumber/vendor/lift/test/testsuite-expects.lisp +60 -0
- data/lib/clucumber/vendor/lift/timeout/package.lisp +13 -0
- data/lib/clucumber/vendor/lift/timeout/with-timeout.lisp +123 -0
- data/lib/clucumber/vendor/lift/website/stuff/Temp.lisp +34 -0
- data/lib/clucumber/vendor/st-json/st-json.asd +3 -0
- data/lib/clucumber/vendor/st-json/st-json.lisp +310 -0
- data/lib/clucumber/vendor/trivial-backtrace/dev/backtrace.lisp +127 -0
- data/lib/clucumber/vendor/trivial-backtrace/dev/fallback.lisp +10 -0
- data/lib/clucumber/vendor/trivial-backtrace/dev/map-backtrace.lisp +103 -0
- data/lib/clucumber/vendor/trivial-backtrace/dev/mucking.lisp +75 -0
- data/lib/clucumber/vendor/trivial-backtrace/dev/packages.lisp +13 -0
- data/lib/clucumber/vendor/trivial-backtrace/dev/utilities.lisp +104 -0
- data/lib/clucumber/vendor/trivial-backtrace/test/packages.lisp +5 -0
- data/lib/clucumber/vendor/trivial-backtrace/test/test-setup.lisp +4 -0
- data/lib/clucumber/vendor/trivial-backtrace/test/tests.lisp +16 -0
- data/lib/clucumber/vendor/trivial-backtrace/trivial-backtrace-test.asd +22 -0
- data/lib/clucumber/vendor/trivial-backtrace/trivial-backtrace.asd +35 -0
- data/lib/clucumber/vendor/usocket/backend/allegro.lisp +199 -0
- data/lib/clucumber/vendor/usocket/backend/armedbear.lisp +491 -0
- data/lib/clucumber/vendor/usocket/backend/clisp.lisp +260 -0
- data/lib/clucumber/vendor/usocket/backend/cmucl.lisp +266 -0
- data/lib/clucumber/vendor/usocket/backend/lispworks.lisp +741 -0
- data/lib/clucumber/vendor/usocket/backend/mcl.lisp +369 -0
- data/lib/clucumber/vendor/usocket/backend/openmcl.lisp +206 -0
- data/lib/clucumber/vendor/usocket/backend/sbcl.lisp +424 -0
- data/lib/clucumber/vendor/usocket/backend/scl.lisp +261 -0
- data/lib/clucumber/vendor/usocket/condition.lisp +227 -0
- data/lib/clucumber/vendor/usocket/package.lisp +82 -0
- data/lib/clucumber/vendor/usocket/server.lisp +45 -0
- data/lib/clucumber/vendor/usocket/test/package.lisp +13 -0
- data/lib/clucumber/vendor/usocket/test/test-usocket.lisp +166 -0
- data/lib/clucumber/vendor/usocket/usocket-test.asd +26 -0
- data/lib/clucumber/vendor/usocket/usocket.asd +37 -0
- data/lib/clucumber/vendor/usocket/usocket.lisp +542 -0
- data/lib/clucumber/vendor/usocket/vendor/kqueue.lisp +1 -0
- data/lib/clucumber/vendor/usocket/vendor/split-sequence.lisp +245 -0
- data/lib/clucumber.rb +29 -7
- metadata +151 -5
@@ -0,0 +1,123 @@
|
|
1
|
+
(in-package #:com.metabang.trivial-timeout)
|
2
|
+
|
3
|
+
(eval-when (:compile-toplevel :load-toplevel :execute)
|
4
|
+
(unless (and (find-symbol (symbol-name '#:with-timeout)
|
5
|
+
'#:com.metabang.trivial-timeout)
|
6
|
+
(fboundp (find-symbol (symbol-name '#:with-timeout)
|
7
|
+
'#:com.metabang.trivial-timeout)))
|
8
|
+
(define-condition timeout-error (error)
|
9
|
+
()
|
10
|
+
(:report (lambda (c s)
|
11
|
+
(declare (ignore c))
|
12
|
+
(format s "Process timeout")))
|
13
|
+
(:documentation "An error signaled when the duration specified in
|
14
|
+
the [with-timeout][] is exceeded."))
|
15
|
+
|
16
|
+
(defmacro with-timeout ((seconds) &body body)
|
17
|
+
"Execute `body` for no more than `seconds` time.
|
18
|
+
|
19
|
+
If `seconds` is exceeded, then a [timeout-error][] will be signaled.
|
20
|
+
|
21
|
+
If `seconds` is nil, then the body will be run normally until it completes
|
22
|
+
or is interrupted."
|
23
|
+
(build-with-timeout seconds body))
|
24
|
+
|
25
|
+
(defun build-with-timeout (seconds body)
|
26
|
+
(let ((gseconds (gensym "seconds-"))
|
27
|
+
(gdoit (gensym "doit-")))
|
28
|
+
`(let ((,gseconds ,seconds))
|
29
|
+
(flet ((,gdoit ()
|
30
|
+
(progn ,@body)))
|
31
|
+
(cond (,gseconds
|
32
|
+
,(generate-platform-specific-code gseconds gdoit))
|
33
|
+
(t
|
34
|
+
(,gdoit)))))))
|
35
|
+
|
36
|
+
#+allegro
|
37
|
+
(defun generate-platform-specific-code (seconds-symbol doit-symbol)
|
38
|
+
`(mp:with-timeout (,seconds-symbol (error 'timeout-error))
|
39
|
+
(,doit-symbol)))
|
40
|
+
|
41
|
+
|
42
|
+
#+(and sbcl (not sb-thread))
|
43
|
+
(defun generate-platform-specific-code (seconds-symbol doit-symbol)
|
44
|
+
(let ((glabel (gensym "label-"))
|
45
|
+
(gused-timer? (gensym "used-timer-")))
|
46
|
+
`(let ((,gused-timer? nil))
|
47
|
+
(catch ',glabel
|
48
|
+
(sb-ext:schedule-timer
|
49
|
+
(sb-ext:make-timer (lambda ()
|
50
|
+
(setf ,gused-timer? t)
|
51
|
+
(throw ',glabel nil)))
|
52
|
+
,seconds-symbol)
|
53
|
+
(,doit-symbol))
|
54
|
+
(when ,gused-timer?
|
55
|
+
(error 'timeout-error)))))
|
56
|
+
|
57
|
+
#+(and sbcl sb-thread)
|
58
|
+
(defun generate-platform-specific-code (seconds-symbol doit-symbol)
|
59
|
+
`(handler-case
|
60
|
+
(sb-ext:with-timeout ,seconds-symbol (,doit-symbol))
|
61
|
+
(sb-ext::timeout (c)
|
62
|
+
(declare (ignore c))
|
63
|
+
(error 'timeout-error))))
|
64
|
+
|
65
|
+
#+cmu
|
66
|
+
;;; surely wrong
|
67
|
+
(defun generate-platform-specific-code (seconds-symbol doit-symbol)
|
68
|
+
`(handler-case
|
69
|
+
(mp:with-timeout (seconds-symbol) (,doit-symbol))
|
70
|
+
(sb-ext::timeout (c)
|
71
|
+
(declare (ignore c))
|
72
|
+
(error 'timeout-error))))
|
73
|
+
|
74
|
+
#+(or digitool openmcl ccl)
|
75
|
+
(defun generate-platform-specific-code (seconds-symbol doit-symbol)
|
76
|
+
(let ((checker-process (format nil "Checker ~S" (gensym)))
|
77
|
+
(waiting-process (format nil "Waiter ~S" (gensym)))
|
78
|
+
(result (gensym))
|
79
|
+
(process (gensym)))
|
80
|
+
`(let* ((,result nil)
|
81
|
+
(,process (ccl:process-run-function
|
82
|
+
,checker-process
|
83
|
+
(lambda ()
|
84
|
+
(setf ,result (progn (,doit-symbol)))))))
|
85
|
+
(ccl:process-wait-with-timeout
|
86
|
+
,waiting-process
|
87
|
+
(* ,seconds-symbol #+(or openmcl ccl)
|
88
|
+
ccl:*ticks-per-second* #+digitool 60)
|
89
|
+
(lambda ()
|
90
|
+
(not (ccl::process-active-p ,process))))
|
91
|
+
(when (ccl::process-active-p ,process)
|
92
|
+
(ccl:process-kill ,process)
|
93
|
+
(cerror "Timeout" 'timeout-error))
|
94
|
+
(values ,result))))
|
95
|
+
|
96
|
+
#+lispworks
|
97
|
+
(defun generate-platform-specific-code (seconds-symbol doit-symbol)
|
98
|
+
(let ((gresult (gensym "result-"))
|
99
|
+
(gprocess (gensym "process-")))
|
100
|
+
`(let* (,gresult
|
101
|
+
(,gprocess (mp:process-run-function
|
102
|
+
"WITH-TIMEOUT"
|
103
|
+
'()
|
104
|
+
(lambda ()
|
105
|
+
(setq ,gresult (,doit-symbol))))))
|
106
|
+
(unless (mp:process-wait-with-timeout
|
107
|
+
"WITH-TIMEOUT"
|
108
|
+
,seconds-symbol
|
109
|
+
(lambda ()
|
110
|
+
(not (mp:process-alive-p ,gprocess))))
|
111
|
+
(mp:process-kill ,gprocess)
|
112
|
+
(cerror "Timeout" 'timeout-error))
|
113
|
+
,gresult)))
|
114
|
+
|
115
|
+
(unless (let ((symbol
|
116
|
+
(find-symbol (symbol-name '#:generate-platform-specific-code)
|
117
|
+
'#:com.metabang.trivial-timeout)))
|
118
|
+
(and symbol (fboundp symbol)))
|
119
|
+
(defun generate-platform-specific-code (seconds-symbol doit-symbol)
|
120
|
+
(declare (ignore seconds-symbol))
|
121
|
+
`(,doit-symbol)))
|
122
|
+
|
123
|
+
))
|
@@ -0,0 +1,34 @@
|
|
1
|
+
(in-package #:few)
|
2
|
+
|
3
|
+
#+Ignore
|
4
|
+
;; suck site up and output as LML
|
5
|
+
(mapc
|
6
|
+
(lambda (file)
|
7
|
+
(let ((html (net.html.parser:parse-html file)))
|
8
|
+
(setf html (remove-if (lambda (x)
|
9
|
+
(and (consp x)
|
10
|
+
(member (first x) '(:!doctype))))
|
11
|
+
html))
|
12
|
+
(with-new-file (s (make-pathname :type "lml" :defaults file)
|
13
|
+
:print-right-margin 70)
|
14
|
+
(format s "~S" html))))
|
15
|
+
(directory "Billy-Pilgrim:Users:gwking:darcs:metabang.tinaa:website:*.html"))
|
16
|
+
|
17
|
+
(net.html.parser:parse-html
|
18
|
+
#P"Billy-Pilgrim:Users:gwking:darcs:metabang.tinaa:website:index.html")
|
19
|
+
|
20
|
+
(probe-file
|
21
|
+
"Billy-Pilgrim:Users:gwking:darcs:cl-containers:website:index.shtml")
|
22
|
+
|
23
|
+
(eval `(html
|
24
|
+
((:html :xmlns "http://www.w3.org/1999/xhtml")
|
25
|
+
,@(rest ccl:!))))
|
26
|
+
|
27
|
+
|
28
|
+
|
29
|
+
#+No
|
30
|
+
(with-new-file (*html-stream* (spy (make-pathname :type "lml" :defaults file)))
|
31
|
+
(dtd-prologue :xhtml11)
|
32
|
+
(eval `(html
|
33
|
+
((:html :xmlns "http://www.w3.org/1999/xhtml")
|
34
|
+
,@html))))
|
@@ -0,0 +1,310 @@
|
|
1
|
+
(defpackage :st-json
|
2
|
+
(:use :common-lisp)
|
3
|
+
(:export #:read-json #:read-json-as-type #:read-json-from-string
|
4
|
+
#:write-json #:write-json-to-string #:write-json-element
|
5
|
+
#:as-json-bool #:from-json-bool
|
6
|
+
#:json-bool #:json-null
|
7
|
+
#:jso #:getjso #:mapjso
|
8
|
+
#:json-error #:json-type-error #:json-parse-error
|
9
|
+
#:json-eof-error
|
10
|
+
#:*script-tag-hack*))
|
11
|
+
|
12
|
+
(in-package :st-json)
|
13
|
+
|
14
|
+
(eval-when (:compile-toplevel :load-toplevel :execute)
|
15
|
+
(defparameter *optimize*
|
16
|
+
'(optimize (speed 3) (safety 0) (space 1) (debug 1) (compilation-speed 0))))
|
17
|
+
|
18
|
+
;; Boolean types. It is hard to see what is meant by NIL when encoding
|
19
|
+
;; a lisp value -- false or [] -- so :false and :true are used instead
|
20
|
+
;; of T and NIL.
|
21
|
+
(defun as-json-bool (value)
|
22
|
+
"Convert a generalised boolean to a :true/:false keyword."
|
23
|
+
(if value :true :false))
|
24
|
+
(defun from-json-bool (value)
|
25
|
+
"Convert :true or :false to its boolean equivalent."
|
26
|
+
(ecase value (:true t) (:false nil)))
|
27
|
+
|
28
|
+
;; Types that might be useful when checking the type of input.
|
29
|
+
(deftype json-bool () '(member :true :false))
|
30
|
+
(deftype json-null () '(eql :null))
|
31
|
+
|
32
|
+
;; These are used to represent JS objects on the Lisp side -- hash
|
33
|
+
;; tables are too heavyweight on some implementations.
|
34
|
+
(defstruct jso alist)
|
35
|
+
(defun jso (&rest fields)
|
36
|
+
"Create a JS object. Arguments should be alternating labels and values."
|
37
|
+
(make-jso :alist (loop :for (key val) :on fields :by #'cddr
|
38
|
+
:collect (cons key val))))
|
39
|
+
|
40
|
+
;; A hash-table-like interface for JS objects.
|
41
|
+
(defun getjso (key map)
|
42
|
+
"Fetch a value from a JS object. Returns a second value like
|
43
|
+
gethash."
|
44
|
+
(let ((pair (assoc key (jso-alist map) :test #'string=)))
|
45
|
+
(values (cdr pair) (and pair t))))
|
46
|
+
(defun (setf getjso) (val key map)
|
47
|
+
"Store a value in a JS object."
|
48
|
+
(let ((pair (assoc key (jso-alist map) :test #'string=)))
|
49
|
+
(if pair
|
50
|
+
(setf (cdr pair) val)
|
51
|
+
(prog1 val (push (cons key val) (jso-alist map))))))
|
52
|
+
(defun mapjso (func map)
|
53
|
+
"Iterate over the key/value pairs in a JS object."
|
54
|
+
(loop :for (key . val) :in (jso-alist map)
|
55
|
+
:do (funcall func key val)))
|
56
|
+
|
57
|
+
;; Reader
|
58
|
+
|
59
|
+
(define-condition json-error (simple-error) ())
|
60
|
+
(define-condition json-parse-error (json-error) ())
|
61
|
+
(define-condition json-eof-error (json-parse-error) ())
|
62
|
+
(define-condition json-write-error (json-error) ())
|
63
|
+
(define-condition json-type-error (json-error) ())
|
64
|
+
(defun raise (type format &rest args)
|
65
|
+
(error type :format-control format :format-arguments args))
|
66
|
+
|
67
|
+
(defvar *reading-slot-name* nil)
|
68
|
+
|
69
|
+
(defun is-whitespace (char)
|
70
|
+
(member char '(#\space #\newline #\return #\tab)))
|
71
|
+
|
72
|
+
(defun ends-atom (char)
|
73
|
+
(or (is-whitespace char) (member char '(#\) #\] #\} #\, #\:))))
|
74
|
+
|
75
|
+
(defun skip-whitespace (stream)
|
76
|
+
(declare #.*optimize*)
|
77
|
+
(loop :while (is-whitespace (peek-char nil stream nil))
|
78
|
+
:do (read-char stream)))
|
79
|
+
|
80
|
+
(defun at-eof (stream)
|
81
|
+
(eql (peek-char nil stream nil :eof) :eof))
|
82
|
+
|
83
|
+
(defgeneric read-json (in &optional junk-allowed-p)
|
84
|
+
(:documentation "Read a JSON-encoded value from a stream or a string."))
|
85
|
+
|
86
|
+
(defmethod read-json ((in stream) &optional (junk-allowed-p t))
|
87
|
+
(let ((value (read-json-element in)))
|
88
|
+
(skip-whitespace in)
|
89
|
+
(unless (or junk-allowed-p (at-eof in))
|
90
|
+
(raise 'json-parse-error "Unused characters at end of input."))
|
91
|
+
value))
|
92
|
+
|
93
|
+
(defmethod read-json ((in string) &optional (junk-allowed-p nil))
|
94
|
+
(with-input-from-string (stream in)
|
95
|
+
(read-json stream junk-allowed-p)))
|
96
|
+
|
97
|
+
(defun read-json-from-string (string &key (start 0) end junk-allowed-p)
|
98
|
+
(let (index value)
|
99
|
+
(with-input-from-string (stream string :index index :start start :end end)
|
100
|
+
(setf value (read-json stream junk-allowed-p)))
|
101
|
+
(values value index)))
|
102
|
+
|
103
|
+
(defun read-json-as-type (source type)
|
104
|
+
"Read a JSON value and assert the result to be of a given type.
|
105
|
+
Raises a json-type-error when the type is wrong."
|
106
|
+
(let ((val (read-json source)))
|
107
|
+
(if (typep val type)
|
108
|
+
val
|
109
|
+
(raise 'json-type-error "JSON input '~A' is not of expected type ~A." source type))))
|
110
|
+
|
111
|
+
(defun read-json-element (stream)
|
112
|
+
(declare #.*optimize*)
|
113
|
+
(skip-whitespace stream)
|
114
|
+
(case (peek-char nil stream nil :eof)
|
115
|
+
(:eof (raise 'json-eof-error "Unexpected end of input."))
|
116
|
+
((#\" #\') (read-json-string stream))
|
117
|
+
(#\[ (read-json-list stream))
|
118
|
+
(#\{ (read-json-object stream))
|
119
|
+
(t (read-json-atom stream))))
|
120
|
+
|
121
|
+
(defun read-json-string (stream)
|
122
|
+
(declare #.*optimize*)
|
123
|
+
(labels ((interpret (char)
|
124
|
+
(if (eql char #\\)
|
125
|
+
(let ((escaped (read-char stream)))
|
126
|
+
(case escaped
|
127
|
+
(#\u (read-unicode))
|
128
|
+
(#\b #\backspace) (#\n #\newline) (#\r #\return)
|
129
|
+
(#\t #\tab) (#\f #\page) (t escaped)))
|
130
|
+
char))
|
131
|
+
(read-unicode ()
|
132
|
+
(code-char (loop :for pos :from 0 :below 4
|
133
|
+
:for weight :of-type fixnum := #.(expt 16 3) :then (ash weight -4)
|
134
|
+
:for digit := (digit-char-p (read-char stream) 16)
|
135
|
+
:do (unless digit (raise 'json-parse-error "Invalid unicode constant in string."))
|
136
|
+
:sum (* digit weight)))))
|
137
|
+
(with-output-to-string (out)
|
138
|
+
(handler-case
|
139
|
+
(loop :with quote :of-type character := (read-char stream)
|
140
|
+
:for next :of-type character := (read-char stream)
|
141
|
+
:until (eql next quote)
|
142
|
+
:do (write-char (interpret next) out))
|
143
|
+
(end-of-file () (raise 'json-eof-error "Encountered end of input inside string constant."))))))
|
144
|
+
|
145
|
+
(defun gather-comma-separated (stream end-char obj-name gather-func)
|
146
|
+
(declare #.*optimize*)
|
147
|
+
(declare (type character end-char))
|
148
|
+
(declare (type function gather-func))
|
149
|
+
;; Throw away opening char
|
150
|
+
(read-char stream)
|
151
|
+
(let ((finished nil))
|
152
|
+
(loop
|
153
|
+
(skip-whitespace stream)
|
154
|
+
(let ((next (peek-char nil stream nil #\nul)))
|
155
|
+
(declare (type character next))
|
156
|
+
(when (eql next #\nul)
|
157
|
+
(raise 'json-eof-error "Encountered end of input inside ~A." obj-name))
|
158
|
+
(when (eql next end-char)
|
159
|
+
(read-char stream)
|
160
|
+
(return))
|
161
|
+
(when finished
|
162
|
+
(raise 'json-parse-error "Comma or end of ~A expected, found '~A'" obj-name next)))
|
163
|
+
(funcall gather-func)
|
164
|
+
(skip-whitespace stream)
|
165
|
+
(if (eql (peek-char nil stream nil) #\,)
|
166
|
+
(read-char stream)
|
167
|
+
(setf finished t)))))
|
168
|
+
|
169
|
+
(defun read-json-list (stream)
|
170
|
+
(declare #.*optimize*)
|
171
|
+
(let ((accum ()))
|
172
|
+
(gather-comma-separated
|
173
|
+
stream #\] "list"
|
174
|
+
(lambda ()
|
175
|
+
(push (read-json-element stream) accum)))
|
176
|
+
(nreverse accum)))
|
177
|
+
|
178
|
+
(defun read-json-object (stream)
|
179
|
+
(declare #.*optimize*)
|
180
|
+
(let ((accum ()))
|
181
|
+
(gather-comma-separated
|
182
|
+
stream #\} "object literal"
|
183
|
+
(lambda ()
|
184
|
+
(let ((slot-name (let ((*reading-slot-name* t)) (read-json-element stream))))
|
185
|
+
(unless (or (typep slot-name 'string) (typep slot-name 'number))
|
186
|
+
(raise 'json-parse-error "Invalid slot name in object literal: ~A" slot-name))
|
187
|
+
(skip-whitespace stream)
|
188
|
+
(when (not (eql (read-char stream nil) #\:))
|
189
|
+
(raise 'json-parse-error "Colon expected after '~a'." slot-name))
|
190
|
+
(push (cons slot-name (read-json-element stream)) accum))))
|
191
|
+
(make-jso :alist (nreverse accum))))
|
192
|
+
|
193
|
+
(defun looks-like-a-number (string)
|
194
|
+
(declare #.*optimize*)
|
195
|
+
(let ((string (coerce string 'simple-string)))
|
196
|
+
(every (lambda (char)
|
197
|
+
(or (digit-char-p char)
|
198
|
+
(member char '(#\e #\E #\. #\- #\+))))
|
199
|
+
string)))
|
200
|
+
|
201
|
+
(defun read-json-atom (stream)
|
202
|
+
(declare #.*optimize*)
|
203
|
+
(let ((accum (make-array 0 :element-type 'character :fill-pointer 0 :adjustable t)))
|
204
|
+
(loop
|
205
|
+
(let ((next (peek-char nil stream nil :eof)))
|
206
|
+
(when (or (ends-atom next) (eql next :eof))
|
207
|
+
(return))
|
208
|
+
(vector-push-extend next accum)
|
209
|
+
(read-char stream)))
|
210
|
+
(let ((number-val (and (looks-like-a-number accum)
|
211
|
+
(ignore-errors (read-from-string accum)))))
|
212
|
+
(cond ((numberp number-val) number-val)
|
213
|
+
((string= accum "false") :false)
|
214
|
+
((string= accum "true") :true)
|
215
|
+
((string= accum "null") :null)
|
216
|
+
((string= accum "undefined") :undefined)
|
217
|
+
((and *reading-slot-name*
|
218
|
+
(every (lambda (c)
|
219
|
+
(declare (type character c))
|
220
|
+
(or (alphanumericp c) (eql c #\_) (eql c #\$)))
|
221
|
+
accum))
|
222
|
+
accum)
|
223
|
+
(t (raise 'json-parse-error "Unrecognized value in JSON data: ~A" accum))))))
|
224
|
+
|
225
|
+
;; Writer
|
226
|
+
|
227
|
+
(defparameter *script-tag-hack* nil
|
228
|
+
"Bind this to T when writing JSON that will be written to an HTML
|
229
|
+
document. It prevents '</script>' from occurring in strings by
|
230
|
+
escaping any slash following a '<' character.")
|
231
|
+
|
232
|
+
(defun write-json-to-string (element)
|
233
|
+
"Write a value's JSON representation to a string."
|
234
|
+
(with-output-to-string (out)
|
235
|
+
(write-json element out)))
|
236
|
+
|
237
|
+
(defun write-json (element stream)
|
238
|
+
"Write a value's JSON representation to a stream."
|
239
|
+
(let ((*print-pretty* nil))
|
240
|
+
(write-json-element element stream)
|
241
|
+
(values)))
|
242
|
+
|
243
|
+
(defgeneric write-json-element (element stream)
|
244
|
+
(:method (element stream)
|
245
|
+
(declare (ignore stream))
|
246
|
+
(raise 'json-write-error "Can not write object of type ~A as JSON." (type-of element)))
|
247
|
+
(:documentation "Method used for writing values of a specific type.
|
248
|
+
You can specialise this for your own types."))
|
249
|
+
|
250
|
+
(defmethod write-json-element ((element symbol) stream)
|
251
|
+
(declare #.*optimize*)
|
252
|
+
(ecase element
|
253
|
+
((nil) (write-string "[]" stream))
|
254
|
+
((t :true) (write-string "true" stream))
|
255
|
+
(:false (write-string "false" stream))
|
256
|
+
(:undefined (write-string "undefined" stream))
|
257
|
+
(:null (write-string "null" stream))))
|
258
|
+
|
259
|
+
(defmethod write-json-element ((element string) stream)
|
260
|
+
(declare #.*optimize*)
|
261
|
+
(let ((element (coerce element 'simple-string)))
|
262
|
+
(write-char #\" stream)
|
263
|
+
(loop :for prev := nil :then ch
|
264
|
+
:for ch :across element
|
265
|
+
:do (princ
|
266
|
+
(case ch
|
267
|
+
(#\\ "\\\\") (#\" "\\\"")
|
268
|
+
(#\backspace "\\b") (#\newline "\\n")
|
269
|
+
(#\return "\\r") (#\page "\\f")
|
270
|
+
(#\tab "\\t")
|
271
|
+
;; Prevent </script> by escaping every #\/ that follows a #\<
|
272
|
+
(#\/ (if (and *script-tag-hack* (eql prev #\<)) "\\/" #\/))
|
273
|
+
(t ch))
|
274
|
+
stream))
|
275
|
+
(write-char #\" stream)))
|
276
|
+
|
277
|
+
(defmethod write-json-element ((element integer) stream)
|
278
|
+
(write element :stream stream))
|
279
|
+
|
280
|
+
(defmethod write-json-element ((element real) stream)
|
281
|
+
(format stream "~,,,,,,'eE" element))
|
282
|
+
|
283
|
+
(defmethod write-json-element ((element hash-table) stream)
|
284
|
+
(declare #.*optimize*)
|
285
|
+
(write-json-element
|
286
|
+
(make-jso :alist (loop :for key :being :the :hash-key :using (hash-value val) :of element
|
287
|
+
:collect (cons key val)))
|
288
|
+
stream))
|
289
|
+
|
290
|
+
(defmethod write-json-element ((element jso) stream)
|
291
|
+
(declare #.*optimize*)
|
292
|
+
(write-char #\{ stream)
|
293
|
+
(loop :for (key . val) :in (jso-alist element)
|
294
|
+
:for first := t :then nil
|
295
|
+
:unless first :do (write-char #\, stream)
|
296
|
+
:do (write-json-element key stream)
|
297
|
+
:do (write-char #\: stream)
|
298
|
+
:do (write-json-element val stream))
|
299
|
+
(write-char #\} stream))
|
300
|
+
|
301
|
+
(defmethod write-json-element ((element list) stream)
|
302
|
+
(declare #.*optimize*)
|
303
|
+
(write-char #\[ stream)
|
304
|
+
(let ((first t))
|
305
|
+
(dolist (part element)
|
306
|
+
(if first
|
307
|
+
(setf first nil)
|
308
|
+
(write-char #\, stream))
|
309
|
+
(write-json-element part stream)))
|
310
|
+
(write-char #\] stream))
|
@@ -0,0 +1,127 @@
|
|
1
|
+
(in-package #:trivial-backtrace)
|
2
|
+
|
3
|
+
(defun print-condition (condition stream)
|
4
|
+
"Print `condition` to `stream` using the pretty printer."
|
5
|
+
(format
|
6
|
+
stream
|
7
|
+
"~@<An unhandled error condition has been signalled:~3I ~a~I~:@>~%~%"
|
8
|
+
condition))
|
9
|
+
|
10
|
+
(defun print-backtrace (error &key (output *debug-io*)
|
11
|
+
(if-exists :append)
|
12
|
+
(verbose nil))
|
13
|
+
"Send a backtrace for the error `error` to `output`.
|
14
|
+
|
15
|
+
The keywords arguments are:
|
16
|
+
|
17
|
+
* :output - where to send the output. This can be:
|
18
|
+
|
19
|
+
* a string (which is assumed to designate a pathname)
|
20
|
+
* an open stream
|
21
|
+
* nil to indicate that the backtrace information should be
|
22
|
+
returned as a string
|
23
|
+
|
24
|
+
* if-exists - what to do if output designates a pathname and
|
25
|
+
the pathname already exists. Defaults to :append.
|
26
|
+
|
27
|
+
* verbose - if true, then a message about the backtrace is sent
|
28
|
+
to \\*terminal-io\\*. Defaults to `nil`.
|
29
|
+
|
30
|
+
If the `output` is nil, the returns the backtrace output as a
|
31
|
+
string. Otherwise, returns nil.
|
32
|
+
"
|
33
|
+
(when verbose
|
34
|
+
(print-condition error *terminal-io*))
|
35
|
+
(multiple-value-bind (stream close?)
|
36
|
+
(typecase output
|
37
|
+
(null (values (make-string-output-stream) nil))
|
38
|
+
(string (values (open output :if-exists if-exists
|
39
|
+
:if-does-not-exist :create
|
40
|
+
:direction :output) t))
|
41
|
+
(stream (values output nil)))
|
42
|
+
(unwind-protect
|
43
|
+
(progn
|
44
|
+
(format stream "~&Date/time: ~a" (date-time-string))
|
45
|
+
(print-condition error stream)
|
46
|
+
(terpri stream)
|
47
|
+
(print-backtrace-to-stream stream)
|
48
|
+
(terpri stream)
|
49
|
+
(when (typep stream 'string-stream)
|
50
|
+
(get-output-stream-string stream)))
|
51
|
+
;; cleanup
|
52
|
+
(when close?
|
53
|
+
(close stream)))))
|
54
|
+
|
55
|
+
#+(or mcl ccl)
|
56
|
+
(defun print-backtrace-to-stream (stream)
|
57
|
+
(let ((*debug-io* stream))
|
58
|
+
(ccl:print-call-history :detailed-p nil)))
|
59
|
+
|
60
|
+
#+allegro
|
61
|
+
(defun print-backtrace-to-stream (stream)
|
62
|
+
(with-standard-io-syntax
|
63
|
+
(let ((*print-readably* nil)
|
64
|
+
(*print-miser-width* 40)
|
65
|
+
(*print-pretty* t)
|
66
|
+
(tpl:*zoom-print-circle* t)
|
67
|
+
(tpl:*zoom-print-level* nil)
|
68
|
+
(tpl:*zoom-print-length* nil))
|
69
|
+
(cl:ignore-errors
|
70
|
+
(let ((*terminal-io* stream)
|
71
|
+
(*standard-output* stream))
|
72
|
+
(tpl:do-command "zoom"
|
73
|
+
:from-read-eval-print-loop nil
|
74
|
+
:count t
|
75
|
+
:all t))))))
|
76
|
+
|
77
|
+
#+lispworks
|
78
|
+
(defun print-backtrace-to-stream (stream)
|
79
|
+
(let ((dbg::*debugger-stack*
|
80
|
+
(dbg::grab-stack nil :how-many most-positive-fixnum))
|
81
|
+
(*debug-io* stream)
|
82
|
+
(dbg:*debug-print-level* nil)
|
83
|
+
(dbg:*debug-print-length* nil))
|
84
|
+
(dbg:bug-backtrace nil)))
|
85
|
+
|
86
|
+
#+sbcl
|
87
|
+
;; determine how we're going to access the backtrace in the next
|
88
|
+
;; function
|
89
|
+
(eval-when (:compile-toplevel :load-toplevel :execute)
|
90
|
+
(when (find-symbol "*DEBUG-PRINT-VARIABLE-ALIST*" :sb-debug)
|
91
|
+
(pushnew :sbcl-debug-print-variable-alist *features*)))
|
92
|
+
|
93
|
+
#+sbcl
|
94
|
+
(defun print-backtrace-to-stream (stream)
|
95
|
+
(let (#+:sbcl-debug-print-variable-alist
|
96
|
+
(sb-debug:*debug-print-variable-alist*
|
97
|
+
(list* '(*print-level* . nil)
|
98
|
+
'(*print-length* . nil)
|
99
|
+
sb-debug:*debug-print-variable-alist*))
|
100
|
+
#-:sbcl-debug-print-variable-alist
|
101
|
+
(sb-debug:*debug-print-level* nil)
|
102
|
+
#-:sbcl-debug-print-variable-alist
|
103
|
+
(sb-debug:*debug-print-length* nil))
|
104
|
+
(sb-debug:backtrace most-positive-fixnum stream)))
|
105
|
+
|
106
|
+
#+clisp
|
107
|
+
(defun print-backtrace-to-stream (stream)
|
108
|
+
(system::print-backtrace :out stream))
|
109
|
+
|
110
|
+
#+(or cmucl scl)
|
111
|
+
(defun print-backtrace-to-stream (stream)
|
112
|
+
(let ((debug:*debug-print-level* nil)
|
113
|
+
(debug:*debug-print-length* nil))
|
114
|
+
(debug:backtrace most-positive-fixnum stream)))
|
115
|
+
|
116
|
+
|
117
|
+
;; must be after the defun above or the docstring may be wiped out
|
118
|
+
(setf (documentation 'print-backtrace-to-stream 'function)
|
119
|
+
"Send a backtrace of the current error to stream.
|
120
|
+
|
121
|
+
Stream is assumed to be an open writable file stream or a
|
122
|
+
string-output-stream. Note that `print-backtrace-to-stream`
|
123
|
+
will print a backtrace for whatever the Lisp deems to be the
|
124
|
+
*current* error.
|
125
|
+
")
|
126
|
+
|
127
|
+
|
@@ -0,0 +1,10 @@
|
|
1
|
+
(in-package #:trivial-backtrace)
|
2
|
+
|
3
|
+
(eval-when (:compile-toplevel :load-toplevel :execute)
|
4
|
+
(unless (fboundp 'map-backtrace)
|
5
|
+
(defun map-backtrace (func)
|
6
|
+
(declare (ignore func))))
|
7
|
+
|
8
|
+
(unless (fboundp 'print-backtrace-to-stream)
|
9
|
+
(defun print-backtrace-to-stream (stream)
|
10
|
+
(format stream "~&backtrace output unavailable.~%"))))
|