regexp_parser 0.1.6 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. checksums.yaml +4 -4
  2. data/ChangeLog +57 -0
  3. data/Gemfile +8 -0
  4. data/LICENSE +1 -1
  5. data/README.md +225 -206
  6. data/Rakefile +9 -3
  7. data/lib/regexp_parser.rb +7 -11
  8. data/lib/regexp_parser/expression.rb +72 -14
  9. data/lib/regexp_parser/expression/classes/alternation.rb +3 -16
  10. data/lib/regexp_parser/expression/classes/conditional.rb +57 -0
  11. data/lib/regexp_parser/expression/classes/free_space.rb +17 -0
  12. data/lib/regexp_parser/expression/classes/keep.rb +7 -0
  13. data/lib/regexp_parser/expression/classes/set.rb +28 -7
  14. data/lib/regexp_parser/expression/methods/strfregexp.rb +113 -0
  15. data/lib/regexp_parser/expression/methods/tests.rb +116 -0
  16. data/lib/regexp_parser/expression/methods/traverse.rb +63 -0
  17. data/lib/regexp_parser/expression/quantifier.rb +10 -0
  18. data/lib/regexp_parser/expression/sequence.rb +45 -0
  19. data/lib/regexp_parser/expression/subexpression.rb +29 -1
  20. data/lib/regexp_parser/lexer.rb +31 -8
  21. data/lib/regexp_parser/parser.rb +118 -45
  22. data/lib/regexp_parser/scanner.rb +1745 -1404
  23. data/lib/regexp_parser/scanner/property.rl +57 -3
  24. data/lib/regexp_parser/scanner/scanner.rl +161 -34
  25. data/lib/regexp_parser/syntax.rb +12 -2
  26. data/lib/regexp_parser/syntax/ruby/1.9.1.rb +3 -3
  27. data/lib/regexp_parser/syntax/ruby/1.9.3.rb +2 -7
  28. data/lib/regexp_parser/syntax/ruby/2.0.0.rb +4 -1
  29. data/lib/regexp_parser/syntax/ruby/2.1.4.rb +13 -0
  30. data/lib/regexp_parser/syntax/ruby/2.1.5.rb +13 -0
  31. data/lib/regexp_parser/syntax/ruby/2.1.rb +2 -2
  32. data/lib/regexp_parser/syntax/ruby/2.2.0.rb +16 -0
  33. data/lib/regexp_parser/syntax/ruby/2.2.rb +8 -0
  34. data/lib/regexp_parser/syntax/tokens.rb +19 -2
  35. data/lib/regexp_parser/syntax/tokens/conditional.rb +22 -0
  36. data/lib/regexp_parser/syntax/tokens/keep.rb +14 -0
  37. data/lib/regexp_parser/syntax/tokens/unicode_property.rb +45 -4
  38. data/lib/regexp_parser/token.rb +23 -8
  39. data/lib/regexp_parser/version.rb +5 -0
  40. data/regexp_parser.gemspec +35 -0
  41. data/test/expression/test_all.rb +6 -1
  42. data/test/expression/test_base.rb +19 -0
  43. data/test/expression/test_conditionals.rb +114 -0
  44. data/test/expression/test_free_space.rb +33 -0
  45. data/test/expression/test_set.rb +61 -0
  46. data/test/expression/test_strfregexp.rb +214 -0
  47. data/test/expression/test_subexpression.rb +24 -0
  48. data/test/expression/test_tests.rb +99 -0
  49. data/test/expression/test_to_h.rb +48 -0
  50. data/test/expression/test_to_s.rb +46 -0
  51. data/test/expression/test_traverse.rb +164 -0
  52. data/test/lexer/test_all.rb +16 -3
  53. data/test/lexer/test_conditionals.rb +101 -0
  54. data/test/lexer/test_keep.rb +24 -0
  55. data/test/lexer/test_literals.rb +51 -51
  56. data/test/lexer/test_nesting.rb +62 -62
  57. data/test/lexer/test_refcalls.rb +18 -20
  58. data/test/parser/test_all.rb +18 -3
  59. data/test/parser/test_alternation.rb +11 -14
  60. data/test/parser/test_conditionals.rb +148 -0
  61. data/test/parser/test_escapes.rb +29 -5
  62. data/test/parser/test_free_space.rb +139 -0
  63. data/test/parser/test_groups.rb +40 -0
  64. data/test/parser/test_keep.rb +21 -0
  65. data/test/scanner/test_all.rb +8 -2
  66. data/test/scanner/test_conditionals.rb +166 -0
  67. data/test/scanner/test_escapes.rb +8 -5
  68. data/test/scanner/test_free_space.rb +133 -0
  69. data/test/scanner/test_groups.rb +28 -0
  70. data/test/scanner/test_keep.rb +33 -0
  71. data/test/scanner/test_properties.rb +4 -0
  72. data/test/scanner/test_scripts.rb +71 -1
  73. data/test/syntax/ruby/test_1.9.3.rb +2 -2
  74. data/test/syntax/ruby/test_2.0.0.rb +38 -0
  75. data/test/syntax/ruby/test_2.2.0.rb +38 -0
  76. data/test/syntax/ruby/test_all.rb +1 -8
  77. data/test/syntax/ruby/test_files.rb +104 -0
  78. data/test/test_all.rb +2 -1
  79. data/test/token/test_all.rb +2 -0
  80. data/test/token/test_token.rb +109 -0
  81. metadata +75 -21
  82. data/VERSION.yml +0 -5
  83. data/lib/regexp_parser/ctype.rb +0 -48
  84. data/test/syntax/ruby/test_2.x.rb +0 -46
@@ -4,91 +4,91 @@ class LexerNesting < Test::Unit::TestCase
4
4
 
5
5
  tests = {
6
6
  '(((b)))' => {
7
- 0 => [:group, :capture, '(', 0, 1, 0, 0],
8
- 1 => [:group, :capture, '(', 1, 2, 1, 0],
9
- 2 => [:group, :capture, '(', 2, 3, 2, 0],
10
- 3 => [:literal, :literal, 'b', 3, 4, 3, 0],
11
- 4 => [:group, :close, ')', 4, 5, 2, 0],
12
- 5 => [:group, :close, ')', 5, 6, 1, 0],
13
- 6 => [:group, :close, ')', 6, 7, 0, 0],
7
+ 0 => [:group, :capture, '(', 0, 1, 0, 0, 0],
8
+ 1 => [:group, :capture, '(', 1, 2, 1, 0, 0],
9
+ 2 => [:group, :capture, '(', 2, 3, 2, 0, 0],
10
+ 3 => [:literal, :literal, 'b', 3, 4, 3, 0, 0],
11
+ 4 => [:group, :close, ')', 4, 5, 2, 0, 0],
12
+ 5 => [:group, :close, ')', 5, 6, 1, 0, 0],
13
+ 6 => [:group, :close, ')', 6, 7, 0, 0, 0],
14
14
  },
15
15
 
16
16
  '(\((b)\))' => {
17
- 0 => [:group, :capture, '(', 0, 1, 0, 0],
18
- 1 => [:escape, :group_open, '\(', 1, 3, 1, 0],
19
- 2 => [:group, :capture, '(', 3, 4, 1, 0],
20
- 3 => [:literal, :literal, 'b', 4, 5, 2, 0],
21
- 4 => [:group, :close, ')', 5, 6, 1, 0],
22
- 5 => [:escape, :group_close, '\)', 6, 8, 1, 0],
23
- 6 => [:group, :close, ')', 8, 9, 0, 0],
17
+ 0 => [:group, :capture, '(', 0, 1, 0, 0, 0],
18
+ 1 => [:escape, :group_open, '\(', 1, 3, 1, 0, 0],
19
+ 2 => [:group, :capture, '(', 3, 4, 1, 0, 0],
20
+ 3 => [:literal, :literal, 'b', 4, 5, 2, 0, 0],
21
+ 4 => [:group, :close, ')', 5, 6, 1, 0, 0],
22
+ 5 => [:escape, :group_close, '\)', 6, 8, 1, 0, 0],
23
+ 6 => [:group, :close, ')', 8, 9, 0, 0, 0],
24
24
  },
25
25
 
26
26
  '(?>a(?>b(?>c)))' => {
27
- 0 => [:group, :atomic, '(?>', 0, 3, 0, 0],
28
- 2 => [:group, :atomic, '(?>', 4, 7, 1, 0],
29
- 4 => [:group, :atomic, '(?>', 8, 11, 2, 0],
30
- 6 => [:group, :close, ')', 12, 13, 2, 0],
31
- 7 => [:group, :close, ')', 13, 14, 1, 0],
32
- 8 => [:group, :close, ')', 14, 15, 0, 0],
27
+ 0 => [:group, :atomic, '(?>', 0, 3, 0, 0, 0],
28
+ 2 => [:group, :atomic, '(?>', 4, 7, 1, 0, 0],
29
+ 4 => [:group, :atomic, '(?>', 8, 11, 2, 0, 0],
30
+ 6 => [:group, :close, ')', 12, 13, 2, 0, 0],
31
+ 7 => [:group, :close, ')', 13, 14, 1, 0, 0],
32
+ 8 => [:group, :close, ')', 14, 15, 0, 0, 0],
33
33
  },
34
34
 
35
35
  '(?:a(?:b(?:c)))' => {
36
- 0 => [:group, :passive, '(?:', 0, 3, 0, 0],
37
- 2 => [:group, :passive, '(?:', 4, 7, 1, 0],
38
- 4 => [:group, :passive, '(?:', 8, 11, 2, 0],
39
- 6 => [:group, :close, ')', 12, 13, 2, 0],
40
- 7 => [:group, :close, ')', 13, 14, 1, 0],
41
- 8 => [:group, :close, ')', 14, 15, 0, 0],
36
+ 0 => [:group, :passive, '(?:', 0, 3, 0, 0, 0],
37
+ 2 => [:group, :passive, '(?:', 4, 7, 1, 0, 0],
38
+ 4 => [:group, :passive, '(?:', 8, 11, 2, 0, 0],
39
+ 6 => [:group, :close, ')', 12, 13, 2, 0, 0],
40
+ 7 => [:group, :close, ')', 13, 14, 1, 0, 0],
41
+ 8 => [:group, :close, ')', 14, 15, 0, 0, 0],
42
42
  },
43
43
 
44
44
  '(?=a(?!b(?<=c(?<!d))))' => {
45
- 0 => [:assertion, :lookahead, '(?=', 0, 3, 0, 0],
46
- 2 => [:assertion, :nlookahead, '(?!', 4, 7, 1, 0],
47
- 4 => [:assertion, :lookbehind, '(?<=', 8, 12, 2, 0],
48
- 6 => [:assertion, :nlookbehind, '(?<!', 13, 17, 3, 0],
49
- 8 => [:group, :close, ')', 18, 19, 3, 0],
50
- 9 => [:group, :close, ')', 19, 20, 2, 0],
51
- 10 => [:group, :close, ')', 20, 21, 1, 0],
52
- 11 => [:group, :close, ')', 21, 22, 0, 0],
45
+ 0 => [:assertion, :lookahead, '(?=', 0, 3, 0, 0, 0],
46
+ 2 => [:assertion, :nlookahead, '(?!', 4, 7, 1, 0, 0],
47
+ 4 => [:assertion, :lookbehind, '(?<=', 8, 12, 2, 0, 0],
48
+ 6 => [:assertion, :nlookbehind, '(?<!', 13, 17, 3, 0, 0],
49
+ 8 => [:group, :close, ')', 18, 19, 3, 0, 0],
50
+ 9 => [:group, :close, ')', 19, 20, 2, 0, 0],
51
+ 10 => [:group, :close, ')', 20, 21, 1, 0, 0],
52
+ 11 => [:group, :close, ')', 21, 22, 0, 0, 0],
53
53
  },
54
54
 
55
55
  '((?#a)b(?#c)d(?#e))' => {
56
- 0 => [:group, :capture, '(', 0, 1, 0, 0],
57
- 1 => [:group, :comment, '(?#a)', 1, 6, 1, 0],
58
- 3 => [:group, :comment, '(?#c)', 7, 12, 1, 0],
59
- 5 => [:group, :comment, '(?#e)', 13, 18, 1, 0],
60
- 6 => [:group, :close, ')', 18, 19, 0, 0],
56
+ 0 => [:group, :capture, '(', 0, 1, 0, 0, 0],
57
+ 1 => [:group, :comment, '(?#a)', 1, 6, 1, 0, 0],
58
+ 3 => [:group, :comment, '(?#c)', 7, 12, 1, 0, 0],
59
+ 5 => [:group, :comment, '(?#e)', 13, 18, 1, 0, 0],
60
+ 6 => [:group, :close, ')', 18, 19, 0, 0, 0],
61
61
  },
62
62
 
63
63
  'a[b-e]f' => {
64
- 1 => [:set, :open, '[', 1, 2, 0, 0],
65
- 2 => [:set, :range, 'b-e', 2, 5, 0, 1],
66
- 3 => [:set, :close, ']', 5, 6, 0, 0],
64
+ 1 => [:set, :open, '[', 1, 2, 0, 0, 0],
65
+ 2 => [:set, :range, 'b-e', 2, 5, 0, 1, 0],
66
+ 3 => [:set, :close, ']', 5, 6, 0, 0, 0],
67
67
  },
68
68
 
69
69
  '[a-w&&[^c-g]z]' => {
70
- 0 => [:set, :open, '[', 0, 1, 0, 0],
71
- 2 => [:set, :intersection, '&&', 4, 6, 0, 1],
72
- 3 => [:subset, :open, '[', 6, 7, 0, 1],
73
- 4 => [:subset, :negate, '^', 7, 8, 0, 2],
74
- 5 => [:subset, :range, 'c-g', 8, 11, 0, 2],
75
- 6 => [:subset, :close, ']', 11, 12, 0, 1],
76
- 8 => [:set, :close, ']', 13, 14, 0, 0],
70
+ 0 => [:set, :open, '[', 0, 1, 0, 0, 0],
71
+ 2 => [:set, :intersection, '&&', 4, 6, 0, 1, 0],
72
+ 3 => [:subset, :open, '[', 6, 7, 0, 1, 0],
73
+ 4 => [:subset, :negate, '^', 7, 8, 0, 2, 0],
74
+ 5 => [:subset, :range, 'c-g', 8, 11, 0, 2, 0],
75
+ 6 => [:subset, :close, ']', 11, 12, 0, 1, 0],
76
+ 8 => [:set, :close, ']', 13, 14, 0, 0, 0],
77
77
  },
78
78
 
79
79
  '[a[b[c[d-g]]]]' => {
80
- 0 => [:set, :open, '[', 0, 1, 0, 0],
81
- 1 => [:set, :member, 'a', 1, 2, 0, 1],
82
- 2 => [:subset, :open, '[', 2, 3, 0, 1],
83
- 3 => [:subset, :member, 'b', 3, 4, 0, 2],
84
- 4 => [:subset, :open, '[', 4, 5, 0, 2],
85
- 5 => [:subset, :member, 'c', 5, 6, 0, 3],
86
- 6 => [:subset, :open, '[', 6, 7, 0, 3],
87
- 7 => [:subset, :range, 'd-g', 7, 10, 0, 4],
88
- 8 => [:subset, :close, ']', 10, 11, 0, 3],
89
- 9 => [:subset, :close, ']', 11, 12, 0, 2],
90
- 10 => [:subset, :close, ']', 12, 13, 0, 1],
91
- 11 => [:set, :close, ']', 13, 14, 0, 0],
80
+ 0 => [:set, :open, '[', 0, 1, 0, 0, 0],
81
+ 1 => [:set, :member, 'a', 1, 2, 0, 1, 0],
82
+ 2 => [:subset, :open, '[', 2, 3, 0, 1, 0],
83
+ 3 => [:subset, :member, 'b', 3, 4, 0, 2, 0],
84
+ 4 => [:subset, :open, '[', 4, 5, 0, 2, 0],
85
+ 5 => [:subset, :member, 'c', 5, 6, 0, 3, 0],
86
+ 6 => [:subset, :open, '[', 6, 7, 0, 3, 0],
87
+ 7 => [:subset, :range, 'd-g', 7, 10, 0, 4, 0],
88
+ 8 => [:subset, :close, ']', 10, 11, 0, 3, 0],
89
+ 9 => [:subset, :close, ']', 11, 12, 0, 2, 0],
90
+ 10 => [:subset, :close, ']', 12, 13, 0, 1, 0],
91
+ 11 => [:set, :close, ']', 13, 14, 0, 0, 0],
92
92
  },
93
93
  }
94
94
 
@@ -96,7 +96,7 @@ class LexerNesting < Test::Unit::TestCase
96
96
  tests.each do |pattern, checks|
97
97
  define_method "test_lex_nesting_#{count+=1}" do
98
98
 
99
- tokens = RL.scan(pattern, 'ruby/1.9')
99
+ tokens = RL.lex(pattern, 'ruby/1.9')
100
100
  checks.each do |offset, token|
101
101
  assert_equal( token, tokens[offset].to_a )
102
102
  end
@@ -4,41 +4,39 @@ class LexerRefCalls < Test::Unit::TestCase
4
4
 
5
5
  tests = {
6
6
  # Group back-references, named, numbered, and relative
7
- '(?<X>abc)\k<X>' => [3, :backref, :name_ref, '\k<X>', 9, 14, 0, 0],
8
- "(?<X>abc)\\k'X'" => [3, :backref, :name_ref, "\\k'X'", 9, 14, 0, 0],
7
+ '(?<X>abc)\k<X>' => [3, :backref, :name_ref, '\k<X>', 9, 14, 0, 0, 0],
8
+ "(?<X>abc)\\k'X'" => [3, :backref, :name_ref, "\\k'X'", 9, 14, 0, 0, 0],
9
9
 
10
- '(abc)\k<1>' => [3, :backref, :number_ref, '\k<1>', 5, 10, 0, 0],
11
- "(abc)\\k'1'" => [3, :backref, :number_ref, "\\k'1'", 5, 10, 0, 0],
10
+ '(abc)\k<1>' => [3, :backref, :number_ref, '\k<1>', 5, 10, 0, 0, 0],
11
+ "(abc)\\k'1'" => [3, :backref, :number_ref, "\\k'1'", 5, 10, 0, 0, 0],
12
12
 
13
- '(abc)\k<-1>' => [3, :backref, :number_rel_ref, '\k<-1>', 5, 11, 0, 0],
14
- "(abc)\\k'-1'" => [3, :backref, :number_rel_ref, "\\k'-1'", 5, 11, 0, 0],
13
+ '(abc)\k<-1>' => [3, :backref, :number_rel_ref, '\k<-1>', 5, 11, 0, 0, 0],
14
+ "(abc)\\k'-1'" => [3, :backref, :number_rel_ref, "\\k'-1'", 5, 11, 0, 0, 0],
15
15
 
16
16
  # Sub-expression invocation, named, numbered, and relative
17
- '(?<X>abc)\g<X>' => [3, :backref, :name_call, '\g<X>', 9, 14, 0, 0],
18
- "(?<X>abc)\\g'X'" => [3, :backref, :name_call, "\\g'X'", 9, 14, 0, 0],
17
+ '(?<X>abc)\g<X>' => [3, :backref, :name_call, '\g<X>', 9, 14, 0, 0, 0],
18
+ "(?<X>abc)\\g'X'" => [3, :backref, :name_call, "\\g'X'", 9, 14, 0, 0, 0],
19
19
 
20
- '(abc)\g<1>' => [3, :backref, :number_call, '\g<1>', 5, 10, 0, 0],
21
- "(abc)\\g'1'" => [3, :backref, :number_call, "\\g'1'", 5, 10, 0, 0],
20
+ '(abc)\g<1>' => [3, :backref, :number_call, '\g<1>', 5, 10, 0, 0, 0],
21
+ "(abc)\\g'1'" => [3, :backref, :number_call, "\\g'1'", 5, 10, 0, 0, 0],
22
22
 
23
- '(abc)\g<-1>' => [3, :backref, :number_rel_call, '\g<-1>', 5, 11, 0, 0],
24
- "(abc)\\g'-1'" => [3, :backref, :number_rel_call, "\\g'-1'", 5, 11, 0, 0],
23
+ '(abc)\g<-1>' => [3, :backref, :number_rel_call, '\g<-1>', 5, 11, 0, 0, 0],
24
+ "(abc)\\g'-1'" => [3, :backref, :number_rel_call, "\\g'-1'", 5, 11, 0, 0, 0],
25
25
 
26
26
  # Group back-references, with nesting level
27
- '(?<X>abc)\k<X-0>' => [3, :backref, :name_nest_ref, '\k<X-0>', 9, 16, 0, 0],
28
- "(?<X>abc)\\k'X-0'" => [3, :backref, :name_nest_ref, "\\k'X-0'", 9, 16, 0, 0],
27
+ '(?<X>abc)\k<X-0>' => [3, :backref, :name_nest_ref, '\k<X-0>', 9, 16, 0, 0, 0],
28
+ "(?<X>abc)\\k'X-0'" => [3, :backref, :name_nest_ref, "\\k'X-0'", 9, 16, 0, 0, 0],
29
29
 
30
- '(abc)\k<1-0>' => [3, :backref, :number_nest_ref, '\k<1-0>', 5, 12, 0, 0],
31
- "(abc)\\k'1-0'" => [3, :backref, :number_nest_ref, "\\k'1-0'", 5, 12, 0, 0],
30
+ '(abc)\k<1-0>' => [3, :backref, :number_nest_ref, '\k<1-0>', 5, 12, 0, 0, 0],
31
+ "(abc)\\k'1-0'" => [3, :backref, :number_nest_ref, "\\k'1-0'", 5, 12, 0, 0, 0],
32
32
  }
33
33
 
34
34
  count = 0
35
35
  tests.each do |pattern, test|
36
36
  define_method "test_lexer_#{test[1]}_#{test[2]}_#{count+=1}" do
37
37
 
38
- tokens = RL.scan(pattern, 'ruby/1.9')
39
- assert_equal( test[1,7], tokens[test[0]].to_a)
40
- assert_equal( test[3], pattern[tokens[test[0]][3], tokens[test[0]][4]])
41
-
38
+ tokens = RL.lex(pattern, 'ruby/1.9')
39
+ assert_equal( test[1,8], tokens[test[0]].to_a)
42
40
  end
43
41
  end
44
42
 
@@ -1,18 +1,25 @@
1
1
  require File.expand_path("../../helpers", __FILE__)
2
2
 
3
3
  %w{
4
- alternation anchors errors escapes groups properties
5
- quantifiers refcalls sets
4
+ alternation anchors errors escapes free_space groups
5
+ properties quantifiers refcalls sets
6
6
  }.each do|tc|
7
7
  require File.expand_path("../test_#{tc}", __FILE__)
8
8
  end
9
9
 
10
+ if RUBY_VERSION >= '2.0.0'
11
+ %w{conditionals keep}.each do|tc|
12
+ require File.expand_path("../test_#{tc}", __FILE__)
13
+ end
14
+ end
15
+
10
16
  class TestParser < Test::Unit::TestCase
11
17
 
12
18
  def test_parse_returns_a_root_expression
13
19
  assert_instance_of( Regexp::Expression::Root, RP.parse('abc'))
14
20
  end
15
21
 
22
+
16
23
  def test_parse_root_contains_expressions
17
24
  root = RP.parse(/^a.c+[^one]{2,3}\b\d\\\C-C$/)
18
25
 
@@ -21,7 +28,7 @@ class TestParser < Test::Unit::TestCase
21
28
  "Not all nodes are instances of Regexp::Expression")
22
29
  end
23
30
 
24
- # too much going on here, it's just for development
31
+
25
32
  def test_parse_node_types
26
33
  root = RP.parse('^(one){2,3}([^d\]efm-qz\,\-]*)(ghi)+$')
27
34
 
@@ -41,4 +48,12 @@ class TestParser < Test::Unit::TestCase
41
48
  assert_equal( true, root.expressions[3].quantified? )
42
49
  end
43
50
 
51
+ def test_parse_no_quantifier_target_raises_error
52
+ assert_raise( ArgumentError ) { RP.parse('?abc') }
53
+ end
54
+
55
+ def test_parse_sequence_no_quantifier_target_raises_error
56
+ assert_raise( ArgumentError ) { RP.parse('abc|?def') }
57
+ end
58
+
44
59
  end
@@ -2,9 +2,6 @@ require File.expand_path("../../helpers", __FILE__)
2
2
 
3
3
  class ParserAlternation < Test::Unit::TestCase
4
4
 
5
- # TODO: these tests pass, but they show how hard and messy the tree is
6
- # to navigate
7
-
8
5
  def setup
9
6
  @root = RP.parse('(ab??|cd*|ef+)*|(gh|ij|kl)?')
10
7
  end
@@ -17,8 +14,8 @@ class ParserAlternation < Test::Unit::TestCase
17
14
  def test_parse_alternation_alts
18
15
  alts = @root.expressions[0].alternatives
19
16
 
20
- assert_equal( true, alts[0].is_a?(Sequence) )
21
- assert_equal( true, alts[1].is_a?(Sequence) )
17
+ assert_equal( true, alts[0].is_a?(Alternative) )
18
+ assert_equal( true, alts[1].is_a?(Alternative) )
22
19
 
23
20
  assert_equal( true, alts[0][0].is_a?(Group::Capture) )
24
21
  assert_equal( true, alts[1][0].is_a?(Group::Capture) )
@@ -36,7 +33,7 @@ class ParserAlternation < Test::Unit::TestCase
36
33
  alts = @root.expressions[0][0]
37
34
  nested = alts.expressions[0][0][0]
38
35
 
39
- assert_equal( true, nested.is_a?(Sequence) )
36
+ assert_equal( true, nested.is_a?(Alternative) )
40
37
 
41
38
  assert_equal( true, nested.expressions[0].is_a?(Literal) )
42
39
  assert_equal( true, nested.expressions[1].is_a?(Literal) )
@@ -56,10 +53,10 @@ class ParserAlternation < Test::Unit::TestCase
56
53
  alts = root.expressions[1][0].alternatives
57
54
 
58
55
  assert_equal( 4, alts.length )
59
- assert_equal( true, alts[0].is_a?(Sequence) )
60
- assert_equal( true, alts[1].is_a?(Sequence) )
61
- assert_equal( true, alts[2].is_a?(Sequence) )
62
- assert_equal( true, alts[3].is_a?(Sequence) )
56
+ assert_equal( true, alts[0].is_a?(Alternative) )
57
+ assert_equal( true, alts[1].is_a?(Alternative) )
58
+ assert_equal( true, alts[2].is_a?(Alternative) )
59
+ assert_equal( true, alts[3].is_a?(Alternative) )
63
60
  end
64
61
 
65
62
  def test_parse_alternation_nested_grouped_alts
@@ -68,14 +65,14 @@ class ParserAlternation < Test::Unit::TestCase
68
65
  alts = root.expressions[1][0].alternatives
69
66
 
70
67
  assert_equal( 2, alts.length )
71
- assert_equal( true, alts[0].is_a?(Sequence) )
72
- assert_equal( true, alts[1].is_a?(Sequence) )
68
+ assert_equal( true, alts[0].is_a?(Alternative) )
69
+ assert_equal( true, alts[1].is_a?(Alternative) )
73
70
 
74
71
  subalts = root.expressions[1][0][0][0][0].alternatives
75
72
 
76
73
  assert_equal( 2, alts.length )
77
- assert_equal( true, subalts[0].is_a?(Sequence) )
78
- assert_equal( true, subalts[1].is_a?(Sequence) )
74
+ assert_equal( true, subalts[0].is_a?(Alternative) )
75
+ assert_equal( true, subalts[1].is_a?(Alternative) )
79
76
  end
80
77
 
81
78
  def test_parse_alternation_continues_after_nesting
@@ -0,0 +1,148 @@
1
+ require File.expand_path("../../helpers", __FILE__)
2
+
3
+ class TestParserConditionals < Test::Unit::TestCase
4
+
5
+ def test_parse_conditional
6
+ regexp = /(?<A>a)(?(<A>)T|F)/
7
+
8
+ root = RP.parse(regexp, 'ruby/2.0')
9
+ exp = root.expressions[1]
10
+
11
+ assert( exp.is_a?( Conditional::Expression ),
12
+ "Expected Condition, but got #{exp.class.name}")
13
+
14
+ assert_equal( exp.type, :conditional )
15
+ assert_equal( exp.token, :open )
16
+ assert_equal( exp.text, '(?' )
17
+ end
18
+
19
+
20
+ def test_parse_conditional_condition
21
+ regexp = /(?<A>a)(?(<A>)T|F)/
22
+
23
+ root = RP.parse(regexp, 'ruby/2.0')
24
+ exp = root[1].condition
25
+
26
+ assert( exp.is_a?( Conditional::Condition ),
27
+ "Expected Condition, but got #{exp.class.name}")
28
+
29
+ assert_equal( exp.type, :conditional )
30
+ assert_equal( exp.token, :condition )
31
+ assert_equal( exp.text, '(<A>)' )
32
+ end
33
+
34
+
35
+ def test_parse_conditional_nested_groups
36
+ regexp = /((a)|(b)|((?(2)(c(d|e)+)?|(?(3)f|(?(4)(g|(h)(i)))))))/
37
+
38
+ root = RP.parse(regexp, 'ruby/2.0')
39
+
40
+ assert_equal( regexp.source, root.to_s )
41
+
42
+ group = root.first
43
+ assert_equal( Group::Capture, group.class )
44
+
45
+ alt = group.first
46
+ assert_equal( Alternation, alt.class )
47
+ assert_equal( 3, alt.length )
48
+
49
+ assert_equal( true, alt.all? {|exp|
50
+ exp.first.is_a?(Group::Capture) }
51
+ )
52
+
53
+ subgroup = alt[2].first
54
+ conditional = subgroup.first
55
+
56
+ assert_equal( Conditional::Expression, conditional.class )
57
+ assert_equal( 3, conditional.length )
58
+
59
+ assert_equal( Conditional::Condition, conditional[0].class )
60
+ assert_equal( '(2)', conditional[0].text )
61
+
62
+ condition = conditional.condition
63
+ assert_equal( Conditional::Condition, condition.class )
64
+ assert_equal( '(2)', condition.text )
65
+
66
+ branches = conditional.branches
67
+ assert_equal( 2, branches.length )
68
+ assert_equal( Array, branches.class )
69
+ end
70
+
71
+ def test_parse_conditional_nested
72
+ regexp = /(a(b(c)))(?(1)(?(2)d|(?(3)e|f))|(?(4)(?(5)g|h)))/
73
+
74
+ root = RP.parse(regexp, 'ruby/2.0')
75
+
76
+ assert_equal( regexp.source, root.to_s )
77
+
78
+ { 1 => [2, root[1]],
79
+ 2 => [2, root[1][1][0]],
80
+ 3 => [2, root[1][1][0][2][0]],
81
+ 4 => [1, root[1][2][0]],
82
+ 5 => [2, root[1][2][0][1][0]],
83
+ }.each do |index, test|
84
+ branch_count, exp = test
85
+
86
+ assert_equal( Conditional::Expression, exp.class )
87
+ assert_equal( "(#{index})", exp.condition.text )
88
+ assert_equal( branch_count, exp.branches.length )
89
+ end
90
+ end
91
+
92
+
93
+ def test_parse_conditional_nested_alternation
94
+ regexp = /(a)(?(1)(b|c|d)|(e|f|g))(h)(?(2)(i|j|k)|(l|m|n))|o|p/
95
+
96
+ root = RP.parse(regexp, 'ruby/2.0')
97
+
98
+ assert_equal( regexp.source, root.to_s )
99
+
100
+ assert_equal( Alternation, root.first.class )
101
+
102
+ [ [3, 'b|c|d', root[0][0][1][1][0][0]],
103
+ [3, 'e|f|g', root[0][0][1][2][0][0]],
104
+ [3, 'i|j|k', root[0][0][3][1][0][0]],
105
+ [3, 'l|m|n', root[0][0][3][2][0][0]],
106
+ ].each do |test|
107
+ alt_count, alt_text, exp = test
108
+
109
+ assert_equal( Alternation, exp.class )
110
+ assert_equal( alt_text, exp.to_s )
111
+ assert_equal( alt_count, exp.alternatives.length )
112
+ end
113
+ end
114
+
115
+
116
+ def test_parse_conditional_extra_separator
117
+ regexp = /(?<A>a)(?(<A>)T|)/
118
+
119
+ root = RP.parse(regexp, 'ruby/2.0')
120
+ branches = root[1].branches
121
+
122
+ assert_equal( 2, branches.length )
123
+
124
+ seq_1, seq_2 = branches
125
+
126
+ [seq_1, seq_2].each do |seq|
127
+ assert( seq.is_a?( Sequence ),
128
+ "Expected Condition, but got #{seq.class.name}")
129
+
130
+ assert_equal( :expression, seq.type )
131
+ assert_equal( :sequence, seq.token )
132
+ end
133
+
134
+ assert_equal( 'T', seq_1.to_s )
135
+ assert_equal( '', seq_2.to_s )
136
+ end
137
+
138
+
139
+ # For source (text) expressions only, ruby raises an error otherwise.
140
+ def test_parse_conditional_excessive_branches
141
+ regexp = '(?<A>a)(?(<A>)T|F|X)'
142
+
143
+ assert_raise( Conditional::TooManyBranches ) {
144
+ RP.parse(regexp, 'ruby/2.0')
145
+ }
146
+ end
147
+
148
+ end