class Dry::Schema::PredicateInferrer::Compiler

@api private
Compiler reduces type AST into a list of predicates

def infer_predicate(type)

Other tags:
    Api: - private
def infer_predicate(type)
  [TYPE_TO_PREDICATE.fetch(type) { :"#{type.name.split('::').last.downcase}?" }]
end

def initialize(registry)

Other tags:
    Api: - private
def initialize(registry)
  @registry = registry
end

def merge_predicates(nodes)

Other tags:
    Api: - private
def merge_predicates(nodes)
  preds, merged = nodes.each_with_object([[], {}]) do |predicate, (ps, h)|
    if predicate.is_a?(::Hash)
      h.update(predicate)
    else
      ps << predicate
    end
  end
  merged.empty? ? preds : [*preds, merged]
end

def visit(node)

Other tags:
    Api: - private
def visit(node)
  meth, rest = node
  public_send(:"visit_#{meth}", rest)
end

def visit_and(node)

Other tags:
    Api: - private
def visit_and(node)
  left, right = node
  visit(left) + visit(right)
end

def visit_any(_)

Other tags:
    Api: - private
def visit_any(_)
  EMPTY_ARRAY
end

def visit_array(_)

Other tags:
    Api: - private
def visit_array(_)
  ARRAY
end

def visit_constrained(node)

Other tags:
    Api: - private
def visit_constrained(node)
  other, rules = node
  predicates = visit(rules)
  if predicates.empty?
    visit(other)
  else
    [*visit(other), *merge_predicates(predicates)]
  end
end

def visit_constructor(node)

Other tags:
    Api: - private
def visit_constructor(node)
  other, * = node
  visit(other)
end

def visit_enum(node)

Other tags:
    Api: - private
def visit_enum(node)
  other, * = node
  visit(other)
end

def visit_hash(_)

Other tags:
    Api: - private
def visit_hash(_)
  HASH
end

def visit_lax(node)

Other tags:
    Api: - private
def visit_lax(node)
  visit(node)
end

def visit_nominal(node)

Other tags:
    Api: - private
def visit_nominal(node)
  type = node[0]
  predicate = infer_predicate(type)
  if registry.key?(predicate[0])
    predicate
  else
    [type?: type]
  end
end

def visit_predicate(node)

Other tags:
    Api: - private
def visit_predicate(node)
  pred, args = node
  if pred.equal?(:type?)
    EMPTY_ARRAY
  elsif registry.key?(pred)
    *curried, _ = args
    values = curried.map { |_, v| v }
    if values.empty?
      [pred]
    else
      [pred => values[0]]
    end
  else
    EMPTY_ARRAY
  end
end

def visit_sum(node)

Other tags:
    Api: - private
def visit_sum(node)
  left_node, right_node, = node
  left = visit(left_node)
  right = visit(right_node)
  if left.eql?(NIL)
    right
  else
    [[left, right]]
  end
end