class DDQL::Operator

Attributes

associativity[R]
name[R]
precedence[R]
return_type[R]
symbol[R]
type[R]

Public Class Methods

new(symbol, name, type, precedence, right, return_type) click to toggle source
# File lib/ddql/operator.rb, line 5
def initialize(symbol, name, type, precedence, right, return_type)
  @symbol        = symbol
  @name          = name
  @type          = type
  @precedence    = precedence
  @associativity = right ? :right : :left
  @return_type   = return_type
end

Public Instance Methods

any_type?() click to toggle source
# File lib/ddql/operator.rb, line 14
def any_type?
  return_type == :any
end
boolean?() click to toggle source
# File lib/ddql/operator.rb, line 18
def boolean?
  return_type == :boolean
end
comparison?() click to toggle source
# File lib/ddql/operator.rb, line 22
def comparison?
  (infix? || postfix?) && boolean?
end
complex_comparison?() click to toggle source
# File lib/ddql/operator.rb, line 26
def complex_comparison?
  comparison? && !simple_comparison?
end
infix?() click to toggle source
# File lib/ddql/operator.rb, line 30
def infix?
  @name == :infixoperator || @type == :infix
end
left?() click to toggle source
# File lib/ddql/operator.rb, line 34
def left?
  !right?
end
math?() click to toggle source
# File lib/ddql/operator.rb, line 38
def math?
  math_op?(symbol)
end
parse(parser, token, expression: nil) click to toggle source
# File lib/ddql/operator.rb, line 42
def parse(parser, token, expression: nil)
  case type
  when :infix; parse_infix(parser, token, expression)
  when :prefix; parse_prefix(parser, token, expression)
  when :postfix; parse_postfix(parser, token, expression)
  else
    raise "unsupported operator type[#{type}]"
  end
end
pattern() click to toggle source
# File lib/ddql/operator.rb, line 52
def pattern
  symbol
end
postfix?() click to toggle source
# File lib/ddql/operator.rb, line 56
def postfix?
  @name == :postfixoperator || @type == :postfix
end
prefix?() click to toggle source
# File lib/ddql/operator.rb, line 60
def prefix?
  @name == :prefixoperator || @type == :prefix
end
register(hash) click to toggle source
# File lib/ddql/operator.rb, line 64
def register(hash)
  hash[symbol] = self
  hash
end
right?() click to toggle source
# File lib/ddql/operator.rb, line 69
def right?
  @associativity == :right
end
simple_comparison?() click to toggle source
# File lib/ddql/operator.rb, line 73
def simple_comparison?
  case symbol
  when "==", "=", "!=", "<=", "<", ">=", ">"
    true
  else
    false
  end
end
type?(incoming) click to toggle source
# File lib/ddql/operator.rb, line 82
def type?(incoming)
  type == incoming
end

Private Instance Methods

boolean_stmt(left, op, right) click to toggle source
# File lib/ddql/operator.rb, line 88
def boolean_stmt(left, op, right)
  # the following avoids unnecessarily deeply nested statements
  while left.key?(:lstatement) && !left.key?(:rstatement)
    left = left[:lstatement]
  end
  while right.key?(:lstatement) && !right.key?(:rstatement)
    right = right[:lstatement]
  end
  {
    lstatement: left,
    boolean_operator: op[:op],
    rstatement: right,
  }
end
math_op?(str) click to toggle source
# File lib/ddql/operator.rb, line 103
def math_op?(str)
  case str
  when '+', '-', '*', '/', '%', '^'
    true
  else
    false
  end
end
merged_negation(left, right, op) click to toggle source
# File lib/ddql/operator.rb, line 112
def merged_negation(left, right, op)
  needs_statement_wrapper = lambda do |expr|
    (expr.key?(:lstatement) && expr.key?(:op_not)) || !expr.key?(:lstatement)
  end

  left = {lstatement: left} if needs_statement_wrapper[left]
  right = {rstatement: right} if needs_statement_wrapper[right]
  left.merge(boolean_operator: op[:op]).merge(right)
end
parse_infix(parser, token, expression) click to toggle source
# File lib/ddql/operator.rb, line 122
def parse_infix(parser, token, expression)
  precedence      = self.precedence
  precedence     -= 0.05 if right?
  next_expression = parser.parse(precedence: precedence)
  op_expression   = token.as_hash

  if math? && next_expression&.dig(:left, :factor) && next_expression.size == 1
    return op_expression.merge(left: expression, right: next_expression[:left])
  end

  if token.and? || token.or?
    return boolean_stmt(expression, op_expression, next_expression)
  end

  if expression.key?(:op_not) || next_expression.key?(:op_not)
    return merged_negation(expression, next_expression, op_expression)
  end

  if next_expression&.key?(:lstatement) && expression&.key?(:lstatement)
    left = expression.merge(boolean_operator: op_expression[:op], rstatement: next_expression[:lstatement])
    return next_expression.key?(:rstatement) ?
      left.merge(
        boolean_operator: next_expression[:boolean_operator][:op],
        rstatement: next_expression[:rstatement]
      ) :
      left
  end

  expression = {left: expression} unless redundant?(expression, :left)
  next_expression = {right: next_expression} unless redundant?(next_expression, :right)
  expression.merge(op_expression).merge(next_expression)
end
parse_postfix(parser, token, expression) click to toggle source
# File lib/ddql/operator.rb, line 155
def parse_postfix(parser, token, expression)
  op_expression = token.as_hash
  if expression && !expression.empty?
    expression = {left: expression} unless expression.key?(:left)
    expression.merge(op_expression)
  else
    op_expression
  end
end
parse_prefix(parser, token, _expression) click to toggle source
# File lib/ddql/operator.rb, line 165
def parse_prefix(parser, token, _expression)
  op_expression   = token.type.as_hash(token.data)
  next_expression = parser.parse(precedence: precedence)
  if next_expression.key?(:lstatement) && !next_expression.key?(:rstatement)
    next_expression = next_expression[:lstatement]
  elsif next_expression.key?(:rstatement) && !next_expression.key?(:lstatement)
    next_expression = next_expression[:rstatement]
  elsif op_expression[:op].key?(:op_not) && next_expression.key?(:op_not)
    next_expression.delete(:op_not)
    return next_expression
  end
  op_expression[:op].merge(next_expression)
end
redundant?(expression, *keys) click to toggle source
# File lib/ddql/operator.rb, line 179
def redundant?(expression, *keys)
  expression.keys == keys
end