lib/yarp.rb in yarp-0.10.0 vs lib/yarp.rb in yarp-0.11.0
- old
+ new
@@ -18,10 +18,14 @@
def line(value)
offsets.bsearch_index { |offset| offset > value } || offsets.length
end
+ def line_offset(value)
+ offsets[line(value) - 1]
+ end
+
def column(value)
value - offsets[line(value) - 1]
end
private
@@ -44,14 +48,18 @@
attr_reader :start_offset
# The length of this location in bytes.
attr_reader :length
+ # The list of comments attached to this location
+ attr_reader :comments
+
def initialize(source, start_offset, length)
@source = source
@start_offset = start_offset
@length = length
+ @comments = []
end
# Create a new location object with the given options.
def copy(**options)
Location.new(
@@ -79,10 +87,16 @@
# The line number where this location starts.
def start_line
source.line(start_offset)
end
+ # The content of the line where this location starts before this location.
+ def start_line_slice
+ offset = source.line_offset(start_offset)
+ source.slice(offset, start_offset - offset)
+ end
+
# The line number where this location ends.
def end_line
source.line(end_offset - 1)
end
@@ -93,11 +107,11 @@
end
# The column number in bytes where this location ends from the start of the
# line.
def end_column
- source.column(end_offset - 1)
+ source.column(end_offset)
end
def deconstruct_keys(keys)
{ start_offset: start_offset, end_offset: end_offset }
end
@@ -139,10 +153,19 @@
end
def deconstruct_keys(keys)
{ type: type, location: location }
end
+
+ # Returns true if the comment happens on the same line as other code and false if the comment is by itself
+ def trailing?
+ type == :inline && !location.start_line_slice.strip.empty?
+ end
+
+ def inspect
+ "#<YARP::Comment @type=#{@type.inspect} @location=#{@location.inspect}>"
+ end
end
# This represents an error that was encountered during parsing.
class ParseError
attr_reader :message, :location
@@ -153,10 +176,14 @@
end
def deconstruct_keys(keys)
{ message: message, location: location }
end
+
+ def inspect
+ "#<YARP::ParseError @message=#{@message.inspect} @location=#{@location.inspect}>"
+ end
end
# This represents a warning that was encountered during parsing.
class ParseWarning
attr_reader :message, :location
@@ -167,10 +194,14 @@
end
def deconstruct_keys(keys)
{ message: message, location: location }
end
+
+ def inspect
+ "#<YARP::ParseWarning @message=#{@message.inspect} @location=#{@location.inspect}>"
+ end
end
# A class that knows how to walk down the tree. None of the individual visit
# methods are implemented on this visitor, so it forces the consumer to
# implement each one that they need. For a default implementation that
@@ -215,49 +246,10 @@
end
def failure?
!success?
end
-
- # Keep in sync with Java MarkNewlinesVisitor
- class MarkNewlinesVisitor < YARP::Visitor
- def initialize(newline_marked)
- @newline_marked = newline_marked
- end
-
- def visit_block_node(node)
- old_newline_marked = @newline_marked
- @newline_marked = Array.new(old_newline_marked.size, false)
- begin
- super(node)
- ensure
- @newline_marked = old_newline_marked
- end
- end
- alias_method :visit_lambda_node, :visit_block_node
-
- def visit_if_node(node)
- node.set_newline_flag(@newline_marked)
- super(node)
- end
- alias_method :visit_unless_node, :visit_if_node
-
- def visit_statements_node(node)
- node.body.each do |child|
- child.set_newline_flag(@newline_marked)
- end
- super(node)
- end
- end
- private_constant :MarkNewlinesVisitor
-
- def mark_newlines
- newline_marked = Array.new(1 + @source.offsets.size, false)
- visitor = MarkNewlinesVisitor.new(newline_marked)
- value.accept(visitor)
- value
- end
end
# This represents a token from the Ruby source.
class Token
attr_reader :type, :value, :location
@@ -321,20 +313,84 @@
q.text("[Li:#{location.start_line}]") if newline?
q.text("(")
q.nest(2) do
deconstructed = deconstruct_keys([])
deconstructed.delete(:location)
-
q.breakable("")
q.seplist(deconstructed, lambda { q.comma_breakable }, :each_value) { |value| q.pp(value) }
end
q.breakable("")
q.text(")")
end
end
end
+ # This object is responsible for generating the output for the inspect method
+ # implementations of child nodes.
+ class NodeInspector
+ attr_reader :prefix, :output
+
+ def initialize(prefix = "")
+ @prefix = prefix
+ @output = +""
+ end
+
+ # Appends a line to the output with the current prefix.
+ def <<(line)
+ output << "#{prefix}#{line}"
+ end
+
+ # This generates a string that is used as the header of the inspect output
+ # for any given node.
+ def header(node)
+ output = +"@ #{node.class.name.split("::").last} ("
+ output << "location: (#{node.location.start_offset}...#{node.location.end_offset})"
+ output << ", newline: true" if node.newline?
+ output << ")\n"
+ output
+ end
+
+ # Generates a string that represents a list of nodes. It handles properly
+ # using the box drawing characters to make the output look nice.
+ def list(prefix, nodes)
+ output = +"(length: #{nodes.length})\n"
+ last_index = nodes.length - 1
+
+ nodes.each_with_index do |node, index|
+ pointer, preadd = (index == last_index) ? ["└── ", " "] : ["├── ", "│ "]
+ node_prefix = "#{prefix}#{preadd}"
+ output << node.inspect(NodeInspector.new(node_prefix)).sub(node_prefix, "#{prefix}#{pointer}")
+ end
+
+ output
+ end
+
+ # Generates a string that represents a location field on a node.
+ def location(value)
+ if value
+ "(#{value.start_offset}...#{value.end_offset}) = #{value.slice.inspect}"
+ else
+ "∅"
+ end
+ end
+
+ # Generates a string that represents a child node.
+ def child_node(node, append)
+ node.inspect(child_inspector(append)).delete_prefix(prefix)
+ end
+
+ # Returns a new inspector that can be used to inspect a child node.
+ def child_inspector(append)
+ NodeInspector.new("#{prefix}#{append}")
+ end
+
+ # Returns the output as a string.
+ def to_str
+ output
+ end
+ end
+
class FloatNode < Node
def value
Float(slice)
end
end
@@ -462,14 +518,14 @@
# order here so that we can compare properly.
if params
sorted = [
*params.requireds.grep(RequiredParameterNode).map(&:name),
*params.optionals.map(&:name),
- *((params.rest.name ? params.rest.name.to_sym : :*) if params.rest && params.rest.operator != ","),
+ *((params.rest.name || :*) if params.rest && params.rest.operator != ","),
*params.posts.grep(RequiredParameterNode).map(&:name),
- *params.keywords.reject(&:value).map { |param| param.name.chomp(":").to_sym },
- *params.keywords.select(&:value).map { |param| param.name.chomp(":").to_sym }
+ *params.keywords.reject(&:value).map(&:name),
+ *params.keywords.select(&:value).map(&:name)
]
# TODO: When we get a ... parameter, we should be pushing * and &
# onto the local list. We don't do that yet, so we need to add them
# in here.
@@ -531,9 +587,13 @@
require_relative "yarp/desugar_visitor"
require_relative "yarp/node"
require_relative "yarp/ripper_compat"
require_relative "yarp/serialize"
require_relative "yarp/pack"
+require_relative "yarp/pattern"
+
+require_relative "yarp/parse_result/comments"
+require_relative "yarp/parse_result/newlines"
if RUBY_ENGINE == "ruby" and !ENV["YARP_FFI_BACKEND"]
require "yarp/yarp"
else
require_relative "yarp/ffi"