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