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.
- data/Rakefile +6 -0
- data/lib/nodes.rb +1 -1
- data/lib/nodes/empty_node.rb +1 -20
- data/lib/nodes/node.rb +33 -32
- data/lib/nodes/non_terminal_node.rb +10 -13
- data/lib/nodes/root_node.rb +4 -0
- data/lib/nodes/rule_node.rb +97 -44
- data/lib/nodes/terminal_node.rb +3 -3
- data/lib/parser.rb +95 -61
- data/lib/pattern_element.rb +71 -43
- data/lib/rule.rb +12 -6
- data/lib/rule_variant.rb +39 -15
- data/lib/string.rb +2 -9
- data/lib/tools.rb +26 -6
- data/lib/version.rb +2 -1
- data/spec/advanced_parsers_spec.rb +49 -0
- data/spec/basic_parsing_spec.rb +94 -0
- data/spec/bb_spec.rb +7 -163
- data/spec/ignore_whitespace_spec.rb +227 -0
- data/spec/inspect_spec.rb +50 -0
- data/spec/many_spec.rb +60 -0
- data/spec/node_spec.rb +117 -0
- data/spec/pattern_generators_spec.rb +41 -0
- data/spec/rule_parsing_spec.rb +61 -0
- data/spec/spec_helper.rb +31 -0
- data/spec/tools_spec.rb +21 -0
- metadata +13 -4
- data/lib/nodes/many_node.rb +0 -53
- data/test/test_bb.rb +0 -458
- data/test/test_helper.rb +0 -44
@@ -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
|
data/spec/bb_spec.rb
CHANGED
@@ -1,44 +1,7 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
3
|
describe BabelBridge do
|
4
|
-
|
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 "
|
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
|
-
|
150
|
-
rule :
|
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("
|
208
|
-
test_parse("
|
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
|