hipe-gorillagrammar 0.0.1beta

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.
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