babel_bridge 0.4.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,94 @@
1
+ require 'spec_helper'
2
+
3
+ describe "basic parsing" do
4
+ include TestParserGenerator
5
+
6
+ it "string literal should work" do
7
+ new_parser do
8
+ rule :foo, "foo"
9
+ end
10
+
11
+ test_parse "foo"
12
+ test_parse("foo").offset.should == 0
13
+ test_parse("foo").text.length.should == 3
14
+ end
15
+
16
+ it ".as option should work" do
17
+ new_parser do
18
+ rule :foo, match("foo").as(:boo)
19
+ end
20
+
21
+ test_parse "foo"
22
+ test_parse("foo").boo.text.should == "foo"
23
+ end
24
+
25
+ it "regexp should work" do
26
+ new_parser do
27
+ rule :foo, /[0-9]+/
28
+ end
29
+
30
+ %w{ 0 1 10 123 1001 }.each do |numstr|
31
+ test_parse numstr
32
+ end
33
+ end
34
+
35
+ # bb uses some regexp optimizations which could fail if not matched @ the first character of the source
36
+ it "regexp should work even when it isn't the first match" do
37
+ new_parser do
38
+ rule :foo, /[0-9]+/
39
+ rule :foo, "hi", /[0-9]+/
40
+ end
41
+
42
+ test_parse "123"
43
+ test_parse "hi123"
44
+ end
45
+
46
+ it "test optional" do
47
+ new_parser do
48
+ rule :foo, "foo", :bar?
49
+ rule :bar, "bar"
50
+ end
51
+
52
+ test_parse "foo"
53
+ test_parse "foobar"
54
+ end
55
+
56
+ it "test could" do
57
+ new_parser do
58
+ rule :foo, could.match(/[a-z]/), /[a-zA-Z]+/
59
+ end
60
+ test_parse "FOO", :should_fail_at => 0
61
+ test_parse "fOO"
62
+ test_parse "foo"
63
+ end
64
+
65
+ it "test optional in the middle" do
66
+ new_parser do
67
+ rule :foo, "foo", match?("bar"), "foo"
68
+ end
69
+
70
+ test_parse "foofoo"
71
+ test_parse "foobarfoo"
72
+ end
73
+
74
+ # this seems a little strange, but it is correct behavior for a Parsing-Expression-Grammar parser
75
+ it "test_greedy_optional_middle" do
76
+ new_parser do
77
+ rule :foo, "foo", match?("foo"), "foo"
78
+ end
79
+
80
+ test_parse "foofoo", :should_fail_at => 6
81
+ test_parse "foofoofoo"
82
+ end
83
+
84
+ it "! (not-match) should work" do
85
+ new_parser do
86
+ rule :foo, match!("boo"), /[a-zA-Z]+/
87
+ end
88
+
89
+ test_parse "boo", :should_fail_at => 0
90
+ test_parse "foo"
91
+ test_parse "boO"
92
+ end
93
+
94
+ end
@@ -1,44 +1,7 @@
1
- require File.join(File.dirname(__FILE__),"..","lib","babel_bridge")
1
+ require 'spec_helper'
2
2
 
3
3
  describe BabelBridge do
4
- attr_accessor :parser
5
-
6
- def new_parser(&block)
7
- $parser_counter||=0
8
- $parser_counter+=1
9
- Object.const_set(klass_name="TestParser#{$parser_counter}",Class.new(BabelBridge::Parser,&block))
10
- @parser=Object.const_get(klass_name).new
11
- end
12
-
13
- #options
14
- # :parser
15
- # :failure_ok
16
- def test_parse(string,options={},&block)
17
- parser = options[:parser] || @parser
18
- res = parser.parse(string)
19
- yield res if res && block
20
- if options[:should_fail_at]
21
- res.should == nil
22
- parser.failure_index.should == options[:should_fail_at]
23
- elsif !options[:failure_ok]
24
- puts parser.parser_failure_info :verbose => true unless res
25
- res.should_not == nil
26
- end
27
- res
28
- end
29
-
30
- it "ignore_whitespace should work" do
31
- new_parser do
32
- ignore_whitespace
33
- rule :foobar, "foo", "bar"
34
- end
35
-
36
- test_parse "foobar"
37
- test_parse "foo bar"
38
- test_parse "foo \t \r \f \n bar"
39
- test_parse " foobar"
40
- test_parse "foobar "
41
- end
4
+ include TestParserGenerator
42
5
 
43
6
  it "the failure_index should be the furthest point reached, even if we managed to successfully match less" do
44
7
  new_parser do
@@ -65,71 +28,6 @@ describe BabelBridge do
65
28
  parser.parser_failure_info[partial_match_string].should == nil
66
29
  end
67
30
 
68
- it "include_whitespace should work" do
69
- new_parser do
70
- ignore_whitespace
71
-
72
- rule :pair, :statement, :end_statement, :statement
73
- rule :end_statement, rewind_whitespace, /([\t ]*[\n;])+/
74
- rule :statement, "0"
75
- end
76
-
77
- test_parse "0;0"
78
- test_parse "0\n0"
79
- test_parse "0 ; 0"
80
- test_parse "0 ; ; 0"
81
- test_parse "0 \n 0"
82
- test_parse "0 \n \n 0"
83
- test_parse "0 \n ; \n 0"
84
- test_parse "0 ; \n ;0"
85
- test_parse "0 0", :should_fail_at => 1
86
- end
87
-
88
- it "include_whitespace should work even with EmptyNodes" do
89
- new_parser do
90
- ignore_whitespace
91
-
92
- rule :pair, :statement, :end_statement, :statement
93
- rule :end_statement, rewind_whitespace, /([\t ]*[\n;])+/
94
- rule :statement, "0", :one?, :one?, :one?
95
- rule :one, "1"
96
- end
97
-
98
- test_parse "0;0"
99
- test_parse "01;0"
100
- test_parse "0\n0"
101
- test_parse "01\n0"
102
- test_parse "011\n0"
103
- test_parse "0111\n0"
104
- end
105
-
106
- it "include_whitespace should work with many" do
107
- new_parser do
108
- ignore_whitespace
109
- rule :statements, many(:statement,:end_statement)
110
- rule :end_statement, rewind_whitespace, /([\t ]*[;\n])+/
111
- rule :statement, "0"
112
- end
113
-
114
- test_parse "0"
115
- test_parse "0\n0"
116
- end
117
-
118
- it "custom ignore_whitespace should work" do
119
- new_parser do
120
- ignore_whitespace /[_\s]*/
121
-
122
- rule :foobar, "foo", "bar"
123
- end
124
-
125
- test_parse "foobar"
126
- test_parse "foo_bar"
127
- test_parse "foo_ bar"
128
- test_parse "foo _ bar"
129
- test_parse "foo bar"
130
- test_parse "foo-bar", :should_fail_at => 3
131
- end
132
-
133
31
  it "should work to have many-many parsing" do
134
32
  new_parser do
135
33
  rule :top, many(:bottom,";")
@@ -144,68 +42,14 @@ describe BabelBridge do
144
42
  test_parse "0,0,0;0;0,0,0"
145
43
  end
146
44
 
147
- it "should work to have many parsing with whitespace tricks" do
45
+ it "if a name can be optionally matched more than one time, it should always be an array of matchs" do
148
46
  new_parser do
149
- ignore_whitespace
150
- rule :statements, many(:statement,:end_statement)
151
- rule :end_statement, rewind_whitespace, /([\t ]*[;\n])+/
152
- rule :statement, :bin_op
153
- binary_operators_rule :bin_op, :int, ["**", [:/, :*], [:+, "-"]], :right_operators => ["**"]
154
- rule :int, /\d+/
155
- end
156
-
157
- test_parse "0"
158
- test_parse <<ENDCODE
159
- 3+4
160
- 9-2
161
- 4
162
- ENDCODE
163
- end
164
-
165
- it "should work to rewind_whitespace, :rule" do
166
- new_parser do
167
- ignore_whitespace
168
- rule :all, :identifier, :parameter?, :identifier do
169
- def to_model
170
- [[identifier[0].to_sym, parameter && parameter.to_sym], identifier[1].to_sym]
171
- end
172
- end
173
- rule :parameter, rewind_whitespace, /[ \t]*/, rewind_whitespace, :identifier
174
- rule :identifier, /[_a-zA-Z][_a-zA-Z0-9]*/
175
- end
176
-
177
- test_parse("fred\nbar") {|parsed|parsed.to_model.should == [[:fred,nil],:bar]}
178
- test_parse("fred foo\nbar") {|parsed|parsed.to_model.should == [[:fred,:foo],:bar]}
179
- end
180
-
181
- it "should work to rewind_whitespace, many" do
182
- new_parser do
183
- ignore_whitespace
184
- rule :all, :identifier, :parameters?, :identifier do
185
- def to_model
186
- [[identifier[0].to_sym, parameters && parameters.to_s], identifier[1].to_sym]
187
- end
188
- end
189
- rule :parameters, rewind_whitespace, /[ \t]*/, rewind_whitespace, many(:identifier,",")
190
- rule :identifier, /[_a-zA-Z][_a-zA-Z0-9]*/
191
- end
192
-
193
- test_parse("fred\nbar") {|parsed| parsed.to_model.should==[[:fred,nil],:bar]}
194
- test_parse("fred foo\nbar") {|parsed| parsed.to_model.should==[[:fred,"foo"],:bar]}
195
- test_parse("fred foo, bar\nbar") {|parsed| parsed.to_model.should==[[:fred,"foo, bar"],:bar]}
196
- end
197
-
198
- it "dont.match shouldn't consume any whitespace" do
199
- new_parser do
200
- ignore_whitespace
201
- rule :statements, :statement, "bar"
202
- rule :statement, :identifier, :parameters?
203
- rule :parameters, rewind_whitespace, / */, rewind_whitespace, :identifier
204
- rule :identifier, dont.match("end"), /[_a-zA-Z][_a-zA-Z0-9]*/
47
+ rule :foo, :bar, :bar?
48
+ rule :bar, "bar"
205
49
  end
206
50
 
207
- test_parse("fred\nbar")
208
- test_parse("fred foo\nbar")
51
+ test_parse("bar").bar.class.should == BabelBridge::MultiMatchesArray
52
+ test_parse("barbar").bar.class.should == BabelBridge::MultiMatchesArray
209
53
  end
210
54
 
211
55
  end
@@ -0,0 +1,227 @@
1
+ require 'spec_helper'
2
+
3
+ describe "ignore_whitespace" do
4
+ include TestParserGenerator
5
+
6
+ it "ignore_whitespace should work" do
7
+ new_parser do
8
+ ignore_whitespace
9
+ rule :foobar, "foo", "bar"
10
+ end
11
+
12
+ # test_parse "foobar"
13
+ # test_parse "foo bar"
14
+ # test_parse "foo \t \r \f \n bar"
15
+ # test_parse " foobar"
16
+ test_parse "foobar "
17
+ end
18
+
19
+ it "ignore_whitespace should work with many" do
20
+ new_parser do
21
+ ignore_whitespace
22
+ rule :foobar, many("foo")
23
+ end
24
+
25
+ test_parse "foo"
26
+ test_parse "foofoo"
27
+ test_parse "foo foo"
28
+ test_parse "foo foo\nfoo"
29
+ end
30
+
31
+ it "custom delimiter should work" do
32
+ new_parser do
33
+ ignore_whitespace
34
+ rule :pair, "0", "0", :delimiter => /-*/
35
+ end
36
+
37
+ test_parse "00"
38
+ test_parse "0-0"
39
+ test_parse " 0-0"
40
+ test_parse " 0-0 "
41
+ test_parse " 0--0 "
42
+ end
43
+
44
+ it "custom // delimiter should work" do
45
+ new_parser do
46
+ ignore_whitespace
47
+ rule :pair, "0", "0", :delimiter => //
48
+ end
49
+
50
+ test_parse "00"
51
+ test_parse " 00"
52
+ test_parse " 00 "
53
+ test_parse "0 0", :should_fail_at => 1
54
+ end
55
+
56
+
57
+ it "custom delimiter should work" do
58
+ new_parser do
59
+ ignore_whitespace
60
+
61
+ rule :pair, :statement, :end_statement, :statement, :delimiter => //
62
+ rule :end_statement, /([\t ]*[\n;])+([\t ]*)?/
63
+ rule :statement, "0"
64
+ end
65
+
66
+ test_parse "0;0"
67
+ test_parse "0\n0"
68
+ test_parse "0 ; 0"
69
+ test_parse "0 ; ; 0"
70
+ test_parse "0 \n 0"
71
+ test_parse "0 \n \n 0"
72
+ test_parse "0 \n ; \n 0"
73
+ test_parse "0 ; \n ;0"
74
+ test_parse "0 0", :should_fail_at => 1
75
+ end
76
+
77
+ it "custom delimiters should work even with EmptyNodes" do
78
+ new_parser do
79
+ ignore_whitespace
80
+
81
+ rule :pair, :statement, :end_statement, :statement, :delimiter => //
82
+ rule :end_statement, /([\t ]*[\n;])+([\t ]*)?/
83
+ rule :statement, "0", :one?, :one?, :one?
84
+ rule :one, "1"
85
+ end
86
+
87
+ test_parse "0;0"
88
+ test_parse "01;0"
89
+ test_parse "0\n0"
90
+ test_parse "01\n0"
91
+ test_parse "011\n0"
92
+ test_parse "0111\n0"
93
+ end
94
+
95
+ it "custom delimiters should work with many" do
96
+ new_parser do
97
+ ignore_whitespace
98
+ rule :statements, many(:statement,:end_statement), :delimiter => //
99
+ rule :end_statement, /([\t ]*[\n;])+([\t ]*)?/
100
+ rule :statement, "0"
101
+ end
102
+
103
+ test_parse "0"
104
+ test_parse "0\n0"
105
+ test_parse "0\n0;0"
106
+ test_parse "0 0", :should_fail_at => 2
107
+ end
108
+
109
+ it "custom global delimiter should work" do
110
+ new_parser do
111
+ delimiter /[_\s]*/
112
+
113
+ rule :foobar, "foo", "bar"
114
+ end
115
+
116
+ test_parse "foobar"
117
+ test_parse "foo_bar"
118
+ test_parse "foo_ bar"
119
+ test_parse "foo _ bar"
120
+ test_parse "foo bar"
121
+ test_parse "foo-bar", :should_fail_at => 3
122
+ end
123
+
124
+
125
+ it "should work to rewind_whitespace, :rule" do
126
+ new_parser do
127
+ ignore_whitespace
128
+ rule :two, :statement, :statement do
129
+ def to_model
130
+ statement.map {|a|a.to_model}
131
+ end
132
+ end
133
+ rule :statement, :identifier, :parameter?, :delimiter => // do
134
+ def to_model
135
+ [identifier.to_sym, parameter && parameter.identifier.to_sym]
136
+ end
137
+ end
138
+ rule :parameter, /[ \t]*/, :identifier, :delimiter => //
139
+ rule :identifier, /[_a-zA-Z][_a-zA-Z0-9]*/
140
+ end
141
+
142
+ test_parse("fred\nbar") {|parsed|parsed.to_model.should == [[:fred,nil],[:bar,nil]]}
143
+ test_parse("fred foo\nbar") {|parsed|parsed.to_model.should == [[:fred,:foo],[:bar,nil]]}
144
+ end
145
+
146
+ it "should work to have nested custom delimiters" do
147
+ new_parser do
148
+ ignore_whitespace
149
+ rule :all, :call, :call do
150
+ def to_model
151
+ call.collect &:to_model
152
+ end
153
+ end
154
+ rule :call, :identifier, :parameters?, :delimiter => // do
155
+ def to_model
156
+ [identifier.to_sym, parameters && parameters.to_s]
157
+ end
158
+ end
159
+ rule :parameters, /[ \t]*/, many(:identifier,","), :delimiter => //
160
+ rule :identifier, /[_a-zA-Z][_a-zA-Z0-9]*/
161
+ end
162
+
163
+ test_parse("fred\nbar") {|parsed| parsed.to_model.should==[[:fred,nil],[:bar,nil]]}
164
+ test_parse("fred foo\nbar") {|parsed| parsed.to_model.should==[[:fred," foo"],[:bar,nil]]}
165
+ test_parse("fred foo,bar\nbar") {|parsed| parsed.to_model.should==[[:fred," foo,bar"],[:bar,nil]]}
166
+ end
167
+
168
+ it "dont.match shouldn't consume any whitespace" do
169
+ new_parser do
170
+ ignore_whitespace
171
+ rule :statements, :statement, "bar"
172
+ rule :statement, :identifier, :parameters?, :delimiter => //
173
+ rule :parameters, / */, :identifier, :delimiter => //
174
+ rule :identifier, dont.match("end"), /[_a-zA-Z][_a-zA-Z0-9]*/
175
+ end
176
+
177
+ test_parse("fred\nbar")
178
+ #test_parse("fred foo\nbar")
179
+ end
180
+
181
+ it "delimiter should work" do
182
+ new_parser do
183
+ delimiter :custom_delimiter
184
+ rule :foobar, "foo", "bar"
185
+ rule :custom_delimiter, /-*/
186
+ end
187
+
188
+ test_parse "foobar"
189
+ test_parse "foo-bar"
190
+ test_parse "foo---bar"
191
+ end
192
+
193
+ it "should work to have many parsing with whitespace tricks" do
194
+ new_parser do
195
+ ignore_whitespace
196
+ #rule :statements, many(:statement,:end_statement), :delimiter => //
197
+ #rule :end_statement, /([\t ]*[;\n])+/
198
+ #rule :statement, :bin_op
199
+ binary_operators_rule :bin_op, :int, ["**", [:/, :*], [:+, "-"]], :right_operators => ["**"]
200
+ rule :int, /\d+/
201
+ end
202
+
203
+ =begin
204
+ NOTES: the problem is the post-parsing results method-missing methods don't work well.
205
+
206
+ If a named pattern is never matched, method-missing will fail. It should return nil.
207
+ If a named pattern may match 1 or more times, you will get back a singleton OR an array depending on the number of times.
208
+
209
+ I think the right answer is to drop method-missing entirely. Instead, when the rule is declared, create the accessor methods explicitly.
210
+
211
+ If a named pattern could match more than once, it will always return an array.
212
+
213
+ If it could match 0 times, it will work and return nil, if 0 times were indeed matched.
214
+
215
+ =end
216
+ test_parse "3"
217
+ =begin
218
+ test_parse "3+4"
219
+ test_parse <<ENDCODE
220
+ 3+4
221
+ 9-2
222
+ 4
223
+ ENDCODE
224
+ =end
225
+ end
226
+
227
+ end