class Dentaku::TokenMatcher

def self.addsub; new(:operator, [:add, :subtract]); end

def self.addsub;         new(:operator, [:add, :subtract]);    end

def self.anchored_minus; new(:operator, :subtract).caret; end

def self.anchored_minus; new(:operator, :subtract).caret;      end

def self.arguments; (value | comma).plus; end

def self.arguments;      (value | comma).plus;                 end

def self.close; new(:grouping, :close); end

def self.close;          new(:grouping, :close);               end

def self.combinator; new(:combinator); end

def self.combinator;     new(:combinator);                     end

def self.comma; new(:grouping, :comma); end

def self.comma;          new(:grouping, :comma);               end

def self.comp_gt; new(:comparator, [:gt, :ge]); end

def self.comp_gt;        new(:comparator, [:gt, :ge]);         end

def self.comp_lt; new(:comparator, [:lt, :le]); end

def self.comp_lt;        new(:comparator, [:lt, :le]);         end

def self.comparator; new(:comparator); end

def self.comparator;     new(:comparator);                     end

def self.datetime; new(:datetime); end

def self.datetime;       new(:datetime);                       end

def self.if; new(:function, :if); end

def self.if;             new(:function, :if);                  end

def self.logical; new(:logical); end

def self.logical;        new(:logical);                        end

def self.method_missing(name, *args, &block)

def self.method_missing(name, *args, &block)
  new(:function, name)
end

def self.mod; new(:operator, :mod); end

def self.mod;            new(:operator, :mod);                 end

def self.muldiv; new(:operator, [:multiply, :divide]); end

def self.muldiv;         new(:operator, [:multiply, :divide]); end

def self.non_close_plus; new(:grouping, :close).invert.plus; end

def self.non_close_plus; new(:grouping, :close).invert.plus;   end

def self.non_group; new(:grouping).invert; end

def self.non_group;      new(:grouping).invert;                end

def self.non_group_star; new(:grouping).invert.star; end

def self.non_group_star; new(:grouping).invert.star;           end

def self.not; new(:function, :not); end

def self.not;            new(:function, :not);                 end

def self.numeric; new(:numeric); end

def self.numeric;        new(:numeric);                        end

def self.open; new(:grouping, :open); end

def self.open;           new(:grouping, :open);                end

def self.pow; new(:operator, :pow); end

def self.pow;            new(:operator, :pow);                 end

def self.respond_to_missing?(name, include_priv)

def self.respond_to_missing?(name, include_priv)
  true
end

def self.round; new(:function, :round); end

def self.round;          new(:function, :round);               end

def self.rounddown; new(:function, :rounddown); end

def self.rounddown;      new(:function, :rounddown);           end

def self.roundup; new(:function, :roundup); end

def self.roundup;        new(:function, :roundup);             end

def self.string; new(:string); end

def self.string;         new(:string);                         end

def self.subtract; new(:operator, :subtract); end

def self.subtract;       new(:operator, :subtract);            end

def self.value

def self.value
  new(:datetime) | new(:numeric) | new(:string) | new(:logical)
end

def ==(token)

def ==(token)
  leaf_matcher? ? matches_token?(token) : any_child_matches_token?(token)
end

def any_child_matches_token?(token)

def any_child_matches_token?(token)
  children.any? { |child| child == token }
end

def caret

def caret
  @caret = true
  self
end

def caret?

def caret?
  @caret
end

def category_match(category)

def category_match(category)
  @categories.empty? || @categories.key?(category)
end

def initialize(categories = nil, values = nil, children = [])

def initialize(categories = nil, values = nil, children = [])
  # store categories and values as hash to optimize key lookup, h/t @jan-mangs
  @categories = [categories].compact.flatten.each_with_object({}) { |c, h| h[c] = 1 }
  @values     = [values].compact.flatten.each_with_object({}) { |v, h| h[v] = 1 }
  @children   = children.compact
  @invert     = false
  @min = 1
  @max = 1
  @range = (@min..@max)
end

def invert

def invert
  @invert = ! @invert
  self
end

def leaf_matcher?

def leaf_matcher?
  children.empty?
end

def leaf_matchers

def leaf_matchers
  leaf_matcher? ? [self] : children
end

def match(token_stream, offset = 0)

def match(token_stream, offset = 0)
  matched_tokens = []
  matched = false
  while self == token_stream[matched_tokens.length + offset] && matched_tokens.length < @max
    matched_tokens << token_stream[matched_tokens.length + offset]
  end
  if @range.cover?(matched_tokens.length)
    matched = true
  end
  [matched, matched_tokens]
end

def matches_token?(token)

def matches_token?(token)
  return false if token.nil?
  (category_match(token.category) && value_match(token.value)) ^ @invert
end

def plus

def plus
  @max = Float::INFINITY
  @range = (@min..@max)
  self
end

def star

def star
  @min = 0
  @max = Float::INFINITY
  @range = (@min..@max)
  self
end

def value_match(value)

def value_match(value)
  @values.empty? || @values.key?(value)
end

def |(other_matcher)

def |(other_matcher)
  self.class.new(:nomatch, :nomatch, leaf_matchers + other_matcher.leaf_matchers)
end