# frozen_string_literal: truemodulePrism# This represents a source of Ruby code that has been parsed. It is used in# conjunction with locations to allow them to resolve line numbers and source# ranges.classSourceattr_reader:source,:offsetsdefinitialize(source,offsets=compute_offsets(source))@source=source@offsets=offsetsenddefslice(offset,length)source.byteslice(offset,length)enddefline(value)offsets.bsearch_index{|offset|offset>value}||offsets.lengthenddefline_offset(value)offsets[line(value)-1]enddefcolumn(value)value-offsets[line(value)-1]endprivatedefcompute_offsets(code)offsets=[0]code.b.scan("\n"){offsets<<$~.end(0)}offsetsendend# This represents a location in the source.classLocation# A Source object that is used to determine more information from the given# offset and length.protectedattr_reader:source# The byte offset from the beginning of the source where this location# starts.attr_reader:start_offset# The length of this location in bytes.attr_reader:length# The list of comments attached to this locationattr_reader:commentsdefinitialize(source,start_offset,length)@source=source@start_offset=start_offset@length=length@comments=[]end# Create a new location object with the given options.defcopy(**options)Location.new(options.fetch(:source){source},options.fetch(:start_offset){start_offset},options.fetch(:length){length})end# Returns a string representation of this location.definspect"#<Prism::Location @start_offset=#{@start_offset} @length=#{@length} start_line=#{start_line}>"end# The source code that this location represents.defslicesource.slice(start_offset,length)end# The byte offset from the beginning of the source where this location ends.defend_offsetstart_offset+lengthend# The line number where this location starts.defstart_linesource.line(start_offset)end# The content of the line where this location starts before this location.defstart_line_sliceoffset=source.line_offset(start_offset)source.slice(offset,start_offset-offset)end# The line number where this location ends.defend_linesource.line(end_offset-1)end# The column number in bytes where this location starts from the start of# the line.defstart_columnsource.column(start_offset)end# The column number in bytes where this location ends from the start of the# line.defend_columnsource.column(end_offset)enddefdeconstruct_keys(keys){start_offset: start_offset,end_offset: end_offset}enddefpretty_print(q)q.text("(#{start_line},#{start_column})-(#{end_line},#{end_column}))")enddef==(other)other.is_a?(Location)&&other.start_offset==start_offset&&other.end_offset==end_offsetend# Returns a new location that stretches from this location to the given# other location. Raises an error if this location is not before the other# location or if they don't share the same source.defjoin(other)raise"Incompatible sources"ifsource!=other.sourceraise"Incompatible locations"ifstart_offset>other.start_offsetLocation.new(source,start_offset,other.end_offset-start_offset)enddefself.nullnew(0,0)endend# This represents a comment that was encountered during parsing.classCommentTYPES=[:inline,:embdoc,:__END__]attr_reader:type,:locationdefinitialize(type,location)@type=type@location=locationenddefdeconstruct_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 itselfdeftrailing?type==:inline&&!location.start_line_slice.strip.empty?enddefinspect"#<Prism::Comment @type=#{@type.inspect} @location=#{@location.inspect}>"endend# This represents an error that was encountered during parsing.classParseErrorattr_reader:message,:locationdefinitialize(message,location)@message=message@location=locationenddefdeconstruct_keys(keys){message: message,location: location}enddefinspect"#<Prism::ParseError @message=#{@message.inspect} @location=#{@location.inspect}>"endend# This represents a warning that was encountered during parsing.classParseWarningattr_reader:message,:locationdefinitialize(message,location)@message=message@location=locationenddefdeconstruct_keys(keys){message: message,location: location}enddefinspect"#<Prism::ParseWarning @message=#{@message.inspect} @location=#{@location.inspect}>"endend# This represents the result of a call to ::parse or ::parse_file. It contains# the AST, any comments that were encounters, and any errors that were# encountered.classParseResultattr_reader:value,:comments,:errors,:warnings,:sourcedefinitialize(value,comments,errors,warnings,source)@value=value@comments=comments@errors=errors@warnings=warnings@source=sourceenddefdeconstruct_keys(keys){value: value,comments: comments,errors: errors,warnings: warnings}enddefsuccess?errors.empty?enddeffailure?!success?endend# This represents a token from the Ruby source.classTokenattr_reader:type,:value,:locationdefinitialize(type,value,location)@type=type@value=value@location=locationenddefdeconstruct_keys(keys){type: type,value: value,location: location}enddefpretty_print(q)q.groupdoq.text(type.to_s)self.location.pretty_print(q)q.text("(")q.nest(2)doq.breakable("")q.pp(value)endq.breakable("")q.text(")")endenddef==(other)other.is_a?(Token)&&other.type==type&&other.value==valueendendend