clucumber 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (139) hide show
  1. data/LICENSE +1 -1
  2. data/README.md +4 -9
  3. data/lib/clucumber/clucumber-bootstrap.lisp +32 -0
  4. data/lib/clucumber/vendor/cl-interpol/alias.lisp +55 -0
  5. data/lib/clucumber/vendor/cl-interpol/cl-interpol.asd +56 -0
  6. data/lib/clucumber/vendor/cl-interpol/load.lisp +53 -0
  7. data/lib/clucumber/vendor/cl-interpol/packages.lisp +40 -0
  8. data/lib/clucumber/vendor/cl-interpol/read.lisp +716 -0
  9. data/lib/clucumber/vendor/cl-interpol/specials.lisp +113 -0
  10. data/lib/clucumber/vendor/cl-interpol/test/packages.lisp +34 -0
  11. data/lib/clucumber/vendor/cl-interpol/test/tests.lisp +128 -0
  12. data/lib/clucumber/vendor/cl-interpol/test.lisp +177 -0
  13. data/lib/clucumber/vendor/cl-interpol/test2.lisp +6254 -0
  14. data/lib/clucumber/vendor/cl-interpol/unicode.lisp +13912 -0
  15. data/lib/clucumber/vendor/cl-interpol/util.lisp +122 -0
  16. data/lib/clucumber/vendor/cl-ppcre/api.lisp +1262 -0
  17. data/lib/clucumber/vendor/cl-ppcre/charmap.lisp +152 -0
  18. data/lib/clucumber/vendor/cl-ppcre/charset.lisp +242 -0
  19. data/lib/clucumber/vendor/cl-ppcre/chartest.lisp +98 -0
  20. data/lib/clucumber/vendor/cl-ppcre/cl-ppcre-test.asd +34 -0
  21. data/lib/clucumber/vendor/cl-ppcre/cl-ppcre-unicode/packages.lisp +38 -0
  22. data/lib/clucumber/vendor/cl-ppcre/cl-ppcre-unicode/resolver.lisp +61 -0
  23. data/lib/clucumber/vendor/cl-ppcre/cl-ppcre-unicode.asd +58 -0
  24. data/lib/clucumber/vendor/cl-ppcre/cl-ppcre.asd +79 -0
  25. data/lib/clucumber/vendor/cl-ppcre/closures.lisp +471 -0
  26. data/lib/clucumber/vendor/cl-ppcre/convert.lisp +875 -0
  27. data/lib/clucumber/vendor/cl-ppcre/errors.lisp +84 -0
  28. data/lib/clucumber/vendor/cl-ppcre/lexer.lisp +737 -0
  29. data/lib/clucumber/vendor/cl-ppcre/lispworks-defsystem.lisp +57 -0
  30. data/lib/clucumber/vendor/cl-ppcre/load.lisp +67 -0
  31. data/lib/clucumber/vendor/cl-ppcre/optimize.lisp +578 -0
  32. data/lib/clucumber/vendor/cl-ppcre/packages.lisp +68 -0
  33. data/lib/clucumber/vendor/cl-ppcre/parser.lisp +319 -0
  34. data/lib/clucumber/vendor/cl-ppcre/ppcre-tests.lisp +269 -0
  35. data/lib/clucumber/vendor/cl-ppcre/regex-class-util.lisp +555 -0
  36. data/lib/clucumber/vendor/cl-ppcre/regex-class.lisp +259 -0
  37. data/lib/clucumber/vendor/cl-ppcre/repetition-closures.lisp +833 -0
  38. data/lib/clucumber/vendor/cl-ppcre/scanner.lisp +506 -0
  39. data/lib/clucumber/vendor/cl-ppcre/specials.lisp +172 -0
  40. data/lib/clucumber/vendor/cl-ppcre/test/packages.lisp +37 -0
  41. data/lib/clucumber/vendor/cl-ppcre/test/perl-tests.lisp +150 -0
  42. data/lib/clucumber/vendor/cl-ppcre/test/tests.lisp +159 -0
  43. data/lib/clucumber/vendor/cl-ppcre/test/unicode-tests.lisp +80 -0
  44. data/lib/clucumber/vendor/cl-ppcre/util.lisp +201 -0
  45. data/lib/clucumber/vendor/cl-unicode/alias.lisp +135 -0
  46. data/lib/clucumber/vendor/cl-unicode/api.lisp +412 -0
  47. data/lib/clucumber/vendor/cl-unicode/build/char-info.lisp +133 -0
  48. data/lib/clucumber/vendor/cl-unicode/build/dump.lisp +239 -0
  49. data/lib/clucumber/vendor/cl-unicode/build/read.lisp +280 -0
  50. data/lib/clucumber/vendor/cl-unicode/build/util.lisp +182 -0
  51. data/lib/clucumber/vendor/cl-unicode/cl-unicode.asd +90 -0
  52. data/lib/clucumber/vendor/cl-unicode/conditions.lisp +54 -0
  53. data/lib/clucumber/vendor/cl-unicode/derived.lisp +120 -0
  54. data/lib/clucumber/vendor/cl-unicode/hash-tables.lisp +20 -0
  55. data/lib/clucumber/vendor/cl-unicode/lists.lisp +10 -0
  56. data/lib/clucumber/vendor/cl-unicode/methods.lisp +15 -0
  57. data/lib/clucumber/vendor/cl-unicode/packages.lisp +76 -0
  58. data/lib/clucumber/vendor/cl-unicode/specials.lisp +135 -0
  59. data/lib/clucumber/vendor/cl-unicode/test/packages.lisp +34 -0
  60. data/lib/clucumber/vendor/cl-unicode/test/tests.lisp +150 -0
  61. data/lib/clucumber/vendor/cl-unicode/test-functions.lisp +94 -0
  62. data/lib/clucumber/vendor/cl-unicode/util.lisp +274 -0
  63. data/lib/clucumber/vendor/lift/compare/fiveam-tests.lisp +14 -0
  64. data/lib/clucumber/vendor/lift/compare/lift-tests.lisp +13 -0
  65. data/lib/clucumber/vendor/lift/compare/rt-tests.lisp +16 -0
  66. data/lib/clucumber/vendor/lift/compare/xlunit-tests.lisp +15 -0
  67. data/lib/clucumber/vendor/lift/dev/changes.lisp +61 -0
  68. data/lib/clucumber/vendor/lift/dev/config.lisp +354 -0
  69. data/lib/clucumber/vendor/lift/dev/copy-file.lisp +117 -0
  70. data/lib/clucumber/vendor/lift/dev/introspection.lisp +232 -0
  71. data/lib/clucumber/vendor/lift/dev/lift-interface.lisp +56 -0
  72. data/lib/clucumber/vendor/lift/dev/lift-notes.lisp +202 -0
  73. data/lib/clucumber/vendor/lift/dev/lift-randomized.lisp +45 -0
  74. data/lib/clucumber/vendor/lift/dev/lift.lisp +2383 -0
  75. data/lib/clucumber/vendor/lift/dev/macros.lisp +229 -0
  76. data/lib/clucumber/vendor/lift/dev/measuring.lisp +156 -0
  77. data/lib/clucumber/vendor/lift/dev/packages.lisp +161 -0
  78. data/lib/clucumber/vendor/lift/dev/port.lisp +151 -0
  79. data/lib/clucumber/vendor/lift/dev/prototypes.lisp +282 -0
  80. data/lib/clucumber/vendor/lift/dev/random-testing.lisp +124 -0
  81. data/lib/clucumber/vendor/lift/dev/report-locations.lisp +13 -0
  82. data/lib/clucumber/vendor/lift/dev/reports.lisp +916 -0
  83. data/lib/clucumber/vendor/lift/dev/utilities.lisp +242 -0
  84. data/lib/clucumber/vendor/lift/docs/package.lisp +6 -0
  85. data/lib/clucumber/vendor/lift/docs/setup.lisp +17 -0
  86. data/lib/clucumber/vendor/lift/examples/basic-examples.lisp +289 -0
  87. data/lib/clucumber/vendor/lift/examples/random-testing.lisp +32 -0
  88. data/lib/clucumber/vendor/lift/lift-documentation.asd +28 -0
  89. data/lib/clucumber/vendor/lift/lift-test.asd +35 -0
  90. data/lib/clucumber/vendor/lift/lift.asd +77 -0
  91. data/lib/clucumber/vendor/lift/test/equality-tests.lisp +40 -0
  92. data/lib/clucumber/vendor/lift/test/finding-tests.lisp +32 -0
  93. data/lib/clucumber/vendor/lift/test/lift-test.lisp +783 -0
  94. data/lib/clucumber/vendor/lift/test/order-of-operations.lisp +54 -0
  95. data/lib/clucumber/vendor/lift/test/packages.lisp +17 -0
  96. data/lib/clucumber/vendor/lift/test/test-config-files.lisp +20 -0
  97. data/lib/clucumber/vendor/lift/test/test-dynamic-variables.lisp +57 -0
  98. data/lib/clucumber/vendor/lift/test/test-maximum-problems.lisp +74 -0
  99. data/lib/clucumber/vendor/lift/test/test-prototypes.lisp +278 -0
  100. data/lib/clucumber/vendor/lift/test/test-timeout.lisp +37 -0
  101. data/lib/clucumber/vendor/lift/test/tests-in-progress.lisp +62 -0
  102. data/lib/clucumber/vendor/lift/test/testsuite-expects.lisp +60 -0
  103. data/lib/clucumber/vendor/lift/timeout/package.lisp +13 -0
  104. data/lib/clucumber/vendor/lift/timeout/with-timeout.lisp +123 -0
  105. data/lib/clucumber/vendor/lift/website/stuff/Temp.lisp +34 -0
  106. data/lib/clucumber/vendor/st-json/st-json.asd +3 -0
  107. data/lib/clucumber/vendor/st-json/st-json.lisp +310 -0
  108. data/lib/clucumber/vendor/trivial-backtrace/dev/backtrace.lisp +127 -0
  109. data/lib/clucumber/vendor/trivial-backtrace/dev/fallback.lisp +10 -0
  110. data/lib/clucumber/vendor/trivial-backtrace/dev/map-backtrace.lisp +103 -0
  111. data/lib/clucumber/vendor/trivial-backtrace/dev/mucking.lisp +75 -0
  112. data/lib/clucumber/vendor/trivial-backtrace/dev/packages.lisp +13 -0
  113. data/lib/clucumber/vendor/trivial-backtrace/dev/utilities.lisp +104 -0
  114. data/lib/clucumber/vendor/trivial-backtrace/test/packages.lisp +5 -0
  115. data/lib/clucumber/vendor/trivial-backtrace/test/test-setup.lisp +4 -0
  116. data/lib/clucumber/vendor/trivial-backtrace/test/tests.lisp +16 -0
  117. data/lib/clucumber/vendor/trivial-backtrace/trivial-backtrace-test.asd +22 -0
  118. data/lib/clucumber/vendor/trivial-backtrace/trivial-backtrace.asd +35 -0
  119. data/lib/clucumber/vendor/usocket/backend/allegro.lisp +199 -0
  120. data/lib/clucumber/vendor/usocket/backend/armedbear.lisp +491 -0
  121. data/lib/clucumber/vendor/usocket/backend/clisp.lisp +260 -0
  122. data/lib/clucumber/vendor/usocket/backend/cmucl.lisp +266 -0
  123. data/lib/clucumber/vendor/usocket/backend/lispworks.lisp +741 -0
  124. data/lib/clucumber/vendor/usocket/backend/mcl.lisp +369 -0
  125. data/lib/clucumber/vendor/usocket/backend/openmcl.lisp +206 -0
  126. data/lib/clucumber/vendor/usocket/backend/sbcl.lisp +424 -0
  127. data/lib/clucumber/vendor/usocket/backend/scl.lisp +261 -0
  128. data/lib/clucumber/vendor/usocket/condition.lisp +227 -0
  129. data/lib/clucumber/vendor/usocket/package.lisp +82 -0
  130. data/lib/clucumber/vendor/usocket/server.lisp +45 -0
  131. data/lib/clucumber/vendor/usocket/test/package.lisp +13 -0
  132. data/lib/clucumber/vendor/usocket/test/test-usocket.lisp +166 -0
  133. data/lib/clucumber/vendor/usocket/usocket-test.asd +26 -0
  134. data/lib/clucumber/vendor/usocket/usocket.asd +37 -0
  135. data/lib/clucumber/vendor/usocket/usocket.lisp +542 -0
  136. data/lib/clucumber/vendor/usocket/vendor/kqueue.lisp +1 -0
  137. data/lib/clucumber/vendor/usocket/vendor/split-sequence.lisp +245 -0
  138. data/lib/clucumber.rb +29 -7
  139. 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,3 @@
1
+ (asdf:defsystem :st-json
2
+ :depends-on ()
3
+ :components ((:file "st-json")))
@@ -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.~%"))))