Spectre 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. data/CHANGELOG +1 -0
  2. data/LICENSE +23 -0
  3. data/README +20 -0
  4. data/Rakefile +112 -0
  5. data/lib/spectre/base.rb +44 -0
  6. data/lib/spectre/base/closure.rb +96 -0
  7. data/lib/spectre/base/directive.rb +148 -0
  8. data/lib/spectre/base/grammar.rb +269 -0
  9. data/lib/spectre/base/inputiterator.rb +276 -0
  10. data/lib/spectre/base/node.rb +393 -0
  11. data/lib/spectre/base/operators.rb +342 -0
  12. data/lib/spectre/base/parser.rb +110 -0
  13. data/lib/spectre/generic.rb +115 -0
  14. data/lib/spectre/generic/directives.rb +246 -0
  15. data/lib/spectre/generic/negations.rb +68 -0
  16. data/lib/spectre/generic/primitives.rb +172 -0
  17. data/lib/spectre/generic/semanticaction.rb +43 -0
  18. data/lib/spectre/string.rb +57 -0
  19. data/lib/spectre/string/additionals.rb +80 -0
  20. data/lib/spectre/string/directives.rb +51 -0
  21. data/lib/spectre/string/inputiterator.rb +57 -0
  22. data/lib/spectre/string/primitives.rb +400 -0
  23. data/test/base/closure_tests.rb +108 -0
  24. data/test/base/grammar_tests.rb +97 -0
  25. data/test/base/operator_tests.rb +335 -0
  26. data/test/base/semanticaction_tests.rb +53 -0
  27. data/test/generic/directive_tests.rb +224 -0
  28. data/test/generic/negation_tests.rb +146 -0
  29. data/test/generic/primitive_tests.rb +99 -0
  30. data/test/string/POD2Parser_tests.rb +93 -0
  31. data/test/string/additional_tests.rb +43 -0
  32. data/test/string/directive_tests.rb +32 -0
  33. data/test/string/primitive_tests.rb +173 -0
  34. data/test/tests.rb +33 -0
  35. data/test/tutorial/funnymath_tests.rb +57 -0
  36. data/test/tutorial/html_tests.rb +171 -0
  37. data/test/tutorial/skipping_tests.rb +60 -0
  38. metadata +109 -0
@@ -0,0 +1,108 @@
1
+ #!/usr/bin/env ruby
2
+ # This is Spectre, a parser framework inspired by Boost.Spirit,
3
+ # which can be found at http://spirit.sourceforge.net/.
4
+ #
5
+ # If you want to find out more or need a tutorial, go to
6
+ # http://spectre.rubyforge.org/
7
+ # You'll find a nice wiki there!
8
+ #
9
+ # Author:: Fabian Streitel (karottenreibe)
10
+ # Copyright:: Copyright (c) 2009 Fabian Streitel
11
+ # License:: Boost Software License 1.0
12
+ # For further information regarding this license, you can go to
13
+ # http://www.boost.org/LICENSE_1_0.txt
14
+ # or read the file LICENSE distributed with this software.
15
+ # Homepage:: http://spectre.rubyforge.org/
16
+ # Git repo:: http://rubyforge.org/scm/?group_id=7618
17
+ #
18
+
19
+ require 'rubygems'
20
+ require 'test/unit'
21
+ require 'spectre/string'
22
+
23
+ class ClosureTests < Test::Unit::TestCase
24
+ include Spectre
25
+ include Spectre::StringParsing
26
+ include Spectre::ShortcutsMixin
27
+
28
+ def testClosureFinding
29
+ p3 = 'bacon'.to_p
30
+ p2 = ' ' >> p3
31
+ p = 'chunky' >> p2
32
+
33
+ c = p.closure = Closure.new
34
+ assert_same c, p.closure
35
+ assert_same c, p2.closure
36
+ assert_same c, p3.closure
37
+ end
38
+
39
+ def testClosureFindingGram
40
+ g = Grammar.new do
41
+ start_with 'bar'.to_p[:tag]
42
+ end
43
+
44
+ g.bind
45
+
46
+ c = g.closure = Closure.new
47
+ parse 'bar', g
48
+ assert_equal 'bar', c[:tag]
49
+
50
+ g = Grammar.new do
51
+ start_with close( 'bar'.to_p[:tag] )
52
+ end
53
+
54
+ c = g.closure = Closure.new
55
+ g.bind
56
+
57
+ parse 'bar', g
58
+ assert_equal nil, c[:tag]
59
+ end
60
+
61
+ def testClosureHierarchy
62
+ p1 = 'chunky' >> blank_char >> 'bacon'
63
+ p11 = p1.dup
64
+ p2 = p1 >> blank_char >> p11
65
+
66
+ c1 = Closure.new
67
+ c2 = Closure.new
68
+ p1.closure = c1
69
+ p2.closure = c2
70
+
71
+ assert_same c2, p2.closure
72
+ assert_same c2, p11.closure
73
+ assert_same c1, p1.closure
74
+ assert_not_same c2, p1.closure
75
+ assert_same c2, p1.parent.closure
76
+ end
77
+
78
+ def testGrammarClosure
79
+ val = 0
80
+ tester = lambda { |match,closure| assert_kind_of Closure, closure }
81
+
82
+ g = Grammar.new do
83
+ rule :expr => close( :term.to_p[tester] | :plus | :minus )[tester]
84
+ rule :term => alnum_char
85
+ rule :plus => '('.to_p >> :expr >> '+' >> :expr >> ')'
86
+ rule :minus => '(' >> :expr.to_p[tester] >> '-' >> :expr >> ')'
87
+ start_with :expr.to_p
88
+ end.bind
89
+
90
+ parse '((a-b)+c)', g
91
+ end
92
+
93
+ def testGrammarParents
94
+ val = 0
95
+ tester = lambda { |match,closure| p closure[:term]; p match }
96
+
97
+ g = Grammar.new do
98
+ rule :expr => close( :term.to_p | :plus | :minus )
99
+ rule :term => close( alnum_char[:term] )
100
+ rule :plus => '('.to_p >> :expr >> '+' >> :expr >> ')'
101
+ rule :minus => '('.to_p >> :expr >> '-' >> :expr >> ')'
102
+ start_with :expr.to_p
103
+ end.bind
104
+
105
+ parse '((a-b)+c)', g
106
+ end
107
+ end
108
+
@@ -0,0 +1,97 @@
1
+ #!/usr/bin/env ruby
2
+ # This is Spectre, a parser framework inspired by Boost.Spirit,
3
+ # which can be found at http://spirit.sourceforge.net/.
4
+ #
5
+ # If you want to find out more or need a tutorial, go to
6
+ # http://spectre.rubyforge.org/
7
+ # You'll find a nice wiki there!
8
+ #
9
+ # Author:: Fabian Streitel (karottenreibe)
10
+ # Copyright:: Copyright (c) 2009 Fabian Streitel
11
+ # License:: Boost Software License 1.0
12
+ # For further information regarding this license, you can go to
13
+ # http://www.boost.org/LICENSE_1_0.txt
14
+ # or read the file LICENSE distributed with this software.
15
+ # Homepage:: http://spectre.rubyforge.org/
16
+ # Git repo:: http://rubyforge.org/scm/?group_id=7618
17
+ #
18
+
19
+ require 'rubygems'
20
+ require 'test/unit'
21
+ require 'spectre/string'
22
+
23
+ class GrammarTests < Test::Unit::TestCase
24
+ include Spectre
25
+ include Spectre::StringParsing
26
+
27
+ def testSimpleGrammar
28
+ simple_grammar = Grammar.new do ||
29
+ rule :rule => alnum_char % ','
30
+ start_with :rule
31
+ end
32
+
33
+ ret = parse "a,b,c,1,2,3", simple_grammar
34
+ assert_equal 11, ret.length
35
+ assert_equal "a,b,c,1,2,3", ret.value
36
+ end
37
+
38
+ def testHTMLGrammar
39
+ html_grammar = Grammar.new do ||
40
+ rule :tag => '<'.to_p >> :tagname >> '>'
41
+ rule :endtag => '</'.to_p >> :tagname >> '>'
42
+ rule :tagname => ( ~char('>') ).+
43
+ rule :data => lexeme_d[( ~char('<') ).+]
44
+ rule :inner => :data.to_p | :element
45
+ rule :element => :tag.to_p >> :inner >> :endtag
46
+ start_with :element
47
+ end
48
+
49
+ html = "<html><body><p>print me!</p></body></html>"
50
+ ret = parse html, html_grammar
51
+ assert_kind_of Match, ret
52
+ assert_equal html.length, ret.length
53
+ assert_equal html, ret.value
54
+ end
55
+
56
+ def testGrammarArgs
57
+ dyn = Grammar.new do |op1, op2|
58
+ rule :expr => :term.to_p | :o1 | :o2,
59
+ :term => alnum_char.+,
60
+ :o1 => '('.to_p >> :expr >> op1.to_p >> :expr >> ')',
61
+ :o2 => '('.to_p >> :expr >> op2.to_p >> :expr >> ')'
62
+ start_with :expr
63
+ end
64
+
65
+ dyn.bind('+', '-')
66
+ ex = '(A+(3-B))'
67
+ ret = parse ex, dyn
68
+ assert_kind_of Match, ret
69
+ assert_equal ex.length, ret.length
70
+ assert_equal ex, ret.value
71
+
72
+ dyn.bind('*', '/')
73
+ ex = '(A*(22*((33*B)/44)))'
74
+ ret = parse ex, dyn
75
+ assert_kind_of Match, ret
76
+ assert_equal ex.length, ret.length
77
+ assert_equal ex, ret.value
78
+ end
79
+
80
+ class MixinTester
81
+ include Spectre::ShortcutsMixin
82
+ end
83
+
84
+ class FooParser
85
+ include Spectre::Parser
86
+ end
87
+
88
+ def testShortcutsMixin
89
+ before = MixinTester.new
90
+ ShortcutsMixin.register_shortcut :foo => FooParser
91
+ after = MixinTester.new
92
+
93
+ assert_respond_to after, :foo
94
+ assert_respond_to before, :foo
95
+ end
96
+ end
97
+
@@ -0,0 +1,335 @@
1
+ #!/usr/bin/env ruby
2
+ # This is Spectre, a parser framework inspired by Boost.Spirit,
3
+ # which can be found at http://spirit.sourceforge.net/.
4
+ #
5
+ # If you want to find out more or need a tutorial, go to
6
+ # http://spectre.rubyforge.org/
7
+ # You'll find a nice wiki there!
8
+ #
9
+ # Author:: Fabian Streitel (karottenreibe)
10
+ # Copyright:: Copyright (c) 2009 Fabian Streitel
11
+ # License:: Boost Software License 1.0
12
+ # For further information regarding this license, you can go to
13
+ # http://www.boost.org/LICENSE_1_0.txt
14
+ # or read the file LICENSE distributed with this software.
15
+ # Homepage:: http://spectre.rubyforge.org/
16
+ # Git repo:: http://rubyforge.org/scm/?group_id=7618
17
+ #
18
+
19
+ require 'rubygems'
20
+ require 'test/unit'
21
+ require 'spectre/string'
22
+
23
+ class StringOperatorTests < Test::Unit::TestCase
24
+ include Spectre
25
+ include Spectre::Operators
26
+ include Spectre::StringParsing
27
+
28
+ def testSequence
29
+ p = Node.new Sequence.new, CharParser.new("a"), CharParser.new("s")
30
+ iter = StringInputIterator.new "asdf"
31
+ ret = p.parse iter
32
+ assert_kind_of Match, ret
33
+ assert_equal 2, ret.length
34
+ assert_equal "as", ret.value
35
+ assert_equal 2, iter.pos
36
+
37
+ iter = StringInputIterator.new "a sdf"
38
+ ret = p.parse iter
39
+ assert_kind_of Match, ret
40
+ assert_equal 3, ret.length
41
+ assert_equal "as", ret.value
42
+ assert_equal 3, iter.pos
43
+
44
+ iter = StringInputIterator.new "bsdf"
45
+ ret = p.parse iter
46
+ assert_kind_of NilClass, ret
47
+ assert_equal 0, iter.pos
48
+
49
+ iter = StringInputIterator.new "abdf"
50
+ ret = p.parse iter
51
+ assert_kind_of NilClass, ret
52
+ assert_equal 0, iter.pos
53
+ end
54
+
55
+ def testSequentialOr
56
+ p = Node.new SequentialOr.new, CharParser.new("a"), CharParser.new("s")
57
+
58
+ iter = StringInputIterator.new "asdf"
59
+ ret = p.parse iter
60
+ assert_kind_of Match, ret
61
+ assert_equal 2, ret.length
62
+ assert_equal "as", ret.value
63
+ assert_equal 2, iter.pos
64
+
65
+ iter = StringInputIterator.new "a s df"
66
+ ret = p.parse iter
67
+ assert_kind_of Match, ret
68
+ assert_equal 3, ret.length
69
+ assert_equal "as", ret.value
70
+ assert_equal 3, iter.pos
71
+
72
+ iter = StringInputIterator.new "a3df"
73
+ ret = p.parse iter
74
+ assert_kind_of Match, ret
75
+ assert_equal 1, ret.length
76
+ assert_equal "a", ret.value
77
+ assert_equal 1, iter.pos
78
+
79
+ iter = StringInputIterator.new "bsdf"
80
+ ret = p.parse iter
81
+ assert_kind_of NilClass, ret
82
+ assert_equal 0, iter.pos
83
+ end
84
+
85
+ def testUnion
86
+ p = Node.new Union.new, CharParser.new("a"), CharParser.new("s")
87
+ iter = StringInputIterator.new "asdf"
88
+ ret = p.parse iter
89
+ assert_kind_of Match, ret
90
+ assert_equal 1, ret.length
91
+ assert_equal "a", ret.value
92
+ assert_equal 1, iter.pos
93
+
94
+ iter = StringInputIterator.new "s3df"
95
+ ret = p.parse iter
96
+ assert_kind_of Match, ret
97
+ assert_equal 1, ret.length
98
+ assert_equal "s", ret.value
99
+ assert_equal 1, iter.pos
100
+
101
+ iter = StringInputIterator.new " s 3df"
102
+ ret = p.parse iter
103
+ assert_kind_of Match, ret
104
+ assert_equal 3, ret.length
105
+ assert_equal "s", ret.value
106
+ assert_equal 3, iter.pos
107
+
108
+ iter = StringInputIterator.new "bsdf"
109
+ ret = p.parse iter
110
+ assert_kind_of NilClass, ret
111
+ assert_equal 0, iter.pos
112
+ end
113
+
114
+ def testIntersection
115
+ p = Node.new Intersection.new, RangeParser.new("a".."b"), RangeParser.new("a".."c")
116
+ iter = StringInputIterator.new "asdf"
117
+ ret = p.parse iter
118
+ assert_kind_of Match, ret
119
+ assert_equal 1, ret.length
120
+ assert_equal "a", ret.value
121
+ assert_equal 1, iter.pos
122
+
123
+ iter = StringInputIterator.new "b3df"
124
+ ret = p.parse iter
125
+ assert_kind_of Match, ret
126
+ assert_equal 1, ret.length
127
+ assert_equal "b", ret.value
128
+ assert_equal 1, iter.pos
129
+
130
+ iter = StringInputIterator.new " b3df"
131
+ ret = p.parse iter
132
+ assert_kind_of Match, ret
133
+ assert_equal 3, ret.length
134
+ assert_equal "b", ret.value
135
+ assert_equal 3, iter.pos
136
+
137
+ iter = StringInputIterator.new "csdf"
138
+ ret = p.parse iter
139
+ assert_kind_of NilClass, ret
140
+ assert_equal 0, iter.pos
141
+
142
+ iter = StringInputIterator.new "xsdf"
143
+ ret = p.parse iter
144
+ assert_kind_of NilClass, ret
145
+ assert_equal 0, iter.pos
146
+ end
147
+
148
+ def testDifference
149
+ p = Node.new Difference.new, RangeParser.new("a".."c"), RangeParser.new("a".."b")
150
+ iter = StringInputIterator.new "csdf"
151
+ ret = p.parse iter
152
+ assert_kind_of Match, ret
153
+ assert_equal 1, ret.length
154
+ assert_equal "c", ret.value
155
+ assert_equal 1, iter.pos
156
+
157
+ iter = StringInputIterator.new " csdf"
158
+ ret = p.parse iter
159
+ assert_kind_of Match, ret
160
+ assert_equal 2, ret.length
161
+ assert_equal "c", ret.value
162
+ assert_equal 2, iter.pos
163
+
164
+ iter = StringInputIterator.new "a3df"
165
+ ret = p.parse iter
166
+ assert_kind_of NilClass, ret
167
+ assert_equal 0, iter.pos
168
+
169
+ iter = StringInputIterator.new "xsdf"
170
+ ret = p.parse iter
171
+ assert_kind_of NilClass, ret
172
+ assert_equal 0, iter.pos
173
+ end
174
+
175
+ def testXor
176
+ p = Node.new Xor.new, RangeParser.new("b".."x"), RangeParser.new("a".."b")
177
+ iter = StringInputIterator.new "asdf"
178
+ ret = p.parse iter
179
+ assert_kind_of Match, ret
180
+ assert_equal 1, ret.length
181
+ assert_equal "a", ret.value
182
+ assert_equal 1, iter.pos
183
+
184
+ iter = StringInputIterator.new " t3df"
185
+ ret = p.parse iter
186
+ assert_kind_of Match, ret
187
+ assert_equal 4, ret.length
188
+ assert_equal "t", ret.value
189
+ assert_equal 4, iter.pos
190
+
191
+ iter = StringInputIterator.new "t3df"
192
+ ret = p.parse iter
193
+ assert_kind_of Match, ret
194
+ assert_equal 1, ret.length
195
+ assert_equal "t", ret.value
196
+ assert_equal 1, iter.pos
197
+
198
+ iter = StringInputIterator.new "bsdf"
199
+ ret = p.parse iter
200
+ assert_kind_of NilClass, ret
201
+ assert_equal 0, iter.pos
202
+
203
+ iter = StringInputIterator.new "3sdf"
204
+ ret = p.parse iter
205
+ assert_kind_of NilClass, ret
206
+ assert_equal 0, iter.pos
207
+ end
208
+
209
+ def testKleeneStar
210
+ p = Node.new KleeneStar.new, RangeParser.new("a".."s")
211
+ iter = StringInputIterator.new "asdf"
212
+ ret = p.parse iter
213
+ assert_kind_of Match, ret
214
+ assert_equal 4, ret.length
215
+ assert_equal "asdf", ret.value
216
+ assert_equal 4, iter.pos
217
+
218
+ iter = StringInputIterator.new "a3df"
219
+ ret = p.parse iter
220
+ assert_kind_of Match, ret
221
+ assert_equal 1, ret.length
222
+ assert_equal "a", ret.value
223
+ assert_equal 1, iter.pos
224
+
225
+ iter = StringInputIterator.new " a3df"
226
+ ret = p.parse iter
227
+ assert_kind_of Match, ret
228
+ assert_equal 2, ret.length
229
+ assert_equal "a", ret.value
230
+ assert_equal 2, iter.pos
231
+
232
+ iter = StringInputIterator.new "3sdf"
233
+ ret = p.parse iter
234
+ assert_kind_of Match, ret
235
+ assert_equal 0, ret.length
236
+ assert_equal "", ret.value
237
+ assert_equal 0, iter.pos
238
+ end
239
+
240
+ def testPositive
241
+ p = Node.new Positive.new, CharParser.new("a")
242
+ iter = StringInputIterator.new "aaaa"
243
+ ret = p.parse iter
244
+ assert_kind_of Match, ret
245
+ assert_equal 4, ret.length
246
+ assert_equal "aaaa", ret.value
247
+ assert_equal 4, iter.pos
248
+
249
+ iter = StringInputIterator.new " a3df"
250
+ ret = p.parse iter
251
+ assert_kind_of Match, ret
252
+ assert_equal 2, ret.length
253
+ assert_equal "a", ret.value
254
+ assert_equal 2, iter.pos
255
+
256
+ iter = StringInputIterator.new "a3df"
257
+ ret = p.parse iter
258
+ assert_kind_of Match, ret
259
+ assert_equal 1, ret.length
260
+ assert_equal "a", ret.value
261
+ assert_equal 1, iter.pos
262
+
263
+ iter = StringInputIterator.new "3sdf"
264
+ ret = p.parse iter
265
+ assert_kind_of NilClass, ret
266
+ assert_equal 0, iter.pos
267
+ end
268
+
269
+ def testOptional
270
+ p = Node.new Optional.new, CharParser.new("a")
271
+ iter = StringInputIterator.new "asdf"
272
+ ret = p.parse iter
273
+ assert_kind_of Match, ret
274
+ assert_equal 1, ret.length
275
+ assert_equal "a", ret.value
276
+ assert_equal 1, iter.pos
277
+
278
+ iter = StringInputIterator.new "33df"
279
+ ret = p.parse iter
280
+ assert_kind_of Match, ret
281
+ assert_equal 0, ret.length
282
+ assert_equal "", ret.value
283
+ assert_equal 0, iter.pos
284
+
285
+ iter = StringInputIterator.new " a3df"
286
+ ret = p.parse iter
287
+ assert_kind_of Match, ret
288
+ assert_equal 3, ret.length
289
+ assert_equal "a", ret.value
290
+ assert_equal 3, iter.pos
291
+ end
292
+
293
+ def testList
294
+ p = Node.new List.new, CharParser.new("a"), CharParser.new("s")
295
+ iter = StringInputIterator.new "asasa"
296
+ ret = p.parse iter
297
+ assert_kind_of Match, ret
298
+ assert_equal 5, ret.length
299
+ assert_equal "asasa", ret.value
300
+ assert_equal 5, iter.pos
301
+
302
+ iter = StringInputIterator.new "asas"
303
+ ret = p.parse iter
304
+ assert_kind_of Match, ret
305
+ assert_equal 3, ret.length
306
+ assert_equal "asa", ret.value
307
+ assert_equal 3, iter.pos
308
+
309
+ iter = StringInputIterator.new "a s a s a"
310
+ ret = p.parse iter
311
+ assert_kind_of Match, ret
312
+ assert_equal 9, ret.length
313
+ assert_equal "asasa", ret.value
314
+ assert_equal 9, iter.pos
315
+
316
+ iter = StringInputIterator.new "a3df"
317
+ ret = p.parse iter
318
+ assert_kind_of Match, ret
319
+ assert_equal 1, ret.length
320
+ assert_equal "a", ret.value
321
+ assert_equal 1, iter.pos
322
+
323
+ iter = StringInputIterator.new "bsdf"
324
+ ret = p.parse iter
325
+ assert_kind_of NilClass, ret
326
+ assert_equal 0, iter.pos
327
+
328
+ iter = StringInputIterator.new "ssdf"
329
+ ret = p.parse iter
330
+ assert_kind_of NilClass, ret
331
+ assert_equal 0, iter.pos
332
+ end
333
+
334
+ end
335
+