класс Prism::Translation::Parser::Compiler
Визитор, знающий, как преобразовать синтаксическое дерево Prism в синтаксическое дерево библиотеки whitequark/parser.
Константы
- Range
-
Позиции в AST библиотеки parser генерируются с помощью этого класса. Мы сохраняем ссылку на его константу, чтобы ускорить поиск.
Атрибуты
Экземпляр Parser::Builders::Default, используемый для построения AST.
Типы значений, которые могут быть перенаправлены в текущем контексте.
Указывает, находится ли текущий узел в структуре разбора.
Указывает, находится ли текущий узел в шаблоне.
Кэш смещений, используемый для преобразования между байтовыми и символьными смещениями в файле.
Экземпляр Parser::Base, используемый для построения AST.
Экземпляр Parser::Source::Buffer, содержащий ссылку на исходный код.
Публичные методы класса
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 39 def initialize(parser, offset_cache, forwarding: [], in_destructure: false, in_pattern: false) @parser = parser @builder = parser.builder @source_buffer = parser.source_buffer @offset_cache = offset_cache @forwarding = forwarding @in_destructure = in_destructure @in_pattern = in_pattern end
Инициализирует новый компилятор с заданным парсером, кэшем смещений и опциями.
Публичные методы экземпляра
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 58 def visit_alias_global_variable_node(node) builder.alias(token(node.keyword_loc), visit(node.new_name), visit(node.old_name)) end
alias $foo $bar ^^^^^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 52 def visit_alias_method_node(node) builder.alias(token(node.keyword_loc), visit(node.new_name), visit(node.old_name)) end
alias foo bar ^^^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 64 def visit_alternation_pattern_node(node) builder.match_alt(visit(node.left), token(node.operator_loc), visit(node.right)) end
foo => bar | baz
^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 70 def visit_and_node(node) builder.logical_op(:and, visit(node.left), token(node.operator_loc), visit(node.right)) end
a and b ^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 105 def visit_arguments_node(node) visit_all(node.arguments) end
foo(bar)
^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 76 def visit_array_node(node) builder.array(token(node.opening_loc), visit_all(node.elements), token(node.closing_loc)) end
-
^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 82
def visit_array_pattern_node(node)
elements = [*node.requireds]
elements << node.rest if !node.rest.nil? && !node.rest.is_a?(ImplicitRestNode)
elements.concat(node.posts)
visited = visit_all(elements)
if node.rest.is_a?(ImplicitRestNode)
visited[-1] = builder.match_with_trailing_comma(visited[-1], token(node.rest.location))
end
if node.constant
if visited.empty?
builder.const_pattern(visit(node.constant), token(node.opening_loc), builder.array_pattern(token(node.opening_loc), visited, token(node.closing_loc)), token(node.closing_loc))
else
builder.const_pattern(visit(node.constant), token(node.opening_loc), builder.array_pattern(nil, visited, nil), token(node.closing_loc))
end
else
builder.array_pattern(token(node.opening_loc), visited, token(node.closing_loc))
end
end foo => [bar]
^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 111
def visit_assoc_node(node)
key = node.key
if in_pattern
if node.value.is_a?(ImplicitNode)
if key.is_a?(SymbolNode)
if key.opening.nil?
builder.match_hash_var([key.unescaped, srange(key.location)])
else
builder.match_hash_var_from_str(token(key.opening_loc), [builder.string_internal([key.unescaped, srange(key.value_loc)])], token(key.closing_loc))
end
else
builder.match_hash_var_from_str(token(key.opening_loc), visit_all(key.parts), token(key.closing_loc))
end
elsif key.opening.nil?
builder.pair_keyword([key.unescaped, srange(key.location)], visit(node.value))
else
builder.pair_quoted(token(key.opening_loc), [builder.string_internal([key.unescaped, srange(key.value_loc)])], token(key.closing_loc), visit(node.value))
end
elsif node.value.is_a?(ImplicitNode)
if (value = node.value.value).is_a?(LocalVariableReadNode)
builder.pair_keyword(
[key.unescaped, srange(key)],
builder.ident([value.name, srange(key.value_loc)]).updated(:lvar)
)
else
builder.pair_label([key.unescaped, srange(key.location)])
end
elsif node.operator_loc
builder.pair(visit(key), token(node.operator_loc), visit(node.value))
elsif key.is_a?(SymbolNode) && key.opening_loc.nil?
builder.pair_keyword([key.unescaped, srange(key.location)], visit(node.value))
else
parts =
if key.is_a?(SymbolNode)
[builder.string_internal([key.unescaped, srange(key.value_loc)])]
else
visit_all(key.parts)
end
builder.pair_quoted(token(key.opening_loc), parts, token(key.closing_loc), visit(node.value))
end
end { a: 1 }
^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 160
def visit_assoc_splat_node(node)
if in_pattern
builder.match_rest(token(node.operator_loc), token(node.value&.location))
elsif node.value.nil? && forwarding.include?(:**)
builder.forwarded_kwrestarg(token(node.operator_loc))
else
builder.kwsplat(token(node.operator_loc), visit(node.value))
end
end def foo(**); bar(**); end
^^
{ **foo }
^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 172 def visit_back_reference_read_node(node) builder.back_ref(token(node.location)) end
$+ ^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 178
def visit_begin_node(node)
rescue_bodies = []
if (rescue_clause = node.rescue_clause)
begin
find_start_offset = (rescue_clause.reference&.location || rescue_clause.exceptions.last&.location || rescue_clause.keyword_loc).end_offset
find_end_offset = (rescue_clause.statements&.location&.start_offset || rescue_clause.subsequent&.location&.start_offset || (find_start_offset + 1))
rescue_bodies << builder.rescue_body(
token(rescue_clause.keyword_loc),
rescue_clause.exceptions.any? ? builder.array(nil, visit_all(rescue_clause.exceptions), nil) : nil,
token(rescue_clause.operator_loc),
visit(rescue_clause.reference),
srange_find(find_start_offset, find_end_offset, ";"),
visit(rescue_clause.statements)
)
end until (rescue_clause = rescue_clause.subsequent).nil?
end
begin_body =
builder.begin_body(
visit(node.statements),
rescue_bodies,
token(node.else_clause&.else_keyword_loc),
visit(node.else_clause),
token(node.ensure_clause&.ensure_keyword_loc),
visit(node.ensure_clause&.statements)
)
if node.begin_keyword_loc
builder.begin_keyword(token(node.begin_keyword_loc), begin_body, token(node.end_keyword_loc))
else
begin_body
end
end begin end ^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 216 def visit_block_argument_node(node) builder.block_pass(token(node.operator_loc), visit(node.expression)) end
foo(&bar)
^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 222 def visit_block_local_variable_node(node) builder.shadowarg(token(node.location)) end
foo { |; bar| }
^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 227 def visit_block_node(node) raise CompilationError, "Cannot directly compile block nodes" end
Блок на вызове ключевого слова или метода.
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 233 def visit_block_parameter_node(node) builder.blockarg(token(node.operator_loc), token(node.name_loc)) end
def foo(&bar); end
^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 238 def visit_block_parameters_node(node) [*visit(node.parameters)].concat(visit_all(node.locals)) end
Параметры блока.
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 247 def visit_break_node(node) builder.keyword_cmd(:break, token(node.keyword_loc), nil, visit(node.arguments) || [], nil) end
break ^^^^^
break foo ^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 352
def visit_call_and_write_node(node)
call_operator_loc = node.call_operator_loc
builder.op_assign(
builder.call_method(
visit(node.receiver),
call_operator_loc.nil? ? nil : [{ "." => :dot, "&." => :anddot, "::" => "::" }.fetch(call_operator_loc.slice), srange(call_operator_loc)],
node.message_loc ? [node.read_name, srange(node.message_loc)] : nil,
nil,
[],
nil
),
[node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
visit(node.value)
)
end foo.bar &&= baz ^^^^^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 259
def visit_call_node(node)
name = node.name
arguments = node.arguments&.arguments || []
block = node.block
if block.is_a?(BlockArgumentNode)
arguments = [*arguments, block]
block = nil
end
if node.call_operator_loc.nil?
case name
when :-@
case (receiver = node.receiver).type
when :integer_node, :float_node, :rational_node, :imaginary_node
return visit(numeric_negate(node.message_loc, receiver))
end
when :!
return visit_block(builder.not_op(token(node.message_loc), token(node.opening_loc), visit(node.receiver), token(node.closing_loc)), block)
when :=~
if (receiver = node.receiver).is_a?(RegularExpressionNode)
return builder.match_op(visit(receiver), token(node.message_loc), visit(node.arguments.arguments.first))
end
when :[]
return visit_block(builder.index(visit(node.receiver), token(node.opening_loc), visit_all(arguments), token(node.closing_loc)), block)
when :[]=
if node.message != "[]=" && node.arguments && block.nil? && !node.safe_navigation?
arguments = node.arguments.arguments[...-1]
arguments << node.block if node.block
return visit_block(
builder.assign(
builder.index_asgn(
visit(node.receiver),
token(node.opening_loc),
visit_all(arguments),
token(node.closing_loc),
),
srange_find(node.message_loc.end_offset, node.arguments.arguments.last.location.start_offset, "="),
visit(node.arguments.arguments.last)
),
block
)
end
end
end
message_loc = node.message_loc
call_operator_loc = node.call_operator_loc
call_operator = [{ "." => :dot, "&." => :anddot, "::" => "::" }.fetch(call_operator_loc.slice), srange(call_operator_loc)] if call_operator_loc
visit_block(
if name.end_with?("=") && !message_loc.slice.end_with?("=") && node.arguments && block.nil?
builder.assign(
builder.attr_asgn(visit(node.receiver), call_operator, token(message_loc)),
srange_find(message_loc.end_offset, node.arguments.location.start_offset, "="),
visit(node.arguments.arguments.last)
)
else
builder.call_method(
visit(node.receiver),
call_operator,
message_loc ? [node.name, srange(message_loc)] : nil,
token(node.opening_loc),
visit_all(arguments),
token(node.closing_loc)
)
end,
block
)
end foo ^^^
foo.bar ^^^^^^^
foo.bar() {} ^^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 333
def visit_call_operator_write_node(node)
call_operator_loc = node.call_operator_loc
builder.op_assign(
builder.call_method(
visit(node.receiver),
call_operator_loc.nil? ? nil : [{ "." => :dot, "&." => :anddot, "::" => "::" }.fetch(call_operator_loc.slice), srange(call_operator_loc)],
node.message_loc ? [node.read_name, srange(node.message_loc)] : nil,
nil,
[],
nil
),
[node.binary_operator_loc.slice.chomp("="), srange(node.binary_operator_loc)],
visit(node.value)
)
end foo.bar += baz ^^^^^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 371
def visit_call_or_write_node(node)
call_operator_loc = node.call_operator_loc
builder.op_assign(
builder.call_method(
visit(node.receiver),
call_operator_loc.nil? ? nil : [{ "." => :dot, "&." => :anddot, "::" => "::" }.fetch(call_operator_loc.slice), srange(call_operator_loc)],
node.message_loc ? [node.read_name, srange(node.message_loc)] : nil,
nil,
[],
nil
),
[node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
visit(node.value)
)
end foo.bar ||= baz ^^^^^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 390
def visit_call_target_node(node)
call_operator_loc = node.call_operator_loc
builder.attr_asgn(
visit(node.receiver),
call_operator_loc.nil? ? nil : [{ "." => :dot, "&." => :anddot, "::" => "::" }.fetch(call_operator_loc.slice), srange(call_operator_loc)],
token(node.message_loc)
)
end foo.bar, = 1 ^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 402 def visit_capture_pattern_node(node) builder.match_as(visit(node.value), token(node.operator_loc), visit(node.target)) end
foo => bar => baz
^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 421
def visit_case_match_node(node)
builder.case_match(
token(node.case_keyword_loc),
visit(node.predicate),
visit_all(node.conditions),
token(node.else_clause&.else_keyword_loc),
visit(node.else_clause),
token(node.end_keyword_loc)
)
end case foo; in bar; end ^^^^^^^^^^^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 408
def visit_case_node(node)
builder.case(
token(node.case_keyword_loc),
visit(node.predicate),
visit_all(node.conditions),
token(node.else_clause&.else_keyword_loc),
visit(node.else_clause),
token(node.end_keyword_loc)
)
end case foo; when bar; end ^^^^^^^^^^^^^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 434
def visit_class_node(node)
builder.def_class(
token(node.class_keyword_loc),
visit(node.constant_path),
token(node.inheritance_operator_loc),
visit(node.superclass),
node.body&.accept(copy_compiler(forwarding: [])),
token(node.end_keyword_loc)
)
end class Foo; end ^^^^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 473
def visit_class_variable_and_write_node(node)
builder.op_assign(
builder.assignable(builder.cvar(token(node.name_loc))),
[node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
visit(node.value)
)
end @@foo &&= bar ^^^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 463
def visit_class_variable_operator_write_node(node)
builder.op_assign(
builder.assignable(builder.cvar(token(node.name_loc))),
[node.binary_operator_loc.slice.chomp("="), srange(node.binary_operator_loc)],
visit(node.value)
)
end @@foo += bar ^^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 483
def visit_class_variable_or_write_node(node)
builder.op_assign(
builder.assignable(builder.cvar(token(node.name_loc))),
[node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
visit(node.value)
)
end @@foo ||= bar ^^^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 447 def visit_class_variable_read_node(node) builder.cvar(token(node.location)) end
@@foo ^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 493 def visit_class_variable_target_node(node) builder.assignable(builder.cvar(token(node.location))) end
@@foo, = bar ^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 453
def visit_class_variable_write_node(node)
builder.assign(
builder.assignable(builder.cvar(token(node.name_loc))),
token(node.operator_loc),
visit(node.value)
)
end @@foo = 1 ^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 524
def visit_constant_and_write_node(node)
builder.op_assign(
builder.assignable(builder.const([node.name, srange(node.name_loc)])),
[node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
visit(node.value)
)
end Foo &&= bar ^^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 514
def visit_constant_operator_write_node(node)
builder.op_assign(
builder.assignable(builder.const([node.name, srange(node.name_loc)])),
[node.binary_operator_loc.slice.chomp("="), srange(node.binary_operator_loc)],
visit(node.value)
)
end Foo += bar ^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 534
def visit_constant_or_write_node(node)
builder.op_assign(
builder.assignable(builder.const([node.name, srange(node.name_loc)])),
[node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
visit(node.value)
)
end Foo ||= bar ^^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 590
def visit_constant_path_and_write_node(node)
builder.op_assign(
builder.assignable(visit(node.target)),
[node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
visit(node.value)
)
end Foo::Bar &&= baz ^^^^^^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 550
def visit_constant_path_node(node)
if node.parent.nil?
builder.const_global(
token(node.delimiter_loc),
[node.name, srange(node.name_loc)]
)
else
builder.const_fetch(
visit(node.parent),
token(node.delimiter_loc),
[node.name, srange(node.name_loc)]
)
end
end Foo::Bar ^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 580
def visit_constant_path_operator_write_node(node)
builder.op_assign(
builder.assignable(visit(node.target)),
[node.binary_operator_loc.slice.chomp("="), srange(node.binary_operator_loc)],
visit(node.value)
)
end Foo::Bar += baz ^^^^^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 600
def visit_constant_path_or_write_node(node)
builder.op_assign(
builder.assignable(visit(node.target)),
[node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
visit(node.value)
)
end Foo::Bar ||= baz ^^^^^^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 610 def visit_constant_path_target_node(node) builder.assignable(visit_constant_path_node(node)) end
Foo::Bar, = baz ^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 570
def visit_constant_path_write_node(node)
builder.assign(
builder.assignable(visit(node.target)),
token(node.operator_loc),
visit(node.value)
)
end Foo::Bar = 1 ^^^^^^^^^^^^
Foo::Foo, Bar::Bar = 1 ^^^^^^^^ ^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 499 def visit_constant_read_node(node) builder.const([node.name, srange(node.location)]) end
Foo ^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 544 def visit_constant_target_node(node) builder.assignable(builder.const([node.name, srange(node.location)])) end
Foo, = bar ^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 508 def visit_constant_write_node(node) builder.assign(builder.assignable(builder.const([node.name, srange(node.name_loc)])), token(node.operator_loc), visit(node.value)) end
Foo = 1 ^^^^^^^
Foo, Bar = 1 ^^^ ^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 619
def visit_def_node(node)
if node.equal_loc
if node.receiver
builder.def_endless_singleton(
token(node.def_keyword_loc),
visit(node.receiver.is_a?(ParenthesesNode) ? node.receiver.body : node.receiver),
token(node.operator_loc),
token(node.name_loc),
builder.args(token(node.lparen_loc), visit(node.parameters) || [], token(node.rparen_loc), false),
token(node.equal_loc),
node.body&.accept(copy_compiler(forwarding: find_forwarding(node.parameters)))
)
else
builder.def_endless_method(
token(node.def_keyword_loc),
token(node.name_loc),
builder.args(token(node.lparen_loc), visit(node.parameters) || [], token(node.rparen_loc), false),
token(node.equal_loc),
node.body&.accept(copy_compiler(forwarding: find_forwarding(node.parameters)))
)
end
elsif node.receiver
builder.def_singleton(
token(node.def_keyword_loc),
visit(node.receiver.is_a?(ParenthesesNode) ? node.receiver.body : node.receiver),
token(node.operator_loc),
token(node.name_loc),
builder.args(token(node.lparen_loc), visit(node.parameters) || [], token(node.rparen_loc), false),
node.body&.accept(copy_compiler(forwarding: find_forwarding(node.parameters))),
token(node.end_keyword_loc)
)
else
builder.def_method(
token(node.def_keyword_loc),
token(node.name_loc),
builder.args(token(node.lparen_loc), visit(node.parameters) || [], token(node.rparen_loc), false),
node.body&.accept(copy_compiler(forwarding: find_forwarding(node.parameters))),
token(node.end_keyword_loc)
)
end
end def foo; end ^^^^^^^^^^^^
def self.foo; end ^^^^^^^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 666
def visit_defined_node(node)
builder.keyword_cmd(
:defined?,
token(node.keyword_loc),
token(node.lparen_loc),
[visit(node.value)],
token(node.rparen_loc)
)
end defined? a ^^^^^^^^^^
defined?(a) ^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 678 def visit_else_node(node) visit(node.statements) end
if foo then bar else baz end
^^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 684
def visit_embedded_statements_node(node)
builder.begin(
token(node.opening_loc),
visit(node.statements),
token(node.closing_loc)
)
end “foo #{bar}”
^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 694 def visit_embedded_variable_node(node) visit(node.variable) end
“foo #@bar”
^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 700 def visit_ensure_node(node) raise CompilationError, "Cannot directly compile ensure nodes" end
begin; foo; ensure; bar; end
^^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 706 def visit_false_node(node) builder.false(token(node.location)) end
false ^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 712
def visit_find_pattern_node(node)
elements = [node.left, *node.requireds, node.right]
if node.constant
builder.const_pattern(visit(node.constant), token(node.opening_loc), builder.find_pattern(nil, visit_all(elements), nil), token(node.closing_loc))
else
builder.find_pattern(token(node.opening_loc), visit_all(elements), token(node.closing_loc))
end
end foo => [*, bar, *]
^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 724 def visit_float_node(node) visit_numeric(node, builder.float([node.value, srange(node.location)])) end
1.0 ^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 730
def visit_for_node(node)
builder.for(
token(node.for_keyword_loc),
visit(node.index),
token(node.in_keyword_loc),
visit(node.collection),
if (do_keyword_loc = node.do_keyword_loc)
token(do_keyword_loc)
else
srange_find(node.collection.location.end_offset, (node.statements&.location || node.end_keyword_loc).start_offset, ";")
end,
visit(node.statements),
token(node.end_keyword_loc)
)
end для foo в bar делаем end ^^^^^^^^^^^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 748 def visit_forwarding_arguments_node(node) builder.forwarded_args(token(node.location)) end
определить foo(…); bar(…); end
^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 754 def visit_forwarding_parameter_node(node) builder.forward_arg(token(node.location)) end
определить foo(…); end
^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 763
def visit_forwarding_super_node(node)
visit_block(
builder.keyword_cmd(
:zsuper,
["super", srange_offsets(node.location.start_offset, node.location.start_offset + 5)]
),
node.block
)
end супер ^^^^^
супер {} ^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 801
def visit_global_variable_and_write_node(node)
builder.op_assign(
builder.assignable(builder.gvar(token(node.name_loc))),
[node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
visit(node.value)
)
end $foo &&= bar ^^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 791
def visit_global_variable_operator_write_node(node)
builder.op_assign(
builder.assignable(builder.gvar(token(node.name_loc))),
[node.binary_operator_loc.slice.chomp("="), srange(node.binary_operator_loc)],
visit(node.value)
)
end $foo += bar ^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 811
def visit_global_variable_or_write_node(node)
builder.op_assign(
builder.assignable(builder.gvar(token(node.name_loc))),
[node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
visit(node.value)
)
end $foo ||= bar ^^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 775 def visit_global_variable_read_node(node) builder.gvar(token(node.location)) end
$foo ^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 821 def visit_global_variable_target_node(node) builder.assignable(builder.gvar([node.slice, srange(node.location)])) end
$foo, = bar ^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 781
def visit_global_variable_write_node(node)
builder.assign(
builder.assignable(builder.gvar(token(node.name_loc))),
token(node.operator_loc),
visit(node.value)
)
end $foo = 1 ^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 827
def visit_hash_node(node)
builder.associate(
token(node.opening_loc),
visit_all(node.elements),
token(node.closing_loc)
)
end {} ^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 837
def visit_hash_pattern_node(node)
elements = [*node.elements, *node.rest]
if node.constant
builder.const_pattern(visit(node.constant), token(node.opening_loc), builder.hash_pattern(nil, visit_all(elements), nil), token(node.closing_loc))
else
builder.hash_pattern(token(node.opening_loc), visit_all(elements), token(node.closing_loc))
end
end foo => {}
^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 855
def visit_if_node(node)
if !node.if_keyword_loc
builder.ternary(
visit(node.predicate),
token(node.then_keyword_loc),
visit(node.statements),
token(node.subsequent.else_keyword_loc),
visit(node.subsequent)
)
elsif node.if_keyword_loc.start_offset == node.location.start_offset
builder.condition(
token(node.if_keyword_loc),
visit(node.predicate),
if (then_keyword_loc = node.then_keyword_loc)
token(then_keyword_loc)
else
srange_find(node.predicate.location.end_offset, (node.statements&.location || node.subsequent&.location || node.end_keyword_loc).start_offset, ";")
end,
visit(node.statements),
case node.subsequent
when IfNode
token(node.subsequent.if_keyword_loc)
when ElseNode
token(node.subsequent.else_keyword_loc)
end,
visit(node.subsequent),
if node.if_keyword != "elsif"
token(node.end_keyword_loc)
end
)
else
builder.condition_mod(
visit(node.statements),
visit(node.subsequent),
token(node.if_keyword_loc),
visit(node.predicate)
)
end
end если foo, то bar end ^^^^^^^^^^^^^^^^^^^
bar, если foo ^^^^^^^^^^
foo ? bar : baz ^^^^^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 897 def visit_imaginary_node(node) visit_numeric(node, builder.complex([Complex(0, node.numeric.value), srange(node.location)])) end
1i ^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 903 def visit_implicit_node(node) raise CompilationError, "Cannot directly compile implicit nodes" end
{ foo: }
^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 909 def visit_implicit_rest_node(node) raise CompilationError, "Cannot compile implicit rest nodes" end
foo { |bar,| }
^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 915
def visit_in_node(node)
pattern = nil
guard = nil
case node.pattern
when IfNode
pattern = within_pattern { |compiler| node.pattern.statements.accept(compiler) }
guard = builder.if_guard(token(node.pattern.if_keyword_loc), visit(node.pattern.predicate))
when UnlessNode
pattern = within_pattern { |compiler| node.pattern.statements.accept(compiler) }
guard = builder.unless_guard(token(node.pattern.keyword_loc), visit(node.pattern.predicate))
else
pattern = within_pattern { |compiler| node.pattern.accept(compiler) }
end
builder.in_pattern(
token(node.in_loc),
pattern,
guard,
if (then_loc = node.then_loc)
token(then_loc)
else
srange_find(node.pattern.location.end_offset, node.statements&.location&.start_offset, ";")
end,
visit(node.statements)
)
end в зависимости от foo; в bar; end ^^^^^^^^^^^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 963
def visit_index_and_write_node(node)
arguments = node.arguments&.arguments || []
arguments << node.block if node.block
builder.op_assign(
builder.index(
visit(node.receiver),
token(node.opening_loc),
visit_all(arguments),
token(node.closing_loc)
),
[node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
visit(node.value)
)
end foo &&= baz ^^^^^^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 945
def visit_index_operator_write_node(node)
arguments = node.arguments&.arguments || []
arguments << node.block if node.block
builder.op_assign(
builder.index(
visit(node.receiver),
token(node.opening_loc),
visit_all(arguments),
token(node.closing_loc)
),
[node.binary_operator_loc.slice.chomp("="), srange(node.binary_operator_loc)],
visit(node.value)
)
end foo += baz ^^^^^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 981
def visit_index_or_write_node(node)
arguments = node.arguments&.arguments || []
arguments << node.block if node.block
builder.op_assign(
builder.index(
visit(node.receiver),
token(node.opening_loc),
visit_all(arguments),
token(node.closing_loc)
),
[node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
visit(node.value)
)
end foo ||= baz ^^^^^^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 999
def visit_index_target_node(node)
builder.index_asgn(
visit(node.receiver),
token(node.opening_loc),
visit_all(node.arguments.arguments),
token(node.closing_loc),
)
end foo, = 1 ^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1036
def visit_instance_variable_and_write_node(node)
builder.op_assign(
builder.assignable(builder.ivar(token(node.name_loc))),
[node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
visit(node.value)
)
end @foo &&= bar ^^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1026
def visit_instance_variable_operator_write_node(node)
builder.op_assign(
builder.assignable(builder.ivar(token(node.name_loc))),
[node.binary_operator_loc.slice.chomp("="), srange(node.binary_operator_loc)],
visit(node.value)
)
end @foo += bar ^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1046
def visit_instance_variable_or_write_node(node)
builder.op_assign(
builder.assignable(builder.ivar(token(node.name_loc))),
[node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
visit(node.value)
)
end @foo ||= bar ^^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1010 def visit_instance_variable_read_node(node) builder.ivar(token(node.location)) end
@foo ^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1056 def visit_instance_variable_target_node(node) builder.assignable(builder.ivar(token(node.location))) end
@foo, = bar ^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1016
def visit_instance_variable_write_node(node)
builder.assign(
builder.assignable(builder.ivar(token(node.name_loc))),
token(node.operator_loc),
visit(node.value)
)
end @foo = 1 ^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1062 def visit_integer_node(node) visit_numeric(node, builder.integer([node.value, srange(node.location)])) end
1 ^
if /foo #{bar}/ then end
^^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1068
def visit_interpolated_regular_expression_node(node)
builder.regexp_compose(
token(node.opening_loc),
visit_all(node.parts),
[node.closing[0], srange_offsets(node.closing_loc.start_offset, node.closing_loc.start_offset + 1)],
builder.regexp_options([node.closing[1..], srange_offsets(node.closing_loc.start_offset + 1, node.closing_loc.end_offset)])
)
end /foo #{bar}/ ^^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1083
def visit_interpolated_string_node(node)
if node.heredoc?
return visit_heredoc(node) { |children, closing| builder.string_compose(token(node.opening_loc), children, closing) }
end
parts = if node.parts.one? { |part| part.type == :string_node }
node.parts.flat_map do |node|
if node.type == :string_node && node.unescaped.lines.count >= 2
start_offset = node.content_loc.start_offset
node.unescaped.lines.map do |line|
end_offset = start_offset + line.length
offsets = srange_offsets(start_offset, end_offset)
start_offset = end_offset
builder.string_internal([line, offsets])
end
else
visit(node)
end
end
else
visit_all(node.parts)
end
builder.string_compose(
token(node.opening_loc),
parts,
token(node.closing_loc)
)
end “foo #{bar}” ^^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1117
def visit_interpolated_symbol_node(node)
builder.symbol_compose(
token(node.opening_loc),
visit_all(node.parts),
token(node.closing_loc)
)
end :“foo #{bar}” ^^^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1127
def visit_interpolated_x_string_node(node)
if node.heredoc?
visit_heredoc(node) { |children, closing| builder.xstring_compose(token(node.opening_loc), children, closing) }
else
builder.xstring_compose(
token(node.opening_loc),
visit_all(node.parts),
token(node.closing_loc)
)
end
end ‘foo #{bar}` ^^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1141 def visit_it_local_variable_read_node(node) builder.ident([:it, srange(node.location)]).updated(:lvar) end
-> { it }
^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1147 def visit_it_parameters_node(node) builder.args(nil, [], nil, false) end
-> { it } ^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1153 def visit_keyword_hash_node(node) builder.associate(nil, visit_all(node.elements), nil) end
foo(bar: baz)
^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1162
def visit_keyword_rest_parameter_node(node)
builder.kwrestarg(
token(node.operator_loc),
node.name ? [node.name, srange(node.name_loc)] : nil
)
end def foo(**bar); end
^^^^^
def foo(**); end
^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1171
def visit_lambda_node(node)
parameters = node.parameters
implicit_parameters = parameters.is_a?(NumberedParametersNode) || parameters.is_a?(ItParametersNode)
builder.block(
builder.call_lambda(token(node.operator_loc)),
[node.opening, srange(node.opening_loc)],
if parameters.nil?
builder.args(nil, [], nil, false)
elsif implicit_parameters
visit(node.parameters)
else
builder.args(
token(node.parameters.opening_loc),
visit(node.parameters),
token(node.parameters.closing_loc),
false
)
end,
node.body&.accept(copy_compiler(forwarding: implicit_parameters ? [] : find_forwarding(parameters&.parameters))),
[node.closing, srange(node.closing_loc)]
)
end -> {} ^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1223
def visit_local_variable_and_write_node(node)
builder.op_assign(
builder.assignable(builder.ident(token(node.name_loc))),
[node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
visit(node.value)
)
end foo &&= bar ^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1213
def visit_local_variable_operator_write_node(node)
builder.op_assign(
builder.assignable(builder.ident(token(node.name_loc))),
[node.binary_operator_loc.slice.chomp("="), srange(node.binary_operator_loc)],
visit(node.value)
)
end foo += bar ^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1233
def visit_local_variable_or_write_node(node)
builder.op_assign(
builder.assignable(builder.ident(token(node.name_loc))),
[node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
visit(node.value)
)
end foo ||= bar ^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1197 def visit_local_variable_read_node(node) builder.ident([node.name, srange(node.location)]).updated(:lvar) end
foo ^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1243
def visit_local_variable_target_node(node)
if in_pattern
builder.assignable(builder.match_var([node.name, srange(node.location)]))
else
builder.assignable(builder.ident(token(node.location)))
end
end foo, = bar ^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1203
def visit_local_variable_write_node(node)
builder.assign(
builder.assignable(builder.ident(token(node.name_loc))),
token(node.operator_loc),
visit(node.value)
)
end foo = 1 ^^^^^^^
if /foo/ then end
^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1253
def visit_match_predicate_node(node)
builder.match_pattern_p(
visit(node.value),
token(node.operator_loc),
within_pattern { |compiler| node.pattern.accept(compiler) }
)
end foo in bar ^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1263
def visit_match_required_node(node)
builder.match_pattern(
visit(node.value),
token(node.operator_loc),
within_pattern { |compiler| node.pattern.accept(compiler) }
)
end foo => bar ^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1273
def visit_match_write_node(node)
builder.match_op(
visit(node.call.receiver),
token(node.call.message_loc),
visit(node.call.arguments.arguments.first)
)
end /(?<foo>foo)/ =~ bar ^^^^^^^^^^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1284 def visit_missing_node(node) ::AST::Node.new(:missing, [], location: ::Parser::Source::Map.new(srange(node.location))) end
Узел, отсутствующий в синтаксическом дереве. Используется только в случае синтаксической ошибки. В бибилиотеке парсера такой концепции нет, поэтому мы её придумали.
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1290
def visit_module_node(node)
builder.def_module(
token(node.module_keyword_loc),
visit(node.constant_path),
node.body&.accept(copy_compiler(forwarding: [])),
token(node.end_keyword_loc)
)
end module Foo; end ^^^^^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1301
def visit_multi_target_node(node)
builder.multi_lhs(
token(node.lparen_loc),
visit_all(multi_target_elements(node)),
token(node.rparen_loc)
)
end foo, bar = baz ^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1311
def visit_multi_write_node(node)
elements = multi_target_elements(node)
if elements.length == 1 && elements.first.is_a?(MultiTargetNode)
elements = multi_target_elements(elements.first)
end
builder.multi_assign(
builder.multi_lhs(
token(node.lparen_loc),
visit_all(elements),
token(node.rparen_loc)
),
token(node.operator_loc),
visit(node.value)
)
end foo, bar = baz ^^^^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1334
def visit_next_node(node)
builder.keyword_cmd(
:next,
token(node.keyword_loc),
nil,
visit(node.arguments) || [],
nil
)
end next ^^^^
next foo ^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1346 def visit_nil_node(node) builder.nil(token(node.location)) end
nil ^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1352
def visit_no_keywords_parameter_node(node)
if in_pattern
builder.match_nil_pattern(token(node.operator_loc), token(node.keyword_loc))
else
builder.kwnilarg(token(node.operator_loc), token(node.keyword_loc))
end
end def foo(**nil); end
^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1362 def visit_numbered_parameters_node(node) builder.numargs(node.maximum) end
-> { _1 + _2 } ^^^^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1368 def visit_numbered_reference_read_node(node) builder.nth_ref([node.number, srange(node.location)]) end
$1 ^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1374 def visit_optional_keyword_parameter_node(node) builder.kwoptarg([node.name, srange(node.name_loc)], visit(node.value)) end
def foo(bar: baz); end
^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1380 def visit_optional_parameter_node(node) builder.optarg(token(node.name_loc), token(node.operator_loc), visit(node.value)) end
def foo(bar = 1); end
^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1386 def visit_or_node(node) builder.logical_op(:or, visit(node.left), token(node.operator_loc), visit(node.right)) end
a or b ^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1392
def visit_parameters_node(node)
params = []
if node.requireds.any?
node.requireds.each do |required|
params <<
if required.is_a?(RequiredParameterNode)
visit(required)
else
required.accept(copy_compiler(in_destructure: true))
end
end
end
params.concat(visit_all(node.optionals)) if node.optionals.any?
params << visit(node.rest) if !node.rest.nil? && !node.rest.is_a?(ImplicitRestNode)
if node.posts.any?
node.posts.each do |post|
params <<
if post.is_a?(RequiredParameterNode)
visit(post)
else
post.accept(copy_compiler(in_destructure: true))
end
end
end
params.concat(visit_all(node.keywords)) if node.keywords.any?
params << visit(node.keyword_rest) if !node.keyword_rest.nil?
params << visit(node.block) if !node.block.nil?
params
end def foo(bar, *baz); end
^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1431
def visit_parentheses_node(node)
builder.begin(
token(node.opening_loc),
visit(node.body),
token(node.closing_loc)
)
end () ^^
(1) ^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1441 def visit_pinned_expression_node(node) expression = builder.begin(token(node.lparen_loc), visit(node.expression), token(node.rparen_loc)) builder.pin(token(node.operator_loc), expression) end
foo => ^(bar)
^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1448 def visit_pinned_variable_node(node) builder.pin(token(node.operator_loc), visit(node.variable)) end
foo = 1 and bar => ^foo
^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1453
def visit_post_execution_node(node)
builder.postexe(
token(node.keyword_loc),
token(node.opening_loc),
visit(node.statements),
token(node.closing_loc)
)
end END {}
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1463
def visit_pre_execution_node(node)
builder.preexe(
token(node.keyword_loc),
token(node.opening_loc),
visit(node.statements),
token(node.closing_loc)
)
end BEGIN {}
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1473 def visit_program_node(node) visit(node.statements) end
Узел программы верхнего уровня.
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1479
def visit_range_node(node)
if node.exclude_end?
builder.range_exclusive(
visit(node.left),
token(node.operator_loc),
visit(node.right)
)
else
builder.range_inclusive(
visit(node.left),
token(node.operator_loc),
visit(node.right)
)
end
end 0..5 ^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1501 def visit_rational_node(node) visit_numeric(node, builder.rational([node.value, srange(node.location)])) end
1r ^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1507 def visit_redo_node(node) builder.keyword_cmd(:redo, token(node.location)) end
redo ^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1513
def visit_regular_expression_node(node)
content = node.content
parts =
if content.include?("\n")
offset = node.content_loc.start_offset
content.lines.map do |line|
builder.string_internal([line, srange_offsets(offset, offset += line.bytesize)])
end
else
[builder.string_internal(token(node.content_loc))]
end
builder.regexp_compose(
token(node.opening_loc),
parts,
[node.closing[0], srange_offsets(node.closing_loc.start_offset, node.closing_loc.start_offset + 1)],
builder.regexp_options([node.closing[1..], srange_offsets(node.closing_loc.start_offset + 1, node.closing_loc.end_offset)])
)
end /foo/ ^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1539 def visit_required_keyword_parameter_node(node) builder.kwarg([node.name, srange(node.name_loc)]) end
def foo(bar:); end
^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1545 def visit_required_parameter_node(node) builder.arg(token(node.location)) end
def foo(bar); end
^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1551
def visit_rescue_modifier_node(node)
builder.begin_body(
visit(node.expression),
[
builder.rescue_body(
token(node.keyword_loc),
nil,
nil,
nil,
nil,
visit(node.rescue_expression)
)
]
)
end foo rescue bar ^^^^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1569 def visit_rescue_node(node) raise CompilationError, "Cannot directly compile rescue nodes" end
begin; rescue; end
^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1578 def visit_rest_parameter_node(node) builder.restarg(token(node.operator_loc), token(node.name_loc)) end
def foo(*bar); end
^^^^
def foo(*); end
^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1584 def visit_retry_node(node) builder.keyword_cmd(:retry, token(node.location)) end
retry ^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1593
def visit_return_node(node)
builder.keyword_cmd(
:return,
token(node.keyword_loc),
nil,
visit(node.arguments) || [],
nil
)
end return ^^^^^^
return 1 ^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1605 def visit_self_node(node) builder.self(token(node.location)) end
self ^^^^
Исходный код
Постоянная величина, которая может быть разделена.
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1616
def visit_singleton_class_node(node)
builder.def_sclass(
token(node.class_keyword_loc),
token(node.operator_loc),
visit(node.expression),
node.body&.accept(copy_compiler(forwarding: [])),
token(node.end_keyword_loc)
)
end class << self; end ^^^^^^^^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1628 def visit_source_encoding_node(node) builder.accessible(builder.__ENCODING__(token(node.location))) end
__ENCODING__ ^^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1634 def visit_source_file_node(node) builder.accessible(builder.__FILE__(token(node.location))) end
__FILE__ ^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1640 def visit_source_line_node(node) builder.accessible(builder.__LINE__(token(node.location))) end
__LINE__ ^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1652
def visit_splat_node(node)
if node.expression.nil? && forwarding.include?(:*)
builder.forwarded_restarg(token(node.operator_loc))
elsif in_destructure
builder.restarg(token(node.operator_loc), token(node.expression&.location))
elsif in_pattern
builder.match_rest(token(node.operator_loc), token(node.expression&.location))
else
builder.splat(token(node.operator_loc), visit(node.expression))
end
end foo(*bar)
^^^^
def foo((bar, *baz)); end
^^^^
def foo(*); bar(*); end
^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1665 def visit_statements_node(node) builder.compstmt(visit_all(node.body)) end
Список инструкций.
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1671
def visit_string_node(node)
if node.heredoc?
visit_heredoc(node.to_interpolated) { |children, closing| builder.string_compose(token(node.opening_loc), children, closing) }
elsif node.opening == "?"
builder.character([node.unescaped, srange(node.location)])
elsif node.opening&.start_with?("%") && node.unescaped.empty?
builder.string_compose(token(node.opening_loc), [], token(node.closing_loc))
else
content_lines = node.content.lines
unescaped_lines = node.unescaped.lines
parts =
if content_lines.length <= 1 || unescaped_lines.length <= 1
[builder.string_internal([node.unescaped, srange(node.content_loc)])]
elsif content_lines.length != unescaped_lines.length
# This occurs when we have line continuations in the string. We
# need to come back and fix this, but for now this stops the
# code from breaking when we encounter it because of trying to
# transpose arrays of different lengths.
[builder.string_internal([node.unescaped, srange(node.content_loc)])]
else
start_offset = node.content_loc.start_offset
[content_lines, unescaped_lines].transpose.map do |content_line, unescaped_line|
end_offset = start_offset + content_line.length
offsets = srange_offsets(start_offset, end_offset)
start_offset = end_offset
builder.string_internal([unescaped_line, offsets])
end
end
builder.string_compose(
token(node.opening_loc),
parts,
token(node.closing_loc)
)
end
end “foo” ^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1713
def visit_super_node(node)
arguments = node.arguments&.arguments || []
block = node.block
if block.is_a?(BlockArgumentNode)
arguments = [*arguments, block]
block = nil
end
visit_block(
builder.keyword_cmd(
:super,
token(node.keyword_loc),
token(node.lparen_loc),
visit_all(arguments),
token(node.rparen_loc)
),
block
)
end super(foo) ^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1736
def visit_symbol_node(node)
if node.closing_loc.nil?
if node.opening_loc.nil?
builder.symbol_internal([node.unescaped, srange(node.location)])
else
builder.symbol([node.unescaped, srange(node.location)])
end
else
parts = if node.value.lines.one?
[builder.string_internal([node.unescaped, srange(node.value_loc)])]
else
start_offset = node.value_loc.start_offset
node.value.lines.map do |line|
end_offset = start_offset + line.length
offsets = srange_offsets(start_offset, end_offset)
start_offset = end_offset
builder.string_internal([line, offsets])
end
end
builder.symbol_compose(
token(node.opening_loc),
parts,
token(node.closing_loc)
)
end
end :foo ^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1768 def visit_true_node(node) builder.true(token(node.location)) end
истина ^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1774 def visit_undef_node(node) builder.undef_method(token(node.keyword_loc), visit_all(node.names)) end
undef foo ^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1783
def visit_unless_node(node)
if node.keyword_loc.start_offset == node.location.start_offset
builder.condition(
token(node.keyword_loc),
visit(node.predicate),
if (then_keyword_loc = node.then_keyword_loc)
token(then_keyword_loc)
else
srange_find(node.predicate.location.end_offset, (node.statements&.location || node.else_clause&.location || node.end_keyword_loc).start_offset, ";")
end,
visit(node.else_clause),
token(node.else_clause&.else_keyword_loc),
visit(node.statements),
token(node.end_keyword_loc)
)
else
builder.condition_mod(
visit(node.else_clause),
visit(node.statements),
token(node.keyword_loc),
visit(node.predicate)
)
end
end unless foo; bar end ^^^^^^^^^^^^^^^^^^^
bar если не foo ^^^^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1813
def visit_until_node(node)
if node.location.start_offset == node.keyword_loc.start_offset
builder.loop(
:until,
token(node.keyword_loc),
visit(node.predicate),
if (do_keyword_loc = node.do_keyword_loc)
token(do_keyword_loc)
else
srange_find(node.predicate.location.end_offset, (node.statements&.location || node.closing_loc).start_offset, ";")
end,
visit(node.statements),
token(node.closing_loc)
)
else
builder.loop_mod(
:until,
visit(node.statements),
token(node.keyword_loc),
visit(node.predicate)
)
end
end until foo; bar end ^^^^^^^^^^^^^^^^^^
bar пока не foo ^^^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1839
def visit_when_node(node)
builder.when(
token(node.keyword_loc),
visit_all(node.conditions),
if (then_keyword_loc = node.then_keyword_loc)
token(then_keyword_loc)
else
srange_find(node.conditions.last.location.end_offset, node.statements&.location&.start_offset, ";")
end,
visit(node.statements)
)
end case foo; when bar; end
^^^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1857
def visit_while_node(node)
if node.location.start_offset == node.keyword_loc.start_offset
builder.loop(
:while,
token(node.keyword_loc),
visit(node.predicate),
if (do_keyword_loc = node.do_keyword_loc)
token(do_keyword_loc)
else
srange_find(node.predicate.location.end_offset, (node.statements&.location || node.closing_loc).start_offset, ";")
end,
visit(node.statements),
token(node.closing_loc)
)
else
builder.loop_mod(
:while,
visit(node.statements),
token(node.keyword_loc),
visit(node.predicate)
)
end
end while foo; bar end ^^^^^^^^^^^^^^^^^^
bar пока foo ^^^^^^^^^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1883
def visit_x_string_node(node)
if node.heredoc?
visit_heredoc(node.to_interpolated) { |children, closing| builder.xstring_compose(token(node.opening_loc), children, closing) }
else
parts = if node.unescaped.lines.one?
[builder.string_internal([node.unescaped, srange(node.content_loc)])]
else
start_offset = node.content_loc.start_offset
node.unescaped.lines.map do |line|
end_offset = start_offset + line.length
offsets = srange_offsets(start_offset, end_offset)
start_offset = end_offset
builder.string_internal([line, offsets])
end
end
builder.xstring_compose(
token(node.opening_loc),
parts,
token(node.closing_loc)
)
end
end ‘foo` ^^^^^
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1914
def visit_yield_node(node)
builder.keyword_cmd(
:yield,
token(node.keyword_loc),
token(node.lparen_loc),
visit(node.arguments) || [],
token(node.rparen_loc)
)
end yield ^^^^^
yield 1 ^^^^^^^
Методы частного экземпляра
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 2055 def chomped_bytesize(line) chomped = line.chomp chomped.bytesize + (chomped == line ? 0 : 1) end
Модуль парсера автоматически преобразует rn в n, поэтому наши смещения должны всегда уменьшаться на 1 от длины.
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1928 def copy_compiler(forwarding: self.forwarding, in_destructure: self.in_destructure, in_pattern: self.in_pattern) Compiler.new(parser, offset_cache, forwarding: forwarding, in_destructure: in_destructure, in_pattern: in_pattern) end
Инициализирует новый компилятор с заданными переопределениями параметров, используемыми для посещения поддерева с заданными параметрами.
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1935 def find_forwarding(node) return [] if node.nil? forwarding = [] forwarding << :* if node.rest.is_a?(RestParameterNode) && node.rest.name.nil? forwarding << :** if node.keyword_rest.is_a?(KeywordRestParameterNode) && node.keyword_rest.name.nil? forwarding << :& if !node.block.nil? && node.block.name.nil? forwarding |= [:&, :"..."] if node.keyword_rest.is_a?(ForwardingParameterNode) forwarding end
Когда *, **, & или … используются в качестве аргументов в вызове метода, мы проверяем, разрешены ли они текущим контекстом. Для определения этого мы строим эту таблицу поиска.
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1948 def multi_target_elements(node) elements = [*node.lefts] elements << node.rest if !node.rest.nil? && !node.rest.is_a?(ImplicitRestNode) elements.concat(node.rights) elements end
Возвращает набор целей для MultiTargetNode или MultiWriteNode.
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1960
def numeric_negate(message_loc, receiver)
case receiver.type
when :integer_node, :float_node
receiver.copy(value: -receiver.value, location: message_loc.join(receiver.location))
when :rational_node
receiver.copy(numerator: -receiver.numerator, location: message_loc.join(receiver.location))
when :imaginary_node
receiver.copy(numeric: numeric_negate(message_loc, receiver.numeric), location: message_loc.join(receiver.location))
end
end Изменить знак числового узла. Это особый случай, когда у вас есть знак минус в одной строке, а затем число в следующей. В обычном Ruby это всегда вызов метода. Однако модуль парсера помечает это как числовую литерал. Мы должны изменить структуру, чтобы привести её к правильному виду.
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1974
def procarg0?(parameters)
parameters &&
parameters.requireds.length == 1 &&
parameters.optionals.empty? &&
parameters.rest.nil? &&
parameters.posts.empty? &&
parameters.keywords.empty? &&
parameters.keyword_rest.nil? &&
parameters.block.nil?
end Блоки могут иметь специальный набор параметров, которые автоматически расширяются при передаче массивов, если у них есть один обязательный параметр и нет других.
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1991 def srange(location) Range.new(source_buffer, offset_cache[location.start_offset], offset_cache[location.end_offset]) if location end
Создаёт новый диапазон исходного кода из заданных начальных и конечных смещений.
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 2006
def srange_find(start_offset, end_offset, character)
if (match = source_buffer.source.byteslice(start_offset...end_offset)[/\A\s*#{character}/])
final_offset = start_offset + match.bytesize
[character, Range.new(source_buffer, offset_cache[final_offset - character.bytesize], offset_cache[final_offset])]
end
end Создаёт новый диапазон исходного кода, найдя заданный символ между заданным начальным и конечным смещением. Если искомый элемент не найден, возвращает nil. Важно, что поиск не идёт за пределы символов новой строки или комментариев.
Обратите внимание, что конечное_смещение может быть nil, в этом случае поиск будет продолжаться до конца строки.
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 1996 def srange_offsets(start_offset, end_offset) Range.new(source_buffer, offset_cache[start_offset], offset_cache[end_offset]) end
Создаёт новый диапазон исходного кода из заданных начальных и конечных смещений.
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 2014 def token(location) [location.slice, Range.new(source_buffer, offset_cache[location.start_offset], offset_cache[location.end_offset])] if location end
Преобразует местоположение в токен, ожидаемый модулем парсера.
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 2019
def visit_block(call, block)
if block
parameters = block.parameters
implicit_parameters = parameters.is_a?(NumberedParametersNode) || parameters.is_a?(ItParametersNode)
builder.block(
call,
token(block.opening_loc),
if parameters.nil?
builder.args(nil, [], nil, false)
elsif implicit_parameters
visit(parameters)
else
builder.args(
token(parameters.opening_loc),
if procarg0?(parameters.parameters)
parameter = parameters.parameters.requireds.first
visited = parameter.is_a?(RequiredParameterNode) ? visit(parameter) : parameter.accept(copy_compiler(in_destructure: true))
[builder.procarg0(visited)].concat(visit_all(parameters.locals))
else
visit(parameters)
end,
token(parameters.closing_loc),
false
)
end,
block.body&.accept(copy_compiler(forwarding: implicit_parameters ? [] : find_forwarding(parameters&.parameters))),
token(block.closing_loc)
)
else
call
end
end Посещает узел блока в вызове.
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 2061
def visit_heredoc(node)
children = Array.new
indented = false
# If this is a dedenting heredoc, then we need to insert the opening
# content into the children as well.
if node.opening.start_with?("<<~") && node.parts.length > 0 && !node.parts.first.is_a?(StringNode)
location = node.parts.first.location
location = location.copy(start_offset: location.start_offset - location.start_line_slice.bytesize)
children << builder.string_internal(token(location))
indented = true
end
node.parts.each do |part|
pushing =
if part.is_a?(StringNode) && part.unescaped.include?("\n")
unescaped = part.unescaped.lines
escaped = part.content.lines
escaped_lengths = []
normalized_lengths = []
if node.opening.end_with?("'")
escaped.each do |line|
escaped_lengths << line.bytesize
normalized_lengths << chomped_bytesize(line)
end
else
escaped
.chunk_while { |before, after| before.match?(/(?<!\\)\\\r?\n$/) }
.each do |lines|
escaped_lengths << lines.sum(&:bytesize)
normalized_lengths << lines.sum { |line| chomped_bytesize(line) }
end
end
start_offset = part.location.start_offset
unescaped.map.with_index do |unescaped_line, index|
inner_part = builder.string_internal([unescaped_line, srange_offsets(start_offset, start_offset + normalized_lengths.fetch(index, 0))])
start_offset += escaped_lengths.fetch(index, 0)
inner_part
end
else
[visit(part)]
end
pushing.each do |child|
if child.type == :str && child.children.last == ""
# nothing
elsif child.type == :str && children.last && children.last.type == :str && !children.last.children.first.end_with?("\n")
appendee = children[-1]
location = appendee.loc
location = location.with_expression(location.expression.join(child.loc.expression))
children[-1] = appendee.updated(:str, [appendee.children.first << child.children.first], location: location)
else
children << child
end
end
end
closing = node.closing
closing_t = [closing.chomp, srange_offsets(node.closing_loc.start_offset, node.closing_loc.end_offset - (closing[/\s+$/]&.length || 0))]
composed = yield children, closing_t
composed = composed.updated(nil, children[1..-1]) if indented
composed
end Посещает heredoc, который может быть строкой или xстрокой.
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 2133
def visit_numeric(node, value)
if (slice = node.slice).match?(/^[+-]/)
builder.unary_num(
[slice[0].to_sym, srange_offsets(node.location.start_offset, node.location.start_offset + 1)],
value
)
else
value
end
end Посещает числовой узел и учитывает необязательный знак.
Исходный код
# File lib/prism/translation/parser/compiler.rb, line 2145
def within_pattern
begin
parser.pattern_variables.push
yield copy_compiler(in_pattern: true)
ensure
parser.pattern_variables.pop
end
end Внутри данного блока отслеживаем, что мы находимся внутри шаблона.
Ruby Core © 1993–2024 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.