Class: Pacer::Filter::WhereFilter::NodeVisitor

Inherits:
Object
  • Object
show all
Defined in:
lib/pacer/filter/where_filter/node_visitor.rb

Overview

NOTE: the property filter also uses this to build { key: Set[v1, v2] } filters as or statements.

Defined Under Namespace

Classes: Pipe, Value

Constant Summary collapse

NeverPipe =
Pacer::Pipes::NeverPipe
IdentityPipe =
Pacer::Pipes::IdentityPipe
PropertyComparisonFilterPipe =
Pacer::Pipes::PropertyComparisonFilterPipe
Pipeline =
Pacer::Pipes::Pipeline
CrossProductTransformPipe =
Pacer::Pipes::CrossProductTransformPipe
UnaryTransformPipe =
Pacer::Pipes::UnaryTransformPipe
BlockFilterPipe =
Pacer::Pipes::BlockFilterPipe
Filters =
{
  '==' => Compare::EQUAL,
  '='  => Compare::EQUAL,
  '!=' => Compare::NOT_EQUAL,
  '>'  => Compare::GREATER_THAN,
  '<'  => Compare::LESS_THAN,
  '>=' => Compare::GREATER_THAN_EQUAL,
  '<=' => Compare::LESS_THAN_EQUAL
}
ReverseFilters =
Filters.merge(
  '<'  => Compare::GREATER_THAN,
  '>'  => Compare::LESS_THAN,
  '<=' => Compare::GREATER_THAN_EQUAL,
  '>=' => Compare::LESS_THAN_EQUAL
)
COMPARATORS =
%w[ == != > < >= <= ]
METHODS =
%w[ + - * / % ]
REGEX_COMPARATORS =
%w[ =~ !~ ]
VALID_OPERATIONS =

+ REGEX_COMPARATORS

COMPARATORS + METHODS

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(route, values = {}) ⇒ NodeVisitor

Returns a new instance of NodeVisitor.



115
116
117
118
# File 'lib/pacer/filter/where_filter/node_visitor.rb', line 115

def initialize(route, values = {})
  @route = route
  @values = values
end

Instance Attribute Details

#routeObject (readonly)

Returns the value of attribute route.



113
114
115
# File 'lib/pacer/filter/where_filter/node_visitor.rb', line 113

def route
  @route
end

#valuesObject (readonly)

Returns the value of attribute values.



113
114
115
# File 'lib/pacer/filter/where_filter/node_visitor.rb', line 113

def values
  @values
end

Instance Method Details

#build_comparison(a, b, name) ⇒ Object



120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/pacer/filter/where_filter/node_visitor.rb', line 120

def build_comparison(a, b, name)
  # TODO: support regex matches

  raise "Operation not supported: #{ name }" unless VALID_OPERATIONS.include? name
  if COMPARATORS.include? name
    if a.is_a? Value and b.is_a? Value
      if a.value.send name, b.value
        Pipe.new IdentityPipe
      else
        Pipe.new NeverPipe
      end
    elsif a.pipe == PropertyPipe and b.pipe == PropertyPipe
      Pipe.new PropertyComparisonFilterPipe, a, b, Filters[name]
    elsif b.pipe == PropertyPipe and a.is_a? Value
      Pipe.new Pipeline, b, Pipe.new(ObjectFilterPipe, a, ReverseFilters[name])
    else
      Pipe.new Pipeline, a, Pipe.new(ObjectFilterPipe, b, Filters[name])
    end
  elsif METHODS.include? name
    if a.is_a? Value and b.is_a? Value
      Value.new a.value.send(name, b.value)
    else
      Pipe.new CrossProductTransformPipe, name, a, b
    end
  end
end

#comparable_pipe(pipe) ⇒ Object



151
152
153
154
155
156
157
# File 'lib/pacer/filter/where_filter/node_visitor.rb', line 151

def comparable_pipe(pipe)
  if pipe.pipe == PropertyPipe
    build_comparison(pipe, Value.new(nil), '!=')
  else
    pipe
  end
end

#negate(pipe) ⇒ Object



147
148
149
# File 'lib/pacer/filter/where_filter/node_visitor.rb', line 147

def negate(pipe)
  Pipe.new(Pipeline, pipe, Pipe.new(HasCountPipe, -1, 0), Pipe.new(ObjectFilterPipe, true, Filters['==']))
end

#visitAndNode(node) ⇒ Object



234
235
236
# File 'lib/pacer/filter/where_filter/node_visitor.rb', line 234

def visitAndNode(node)
  visit_and_or(AndFilterPipe, node)
end

#visitArrayNode(node) ⇒ Object



159
160
161
# File 'lib/pacer/filter/where_filter/node_visitor.rb', line 159

def visitArrayNode(node)
  Value.new Value.new(node.child_nodes.map { |n| n.accept self }).values!
end

#visitBignumNode(node) ⇒ Object



163
164
165
# File 'lib/pacer/filter/where_filter/node_visitor.rb', line 163

def visitBignumNode(node)
  Value.new node.value.to_s
end

#visitCallNode(node) ⇒ Object



167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# File 'lib/pacer/filter/where_filter/node_visitor.rb', line 167

def visitCallNode(node)
  a = node.receiver_node.accept(self)
  if node.args_node
    b = node.args_node.child_nodes.first.accept(self)
    build_comparison(a, b, node.name)
  else
    return a if node.name == '+'
    if a.is_a? Value
      Value.new a.value.send(a.name)
    elsif a.pipe == PropertyPipe
      if node.name == '!'
        negate(comparable_pipe(a))
      else
        Pipe.new(UnaryTransformPipe, node.name, a)
      end
    else
      case node.name
      when '!'
        # Special case for "a == 1 and not (b == 1)", etc.
        negate a
      else
        raise 'not sure'
      end
    end
  end
end

#visitConstDeclNode(node) ⇒ Object



216
217
218
219
220
# File 'lib/pacer/filter/where_filter/node_visitor.rb', line 216

def visitConstDeclNode(node)
  a = Pipe.new PropertyPipe, node.name
  b = node.value_node.accept(self)
  build_comparison(a, b, '==')
end

#visitConstNode(node) ⇒ Object



273
274
275
# File 'lib/pacer/filter/where_filter/node_visitor.rb', line 273

def visitConstNode(node)
  Pipe.new PropertyPipe, node.name
end

#visitFalseNode(node) ⇒ Object



194
195
196
# File 'lib/pacer/filter/where_filter/node_visitor.rb', line 194

def visitFalseNode(node)
  Pipe.new NeverPipe
end

#visitFixnumNode(node) ⇒ Object



198
199
200
# File 'lib/pacer/filter/where_filter/node_visitor.rb', line 198

def visitFixnumNode(node)
  Value.new node.value
end

#visitFloatNode(node) ⇒ Object



202
203
204
# File 'lib/pacer/filter/where_filter/node_visitor.rb', line 202

def visitFloatNode(node)
  Value.new node.value
end

#visitHashNode(node) ⇒ Object



206
207
208
# File 'lib/pacer/filter/where_filter/node_visitor.rb', line 206

def visitHashNode(node)
  Value.new Hash[*node.child_nodes.first.accept(self).value.map { |v| v.value }]
end

#visitLocalAsgnNode(node) ⇒ Object



210
211
212
213
214
# File 'lib/pacer/filter/where_filter/node_visitor.rb', line 210

def visitLocalAsgnNode(node)
  a = Pipe.new PropertyPipe, node.name
  b = node.value_node.accept(self)
  build_comparison(a, b, '==')
end

#visitLocalVarNode(node) ⇒ Object



222
223
224
# File 'lib/pacer/filter/where_filter/node_visitor.rb', line 222

def visitLocalVarNode(node)
  Pipe.new PropertyPipe, node.name
end

#visitNewlineNode(node) ⇒ Object



226
227
228
# File 'lib/pacer/filter/where_filter/node_visitor.rb', line 226

def visitNewlineNode(node)
  node.next_node.accept(self)
end

#visitNilNode(node) ⇒ Object



230
231
232
# File 'lib/pacer/filter/where_filter/node_visitor.rb', line 230

def visitNilNode(node)
  Value.new nil
end

#visitOrNode(node) ⇒ Object



238
239
240
# File 'lib/pacer/filter/where_filter/node_visitor.rb', line 238

def visitOrNode(node)
  visit_and_or(OrFilterPipe, node)
end

#visitRootNode(node) ⇒ Object



242
243
244
245
246
247
248
249
250
251
252
253
254
255
# File 'lib/pacer/filter/where_filter/node_visitor.rb', line 242

def visitRootNode(node)
  pipe = node.body_node.accept self
  if pipe.pipe == AndFilterPipe or pipe.pipe == OrFilterPipe
    pipe
  elsif pipe.is_a? Value
    if pipe.value
      Pipe.new IdentityPipe
    else
      Pipe.new NeverPipe
    end
  else
    Pipe.new AndFilterPipe, comparable_pipe(pipe)
  end
end

#visitStrNode(node) ⇒ Object



257
258
259
# File 'lib/pacer/filter/where_filter/node_visitor.rb', line 257

def visitStrNode(node)
  Value.new node.value
end

#visitSymbolNode(node) ⇒ Object



261
262
263
# File 'lib/pacer/filter/where_filter/node_visitor.rb', line 261

def visitSymbolNode(node)
  Value.new values.fetch(node.name.to_sym, node.name.to_sym)
end

#visitTrueNode(node) ⇒ Object



265
266
267
# File 'lib/pacer/filter/where_filter/node_visitor.rb', line 265

def visitTrueNode(node)
  Pipe.new IdentityPipe
end

#visitVCallNode(node) ⇒ Object



269
270
271
# File 'lib/pacer/filter/where_filter/node_visitor.rb', line 269

def visitVCallNode(node)
  Pipe.new PropertyPipe, node.name
end

#visitXStrNode(node) ⇒ Object



277
278
279
# File 'lib/pacer/filter/where_filter/node_visitor.rb', line 277

def visitXStrNode(node)
  Pipe.new PropertyPipe, node.value
end

#visitYieldNode(node) ⇒ Object



281
282
283
284
# File 'lib/pacer/filter/where_filter/node_visitor.rb', line 281

def visitYieldNode(node)
  block = node.args_node.child_nodes.first.accept(self)
  Pipe.new BlockFilterPipe, Value.new(route), block
end

#visitZArrayNode(node) ⇒ Object



286
287
288
# File 'lib/pacer/filter/where_filter/node_visitor.rb', line 286

def visitZArrayNode(node)
  Value.new []
end