hipe-gorillagrammar 0.0.1beta

Sign up to get free protection for your applications and to get access to all the features.
data/spec/argv.rb ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ # this is for debugging with how the shell parses strings into tokens
3
+ puts Marshal.dump(ARGV)
@@ -0,0 +1,41 @@
1
+ #rake spec SPEC=spec/extensions/syntax_spec.rb
2
+ require 'hipe-gorillagrammar'
3
+ include Hipe::GorillaGrammar
4
+ require 'hipe-gorillagrammar/extensions/syntax'
5
+
6
+ describe ParseTree, 'in the context of Parsing' do
7
+
8
+ before :all do
9
+ @g = Hipe.GorillaGrammar {
10
+ :dry =~ zero_or_one([zero_or_one('as'),'dry',zero_or_one('run')])
11
+ :delete_command =~ ['delete',zero_or_one('deleted')]
12
+ :add_command =~ ['add',one('untracked','modified','both')]
13
+ :help_command =~ 'help'; :version_command =~ 'version'; :info_command =~ 'info'
14
+ :command =~ :add_command | :delete_command | :help_command |
15
+ :version_command | :info_command
16
+ :add_file =~ ['add',one_or_more(:file)]
17
+ :never_using_this =~ [(1..3).of(:blah)]
18
+ :commands =~ [:command,zero_or_more(['and',:command])]
19
+ }
20
+ end
21
+
22
+ it "should put square brackets around zero or one (sx1)" do
23
+ @g[:delete_command].syntax.should == 'delete [deleted]'
24
+ end
25
+
26
+ it "should do a parenthesis and pipe thing for inline one (sx2)" do
27
+ @g[:add_command].syntax.should == 'add (untracked|modified|both)'
28
+ end
29
+
30
+ it "should capitalize symbol references and put square brackets with ellipses around zero or more (sx3)" do
31
+ @g[:commands].syntax.should == 'COMMAND [and COMMAND [...]]'
32
+ end
33
+
34
+ it "it should do the one or more thing (sx4)" do
35
+ @g[:add_file].syntax.should == 'add FILE [FILE [...]]'
36
+ end
37
+
38
+ it "whatever ridiculous" do
39
+ @g[:never_using_this].syntax.should == '(1..3) of (BLAH)'
40
+ end
41
+ end
@@ -0,0 +1,91 @@
1
+ #rake spec SPEC=spec/grammar_spec.rb
2
+ require 'hipe-gorillagrammar'
3
+ include Hipe::GorillaGrammar
4
+
5
+ describe Grammar,'in general' do
6
+ it "should allow basic reflection" do
7
+ g = Hipe.GorillaGrammar{ :items =~ [:item[//]] }
8
+ g.should be_a_kind_of Grammar
9
+ g.size.should == 2
10
+ (g.names - [:item,:items]).should == []
11
+ end
12
+ end
13
+
14
+ describe Grammar,'in general' do
15
+ it "should have entries in the symbol table for all its children" do
16
+ g = Hipe.GorillaGrammar{ :items =~ [:item[//]] }
17
+ g[:items].should_not == nil
18
+ g[:item].should_not == nil
19
+ end
20
+ end
21
+
22
+ describe Grammar,'with respect to naming' do
23
+ it "should get anonymous sequential names" do
24
+ Runtime.instance.instance_variable_set '@grammars', {}
25
+ g1 = Hipe.GorillaGrammar{ :items =~ [:item[//]] }
26
+ g2 = Hipe.GorillaGrammar{ :items =~ [:item[//]] }
27
+ g3 = Hipe.GorillaGrammar{ :items =~ [:item[//]] }
28
+ g4 = Hipe.GorillaGrammar(:name=>'yo, g'){ :items =~ [:item[//]] }
29
+ g1.name.should == 'grammar1'
30
+ g2.name.should == 'grammar2'
31
+ g3.name.should == 'grammar3'
32
+ g4.name.should == 'yo, g'
33
+ end
34
+ end
35
+
36
+ describe "In grammars, the bracket operator" do
37
+ it "when there is only one native element in it which represents a terminal symbol, it should add such a symbol to the table" do
38
+ g = Hipe.GorillaGrammar{ :items =~ [:item[//]] }
39
+ g[:items].should be_kind_of Sequence
40
+ g[:item].should be_kind_of RegexpTerminal
41
+ end
42
+ end
43
+
44
+ describe Grammar do
45
+ it "should not allow redefinitions of symbols" do
46
+ lambda {
47
+ Hipe.GorillaGrammar {
48
+ :once =~ /espresso/
49
+ :twice =~ ['i','love',:once[/coffee/]]
50
+ }
51
+ }.should raise_error GrammarGrammarException, /multiple definitions for :once/i
52
+ end
53
+ end
54
+
55
+ describe Grammar, 'with respect to anonymous symbols' do
56
+ it("still get entries in the symbol table if they're the last one") {
57
+ g = Hipe.GorillaGrammar{[:item[//]]}
58
+ g.size.should == 2
59
+ g['__main__'].should be_kind_of Sequence
60
+ }
61
+ end
62
+
63
+ describe Grammar," with respect to brackets and symbol tables" do
64
+ before :each do
65
+ @g1 = Hipe.GorillaGrammar {
66
+ :thing =~ "beans"
67
+ :color =~ /^(red|green)$/
68
+ :noun_phrase =~ [:color, :thing]
69
+ }
70
+ @g2 = Hipe.GorillaGrammar {
71
+ :noun_phrase =~ [:color[/^(red|green)$/], :thing["beans"]]
72
+ }
73
+ @g3 = Hipe.GorillaGrammar {
74
+ :noun_phrase =~ [:color[/^(red|green)$/], :thing["beans"]]
75
+ :billy =~ 'bob thornton'
76
+ }
77
+ end
78
+
79
+ it "brackets should put entries in the symbol table and return symbol references" do
80
+ g1,g2,g3 = @g1, @g2, @g3
81
+ s1,s2 = '', ''
82
+ PP.pp g1, s1
83
+ PP.pp g2, s2
84
+ s1.should == s2
85
+ (g1==g2).should == true
86
+ (g2==g1).should == true
87
+ (g2==g3).should == false
88
+ end
89
+
90
+ end
91
+
data/spec/helpers.rb ADDED
@@ -0,0 +1,5 @@
1
+ module Helpers
2
+ def shell! str # danger -- will execute any arbitrary string
3
+ Marshal.load %x{ruby #{File.dirname(__FILE__)}/argv.rb #{str}}
4
+ end
5
+ end
@@ -0,0 +1,64 @@
1
+ #rake spec SPEC=spec/parse_tree_spec.rb
2
+ require 'hipe-gorillagrammar'
3
+ include Hipe::GorillaGrammar
4
+
5
+
6
+ describe "ParseTree with fun grammar" do
7
+
8
+ before :each do
9
+ @g1 = Hipe.GorillaGrammar {
10
+ :mode =~ one(['bike'],['walk'],['take','the','train'])
11
+ :person =~ /\A.*\Z/
12
+ :modes =~ [:mode, zero_or_more(['and', :mode])]
13
+ :sentence =~ [:person, 'will', :modes, 'home']
14
+ }
15
+ end
16
+
17
+ it "should parse this fun grammar (pt1)" do
18
+ g = @g1
19
+ res = g.parse %w(mark will take the train home)
20
+ res.is_error?.should == false
21
+ res.size.should == 4
22
+
23
+ res = g.parse %w(fecetious will swim)
24
+ res.is_error?.should == true
25
+ res.tree.expecting.should == %w("bike" "walk" "take")
26
+
27
+ res = g.parse(%w(yoko will bike and walk and take the train home))
28
+ res.is_error?.should == false
29
+ end
30
+
31
+ it "should pp this fun grammar (pt2)" do
32
+ res = @g1.parse(%w(yoko will bike and walk and take the train home))
33
+ num_of_things_deleted = res.recurse{ |x| x.prune! }
34
+ num_of_things_deleted.should be > 30
35
+ num_of_things_deleted.should be < 80 # was 59 at one point. whatever
36
+ # puts %{number of things deleted: #{num_of_things_deleted}}
37
+ PP.pp(res,s = '')
38
+ s.should be_kind_of String
39
+ s.length.should be_close(650, 350)
40
+ end
41
+
42
+ it "should unparse (pt3)" do
43
+ # this is such a small example but i can't explain how awesome it is.
44
+ res = @g1.parse(%w(yoko will bike and walk and take the train home))
45
+ tokens = res.recurse{|x| x.tokens}
46
+ tokens.should == %w(yoko will bike and walk and take the train home)
47
+ end
48
+
49
+ end
50
+
51
+ describe RangeOf,' in the context of ParseTrees' do
52
+ it "should create or-lists correctly (ptro1)" do
53
+ RangeOf.join(['a','b','c','d'],', ',' or '){|x| %{"#{x}"}}.should ==
54
+ %{"a", "b", "c" or "d"}
55
+ RangeOf.join(['a','b','c'],', ',' or '){|x| %{"#{x}"}}.should ==
56
+ %{"a", "b" or "c"}
57
+ RangeOf.join(['a','b'],', ',' or '){|x| %{"#{x}"}}.should ==
58
+ %{"a" or "b"}
59
+ RangeOf.join(['a'],', ',' or '){|x| %{"#{x}"}}.should ==
60
+ %{"a"}
61
+ RangeOf.join([],', ',' or '){|x| %{"#{x}"}}.should ==
62
+ %{}
63
+ end
64
+ end
@@ -0,0 +1,304 @@
1
+ #rake spec SPEC=spec/parsing_spec.rb
2
+ require 'hipe-gorillagrammar'
3
+ include Hipe::GorillaGrammar
4
+
5
+
6
+ describe ParseTree, 'in the context of Parsing' do
7
+
8
+ it("should parse with the empty grammar") {
9
+ Hipe.GorillaGrammar{ (0..more).of('') }.parse([]).is_error?.should == false
10
+ }
11
+
12
+ it("should parse with the one token grammar") {
13
+ g = Hipe.GorillaGrammar{[:item[//]]}
14
+ tree = g.parse(['abc'])
15
+ tree.is_error?.should == false
16
+ }
17
+
18
+ end
19
+
20
+ describe "in the context of Parsing, a simple union grammar" do
21
+ before :each do
22
+ @g_union = Hipe.GorillaGrammar { :base =~ 'mac' | 'whopper' }
23
+ end
24
+
25
+ it "(u0) should allow two ways to define union -- pipe and named functions" do
26
+ g1 = @g_union
27
+ g2 = Hipe.GorillaGrammar{ :base =~ one('mac','whopper') }
28
+ g3 = Hipe.GorillaGrammar{ :base =~ one('mac','whopper',['bk','broiler']) }
29
+ g1.should == g2
30
+ g1.should_not == g3
31
+ end
32
+
33
+ it "(u1) should raise unexpected end when zero tokens" do
34
+ g = @g_union
35
+ result = g.parse []
36
+ result.is_error?.should == true
37
+ result.should be_kind_of UnexpectedEndOfInput
38
+ result.message.should be_kind_of String
39
+ end
40
+
41
+ it "(u2) should parse one correct token" do
42
+ result = @g_union.parse ['mac']
43
+ result.is_error?.should == false
44
+ result.should be_kind_of(RangeOf)
45
+ result.size.should == 1
46
+ result[0].should == 'mac'
47
+ end
48
+
49
+ it "(u3) should raise unexpected with one incorrect token" do
50
+ result = @g_union.parse ['falafel']
51
+ result.is_error?.should == true
52
+ result.should be_kind_of(UnexpectedInput)
53
+ result.message.should be_kind_of(String)
54
+ end
55
+
56
+ it "(u4) should raise unexpected with extra token" do
57
+ result = @g_union.parse ['mac','falafel']
58
+ result.is_error?.should == true
59
+ result.should be_kind_of(UnexpectedInput)
60
+ result.message.should be_kind_of(String)
61
+ end
62
+ end
63
+
64
+ describe "in the context of Parsing, a simple concatenated grammar" do
65
+
66
+ before :each do
67
+ @g_concat = Hipe.GorillaGrammar { :base =~ [ 'big' , 'mac' ] }
68
+ end
69
+
70
+ it "(c1) should raise unexpected end when it has zero tokens" do
71
+ g = @g_concat
72
+ result = g.parse []
73
+ result.is_error?.should == true
74
+ result.should be_kind_of UnexpectedEndOfInput
75
+ result.message.should be_kind_of String
76
+ end
77
+
78
+ it "(c2) should raise unexpected end when nonzero not enough tokens" do
79
+ g = @g_concat
80
+ result = g.parse ['big']
81
+ result.is_error?.should == true
82
+ result.should be_kind_of UnexpectedEndOfInput
83
+ result.message.should be_kind_of String
84
+ end
85
+
86
+ it "(c3) should raise unexpected with one bad token " do
87
+ g = @g_concat
88
+ result = g.parse ['falafel']
89
+ result.is_error?.should == true
90
+ result.should be_kind_of UnexpectedInput
91
+ result.message.should be_kind_of String
92
+ end
93
+
94
+ it "(c4) should parse correctly " do
95
+ g = @g_concat
96
+ result = g.parse ['big','mac']
97
+ result.is_error?.should == false
98
+ result.should be_kind_of Sequence
99
+ result.size.should == 2
100
+ end
101
+
102
+ it "(c5) with the second token being bad should raise unexpected" do
103
+ g = @g_concat
104
+ result = g.parse ['big','falafel']
105
+ result.is_error?.should == true
106
+ result.should be_kind_of UnexpectedInput
107
+ result.message.should be_kind_of String
108
+ end
109
+
110
+ it "(c6) with too many tokens should raise unexpected" do
111
+ g = @g_concat
112
+ result = g.parse ['big','mac','attack']
113
+ result.is_error?.should == true
114
+ result.should be_kind_of UnexpectedInput
115
+ result.message.should be_kind_of String
116
+ end
117
+
118
+ end
119
+
120
+ describe "in the context of Parsing a simple sequence (same as concat)" do
121
+ before(:each) do
122
+ @abc = Hipe.GorillaGrammar do
123
+ sequence 'a','b','c'
124
+ end
125
+ end
126
+
127
+ it "should fail with a message when expecting more (s5)" do
128
+ result = @abc.parse(['a','b'])
129
+ result.is_error?.should == true
130
+ result.message.should match(/unexpected end of input/i)
131
+ result.message.should match(/expecting(?: you to say) "c"/i)
132
+ end
133
+
134
+ end
135
+
136
+
137
+ describe "in the context of Parsing, an integrated union and concat with leading union" do
138
+ before :each do
139
+ @g1 = Hipe.GorillaGrammar do
140
+ sequence zero_or_more('real','big'),'burger'
141
+ end
142
+ end
143
+
144
+ it "(i1) should fail on zero" do
145
+ r = @g1.parse []
146
+ r.is_error?.should == true
147
+ r.should be_kind_of(UnexpectedEndOfInput)
148
+ r.message.should match(/expecting.*real.*big.*burger/i)
149
+ end
150
+
151
+ it "(i2) should fail on one bad token" do
152
+ r = @g1.parse ['falafel']
153
+ r.is_error?.should == true
154
+ r.should be_kind_of(UnexpectedInput)
155
+ r.message.should match(/expecting.*real.*big.*burger/i)
156
+ end
157
+
158
+ it "(i3) should fail on a second bad token" do
159
+ r = @g1.parse ['real','falafel']
160
+ r.is_error?.should == true
161
+ r.should be_kind_of(UnexpectedInput)
162
+ r.message.should match(/expecting.*real.*big.*burger/i)
163
+ end
164
+
165
+ it "(i4) should fail on a third bad token A" do
166
+ r = @g1.parse ['real','big','falafel']
167
+ r.is_error?.should == true
168
+ r.should be_kind_of(UnexpectedInput)
169
+ r.message.should match(/expecting.*real.*big.*burger/i)
170
+ end
171
+
172
+ it "(i5) should fail on a an extra token" do
173
+ r = @g1.parse ['real','big','burger','falafel']
174
+ r.is_error?.should == true
175
+ r.should be_kind_of(UnexpectedInput)
176
+ r.message.should match(/wasn't expecting/i)
177
+ end
178
+
179
+ it "(i6) should parse correctly A" do
180
+ r = @g1.parse ['burger']
181
+ r.is_error?.should == false
182
+ r.size.should == 2
183
+ end
184
+
185
+ it "(i7) should parse correctly B" do
186
+ r = @g1.parse ['real','burger']
187
+ r.is_error?.should == false
188
+ r.size.should == 2
189
+ end
190
+
191
+ it "(i8) should parse correctly C" do
192
+ r = @g1.parse ['real','big','burger']
193
+ r.is_error?.should == false
194
+ r.size.should == 2
195
+ end
196
+
197
+ it "(i9) should parse correctly D" do
198
+ r = @g1.parse ['real','big','real','burger']
199
+ r.is_error?.should == false
200
+ r.size.should == 2
201
+ end
202
+
203
+ end
204
+
205
+
206
+ describe "in the context of Parsing, an integrated union and concat with trailing union" do
207
+ before :each do
208
+ @g1 = Hipe.GorillaGrammar do
209
+ sequence one('burger','goat'),zero_or_more(['with','fries'],['with','falafel'])
210
+ end
211
+ end
212
+
213
+ it "(j1) should fail on zero" do
214
+ r = @g1.parse []
215
+ r.is_error?.should == true
216
+ r.should be_kind_of(UnexpectedEndOfInput)
217
+ r.message.should match(/expecting.*burger.*goat/i)
218
+ end
219
+
220
+ it "(j2) should fail on one bad token" do
221
+ r = @g1.parse ['falafel']
222
+ r.is_error?.should == true
223
+ r.should be_kind_of(UnexpectedInput)
224
+ r.message.should match(/expecting.*burger.*goat/i)
225
+ end
226
+
227
+ it "(j3) should fail on a second bad token (and do uniq on expecting tokens)" do
228
+ r = @g1.parse ['burger','without']
229
+ r.is_error?.should == true
230
+ r.should be_kind_of(UnexpectedInput)
231
+ r.message.should match(/expecting.*with/i)
232
+ end
233
+
234
+ it "(j4) should fail on a third bad token A" do
235
+ r = @g1.parse ['burger','with','toast']
236
+ r.is_error?.should == true
237
+ r.should be_kind_of(UnexpectedInput)
238
+ r.message.should match(/expecting.*fries.*falafel.*end/i)
239
+ end
240
+
241
+ it "(j5) should fail on two extra tokens" do
242
+ r = @g1.parse ['burger','with','fries','to','go']
243
+ r.is_error?.should == true
244
+ r.should be_kind_of(UnexpectedInput)
245
+ r.message.should match(/(?:wasn't expecting|don't know what you mean by).*to.*end/i)
246
+ end
247
+
248
+ it "(j6) should parse correctly A" do
249
+ r = @g1.parse ['burger']
250
+ r.is_error?.should == false
251
+ r.size.should == 1
252
+ end
253
+
254
+ it "(j7) should parse correctly B" do
255
+ r = @g1.parse ['burger','with','falafel']
256
+ r.is_error?.should == false
257
+ r.size.should == 2
258
+ end
259
+
260
+ it "(j8) should parse correctly C" do
261
+ r = @g1.parse ['goat','with','fries']
262
+ r.is_error?.should == false
263
+ r.size.should == 2
264
+ end
265
+
266
+ # no j9. there are only 3 permutations of correct productions
267
+
268
+
269
+ it "parse sequence 2 branch 2 x 2 x 1 (h15)" do
270
+ g = Hipe.GorillaGrammar {
271
+ :sentence =~ ['want', :manufacturer[ one %w(jimmy dean), %w(hickory farms) ] ]
272
+ }
273
+ $stop =1
274
+ thing = g.parse ['want','jimmy']
275
+ thing.is_error?.should == true
276
+ thing.should be_kind_of UnexpectedEndOfInput
277
+ thing.tree.expecting.should == %w("dean")
278
+ end
279
+
280
+ end
281
+
282
+ describe "test" do
283
+
284
+ it "union of concat"
285
+ end
286
+
287
+ describe 'in the context of Parsing, an "and-list" gramar' do
288
+ before(:all){
289
+ @g = Hipe.GorillaGrammar{ :items =~ [:item[/^.+$/],(0..more).of(['and', :item])]}
290
+ @g = Hipe.GorillaGrammar{ [:item[/^.+$/]] }
291
+ }
292
+ it("uno") {
293
+ @g.parse(['abc']).is_error?.should == false
294
+ }
295
+ end
296
+
297
+
298
+ describe 'in the context of Parsing, an "and-list" gramar' do
299
+ before(:all){ @g = Hipe.GorillaGrammar{ :items =~ [:item[/^.+$/],(0..more).of(['and', :item])]} }
300
+ it("uno") { @g.parse(['abc']).is_error?.should == false }
301
+ it("uno.5") { @g.parse(['abc','and']).is_error?.should == true }
302
+ it("dos") { @g.parse(['abc','and','def']).is_error?.should == false }
303
+ it("tres") { @g.parse(['abc','and','def','and','hij']).is_error?.should ==false }
304
+ end