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)
def self.sexp(source) SexpBuilderPP.new(source).parse end
def self.sexp_raw(source)
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)
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