class YARP::RipperCompat

meant as a test harness for the YARP parser.
is meant as a stopgap until developers migrate to using YARP. It is also
This class is going to necessarily be slower than the native Ripper API. It
and executing each of the Ripper callbacks as it goes.
Ripper. It functions by parsing the entire tree first and then walking it
This class is meant to provide a compatibility layer between YARP and

def self.sexp(source)

This is a convenience method that runs the SexpBuilderPP subclass parser.
def self.sexp(source)
  SexpBuilderPP.new(source).parse
end

def self.sexp_raw(source)

This is a convenience method that runs the SexpBuilder subclass parser.
def self.sexp_raw(source)
  SexpBuilder.new(source).parse
end

def _dispatch0; end

def _dispatch0; end

def _dispatch1(_); end

def _dispatch1(_); end

def _dispatch2(_, _); end

def _dispatch2(_, _); end

def _dispatch3(_, _, _); end

def _dispatch3(_, _, _); end

def _dispatch4(_, _, _, _); end

def _dispatch4(_, _, _, _); end

def _dispatch5(_, _, _, _, _); end

def _dispatch5(_, _, _, _, _); end

def _dispatch7(_, _, _, _, _, _, _); end

def _dispatch7(_, _, _, _, _, _, _); end

def bounds(location)

of every line, but for now it's good enough.
This method could be drastically improved with some caching on the start

to reflect the current node.
This method is responsible for updating lineno and column information
def bounds(location)
  start_offset = location.start_offset
  @lineno = source[0..start_offset].count("\n") + 1
  @column = start_offset - (source.rindex("\n", start_offset) || 0)
end

def error?

def error?
  result.errors.any?
end

def initialize(source)

def initialize(source)
  @source = source
  @result = nil
  @lineno = nil
  @column = nil
end

def parse

def parse
  result.value.accept(self) unless error?
end

def result

def result
  @result ||= YARP.parse(source)
end

def visit(node)

def visit(node)
  node&.accept(self)
end

def visit_call_node(node)

def visit_call_node(node)
  if !node.opening_loc && node.arguments.arguments.length == 1
    bounds(node.receiver.location)
    left = visit(node.receiver)
    bounds(node.arguments.arguments.first.location)
    right = visit(node.arguments.arguments.first)
    on_binary(left, source[node.message_loc.start_offset...node.message_loc.end_offset].to_sym, right)
  else
    raise NotImplementedError
  end
end

def visit_integer_node(node)

def visit_integer_node(node)
  bounds(node.location)
  on_int(source[node.location.start_offset...node.location.end_offset])
end

def visit_program_node(node)

def visit_program_node(node)
  bounds(node.location)
  on_program(visit(node.statements))
end

def visit_statements_node(node)

def visit_statements_node(node)
  bounds(node.location)
  node.body.inject(on_stmts_new) do |stmts, stmt|
    on_stmts_add(stmts, visit(stmt))
  end
end

def visit_token(node)

def visit_token(node)
  bounds(node.location)
  case node.type
  when :MINUS
    on_op(node.value)
  when :PLUS
    on_op(node.value)
  else
    raise NotImplementedError, "Unknown token: #{node.type}"
  end
end