class Prism::RipperCompat
treat the ‘Ripper` class.
To use this class, you treat `Prism::RipperCompat` effectively as you would
meant as a test harness for the prism parser.
is meant as a stopgap until developers migrate to using prism. 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 prism and
be greatly appreciated!
inconsistencies with Ripper. If you’d like to help out, pull requests would
Note: This integration is not finished, and therefore still has many
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 # :nodoc:
def _dispatch0; end # :nodoc:
def _dispatch1(_); end # :nodoc:
:nodoc:
def _dispatch1(_); end # :nodoc:
def _dispatch2(_, _); end # :nodoc:
:nodoc:
:nodoc:
def _dispatch2(_, _); end # :nodoc:
def _dispatch3(_, _, _); end # :nodoc:
:nodoc:
:nodoc:
:nodoc:
def _dispatch3(_, _, _); end # :nodoc:
def _dispatch4(_, _, _, _); end # :nodoc:
:nodoc:
:nodoc:
:nodoc:
:nodoc:
def _dispatch4(_, _, _, _); end # :nodoc:
def _dispatch5(_, _, _, _, _); end # :nodoc:
:nodoc:
:nodoc:
:nodoc:
:nodoc:
:nodoc:
def _dispatch5(_, _, _, _, _); end # :nodoc:
def _dispatch7(_, _, _, _, _, _, _); end # :nodoc:
:nodoc:
:nodoc:
:nodoc:
:nodoc:
:nodoc:
:nodoc:
def _dispatch7(_, _, _, _, _, _, _); end # :nodoc:
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) @lineno = location.start_line @column = location.start_column end
def bounds_values(lineno, column)
If we need to do something unusual, we can directly update the line number
def bounds_values(lineno, column) @lineno = lineno @column = column end
def error?
def error? result.failure? end
def initialize(source)
def initialize(source) @source = source @result = nil @lineno = nil @column = nil end
def parse
def parse result.magic_comments.each do |magic_comment| on_magic_comment(magic_comment.key, magic_comment.value) end if error? result.errors.each do |error| on_parse_error(error.message) end nil else result.value.accept(self) end end
def result
def result @result ||= Prism.parse(source) end
def visit_array_node(node)
def visit_array_node(node) elements = visit_elements(node.elements) unless node.elements.empty? bounds(node.location) on_array(elements) end
def visit_call_node(node)
def visit_call_node(node) if node.variable_call? if node.message.match?(/^[[:alpha:]_]/) bounds(node.message_loc) return on_vcall(on_ident(node.message)) end raise NotImplementedError, "Non-alpha variable call" end if node.opening_loc.nil? left = visit(node.receiver) if node.arguments&.arguments&.length == 1 right = visit(node.arguments.arguments.first) on_binary(left, node.name, right) elsif !node.arguments || node.arguments.empty? on_unary(node.name, left) else raise NotImplementedError, "More than two arguments for operator" end else raise NotImplementedError, "Non-nil opening_loc" end end
def visit_elements(elements)
def visit_elements(elements) bounds(elements.first.location) elements.inject(on_args_new) do |args, element| on_args_add(args, visit(element)) end end
def visit_float_node(node)
def visit_float_node(node) visit_number(node) { |text| on_float(text) } end
def visit_imaginary_node(node)
def visit_imaginary_node(node) visit_number(node) { |text| on_imaginary(text) } end
def visit_integer_node(node)
def visit_integer_node(node) visit_number(node) { |text| on_int(text) } end
def visit_number(node)
Visit a node that represents a number. We need to explicitly handle the
def visit_number(node) slice = node.slice location = node.location if slice[0] == "-" bounds_values(location.start_line, location.start_column + 1) value = yield slice[1..-1] bounds(node.location) on_unary(RUBY_ENGINE == "jruby" ? :- : :-@, value) else bounds(location) yield slice end end
def visit_parentheses_node(node)
def visit_parentheses_node(node) body = if node.body.nil? on_stmts_add(on_stmts_new, on_void_stmt) else visit(node.body) end bounds(node.location) on_paren(body) end
def visit_program_node(node)
def visit_program_node(node) statements = visit(node.statements) bounds(node.location) on_program(statements) end
def visit_range_node(node)
def visit_range_node(node) left = visit(node.left) right = visit(node.right) bounds(node.location) if node.exclude_end? on_dot3(left, right) else on_dot2(left, right) end end
def visit_rational_node(node)
def visit_rational_node(node) visit_number(node) { |text| on_rational(text) } 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