json_select 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. data/.gitmodules +3 -0
  2. data/.travis.yml +1 -1
  3. data/Gemfile +1 -0
  4. data/README.md +52 -1
  5. data/Rakefile +12 -1
  6. data/lib/json_select/helpers/depth.rb +6 -2
  7. data/lib/json_select/helpers/key.rb +6 -2
  8. data/lib/json_select/helpers/position.rb +15 -7
  9. data/lib/json_select/helpers/size.rb +14 -6
  10. data/lib/json_select/helpers/type.rb +8 -4
  11. data/lib/json_select/selector.rb +47 -11
  12. data/lib/json_select/selector_parser.rb +179 -44
  13. data/lib/json_select/selector_parser.tt +9 -2
  14. data/lib/json_select/version.rb +1 -1
  15. data/spec/conformance_spec.rb +94 -38
  16. data/spec/fixtures/{basic_children.selector → parser/level_1/basic_children.output} +0 -0
  17. data/spec/fixtures/parser/level_1/basic_children.selector +1 -0
  18. data/spec/fixtures/{basic_combination.selector → parser/level_1/basic_combination.output} +0 -0
  19. data/spec/fixtures/parser/level_1/basic_combination.selector +1 -0
  20. data/spec/fixtures/parser/level_1/basic_first-child.output +1 -0
  21. data/spec/fixtures/{basic_first-child.selector → parser/level_1/basic_first-child.selector} +0 -0
  22. data/spec/fixtures/parser/level_1/basic_grouping.output +1 -0
  23. data/spec/fixtures/{basic_grouping.selector → parser/level_1/basic_grouping.selector} +0 -0
  24. data/spec/fixtures/parser/level_1/basic_id.output +1 -0
  25. data/spec/fixtures/{basic_id.selector → parser/level_1/basic_id.selector} +0 -0
  26. data/spec/fixtures/parser/level_1/basic_id_multiple.output +1 -0
  27. data/spec/fixtures/{basic_id_multiple.selector → parser/level_1/basic_id_multiple.selector} +0 -0
  28. data/spec/fixtures/parser/level_1/basic_id_quotes.output +1 -0
  29. data/spec/fixtures/{basic_id_quotes.selector → parser/level_1/basic_id_quotes.selector} +0 -0
  30. data/spec/fixtures/parser/level_1/basic_id_with_type.output +1 -0
  31. data/spec/fixtures/{basic_id_with_type.selector → parser/level_1/basic_id_with_type.selector} +0 -0
  32. data/spec/fixtures/parser/level_1/basic_last-child.output +1 -0
  33. data/spec/fixtures/{basic_last-child.selector → parser/level_1/basic_last-child.selector} +0 -0
  34. data/spec/fixtures/parser/level_1/basic_nth-child-2.output +1 -0
  35. data/spec/fixtures/{basic_nth-child-2.selector → parser/level_1/basic_nth-child-2.selector} +0 -0
  36. data/spec/fixtures/parser/level_1/basic_nth-child.output +1 -0
  37. data/spec/fixtures/{basic_nth-child.selector → parser/level_1/basic_nth-child.selector} +0 -0
  38. data/spec/fixtures/parser/level_1/basic_nth-last-child.output +1 -0
  39. data/spec/fixtures/{basic_nth-last-child.selector → parser/level_1/basic_nth-last-child.selector} +0 -0
  40. data/spec/fixtures/parser/level_1/basic_root_pseudo.output +1 -0
  41. data/spec/fixtures/{basic_root_pseudo.selector → parser/level_1/basic_root_pseudo.selector} +0 -0
  42. data/spec/fixtures/{basic_type.selector → parser/level_1/basic_type.output} +0 -0
  43. data/spec/fixtures/parser/level_1/basic_type.selector +1 -0
  44. data/spec/fixtures/{basic_type2.selector → parser/level_1/basic_type2.output} +0 -0
  45. data/spec/fixtures/parser/level_1/basic_type2.selector +1 -0
  46. data/spec/fixtures/parser/level_1/basic_type3.output +1 -0
  47. data/spec/fixtures/{basic_type3.selector → parser/level_1/basic_type3.selector} +0 -0
  48. data/spec/fixtures/parser/level_1/basic_universal.output +1 -0
  49. data/spec/fixtures/{basic_universal.selector → parser/level_1/basic_universal.selector} +0 -0
  50. data/spec/fixtures/parser/level_3/basic_has-sans-paren.output +1 -0
  51. data/spec/fixtures/parser/level_3/basic_has-sans-paren.selector +2 -0
  52. data/spec/fixtures/parser/level_3/basic_has-whitespace.output +1 -0
  53. data/spec/fixtures/parser/level_3/basic_has-whitespace.selector +3 -0
  54. data/spec/fixtures/parser/level_3/basic_has.output +1 -0
  55. data/spec/fixtures/parser/level_3/basic_has.selector +1 -0
  56. data/spec/parser_spec.rb +52 -0
  57. metadata +123 -148
  58. data/spec/fixtures/README.md +0 -14
  59. data/spec/fixtures/alltests.txt +0 -31
  60. data/spec/fixtures/basic.json +0 -31
  61. data/spec/fixtures/basic.xml +0 -31
  62. data/spec/fixtures/basic_children.ast +0 -14
  63. data/spec/fixtures/basic_children.output +0 -1
  64. data/spec/fixtures/basic_combination.ast +0 -13
  65. data/spec/fixtures/basic_combination.output +0 -1
  66. data/spec/fixtures/basic_first-child.ast +0 -11
  67. data/spec/fixtures/basic_first-child.output +0 -2
  68. data/spec/fixtures/basic_grouping.ast +0 -22
  69. data/spec/fixtures/basic_grouping.output +0 -4
  70. data/spec/fixtures/basic_id.ast +0 -7
  71. data/spec/fixtures/basic_id.output +0 -1
  72. data/spec/fixtures/basic_id_multiple.ast +0 -7
  73. data/spec/fixtures/basic_id_multiple.output +0 -3
  74. data/spec/fixtures/basic_id_quotes.ast +0 -7
  75. data/spec/fixtures/basic_id_quotes.output +0 -2
  76. data/spec/fixtures/basic_id_with_type.ast +0 -10
  77. data/spec/fixtures/basic_id_with_type.output +0 -1
  78. data/spec/fixtures/basic_last-child.ast +0 -11
  79. data/spec/fixtures/basic_last-child.output +0 -2
  80. data/spec/fixtures/basic_nth-child-2.ast +0 -11
  81. data/spec/fixtures/basic_nth-child-2.output +0 -4
  82. data/spec/fixtures/basic_nth-child.ast +0 -11
  83. data/spec/fixtures/basic_nth-child.output +0 -3
  84. data/spec/fixtures/basic_nth-last-child.ast +0 -11
  85. data/spec/fixtures/basic_nth-last-child.output +0 -2
  86. data/spec/fixtures/basic_root_pseudo.ast +0 -6
  87. data/spec/fixtures/basic_root_pseudo.output +0 -31
  88. data/spec/fixtures/basic_type.ast +0 -7
  89. data/spec/fixtures/basic_type.output +0 -14
  90. data/spec/fixtures/basic_type2.ast +0 -7
  91. data/spec/fixtures/basic_type2.output +0 -1
  92. data/spec/fixtures/basic_type3.ast +0 -7
  93. data/spec/fixtures/basic_type3.output +0 -47
  94. data/spec/fixtures/basic_universal.ast +0 -5
  95. data/spec/fixtures/basic_universal.output +0 -86
@@ -0,0 +1,3 @@
1
+ [submodule "spec/fixtures/conformance"]
2
+ path = spec/fixtures/conformance
3
+ url = git://github.com/lloyd/JSONSelectTests.git
@@ -1,6 +1,6 @@
1
1
  rvm:
2
2
  # - 1.8.7
3
- - 1.9.1
3
+ # - 1.9.1
4
4
  - 1.9.2
5
5
  - jruby
6
6
  # - rbx
data/Gemfile CHANGED
@@ -6,3 +6,4 @@ gemspec
6
6
  gem 'rake', '0.8.7'
7
7
  gem 'rspec'
8
8
  gem 'yajl-ruby'
9
+ gem 'rubygems-openpgp'
data/README.md CHANGED
@@ -53,8 +53,59 @@ JSONSelect('string:first-child').match(json) # => "window"
53
53
  JSONSelect('string:first-child').matches(json) # => ["window", "beer"]
54
54
  ```
55
55
 
56
+ ## Language support
57
+
58
+ ✓ — **Level 1** — `*`<br>
59
+ Any node
60
+
61
+ ✓ — **Level 1** — `T`<br>
62
+ A node of type `T`, where `T` is one `string`, `number`, `object`, `array`, `boolean`, or `null`
63
+
64
+ ✓ — **Level 1** — `T.key`<br>
65
+ A node of type `T` which is the child of an object and is the value its parents key property
66
+
67
+ ✓ — **Level 1** — `T."complex key"`<br>
68
+ Same as previous, but with property name specified as a JSON string
69
+
70
+ ✓ — **Level 1** — `T:root`<br>
71
+ A node of type `T` which is the root of the JSON document
72
+
73
+ ✓ — **Level 1** — `T:nth-child(n)`<br>
74
+ A node of type `T` which is the nth child of an array parent
75
+
76
+ ✓ — **Level 2** — `T:nth-last-child(n)`<br>
77
+ A node of type `T` which is the nth child of an array parent counting from the end
78
+
79
+ ✓ — **Level 1** — `T:first-child`<br>
80
+ A node of type `T` which is the first child of an array parent (equivalent to `T:nth-child(1)`)
81
+
82
+ ✓ — **Level 2** — `T:last-child`<br>
83
+ A node of type `T` which is the last child of an array parent (equivalent to `T:nth-last-child(1)`)
84
+
85
+ ✓ — **Level 2** — `T:only-child`<br>
86
+ A node of type `T` which is the only child of an array parent
87
+
88
+ ✓ — **Level 2** — `T:empty`<br>
89
+ A node of type `T` which is an array or object with no child
90
+
91
+ ✓ — **Level 1** — `T U`<br>
92
+ A node of type `U` with an ancestor of type `T`
93
+
94
+ ✓ — **Level 1** — `T > U`<br>
95
+ A node of type `U` with a parent of type `T`
96
+
97
+ ✗ — **Level 2** — `T ~ U`<br>
98
+ A node of type `U` with a sibling of type `T`
99
+
100
+ ✓ — **Level 1** — `S1, S2`<br>
101
+ Any node which matches either selector `S1` or `S2`
102
+
103
+ ✗ — **Level 3** — `T:has(S)`<br>
104
+ A node of type `T` which has a child node satisfying the selector `S`
105
+
106
+
56
107
  ## Note on Patches/Pull Requests
57
-
108
+
58
109
  * Fork the project.
59
110
  * Make your feature addition or bug fix.
60
111
  * Add tests for it. This is important so I don't break it in a future version
data/Rakefile CHANGED
@@ -9,6 +9,11 @@ RSpec::Core::RakeTask.new do |t|
9
9
  '-r', File.expand_path("../spec/spec_helper.rb", __FILE__)]
10
10
  end
11
11
 
12
+ task :checkout_conformance_tests do
13
+ sh "git submodule init"
14
+ sh "git submodule update"
15
+ end
16
+
12
17
  task :build_parser do
13
18
  sh "bundle exec tt lib/json_select/selector_parser.tt -o lib/json_select/selector_parser.rb"
14
19
 
@@ -18,6 +23,12 @@ task :build_parser do
18
23
  File.open(path, 'w+') { |f| f.write src }
19
24
  end
20
25
 
21
- task :spec => :build_parser
26
+ task :build do
27
+ h = Bundler::GemHelper.instance
28
+ path = Dir[File.join(h.base, "pkg", "#{h.gemspec.name}-*.gem")].sort_by{|f| File.mtime(f)}.last
29
+ sh "gem sign #{path}"
30
+ end
31
+
32
+ task :spec => [:checkout_conformance_tests, :build_parser]
22
33
  task :build => :build_parser
23
34
  task :default => :spec
@@ -1,7 +1,11 @@
1
1
  module JSONSelect::DepthHelpers
2
-
2
+
3
3
  def is_root(object, test, key, idx, size, depth)
4
4
  depth == 0
5
5
  end
6
-
6
+
7
+ def format_is_root(test)
8
+ ":root"
9
+ end
10
+
7
11
  end
@@ -1,7 +1,11 @@
1
1
  module JSONSelect::KeyHelpers
2
-
2
+
3
3
  def has_class(object, test, key, idx, size, depth)
4
4
  test[:n] == key.to_s
5
5
  end
6
-
6
+
7
+ def format_has_class(test)
8
+ ".#{test[:n]}"
9
+ end
10
+
7
11
  end
@@ -1,24 +1,32 @@
1
1
  module JSONSelect::PositionHelpers
2
-
2
+
3
3
  def nth_child(object, test, key, idx, size, depth)
4
4
  return false unless idx and size
5
-
5
+
6
6
  idx += 1
7
-
7
+
8
8
  a = test[:a]
9
9
  b = test[:b]
10
-
10
+
11
11
  if a == 0
12
12
  (b == idx)
13
13
  else
14
14
  (((idx - b) % a) == 0) and ((idx * a + b) >= 0)
15
15
  end
16
16
  end
17
-
17
+
18
+ def format_nth_child(test)
19
+ ":nth-child(#{test[:a]}n#{test[:b]})"
20
+ end
21
+
18
22
  def nth_last_child(object, test, key, idx, size, depth)
19
23
  return false unless idx and size
20
-
24
+
21
25
  nth_child(object, test, key, (size - idx) - 1, size, depth)
22
26
  end
23
-
27
+
28
+ def format_nth_last_child(test)
29
+ ":nth-last-child(#{test[:a]}n#{test[:b]})"
30
+ end
31
+
24
32
  end
@@ -1,14 +1,18 @@
1
1
  module JSONSelect::SizeHelpers
2
-
2
+
3
3
  def only_child(object, test, key, idx, size, depth)
4
4
  return false unless size
5
-
5
+
6
6
  size == 1
7
7
  end
8
-
8
+
9
+ def format_only_child(test)
10
+ ":only-child"
11
+ end
12
+
9
13
  def empty(object, test, key, idx, size, depth)
10
14
  return false unless size
11
-
15
+
12
16
  case object
13
17
  when Array then return object.empty?
14
18
  else
@@ -17,8 +21,12 @@ module JSONSelect::SizeHelpers
17
21
  return true
18
22
  end
19
23
  end
20
-
24
+
21
25
  return false
22
26
  end
23
-
27
+
28
+ def format_empty(test)
29
+ ":empty"
30
+ end
31
+
24
32
  end
@@ -1,20 +1,24 @@
1
1
  module JSONSelect::TypeHelpers
2
-
2
+
3
3
  def instance_of_type(object, test, key, idx, size, depth)
4
4
  test[:n] == type_of(object)
5
5
  end
6
6
 
7
+ def format_instance_of_type(test)
8
+ test[:n].to_s
9
+ end
10
+
7
11
  private
8
12
 
9
13
  def type_of(object)
10
14
  if object.respond_to?(:json_select_each)
11
15
  return 'array'
12
16
  end
13
-
17
+
14
18
  if object.respond_to?(:json_select_each_pair)
15
19
  return 'object'
16
20
  end
17
-
21
+
18
22
  case object
19
23
  when Hash then 'object'
20
24
  when Array then 'array'
@@ -27,5 +31,5 @@ private
27
31
  else raise "Invalid object of class #{object.class} for JSONSelect: #{object.inspect}"
28
32
  end
29
33
  end
30
-
34
+
31
35
  end
@@ -42,7 +42,7 @@ class JSONSelect
42
42
  raise ArgumentError, "Expected a string for ast"
43
43
 
44
44
  end
45
-
45
+
46
46
  @helpers = Module.new
47
47
  @helpers.send(:extend,
48
48
  JSONSelect::KeyHelpers,
@@ -50,7 +50,7 @@ class JSONSelect
50
50
  JSONSelect::SizeHelpers,
51
51
  JSONSelect::DepthHelpers,
52
52
  JSONSelect::PositionHelpers)
53
-
53
+
54
54
  @helper_methods = {}
55
55
  (@helpers.public_methods - Module.public_methods).map do |name|
56
56
  @helper_methods[name.to_sym] = @helpers.method(name)
@@ -90,6 +90,42 @@ class JSONSelect
90
90
 
91
91
  alias_method :===, :test
92
92
 
93
+ def to_s
94
+ selectors = @ast
95
+ selectors = (selectors[0] == ',' ? selectors[1..-1] : [selectors])
96
+
97
+ selectors.map do |selector|
98
+ selector.map do |part|
99
+ case part
100
+
101
+ when :>
102
+ '>'
103
+
104
+ when Hash
105
+ tests = (part[:tests].empty? ? ['*'] : part[:tests])
106
+
107
+ tests.map do |test|
108
+ case test
109
+
110
+ when '*'
111
+ '*'
112
+
113
+ when Hash
114
+ @helpers.send("format_#{test[:f]}", test)
115
+
116
+ end
117
+ end.join('')
118
+
119
+ end
120
+
121
+ end.join(' ')
122
+ end.join(', ')
123
+ end
124
+
125
+ def inspect
126
+ "#<JSONSelect (#{to_s})>"
127
+ end
128
+
93
129
  private
94
130
 
95
131
  def _each(selector, object, id, number, total, depth, &block)
@@ -129,21 +165,21 @@ private
129
165
  object.json_select_each do |value|
130
166
  children << value
131
167
  end
132
-
168
+
133
169
  a1.unshift(',')
134
170
  size = children.size
135
-
171
+
136
172
  children.each_with_index do |child, idx|
137
173
  _each(a1, child, nil, idx, size, depth + 1, &block)
138
174
  end
139
-
175
+
140
176
  elsif object.respond_to?(:json_select_each_pair)
141
177
  a1.unshift(',')
142
-
178
+
143
179
  object.json_select_each_pair do |key, child|
144
180
  _each(a1, child, key, nil, nil, depth + 1, &block)
145
181
  end
146
-
182
+
147
183
  end
148
184
  end
149
185
  end
@@ -163,7 +199,7 @@ private
163
199
  if test[:f] == :is_root
164
200
  has_root_test = true
165
201
  end
166
-
202
+
167
203
  if match
168
204
  match = !!@helper_methods[test[:f].to_sym].call(object, test, id, number, total, depth)
169
205
  end
@@ -183,16 +219,16 @@ private
183
219
  unless match
184
220
  return [match, selectors]
185
221
  end
186
-
222
+
187
223
  # continue search for decendants
188
224
  unless selector[0] == :>
189
225
  match = false
190
226
  selectors.push selector[1..-1]
191
227
  return [match, selectors]
192
228
  end
193
-
229
+
194
230
  # continue search for children
195
- if selector.length > 2
231
+ if selector.length > 2
196
232
  match = false
197
233
  selectors.push selector[2..-1]
198
234
  end
@@ -619,7 +619,18 @@ module JSONSelect::Selector
619
619
  end
620
620
 
621
621
  def e
622
- elements[4]
622
+ elements[5]
623
+ end
624
+
625
+ end
626
+
627
+ module Pseudo2
628
+ def a
629
+ elements[1]
630
+ end
631
+
632
+ def s
633
+ elements[5]
623
634
  end
624
635
 
625
636
  end
@@ -669,53 +680,66 @@ module JSONSelect::Selector
669
680
  end
670
681
  s4 << r5
671
682
  if r5
672
- r6 = _nt_pseudo_function_name
683
+ r6 = _nt_positional_pseudo_function_name
673
684
  s4 << r6
674
685
  if r6
675
- if has_terminal?('(', false, index)
676
- r7 = instantiate_node(SyntaxNode,input, index...(index + 1))
677
- @index += 1
678
- else
679
- terminal_parse_failure('(')
680
- r7 = nil
686
+ s7, i7 = [], index
687
+ loop do
688
+ r8 = _nt_ws
689
+ if r8
690
+ s7 << r8
691
+ else
692
+ break
693
+ end
681
694
  end
695
+ r7 = instantiate_node(SyntaxNode,input, i7...index, s7)
682
696
  s4 << r7
683
697
  if r7
684
- s8, i8 = [], index
685
- loop do
686
- r9 = _nt_ws
687
- if r9
688
- s8 << r9
689
- else
690
- break
691
- end
698
+ if has_terminal?('(', false, index)
699
+ r9 = instantiate_node(SyntaxNode,input, index...(index + 1))
700
+ @index += 1
701
+ else
702
+ terminal_parse_failure('(')
703
+ r9 = nil
692
704
  end
693
- r8 = instantiate_node(SyntaxNode,input, i8...index, s8)
694
- s4 << r8
695
- if r8
696
- r10 = _nt_expression
705
+ s4 << r9
706
+ if r9
707
+ s10, i10 = [], index
708
+ loop do
709
+ r11 = _nt_ws
710
+ if r11
711
+ s10 << r11
712
+ else
713
+ break
714
+ end
715
+ end
716
+ r10 = instantiate_node(SyntaxNode,input, i10...index, s10)
697
717
  s4 << r10
698
718
  if r10
699
- s11, i11 = [], index
700
- loop do
701
- r12 = _nt_ws
702
- if r12
703
- s11 << r12
704
- else
705
- break
706
- end
707
- end
708
- r11 = instantiate_node(SyntaxNode,input, i11...index, s11)
709
- s4 << r11
710
- if r11
711
- if has_terminal?(')', false, index)
712
- r13 = instantiate_node(SyntaxNode,input, index...(index + 1))
713
- @index += 1
714
- else
715
- terminal_parse_failure(')')
716
- r13 = nil
719
+ r12 = _nt_expression
720
+ s4 << r12
721
+ if r12
722
+ s13, i13 = [], index
723
+ loop do
724
+ r14 = _nt_ws
725
+ if r14
726
+ s13 << r14
727
+ else
728
+ break
729
+ end
717
730
  end
731
+ r13 = instantiate_node(SyntaxNode,input, i13...index, s13)
718
732
  s4 << r13
733
+ if r13
734
+ if has_terminal?(')', false, index)
735
+ r15 = instantiate_node(SyntaxNode,input, index...(index + 1))
736
+ @index += 1
737
+ else
738
+ terminal_parse_failure(')')
739
+ r15 = nil
740
+ end
741
+ s4 << r15
742
+ end
719
743
  end
720
744
  end
721
745
  end
@@ -732,8 +756,95 @@ module JSONSelect::Selector
732
756
  if r4
733
757
  r0 = r4
734
758
  else
735
- @index = i0
736
- r0 = nil
759
+ i16, s16 = index, []
760
+ if has_terminal?(':', false, index)
761
+ r17 = instantiate_node(SyntaxNode,input, index...(index + 1))
762
+ @index += 1
763
+ else
764
+ terminal_parse_failure(':')
765
+ r17 = nil
766
+ end
767
+ s16 << r17
768
+ if r17
769
+ r18 = _nt_subselector_pseudo_function_name
770
+ s16 << r18
771
+ if r18
772
+ s19, i19 = [], index
773
+ loop do
774
+ r20 = _nt_ws
775
+ if r20
776
+ s19 << r20
777
+ else
778
+ break
779
+ end
780
+ end
781
+ r19 = instantiate_node(SyntaxNode,input, i19...index, s19)
782
+ s16 << r19
783
+ if r19
784
+ if has_terminal?('(', false, index)
785
+ r21 = instantiate_node(SyntaxNode,input, index...(index + 1))
786
+ @index += 1
787
+ else
788
+ terminal_parse_failure('(')
789
+ r21 = nil
790
+ end
791
+ s16 << r21
792
+ if r21
793
+ s22, i22 = [], index
794
+ loop do
795
+ r23 = _nt_ws
796
+ if r23
797
+ s22 << r23
798
+ else
799
+ break
800
+ end
801
+ end
802
+ r22 = instantiate_node(SyntaxNode,input, i22...index, s22)
803
+ s16 << r22
804
+ if r22
805
+ r24 = _nt_selectors_group
806
+ s16 << r24
807
+ if r24
808
+ s25, i25 = [], index
809
+ loop do
810
+ r26 = _nt_ws
811
+ if r26
812
+ s25 << r26
813
+ else
814
+ break
815
+ end
816
+ end
817
+ r25 = instantiate_node(SyntaxNode,input, i25...index, s25)
818
+ s16 << r25
819
+ if r25
820
+ if has_terminal?(')', false, index)
821
+ r27 = instantiate_node(SyntaxNode,input, index...(index + 1))
822
+ @index += 1
823
+ else
824
+ terminal_parse_failure(')')
825
+ r27 = nil
826
+ end
827
+ s16 << r27
828
+ end
829
+ end
830
+ end
831
+ end
832
+ end
833
+ end
834
+ end
835
+ if s16.last
836
+ r16 = instantiate_node(JSONSelect::Ast::PseudoSelector,input, i16...index, s16)
837
+ r16.extend(Pseudo2)
838
+ else
839
+ @index = i16
840
+ r16 = nil
841
+ end
842
+ if r16
843
+ r0 = r16
844
+ else
845
+ @index = i0
846
+ r0 = nil
847
+ end
737
848
  end
738
849
  end
739
850
 
@@ -817,10 +928,10 @@ module JSONSelect::Selector
817
928
  r0
818
929
  end
819
930
 
820
- def _nt_pseudo_function_name
931
+ def _nt_positional_pseudo_function_name
821
932
  start_index = index
822
- if node_cache[:pseudo_function_name].has_key?(index)
823
- cached = node_cache[:pseudo_function_name][index]
933
+ if node_cache[:positional_pseudo_function_name].has_key?(index)
934
+ cached = node_cache[:positional_pseudo_function_name][index]
824
935
  if cached
825
936
  cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
826
937
  @index = cached.interval.end
@@ -854,7 +965,31 @@ module JSONSelect::Selector
854
965
  end
855
966
  end
856
967
 
857
- node_cache[:pseudo_function_name][start_index] = r0
968
+ node_cache[:positional_pseudo_function_name][start_index] = r0
969
+
970
+ r0
971
+ end
972
+
973
+ def _nt_subselector_pseudo_function_name
974
+ start_index = index
975
+ if node_cache[:subselector_pseudo_function_name].has_key?(index)
976
+ cached = node_cache[:subselector_pseudo_function_name][index]
977
+ if cached
978
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
979
+ @index = cached.interval.end
980
+ end
981
+ return cached
982
+ end
983
+
984
+ if has_terminal?('has', false, index)
985
+ r0 = instantiate_node(SyntaxNode,input, index...(index + 3))
986
+ @index += 3
987
+ else
988
+ terminal_parse_failure('has')
989
+ r0 = nil
990
+ end
991
+
992
+ node_cache[:subselector_pseudo_function_name][start_index] = r0
858
993
 
859
994
  r0
860
995
  end