Spectre 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
+