regexp_parser 0.1.6 → 0.2.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.
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