diff options
| -rw-r--r-- | lib/prism/parse_result.rb | 113 | ||||
| -rw-r--r-- | prism/templates/lib/prism/node.rb.erb | 9 |
2 files changed, 109 insertions, 13 deletions
diff --git a/lib/prism/parse_result.rb b/lib/prism/parse_result.rb index 00ae3aaa1a..5c2d97bc1e 100644 --- a/lib/prism/parse_result.rb +++ b/lib/prism/parse_result.rb @@ -5,19 +5,28 @@ module Prism # conjunction with locations to allow them to resolve line numbers and source # ranges. class Source - attr_reader :source, :offsets + # The source code that this source object represents. + attr_reader :source + # The list of newline byte offsets in the source code. + attr_reader :offsets + + # Create a new source object with the given source code and newline byte + # offsets. If no newline byte offsets are given, they will be computed from + # the source code. def initialize(source, offsets = compute_offsets(source)) @source = source @offsets = offsets end + # Perform a byteslice on the source code using the given byte offset and + # byte length. def slice(offset, length) source.byteslice(offset, length) end # Binary search through the offsets to find the line number for the given - # offset. + # byte offset. def line(value) left = 0 right = offsets.length - 1 @@ -36,10 +45,13 @@ module Prism left - 1 end + # Return the byte offset of the start of the line corresponding to the given + # byte offset. def line_offset(value) offsets[line(value)] end + # Return the column number for the given byte offset. def column(value) value - offsets[line(value)] end @@ -69,6 +81,8 @@ module Prism # The list of comments attached to this location attr_reader :comments + # Create a new location object with the given source, start byte offset, and + # byte length. def initialize(source, start_offset, length) @source = source @start_offset = start_offset @@ -128,14 +142,17 @@ module Prism source.column(end_offset) end + # Implement the hash pattern matching interface for Location. def deconstruct_keys(keys) { start_offset: start_offset, end_offset: end_offset } end + # Implement the pretty print interface for Location. def pretty_print(q) q.text("(#{start_line},#{start_column})-(#{end_line},#{end_column})") end + # Returns true if the given other location is equal to this location. def ==(other) other.is_a?(Location) && other.start_offset == start_offset && @@ -152,6 +169,9 @@ module Prism Location.new(source, start_offset, other.end_offset - start_offset) end + # Returns a null location that does not correspond to a source and points to + # the beginning of the file. Useful for when you want a location object but + # do not care where it points. def self.null new(nil, 0, 0) end @@ -159,24 +179,41 @@ module Prism # This represents a comment that was encountered during parsing. class Comment + # These are the three types that comments can be from a source file. + # + # :inline comments are the most common. They correspond to comments in the + # source file like this one that start with #. + # + # :embdoc comments are comments that are surrounded by =begin and =end. + # + # :__END__ comments are comments that are after the __END__ keyword in a + # source file. TYPES = [:inline, :embdoc, :__END__] - attr_reader :type, :location + # The type of comment that this comment is. + attr_reader :type + + # The location of this comment in the source. + attr_reader :location + # Create a new comment object with the given type and location. def initialize(type, location) @type = type @location = location end + # Implement the hash pattern matching interface for Comment. 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 + # 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 + # Returns a string representation of this comment. def inspect "#<Prism::Comment @type=#{@type.inspect} @location=#{@location.inspect}>" end @@ -184,25 +221,34 @@ module Prism # This represents a magic comment that was encountered during parsing. class MagicComment - attr_reader :key_loc, :value_loc + # A Location object representing the location of the key in the source. + attr_reader :key_loc + # A Location object representing the location of the value in the source. + attr_reader :value_loc + + # Create a new magic comment object with the given key and value locations. def initialize(key_loc, value_loc) @key_loc = key_loc @value_loc = value_loc end + # Returns the key of the magic comment by slicing it from the source code. def key key_loc.slice end + # Returns the value of the magic comment by slicing it from the source code. def value value_loc.slice end + # Implement the hash pattern matching interface for MagicComment. def deconstruct_keys(keys) { key_loc: key_loc, value_loc: value_loc } end + # Returns a string representation of this magic comment. def inspect "#<Prism::MagicComment @key=#{key.inspect} @value=#{value.inspect}>" end @@ -210,17 +256,24 @@ module Prism # This represents an error that was encountered during parsing. class ParseError - attr_reader :message, :location + # The message associated with this error. + attr_reader :message + + # A Location object representing the location of this error in the source. + attr_reader :location + # Create a new error object with the given message and location. def initialize(message, location) @message = message @location = location end + # Implement the hash pattern matching interface for ParseError. def deconstruct_keys(keys) { message: message, location: location } end + # Returns a string representation of this error. def inspect "#<Prism::ParseError @message=#{@message.inspect} @location=#{@location.inspect}>" end @@ -228,17 +281,24 @@ module Prism # This represents a warning that was encountered during parsing. class ParseWarning - attr_reader :message, :location + # The message associated with this warning. + attr_reader :message + # A Location object representing the location of this warning in the source. + attr_reader :location + + # Create a new warning object with the given message and location. def initialize(message, location) @message = message @location = location end + # Implement the hash pattern matching interface for ParseWarning. def deconstruct_keys(keys) { message: message, location: location } end + # Returns a string representation of this warning. def inspect "#<Prism::ParseWarning @message=#{@message.inspect} @location=#{@location.inspect}>" end @@ -248,8 +308,27 @@ module Prism # the AST, any comments that were encounters, and any errors that were # encountered. class ParseResult - attr_reader :value, :comments, :magic_comments, :errors, :warnings, :source + # The value that was generated by parsing. Normally this holds the AST, but + # it can sometimes how a list of tokens or other results passed back from + # the parser. + attr_reader :value + + # The list of comments that were encountered during parsing. + attr_reader :comments + # The list of magic comments that were encountered during parsing. + attr_reader :magic_comments + + # The list of errors that were generated during parsing. + attr_reader :errors + + # The list of warnings that were generated during parsing. + attr_reader :warnings + + # A Source instance that represents the source code that was parsed. + attr_reader :source + + # Create a new parse result object with the given values. def initialize(value, comments, magic_comments, errors, warnings, source) @value = value @comments = comments @@ -259,14 +338,19 @@ module Prism @source = source end + # Implement the hash pattern matching interface for ParseResult. def deconstruct_keys(keys) { value: value, comments: comments, magic_comments: magic_comments, errors: errors, warnings: warnings } end + # Returns true if there were no errors during parsing and false if there + # were. def success? errors.empty? end + # Returns true if there were errors during parsing and false if there were + # not. def failure? !success? end @@ -274,18 +358,28 @@ module Prism # This represents a token from the Ruby source. class Token - attr_reader :type, :value, :location + # The type of token that this token is. + attr_reader :type + + # A byteslice of the source that this token represents. + attr_reader :value + + # A Location object representing the location of this token in the source. + attr_reader :location + # Create a new token object with the given type, value, and location. def initialize(type, value, location) @type = type @value = value @location = location end + # Implement the hash pattern matching interface for Token. def deconstruct_keys(keys) { type: type, value: value, location: location } end + # Implement the pretty print interface for Token. def pretty_print(q) q.group do q.text(type.to_s) @@ -300,6 +394,7 @@ module Prism end end + # Returns true if the given other token is equal to this token. def ==(other) other.is_a?(Token) && other.type == type && diff --git a/prism/templates/lib/prism/node.rb.erb b/prism/templates/lib/prism/node.rb.erb index 23bf77dc06..a97ae557d5 100644 --- a/prism/templates/lib/prism/node.rb.erb +++ b/prism/templates/lib/prism/node.rb.erb @@ -4,11 +4,11 @@ module Prism class Node attr_reader :location - def newline? + def newline? # :nodoc: @newline ? true : false end - def set_newline_flag(newline_marked) + def set_newline_flag(newline_marked) # :nodoc: line = location.start_line unless newline_marked[line] newline_marked[line] = true @@ -55,12 +55,12 @@ module Prism end <%- if node.newline == false -%> - def set_newline_flag(newline_marked) + def set_newline_flag(newline_marked) # :nodoc: # Never mark <%= node.name %> with a newline flag, mark children instead end <%- elsif node.newline.is_a?(String) -%> - def set_newline_flag(newline_marked) + def set_newline_flag(newline_marked) # :nodoc: <%- field = node.fields.find { |f| f.name == node.newline } or raise node.newline -%> <%- case field -%> <%- when Prism::NodeField, Prism::OptionalNodeField -%> @@ -163,6 +163,7 @@ module Prism <%- end -%> <%- end -%> + # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) <%- node.fields.each_with_index do |field, index| -%> |
