json_select 0.1.3 → 0.1.4

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