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,319 @@
1
+ ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-PPCRE; Base: 10 -*-
2
+ ;;; $Header: /usr/local/cvsrep/cl-ppcre/parser.lisp,v 1.31 2009/09/17 19:17:31 edi Exp $
3
+
4
+ ;;; The parser will - with the help of the lexer - parse a regex
5
+ ;;; string and convert it into a "parse tree" (see docs for details
6
+ ;;; about the syntax of these trees). Note that the lexer might
7
+ ;;; return illegal parse trees. It is assumed that the conversion
8
+ ;;; process later on will track them down.
9
+
10
+ ;;; Copyright (c) 2002-2009, Dr. Edmund Weitz. All rights reserved.
11
+
12
+ ;;; Redistribution and use in source and binary forms, with or without
13
+ ;;; modification, are permitted provided that the following conditions
14
+ ;;; are met:
15
+
16
+ ;;; * Redistributions of source code must retain the above copyright
17
+ ;;; notice, this list of conditions and the following disclaimer.
18
+
19
+ ;;; * Redistributions in binary form must reproduce the above
20
+ ;;; copyright notice, this list of conditions and the following
21
+ ;;; disclaimer in the documentation and/or other materials
22
+ ;;; provided with the distribution.
23
+
24
+ ;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED
25
+ ;;; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26
+ ;;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27
+ ;;; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
28
+ ;;; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29
+ ;;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
30
+ ;;; GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31
+ ;;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
32
+ ;;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
33
+ ;;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
34
+ ;;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35
+
36
+ (in-package :cl-ppcre)
37
+
38
+ (defun group (lexer)
39
+ "Parses and consumes a <group>.
40
+ The productions are: <group> -> \"\(\"<regex>\")\"
41
+ \"\(?:\"<regex>\")\"
42
+ \"\(?>\"<regex>\")\"
43
+ \"\(?<flags>:\"<regex>\")\"
44
+ \"\(?=\"<regex>\")\"
45
+ \"\(?!\"<regex>\")\"
46
+ \"\(?<=\"<regex>\")\"
47
+ \"\(?<!\"<regex>\")\"
48
+ \"\(?\(\"<num>\")\"<regex>\")\"
49
+ \"\(?\(\"<regex>\")\"<regex>\")\"
50
+ \"\(?<name>\"<regex>\")\" \(when *ALLOW-NAMED-REGISTERS* is T)
51
+ <legal-token>
52
+ where <flags> is parsed by the lexer function MAYBE-PARSE-FLAGS.
53
+ Will return <parse-tree> or \(<grouping-type> <parse-tree>) where
54
+ <grouping-type> is one of six keywords - see source for details."
55
+ (declare #.*standard-optimize-settings*)
56
+ (multiple-value-bind (open-token flags)
57
+ (get-token lexer)
58
+ (cond ((eq open-token :open-paren-paren)
59
+ ;; special case for conditional regular expressions; note
60
+ ;; that at this point we accept a couple of illegal
61
+ ;; combinations which'll be sorted out later by the
62
+ ;; converter
63
+ (let* ((open-paren-pos (car (lexer-last-pos lexer)))
64
+ ;; check if what follows "(?(" is a number
65
+ (number (try-number lexer :no-whitespace-p t))
66
+ ;; make changes to extended-mode-p local
67
+ (*extended-mode-p* *extended-mode-p*))
68
+ (declare (fixnum open-paren-pos))
69
+ (cond (number
70
+ ;; condition is a number (i.e. refers to a
71
+ ;; back-reference)
72
+ (let* ((inner-close-token (get-token lexer))
73
+ (reg-expr (reg-expr lexer))
74
+ (close-token (get-token lexer)))
75
+ (unless (eq inner-close-token :close-paren)
76
+ (signal-syntax-error* (+ open-paren-pos 2)
77
+ "Opening paren has no matching closing paren."))
78
+ (unless (eq close-token :close-paren)
79
+ (signal-syntax-error* open-paren-pos
80
+ "Opening paren has no matching closing paren."))
81
+ (list :branch number reg-expr)))
82
+ (t
83
+ ;; condition must be a full regex (actually a
84
+ ;; look-behind or look-ahead); and here comes a
85
+ ;; terrible kludge: instead of being cleanly
86
+ ;; separated from the lexer, the parser pushes
87
+ ;; back the lexer by one position, thereby
88
+ ;; landing in the middle of the 'token' "(?(" -
89
+ ;; yuck!!
90
+ (decf (lexer-pos lexer))
91
+ (let* ((inner-reg-expr (group lexer))
92
+ (reg-expr (reg-expr lexer))
93
+ (close-token (get-token lexer)))
94
+ (unless (eq close-token :close-paren)
95
+ (signal-syntax-error* open-paren-pos
96
+ "Opening paren has no matching closing paren."))
97
+ (list :branch inner-reg-expr reg-expr))))))
98
+ ((member open-token '(:open-paren
99
+ :open-paren-colon
100
+ :open-paren-greater
101
+ :open-paren-equal
102
+ :open-paren-exclamation
103
+ :open-paren-less-equal
104
+ :open-paren-less-exclamation
105
+ :open-paren-less-letter)
106
+ :test #'eq)
107
+ ;; make changes to extended-mode-p local
108
+ (let ((*extended-mode-p* *extended-mode-p*))
109
+ ;; we saw one of the six token representing opening
110
+ ;; parentheses
111
+ (let* ((open-paren-pos (car (lexer-last-pos lexer)))
112
+ (register-name (when (eq open-token :open-paren-less-letter)
113
+ (parse-register-name-aux lexer)))
114
+ (reg-expr (reg-expr lexer))
115
+ (close-token (get-token lexer)))
116
+ (when (or (eq open-token :open-paren)
117
+ (eq open-token :open-paren-less-letter))
118
+ ;; if this is the "("<regex>")" or "(?"<name>""<regex>")" production we have to
119
+ ;; increment the register counter of the lexer
120
+ (incf (lexer-reg lexer)))
121
+ (unless (eq close-token :close-paren)
122
+ ;; the token following <regex> must be the closing
123
+ ;; parenthesis or this is a syntax error
124
+ (signal-syntax-error* open-paren-pos
125
+ "Opening paren has no matching closing paren."))
126
+ (if flags
127
+ ;; if the lexer has returned a list of flags this must
128
+ ;; have been the "(?:"<regex>")" production
129
+ (cons :group (nconc flags (list reg-expr)))
130
+ (if (eq open-token :open-paren-less-letter)
131
+ (list :named-register
132
+ ;; every string was reversed, so we have to
133
+ ;; reverse it back to get the name
134
+ (nreverse register-name)
135
+ reg-expr)
136
+ (list (case open-token
137
+ ((:open-paren)
138
+ :register)
139
+ ((:open-paren-colon)
140
+ :group)
141
+ ((:open-paren-greater)
142
+ :standalone)
143
+ ((:open-paren-equal)
144
+ :positive-lookahead)
145
+ ((:open-paren-exclamation)
146
+ :negative-lookahead)
147
+ ((:open-paren-less-equal)
148
+ :positive-lookbehind)
149
+ ((:open-paren-less-exclamation)
150
+ :negative-lookbehind))
151
+ reg-expr))))))
152
+ (t
153
+ ;; this is the <legal-token> production; <legal-token> is
154
+ ;; any token which passes START-OF-SUBEXPR-P (otherwise
155
+ ;; parsing had already stopped in the SEQ method)
156
+ open-token))))
157
+
158
+ (defun greedy-quant (lexer)
159
+ "Parses and consumes a <greedy-quant>.
160
+ The productions are: <greedy-quant> -> <group> | <group><quantifier>
161
+ where <quantifier> is parsed by the lexer function GET-QUANTIFIER.
162
+ Will return <parse-tree> or (:GREEDY-REPETITION <min> <max> <parse-tree>)."
163
+ (declare #.*standard-optimize-settings*)
164
+ (let* ((group (group lexer))
165
+ (token (get-quantifier lexer)))
166
+ (if token
167
+ ;; if GET-QUANTIFIER returned a non-NIL value it's the
168
+ ;; two-element list (<min> <max>)
169
+ (list :greedy-repetition (first token) (second token) group)
170
+ group)))
171
+
172
+ (defun quant (lexer)
173
+ "Parses and consumes a <quant>.
174
+ The productions are: <quant> -> <greedy-quant> | <greedy-quant>\"?\".
175
+ Will return the <parse-tree> returned by GREEDY-QUANT and optionally
176
+ change :GREEDY-REPETITION to :NON-GREEDY-REPETITION."
177
+ (declare #.*standard-optimize-settings*)
178
+ (let* ((greedy-quant (greedy-quant lexer))
179
+ (pos (lexer-pos lexer))
180
+ (next-char (next-char lexer)))
181
+ (when next-char
182
+ (if (char= next-char #\?)
183
+ (setf (car greedy-quant) :non-greedy-repetition)
184
+ (setf (lexer-pos lexer) pos)))
185
+ greedy-quant))
186
+
187
+ (defun seq (lexer)
188
+ "Parses and consumes a <seq>.
189
+ The productions are: <seq> -> <quant> | <quant><seq>.
190
+ Will return <parse-tree> or (:SEQUENCE <parse-tree> <parse-tree>)."
191
+ (declare #.*standard-optimize-settings*)
192
+ (flet ((make-array-from-two-chars (char1 char2)
193
+ (let ((string (make-array 2
194
+ :element-type 'character
195
+ :fill-pointer t
196
+ :adjustable t)))
197
+ (setf (aref string 0) char1)
198
+ (setf (aref string 1) char2)
199
+ string)))
200
+ ;; Note that we're calling START-OF-SUBEXPR-P before we actually try
201
+ ;; to parse a <seq> or <quant> in order to catch empty regular
202
+ ;; expressions
203
+ (if (start-of-subexpr-p lexer)
204
+ (let ((quant (quant lexer)))
205
+ (if (start-of-subexpr-p lexer)
206
+ (let* ((seq (seq lexer))
207
+ (quant-is-char-p (characterp quant))
208
+ (seq-is-sequence-p (and (consp seq)
209
+ (eq (first seq) :sequence))))
210
+ (cond ((and quant-is-char-p
211
+ (characterp seq))
212
+ (make-array-from-two-chars seq quant))
213
+ ((and quant-is-char-p
214
+ (stringp seq))
215
+ (vector-push-extend quant seq)
216
+ seq)
217
+ ((and quant-is-char-p
218
+ seq-is-sequence-p
219
+ (characterp (second seq)))
220
+ (cond ((cddr seq)
221
+ (setf (cdr seq)
222
+ (cons
223
+ (make-array-from-two-chars (second seq)
224
+ quant)
225
+ (cddr seq)))
226
+ seq)
227
+ (t (make-array-from-two-chars (second seq) quant))))
228
+ ((and quant-is-char-p
229
+ seq-is-sequence-p
230
+ (stringp (second seq)))
231
+ (cond ((cddr seq)
232
+ (setf (cdr seq)
233
+ (cons
234
+ (progn
235
+ (vector-push-extend quant (second seq))
236
+ (second seq))
237
+ (cddr seq)))
238
+ seq)
239
+ (t
240
+ (vector-push-extend quant (second seq))
241
+ (second seq))))
242
+ (seq-is-sequence-p
243
+ ;; if <seq> is also a :SEQUENCE parse tree we merge
244
+ ;; both lists into one to avoid unnecessary consing
245
+ (setf (cdr seq)
246
+ (cons quant (cdr seq)))
247
+ seq)
248
+ (t (list :sequence quant seq))))
249
+ quant))
250
+ :void)))
251
+
252
+ (defun reg-expr (lexer)
253
+ "Parses and consumes a <regex>, a complete regular expression.
254
+ The productions are: <regex> -> <seq> | <seq>\"|\"<regex>.
255
+ Will return <parse-tree> or (:ALTERNATION <parse-tree> <parse-tree>)."
256
+ (declare #.*standard-optimize-settings*)
257
+ (let ((pos (lexer-pos lexer)))
258
+ (case (next-char lexer)
259
+ ((nil)
260
+ ;; if we didn't get any token we return :VOID which stands for
261
+ ;; "empty regular expression"
262
+ :void)
263
+ ((#\|)
264
+ ;; now check whether the expression started with a vertical
265
+ ;; bar, i.e. <seq> - the left alternation - is empty
266
+ (list :alternation :void (reg-expr lexer)))
267
+ (otherwise
268
+ ;; otherwise un-read the character we just saw and parse a
269
+ ;; <seq> plus the character following it
270
+ (setf (lexer-pos lexer) pos)
271
+ (let* ((seq (seq lexer))
272
+ (pos (lexer-pos lexer)))
273
+ (case (next-char lexer)
274
+ ((nil)
275
+ ;; no further character, just a <seq>
276
+ seq)
277
+ ((#\|)
278
+ ;; if the character was a vertical bar, this is an
279
+ ;; alternation and we have the second production
280
+ (let ((reg-expr (reg-expr lexer)))
281
+ (cond ((and (consp reg-expr)
282
+ (eq (first reg-expr) :alternation))
283
+ ;; again we try to merge as above in SEQ
284
+ (setf (cdr reg-expr)
285
+ (cons seq (cdr reg-expr)))
286
+ reg-expr)
287
+ (t (list :alternation seq reg-expr)))))
288
+ (otherwise
289
+ ;; a character which is not a vertical bar - this is
290
+ ;; either a syntax error or we're inside of a group and
291
+ ;; the next character is a closing parenthesis; so we
292
+ ;; just un-read the character and let another function
293
+ ;; take care of it
294
+ (setf (lexer-pos lexer) pos)
295
+ seq)))))))
296
+
297
+ (defun reverse-strings (parse-tree)
298
+ "Recursively walks through PARSE-TREE and destructively reverses all
299
+ strings in it."
300
+ (declare #.*standard-optimize-settings*)
301
+ (cond ((stringp parse-tree)
302
+ (nreverse parse-tree))
303
+ ((consp parse-tree)
304
+ (loop for parse-tree-rest on parse-tree
305
+ while parse-tree-rest
306
+ do (setf (car parse-tree-rest)
307
+ (reverse-strings (car parse-tree-rest))))
308
+ parse-tree)
309
+ (t parse-tree)))
310
+
311
+ (defun parse-string (string)
312
+ "Translate the regex string STRING into a parse tree."
313
+ (declare #.*standard-optimize-settings*)
314
+ (let* ((lexer (make-lexer string))
315
+ (parse-tree (reverse-strings (reg-expr lexer))))
316
+ ;; check whether we've consumed the whole regex string
317
+ (if (end-of-string-p lexer)
318
+ parse-tree
319
+ (signal-syntax-error* (lexer-pos lexer) "Expected end of string."))))
@@ -0,0 +1,269 @@
1
+ ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-PPCRE-TEST; Base: 10 -*-
2
+ ;;; $Header: /usr/local/cvsrep/cl-ppcre/ppcre-tests.lisp,v 1.36 2008/06/25 14:04:28 edi Exp $
3
+
4
+ ;;; Copyright (c) 2002-2008, Dr. Edmund Weitz. All rights reserved.
5
+
6
+ ;;; Redistribution and use in source and binary forms, with or without
7
+ ;;; modification, are permitted provided that the following conditions
8
+ ;;; are met:
9
+
10
+ ;;; * Redistributions of source code must retain the above copyright
11
+ ;;; notice, this list of conditions and the following disclaimer.
12
+
13
+ ;;; * Redistributions in binary form must reproduce the above
14
+ ;;; copyright notice, this list of conditions and the following
15
+ ;;; disclaimer in the documentation and/or other materials
16
+ ;;; provided with the distribution.
17
+
18
+ ;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED
19
+ ;;; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20
+ ;;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
+ ;;; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
22
+ ;;; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
+ ;;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
24
+ ;;; GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25
+ ;;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26
+ ;;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27
+ ;;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28
+ ;;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
+
30
+ (in-package #:cl-ppcre-test)
31
+
32
+ (defparameter *cl-ppcre-test-base-directory*
33
+ (make-pathname :name nil :type nil :version nil
34
+ :defaults (parse-namestring *load-truename*)))
35
+
36
+ (defun full-gc ()
37
+ "Start a full garbage collection."
38
+ ;; what are the corresponding values for MCL and OpenMCL?
39
+ #+:allegro (excl:gc t)
40
+ #+(or :cmu :scl) (ext:gc :full t)
41
+ #+:ecl (si:gc t)
42
+ #+:clisp (ext:gc)
43
+ #+:cormanlisp (loop for i from 0 to 3 do (cormanlisp:gc i))
44
+ #+:lispworks4 (hcl:mark-and-sweep 3)
45
+ #+:lispworks5 (hcl:gc-generation #+:lispworks-32bit 3 #+:lispworks-64bit :blocking-gen-num)
46
+ #+:sbcl (sb-ext:gc :full t))
47
+
48
+ ;; warning: ugly code ahead!!
49
+ ;; this is just a quick hack for testing purposes
50
+
51
+ (defun time-regex (factor regex string
52
+ &key case-insensitive-mode
53
+ multi-line-mode
54
+ single-line-mode
55
+ extended-mode)
56
+ (declare #.ppcre::*standard-optimize-settings*)
57
+ "Auxiliary function used by TEST to benchmark a regex scanner
58
+ against Perl timings."
59
+ (declare (type string string))
60
+ (let* ((scanner (create-scanner regex
61
+ :case-insensitive-mode case-insensitive-mode
62
+ :multi-line-mode multi-line-mode
63
+ :single-line-mode single-line-mode
64
+ :extended-mode extended-mode))
65
+ ;; make sure GC doesn't invalidate our benchmarking
66
+ (dummy (full-gc))
67
+ (start (get-internal-real-time)))
68
+ (declare (ignore dummy))
69
+ (dotimes (i factor)
70
+ (funcall scanner string 0 (length string)))
71
+ (float (/ (- (get-internal-real-time) start) internal-time-units-per-second))))
72
+
73
+ #+(or scl
74
+ lispworks
75
+ (and sbcl sb-thread))
76
+ (defun threaded-scan (scanner target-string &key (threads 10) (repetitions 5000))
77
+ (declare #.ppcre::*standard-optimize-settings*)
78
+ "Auxiliary function used by TEST to check whether SCANNER is thread-safe."
79
+ (full-gc)
80
+ (let ((collector (make-array threads))
81
+ (counter 0))
82
+ (loop for i below threads
83
+ do (let* ((j i)
84
+ (fn
85
+ (lambda ()
86
+ (let ((r (random repetitions)))
87
+ (loop for k below repetitions
88
+ if (= k r)
89
+ do (setf (aref collector j)
90
+ (let ((result
91
+ (multiple-value-list
92
+ (cl-ppcre:scan scanner target-string))))
93
+ (unless (cdr result)
94
+ (setq result '(nil nil #() #())))
95
+ result))
96
+ else
97
+ do (cl-ppcre:scan scanner target-string))
98
+ (incf counter)))))
99
+ #+scl (thread:thread-create fn)
100
+ #+lispworks (mp:process-run-function "" nil fn)
101
+ #+(and sbcl sb-thread) (sb-thread:make-thread fn)))
102
+ (loop while (< counter threads)
103
+ do (sleep .1))
104
+ (destructuring-bind (first-start first-end first-reg-starts first-reg-ends)
105
+ (aref collector 0)
106
+ (loop for (start end reg-starts reg-ends) across collector
107
+ if (or (not (eql first-start start))
108
+ (not (eql first-end end))
109
+ (/= (length first-reg-starts) (length reg-starts))
110
+ (/= (length first-reg-ends) (length reg-ends))
111
+ (loop for first-reg-start across first-reg-starts
112
+ for reg-start across reg-starts
113
+ thereis (not (eql first-reg-start reg-start)))
114
+ (loop for first-reg-end across first-reg-ends
115
+ for reg-end across reg-ends
116
+ thereis (not (eql first-reg-end reg-end))))
117
+ do (return (format nil "~&Inconsistent results during multi-threading"))))))
118
+
119
+ (defun create-string-from-input (input)
120
+ (cond ((or (null input)
121
+ (stringp input))
122
+ input)
123
+ (t
124
+ (cl-ppcre::string-list-to-simple-string
125
+ (loop for element in input
126
+ if (stringp element)
127
+ collect element
128
+ else
129
+ collect (string (code-char element)))))))
130
+
131
+ (defun test (&key (file-name
132
+ (make-pathname :name "testdata"
133
+ :type nil :version nil
134
+ :defaults *cl-ppcre-test-base-directory*)
135
+ file-name-provided-p)
136
+ threaded)
137
+ (declare #.ppcre::*standard-optimize-settings*)
138
+ (declare (ignorable threaded))
139
+ "Loop through all test cases in FILE-NAME and print report. Only in
140
+ LispWorks and SCL: If THREADED is true, also test whether the scanners
141
+ work multi-threaded."
142
+ (with-open-file (stream file-name
143
+ #+(or :allegro :clisp :scl :sbcl)
144
+ :external-format
145
+ #+(or :allegro :clisp :scl :sbcl)
146
+ (if file-name-provided-p
147
+ :default
148
+ #+(or :allegro :scl :sbcl) :iso-8859-1
149
+ #+:clisp charset:iso-8859-1))
150
+ (loop with testcount of-type fixnum = 0
151
+ with *regex-char-code-limit* = (if file-name-provided-p
152
+ *regex-char-code-limit*
153
+ ;; the standard test suite
154
+ ;; doesn't need Unicode
155
+ ;; support
156
+ 256)
157
+ with *allow-quoting* = (if file-name-provided-p
158
+ *allow-quoting*
159
+ t)
160
+ for input-line = (read stream nil nil)
161
+ for (counter info-string regex
162
+ case-insensitive-mode multi-line-mode
163
+ single-line-mode extended-mode
164
+ string perl-error factor
165
+ perl-time ex-result ex-subs) = input-line
166
+ while input-line
167
+ do (let ((info-string (create-string-from-input info-string))
168
+ (regex (create-string-from-input regex))
169
+ (string (create-string-from-input string))
170
+ (ex-result (create-string-from-input ex-result))
171
+ (ex-subs (mapcar #'create-string-from-input ex-subs))
172
+ (errors '()))
173
+ ;; provide some visual feedback for slow CL
174
+ ;; implementations; suggested by JP Massar
175
+ (incf testcount)
176
+ #+(or scl
177
+ lispworks
178
+ (and sbcl sb-thread))
179
+ (when threaded
180
+ (format t "Test #~A (ID ~A)~%" testcount counter)
181
+ (force-output))
182
+ (unless #-(or scl
183
+ lispworks
184
+ (and sbcl sb-thread))
185
+ nil
186
+ #+(or scl
187
+ lispworks
188
+ (and sbcl sb-thread))
189
+ threaded
190
+ (when (zerop (mod testcount 10))
191
+ (format t ".")
192
+ (force-output))
193
+ (when (zerop (mod testcount 100))
194
+ (terpri)))
195
+ (handler-case
196
+ (let* ((*use-bmh-matchers* (if (and (> factor 1) (plusp perl-time))
197
+ *use-bmh-matchers*
198
+ ;; if we only check for
199
+ ;; correctness we don't
200
+ ;; care about speed that
201
+ ;; match (but rather
202
+ ;; about space
203
+ ;; constraints of the
204
+ ;; trial versions)
205
+ nil))
206
+ (scanner (create-scanner regex
207
+ :case-insensitive-mode case-insensitive-mode
208
+ :multi-line-mode multi-line-mode
209
+ :single-line-mode single-line-mode
210
+ :extended-mode extended-mode)))
211
+ (multiple-value-bind (result1 result2 sub-starts sub-ends)
212
+ (scan scanner string)
213
+ (cond (perl-error
214
+ (push (format nil
215
+ "~&expected an error but got a result")
216
+ errors))
217
+ (t
218
+ (when (not (eq result1 ex-result))
219
+ (if result1
220
+ (let ((result (subseq string result1 result2)))
221
+ (unless (string= result ex-result)
222
+ (push (format nil
223
+ "~&expected ~S but got ~S"
224
+ ex-result result)
225
+ errors))
226
+ (setq sub-starts (coerce sub-starts 'list)
227
+ sub-ends (coerce sub-ends 'list))
228
+ (loop for i from 0
229
+ for ex-sub in ex-subs
230
+ for sub-start = (nth i sub-starts)
231
+ for sub-end = (nth i sub-ends)
232
+ for sub = (if (and sub-start sub-end)
233
+ (subseq string sub-start sub-end)
234
+ nil)
235
+ unless (string= ex-sub sub)
236
+ do (push (format nil
237
+ "~&\\~A: expected ~S but got ~S"
238
+ (1+ i) ex-sub sub) errors)))
239
+ (push (format nil
240
+ "~&expected ~S but got ~S"
241
+ ex-result result1)
242
+ errors)))))
243
+ #+(or scl
244
+ lispworks
245
+ (and sbcl sb-thread))
246
+ (when threaded
247
+ (let ((thread-result (threaded-scan scanner string)))
248
+ (when thread-result
249
+ (push thread-result errors))))))
250
+ (condition (msg)
251
+ (unless perl-error
252
+ (push (format nil "~&got an unexpected error: '~A'" msg)
253
+ errors))))
254
+ (setq errors (nreverse errors))
255
+ (cond (errors
256
+ (when (or (<= factor 1) (zerop perl-time))
257
+ (format t "~&~4@A (~A):~{~& ~A~}~%"
258
+ counter info-string errors)))
259
+ ((and (> factor 1) (plusp perl-time))
260
+ (let ((result (time-regex factor regex string
261
+ :case-insensitive-mode case-insensitive-mode
262
+ :multi-line-mode multi-line-mode
263
+ :single-line-mode single-line-mode
264
+ :extended-mode extended-mode)))
265
+ (format t "~&~4@A: ~,4F (~A repetitions, Perl: ~,4F seconds, CL-PPCRE: ~,4F seconds)" counter
266
+ (float (/ result perl-time)) factor perl-time result)
267
+ #+:cormanlisp (force-output *standard-output*)))
268
+ (t nil))))
269
+ (values)))