class Prism::RipperCompat

This class is meant to provide a compatibility layer between prism and Ripper. It functions by parsing the entire tree first and then walking it and executing each of the Ripper callbacks as it goes.

This class is going to necessarily be slower than the native Ripper API. It is meant as a stopgap until developers migrate to using prism. It is also meant as a test harness for the prism parser.

Attributes

column[R]

The current column number of the parser.

lineno[R]

The current line number of the parser.

source[R]

The source that is being parsed.

Public Class Methods

new(source) click to toggle source

Create a new RipperCompat object with the given source.

# File prism/ripper_compat.rb, line 67
def initialize(source)
  @source = source
  @result = nil
  @lineno = nil
  @column = nil
end
sexp(source) click to toggle source

This is a convenience method that runs the SexpBuilderPP subclass parser.

# File prism/ripper_compat.rb, line 157
def self.sexp(source)
  SexpBuilderPP.new(source).parse
end
sexp_raw(source) click to toggle source

This is a convenience method that runs the SexpBuilder subclass parser.

# File prism/ripper_compat.rb, line 152
def self.sexp_raw(source)
  SexpBuilder.new(source).parse
end

Public Instance Methods

error?() click to toggle source

True if the parser encountered an error during parsing.

# File prism/ripper_compat.rb, line 79
def error?
  result.errors.any?
end
parse() click to toggle source

Parse the source and return the result.

# File prism/ripper_compat.rb, line 84
def parse
  result.value.accept(self) unless error?
end
visit(node) click to toggle source

This method is responsible for dispatching to the correct visitor method based on the type of the node.

# File prism/ripper_compat.rb, line 94
def visit(node)
  node&.accept(self)
end
visit_call_node(node) click to toggle source

Visit a CallNode node.

# File prism/ripper_compat.rb, line 99
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
visit_integer_node(node) click to toggle source

Visit an IntegerNode node.

# File prism/ripper_compat.rb, line 114
def visit_integer_node(node)
  bounds(node.location)
  on_int(source[node.location.start_offset...node.location.end_offset])
end
visit_program_node(node) click to toggle source

Visit a ProgramNode node.

# File prism/ripper_compat.rb, line 142
def visit_program_node(node)
  bounds(node.location)
  on_program(visit(node.statements))
end
visit_statements_node(node) click to toggle source

Visit a StatementsNode node.

# File prism/ripper_compat.rb, line 120
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
visit_token(node) click to toggle source

Visit a token found during parsing.

# File prism/ripper_compat.rb, line 128
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

Private Instance Methods

bounds(location) click to toggle source

This method is responsible for updating lineno and column information to reflect the current node.

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

# File prism/ripper_compat.rb, line 168
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
result() click to toggle source

Lazily initialize the parse result.

# File prism/ripper_compat.rb, line 176
def result
  @result ||= Prism.parse(source)
end