lib/search_cop_grammar/nodes.rb
require "treetop"
module SearchCopGrammar
module Nodes
module Base
def and(node)
And.new self, node
end
def or(node)
Or.new self, node
end
def not
Not.new self
end
def can_flatten?
false
end
def flatten!
self
end
def can_group?
false
end
def group!
self
end
def fulltext?
false
end
def can_optimize?
can_flatten? || can_group?
end
def optimize!
flatten!.group! while can_optimize?
finalize!
end
def finalize!
self
end
def nodes
[]
end
end
class Binary
include Base
attr_accessor :left, :right
def initialize(left, right)
@left = left
@right = right
end
end
class Equality < Binary; end
class NotEqual < Binary; end
class GreaterThan < Binary; end
class GreaterThanOrEqual < Binary; end
class LessThan < Binary; end
class LessThanOrEqual < Binary; end
class Matches < Binary; end
class Generator < Binary; end
class Not
include Base
attr_accessor :object
def initialize(object)
@object = object
end
def finalize!
@object.finalize!
self
end
end
class MatchesFulltext < Binary
include Base
def not
MatchesFulltextNot.new left, right
end
def fulltext?
true
end
def finalize!
FulltextExpression.new collection, self
end
def collection
left
end
end
class MatchesFulltextNot < MatchesFulltext; end
class FulltextExpression
include Base
attr_reader :collection, :node
def initialize(collection, node)
@collection = collection
@node = node
end
end
class Collection
include Base
attr_reader :nodes
def initialize(*nodes)
@nodes = nodes.flatten
end
def can_flatten?
nodes.any?(&:can_flatten?) || nodes.any? { |node| node.is_a?(self.class) || node.nodes.size == 1 }
end
def flatten!(&block)
@nodes = nodes.collect(&:flatten!).collect { |node| node.is_a?(self.class) || node.nodes.size == 1 ? node.nodes : node }.flatten
self
end
def can_group?
nodes.reject(&:fulltext?).any?(&:can_group?) || nodes.select(&:fulltext?).group_by(&:collection).any? { |_, group| group.size > 1 }
end
def group!
@nodes = nodes.reject(&:fulltext?).collect(&:group!) + nodes.select(&:fulltext?).group_by(&:collection).collect { |collection, group| group.size > 1 ? self.class::Fulltext.new(collection, group) : group.first }
self
end
def finalize!
@nodes = nodes.collect(&:finalize!)
self
end
end
class FulltextCollection < Collection
attr_reader :collection
def initialize(collection, *nodes)
@collection = collection
super(*nodes)
end
def fulltext?
true
end
def finalize!
FulltextExpression.new collection, self
end
end
class And < Collection
class Fulltext < FulltextCollection; end
end
class Or < Collection
class Fulltext < FulltextCollection; end
end
end
end