babel_bridge 0.4.1 → 0.5.0
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/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,50 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "ManyNode#inspect" do
|
4
|
+
include TestParserGenerator
|
5
|
+
|
6
|
+
def basic_many_parser
|
7
|
+
new_parser do
|
8
|
+
rule :foobar, many("foo", ",")
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def inspect_test(a,options={})
|
13
|
+
a.inspect(options).rstrip.gsub(/[ \t]+\n/,"\n")+"\n"
|
14
|
+
end
|
15
|
+
|
16
|
+
it "with no options should look like this" do
|
17
|
+
basic_many_parser
|
18
|
+
test_parse("foo").inspect.should == 'FoobarNode1 > "foo"'
|
19
|
+
inspect_test(test_parse("foo,foo,foo")).should == <<ENDINSPECT
|
20
|
+
FoobarNode1
|
21
|
+
"foo"
|
22
|
+
"foo"
|
23
|
+
"foo"
|
24
|
+
ENDINSPECT
|
25
|
+
end
|
26
|
+
|
27
|
+
it "with :simple=>true should look like this" do
|
28
|
+
basic_many_parser
|
29
|
+
test_parse("foo").inspect(:simple=>true).should == 'FoobarNode1 > "foo"'
|
30
|
+
inspect_test(test_parse("foo,foo,foo"),:simple=>true).should == <<ENDINSPECT
|
31
|
+
FoobarNode1
|
32
|
+
"foo"
|
33
|
+
"foo"
|
34
|
+
"foo"
|
35
|
+
ENDINSPECT
|
36
|
+
end
|
37
|
+
|
38
|
+
it "with :verbose=>true should look like this" do
|
39
|
+
basic_many_parser
|
40
|
+
test_parse("foo").inspect(:verbose=>true).should == 'FoobarNode1 > "foo"'
|
41
|
+
inspect_test(test_parse("foo,foo,foo"),:verbose=>true).should == <<ENDINSPECT
|
42
|
+
FoobarNode1
|
43
|
+
"foo"
|
44
|
+
","
|
45
|
+
"foo"
|
46
|
+
","
|
47
|
+
"foo"
|
48
|
+
ENDINSPECT
|
49
|
+
end
|
50
|
+
end
|
data/spec/many_spec.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "many parsing" do
|
4
|
+
include TestParserGenerator
|
5
|
+
|
6
|
+
it "anonymous manys should work" do
|
7
|
+
new_parser do
|
8
|
+
rule :foo, many("bar")
|
9
|
+
end
|
10
|
+
|
11
|
+
test_parse("bar").matches.length.should == 1
|
12
|
+
test_parse("barbar").matches.length.should == 2
|
13
|
+
end
|
14
|
+
|
15
|
+
it "named manys should work" do
|
16
|
+
new_parser do
|
17
|
+
rule :foo, many(:bar)
|
18
|
+
rule :bar, "bar"
|
19
|
+
end
|
20
|
+
|
21
|
+
test_parse("bar").bar.class.should == BabelBridge::MultiMatchesArray
|
22
|
+
test_parse("barbar").bar.class.should == BabelBridge::MultiMatchesArray
|
23
|
+
end
|
24
|
+
|
25
|
+
it "parse that matches nothing on a many? on the first character should still report valid parser_failure_info" do
|
26
|
+
new_parser do
|
27
|
+
rule :foo, many?("foo")
|
28
|
+
end
|
29
|
+
|
30
|
+
res = parser.parse "bar"
|
31
|
+
parser.parser_failure_info(:verbose => true).class.should == String
|
32
|
+
end
|
33
|
+
|
34
|
+
it "many with .as should work" do
|
35
|
+
new_parser do
|
36
|
+
rule :foo, many("foo").as(:boo)
|
37
|
+
end
|
38
|
+
|
39
|
+
test_parse("foo").boo.join(',').should == "foo"
|
40
|
+
test_parse("foofoo").boo.join(',').should == "foo,foo"
|
41
|
+
test_parse("foofoofoo").boo.join(',').should == "foo,foo,foo"
|
42
|
+
end
|
43
|
+
|
44
|
+
it "many with delimiter" do
|
45
|
+
new_parser do
|
46
|
+
rule :foo, many("foo",";").as(:foo)
|
47
|
+
end
|
48
|
+
test_parse("foo").foo.collect {|f| f.text}.should == %w{foo}
|
49
|
+
test_parse("foo;foo").foo.collect {|f| f.text}.should == %w{foo foo}
|
50
|
+
end
|
51
|
+
|
52
|
+
it "test_poly_optional_delimiter" do
|
53
|
+
parser=new_parser do
|
54
|
+
rule :foo, many(";",match?(/ +/))
|
55
|
+
end
|
56
|
+
test_parse ";"
|
57
|
+
test_parse ";;"
|
58
|
+
test_parse "; ; ;"
|
59
|
+
end
|
60
|
+
end
|
data/spec/node_spec.rb
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "basic parsing" do
|
4
|
+
include TestParserGenerator
|
5
|
+
|
6
|
+
it "offset, matchs, text, and length" do
|
7
|
+
new_parser do
|
8
|
+
rule :foo, "foo", match?("bar")
|
9
|
+
end
|
10
|
+
|
11
|
+
test_parse("foo").offset.should == 0
|
12
|
+
test_parse("foobar").matches[1].offset.should == 3
|
13
|
+
test_parse("foo").length.should == 1
|
14
|
+
test_parse("foobar").length.should == 2
|
15
|
+
test_parse("foo").text.should == "foo"
|
16
|
+
test_parse("foobar").to_s.should == "foobar"
|
17
|
+
end
|
18
|
+
|
19
|
+
it "test custom node methods" do
|
20
|
+
new_parser do
|
21
|
+
rule :number, /[0-9]+/ do
|
22
|
+
def number
|
23
|
+
text.to_i
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
test_parse("123").number.should == 123
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_adder
|
32
|
+
new_parser do
|
33
|
+
rule :adder, :number, "+", :number do
|
34
|
+
def answer;
|
35
|
+
number[0].number + number[1].number
|
36
|
+
end
|
37
|
+
end
|
38
|
+
rule :number, /[0-9]+/ do
|
39
|
+
def number; text.to_i end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
test_parser("123+654").answer.should == 777
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_adder_multiplier
|
48
|
+
new_parser do
|
49
|
+
|
50
|
+
rule :adder, :multiplier, "+", :adder do
|
51
|
+
def value
|
52
|
+
multiplier.value + adder.value
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
rule :adder, :multiplier do
|
57
|
+
def value
|
58
|
+
multiplier.value
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
rule :multiplier, :number, "*", :multiplier do
|
63
|
+
def value
|
64
|
+
number.value * multiplier.value
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
rule :multiplier, :number do
|
69
|
+
def value
|
70
|
+
number.value
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
rule :number, /[0-9]+/ do
|
75
|
+
def value; text.to_i end
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
test_parse("123").value.should == 123
|
81
|
+
test_parse("123*3").value.should == 123*3
|
82
|
+
test_parse("123*3+1").value.should == 123*3+1
|
83
|
+
test_parse("123+3*2").value.should == 123+3*2
|
84
|
+
test_parse("123+654").value.should == 123+654
|
85
|
+
test_parse("20*4+1+100*2").value.should == 20*4+1+100*2
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
it "test_indexed_match_reference_with_optional" do
|
90
|
+
new_parser do
|
91
|
+
rule :foo, :bar, :boo?, :bar do
|
92
|
+
def outter
|
93
|
+
bar[0].text + bar[1].text
|
94
|
+
end
|
95
|
+
end
|
96
|
+
rule :bar, /[0-9]+,?/
|
97
|
+
rule :boo, /[A-Z]+,?/
|
98
|
+
end
|
99
|
+
|
100
|
+
test_parse("1,2").outter.should == "1,2"
|
101
|
+
test_parse("1,A,3").outter.should == "1,3"
|
102
|
+
end
|
103
|
+
|
104
|
+
|
105
|
+
it "test_rule_class" do
|
106
|
+
new_parser do
|
107
|
+
rule :foo, "foo"
|
108
|
+
rule :foo, "bar"
|
109
|
+
node_class :foo do
|
110
|
+
def value; text end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
test_parse("foo").value.should=="foo"
|
115
|
+
test_parse("bar").value.should=="bar"
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "basic parsing" do
|
4
|
+
include TestParserGenerator
|
5
|
+
|
6
|
+
it "test_many" do
|
7
|
+
BabelBridge::Parser.many(";").hash.should == {:many=>";",:match=>true}
|
8
|
+
end
|
9
|
+
|
10
|
+
it "test_many?" do
|
11
|
+
BabelBridge::Parser.many?(";").hash.should == {:many=>";", :optionally=>true, :match=>true}
|
12
|
+
end
|
13
|
+
|
14
|
+
it "test_many!" do
|
15
|
+
BabelBridge::Parser.many!(";").hash.should == {:many=>";", :dont=>true, :match=>true}
|
16
|
+
end
|
17
|
+
|
18
|
+
it "test_match" do
|
19
|
+
BabelBridge::Parser.match(";").hash.should == {:match=>";"}
|
20
|
+
end
|
21
|
+
|
22
|
+
it "test_match?" do
|
23
|
+
BabelBridge::Parser.match?(";").hash.should == {:match=>";",:optionally=>true}
|
24
|
+
end
|
25
|
+
|
26
|
+
it "test_match!" do
|
27
|
+
BabelBridge::Parser.match!(";").hash.should == {:match=>";",:dont=>true}
|
28
|
+
end
|
29
|
+
|
30
|
+
it "test_dont" do
|
31
|
+
BabelBridge::Parser.dont.match(";").hash.should == {:match=>";",:dont=>true}
|
32
|
+
end
|
33
|
+
|
34
|
+
it "test_optionally" do
|
35
|
+
BabelBridge::Parser.optionally.match(";").hash.should == {:match=>";",:optionally=>true}
|
36
|
+
end
|
37
|
+
|
38
|
+
it "test_could" do
|
39
|
+
BabelBridge::Parser.could.match(";").hash.should == {:match=>";",:could=>true}
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "more complex rule structure parsing" do
|
4
|
+
include TestParserGenerator
|
5
|
+
|
6
|
+
it "sub-rules should work" do
|
7
|
+
new_parser do
|
8
|
+
rule :foo, "foo", :bar
|
9
|
+
rule :bar, "bar"
|
10
|
+
end
|
11
|
+
|
12
|
+
test_parse "foo", :should_fail_at => 3
|
13
|
+
test_parse "foobar"
|
14
|
+
end
|
15
|
+
|
16
|
+
it "optional rule" do
|
17
|
+
new_parser do
|
18
|
+
rule :foo, "foo", :bar?
|
19
|
+
rule :bar, "bar"
|
20
|
+
end
|
21
|
+
|
22
|
+
test_parse "foo"
|
23
|
+
test_parse "foobar"
|
24
|
+
end
|
25
|
+
|
26
|
+
it "not-match rule" do
|
27
|
+
new_parser do
|
28
|
+
rule :foo, :boo!, /[a-zA-Z]+/
|
29
|
+
rule :boo, "boo"
|
30
|
+
end
|
31
|
+
|
32
|
+
test_parse "boo", :should_fail_at => 0
|
33
|
+
test_parse "foo"
|
34
|
+
test_parse "boO"
|
35
|
+
end
|
36
|
+
|
37
|
+
it "rule variants should work" do
|
38
|
+
v1=nil
|
39
|
+
v2=nil
|
40
|
+
new_parser do
|
41
|
+
v1=rule :foo, "foo"
|
42
|
+
v2=rule :foo, "bar"
|
43
|
+
end
|
44
|
+
|
45
|
+
test_parse("foo").class.should == v1
|
46
|
+
test_parse("bar").class.should == v2
|
47
|
+
test_parse "baz", :should_fail_at => 0
|
48
|
+
end
|
49
|
+
|
50
|
+
it "test right-recursive" do
|
51
|
+
new_parser do
|
52
|
+
rule :foo, "foo", :foo?
|
53
|
+
end
|
54
|
+
|
55
|
+
test_parse "foo"
|
56
|
+
test_parse "foofoo"
|
57
|
+
test_parse "foofoofoo"
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__),"..","lib","babel_bridge")
|
2
|
+
|
3
|
+
module TestParserGenerator
|
4
|
+
|
5
|
+
attr_accessor :parser
|
6
|
+
|
7
|
+
def new_parser(&block)
|
8
|
+
$parser_counter||=0
|
9
|
+
$parser_counter+=1
|
10
|
+
Object.const_set(klass_name="TestParser#{$parser_counter}",Class.new(BabelBridge::Parser,&block))
|
11
|
+
@parser=Object.const_get(klass_name).new
|
12
|
+
end
|
13
|
+
|
14
|
+
#options
|
15
|
+
# :parser
|
16
|
+
# :failure_ok
|
17
|
+
def test_parse(string,options={},&block)
|
18
|
+
parser = options[:parser] || @parser
|
19
|
+
res = parser.parse(string,options)
|
20
|
+
yield res if res && block
|
21
|
+
if options[:should_fail_at]
|
22
|
+
res.should == nil
|
23
|
+
parser.failure_index.should == options[:should_fail_at]
|
24
|
+
elsif !options[:failure_ok]
|
25
|
+
puts parser.parser_failure_info :verbose => true unless res
|
26
|
+
res.should_not == nil
|
27
|
+
end
|
28
|
+
res
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
data/spec/tools_spec.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Tools::" do
|
4
|
+
include TestParserGenerator
|
5
|
+
|
6
|
+
|
7
|
+
it "line_col" do
|
8
|
+
"". line_col(0).should == [1,1]
|
9
|
+
" ". line_col(0).should == [1,1]
|
10
|
+
"a\nbb\nccc". line_col(0).should == [1,1]
|
11
|
+
"a\nbb\nccc". line_col(1).should == [1,2]
|
12
|
+
"a\nbb\nccc". line_col(2).should == [2,1]
|
13
|
+
"a\nbb\nccc". line_col(3).should == [2,2]
|
14
|
+
"a\nbb\nccc". line_col(4).should == [2,3]
|
15
|
+
"a\nbb\nccc". line_col(5).should == [3,1]
|
16
|
+
"a\nbb\nccc". line_col(6).should == [3,2]
|
17
|
+
"a\nbb\nccc". line_col(7).should == [3,3]
|
18
|
+
"a\nbb\nccc". line_col(8).should == [3,4]
|
19
|
+
"a\nbb\nccc". line_col(9).should == [3,4]
|
20
|
+
end
|
21
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: babel_bridge
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -55,15 +55,24 @@ extensions: []
|
|
55
55
|
extra_rdoc_files: []
|
56
56
|
files:
|
57
57
|
- README
|
58
|
+
- Rakefile
|
58
59
|
- babel_bridge.gemspec
|
59
|
-
-
|
60
|
-
-
|
60
|
+
- spec/advanced_parsers_spec.rb
|
61
|
+
- spec/basic_parsing_spec.rb
|
61
62
|
- spec/bb_spec.rb
|
63
|
+
- spec/ignore_whitespace_spec.rb
|
64
|
+
- spec/inspect_spec.rb
|
65
|
+
- spec/many_spec.rb
|
66
|
+
- spec/node_spec.rb
|
67
|
+
- spec/pattern_generators_spec.rb
|
68
|
+
- spec/rule_parsing_spec.rb
|
69
|
+
- spec/spec_helper.rb
|
70
|
+
- spec/tools_spec.rb
|
62
71
|
- lib/babel_bridge.rb
|
63
72
|
- lib/nodes/empty_node.rb
|
64
|
-
- lib/nodes/many_node.rb
|
65
73
|
- lib/nodes/node.rb
|
66
74
|
- lib/nodes/non_terminal_node.rb
|
75
|
+
- lib/nodes/root_node.rb
|
67
76
|
- lib/nodes/rule_node.rb
|
68
77
|
- lib/nodes/terminal_node.rb
|
69
78
|
- lib/nodes.rb
|
data/lib/nodes/many_node.rb
DELETED
@@ -1,53 +0,0 @@
|
|
1
|
-
=begin
|
2
|
-
Copyright 2011 Shane Brinkman-Davis
|
3
|
-
See README for licence information.
|
4
|
-
http://babel-bridge.rubyforge.org/
|
5
|
-
=end
|
6
|
-
|
7
|
-
module BabelBridge
|
8
|
-
# generated by a :poly PatternElement
|
9
|
-
# Not subclassed
|
10
|
-
class ManyNode < NonTerminalNode
|
11
|
-
|
12
|
-
def delimiter_matches
|
13
|
-
@delimiter_matches||=[]
|
14
|
-
end
|
15
|
-
|
16
|
-
def separate_delimiter_matches
|
17
|
-
count = 0
|
18
|
-
@matches, @delimiter_matches = matches.partition {|el| count+=1;(count%2==1)}
|
19
|
-
@delimiter_matches = @delimiter_matches[0..@matches.length-2] #delimiter_matches should be exactly 1 shorter
|
20
|
-
update_match_length
|
21
|
-
end
|
22
|
-
|
23
|
-
def inspect_helper(list,options)
|
24
|
-
simple=options[:simple]
|
25
|
-
ret=list.collect {|a|a.inspect(options)}.compact
|
26
|
-
ret= if ret.length==0 then simple ? nil : "[]"
|
27
|
-
elsif ret.length==1 && !ret[0]["\n"] then (simple ? ret[0] : "[#{ret[0]}]")
|
28
|
-
else
|
29
|
-
ret = ret.collect {|a| " "+a.gsub("\n","\n ")}
|
30
|
-
(simple ? ret : ["[",ret,"]"]).flatten.join("\n") #.gsub("\n","\n ")
|
31
|
-
end
|
32
|
-
ret
|
33
|
-
end
|
34
|
-
|
35
|
-
def inspect(options={})
|
36
|
-
if options[:simple]
|
37
|
-
c=[]
|
38
|
-
matches.each_with_index {|n,i| c<<n;c<<delimiter_matches[i]}
|
39
|
-
c=c.compact
|
40
|
-
inspect_helper(c,options)
|
41
|
-
else
|
42
|
-
ret=inspect_helper(matches,options)
|
43
|
-
ret+=" delimiters="+inspect_helper(delimiter_matches,options) if delimiter_matches.length>0
|
44
|
-
ret
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
def method_missing(method_name, *args) #method_name is a symbol
|
49
|
-
self.map {|match| match.send(method_name,*args)}
|
50
|
-
end
|
51
|
-
|
52
|
-
end
|
53
|
-
end
|