модуль Prism::Debug
Этот модуль используется для тестирования и отладки и не предназначен для использования потребителями этой библиотеки.
Константы
- AnonymousLocal
-
Используется для обозначения локальной переменной, которая будет присутствовать в таблице локальных переменных, но к которой нельзя получить прямой доступ из исходного кода. Например, переменная итерации в цикле for или позиционный параметр в определении метода, который деструктурируется.
Публичные методы класса
# File lib/prism/debug.rb, line 54
def self.cruby_locals(source)
verbose, $VERBOSE = $VERBOSE, nil
begin
locals = []
stack = [ISeq.new(RubyVM::InstructionSequence.compile(source).to_a)]
while (iseq = stack.pop)
names = [*iseq.local_table]
names.map!.with_index do |name, index|
# When an anonymous local variable is present in the iseq's local
# table, it is represented as the stack offset from the top.
# However, when these are dumped to binary and read back in, they
# are replaced with the symbol :#arg_rest. To consistently handle
# this, we replace them here with their index.
if name == :"#arg_rest"
names.length - index + 1
else
name
end
end
locals << names
iseq.each_child { |child| stack << child }
end
locals
ensure
$VERBOSE = verbose
end
end Для данного исходного кода, компилируется с CRuby и возвращает список всех наборов локальных переменных, которые были встречены.
# File lib/prism/debug.rb, line 196 def self.newlines(source) Prism.parse(source).source.offsets end
Для данной строки исходного кода, возвращает байтовые смещения каждого символа новой строки в исходном коде.
# File lib/prism/debug.rb, line 98
def self.prism_locals(source)
locals = []
stack = [Prism.parse(source).value]
while (node = stack.pop)
case node
when BlockNode, DefNode, LambdaNode
names = node.locals
params =
if node.is_a?(DefNode)
node.parameters
elsif node.parameters.is_a?(NumberedParametersNode)
nil
else
node.parameters&.parameters
end
# prism places parameters in the same order that they appear in the
# source. CRuby places them in the order that they need to appear
# according to their own internal calling convention. We mimic that
# order here so that we can compare properly.
if params
sorted = [
*params.requireds.map do |required|
if required.is_a?(RequiredParameterNode)
required.name
else
AnonymousLocal
end
end,
*params.optionals.map(&:name),
*((params.rest.name || :*) if params.rest && !params.rest.is_a?(ImplicitRestNode)),
*params.posts.map do |post|
if post.is_a?(RequiredParameterNode)
post.name
else
AnonymousLocal
end
end,
*params.keywords.grep(RequiredKeywordParameterNode).map(&:name),
*params.keywords.grep(OptionalKeywordParameterNode).map(&:name),
]
if params.keyword_rest.is_a?(ForwardingParameterNode)
sorted.push(:*, :&, :"...")
end
sorted << AnonymousLocal if params.keywords.any?
# Recurse down the parameter tree to find any destructured
# parameters and add them after the other parameters.
param_stack = params.requireds.concat(params.posts).grep(MultiTargetNode).reverse
while (param = param_stack.pop)
case param
when MultiTargetNode
param_stack.concat(param.rights.reverse)
param_stack << param.rest
param_stack.concat(param.lefts.reverse)
when RequiredParameterNode
sorted << param.name
when SplatNode
sorted << param.expression.name if param.expression
end
end
names = sorted.concat(names - sorted)
end
names.map!.with_index do |name, index|
if name == AnonymousLocal
names.length - index + 1
else
name
end
end
locals << names
when ClassNode, ModuleNode, ProgramNode, SingletonClassNode
locals << node.locals
when ForNode
locals << [2]
when PostExecutionNode
locals.push([], [])
when InterpolatedRegularExpressionNode
locals << [] if node.once?
end
stack.concat(node.compact_child_nodes)
end
locals
end Для данного исходного кода, анализируется с помощью prism и возвращает список всех наборов локальных переменных, которые были встречены.
Ruby Core © 1993–2022 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.