зеркало из https://github.com/github/ruby.git
464 строки
14 KiB
Ruby
464 строки
14 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
# Here we are reopening the prism module to provide methods on nodes that aren't
|
|
# templated and are meant as convenience methods.
|
|
module Prism
|
|
class Node
|
|
def deprecated(*replacements) # :nodoc:
|
|
location = caller_locations(1, 1)
|
|
location = location[0].label if location
|
|
suggest = replacements.map { |replacement| "#{self.class}##{replacement}" }
|
|
|
|
warn(<<~MSG, category: :deprecated)
|
|
[deprecation]: #{self.class}##{location} is deprecated and will be \
|
|
removed in the next major version. Use #{suggest.join("/")} instead.
|
|
#{(caller(1, 3) || []).join("\n")}
|
|
MSG
|
|
end
|
|
end
|
|
|
|
module RegularExpressionOptions # :nodoc:
|
|
# Returns a numeric value that represents the flags that were used to create
|
|
# the regular expression.
|
|
def options
|
|
o = 0
|
|
o |= Regexp::IGNORECASE if flags.anybits?(RegularExpressionFlags::IGNORE_CASE)
|
|
o |= Regexp::EXTENDED if flags.anybits?(RegularExpressionFlags::EXTENDED)
|
|
o |= Regexp::MULTILINE if flags.anybits?(RegularExpressionFlags::MULTI_LINE)
|
|
o |= Regexp::FIXEDENCODING if flags.anybits?(RegularExpressionFlags::EUC_JP | RegularExpressionFlags::WINDOWS_31J | RegularExpressionFlags::UTF_8)
|
|
o |= Regexp::NOENCODING if flags.anybits?(RegularExpressionFlags::ASCII_8BIT)
|
|
o
|
|
end
|
|
end
|
|
|
|
class InterpolatedMatchLastLineNode < Node
|
|
include RegularExpressionOptions
|
|
end
|
|
|
|
class InterpolatedRegularExpressionNode < Node
|
|
include RegularExpressionOptions
|
|
end
|
|
|
|
class MatchLastLineNode < Node
|
|
include RegularExpressionOptions
|
|
end
|
|
|
|
class RegularExpressionNode < Node
|
|
include RegularExpressionOptions
|
|
end
|
|
|
|
private_constant :RegularExpressionOptions
|
|
|
|
module HeredocQuery # :nodoc:
|
|
# Returns true if this node was represented as a heredoc in the source code.
|
|
def heredoc?
|
|
opening&.start_with?("<<")
|
|
end
|
|
end
|
|
|
|
class InterpolatedStringNode < Node
|
|
include HeredocQuery
|
|
end
|
|
|
|
class InterpolatedXStringNode < Node
|
|
include HeredocQuery
|
|
end
|
|
|
|
class StringNode < Node
|
|
include HeredocQuery
|
|
|
|
# Occasionally it's helpful to treat a string as if it were interpolated so
|
|
# that there's a consistent interface for working with strings.
|
|
def to_interpolated
|
|
InterpolatedStringNode.new(
|
|
source,
|
|
-1,
|
|
location,
|
|
frozen? ? InterpolatedStringNodeFlags::FROZEN : 0,
|
|
opening_loc,
|
|
[copy(location: content_loc, opening_loc: nil, closing_loc: nil)],
|
|
closing_loc
|
|
)
|
|
end
|
|
end
|
|
|
|
class XStringNode < Node
|
|
include HeredocQuery
|
|
|
|
# Occasionally it's helpful to treat a string as if it were interpolated so
|
|
# that there's a consistent interface for working with strings.
|
|
def to_interpolated
|
|
InterpolatedXStringNode.new(
|
|
source,
|
|
-1,
|
|
location,
|
|
flags,
|
|
opening_loc,
|
|
[StringNode.new(source, node_id, content_loc, 0, nil, content_loc, nil, unescaped)],
|
|
closing_loc
|
|
)
|
|
end
|
|
end
|
|
|
|
private_constant :HeredocQuery
|
|
|
|
class ImaginaryNode < Node
|
|
# Returns the value of the node as a Ruby Complex.
|
|
def value
|
|
Complex(0, numeric.value)
|
|
end
|
|
end
|
|
|
|
class RationalNode < Node
|
|
# Returns the value of the node as a Ruby Rational.
|
|
def value
|
|
Rational(numerator, denominator)
|
|
end
|
|
|
|
# Returns the value of the node as an IntegerNode or a FloatNode. This
|
|
# method is deprecated in favor of #value or #numerator/#denominator.
|
|
def numeric
|
|
deprecated("value", "numerator", "denominator")
|
|
|
|
if denominator == 1
|
|
IntegerNode.new(source, -1, location.chop, flags, numerator)
|
|
else
|
|
FloatNode.new(source, -1, location.chop, 0, numerator.to_f / denominator)
|
|
end
|
|
end
|
|
end
|
|
|
|
class ConstantReadNode < Node
|
|
# Returns the list of parts for the full name of this constant.
|
|
# For example: [:Foo]
|
|
def full_name_parts
|
|
[name]
|
|
end
|
|
|
|
# Returns the full name of this constant. For example: "Foo"
|
|
def full_name
|
|
name.to_s
|
|
end
|
|
end
|
|
|
|
class ConstantWriteNode < Node
|
|
# Returns the list of parts for the full name of this constant.
|
|
# For example: [:Foo]
|
|
def full_name_parts
|
|
[name]
|
|
end
|
|
|
|
# Returns the full name of this constant. For example: "Foo"
|
|
def full_name
|
|
name.to_s
|
|
end
|
|
end
|
|
|
|
class ConstantPathNode < Node
|
|
# An error class raised when dynamic parts are found while computing a
|
|
# constant path's full name. For example:
|
|
# Foo::Bar::Baz -> does not raise because all parts of the constant path are
|
|
# simple constants
|
|
# var::Bar::Baz -> raises because the first part of the constant path is a
|
|
# local variable
|
|
class DynamicPartsInConstantPathError < StandardError; end
|
|
|
|
# An error class raised when missing nodes are found while computing a
|
|
# constant path's full name. For example:
|
|
# Foo:: -> raises because the constant path is missing the last part
|
|
class MissingNodesInConstantPathError < StandardError; end
|
|
|
|
# Returns the list of parts for the full name of this constant path.
|
|
# For example: [:Foo, :Bar]
|
|
def full_name_parts
|
|
parts = [] #: Array[Symbol]
|
|
current = self #: node?
|
|
|
|
while current.is_a?(ConstantPathNode)
|
|
name = current.name
|
|
if name.nil?
|
|
raise MissingNodesInConstantPathError, "Constant path contains missing nodes. Cannot compute full name"
|
|
end
|
|
|
|
parts.unshift(name)
|
|
current = current.parent
|
|
end
|
|
|
|
if !current.is_a?(ConstantReadNode) && !current.nil?
|
|
raise DynamicPartsInConstantPathError, "Constant path contains dynamic parts. Cannot compute full name"
|
|
end
|
|
|
|
parts.unshift(current&.name || :"")
|
|
end
|
|
|
|
# Returns the full name of this constant path. For example: "Foo::Bar"
|
|
def full_name
|
|
full_name_parts.join("::")
|
|
end
|
|
|
|
# Previously, we had a child node on this class that contained either a
|
|
# constant read or a missing node. To not cause a breaking change, we
|
|
# continue to supply that API.
|
|
def child
|
|
deprecated("name", "name_loc")
|
|
|
|
if name
|
|
ConstantReadNode.new(source, -1, name_loc, 0, name)
|
|
else
|
|
MissingNode.new(source, -1, location, 0)
|
|
end
|
|
end
|
|
end
|
|
|
|
class ConstantPathTargetNode < Node
|
|
# Returns the list of parts for the full name of this constant path.
|
|
# For example: [:Foo, :Bar]
|
|
def full_name_parts
|
|
parts =
|
|
case parent
|
|
when ConstantPathNode, ConstantReadNode
|
|
parent.full_name_parts
|
|
when nil
|
|
[:""]
|
|
else
|
|
# e.g. self::Foo, (var)::Bar = baz
|
|
raise ConstantPathNode::DynamicPartsInConstantPathError, "Constant target path contains dynamic parts. Cannot compute full name"
|
|
end
|
|
|
|
if name.nil?
|
|
raise ConstantPathNode::MissingNodesInConstantPathError, "Constant target path contains missing nodes. Cannot compute full name"
|
|
end
|
|
|
|
parts.push(name)
|
|
end
|
|
|
|
# Returns the full name of this constant path. For example: "Foo::Bar"
|
|
def full_name
|
|
full_name_parts.join("::")
|
|
end
|
|
|
|
# Previously, we had a child node on this class that contained either a
|
|
# constant read or a missing node. To not cause a breaking change, we
|
|
# continue to supply that API.
|
|
def child
|
|
deprecated("name", "name_loc")
|
|
|
|
if name
|
|
ConstantReadNode.new(source, -1, name_loc, 0, name)
|
|
else
|
|
MissingNode.new(source, -1, location, 0)
|
|
end
|
|
end
|
|
end
|
|
|
|
class ConstantTargetNode < Node
|
|
# Returns the list of parts for the full name of this constant.
|
|
# For example: [:Foo]
|
|
def full_name_parts
|
|
[name]
|
|
end
|
|
|
|
# Returns the full name of this constant. For example: "Foo"
|
|
def full_name
|
|
name.to_s
|
|
end
|
|
end
|
|
|
|
class ParametersNode < Node
|
|
# Mirrors the Method#parameters method.
|
|
def signature
|
|
names = [] #: Array[[Symbol, Symbol] | [Symbol]]
|
|
|
|
requireds.each do |param|
|
|
names << (param.is_a?(MultiTargetNode) ? [:req] : [:req, param.name])
|
|
end
|
|
|
|
optionals.each { |param| names << [:opt, param.name] }
|
|
|
|
if rest && rest.is_a?(RestParameterNode)
|
|
names << [:rest, rest.name || :*]
|
|
end
|
|
|
|
posts.each do |param|
|
|
case param
|
|
when MultiTargetNode
|
|
names << [:req]
|
|
when NoKeywordsParameterNode, KeywordRestParameterNode, ForwardingParameterNode
|
|
# Invalid syntax, e.g. "def f(**nil, ...)" moves the NoKeywordsParameterNode to posts
|
|
raise "Invalid syntax"
|
|
else
|
|
names << [:req, param.name]
|
|
end
|
|
end
|
|
|
|
# Regardless of the order in which the keywords were defined, the required
|
|
# keywords always come first followed by the optional keywords.
|
|
keyopt = [] #: Array[OptionalKeywordParameterNode]
|
|
keywords.each do |param|
|
|
if param.is_a?(OptionalKeywordParameterNode)
|
|
keyopt << param
|
|
else
|
|
names << [:keyreq, param.name]
|
|
end
|
|
end
|
|
|
|
keyopt.each { |param| names << [:key, param.name] }
|
|
|
|
case keyword_rest
|
|
when ForwardingParameterNode
|
|
names.concat([[:rest, :*], [:keyrest, :**], [:block, :&]])
|
|
when KeywordRestParameterNode
|
|
names << [:keyrest, keyword_rest.name || :**]
|
|
when NoKeywordsParameterNode
|
|
names << [:nokey]
|
|
end
|
|
|
|
names << [:block, block.name || :&] if block
|
|
names
|
|
end
|
|
end
|
|
|
|
class CallNode < Node
|
|
# When a call node has the attribute_write flag set, it means that the call
|
|
# is using the attribute write syntax. This is either a method call to []=
|
|
# or a method call to a method that ends with =. Either way, the = sign is
|
|
# present in the source.
|
|
#
|
|
# Prism returns the message_loc _without_ the = sign attached, because there
|
|
# can be any amount of space between the message and the = sign. However,
|
|
# sometimes you want the location of the full message including the inner
|
|
# space and the = sign. This method provides that.
|
|
def full_message_loc
|
|
attribute_write? ? message_loc&.adjoin("=") : message_loc
|
|
end
|
|
end
|
|
|
|
class CallOperatorWriteNode < Node
|
|
# Returns the binary operator used to modify the receiver. This method is
|
|
# deprecated in favor of #binary_operator.
|
|
def operator
|
|
deprecated("binary_operator")
|
|
binary_operator
|
|
end
|
|
|
|
# Returns the location of the binary operator used to modify the receiver.
|
|
# This method is deprecated in favor of #binary_operator_loc.
|
|
def operator_loc
|
|
deprecated("binary_operator_loc")
|
|
binary_operator_loc
|
|
end
|
|
end
|
|
|
|
class ClassVariableOperatorWriteNode < Node
|
|
# Returns the binary operator used to modify the receiver. This method is
|
|
# deprecated in favor of #binary_operator.
|
|
def operator
|
|
deprecated("binary_operator")
|
|
binary_operator
|
|
end
|
|
|
|
# Returns the location of the binary operator used to modify the receiver.
|
|
# This method is deprecated in favor of #binary_operator_loc.
|
|
def operator_loc
|
|
deprecated("binary_operator_loc")
|
|
binary_operator_loc
|
|
end
|
|
end
|
|
|
|
class ConstantOperatorWriteNode < Node
|
|
# Returns the binary operator used to modify the receiver. This method is
|
|
# deprecated in favor of #binary_operator.
|
|
def operator
|
|
deprecated("binary_operator")
|
|
binary_operator
|
|
end
|
|
|
|
# Returns the location of the binary operator used to modify the receiver.
|
|
# This method is deprecated in favor of #binary_operator_loc.
|
|
def operator_loc
|
|
deprecated("binary_operator_loc")
|
|
binary_operator_loc
|
|
end
|
|
end
|
|
|
|
class ConstantPathOperatorWriteNode < Node
|
|
# Returns the binary operator used to modify the receiver. This method is
|
|
# deprecated in favor of #binary_operator.
|
|
def operator
|
|
deprecated("binary_operator")
|
|
binary_operator
|
|
end
|
|
|
|
# Returns the location of the binary operator used to modify the receiver.
|
|
# This method is deprecated in favor of #binary_operator_loc.
|
|
def operator_loc
|
|
deprecated("binary_operator_loc")
|
|
binary_operator_loc
|
|
end
|
|
end
|
|
|
|
class GlobalVariableOperatorWriteNode < Node
|
|
# Returns the binary operator used to modify the receiver. This method is
|
|
# deprecated in favor of #binary_operator.
|
|
def operator
|
|
deprecated("binary_operator")
|
|
binary_operator
|
|
end
|
|
|
|
# Returns the location of the binary operator used to modify the receiver.
|
|
# This method is deprecated in favor of #binary_operator_loc.
|
|
def operator_loc
|
|
deprecated("binary_operator_loc")
|
|
binary_operator_loc
|
|
end
|
|
end
|
|
|
|
class IndexOperatorWriteNode < Node
|
|
# Returns the binary operator used to modify the receiver. This method is
|
|
# deprecated in favor of #binary_operator.
|
|
def operator
|
|
deprecated("binary_operator")
|
|
binary_operator
|
|
end
|
|
|
|
# Returns the location of the binary operator used to modify the receiver.
|
|
# This method is deprecated in favor of #binary_operator_loc.
|
|
def operator_loc
|
|
deprecated("binary_operator_loc")
|
|
binary_operator_loc
|
|
end
|
|
end
|
|
|
|
class InstanceVariableOperatorWriteNode < Node
|
|
# Returns the binary operator used to modify the receiver. This method is
|
|
# deprecated in favor of #binary_operator.
|
|
def operator
|
|
deprecated("binary_operator")
|
|
binary_operator
|
|
end
|
|
|
|
# Returns the location of the binary operator used to modify the receiver.
|
|
# This method is deprecated in favor of #binary_operator_loc.
|
|
def operator_loc
|
|
deprecated("binary_operator_loc")
|
|
binary_operator_loc
|
|
end
|
|
end
|
|
|
|
class LocalVariableOperatorWriteNode < Node
|
|
# Returns the binary operator used to modify the receiver. This method is
|
|
# deprecated in favor of #binary_operator.
|
|
def operator
|
|
deprecated("binary_operator")
|
|
binary_operator
|
|
end
|
|
|
|
# Returns the location of the binary operator used to modify the receiver.
|
|
# This method is deprecated in favor of #binary_operator_loc.
|
|
def operator_loc
|
|
deprecated("binary_operator_loc")
|
|
binary_operator_loc
|
|
end
|
|
end
|
|
end
|