Class: Prism::Translation::Ripper
| Relationships & Source Files | |
| Namespace Children | |
|
Classes:
| |
| Extension / Inclusion / Inheritance Descendants | |
|
Subclasses:
|
|
| Super Chains via Extension / Inclusion / Inheritance | |
|
Class Chain:
self,
Compiler
|
|
|
Instance Chain:
self,
Compiler
|
|
| Inherits: |
Compiler
|
| Defined in: | lib/prism/translation/ripper.rb, lib/prism/translation/ripper/filter.rb, lib/prism/translation/ripper/lexer.rb, lib/prism/translation/ripper/sexp.rb |
Overview
This class provides a compatibility layer between prism and Ripper. It
functions by parsing the entire tree first and then walking it and
executing each of the Ripper callbacks as it goes. To use this class, you
treat Ripper effectively as you would treat the
Ripper class.
Note that this class will serve the most common use cases, but Ripper's
API is extensive and undocumented. It relies on reporting the state of the
parser at any given time. We do our best to replicate that here, but
because it is a different architecture it is not possible to perfectly
replicate the behavior of Ripper.
The main known difference is that we may omit dispatching some events in some cases. This impacts the following events:
- on_assign_error
- on_comma
- on_ignored_nl
- on_ignored_sp
- on_nl
- on_operator_ambiguous
- on_semicolon
- on_sp
Constant Summary
-
BINARY_OPERATORS =
private
# File 'lib/prism/translation/ripper.rb', line 352
A list of all of the Ruby binary operators.
[ :!=, :!~, :=~, :==, :===, :<=>, :>, :>=, :<, :<=, :&, :|, :^, :>>, :<<, :-, :+, :%, :/, :*, :** ]
-
EVENTS =
# File 'lib/prism/translation/ripper.rb', line 304
This array contains name of all ripper events.
PARSER_EVENTS + SCANNER_EVENTS
-
EXPR_ARG_ANY =
Internal use only
# File 'lib/prism/translation/ripper.rb', line 463EXPR_ARG | EXPR_CMDARG
-
EXPR_BEG_ANY =
Internal use only
# File 'lib/prism/translation/ripper.rb', line 462EXPR_BEG | EXPR_MID | EXPR_CLASS
-
EXPR_END_ANY =
Internal use only
# File 'lib/prism/translation/ripper.rb', line 464EXPR_END | EXPR_ENDARG | EXPR_ENDFN
-
EXPR_NONE =
Internal use only
# File 'lib/prism/translation/ripper.rb', line 4600 -
EXPR_VALUE =
Internal use only
# File 'lib/prism/translation/ripper.rb', line 461EXPR_BEG -
KEYWORDS =
private
# File 'lib/prism/translation/ripper.rb', line 307
A list of all of the Ruby keywords.
[ "alias", "and", "begin", "BEGIN", "break", "case", "class", "def", "defined?", "do", "else", "elsif", "end", "END", "ensure", "false", "for", "if", "in", "module", "next", "nil", "not", "or", "redo", "rescue", "retry", "return", "self", "super", "then", "true", "undef", "unless", "until", "when", "while", "yield", "__ENCODING__", "__FILE__", "__LINE__" ]
-
LEX_STATE_NAMES =
private
Internal use only
# File 'lib/prism/translation/ripper.rb', line 452
Ripper-internal bitflags.
%i[ BEG END ENDARG ENDFN ARG CMDARG MID FNAME DOT CLASS LABEL LABELED FITEM ].map.with_index.to_h { |name, i| [2 ** i, name] }.freeze
-
PARSER_EVENTS =
# File 'lib/prism/translation/ripper.rb', line 298
This array contains name of parser events.
PARSER_EVENT_TABLE.keys
-
PARSER_EVENT_TABLE =
# File 'lib/prism/translation/ripper.rb', line 99
This contains a table of all of the parser events and their corresponding arity.
{ BEGIN: 1, END: 1, alias: 2, alias_error: 2, aref: 2, aref_field: 2, arg_ambiguous: 1, arg_paren: 1, args_add: 2, args_add_block: 2, args_add_star: 2, args_forward: 0, args_new: 0, array: 1, aryptn: 4, assign: 2, assign_error: 2, assoc_new: 2, assoc_splat: 1, assoclist_from_args: 1, bare_assoc_hash: 1, begin: 1, binary: 3, block_var: 2, blockarg: 1, bodystmt: 4, brace_block: 2, break: 1, call: 3, case: 2, class: 3, class_name_error: 2, command: 2, command_call: 4, const_path_field: 2, const_path_ref: 2, const_ref: 1, def: 3, defined: 1, defs: 5, do_block: 2, dot2: 2, dot3: 2, dyna_symbol: 1, else: 1, elsif: 3, ensure: 1, excessed_comma: 0, fcall: 1, field: 3, fndptn: 4, for: 3, hash: 1, heredoc_dedent: 2, hshptn: 3, if: 3, if_mod: 2, ifop: 3, in: 3, kwrest_param: 1, lambda: 2, magic_comment: 2, massign: 2, method_add_arg: 2, method_add_block: 2, mlhs_add: 2, mlhs_add_post: 2, mlhs_add_star: 2, mlhs_new: 0, mlhs_paren: 1, module: 2, mrhs_add: 2, mrhs_add_star: 2, mrhs_new: 0, mrhs_new_from_args: 1, next: 1, nokw_param: 1, opassign: 3, operator_ambiguous: 2, param_error: 2, params: 7, paren: 1, parse_error: 1, program: 1, qsymbols_add: 2, qsymbols_new: 0, qwords_add: 2, qwords_new: 0, redo: 0, regexp_add: 2, regexp_literal: 2, regexp_new: 0, rescue: 4, rescue_mod: 2, rest_param: 1, retry: 0, return: 1, return0: 0, sclass: 2, stmts_add: 2, stmts_new: 0, string_add: 2, string_concat: 2, string_content: 0, string_dvar: 1, string_embexpr: 1, string_literal: 1, super: 1, symbol: 1, symbol_literal: 1, symbols_add: 2, symbols_new: 0, top_const_field: 1, top_const_ref: 1, unary: 2, undef: 1, unless: 3, unless_mod: 2, until: 2, until_mod: 2, var_alias: 2, var_field: 1, var_ref: 1, vcall: 1, void_stmt: 0, when: 3, while: 2, while_mod: 2, word_add: 2, word_new: 0, words_add: 2, words_new: 0, xstring_add: 2, xstring_literal: 1, xstring_new: 0, yield: 1, yield0: 0, zsuper: 0 } -
SCANNER_EVENTS =
# File 'lib/prism/translation/ripper.rb', line 301
This array contains name of scanner events.
SCANNER_EVENT_TABLE.keys
-
SCANNER_EVENT_TABLE =
# File 'lib/prism/translation/ripper.rb', line 242
This contains a table of all of the scanner events and their corresponding arity.
{ CHAR: 1, __end__: 1, backref: 1, backtick: 1, comma: 1, comment: 1, const: 1, cvar: 1, embdoc: 1, embdoc_beg: 1, embdoc_end: 1, embexpr_beg: 1, embexpr_end: 1, embvar: 1, float: 1, gvar: 1, heredoc_beg: 1, heredoc_end: 1, ident: 1, ignored_nl: 1, imaginary: 1, int: 1, ivar: 1, kw: 1, label: 1, label_end: 1, lbrace: 1, lbracket: 1, lparen: 1, nl: 1, op: 1, period: 1, qsymbols_beg: 1, qwords_beg: 1, rational: 1, rbrace: 1, rbracket: 1, regexp_beg: 1, regexp_end: 1, rparen: 1, semicolon: 1, sp: 1, symbeg: 1, symbols_beg: 1, tlambda: 1, tlambeg: 1, tstring_beg: 1, tstring_content: 1, tstring_end: 1, words_beg: 1, words_sep: 1, ignored_sp: 1 }
Class Method Summary
-
.lex(src, filename = "-", lineno = 1, raise_errors: false)
Tokenizes the Ruby program and returns an array of an array, which is formatted like
[[lineno, column], type, token, state]. -
.new(source, filename = "(ripper)", lineno = 1) ⇒ Ripper
constructor
Create a new
Ripperobject with the given source. -
.parse(src, filename = "(ripper)", lineno = 1)
Parses the given Ruby program read from
src. -
.sexp(src, filename = "-", lineno = 1, raise_errors: false)
Parses
srcand create S-exp tree. -
.sexp_raw(src, filename = "-", lineno = 1, raise_errors: false)
Parses
srcand create S-exp tree. -
.tokenize
Tokenizes the Ruby program and returns an array of strings.
-
.coerce_source(source)
Internal use only
Mirros the various lex_types that ripper supports.
- .lex_state_name(state) Internal use only
Instance Attribute Summary
-
#column
readonly
The current column in bytes of the parser.
-
#error? ⇒ Boolean
readonly
True if the parser encountered an error during parsing.
-
#filename
readonly
The filename of the source being parsed.
-
#lineno
readonly
The current line number of the parser.
-
#source
readonly
The source that is being parsed.
Instance Method Summary
-
#parse
Parse the source and return the result.
- #_dispatch_0 private
- #_dispatch_1(arg) private
- #_dispatch_2(arg, _) private
- #_dispatch_3(arg, _, _) private
- #_dispatch_4(arg, _, _, _) private
- #_dispatch_5(arg, _, _, _, _) private
- #_dispatch_7(arg, _, _, _, _, _, _) private
-
#compile_error(msg)
private
This method is called when the parser found syntax error.
-
#dedent_string(string, width)
private
This method is provided by the
RipperC extension. -
#warn(fmt, *args)
private
This method is called when weak warning is produced by the parser.
-
#warning(fmt, *args)
private
This method is called when strong warning is produced by the parser.
-
#visit_alias_global_variable_node(node)
Internal use only
alias $foo $bar ^^^^^^^^^^^^^^^.
-
#visit_alias_method_node(node)
Internal use only
alias foo bar ^^^^^^^^^^^^^.
-
#visit_alternation_pattern_node(node)
Internal use only
foo => bar | baz.
-
#visit_and_node(node)
Internal use only
a and b ^^^^^^^.
-
#visit_arguments_node(node)
Internal use only
foo(bar).
-
#visit_array_node(node)
Internal use only
[] ^^.
-
#visit_array_pattern_node(node)
Internal use only
foo => [bar].
-
#visit_assoc_node(node)
Internal use only
{ a: 1 }
-
#visit_assoc_splat_node(node)
Internal use only
def foo(); bar(); end.
-
#visit_back_reference_read_node(node)
Internal use only
$+ ^^.
-
#visit_begin_node(node)
Internal use only
begin end ^^^^^^^^^.
-
#visit_block_argument_node(node)
Internal use only
foo(&bar).
-
#visit_block_local_variable_node(node)
Internal use only
foo { |; bar| }
-
#visit_block_node(node)
Internal use only
Visit a BlockNode.
-
#visit_block_parameter_node(node)
Internal use only
def foo(&bar); end.
-
#visit_block_parameters_node(node)
Internal use only
A block's parameters.
-
#visit_break_node(node)
Internal use only
break ^^^^^.
-
#visit_call_and_write_node(node)
Internal use only
foo.bar &&= baz ^^^^^^^^^^^^^^^.
-
#visit_call_node(node)
Internal use only
foo ^^^.
-
#visit_call_operator_write_node(node)
Internal use only
foo.bar += baz ^^^^^^^^^^^^^^^.
-
#visit_call_or_write_node(node)
Internal use only
foo.bar ||= baz ^^^^^^^^^^^^^^^.
-
#visit_call_target_node(node)
Internal use only
foo.bar, = 1 ^^^^^^^.
-
#visit_capture_pattern_node(node)
Internal use only
foo => bar => baz.
-
#visit_case_match_node(node)
Internal use only
case foo; in bar; end ^^^^^^^^^^^^^^^^^^^^^.
-
#visit_case_node(node)
Internal use only
case foo; when bar; end ^^^^^^^^^^^^^^^^^^^^^^^.
-
#visit_class_node(node)
Internal use only
class Foo; end ^^^^^^^^^^^^^^.
-
#visit_class_variable_and_write_node(node)
Internal use only
@@foo &&= bar ^^^^^^^^^^^^^.
-
#visit_class_variable_operator_write_node(node)
Internal use only
@@foo += bar ^^^^^^^^^^^^.
-
#visit_class_variable_or_write_node(node)
Internal use only
@@foo ||= bar ^^^^^^^^^^^^^.
-
#visit_class_variable_read_node(node)
Internal use only
@@foo ^^^^^.
-
#visit_class_variable_target_node(node)
Internal use only
@@foo, = bar ^^^^^.
-
#visit_class_variable_write_node(node)
Internal use only
@@foo = 1 ^^^^^^^^^.
-
#visit_constant_and_write_node(node)
Internal use only
Foo &&= bar ^^^^^^^^^^^^.
-
#visit_constant_operator_write_node(node)
Internal use only
Foo += bar ^^^^^^^^^^^.
-
#visit_constant_or_write_node(node)
Internal use only
Foo ||= bar ^^^^^^^^^^^^.
-
#visit_constant_path_and_write_node(node)
Internal use only
Foo::Bar&&= baz ^^^^^^^^^^^^^^^^. -
#visit_constant_path_node(node)
Internal use only
Foo::Bar^^^^^^^^. -
#visit_constant_path_operator_write_node(node)
Internal use only
Foo::Bar+= baz ^^^^^^^^^^^^^^^. -
#visit_constant_path_or_write_node(node)
Internal use only
Foo::Bar||= baz ^^^^^^^^^^^^^^^^. -
#visit_constant_path_target_node(node)
Internal use only
Foo::Bar, = baz ^^^^^^^^. -
#visit_constant_path_write_node(node)
Internal use only
Foo::Bar= 1 ^^^^^^^^^^^^. -
#visit_constant_read_node(node)
Internal use only
Foo ^^^.
-
#visit_constant_target_node(node)
Internal use only
Foo, = bar ^^^.
-
#visit_constant_write_node(node)
Internal use only
Foo = 1 ^^^^^^^.
-
#visit_def_node(node)
Internal use only
def foo; end ^^^^^^^^^^^^.
-
#visit_defined_node(node)
Internal use only
defined? a ^^^^^^^^^^.
-
#visit_else_node(node)
Internal use only
if foo then bar else baz end.
-
#visit_embedded_statements_node(node)
Internal use only
"foo #
bar". -
#visit_embedded_variable_node(node)
Internal use only
"foo
#@bar" -
#visit_ensure_node(node)
Internal use only
Visit an EnsureNode node.
-
#visit_error_recovery_node(node)
Internal use only
A node that is missing from the syntax tree.
-
#visit_false_node(node)
Internal use only
false ^^^^^.
-
#visit_find_pattern_node(node)
Internal use only
foo => [*, bar, *].
-
#visit_flip_flop_node(node)
Internal use only
if foo ..
-
#visit_float_node(node)
Internal use only
1.0 ^^^.
-
#visit_for_node(node)
Internal use only
for foo in bar do end ^^^^^^^^^^^^^^^^^^^^^.
-
#visit_forwarding_arguments_node(node)
Internal use only
def foo(...); bar(...); end.
-
#visit_forwarding_parameter_node(node)
Internal use only
def foo(...); end.
-
#visit_forwarding_super_node(node)
Internal use only
super ^^^^^.
-
#visit_global_variable_and_write_node(node)
Internal use only
$foo &&= bar ^^^^^^^^^^^^.
-
#visit_global_variable_operator_write_node(node)
Internal use only
$foo += bar ^^^^^^^^^^^.
-
#visit_global_variable_or_write_node(node)
Internal use only
$foo ||= bar ^^^^^^^^^^^^.
-
#visit_global_variable_read_node(node)
Internal use only
$foo ^^^^.
-
#visit_global_variable_target_node(node)
Internal use only
$foo, = bar ^^^^.
-
#visit_global_variable_write_node(node)
Internal use only
$foo = 1 ^^^^^^^^.
-
#visit_hash_node(node)
Internal use only
{} ^^.
-
#visit_hash_pattern_node(node)
Internal use only
foo => {}
-
#visit_if_node(node)
Internal use only
if foo then bar end ^^^^^^^^^^^^^^^^^^^.
-
#visit_imaginary_node(node)
Internal use only
1i ^^.
-
#visit_implicit_node(node)
Internal use only
{ foo: }
-
#visit_implicit_rest_node(node)
Internal use only
foo { |bar,| }
-
#visit_in_node(node)
Internal use only
case foo; in bar; end ^^^^^^^^^^^^^^^^^^^^^.
-
#visit_index_and_write_node(node)
Internal use only
foo &&= baz ^^^^^^^^^^^^^^^^.
-
#visit_index_operator_write_node(node)
Internal use only
foo += baz ^^^^^^^^^^^^^^^.
-
#visit_index_or_write_node(node)
Internal use only
foo ||= baz ^^^^^^^^^^^^^^^^.
-
#visit_index_target_node(node)
Internal use only
foo, = 1 ^^^^^^^^.
-
#visit_instance_variable_and_write_node(node)
Internal use only
^^^^^^^^^^^^.
-
#visit_instance_variable_operator_write_node(node)
Internal use only
^^^^^^^^^^^.
-
#visit_instance_variable_or_write_node(node)
Internal use only
^^^^^^^^^^^^.
-
#visit_instance_variable_read_node(node)
Internal use only
^^^^.
-
#visit_instance_variable_target_node(node)
Internal use only
@foo, = bar ^^^^.
-
#visit_instance_variable_write_node(node)
Internal use only
^^^^^^^^.
-
#visit_integer_node(node)
Internal use only
1 ^.
-
#visit_interpolated_match_last_line_node(node)
Internal use only
if /foo #
bar/ then end. -
#visit_interpolated_regular_expression_node(node)
Internal use only
/foo #
bar/ ^^^^^^^^^^^^. -
#visit_interpolated_string_node(node)
Internal use only
"foo #
bar" ^^^^^^^^^^^^. -
#visit_interpolated_symbol_node(node)
Internal use only
:"foo #
bar" ^^^^^^^^^^^^^. -
#visit_interpolated_x_string_node(node)
Internal use only
foo #{bar}^^^^^^^^^^^^. -
#visit_it_local_variable_read_node(node)
Internal use only
-> { it }
-
#visit_it_parameters_node(node)
Internal use only
-> { it } ^^^^^^^^^.
-
#visit_keyword_hash_node(node)
Internal use only
foo(bar: baz).
-
#visit_keyword_rest_parameter_node(node)
Internal use only
def foo(**bar); end.
-
#visit_lambda_node(node)
Internal use only
-> {}
-
#visit_local_variable_and_write_node(node)
Internal use only
foo &&= bar ^^^^^^^^^^^.
-
#visit_local_variable_operator_write_node(node)
Internal use only
foo += bar ^^^^^^^^^^.
-
#visit_local_variable_or_write_node(node)
Internal use only
foo ||= bar ^^^^^^^^^^^.
-
#visit_local_variable_read_node(node)
Internal use only
foo ^^^.
-
#visit_local_variable_target_node(node)
Internal use only
foo, = bar ^^^.
-
#visit_local_variable_write_node(node)
Internal use only
foo = 1 ^^^^^^^.
-
#visit_match_last_line_node(node)
Internal use only
if /foo/ then end.
-
#visit_match_predicate_node(node)
Internal use only
foo in bar ^^^^^^^^^^.
-
#visit_match_required_node(node)
Internal use only
foo => bar ^^^^^^^^^^.
-
#visit_match_write_node(node)
Internal use only
/(?
foo)/ =~ bar ^^^^^^^^^^^^^^^^^^^^. -
#visit_module_node(node)
Internal use only
module Foo; end ^^^^^^^^^^^^^^^.
-
#visit_multi_target_node(node)
Internal use only
(foo, bar), bar = qux ^^^^^^^^^^.
-
#visit_multi_write_node(node)
Internal use only
foo, bar = baz ^^^^^^^^^^^^^^.
-
#visit_next_node(node)
Internal use only
next ^^^^.
-
#visit_nil_node(node)
Internal use only
nil ^^^.
-
#visit_no_block_parameter_node(node)
Internal use only
def foo(&nil); end.
-
#visit_no_keywords_parameter_node(node)
Internal use only
def foo(**nil); end.
-
#visit_numbered_parameters_node(node)
Internal use only
-> { _1 + _2 } ^^^^^^^^^^^^^^.
-
#visit_numbered_reference_read_node(node)
Internal use only
$1 ^^.
-
#visit_optional_keyword_parameter_node(node)
Internal use only
def foo(bar: baz); end.
-
#visit_optional_parameter_node(node)
Internal use only
def foo(bar = 1); end.
-
#visit_or_node(node)
Internal use only
a or b ^^^^^^.
-
#visit_parameters_node(node)
Internal use only
def foo(bar, *baz); end.
-
#visit_parentheses_node(node)
Internal use only
() ^^.
-
#visit_pinned_expression_node(node)
Internal use only
foo => ^(bar).
-
#visit_pinned_variable_node(node)
Internal use only
foo = 1 and bar => ^foo.
-
#visit_post_execution_node(node)
Internal use only
END {} ^^^^^^.
-
#visit_pre_execution_node(node)
Internal use only
BEGIN {} ^^^^^^^^.
-
#visit_program_node(node)
Internal use only
The top-level program node.
-
#visit_range_node(node)
Internal use only
0..5 ^^^^.
-
#visit_rational_node(node)
Internal use only
1r ^^.
-
#visit_redo_node(node)
Internal use only
redo ^^^^.
-
#visit_regular_expression_node(node)
Internal use only
/foo/ ^^^^^.
-
#visit_required_keyword_parameter_node(node)
Internal use only
def foo(bar:); end.
-
#visit_required_parameter_node(node)
Internal use only
def foo(bar); end.
-
#visit_rescue_modifier_node(node)
Internal use only
foo rescue bar ^^^^^^^^^^^^^^.
-
#visit_rescue_node(node)
Internal use only
begin; rescue; end.
-
#visit_rest_parameter_node(node)
Internal use only
def foo(*bar); end.
-
#visit_retry_node(node)
Internal use only
retry ^^^^^.
-
#visit_return_node(node)
Internal use only
return ^^^^^^.
-
#visit_self_node(node)
Internal use only
self ^^^^.
-
#visit_shareable_constant_node(node)
Internal use only
A shareable constant.
-
#visit_singleton_class_node(node)
Internal use only
class << self; end ^^^^^^^^^^^^^^^^^^.
-
#visit_source_encoding_node(node)
Internal use only
ENCODING ^^^^^^^^^^^^.
-
#visit_source_file_node(node)
Internal use only
FILE ^^^^^^^^.
-
#visit_source_line_node(node)
Internal use only
LINE ^^^^^^^^.
-
#visit_splat_node(node)
Internal use only
foo(*bar).
-
#visit_statements_node(node)
Internal use only
A list of statements.
-
#visit_string_node(node)
Internal use only
"foo" ^^^^^.
-
#visit_super_node(node)
Internal use only
super(foo) ^^^^^^^^^^.
-
#visit_symbol_node(node)
Internal use only
:foo^^^^. -
#visit_true_node(node)
Internal use only
true ^^^^.
-
#visit_undef_node(node)
Internal use only
undef foo ^^^^^^^^^.
-
#visit_unless_node(node)
Internal use only
unless foo; bar end ^^^^^^^^^^^^^^^^^^^.
-
#visit_until_node(node)
Internal use only
until foo; bar end ^^^^^^^^^^^^^^^^^.
-
#visit_when_node(node)
Internal use only
case foo; when bar; end.
-
#visit_while_node(node)
Internal use only
while foo; bar end ^^^^^^^^^^^^^^^^^^.
-
#visit_x_string_node(node)
Internal use only
foo^^^^^. -
#visit_yield_node(node)
Internal use only
yield ^^^^^.
-
#bounds(location)
private
Internal use only
This method is responsible for updating lineno and column information to reflect the current node.
-
#command?(node) ⇒ Boolean
private
Internal use only
Returns true if the given node is a command node.
-
#get_arguments_and_block(arguments_node, block_node)
private
Internal use only
Extract the arguments and block Ripper-style, which means if the block is like
&bthen it's moved to arguments. -
#result
private
Internal use only
Lazily initialize the parse result.
-
#trailing_comma?(left, right) ⇒ Boolean
private
Internal use only
Returns true if there is a comma between the two locations.
-
#visit_alias_global_variable_node_value(node)
private
Internal use only
Visit one side of an alias global variable node.
-
#visit_arguments(elements)
private
Internal use only
Visit a list of elements, like the elements of an array or arguments.
-
#visit_begin_node_clauses(location, node, allow_newline)
private
Internal use only
Visit the clauses of a begin node to form an on_bodystmt call.
-
#visit_body_node(location, node, allow_newline = false)
private
Internal use only
Visit the body of a structure that can have either a set of statements or statements wrapped in rescue/else/ensure.
-
#visit_call_node_arguments(arguments_node, block_node, trailing_comma)
private
Internal use only
Visit the arguments and block of a call node and return the arguments and block as they should be used.
-
#visit_constant_path_write_node_target(node)
private
Internal use only
Visit a constant path that is part of a write node.
-
#visit_destructured_parameter_node(node)
private
Internal use only
Visit a destructured positional parameter node.
-
#visit_heredoc_node(parts, base)
private
Internal use only
Visit a string that is expressed using a <<~ heredoc.
-
#visit_heredoc_node_whitespace(parts)
private
Internal use only
Rippergives back the escaped string content but strips out the common leading whitespace. -
#visit_heredoc_string_node(node)
private
Internal use only
Visit a heredoc node that is representing a string.
-
#visit_heredoc_x_string_node(node)
private
Internal use only
Visit a heredoc node that is representing an xstring.
-
#visit_multi_target_node_targets(lefts, rest, rights, skippable)
private
Internal use only
Visit the targets of a multi-target node.
-
#visit_number_node(node)
private
Internal use only
Visit a node that represents a number.
-
#visit_pattern_node(node)
private
Internal use only
Visit a pattern within a pattern match.
-
#visit_statements_node_body(body)
private
Internal use only
Visit the list of statements of a statements node.
-
#visit_string_content(part)
private
Internal use only
Visit an individual part of a string-like node.
-
#visit_token(token, allow_keywords = true)
private
Internal use only
Visit the string content of a particular node.
-
#visit_words_sep(opening_loc, previous, current)
private
Internal use only
Dispatch words_sep events that contains the whitespace between the elements of list literals.
-
#visit_write_value(node)
private
Internal use only
Visit a node that represents a write value.
-
#void_stmt?(left, right, allow_newline) ⇒ Boolean
private
Internal use only
Returns true if there is a semicolon between the two locations.
-
#with_string_bounds(node)
private
Internal use only
Responsible for emitting the various string-like begin/end events.
Constructor Details
.new(source, filename = "(ripper)", lineno = 1) ⇒ Ripper
Create a new Ripper object with the given source.
Class Method Details
.coerce_source(source)
Mirros the various lex_types that ripper supports
.lex(src, filename = "-", lineno = 1, raise_errors: false)
Tokenizes the Ruby program and returns an array of an array,
which is formatted like
[[lineno, column], type, token, state].
The #filename argument is mostly ignored.
By default, this method does not handle syntax errors in src,
use the raise_errors keyword to raise a SyntaxError for an error in src.
require "ripper"
require "pp"
pp Ripper.lex("def m(a) nil end")
#=> [[[1, 0], :on_kw, "def", FNAME ],
[[1, 3], :on_sp, " ", FNAME ],
[[1, 4], :on_ident, "m", ENDFN ],
[[1, 5], :on_lparen, "(", BEG|LABEL],
[[1, 6], :on_ident, "a", ARG ],
[[1, 7], :on_rparen, ")", ENDFN ],
[[1, 8], :on_sp, " ", BEG ],
[[1, 9], :on_kw, "nil", END ],
[[1, 12], :on_sp, " ", END ],
[[1, 13], :on_kw, "end", END ]]
# File 'lib/prism/translation/ripper.rb', line 59
def self.lex(src, filename = "-", lineno = 1, raise_errors: false) result = Prism.lex_compat(coerce_source(src), filepath: filename, line: lineno, version: "current") if result.failure? && raise_errors raise SyntaxError, result.errors.first. else result.value end end
.lex_state_name(state)
# File 'lib/prism/translation/ripper.rb', line 466
def self.lex_state_name(state) LEX_STATE_NAMES.filter_map { |flag, name| name if state & flag != 0 }.join("|") end
.parse(src, filename = "(ripper)", lineno = 1)
Parses the given Ruby program read from src.
src must be a String or an IO or a object with a #gets method.
.sexp(src, filename = "-", lineno = 1, raise_errors: false)
Parses src and create S-exp tree.
Returns more readable tree rather than .sexp_raw.
This method is mainly for developer use.
The #filename argument is mostly ignored.
By default, this method does not handle syntax errors in src,
returning nil in such cases. Use the raise_errors keyword
to raise a SyntaxError for an error in src.
require "ripper"
require "pp"
pp Ripper.sexp("def m(a) nil end")
#=> [:program,
[[:def,
[:@ident, "m", [1, 4]],
[:paren, [:params, [[:@ident, "a", [1, 6]]], nil, nil, nil, nil, nil, nil]],
[:bodystmt, [[:var_ref, [:@kw, "nil", [1, 9]]]], nil, nil, nil]]]]
.sexp_raw(src, filename = "-", lineno = 1, raise_errors: false)
Parses src and create S-exp tree.
This method is mainly for developer use.
The #filename argument is mostly ignored.
By default, this method does not handle syntax errors in src,
returning nil in such cases. Use the raise_errors keyword
to raise a SyntaxError for an error in src.
require "ripper"
require "pp"
pp Ripper.sexp_raw("def m(a) nil end")
#=> [:program,
[:stmts_add,
[:stmts_new],
[:def,
[:@ident, "m", [1, 4]],
[:paren, [:params, [[:@ident, "a", [1, 6]]], nil, nil, nil]],
[:bodystmt,
[:stmts_add, [:stmts_new], [:var_ref, [:@kw, "nil", [1, 9]]]],
nil,
nil,
nil]]]]
.tokenize
Tokenizes the Ruby program and returns an array of strings.
The #filename and #lineno arguments are mostly ignored, since the
return value is just the tokenized input.
By default, this method does not handle syntax errors in src,
use the raise_errors keyword to raise a SyntaxError for an error in src.
p Ripper.tokenize("def m(a) nil end")
# => ["def", " ", "m", "(", "a", ")", " ", "nil", " ", "end"]
# File 'lib/prism/translation/ripper.rb', line 78
def self.tokenize(...) lex(...).map { |token| token[2] } end
Instance Attribute Details
#column (readonly)
The current column in bytes of the parser.
# File 'lib/prism/translation/ripper.rb', line 482
attr_reader :column
#error? ⇒ Boolean (readonly)
True if the parser encountered an error during parsing.
# File 'lib/prism/translation/ripper.rb', line 498
def error? result.failure? end
#filename (readonly)
The filename of the source being parsed.
# File 'lib/prism/translation/ripper.rb', line 476
attr_reader :filename
#lineno (readonly)
The current line number of the parser.
# File 'lib/prism/translation/ripper.rb', line 479
attr_reader :lineno
#source (readonly)
The source that is being parsed.
# File 'lib/prism/translation/ripper.rb', line 473
attr_reader :source
Instance Method Details
#_dispatch_0 (private)
[ GitHub ]# File 'lib/prism/translation/ripper.rb', line 4151
def _dispatch_0; end
#_dispatch_1(arg) (private)
[ GitHub ]# File 'lib/prism/translation/ripper.rb', line 4152
def _dispatch_1(arg); arg end
#_dispatch_2(arg, _) (private)
[ GitHub ]# File 'lib/prism/translation/ripper.rb', line 4153
def _dispatch_2(arg, _); arg end
#_dispatch_3(arg, _, _) (private)
[ GitHub ]# File 'lib/prism/translation/ripper.rb', line 4154
def _dispatch_3(arg, _, _); arg end
#_dispatch_4(arg, _, _, _) (private)
[ GitHub ]# File 'lib/prism/translation/ripper.rb', line 4155
def _dispatch_4(arg, _, _, _); arg end
#_dispatch_5(arg, _, _, _, _) (private)
[ GitHub ]# File 'lib/prism/translation/ripper.rb', line 4156
def _dispatch_5(arg, _, _, _, _); arg end
#_dispatch_7(arg, _, _, _, _, _, _) (private)
[ GitHub ]# File 'lib/prism/translation/ripper.rb', line 4157
def _dispatch_7(arg, _, _, _, _, _, _); arg end
#bounds(location) (private)
This method is responsible for updating lineno and column information to reflect the current node.
This method could be drastically improved with some caching on the start of every line, but for now it's good enough.
# File 'lib/prism/translation/ripper.rb', line 4139
def bounds(location) @lineno = location.start_line @column = location.start_column end
#command?(node) ⇒ Boolean (private)
Returns true if the given node is a command node.
# File 'lib/prism/translation/ripper.rb', line 1404
private def command?(node) node.is_a?(CallNode) && node.opening_loc.nil? && (!node.arguments.nil? || node.block.is_a?(BlockArgumentNode)) && !BINARY_OPERATORS.include?(node.name) end
#compile_error(msg) (private)
This method is called when the parser found syntax error.
# File 'lib/prism/translation/ripper.rb', line 4179
def compile_error(msg) end
#dedent_string(string, width) (private)
This method is provided by the Ripper C extension. It is called when a
string needs to be dedented because of a tilde heredoc. It is expected
that it will modify the string in place and return the number of bytes
that were removed.
# File 'lib/prism/translation/ripper.rb', line 4194
def dedent_string(string, width) whitespace = 0 cursor = 0 while cursor < string.length && string[cursor].match?(/\s/) && whitespace < width if string[cursor] == "\t" whitespace = ((whitespace / 8 + 1) * 8) break if whitespace > width else whitespace += 1 end cursor += 1 end string.replace(string[cursor..]) cursor end
#get_arguments_and_block(arguments_node, block_node) (private)
Extract the arguments and block Ripper-style, which means if the block
is like &b then it's moved to arguments.
# File 'lib/prism/translation/ripper.rb', line 1369
private def get_arguments_and_block(arguments_node, block_node) arguments = arguments_node&.arguments || [] block = block_node if block.is_a?(BlockArgumentNode) arguments += [block] block = nil end [arguments, block] end
#parse
Parse the source and return the result.
# File 'lib/prism/translation/ripper.rb', line 503
def parse result.comments.each do |comment| location = comment.location bounds(location) if comment.is_a?(InlineComment) # Inline comments always contain a newline if the line itself contains it if result.source.source.bytesize > comment.location.end_offset on_comment("#{comment.slice}\n") else on_comment(comment.slice) end else offset = location.start_offset lines = comment.slice.lines lines.each_with_index do |line, index| bounds(location.copy(start_offset: offset)) if index == 0 on_embdoc_beg(line) elsif index == lines.size - 1 on_embdoc_end(line) else on_embdoc(line) end offset += line.bytesize end end end result.magic_comments.each do |magic_comment| on_magic_comment(magic_comment.key, magic_comment.value) end unless result.data_loc.nil? on___end__(result.data_loc.slice.each_line.first) end result.warnings.each do |warning| bounds(warning.location) if warning.level == :default warning(warning.) else case warning.type when :ambiguous_first_argument_plus on_arg_ambiguous("+") when :ambiguous_first_argument_minus on_arg_ambiguous("-") when :ambiguous_slash on_arg_ambiguous("/") else warn(warning.) end end end if error? result.errors.each do |error| location = error.location bounds(location) case error.type when :alias_argument on_alias_error("can't make alias for the number variables", location.slice) when :argument_formal_class on_param_error("formal argument cannot be a class variable", location.slice) when :argument_format_constant on_param_error("formal argument cannot be a constant", location.slice) when :argument_formal_global on_param_error("formal argument cannot be a global variable", location.slice) when :argument_formal_ivar on_param_error("formal argument cannot be an instance variable", location.slice) when :class_name, :module_name on_class_name_error("class/module name must be CONSTANT", location.slice) else on_parse_error(error.) end end nil else result.value.accept(self) end end
#result (private)
Lazily initialize the parse result.
#trailing_comma?(left, right) ⇒ Boolean (private)
Returns true if there is a comma between the two locations.
# File 'lib/prism/translation/ripper.rb', line 4041
def trailing_comma?(left, right) source.byteslice(left.end_offset...right.start_offset).include?(",") end
#visit_alias_global_variable_node(node)
alias $foo $bar ^^^^^^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 612
def visit_alias_global_variable_node(node) bounds(node.keyword_loc) on_kw("alias") new_name = visit_alias_global_variable_node_value(node.new_name) old_name = visit_alias_global_variable_node_value(node.old_name) bounds(node.location) on_var_alias(new_name, old_name) end
#visit_alias_global_variable_node_value(node) (private)
Visit one side of an alias global variable node.
# File 'lib/prism/translation/ripper.rb', line 624
private def visit_alias_global_variable_node_value(node) bounds(node.location) case node when BackReferenceReadNode on_backref(node.slice) when GlobalVariableReadNode on_gvar(node.name.to_s) else raise end end
#visit_alias_method_node(node)
alias foo bar ^^^^^^^^^^^^^
#visit_alternation_pattern_node(node)
foo => bar | baz ^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 639
def visit_alternation_pattern_node(node) left = visit_pattern_node(node.left) bounds(node.operator_loc) on_op("|") right = visit_pattern_node(node.right) bounds(node.location) on_binary(left, :|, right) end
#visit_and_node(node)
a and b ^^^^^^^
#visit_arguments(elements) (private)
Visit a list of elements, like the elements of an array or arguments.
# File 'lib/prism/translation/ripper.rb', line 842
private def visit_arguments(elements) bounds(elements.first.location) elements.inject(on_args_new) do |args, element| arg = visit(element) bounds(element.location) case element when BlockArgumentNode on_args_add_block(args, arg) when SplatNode on_args_add_star(args, arg) else on_args_add(args, arg) end end end
#visit_arguments_node(node)
foo(bar) ^^^
# File 'lib/prism/translation/ripper.rb', line 895
def visit_arguments_node(node) arguments, _ = visit_call_node_arguments(node, nil, false) arguments end
#visit_array_node(node)
[] ^^
# File 'lib/prism/translation/ripper.rb', line 687
def visit_array_node(node) case (opening = node.opening) when /^%w/ opening_loc = node.opening_loc bounds(opening_loc) on_qwords_beg(opening) elements = on_qwords_new previous = nil node.elements.each do |element| visit_words_sep(opening_loc, previous, element) bounds(element.location) elements = on_qwords_add(elements, on_tstring_content(element.content)) previous = element end visit_words_sep(opening_loc, node.elements.last, node.closing_loc) bounds(node.closing_loc) on_tstring_end(node.closing) when /^%i/ opening_loc = node.opening_loc bounds(opening_loc) on_qsymbols_beg(opening) elements = on_qsymbols_new previous = nil node.elements.each do |element| visit_words_sep(opening_loc, previous, element) bounds(element.location) elements = on_qsymbols_add(elements, on_tstring_content(element.value)) previous = element end visit_words_sep(opening_loc, node.elements.last, node.closing_loc) bounds(node.closing_loc) on_tstring_end(node.closing) when /^%W/ opening_loc = node.opening_loc bounds(opening_loc) on_words_beg(opening) elements = on_words_new previous = nil node.elements.each do |element| visit_words_sep(opening_loc, previous, element) bounds(element.location) elements = on_words_add( elements, if element.is_a?(StringNode) on_word_add(on_word_new, on_tstring_content(element.content)) else element.parts.inject(on_word_new) do |word, part| word_part = if part.is_a?(StringNode) bounds(part.location) on_tstring_content(part.content) else visit(part) end on_word_add(word, word_part) end end ) previous = element end visit_words_sep(opening_loc, node.elements.last, node.closing_loc) bounds(node.closing_loc) on_tstring_end(node.closing) when /^%I/ opening_loc = node.opening_loc bounds(opening_loc) on_symbols_beg(opening) elements = on_symbols_new previous = nil node.elements.each do |element| visit_words_sep(opening_loc, previous, element) bounds(element.location) elements = on_symbols_add( elements, if element.is_a?(SymbolNode) on_word_add(on_word_new, on_tstring_content(element.value)) else element.parts.inject(on_word_new) do |word, part| word_part = if part.is_a?(StringNode) bounds(part.location) on_tstring_content(part.content) else visit(part) end on_word_add(word, word_part) end end ) previous = element end visit_words_sep(opening_loc, node.elements.last, node.closing_loc) bounds(node.closing_loc) on_tstring_end(node.closing) else bounds(node.opening_loc) on_lbracket(opening) elements = visit_arguments(node.elements) unless node.elements.empty? bounds(node.closing_loc) on_rbracket(node.closing) end bounds(node.location) on_array(elements) end
#visit_array_pattern_node(node)
foo => [bar] ^^^^^
# File 'lib/prism/translation/ripper.rb', line 861
def visit_array_pattern_node(node) constant = visit(node.constant) if node.opening_loc bounds(node.opening_loc) node.opening == "[" ? on_lbracket("[") : on_lparen("(") end requireds = visit_all(node.requireds) if node.requireds.any? rest = if (rest_node = node.rest).is_a?(SplatNode) bounds(rest_node.operator_loc) on_op("*") if rest_node.expression.nil? bounds(rest_node.location) on_var_field(nil) else visit(rest_node.expression) end end posts = visit_all(node.posts) if node.posts.any? if node.closing_loc bounds(node.closing_loc) node.closing == "]" ? on_rbracket("]") : on_rparen(")") end bounds(node.location) on_aryptn(constant, requireds, rest, posts) end
#visit_assoc_node(node)
{ a: 1 } ^^^^
#visit_assoc_splat_node(node)
def foo(); bar(); end ^^
{ **foo } ^^^^^
#visit_back_reference_read_node(node)
$+ ^^
# File 'lib/prism/translation/ripper.rb', line 933
def visit_back_reference_read_node(node) bounds(node.location) on_backref(node.slice) end
#visit_begin_node(node)
begin end ^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 940
def visit_begin_node(node) if node.begin_keyword_loc bounds(node.begin_keyword_loc) on_kw("begin") end clauses = visit_begin_node_clauses(node.begin_keyword_loc, node, false) if node.end_keyword_loc bounds(node.end_keyword_loc) on_kw("end") end bounds(node.location) on_begin(clauses) end
#visit_begin_node_clauses(location, node, allow_newline) (private)
Visit the clauses of a begin node to form an on_bodystmt call.
# File 'lib/prism/translation/ripper.rb', line 958
private def visit_begin_node_clauses(location, node, allow_newline) statements = if node.statements.nil? on_stmts_add(on_stmts_new, on_void_stmt) else body = node.statements.body body.unshift(nil) if void_stmt?(location, node.statements.body[0].location, allow_newline) bounds(node.statements.location) visit_statements_node_body(body) end rescue_clause = visit(node.rescue_clause) else_clause = unless (else_clause_node = node.else_clause).nil? bounds(else_clause_node.else_keyword_loc) on_kw("else") else_statements = if else_clause_node.statements.nil? [nil] else body = else_clause_node.statements.body body.unshift(nil) if void_stmt?(else_clause_node.else_keyword_loc, else_clause_node.statements.body[0].location, allow_newline) body end bounds(else_clause_node.location) visit_statements_node_body(else_statements) end ensure_clause = visit(node.ensure_clause) bounds(node.location) on_bodystmt(statements, rescue_clause, else_clause, ensure_clause) end
#visit_block_argument_node(node)
foo(&bar) ^^^^
# File 'lib/prism/translation/ripper.rb', line 1017
def visit_block_argument_node(node) bounds(node.operator_loc) on_op("&") visit(node.expression) end
#visit_block_local_variable_node(node)
foo { |; bar| } ^^^
# File 'lib/prism/translation/ripper.rb', line 1025
def visit_block_local_variable_node(node) bounds(node.location) on_ident(node.name.to_s) end
#visit_block_node(node)
Visit a BlockNode.
# File 'lib/prism/translation/ripper.rb', line 1031
def visit_block_node(node) braces = node.opening == "{" bounds(node.opening_loc) if braces on_lbrace("{") else on_kw("do") end parameters = visit(node.parameters) body = case node.body when nil bounds(node.location) stmts = on_stmts_add(on_stmts_new, on_void_stmt) bounds(node.location) braces ? stmts : on_bodystmt(stmts, nil, nil, nil) when StatementsNode stmts = node.body.body stmts.unshift(nil) if void_stmt?(node.parameters&.location || node.opening_loc, node.body.location, false) stmts = visit_statements_node_body(stmts) bounds(node.body.location) braces ? stmts : on_bodystmt(stmts, nil, nil, nil) when BeginNode visit_body_node(node.parameters&.location || node.opening_loc, node.body) else raise end if braces bounds(node.closing_loc) on_rbrace("}") else bounds(node.closing_loc) on_kw("end") end if braces bounds(node.location) on_brace_block(parameters, body) else bounds(node.location) on_do_block(parameters, body) end end
#visit_block_parameter_node(node)
def foo(&bar); end ^^^^
# File 'lib/prism/translation/ripper.rb', line 1082
def visit_block_parameter_node(node) bounds(node.operator_loc) on_op("&") if node.name_loc.nil? bounds(node.location) on_blockarg(nil) else bounds(node.name_loc) name = visit_token(node.name.to_s) bounds(node.location) on_blockarg(name) end end
#visit_block_parameters_node(node)
A block's parameters.
# File 'lib/prism/translation/ripper.rb', line 1099
def visit_block_parameters_node(node) bounds(node.opening_loc) on_op("|") parameters = if node.parameters.nil? on_params(nil, nil, nil, nil, nil, nil, nil) else visit(node.parameters) end locals = if node.locals.any? visit_all(node.locals) else false end bounds(node.closing_loc) on_op("|") bounds(node.location) on_block_var(parameters, locals) end
#visit_body_node(location, node, allow_newline = false) (private)
Visit the body of a structure that can have either a set of statements or statements wrapped in rescue/else/ensure.
# File 'lib/prism/translation/ripper.rb', line 996
private def visit_body_node(location, node, allow_newline = false) case node when nil bounds(location) on_bodystmt(visit_statements_node_body([nil]), nil, nil, nil) when StatementsNode body = [*node.body] body.unshift(nil) if void_stmt?(location, body[0].location, allow_newline) stmts = visit_statements_node_body(body) bounds(node.body.first.location) on_bodystmt(stmts, nil, nil, nil) when BeginNode visit_begin_node_clauses(location, node, allow_newline) else raise end end
#visit_break_node(node)
break ^^^^^
break foo ^^^^^^^^^
#visit_call_and_write_node(node)
foo.bar &&= baz ^^^^^^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 1435
def visit_call_and_write_node(node) receiver = visit(node.receiver) bounds(node.call_operator_loc) call_operator = visit_token(node.call_operator) bounds(node.) = visit_token(node.) bounds(node.location) target = on_field(receiver, call_operator, ) bounds(node.operator_loc) operator = on_op("&&=") value = visit_write_value(node.value) bounds(node.location) on_opassign(target, operator, value) end
#visit_call_node(node)
foo ^^^
foo.bar ^^^^^^^
foo.bar() {} ^^^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 1152
def visit_call_node(node) if node.call_operator_loc.nil? case node.name when :[] receiver = visit(node.receiver) bounds(node.opening_loc) on_lbracket("[") arguments, block_node = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.closing_loc)) bounds(node.closing_loc) on_rbracket("]") block = visit(block_node) bounds(node.location) call = on_aref(receiver, arguments) if block_node bounds(node.location) on_method_add_block(call, block) else call end when :[]= receiver = visit(node.receiver) bounds(node.opening_loc) on_lbracket("[") *arguments, last_argument = node.arguments.arguments arguments << node.block if !node.block.nil? arguments = if arguments.any? args = visit_arguments(arguments) if !node.block.nil? args else bounds(arguments.first.location) on_args_add_block(args, false) end end bounds(node.closing_loc) on_rbracket("]") bounds(node.equal_loc) on_op("=") bounds(node.location) call = on_aref_field(receiver, arguments) value = visit_write_value(last_argument) bounds(last_argument.location) on_assign(call, value) when :-@, :+@, :~ bounds(node.) on_op(node.) receiver = visit(node.receiver) bounds(node.location) on_unary(node.name, receiver) when :! bounds(node.) if node. == "not" on_kw("not") if node.opening_loc bounds(node.opening_loc) on_lparen("(") end receiver = if node.receiver.is_a?(ParenthesesNode) && node.receiver.body.nil? # The parens in `not()` just emit parens and nothing else. bounds(node.receiver.opening_loc) on_lparen("(") bounds(node.receiver.closing_loc) on_rparen(")") nil else visit(node.receiver) end if node.closing_loc bounds(node.closing_loc) on_rparen(")") end bounds(node.location) on_unary(:not, receiver) else on_op("!") receiver = visit(node.receiver) bounds(node.location) on_unary(:!, receiver) end when *BINARY_OPERATORS receiver = visit(node.receiver) bounds(node.) on_op(node.) value = visit(node.arguments.arguments.first) bounds(node.location) on_binary(receiver, node.name, value) else bounds(node.) = visit_token(node., false) if node.variable_call? on_vcall() else if node.opening_loc bounds(node.opening_loc) on_lparen("(") end arguments, block_node = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.closing_loc || node.location)) if node.closing_loc bounds(node.closing_loc) on_rparen(")") end block = visit(block_node) call = if node.opening_loc.nil? && get_arguments_and_block(node.arguments, node.block).first.any? bounds(node.location) on_command(, arguments) elsif !node.opening_loc.nil? bounds(node.location) on_method_add_arg(on_fcall(), on_arg_paren(arguments)) else bounds(node.location) on_method_add_arg(on_fcall(), on_args_new) end if block_node bounds(node.block.location) on_method_add_block(call, block) else call end end end else receiver = visit(node.receiver) bounds(node.call_operator_loc) call_operator = visit_token(node.call_operator) = if node..nil? :call else bounds(node.) visit_token(node., false) end if node.equal_loc bounds(node.equal_loc) on_op("=") end if node.name.end_with?("=") && !node..end_with?("=") && !node.arguments.nil? && node.block.nil? value = visit_write_value(node.arguments.arguments.first) bounds(node.location) on_assign(on_field(receiver, call_operator, ), value) else if node.opening_loc bounds(node.opening_loc) on_lparen("(") end arguments, block_node = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.closing_loc || node.location)) if node.closing_loc bounds(node.closing_loc) on_rparen(")") end block = visit(block_node) call = if node.opening_loc.nil? bounds(node.location) if node.arguments.nil? && !node.block.is_a?(BlockArgumentNode) on_call(receiver, call_operator, ) else on_command_call(receiver, call_operator, , arguments) end else bounds(node.opening_loc) arguments = on_arg_paren(arguments) bounds(node.location) on_method_add_arg(on_call(receiver, call_operator, ), arguments) end if block_node bounds(node.block.location) on_method_add_block(call, block) else call end end end end
#visit_call_node_arguments(arguments_node, block_node, trailing_comma) (private)
Visit the arguments and block of a call node and return the arguments and block as they should be used.
# File 'lib/prism/translation/ripper.rb', line 1383
private def visit_call_node_arguments(arguments_node, block_node, trailing_comma) arguments, block = get_arguments_and_block(arguments_node, block_node) [ if arguments.length == 1 && arguments.first.is_a?(ForwardingArgumentsNode) visit(arguments.first) elsif arguments.any? args = visit_arguments(arguments) if block_node.is_a?(BlockArgumentNode) || arguments.last.is_a?(ForwardingArgumentsNode) || command?(arguments.last) || trailing_comma args else bounds(arguments.first.location) on_args_add_block(args, false) end end, block, ] end
#visit_call_operator_write_node(node)
foo.bar += baz ^^^^^^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 1413
def visit_call_operator_write_node(node) receiver = visit(node.receiver) bounds(node.call_operator_loc) call_operator = visit_token(node.call_operator) bounds(node.) = visit_token(node.) bounds(node.location) target = on_field(receiver, call_operator, ) bounds(node.binary_operator_loc) operator = on_op("#{node.binary_operator}=") value = visit_write_value(node.value) bounds(node.location) on_opassign(target, operator, value) end
#visit_call_or_write_node(node)
foo.bar ||= baz ^^^^^^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 1457
def visit_call_or_write_node(node) receiver = visit(node.receiver) bounds(node.call_operator_loc) call_operator = visit_token(node.call_operator) bounds(node.) = visit_token(node.) bounds(node.location) target = on_field(receiver, call_operator, ) bounds(node.operator_loc) operator = on_op("||=") value = visit_write_value(node.value) bounds(node.location) on_opassign(target, operator, value) end
#visit_call_target_node(node)
foo.bar, = 1 ^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 1479
def visit_call_target_node(node) if node.call_operator == "::" receiver = visit(node.receiver) bounds(node.call_operator_loc) on_op("::") bounds(node.) = visit_token(node.) bounds(node.location) on_const_path_field(receiver, ) else receiver = visit(node.receiver) bounds(node.call_operator_loc) call_operator = visit_token(node.call_operator) bounds(node.) = visit_token(node.) bounds(node.location) on_field(receiver, call_operator, ) end end
#visit_capture_pattern_node(node)
foo => bar => baz ^^^^^^^^^^
#visit_case_match_node(node)
case foo; in bar; end ^^^^^^^^^^^^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 1545
def visit_case_match_node(node) bounds(node.case_keyword_loc) on_kw("case") predicate = visit(node.predicate) visited_conditions = node.conditions.map do | condition| visit(condition) end visited_else_clause = visit(node.else_clause) if !node.else_clause bounds(node.end_keyword_loc) on_kw("end") end clauses = visited_conditions.reverse_each.inject(visited_else_clause) do |current, condition| on_in(*condition, current) end bounds(node.location) on_case(predicate, clauses) end
#visit_case_node(node)
case foo; when bar; end ^^^^^^^^^^^^^^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 1521
def visit_case_node(node) bounds(node.case_keyword_loc) on_kw("case") predicate = visit(node.predicate) visited_conditions = node.conditions.map { |condition| visit(condition) } visited_else_clause = visit(node.else_clause) if !node.else_clause bounds(node.end_keyword_loc) on_kw("end") end clauses = visited_conditions.reverse_each.inject(visited_else_clause) do |current, condition| on_when(*condition, current) end bounds(node.location) on_case(predicate, clauses) end
#visit_class_node(node)
class Foo; end ^^^^^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 1571
def visit_class_node(node) bounds(node.class_keyword_loc) on_kw("class") constant_path = if node.constant_path.is_a?(ConstantReadNode) bounds(node.constant_path.location) on_const_ref(on_const(node.constant_path.name.to_s)) else visit(node.constant_path) end if node.inheritance_operator_loc bounds(node.inheritance_operator_loc) on_op("<") end superclass = visit(node.superclass) bodystmt = visit_body_node(node.superclass&.location || node.constant_path.location, node.body, node.superclass.nil?) bounds(node.end_keyword_loc) on_kw("end") bounds(node.location) on_class(constant_path, superclass, bodystmt) end
#visit_class_variable_and_write_node(node)
@@foo &&= bar ^^^^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 1639
def visit_class_variable_and_write_node(node) bounds(node.name_loc) target = on_var_field(on_cvar(node.name.to_s)) bounds(node.operator_loc) operator = on_op("&&=") value = visit_write_value(node.value) bounds(node.location) on_opassign(target, operator, value) end
#visit_class_variable_operator_write_node(node)
@@foo += bar ^^^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 1625
def visit_class_variable_operator_write_node(node) bounds(node.name_loc) target = on_var_field(on_cvar(node.name.to_s)) bounds(node.binary_operator_loc) operator = on_op("#{node.binary_operator}=") value = visit_write_value(node.value) bounds(node.location) on_opassign(target, operator, value) end
#visit_class_variable_or_write_node(node)
@@foo ||= bar ^^^^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 1653
def visit_class_variable_or_write_node(node) bounds(node.name_loc) target = on_var_field(on_cvar(node.name.to_s)) bounds(node.operator_loc) operator = on_op("||=") value = visit_write_value(node.value) bounds(node.location) on_opassign(target, operator, value) end
#visit_class_variable_read_node(node)
@@foo ^^^^^
# File 'lib/prism/translation/ripper.rb', line 1600
def visit_class_variable_read_node(node) bounds(node.location) on_var_ref(on_cvar(node.slice)) end
#visit_class_variable_target_node(node)
@@foo, = bar ^^^^^
# File 'lib/prism/translation/ripper.rb', line 1667
def visit_class_variable_target_node(node) bounds(node.location) on_var_field(on_cvar(node.name.to_s)) end
#visit_class_variable_write_node(node)
@@foo = 1 ^^^^^^^^^
@@foo, @@bar = 1 ^^^^^ ^^^^^
# File 'lib/prism/translation/ripper.rb', line 1610
def visit_class_variable_write_node(node) bounds(node.name_loc) target = on_var_field(on_cvar(node.name.to_s)) bounds(node.operator_loc) on_op("=") value = visit_write_value(node.value) bounds(node.location) on_assign(target, value) end
#visit_constant_and_write_node(node)
Foo &&= bar ^^^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 1713
def visit_constant_and_write_node(node) bounds(node.name_loc) target = on_var_field(on_const(node.name.to_s)) bounds(node.operator_loc) operator = on_op("&&=") value = visit_write_value(node.value) bounds(node.location) on_opassign(target, operator, value) end
#visit_constant_operator_write_node(node)
Foo += bar ^^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 1699
def visit_constant_operator_write_node(node) bounds(node.name_loc) target = on_var_field(on_const(node.name.to_s)) bounds(node.binary_operator_loc) operator = on_op("#{node.binary_operator}=") value = visit_write_value(node.value) bounds(node.location) on_opassign(target, operator, value) end
#visit_constant_or_write_node(node)
Foo ||= bar ^^^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 1727
def visit_constant_or_write_node(node) bounds(node.name_loc) target = on_var_field(on_const(node.name.to_s)) bounds(node.operator_loc) operator = on_op("||=") value = visit_write_value(node.value) bounds(node.location) on_opassign(target, operator, value) end
#visit_constant_path_and_write_node(node)
Foo::Bar &&= baz
^^^^^^^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 1833
def visit_constant_path_and_write_node(node) target = visit_constant_path_write_node_target(node.target) bounds(node.operator_loc) operator = on_op("&&=") value = visit_write_value(node.value) bounds(node.location) on_opassign(target, operator, value) end
#visit_constant_path_node(node)
Foo::Bar
^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 1748
def visit_constant_path_node(node) if node.parent.nil? if node.delimiter_loc bounds(node.delimiter_loc) on_op("::") end bounds(node.name_loc) child = on_const(node.name.to_s) bounds(node.location) on_top_const_ref(child) else parent = visit(node.parent) bounds(node.delimiter_loc) on_op("::") bounds(node.name_loc) child = on_const(node.name.to_s) bounds(node.location) on_const_path_ref(parent, child) end end
#visit_constant_path_operator_write_node(node)
Foo::Bar += baz
^^^^^^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 1820
def visit_constant_path_operator_write_node(node) target = visit_constant_path_write_node_target(node.target) bounds(node.binary_operator_loc) operator = on_op("#{node.binary_operator}=") value = visit_write_value(node.value) bounds(node.location) on_opassign(target, operator, value) end
#visit_constant_path_or_write_node(node)
Foo::Bar ||= baz
^^^^^^^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 1846
def visit_constant_path_or_write_node(node) target = visit_constant_path_write_node_target(node.target) bounds(node.operator_loc) operator = on_op("||=") value = visit_write_value(node.value) bounds(node.location) on_opassign(target, operator, value) end
#visit_constant_path_target_node(node)
Foo::Bar, = baz
^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 1859
def visit_constant_path_target_node(node) visit_constant_path_write_node_target(node) end
#visit_constant_path_write_node(node)
Foo::Bar = 1
^^^^^^^^^^^^
Foo::Foo, Bar::Bar = 1
^^^^^^^^ ^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 1779
def visit_constant_path_write_node(node) target = visit_constant_path_write_node_target(node.target) bounds(node.operator_loc) on_op("=") value = visit_write_value(node.value) bounds(node.location) on_assign(target, value) end
#visit_constant_path_write_node_target(node) (private)
Visit a constant path that is part of a write node.
# File 'lib/prism/translation/ripper.rb', line 1792
private def visit_constant_path_write_node_target(node) if node.parent.nil? if node.delimiter_loc bounds(node.delimiter_loc) on_op("::") end bounds(node.name_loc) child = on_const(node.name.to_s) bounds(node.location) on_top_const_field(child) else parent = visit(node.parent) bounds(node.delimiter_loc) on_op("::") bounds(node.name_loc) child = on_const(node.name.to_s) bounds(node.location) on_const_path_field(parent, child) end end
#visit_constant_read_node(node)
Foo ^^^
# File 'lib/prism/translation/ripper.rb', line 1674
def visit_constant_read_node(node) bounds(node.location) on_var_ref(on_const(node.name.to_s)) end
#visit_constant_target_node(node)
Foo, = bar ^^^
# File 'lib/prism/translation/ripper.rb', line 1741
def visit_constant_target_node(node) bounds(node.location) on_var_field(on_const(node.name.to_s)) end
#visit_constant_write_node(node)
Foo = 1 ^^^^^^^
Foo, Bar = 1 ^^^ ^^^
# File 'lib/prism/translation/ripper.rb', line 1684
def visit_constant_write_node(node) bounds(node.name_loc) target = on_var_field(on_const(node.name.to_s)) bounds(node.operator_loc) on_op("=") value = visit_write_value(node.value) bounds(node.location) on_assign(target, value) end
#visit_def_node(node)
def foo; end ^^^^^^^^^^^^
def self.foo; end ^^^^^^^^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 1868
def visit_def_node(node) bounds(node.def_keyword_loc) on_kw("def") receiver = visit(node.receiver) operator = if !node.operator_loc.nil? bounds(node.operator_loc) visit_token(node.operator) end bounds(node.name_loc) name = visit_token(node.name_loc.slice) if node.lparen_loc bounds(node.lparen_loc) on_lparen("(") end parameters = if node.parameters.nil? bounds(node.location) on_params(nil, nil, nil, nil, nil, nil, nil) else visit(node.parameters) end if !node.lparen_loc.nil? bounds(node.rparen_loc) on_rparen(")") bounds(node.lparen_loc) parameters = on_paren(parameters) end if node.equal_loc bounds(node.equal_loc) on_op("=") end bodystmt = if node.equal_loc.nil? visit_body_node(node.rparen_loc || node.end_keyword_loc, node.body) else body = visit(node.body.body.first) bounds(node.body.location) on_bodystmt(body, nil, nil, nil) end if node.end_keyword_loc bounds(node.end_keyword_loc) on_kw("end") end bounds(node.location) if receiver on_defs(receiver, operator, name, parameters, bodystmt) else on_def(name, parameters, bodystmt) end end
#visit_defined_node(node)
defined? a ^^^^^^^^^^
defined?(a) ^^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 1935
def visit_defined_node(node) bounds(node.keyword_loc) on_kw("defined?") if node.lparen_loc bounds(node.lparen_loc) on_lparen("(") end expression = visit(node.value) if node.rparen_loc bounds(node.rparen_loc) on_rparen(")") end # Very weird circumstances here where something like: # # defined? # (1) # # gets parsed in Ruby as having only the `1` expression but in Ripper it # gets parsed as having a parentheses node. In this case we need to # synthesize that node to match Ripper's behavior. if node.lparen_loc && node.keyword_loc.join(node.lparen_loc).slice.include?("\n") bounds(node.lparen_loc.join(node.rparen_loc)) expression = on_paren(on_stmts_add(on_stmts_new, expression)) end bounds(node.location) on_defined(expression) end
#visit_destructured_parameter_node(node) (private)
Visit a destructured positional parameter node.
# File 'lib/prism/translation/ripper.rb', line 3199
private def visit_destructured_parameter_node(node) if node.lparen_loc bounds(node.lparen_loc) on_lparen("(") end bounds(node.location) targets = visit_multi_target_node_targets(node.lefts, node.rest, node.rights, false) if node.rparen_loc bounds(node.rparen_loc) on_rparen(")") end bounds(node.lparen_loc) on_mlhs_paren(targets) end
#visit_else_node(node)
if foo then bar else baz end ^^^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 1970
def visit_else_node(node) bounds(node.else_keyword_loc) on_kw("else") statements = if node.statements.nil? [nil] else body = node.statements.body body.unshift(nil) if void_stmt?(node.else_keyword_loc, node.statements.body[0].location, false) body end else_statements = visit_statements_node_body(statements) bounds(node.end_keyword_loc) on_kw("end") bounds(node.location) on_else(else_statements) end
#visit_embedded_statements_node(node)
"foo #bar"
^^^^^^
# File 'lib/prism/translation/ripper.rb', line 1993
def (node) bounds(node.opening_loc) on_embexpr_beg(node.opening) statements = if node.statements.nil? bounds(node.location) on_stmts_add(on_stmts_new, on_void_stmt) else visit(node.statements) end bounds(node.closing_loc) on_embexpr_end(node.closing) bounds(node.location) on_string_embexpr(statements) end
#visit_embedded_variable_node(node)
"foo #@bar"
^^^^^
#visit_ensure_node(node)
Visit an EnsureNode node.
# File 'lib/prism/translation/ripper.rb', line 2025
def visit_ensure_node(node) bounds(node.ensure_keyword_loc) on_kw("ensure") statements = if node.statements.nil? [nil] else body = node.statements.body body.unshift(nil) if void_stmt?(node.ensure_keyword_loc, body[0].location, false) body end statements = visit_statements_node_body(statements) bounds(node.location) on_ensure(statements) end
#visit_error_recovery_node(node)
A node that is missing from the syntax tree. This is only used in the case of a syntax error.
# File 'lib/prism/translation/ripper.rb', line 2957
def visit_error_recovery_node(node) raise "Cannot visit error recovery nodes directly." end
#visit_false_node(node)
false ^^^^^
# File 'lib/prism/translation/ripper.rb', line 2046
def visit_false_node(node) bounds(node.location) on_var_ref(on_kw("false")) end
#visit_find_pattern_node(node)
foo => [*, bar, *] ^^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 2053
def visit_find_pattern_node(node) constant = visit(node.constant) if node.opening_loc bounds(node.opening_loc) node.opening == "[" ? on_lbracket("[") : on_lparen("(") end bounds(node.left.operator_loc) on_op("*") left = if node.left.expression.nil? bounds(node.left.location) on_var_field(nil) else visit(node.left.expression) end requireds = visit_all(node.requireds) if node.requireds.any? bounds(node.right.operator_loc) on_op("*") right = if node.right.expression.nil? bounds(node.right.location) on_var_field(nil) else visit(node.right.expression) end if node.closing_loc bounds(node.closing_loc) node.closing == "]" ? on_rbracket("]") : on_rparen(")") end bounds(node.location) on_fndptn(constant, left, requireds, right) end
#visit_flip_flop_node(node)
if foo .. bar; end ^^^^^^^^^^
#visit_float_node(node)
1.0 ^^^
# File 'lib/prism/translation/ripper.rb', line 2112
def visit_float_node(node) visit_number_node(node) { |text| on_float(text) } end
#visit_for_node(node)
for foo in bar do end ^^^^^^^^^^^^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 2118
def visit_for_node(node) bounds(node.for_keyword_loc) on_kw("for") index = visit(node.index) bounds(node.in_keyword_loc) on_kw("in") collection = visit(node.collection) if node.do_keyword_loc bounds(node.do_keyword_loc) on_kw("do") end statements = if node.statements.nil? bounds(node.location) on_stmts_add(on_stmts_new, on_void_stmt) else visit(node.statements) end bounds(node.end_keyword_loc) on_kw("end") bounds(node.location) on_for(index, collection, statements) end
#visit_forwarding_arguments_node(node)
def foo(...); bar(...); end ^^^
# File 'lib/prism/translation/ripper.rb', line 2148
def visit_forwarding_arguments_node(node) bounds(node.location) on_op("...") on_args_forward end
#visit_forwarding_parameter_node(node)
def foo(...); end ^^^
# File 'lib/prism/translation/ripper.rb', line 2156
def visit_forwarding_parameter_node(node) bounds(node.location) on_op("...") on_args_forward end
#visit_forwarding_super_node(node)
super ^^^^^
super {} ^^^^^^^^
#visit_global_variable_and_write_node(node)
$foo &&= bar ^^^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 2223
def visit_global_variable_and_write_node(node) bounds(node.name_loc) target = on_var_field(on_gvar(node.name.to_s)) bounds(node.operator_loc) operator = on_op("&&=") value = visit_write_value(node.value) bounds(node.location) on_opassign(target, operator, value) end
#visit_global_variable_operator_write_node(node)
$foo += bar ^^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 2209
def visit_global_variable_operator_write_node(node) bounds(node.name_loc) target = on_var_field(on_gvar(node.name.to_s)) bounds(node.binary_operator_loc) operator = on_op("#{node.binary_operator}=") value = visit_write_value(node.value) bounds(node.location) on_opassign(target, operator, value) end
#visit_global_variable_or_write_node(node)
$foo ||= bar ^^^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 2237
def visit_global_variable_or_write_node(node) bounds(node.name_loc) target = on_var_field(on_gvar(node.name.to_s)) bounds(node.operator_loc) operator = on_op("||=") value = visit_write_value(node.value) bounds(node.location) on_opassign(target, operator, value) end
#visit_global_variable_read_node(node)
$foo ^^^^
# File 'lib/prism/translation/ripper.rb', line 2184
def visit_global_variable_read_node(node) bounds(node.location) on_var_ref(on_gvar(node.name.to_s)) end
#visit_global_variable_target_node(node)
$foo, = bar ^^^^
# File 'lib/prism/translation/ripper.rb', line 2251
def visit_global_variable_target_node(node) bounds(node.location) on_var_field(on_gvar(node.name.to_s)) end
#visit_global_variable_write_node(node)
$foo = 1 ^^^^^^^^
$foo, $bar = 1 ^^^^ ^^^^
# File 'lib/prism/translation/ripper.rb', line 2194
def visit_global_variable_write_node(node) bounds(node.name_loc) target = on_var_field(on_gvar(node.name.to_s)) bounds(node.operator_loc) on_op("=") value = visit_write_value(node.value) bounds(node.location) on_assign(target, value) end
#visit_hash_node(node)
{} ^^
# File 'lib/prism/translation/ripper.rb', line 2258
def visit_hash_node(node) bounds(node.opening_loc) on_lbrace("{") elements = if node.elements.any? args = visit_all(node.elements) bounds(node.elements.first.location) on_assoclist_from_args(args) end bounds(node.closing_loc) on_rbrace("}") bounds(node.location) on_hash(elements) end
#visit_hash_pattern_node(node)
foo => {} ^^
# File 'lib/prism/translation/ripper.rb', line 2278
def visit_hash_pattern_node(node) constant = visit(node.constant) if node.constant bounds(node.opening_loc) node.opening == "[" ? on_lbracket("[") : on_lparen("(") elsif node.opening_loc bounds(node.opening_loc) on_lbrace("{") end elements = if node.elements.any? || !node.rest.nil? node.elements.map do |element| [ if (key = element.key).opening_loc.nil? visit(key) else bounds(key.value_loc) if (value = key.value).empty? on_string_content else on_string_add(on_string_content, on_tstring_content(value)) end end, visit(element.value) ] end end rest = case node.rest when AssocSplatNode bounds(node.rest.operator_loc) on_op("**") visit(node.rest.value) when NoKeywordsParameterNode bounds(node.rest.location) on_var_field(visit(node.rest)) end if node.constant bounds(node.closing_loc) node.closing == "]" ? on_rbracket("]") : on_rparen(")") elsif node.closing_loc bounds(node.closing_loc) on_rbrace("}") end bounds(node.location) on_hshptn(constant, elements, rest) end
#visit_heredoc_node(parts, base) (private)
Visit a string that is expressed using a <<~ heredoc.
# File 'lib/prism/translation/ripper.rb', line 3684
private def visit_heredoc_node(parts, base) common_whitespace = visit_heredoc_node_whitespace(parts) if common_whitespace == 0 bounds(parts.first.location) string = [] result = base parts.each do |part| if part.is_a?(StringNode) if string.empty? string = [part] else string << part end else unless string.empty? bounds(string[0].location) result = yield result, on_tstring_content(string.map(&:content).join) string = [] end result = yield result, visit(part) end end unless string.empty? bounds(string[0].location) result = yield result, on_tstring_content(string.map(&:content).join) end result else bounds(parts.first.location) result = parts.inject(base) do |string_content, part| yield string_content, visit_string_content(part) end bounds(parts.first.location) on_heredoc_dedent(result, common_whitespace) end end
#visit_heredoc_node_whitespace(parts) (private)
Ripper gives back the escaped string content but strips out the common
leading whitespace. ::Prism gives back the unescaped string content and
a location for the escaped string content. Unfortunately these don't
work well together, so here we need to re-derive the common leading
whitespace.
# File 'lib/prism/translation/ripper.rb', line 3659
private def visit_heredoc_node_whitespace(parts) common_whitespace = nil dedent_next = true parts.each do |part| if part.is_a?(StringNode) if dedent_next && !(content = part.content).chomp.empty? common_whitespace = [ common_whitespace || Float::INFINITY, content[/\A\s*/].each_char.inject(0) do |part_whitespace, char| char == "\t" ? ((part_whitespace / 8 + 1) * 8) : (part_whitespace + 1) end ].min end dedent_next = true else dedent_next = false end end common_whitespace || 0 end
#visit_heredoc_string_node(node) (private)
Visit a heredoc node that is representing a string.
# File 'lib/prism/translation/ripper.rb', line 3730
private def visit_heredoc_string_node(node) bounds(node.location) visit_heredoc_node(node.parts, on_string_content) do |parts, part| on_string_add(parts, part) end end
#visit_heredoc_x_string_node(node) (private)
Visit a heredoc node that is representing an xstring.
# File 'lib/prism/translation/ripper.rb', line 3738
private def visit_heredoc_x_string_node(node) bounds(node.location) visit_heredoc_node(node.parts, on_xstring_new) do |parts, part| on_xstring_add(parts, part) end end
#visit_if_node(node)
if foo then bar end ^^^^^^^^^^^^^^^^^^^
bar if foo ^^^^^^^^^^
foo ? bar : baz ^^^^^^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 2338
def visit_if_node(node) if node.then_keyword == "?" predicate = visit(node.predicate) bounds(node.then_keyword_loc) on_op("?") truthy = visit(node.statements.body.first) bounds(node.subsequent.else_keyword_loc) on_op(":") falsy = visit(node.subsequent.statements.body.first) bounds(node.location) on_ifop(predicate, truthy, falsy) elsif node.statements.nil? || (node.predicate.location.start_offset < node.statements.location.start_offset) bounds(node.if_keyword_loc) on_kw(node.if_keyword) predicate = visit(node.predicate) if node.then_keyword_loc && node.then_keyword != "?" bounds(node.then_keyword_loc) on_kw("then") end statements = if node.statements.nil? bounds(node.location) on_stmts_add(on_stmts_new, on_void_stmt) else visit(node.statements) end subsequent = visit(node.subsequent) if node.end_keyword_loc && !node.subsequent bounds(node.end_keyword_loc) on_kw("end") end bounds(node.location) if node.if_keyword == "if" on_if(predicate, statements, subsequent) else on_elsif(predicate, statements, subsequent) end else statements = visit(node.statements.body.first) bounds(node.if_keyword_loc) on_kw(node.if_keyword) predicate = visit(node.predicate) bounds(node.location) on_if_mod(predicate, statements) end end
#visit_imaginary_node(node)
1i ^^
# File 'lib/prism/translation/ripper.rb', line 2395
def visit_imaginary_node(node) visit_number_node(node) { |text| on_imaginary(text) } end
#visit_implicit_node(node)
{ foo: } ^^^^
# File 'lib/prism/translation/ripper.rb', line 2401
def visit_implicit_node(node) end
#visit_implicit_rest_node(node)
foo { |bar,| } ^
# File 'lib/prism/translation/ripper.rb', line 2406
def visit_implicit_rest_node(node) bounds(node.location) on_excessed_comma end
#visit_in_node(node)
case foo; in bar; end ^^^^^^^^^^^^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 2413
def visit_in_node(node) # This is a special case where we're not going to call on_in directly # because we don't have access to the subsequent. Instead, we'll return # the component parts and let the parent node handle it. bounds(node.in_loc) on_kw("in") pattern = visit_pattern_node(node.pattern) if node.then_loc bounds(node.then_loc) on_kw("then") end statements = if node.statements.nil? bounds(node.location) on_stmts_add(on_stmts_new, on_void_stmt) else visit(node.statements) end [pattern, statements] end
#visit_index_and_write_node(node)
foo &&= baz ^^^^^^^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 2462
def visit_index_and_write_node(node) receiver = visit(node.receiver) bounds(node.opening_loc) on_lbracket("[") arguments, _ = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.closing_loc)) bounds(node.closing_loc) on_rbracket("]") bounds(node.location) target = on_aref_field(receiver, arguments) bounds(node.operator_loc) operator = on_op("&&=") value = visit_write_value(node.value) bounds(node.location) on_opassign(target, operator, value) end
#visit_index_operator_write_node(node)
foo += baz ^^^^^^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 2438
def visit_index_operator_write_node(node) receiver = visit(node.receiver) bounds(node.opening_loc) on_lbracket("[") arguments, _ = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.closing_loc)) bounds(node.closing_loc) on_rbracket("]") bounds(node.location) target = on_aref_field(receiver, arguments) bounds(node.binary_operator_loc) operator = on_op("#{node.binary_operator}=") value = visit_write_value(node.value) bounds(node.location) on_opassign(target, operator, value) end
#visit_index_or_write_node(node)
foo ||= baz ^^^^^^^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 2486
def visit_index_or_write_node(node) receiver = visit(node.receiver) bounds(node.opening_loc) on_lbracket("[") arguments, _ = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.closing_loc)) bounds(node.closing_loc) on_rbracket("]") bounds(node.location) target = on_aref_field(receiver, arguments) bounds(node.operator_loc) operator = on_op("||=") value = visit_write_value(node.value) bounds(node.location) on_opassign(target, operator, value) end
#visit_index_target_node(node)
foo, = 1 ^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 2510
def visit_index_target_node(node) receiver = visit(node.receiver) bounds(node.opening_loc) on_lbracket("[") arguments, _ = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.closing_loc)) bounds(node.closing_loc) on_rbracket("]") bounds(node.location) on_aref_field(receiver, arguments) end
#visit_instance_variable_and_write_node(node)
^^^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 2563
def visit_instance_variable_and_write_node(node) bounds(node.name_loc) target = on_var_field(on_ivar(node.name.to_s)) bounds(node.operator_loc) operator = on_op("&&=") value = visit_write_value(node.value) bounds(node.location) on_opassign(target, operator, value) end
#visit_instance_variable_operator_write_node(node)
^^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 2549
def visit_instance_variable_operator_write_node(node) bounds(node.name_loc) target = on_var_field(on_ivar(node.name.to_s)) bounds(node.binary_operator_loc) operator = on_op("#{node.binary_operator}=") value = visit_write_value(node.value) bounds(node.location) on_opassign(target, operator, value) end
#visit_instance_variable_or_write_node(node)
^^^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 2577
def visit_instance_variable_or_write_node(node) bounds(node.name_loc) target = on_var_field(on_ivar(node.name.to_s)) bounds(node.operator_loc) operator = on_op("||=") value = visit_write_value(node.value) bounds(node.location) on_opassign(target, operator, value) end
#visit_instance_variable_read_node(node)
^^^^
# File 'lib/prism/translation/ripper.rb', line 2527
def visit_instance_variable_read_node(node) bounds(node.location) on_var_ref(on_ivar(node.name.to_s)) end
#visit_instance_variable_target_node(node)
@foo, = bar ^^^^
# File 'lib/prism/translation/ripper.rb', line 2591
def visit_instance_variable_target_node(node) bounds(node.location) on_var_field(on_ivar(node.name.to_s)) end
#visit_instance_variable_write_node(node)
^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 2534
def visit_instance_variable_write_node(node) bounds(node.name_loc) target = on_var_field(on_ivar(node.name.to_s)) bounds(node.operator_loc) on_op("=") value = visit_write_value(node.value) bounds(node.location) on_assign(target, value) end
#visit_integer_node(node)
1 ^
# File 'lib/prism/translation/ripper.rb', line 2598
def visit_integer_node(node) visit_number_node(node) { |text| on_int(text) } end
#visit_interpolated_match_last_line_node(node)
if /foo #bar/ then end
^^^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 2604
def visit_interpolated_match_last_line_node(node) bounds(node.opening_loc) on_regexp_beg(node.opening) bounds(node.parts.first.location) parts = node.parts.inject(on_regexp_new) do |content, part| on_regexp_add(content, visit_string_content(part)) end bounds(node.closing_loc) closing = on_regexp_end(node.closing) bounds(node.location) on_regexp_literal(parts, closing) end
#visit_interpolated_regular_expression_node(node)
/foo #bar/
^^^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 2623
def visit_interpolated_regular_expression_node(node) bounds(node.opening_loc) on_regexp_beg(node.opening) bounds(node.parts.first.location) parts = node.parts.inject(on_regexp_new) do |content, part| on_regexp_add(content, visit_string_content(part)) end bounds(node.closing_loc) closing = on_regexp_end(node.closing) bounds(node.location) on_regexp_literal(parts, closing) end
#visit_interpolated_string_node(node)
"foo #bar"
^^^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 2642
def visit_interpolated_string_node(node) with_string_bounds(node) do if node.opening&.start_with?("<<~") heredoc = visit_heredoc_string_node(node) bounds(node.location) on_string_literal(heredoc) elsif !node.heredoc? && node.parts.length > 1 && node.parts.any? { |part| (part.is_a?(StringNode) || part.is_a?(InterpolatedStringNode)) && !part.opening_loc.nil? } first, *rest = node.parts rest.inject(visit(first)) do |content, part| concat = visit(part) bounds(part.location) on_string_concat(content, concat) end else bounds(node.parts.first.location) parts = node.parts.inject(on_string_content) do |content, part| on_string_add(content, visit_string_content(part)) end bounds(node.location) on_string_literal(parts) end end end
#visit_interpolated_symbol_node(node)
:"foo #bar"
^^^^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 2672
def visit_interpolated_symbol_node(node) with_string_bounds(node) do bounds(node.parts.first.location) parts = node.parts.inject(on_string_content) do |content, part| on_string_add(content, visit_string_content(part)) end bounds(node.location) on_dyna_symbol(parts) end end
#visit_interpolated_x_string_node(node)
foo #{bar}
^^^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 2687
def visit_interpolated_x_string_node(node) with_string_bounds(node) do if node.opening.start_with?("<<~") heredoc = visit_heredoc_x_string_node(node) bounds(node.location) on_xstring_literal(heredoc) else bounds(node.parts.first.location) parts = node.parts.inject(on_xstring_new) do |content, part| on_xstring_add(content, visit_string_content(part)) end bounds(node.location) on_xstring_literal(parts) end end end
#visit_it_local_variable_read_node(node)
-> { it } ^^
# File 'lib/prism/translation/ripper.rb', line 2719
def visit_it_local_variable_read_node(node) bounds(node.location) on_vcall(on_ident(node.slice)) end
#visit_it_parameters_node(node)
-> { it } ^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 2726
def visit_it_parameters_node(node) end
#visit_keyword_hash_node(node)
foo(bar: baz) ^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 2731
def visit_keyword_hash_node(node) elements = visit_all(node.elements) bounds(node.location) (elements) end
#visit_keyword_rest_parameter_node(node)
def foo(**bar); end ^^^^^
def foo(**); end ^^
# File 'lib/prism/translation/ripper.rb', line 2743
def visit_keyword_rest_parameter_node(node) bounds(node.operator_loc) on_op("**") if node.name_loc.nil? bounds(node.location) on_kwrest_param(nil) else bounds(node.name_loc) name = on_ident(node.name.to_s) bounds(node.location) on_kwrest_param(name) end end
#visit_lambda_node(node)
-> {}
# File 'lib/prism/translation/ripper.rb', line 2760
def visit_lambda_node(node) bounds(node.operator_loc) on_tlambda(node.operator) parameters = if node.parameters.is_a?(BlockParametersNode) if node.parameters.opening_loc bounds(node.parameters.opening_loc) on_lparen("(") end # Ripper does not track block-locals within lambdas, so we skip # directly to the parameters here. params = if node.parameters.parameters.nil? bounds(node.location) on_params(nil, nil, nil, nil, nil, nil, nil) else visit(node.parameters.parameters) end visit_all(node.parameters.locals) if node.parameters.closing_loc bounds(node.parameters.closing_loc) on_rparen(")") end if node.parameters.opening_loc.nil? params else bounds(node.parameters.opening_loc) on_paren(params) end else bounds(node.location) on_params(nil, nil, nil, nil, nil, nil, nil) end braces = node.opening == "{" bounds(node.opening_loc) if braces on_tlambeg(node.opening) else on_kw("do") end body = case node.body when nil bounds(node.location) stmts = on_stmts_add(on_stmts_new, on_void_stmt) bounds(node.location) braces ? stmts : on_bodystmt(stmts, nil, nil, nil) when StatementsNode stmts = node.body.body stmts.unshift(nil) if void_stmt?(node.parameters&.location || node.opening_loc, node.body.location, false) stmts = visit_statements_node_body(stmts) bounds(node.body.location) braces ? stmts : on_bodystmt(stmts, nil, nil, nil) when BeginNode visit_body_node(node.opening_loc, node.body) else raise end bounds(node.closing_loc) if braces on_rbrace("}") else on_kw("end") end bounds(node.location) on_lambda(parameters, body) end
#visit_local_variable_and_write_node(node)
foo &&= bar ^^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 2877
def visit_local_variable_and_write_node(node) bounds(node.name_loc) target = on_var_field(on_ident(node.name_loc.slice)) bounds(node.operator_loc) operator = on_op("&&=") value = visit_write_value(node.value) bounds(node.location) on_opassign(target, operator, value) end
#visit_local_variable_operator_write_node(node)
foo += bar ^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 2863
def visit_local_variable_operator_write_node(node) bounds(node.name_loc) target = on_var_field(on_ident(node.name_loc.slice)) bounds(node.binary_operator_loc) operator = on_op("#{node.binary_operator}=") value = visit_write_value(node.value) bounds(node.location) on_opassign(target, operator, value) end
#visit_local_variable_or_write_node(node)
foo ||= bar ^^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 2891
def visit_local_variable_or_write_node(node) bounds(node.name_loc) target = on_var_field(on_ident(node.name_loc.slice)) bounds(node.operator_loc) operator = on_op("||=") value = visit_write_value(node.value) bounds(node.location) on_opassign(target, operator, value) end
#visit_local_variable_read_node(node)
foo ^^^
# File 'lib/prism/translation/ripper.rb', line 2841
def visit_local_variable_read_node(node) bounds(node.location) on_var_ref(on_ident(node.slice)) end
#visit_local_variable_target_node(node)
foo, = bar ^^^
# File 'lib/prism/translation/ripper.rb', line 2905
def visit_local_variable_target_node(node) bounds(node.location) on_var_field(on_ident(node.name.to_s)) end
#visit_local_variable_write_node(node)
foo = 1 ^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 2848
def visit_local_variable_write_node(node) bounds(node.name_loc) target = on_var_field(on_ident(node.name_loc.slice)) bounds(node.operator_loc) on_op("=") value = visit_write_value(node.value) bounds(node.location) on_assign(target, value) end
#visit_match_last_line_node(node)
if /foo/ then end ^^^^^
# File 'lib/prism/translation/ripper.rb', line 2912
def visit_match_last_line_node(node) bounds(node.opening_loc) on_regexp_beg(node.opening) bounds(node.content_loc) tstring_content = on_tstring_content(node.content) bounds(node.closing_loc) closing = on_regexp_end(node.closing) on_regexp_literal(on_regexp_add(on_regexp_new, tstring_content), closing) end
#visit_match_predicate_node(node)
foo in bar ^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 2927
def visit_match_predicate_node(node) value = visit(node.value) bounds(node.operator_loc) on_kw("in") pattern = on_in(visit_pattern_node(node.pattern), nil, nil) on_case(value, pattern) end
#visit_match_required_node(node)
foo => bar ^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 2938
def visit_match_required_node(node) value = visit(node.value) bounds(node.operator_loc) on_op("=>") pattern = on_in(visit_pattern_node(node.pattern), nil, nil) on_case(value, pattern) end
#visit_match_write_node(node)
/(?
# File 'lib/prism/translation/ripper.rb', line 2951
def visit_match_write_node(node) visit(node.call) end
#visit_module_node(node)
module Foo; end ^^^^^^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 2963
def visit_module_node(node) bounds(node.module_keyword_loc) on_kw("module") constant_path = if node.constant_path.is_a?(ConstantReadNode) bounds(node.constant_path.location) on_const_ref(on_const(node.constant_path.name.to_s)) else visit(node.constant_path) end bodystmt = visit_body_node(node.constant_path.location, node.body, true) bounds(node.end_keyword_loc) on_kw("end") bounds(node.location) on_module(constant_path, bodystmt) end
#visit_multi_target_node(node)
(foo, bar), bar = qux ^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 2986
def visit_multi_target_node(node) if node.lparen_loc bounds(node.lparen_loc) on_lparen("(") end bounds(node.location) targets = visit_multi_target_node_targets(node.lefts, node.rest, node.rights, true) if node.rparen_loc bounds(node.rparen_loc) on_rparen(")") end if node.lparen_loc.nil? targets else bounds(node.lparen_loc) on_mlhs_paren(targets) end end
#visit_multi_target_node_targets(lefts, rest, rights, skippable) (private)
Visit the targets of a multi-target node.
# File 'lib/prism/translation/ripper.rb', line 3009
private def visit_multi_target_node_targets(lefts, rest, rights, skippable) if skippable && lefts.length == 1 && lefts.first.is_a?(MultiTargetNode) && rest.nil? && rights.empty? return visit(lefts.first) end mlhs = on_mlhs_new lefts.each do |left| bounds(left.location) mlhs = on_mlhs_add(mlhs, visit(left)) end case rest when nil # do nothing when ImplicitRestNode # these do not get put into the generated tree bounds(rest.location) on_excessed_comma else bounds(rest.location) mlhs = on_mlhs_add_star(mlhs, visit(rest)) end if rights.any? bounds(rights.first.location) post = on_mlhs_new rights.each do |right| bounds(right.location) post = on_mlhs_add(post, visit(right)) end mlhs = on_mlhs_add_post(mlhs, post) end mlhs end
#visit_multi_write_node(node)
foo, bar = baz ^^^^^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 3050
def visit_multi_write_node(node) if node.lparen_loc bounds(node.lparen_loc) on_lparen("(") end bounds(node.location) targets = visit_multi_target_node_targets(node.lefts, node.rest, node.rights, true) if node.rparen_loc bounds(node.rparen_loc) on_rparen(")") end bounds(node.operator_loc) on_op("=") unless node.lparen_loc.nil? bounds(node.lparen_loc) targets = on_mlhs_paren(targets) end value = visit_write_value(node.value) bounds(node.location) on_massign(targets, value) end
#visit_next_node(node)
next ^^^^
next foo ^^^^^^^^
#visit_nil_node(node)
nil ^^^
# File 'lib/prism/translation/ripper.rb', line 3100
def visit_nil_node(node) bounds(node.location) on_var_ref(on_kw("nil")) end
#visit_no_block_parameter_node(node)
def foo(&nil); end ^^^^
#visit_no_keywords_parameter_node(node)
def foo(**nil); end ^^^^^
#visit_number_node(node) (private)
Visit a node that represents a number. We need to explicitly handle the unary - operator.
# File 'lib/prism/translation/ripper.rb', line 4080
def visit_number_node(node) slice = node.slice location = node.location if slice[0] == "-" bounds(location.copy(length: 1)) on_op("-") bounds(location.copy(start_offset: location.start_offset + 1)) value = yield slice[1..-1] bounds(node.location) on_unary(:-@, value) else bounds(location) yield slice end end
#visit_numbered_parameters_node(node)
-> { _1 + _2 } ^^^^^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 3131
def visit_numbered_parameters_node(node) end
#visit_numbered_reference_read_node(node)
$1 ^^
# File 'lib/prism/translation/ripper.rb', line 3136
def visit_numbered_reference_read_node(node) bounds(node.location) on_backref(node.slice) end
#visit_optional_keyword_parameter_node(node)
def foo(bar: baz); end ^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 3143
def visit_optional_keyword_parameter_node(node) bounds(node.name_loc) name = on_label("#{node.name}:") value = visit(node.value) [name, value] end
#visit_optional_parameter_node(node)
def foo(bar = 1); end ^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 3153
def visit_optional_parameter_node(node) bounds(node.name_loc) name = visit_token(node.name.to_s) bounds(node.operator_loc) on_op("=") value = visit(node.value) [name, value] end
#visit_or_node(node)
a or b ^^^^^^
#visit_parameters_node(node)
def foo(bar, *baz); end ^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 3185
def visit_parameters_node(node) requireds = node.requireds.map { |required| required.is_a?(MultiTargetNode) ? visit_destructured_parameter_node(required) : visit(required) } if node.requireds.any? optionals = visit_all(node.optionals) if node.optionals.any? rest = visit(node.rest) posts = node.posts.map { |post| post.is_a?(MultiTargetNode) ? visit_destructured_parameter_node(post) : visit(post) } if node.posts.any? keywords = visit_all(node.keywords) if node.keywords.any? keyword_rest = visit(node.keyword_rest) block = visit(node.block) bounds(node.location) on_params(requireds, optionals, rest, posts, keywords, keyword_rest, block) end
#visit_parentheses_node(node)
() ^^
(1) ^^^
#visit_pattern_node(node) (private)
Visit a pattern within a pattern match. This is used to bypass the parenthesis node that can be used to wrap patterns.
# File 'lib/prism/translation/ripper.rb', line 653
private def visit_pattern_node(node) if node.is_a?(ParenthesesNode) bounds(node.opening_loc) on_lparen("(") result = visit(node.body) bounds(node.closing_loc) on_rparen(")") result else visit(node) end end
#visit_pinned_expression_node(node)
foo => ^(bar) ^^^^^^
#visit_pinned_variable_node(node)
foo = 1 and bar => ^foo ^^^^
# File 'lib/prism/translation/ripper.rb', line 3257
def visit_pinned_variable_node(node) bounds(node.operator_loc) on_op("^") visit(node.variable) end
#visit_post_execution_node(node)
END {} ^^^^^^
# File 'lib/prism/translation/ripper.rb', line 3266
def visit_post_execution_node(node) bounds(node.keyword_loc) on_kw("END") bounds(node.opening_loc) on_lbrace("{") statements = if node.statements.nil? bounds(node.location) on_stmts_add(on_stmts_new, on_void_stmt) else visit(node.statements) end bounds(node.closing_loc) on_rbrace("}") bounds(node.location) on_END(statements) end
#visit_pre_execution_node(node)
BEGIN {} ^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 3288
def visit_pre_execution_node(node) bounds(node.keyword_loc) on_kw("BEGIN") bounds(node.opening_loc) on_lbrace("{") statements = if node.statements.nil? bounds(node.location) on_stmts_add(on_stmts_new, on_void_stmt) else visit(node.statements) end bounds(node.closing_loc) on_rbrace("}") bounds(node.location) on_BEGIN(statements) end
#visit_program_node(node)
The top-level program node.
# File 'lib/prism/translation/ripper.rb', line 3309
def visit_program_node(node) body = node.statements.body body << nil if body.empty? statements = visit_statements_node_body(body) bounds(node.location) on_program(statements) end
#visit_range_node(node)
0..5 ^^^^
#visit_rational_node(node)
1r ^^
# File 'lib/prism/translation/ripper.rb', line 3338
def visit_rational_node(node) visit_number_node(node) { |text| on_rational(text) } end
#visit_redo_node(node)
redo ^^^^
# File 'lib/prism/translation/ripper.rb', line 3344
def visit_redo_node(node) bounds(node.location) on_kw("redo") on_redo end
#visit_regular_expression_node(node)
/foo/ ^^^^^
# File 'lib/prism/translation/ripper.rb', line 3352
def visit_regular_expression_node(node) bounds(node.opening_loc) on_regexp_beg(node.opening) if node.content.empty? bounds(node.closing_loc) closing = on_regexp_end(node.closing) on_regexp_literal(on_regexp_new, closing) else bounds(node.content_loc) tstring_content = on_tstring_content(node.content) bounds(node.closing_loc) closing = on_regexp_end(node.closing) on_regexp_literal(on_regexp_add(on_regexp_new, tstring_content), closing) end end
#visit_required_keyword_parameter_node(node)
def foo(bar:); end ^^^^
# File 'lib/prism/translation/ripper.rb', line 3374
def visit_required_keyword_parameter_node(node) bounds(node.name_loc) [on_label("#{node.name}:"), false] end
#visit_required_parameter_node(node)
def foo(bar); end ^^^
# File 'lib/prism/translation/ripper.rb', line 3381
def visit_required_parameter_node(node) bounds(node.location) on_ident(node.name.to_s) end
#visit_rescue_modifier_node(node)
foo rescue bar ^^^^^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 3388
def visit_rescue_modifier_node(node) bounds(node.keyword_loc) on_kw("rescue") expression = visit_write_value(node.expression) rescue_expression = visit(node.rescue_expression) bounds(node.location) on_rescue_mod(expression, rescue_expression) end
#visit_rescue_node(node)
begin; rescue; end ^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 3401
def visit_rescue_node(node) bounds(node.keyword_loc) on_kw("rescue") exceptions = case node.exceptions.length when 0 nil when 1 if (exception = node.exceptions.first).is_a?(SplatNode) bounds(exception.location) on_mrhs_add_star(on_mrhs_new, visit(exception)) else [visit(node.exceptions.first)] end else bounds(node.location) length = node.exceptions.length node.exceptions.each_with_index.inject(on_args_new) do |mrhs, (exception, index)| arg = visit(exception) bounds(exception.location) mrhs = on_mrhs_new_from_args(mrhs) if index == length - 1 if exception.is_a?(SplatNode) if index == length - 1 on_mrhs_add_star(mrhs, arg) else on_args_add_star(mrhs, arg) end else if index == length - 1 on_mrhs_add(mrhs, arg) else on_args_add(mrhs, arg) end end end end if node.operator_loc bounds(node.operator_loc) on_op("=>") end reference = visit(node.reference) statements = if node.statements.nil? bounds(node.location) on_stmts_add(on_stmts_new, on_void_stmt) else visit(node.statements) end subsequent = visit(node.subsequent) bounds(node.location) on_rescue(exceptions, reference, statements, subsequent) end
#visit_rest_parameter_node(node)
def foo(*bar); end ^^^^
def foo(*); end ^
# File 'lib/prism/translation/ripper.rb', line 3467
def visit_rest_parameter_node(node) bounds(node.operator_loc) on_op("*") if node.name_loc.nil? bounds(node.location) on_rest_param(nil) else bounds(node.name_loc) on_rest_param(visit_token(node.name.to_s)) end end
#visit_retry_node(node)
retry ^^^^^
# File 'lib/prism/translation/ripper.rb', line 3482
def visit_retry_node(node) bounds(node.location) on_kw("retry") on_retry end
#visit_return_node(node)
return ^^^^^^
return 1 ^^^^^^^^
#visit_self_node(node)
self ^^^^
# File 'lib/prism/translation/ripper.rb', line 3510
def visit_self_node(node) bounds(node.location) on_var_ref(on_kw("self")) end
#visit_singleton_class_node(node)
class << self; end ^^^^^^^^^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 3522
def visit_singleton_class_node(node) bounds(node.class_keyword_loc) on_kw("class") bounds(node.operator_loc) on_op("<<") expression = visit(node.expression) bodystmt = visit_body_node(node.body&.location || node.end_keyword_loc, node.body) bounds(node.end_keyword_loc) on_kw("end") bounds(node.location) on_sclass(expression, bodystmt) end
#visit_source_encoding_node(node)
ENCODING ^^^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 3540
def visit_source_encoding_node(node) bounds(node.location) on_var_ref(on_kw("__ENCODING__")) end
#visit_source_file_node(node)
FILE ^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 3547
def visit_source_file_node(node) bounds(node.location) on_var_ref(on_kw("__FILE__")) end
#visit_source_line_node(node)
LINE ^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 3554
def visit_source_line_node(node) bounds(node.location) on_var_ref(on_kw("__LINE__")) end
#visit_splat_node(node)
foo(*bar) ^^^^
def foo((bar, *baz)); end ^^^^
def foo(); bar(); end ^
# File 'lib/prism/translation/ripper.rb', line 3567
def visit_splat_node(node) bounds(node.operator_loc) on_op("*") visit(node.expression) end
#visit_statements_node(node)
A list of statements.
# File 'lib/prism/translation/ripper.rb', line 3574
def visit_statements_node(node) bounds(node.location) visit_statements_node_body(node.body) end
#visit_statements_node_body(body) (private)
Visit the list of statements of a statements node. We support nil statements in the list. This would normally not be allowed by the structure of the prism parse tree, but we manually add them here so that we can mirror Ripper's void stmt.
# File 'lib/prism/translation/ripper.rb', line 3583
private def visit_statements_node_body(body) body.inject(on_stmts_new) do |stmts, stmt| on_stmts_add(stmts, stmt.nil? ? on_void_stmt : visit(stmt)) end end
#visit_string_content(part) (private)
Visit an individual part of a string-like node.
# File 'lib/prism/translation/ripper.rb', line 2708
private def visit_string_content(part) if part.is_a?(StringNode) bounds(part.content_loc) on_tstring_content(part.content) else visit(part) end end
#visit_string_node(node)
"foo" ^^^^^
# File 'lib/prism/translation/ripper.rb', line 3591
def visit_string_node(node) with_string_bounds(node) do if (content = node.content).empty? bounds(node.location) on_string_literal(on_string_content) elsif (opening = node.opening) == "?" bounds(node.location) on_CHAR("?#{node.content}") elsif opening.start_with?("<<~") heredoc = visit_heredoc_string_node(node.to_interpolated) bounds(node.location) on_string_literal(heredoc) else bounds(node.content_loc) tstring_content = on_tstring_content(content) bounds(node.location) on_string_literal(on_string_add(on_string_content, tstring_content)) end end end
#visit_super_node(node)
super(foo) ^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 3747
def visit_super_node(node) bounds(node.keyword_loc) on_kw("super") if node.lparen_loc bounds(node.lparen_loc) on_lparen("(") end arguments, block_node = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.rparen_loc || node.location)) if node.rparen_loc bounds(node.rparen_loc) on_rparen(")") end block = visit(block_node) if !node.lparen_loc.nil? bounds(node.lparen_loc) arguments = on_arg_paren(arguments) end bounds(node.location) call = on_super(arguments) if block_node bounds(node.block.location) on_method_add_block(call, block) else call end end
#visit_symbol_node(node)
:foo
^^^^
# File 'lib/prism/translation/ripper.rb', line 3783
def visit_symbol_node(node) with_string_bounds(node) do if node.value_loc.nil? bounds(node.location) on_dyna_symbol(on_string_content) elsif (opening = node.opening)&.match?(/^%s|['"]:?$/) bounds(node.value_loc) content = on_string_add(on_string_content, on_tstring_content(node.value)) bounds(node.location) on_dyna_symbol(content) elsif (closing = node.closing) == ":" bounds(node.location) on_label("#{node.value}:") elsif opening.nil? && node.closing_loc.nil? bounds(node.value_loc) on_symbol_literal(visit_token(node.value)) else bounds(node.value_loc) on_symbol_literal(on_symbol(visit_token(node.value))) end end end
#visit_token(token, allow_keywords = true) (private)
Visit the string content of a particular node. This method is used to split into the various token types.
# File 'lib/prism/translation/ripper.rb', line 4053
def visit_token(token, allow_keywords = true) case token when "." on_period(token) when "`" on_backtick(token) when *(allow_keywords ? KEYWORDS : []) on_kw(token) when /^_/ on_ident(token) when /^[[:upper:]]\w*$/ on_const(token) when /^@@/ on_cvar(token) when /^@/ on_ivar(token) when /^\$/ on_gvar(token) when /^[[:punct:]]/ on_op(token) else on_ident(token) end end
#visit_true_node(node)
true ^^^^
# File 'lib/prism/translation/ripper.rb', line 3808
def visit_true_node(node) bounds(node.location) on_var_ref(on_kw("true")) end
#visit_undef_node(node)
undef foo ^^^^^^^^^
#visit_unless_node(node)
unless foo; bar end ^^^^^^^^^^^^^^^^^^^
bar unless foo ^^^^^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 3830
def visit_unless_node(node) if node.statements.nil? || (node.predicate.location.start_offset < node.statements.location.start_offset) bounds(node.keyword_loc) on_kw("unless") predicate = visit(node.predicate) if node.then_keyword_loc bounds(node.then_keyword_loc) on_kw("then") end statements = if node.statements.nil? bounds(node.location) on_stmts_add(on_stmts_new, on_void_stmt) else visit(node.statements) end else_clause = visit(node.else_clause) if node.end_keyword_loc && !node.else_clause bounds(node.end_keyword_loc) on_kw("end") end bounds(node.location) on_unless(predicate, statements, else_clause) else statements = visit(node.statements.body.first) bounds(node.keyword_loc) on_kw("unless") predicate = visit(node.predicate) bounds(node.location) on_unless_mod(predicate, statements) end end
#visit_until_node(node)
until foo; bar end ^^^^^^^^^^^^^^^^^
bar until foo ^^^^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 3871
def visit_until_node(node) bounds(node.keyword_loc) on_kw("until") if node.statements.nil? || (node.predicate.location.start_offset < node.statements.location.start_offset) if node.do_keyword_loc bounds(node.do_keyword_loc) on_kw("do") end predicate = visit(node.predicate) statements = if node.statements.nil? bounds(node.location) on_stmts_add(on_stmts_new, on_void_stmt) else visit(node.statements) end if node.closing_loc bounds(node.closing_loc) on_kw("end") end bounds(node.location) on_until(predicate, statements) else statements = visit(node.statements.body.first) predicate = visit(node.predicate) bounds(node.location) on_until_mod(predicate, statements) end end
#visit_when_node(node)
case foo; when bar; end ^^^^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 3907
def visit_when_node(node) # This is a special case where we're not going to call on_when directly # because we don't have access to the subsequent. Instead, we'll return # the component parts and let the parent node handle it. bounds(node.keyword_loc) on_kw("when") conditions = visit_arguments(node.conditions) if node.then_keyword_loc bounds(node.then_keyword_loc) on_kw("then") end statements = if node.statements.nil? bounds(node.location) on_stmts_add(on_stmts_new, on_void_stmt) else visit(node.statements) end [conditions, statements] end
#visit_while_node(node)
while foo; bar end ^^^^^^^^^^^^^^^^^^
bar while foo ^^^^^^^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 3935
def visit_while_node(node) if node.statements.nil? || (node.predicate.location.start_offset < node.statements.location.start_offset) bounds(node.keyword_loc) on_kw("while") if node.do_keyword_loc bounds(node.do_keyword_loc) on_kw("do") end predicate = visit(node.predicate) if node.closing_loc bounds(node.closing_loc) on_kw("end") end statements = if node.statements.nil? bounds(node.location) on_stmts_add(on_stmts_new, on_void_stmt) else visit(node.statements) end bounds(node.location) on_while(predicate, statements) else statements = visit(node.statements.body.first) bounds(node.keyword_loc) on_kw("while") predicate = visit(node.predicate) bounds(node.location) on_while_mod(predicate, statements) end end
#visit_words_sep(opening_loc, previous, current) (private)
Dispatch words_sep events that contains the whitespace between the elements of list literals.
# File 'lib/prism/translation/ripper.rb', line 825
private def visit_words_sep(opening_loc, previous, current) start_offset = (previous.nil? ? opening_loc : previous.location).end_offset end_offset = current.start_offset length = end_offset - start_offset if length > 0 whitespace = source.byteslice(start_offset, length) current_offset = start_offset whitespace.each_line do |part| bounds(opening_loc.copy(start_offset: current_offset, length: part.bytesize)) on_words_sep(part) current_offset += part.bytesize end end end
#visit_write_value(node) (private)
Visit a node that represents a write value. This is used to handle the special case of an implicit array that is generated without brackets.
# File 'lib/prism/translation/ripper.rb', line 4101
def visit_write_value(node) if node.is_a?(ArrayNode) && node.opening_loc.nil? elements = node.elements length = elements.length bounds(elements.first.location) elements.each_with_index.inject((elements.first.is_a?(SplatNode) && length == 1) ? on_mrhs_new : on_args_new) do |args, (element, index)| arg = visit(element) bounds(element.location) if index == length - 1 if element.is_a?(SplatNode) mrhs = index == 0 ? args : on_mrhs_new_from_args(args) on_mrhs_add_star(mrhs, arg) else on_mrhs_add(on_mrhs_new_from_args(args), arg) end else case element when BlockArgumentNode on_args_add_block(args, arg) when SplatNode on_args_add_star(args, arg) else on_args_add(args, arg) end end end else visit(node) end end
#visit_x_string_node(node)
foo
^^^^^
# File 'lib/prism/translation/ripper.rb', line 3971
def visit_x_string_node(node) with_string_bounds(node) do if node.unescaped.empty? bounds(node.location) on_xstring_literal(on_xstring_new) elsif node.opening.start_with?("<<~") heredoc = visit_heredoc_x_string_node(node.to_interpolated) bounds(node.location) on_xstring_literal(heredoc) else bounds(node.content_loc) content = on_tstring_content(node.content) bounds(node.location) on_xstring_literal(on_xstring_add(on_xstring_new, content)) end end end
#visit_yield_node(node)
yield ^^^^^
yield 1 ^^^^^^^
# File 'lib/prism/translation/ripper.rb', line 3996
def visit_yield_node(node) bounds(node.keyword_loc) on_kw("yield") if node.arguments.nil? && node.lparen_loc.nil? bounds(node.location) on_yield0 else if node.lparen_loc bounds(node.lparen_loc) on_lparen("(") end arguments = if node.arguments.nil? bounds(node.location) on_args_new else visit(node.arguments) end unless node.lparen_loc.nil? bounds(node.rparen_loc) on_rparen(")") bounds(node.lparen_loc) arguments = on_paren(arguments) end bounds(node.location) on_yield(arguments) end end
#void_stmt?(left, right, allow_newline) ⇒ Boolean (private)
Returns true if there is a semicolon between the two locations.
# File 'lib/prism/translation/ripper.rb', line 4046
def void_stmt?(left, right, allow_newline) pattern = allow_newline ? /[;\n]/ : /;/ source.byteslice(left.end_offset...right.start_offset).match?(pattern) end
#warn(fmt, *args) (private)
This method is called when weak warning is produced by the parser.
fmt and args is printf style.
# File 'lib/prism/translation/ripper.rb', line 4170
def warn(fmt, *args) end
#warning(fmt, *args) (private)
This method is called when strong warning is produced by the parser.
fmt and args is printf style.
# File 'lib/prism/translation/ripper.rb', line 4175
def warning(fmt, *args) end
#with_string_bounds(node) (private)
Responsible for emitting the various string-like begin/end events
# File 'lib/prism/translation/ripper.rb', line 3615
private def with_string_bounds(node) # `foo "bar": baz` doesn't emit the closing location assoc = !(opening = node.opening)&.include?(":") && node.closing&.end_with?(":") is_heredoc = opening&.start_with?("<<") if is_heredoc bounds(node.opening_loc) on_heredoc_beg(node.opening) elsif opening&.start_with?(":", "%s") bounds(node.opening_loc) on_symbeg(node.opening) elsif opening&.start_with?("`", "%x") bounds(node.opening_loc) on_backtick(node.opening) elsif opening && !opening.start_with?("?") bounds(node.opening_loc) on_tstring_beg(opening) end result = yield if assoc if node.closing != ":" bounds(node.closing_loc) on_label_end(node.closing) end return result end if is_heredoc bounds(node.closing_loc) on_heredoc_end(node.closing) elsif node.closing_loc bounds(node.closing_loc) on_tstring_end(node.closing) end result end