Class: Janeway::Interpreters::BinaryOperatorInterpreter

Inherits:
Base
  • Object
show all
Defined in:
lib/janeway/interpreters/binary_operator_interpreter.rb

Overview

Interprets a binary operator within filter selector.

Constant Summary

Constants inherited from Base

Janeway::Interpreters::Base::NOTHING

Instance Attribute Summary

Attributes inherited from Base

#next, #node

Instance Method Summary collapse

Constructor Details

#initialize(operator) ⇒ BinaryOperatorInterpreter

Set up the internal interpreter chain for the BinaryOperator.



12
13
14
15
16
# File 'lib/janeway/interpreters/binary_operator_interpreter.rb', line 12

def initialize(operator)
  super
  @left = TreeConstructor.ast_node_to_interpreter(operator.left)
  @right = TreeConstructor.ast_node_to_interpreter(operator.right)
end

Instance Method Details

#interpret(input, root) ⇒ Object

The binary operators are all comparison operators that test equality.

* boolean values specified in the query
* JSONPath expressions which must be evaluated

After a JSONPath expression is evaluated, it results in a node list. This may contain literal values or nodes, whose value must be extracted before comparison.

Parameters:

  • input (Array, Hash)

    the results of processing so far

  • root (Array, Hash)

    the entire input



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/janeway/interpreters/binary_operator_interpreter.rb', line 28

def interpret(input, root)
  case operator.name
  when :and, :or
    # handle node list for existence check
    lhs = @left.interpret(input, root)
    rhs = @right.interpret(input, root)
  when :equal, :not_equal, :less_than, :greater_than, :less_than_or_equal, :greater_than_or_equal
    # handle node values for comparison check
    lhs = to_single_value @left.interpret(input, root)
    rhs = to_single_value @right.interpret(input, root)
  else
    raise "Don't know how to handle binary operator #{operator.name.inspect}"
  end
  send(:"interpret_#{operator.name}", lhs, rhs)
end

#interpret_and(lhs, rhs) ⇒ Object

Interpret && operator May receive node lists, in which case empty node list == false



90
91
92
93
94
95
# File 'lib/janeway/interpreters/binary_operator_interpreter.rb', line 90

def interpret_and(lhs, rhs)
  # non-empty array is already truthy, so that works properly without conversion
  lhs = false if lhs == []
  rhs = false if rhs == []
  lhs && rhs
end

#interpret_boolean(boolean, _input) ⇒ Boolean

Parameters:

Returns:

  • (Boolean)


140
141
142
# File 'lib/janeway/interpreters/binary_operator_interpreter.rb', line 140

def interpret_boolean(boolean, _input)
  boolean.value
end

#interpret_equal(lhs, rhs) ⇒ Object

Parameters:

  • lhs (String, Numeric, Symbol, nil)

    string/number/null or NOTHING

  • rhs (String, Numeric, Symbol, nil)

    string/number/null or NOTHING



79
80
81
# File 'lib/janeway/interpreters/binary_operator_interpreter.rb', line 79

def interpret_equal(lhs, rhs)
  lhs == rhs
end

#interpret_greater_than(lhs, rhs) ⇒ Object



124
125
126
127
128
# File 'lib/janeway/interpreters/binary_operator_interpreter.rb', line 124

def interpret_greater_than(lhs, rhs)
  lhs > rhs
rescue StandardError
  false
end

#interpret_greater_than_or_equal(lhs, rhs) ⇒ Object



130
131
132
133
134
135
136
# File 'lib/janeway/interpreters/binary_operator_interpreter.rb', line 130

def interpret_greater_than_or_equal(lhs, rhs)
  return true if interpret_equal(lhs, rhs)

  lhs > rhs
rescue StandardError
  false
end

#interpret_less_than(lhs, rhs) ⇒ Object



106
107
108
109
110
# File 'lib/janeway/interpreters/binary_operator_interpreter.rb', line 106

def interpret_less_than(lhs, rhs)
  lhs < rhs
rescue StandardError
  false
end

#interpret_less_than_or_equal(lhs, rhs) ⇒ Object



112
113
114
115
116
117
118
119
120
121
122
# File 'lib/janeway/interpreters/binary_operator_interpreter.rb', line 112

def interpret_less_than_or_equal(lhs, rhs)
  # Must be done in 2 comparisons, because the equality comparison is
  # valid for many types that do not support the < operator.
  return true if interpret_equal(lhs, rhs)

  lhs < rhs
rescue StandardError
  # This catches type mismatches like {} <= 1
  # RFC says that both < and > return false for such comparisons
  false
end

#interpret_not_equal(lhs, rhs) ⇒ Object

Interpret != operator



84
85
86
# File 'lib/janeway/interpreters/binary_operator_interpreter.rb', line 84

def interpret_not_equal(lhs, rhs)
  !interpret_equal(lhs, rhs)
end

#interpret_null(_null, _input) ⇒ Object

Parameters:

  • _null (AST::Null)

    ignored

  • _input (Object)

    ignored



158
159
160
# File 'lib/janeway/interpreters/binary_operator_interpreter.rb', line 158

def interpret_null(_null, _input)
  nil
end

#interpret_number(number, _input) ⇒ Integer, Float

Parameters:

Returns:

  • (Integer, Float)


146
147
148
# File 'lib/janeway/interpreters/binary_operator_interpreter.rb', line 146

def interpret_number(number, _input)
  number.value
end

#interpret_or(lhs, rhs) ⇒ Object

Interpret || operator May receive node lists, in which case empty node list == false



99
100
101
102
103
104
# File 'lib/janeway/interpreters/binary_operator_interpreter.rb', line 99

def interpret_or(lhs, rhs)
  # non-empty array is already truthy, so that works properly without conversion
  lhs = false if lhs.is_a?(Array) && lhs.empty?
  rhs = false if rhs.is_a?(Array) && rhs.empty?
  lhs || rhs
end

#interpret_string_type(string, _input) ⇒ String

Parameters:

Returns:

  • (String)


152
153
154
# File 'lib/janeway/interpreters/binary_operator_interpreter.rb', line 152

def interpret_string_type(string, _input)
  string.value
end

#to_single_value(result) ⇒ Object

Convert an expression result into a single value suitable for use by a comparison operator. Expression result may already ba single value (ie. from a literal like AST::String) or it may be a node list from a singular query.

Any node list is guaranteed not to contain multiple values because the expression that produce it was already verified to be a singular query.

Parameters:



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/janeway/interpreters/binary_operator_interpreter.rb', line 59

def to_single_value(result)
  # Return basic types (ie. from AST::Number, AST::StringType, AST::Null)
  return result unless result.is_a?(Array)

  # Node lists are returned by Selectors, ChildSegment, DescendantSegment.
  #
  # For a comparison operator, an empty node list represents a missing element.
  # This must not match any literal value (including null/nil) but must match another missing value.
  return NOTHING if result.empty?

  # The parsing stage has already verified that both the left and right
  # expressions evaluate to a single value. Both are either a literal or a singular query.
  # So, this check will never raise an error.
  raise 'node list contains multiple elements but this is a comparison' unless result.size == 1

  result.first # Return the only node in the node list
end