class Parser::Builders::Default
Attributes
AST
compatibility attribute; causes a single non-mlhs block argument to be wrapped in s(:procarg0).
If set to false (the default), block arguments `|a|` are emitted as `s(:args, s(:procarg0, :a))`
If set to true, block arguments `|a|` are emitted as `s(:args, s(:procarg0, s(:arg, :a))`
@return [Boolean]
AST
compatibility attribute; locations of `__ENCODING__` are not the same as locations of `Encoding::UTF_8` causing problems during rewriting, all new code should set this attribute to true.
If set to false (the default), `__ENCODING__` is emitted as ` s(:const, s(:const, nil, :Encoding), :UTF_8)`.
If set to true, `__ENCODING__` is emitted as `s(:__ENCODING__)`.
@return [Boolean]
AST
compatibility attribute; arguments forwarding initially didn't have support for leading arguments (i.e. `def m(a, …); end` was a syntax error). However, Ruby 3.0 added support for any number of arguments in front of the `…`.
If set to false (the default):
1. `def m(...) end` is emitted as s(:def, :m, s(:forward_args), nil) 2. `def m(a, b, ...) end` is emitted as s(:def, :m, s(:args, s(:arg, :a), s(:arg, :b), s(:forward_arg)))
If set to true it uses a single format:
1. `def m(...) end` is emitted as s(:def, :m, s(:args, s(:forward_arg))) 2. `def m(a, b, ...) end` is emitted as s(:def, :m, s(:args, s(:arg, :a), s(:arg, :b), s(:forward_arg)))
It does't matter that much on 2.7 (because there can't be any leading arguments), but on 3.0 it should be better enabled to use a single AST
format.
@return [Boolean]
AST
compatibility attribute; indexed assignment, `x[] = 1`, is not semantically equivalent to calling the method directly, `x.[]=(1)`. Specifically, in the former case, the expression's value is always 1, and in the latter case, the expression's value is the return value of the `[]=` method.
If set to false (the default), `self` is emitted as `s(:send, s(:self), :[], s(:int, 1))`, and `self = 2` is emitted as `s(:send, s(:self), :[]=, s(:int, 1), s(:int, 2))`.
If set to true, `self` is emitted as `s(:index, s(:self), s(:int, 1))`, and `self = 2` is emitted as `s(:indexasgn, s(:self), s(:int, 1), s(:int, 2))`.
@return [Boolean]
AST
compatibility attribute; Starting from Ruby 2.7 keyword arguments of method calls that are passed explicitly as a hash (i.e. with curly braces) are treated as positional arguments and Ruby 2.7 emits a warning on such method call. Ruby 3.0 given an ArgumentError.
If set to false (the default) the last hash argument is emitted as `hash`:
“` (send nil :foo
(hash (pair (sym :bar) (int 42))))
“`
If set to true it is emitted as `kwargs`:
“` (send nil :foo
(kwargs (pair (sym :bar) (int 42))))
“`
Note that `kwargs` node is just a replacement for `hash` argument, so if there's are multiple arguments (or a `kwsplat`) all of them are wrapped into `kwargs` instead of `hash`:
“` (send nil :foo
(kwargs (pair (sym :a) (int 42)) (kwsplat (send nil :b)) (pair (sym :c) (int 10))))
“`
AST
compatibility attribute; since `-> {}` is not semantically equivalent to `lambda {}`, all new code should set this attribute to true.
If set to false (the default), `-> {}` is emitted as `s(:block, s(:send, nil, :lambda), s(:args), nil)`.
If set to true, `-> {}` is emitted as `s(:block, s(:lambda), s(:args), nil)`.
@return [Boolean]
AST
compatibility attribute; Starting from 3.0 Ruby returns true/false from single-line pattern matching with `in` keyword.
Before 3.0 there was an exception if given value doesn't match pattern.
NOTE: This attribute affects only Ruby 2.7 grammar. 3.0 grammar always emits `match_pattern`/`match_pattern_p`
If compatibility attribute set to false `foo in bar` is emitted as `in_match`:
“` (in-match
(send nil :foo) (match-var :bar))
“`
If set to true it's emitted as `match_pattern_p`: “` (match-pattern-p
(send nil :foo) (match-var :bar))
“`
AST
compatibility attribute; block arguments of `m { |a| }` are not semantically equivalent to block arguments of `m { |a,| }` or `m { |a, b| }`, all new code should set this attribute to true.
If set to false (the default), arguments of `m { |a| }` are emitted as `s(:args, s(:arg, :a))`.
If set to true, arguments of `m { |a| }` are emitted as `s(:args, s(:procarg0, :a)).
@return [Boolean]
If set to true (the default), `__FILE__` and `__LINE__` are transformed to literal nodes. For example, `s(:str, “lib/foo.rb”)` and `s(:int, 10)`.
If set to false, `__FILE__` and `__LINE__` are emitted as-is, i.e. as `s(:__FILE__)` and `s(:__LINE__)` nodes.
Source
maps are identical in both cases.
@return [Boolean]
@api private
Public Class Methods
@api private
# File lib/parser/builders/default.rb, line 211 def modernize @emit_lambda = true @emit_procarg0 = true @emit_encoding = true @emit_index = true @emit_arg_inside_procarg0 = true @emit_forward_arg = true @emit_kwargs = true @emit_match_pattern = true end
Initializes attributes:
* `emit_file_line_as_literals`: `true`
# File lib/parser/builders/default.rb, line 243 def initialize @emit_file_line_as_literals = true end
Public Instance Methods
# File lib/parser/builders/default.rb, line 696 def __ENCODING__(__ENCODING__t) n0(:__ENCODING__, token_map(__ENCODING__t)) end
# File lib/parser/builders/default.rb, line 348 def __FILE__(__FILE__t) n0(:__FILE__, token_map(__FILE__t)) end
# File lib/parser/builders/default.rb, line 312 def __LINE__(__LINE__t) n0(:__LINE__, token_map(__LINE__t)) end
# File lib/parser/builders/default.rb, line 622 def accessible(node) case node.type when :__FILE__ if @emit_file_line_as_literals n(:str, [ node.loc.expression.source_buffer.name ], node.loc.dup) else node end when :__LINE__ if @emit_file_line_as_literals n(:int, [ node.loc.expression.line ], node.loc.dup) else node end when :__ENCODING__ if !self.class.emit_encoding n(:const, [ n(:const, [ nil, :Encoding], nil), :UTF_8 ], node.loc.dup) else node end when :ident name, = *node if %w[? !].any? { |c| name.to_s.end_with?(c) } diagnostic :error, :invalid_id_to_get, { :identifier => name.to_s }, node.loc.expression end # Numbered parameters are not declared anywhere, # so they take precedence over method calls in numblock contexts if @parser.version >= 27 && @parser.try_declare_numparam(node) return node.updated(:lvar) end unless @parser.static_env.declared?(name) return n(:send, [ nil, name ], var_send_map(node)) end if name.to_s == parser.current_arg_stack.top diagnostic :error, :circular_argument_reference, { :var_name => name.to_s }, node.loc.expression end node.updated(:lvar) else node end end
# File lib/parser/builders/default.rb, line 871 def alias(alias_t, to, from) n(:alias, [ to, from ], keyword_map(alias_t, nil, [to, from], nil)) end
# File lib/parser/builders/default.rb, line 910 def arg(name_t) check_reserved_for_numparam(value(name_t), loc(name_t)) n(:arg, [ value(name_t).to_sym ], variable_map(name_t)) end
Ruby 1.8 block arguments
# File lib/parser/builders/default.rb, line 1000 def arg_expr(expr) if expr.type == :lvasgn expr.updated(:arg) else n(:arg_expr, [ expr ], expr.loc.dup) end end
Formal arguments
# File lib/parser/builders/default.rb, line 880 def args(begin_t, args, end_t, check_args=true) args = check_duplicate_args(args) if check_args validate_no_forward_arg_after_restarg(args) map = collection_map(begin_t, args, end_t) if !self.class.emit_forward_arg && args.length == 1 && args[0].type == :forward_arg n(:forward_args, [], map) else n(:args, args, map) end end
Arrays
# File lib/parser/builders/default.rb, line 440 def array(begin_t, elements, end_t) n(:array, elements, collection_map(begin_t, elements, end_t)) end
# File lib/parser/builders/default.rb, line 1575 def array_pattern(lbrack_t, elements, rbrack_t) return n(:array_pattern, nil, collection_map(lbrack_t, [], rbrack_t)) if elements.nil? trailing_comma = false node_elements = elements.map do |element| if element.type == :match_with_trailing_comma trailing_comma = true element.children.first else trailing_comma = false element end end node_type = trailing_comma ? :array_pattern_with_tail : :array_pattern n(node_type, node_elements, collection_map(lbrack_t, elements, rbrack_t)) end
# File lib/parser/builders/default.rb, line 760 def assign(lhs, eql_t, rhs) (lhs << rhs).updated(nil, nil, :location => lhs.loc. with_operator(loc(eql_t)). with_expression(join_exprs(lhs, rhs))) end
Assignment
# File lib/parser/builders/default.rb, line 705 def assignable(node) case node.type when :cvar node.updated(:cvasgn) when :ivar node.updated(:ivasgn) when :gvar node.updated(:gvasgn) when :const if @parser.context.in_def diagnostic :error, :dynamic_const, nil, node.loc.expression end node.updated(:casgn) when :ident name, = *node var_name = node.children[0].to_s name_loc = node.loc.expression check_assignment_to_numparam(var_name, name_loc) check_reserved_for_numparam(var_name, name_loc) @parser.static_env.declare(name) node.updated(:lvasgn) when :match_var name, = *node var_name = node.children[0].to_s name_loc = node.loc.expression check_assignment_to_numparam(var_name, name_loc) check_reserved_for_numparam(var_name, name_loc) node when :nil, :self, :true, :false, :__FILE__, :__LINE__, :__ENCODING__ diagnostic :error, :invalid_assignment, nil, node.loc.expression when :back_ref, :nth_ref diagnostic :error, :backref_assignment, nil, node.loc.expression end end
# File lib/parser/builders/default.rb, line 540 def associate(begin_t, pairs, end_t) 0.upto(pairs.length - 1) do |i| (i + 1).upto(pairs.length - 1) do |j| key1, = *pairs[i] key2, = *pairs[j] do_warn = false # keys have to be simple nodes, MRI ignores equal composite keys like # `{ a(1) => 1, a(1) => 1 }` case key1.type when :sym, :str, :int, :float if key1 == key2 do_warn = true end when :rational, :complex, :regexp if @parser.version >= 31 && key1 == key2 do_warn = true end end if do_warn diagnostic :warning, :duplicate_hash_key, nil, key2.loc.expression end end end n(:hash, [ *pairs ], collection_map(begin_t, pairs, end_t)) end
# File lib/parser/builders/default.rb, line 1156 def attr_asgn(receiver, dot_t, selector_t) method_name = (value(selector_t) + '=').to_sym type = call_type_for_dot(dot_t) # Incomplete method call. n(type, [ receiver, method_name ], send_map(receiver, dot_t, selector_t)) end
# File lib/parser/builders/default.rb, line 612 def back_ref(token) n(:back_ref, [ value(token).to_sym ], token_map(token)) end
# File lib/parser/builders/default.rb, line 1420 def begin(begin_t, body, end_t) if body.nil? # A nil expression: `()'. n0(:begin, collection_map(begin_t, nil, end_t)) elsif body.type == :mlhs || (body.type == :begin && body.loc.begin.nil? && body.loc.end.nil?) # Synthesized (begin) from compstmt "a; b" or (mlhs) # from multi_lhs "(a, b) = *foo". n(body.type, body.children, collection_map(begin_t, body.children, end_t)) else n(:begin, [ body ], collection_map(begin_t, [ body ], end_t)) end end
# File lib/parser/builders/default.rb, line 1362 def begin_body(compound_stmt, rescue_bodies=[], else_t=nil, else_=nil, ensure_t=nil, ensure_=nil) if rescue_bodies.any? if else_t compound_stmt = n(:rescue, [ compound_stmt, *(rescue_bodies + [ else_ ]) ], eh_keyword_map(compound_stmt, nil, rescue_bodies, else_t, else_)) else compound_stmt = n(:rescue, [ compound_stmt, *(rescue_bodies + [ nil ]) ], eh_keyword_map(compound_stmt, nil, rescue_bodies, nil, nil)) end elsif else_t statements = [] if !compound_stmt.nil? if compound_stmt.type == :begin statements += compound_stmt.children else statements.push(compound_stmt) end end statements.push( n(:begin, [ else_ ], collection_map(else_t, [ else_ ], nil))) compound_stmt = n(:begin, statements, collection_map(nil, statements, nil)) end if ensure_t compound_stmt = n(:ensure, [ compound_stmt, ensure_ ], eh_keyword_map(compound_stmt, ensure_t, [ ensure_ ], nil, nil)) end compound_stmt end
# File lib/parser/builders/default.rb, line 1438 def begin_keyword(begin_t, body, end_t) if body.nil? # A nil expression: `begin end'. n0(:kwbegin, collection_map(begin_t, nil, end_t)) elsif (body.type == :begin && body.loc.begin.nil? && body.loc.end.nil?) # Synthesized (begin) from compstmt "a; b". n(:kwbegin, body.children, collection_map(begin_t, body.children, end_t)) else n(:kwbegin, [ body ], collection_map(begin_t, [ body ], end_t)) end end
# File lib/parser/builders/default.rb, line 1190 def binary_op(receiver, operator_t, arg) source_map = send_binary_op_map(receiver, operator_t, arg) if @parser.version == 18 operator = value(operator_t) if operator == '!=' method_call = n(:send, [ receiver, :==, arg ], source_map) elsif operator == '!~' method_call = n(:send, [ receiver, :=~, arg ], source_map) end if %w(!= !~).include?(operator) return n(:not, [ method_call ], expr_map(source_map.expression)) end end n(:send, [ receiver, value(operator_t).to_sym, arg ], source_map) end
# File lib/parser/builders/default.rb, line 1107 def block(method_call, begin_t, args, body, end_t) _receiver, _selector, *call_args = *method_call if method_call.type == :yield diagnostic :error, :block_given_to_yield, nil, method_call.loc.keyword, [loc(begin_t)] end last_arg = call_args.last if last_arg && (last_arg.type == :block_pass || last_arg.type == :forwarded_args) diagnostic :error, :block_and_blockarg, nil, last_arg.loc.expression, [loc(begin_t)] end if args.type == :numargs block_type = :numblock args = args.children[0] else block_type = :block end if [:send, :csend, :index, :super, :zsuper, :lambda].include?(method_call.type) n(block_type, [ method_call, args, body ], block_map(method_call.loc.expression, begin_t, end_t)) else # Code like "return foo 1 do end" is reduced in a weird sequence. # Here, method_call is actually (return). actual_send, = *method_call block = n(block_type, [ actual_send, args, body ], block_map(actual_send.loc.expression, begin_t, end_t)) n(method_call.type, [ block ], method_call.loc.with_expression(join_exprs(method_call, block))) end end
# File lib/parser/builders/default.rb, line 1142 def block_pass(amper_t, arg) n(:block_pass, [ arg ], unary_op_map(amper_t, arg)) end
# File lib/parser/builders/default.rb, line 975 def blockarg(amper_t, name_t) if !name_t.nil? check_reserved_for_numparam(value(name_t), loc(name_t)) end arg_name = name_t ? value(name_t).to_sym : nil n(:blockarg, [ arg_name ], arg_prefix_map(amper_t, name_t)) end
# File lib/parser/builders/default.rb, line 1020 def blockarg_expr(amper_t, expr) if expr.type == :lvasgn expr.updated(:blockarg) else n(:blockarg_expr, [ expr ], expr.loc.dup) end end
# File lib/parser/builders/default.rb, line 1098 def call_lambda(lambda_t) if self.class.emit_lambda n0(:lambda, expr_map(loc(lambda_t))) else n(:send, [ nil, :lambda ], send_map(nil, nil, lambda_t)) end end
# File lib/parser/builders/default.rb, line 1081 def call_method(receiver, dot_t, selector_t, lparen_t=nil, args=[], rparen_t=nil) type = call_type_for_dot(dot_t) if self.class.emit_kwargs rewrite_hash_args_to_kwargs(args) end if selector_t.nil? n(type, [ receiver, :call, *args ], send_map(receiver, dot_t, nil, lparen_t, args, rparen_t)) else n(type, [ receiver, value(selector_t).to_sym, *args ], send_map(receiver, dot_t, selector_t, lparen_t, args, rparen_t)) end end
Method calls
# File lib/parser/builders/default.rb, line 1061 def call_type_for_dot(dot_t) if !dot_t.nil? && value(dot_t) == :anddot :csend else # This case is a bit tricky. ruby23.y returns the token tDOT with # the value :dot, and the token :tANDDOT with the value :anddot. # # But, ruby{18..22}.y (which unconditionally expect tDOT) just # return "." there, since they are to be kept close to the corresponding # Ruby MRI grammars. # # Thankfully, we don't have to care. :send end end
# File lib/parser/builders/default.rb, line 1295 def case(case_t, expr, when_bodies, else_t, else_body, end_t) n(:case, [ expr, *(when_bodies << else_body)], condition_map(case_t, expr, nil, nil, else_t, else_body, end_t)) end
PATTERN MATCHING
# File lib/parser/builders/default.rb, line 1458 def case_match(case_t, expr, in_bodies, else_t, else_body, end_t) else_body = n(:empty_else, nil, token_map(else_t)) if else_t && !else_body n(:case_match, [ expr, *(in_bodies << else_body)], condition_map(case_t, expr, nil, nil, else_t, else_body, end_t)) end
# File lib/parser/builders/default.rb, line 343 def character(char_t) n(:str, [ string_value(char_t) ], prefix_string_map(char_t)) end
# File lib/parser/builders/default.rb, line 284 def complex(complex_t) numeric(:complex, complex_t) end
Expression grouping
# File lib/parser/builders/default.rb, line 1408 def compstmt(statements) case when statements.none? nil when statements.one? statements.first else n(:begin, statements, collection_map(nil, statements, nil)) end end
Conditionals
# File lib/parser/builders/default.rb, line 1271 def condition(cond_t, cond, then_t, if_true, else_t, if_false, end_t) n(:if, [ check_condition(cond), if_true, if_false ], condition_map(cond_t, cond, then_t, if_true, else_t, if_false, end_t)) end
# File lib/parser/builders/default.rb, line 1277 def condition_mod(if_true, if_false, cond_t, cond) n(:if, [ check_condition(cond), if_true, if_false ], keyword_mod_map(if_true || if_false, cond_t, cond)) end
# File lib/parser/builders/default.rb, line 679 def const(name_t) n(:const, [ nil, value(name_t).to_sym ], constant_map(nil, nil, name_t)) end
# File lib/parser/builders/default.rb, line 691 def const_fetch(scope, t_colon2, name_t) n(:const, [ scope, value(name_t).to_sym ], constant_map(scope, t_colon2, name_t)) end
# File lib/parser/builders/default.rb, line 684 def const_global(t_colon3, name_t) cbase = n0(:cbase, token_map(t_colon3)) n(:const, [ cbase, value(name_t).to_sym ], constant_map(cbase, t_colon3, name_t)) end
# File lib/parser/builders/default.rb, line 756 def const_op_assignable(node) node.updated(:casgn) end
# File lib/parser/builders/default.rb, line 1605 def const_pattern(const, ldelim_t, pattern, rdelim_t) n(:const_pattern, [const, pattern], Source::Map::Collection.new( loc(ldelim_t), loc(rdelim_t), const.loc.expression.join(loc(rdelim_t)) ) ) end
# File lib/parser/builders/default.rb, line 607 def cvar(token) n(:cvar, [ value(token).to_sym ], variable_map(token)) end
Indented (interpolated, noninterpolated, executable) strings
# File lib/parser/builders/default.rb, line 388 def dedent_string(node, dedent_level) if !dedent_level.nil? dedenter = Lexer::Dedenter.new(dedent_level) case node.type when :str str = node.children.first dedenter.dedent(str) when :dstr, :xstr children = node.children.map do |str_node| if str_node.type == :str str = str_node.children.first dedenter.dedent(str) next nil if str.empty? else dedenter.interrupt end str_node end node = node.updated(nil, children.compact) end end node end
Class and module definition
# File lib/parser/builders/default.rb, line 807 def def_class(class_t, name, lt_t, superclass, body, end_t) n(:class, [ name, superclass, body ], module_definition_map(class_t, name, lt_t, end_t)) end
# File lib/parser/builders/default.rb, line 838 def def_endless_method(def_t, name_t, args, assignment_t, body) check_reserved_for_numparam(value(name_t), loc(name_t)) n(:def, [ value(name_t).to_sym, args, body ], endless_definition_map(def_t, nil, name_t, assignment_t, body)) end
# File lib/parser/builders/default.rb, line 856 def def_endless_singleton(def_t, definee, dot_t, name_t, args, assignment_t, body) validate_definee(definee) check_reserved_for_numparam(value(name_t), loc(name_t)) n(:defs, [ definee, value(name_t).to_sym, args, body ], endless_definition_map(def_t, dot_t, name_t, assignment_t, body)) end
Method (un)definition
# File lib/parser/builders/default.rb, line 830 def def_method(def_t, name_t, args, body, end_t) check_reserved_for_numparam(value(name_t), loc(name_t)) n(:def, [ value(name_t).to_sym, args, body ], definition_map(def_t, nil, name_t, end_t)) end
# File lib/parser/builders/default.rb, line 820 def def_module(module_t, name, body, end_t) n(:module, [ name, body ], module_definition_map(module_t, name, nil, end_t)) end
# File lib/parser/builders/default.rb, line 814 def def_sclass(class_t, lshft_t, expr, body, end_t) n(:sclass, [ expr, body ], module_definition_map(class_t, nil, lshft_t, end_t)) end
# File lib/parser/builders/default.rb, line 846 def def_singleton(def_t, definee, dot_t, name_t, args, body, end_t) validate_definee(definee) check_reserved_for_numparam(value(name_t), loc(name_t)) n(:defs, [ definee, value(name_t).to_sym, args, body ], definition_map(def_t, dot_t, name_t, end_t)) end
# File lib/parser/builders/default.rb, line 265 def false(false_t) n0(:false, token_map(false_t)) end
# File lib/parser/builders/default.rb, line 1596 def find_pattern(lbrack_t, elements, rbrack_t) n(:find_pattern, elements, collection_map(lbrack_t, elements, rbrack_t)) end
# File lib/parser/builders/default.rb, line 276 def float(float_t) numeric(:float, float_t) end
# File lib/parser/builders/default.rb, line 1316 def for(for_t, iterator, in_t, iteratee, do_t, body, end_t) n(:for, [ iterator, iteratee, body ], for_map(for_t, in_t, do_t, end_t)) end
# File lib/parser/builders/default.rb, line 906 def forward_arg(dots_t) n(:forward_arg, [], token_map(dots_t)) end
# File lib/parser/builders/default.rb, line 896 def forward_only_args(begin_t, dots_t, end_t) if self.class.emit_forward_arg arg = forward_arg(dots_t) n(:args, [ arg ], collection_map(begin_t, [ arg ], end_t)) else n(:forward_args, [], collection_map(begin_t, token_map(dots_t), end_t)) end end
# File lib/parser/builders/default.rb, line 1077 def forwarded_args(dots_t) n(:forwarded_args, [], token_map(dots_t)) end
# File lib/parser/builders/default.rb, line 602 def gvar(token) n(:gvar, [ value(token).to_sym ], variable_map(token)) end
# File lib/parser/builders/default.rb, line 1569 def hash_pattern(lbrace_t, kwargs, rbrace_t) args = check_duplicate_args(kwargs) n(:hash_pattern, args, collection_map(lbrace_t, args, rbrace_t)) end
# File lib/parser/builders/default.rb, line 592 def ident(token) n(:ident, [ value(token).to_sym ], variable_map(token)) end
# File lib/parser/builders/default.rb, line 1485 def if_guard(if_t, if_body) n(:if_guard, [if_body], guard_map(if_t, if_body)) end
# File lib/parser/builders/default.rb, line 1464 def in_match(lhs, in_t, rhs) n(:in_match, [lhs, rhs], binary_op_map(lhs, in_t, rhs)) end
# File lib/parser/builders/default.rb, line 1479 def in_pattern(in_t, pattern, guard, then_t, body) children = [pattern, guard, body] n(:in_pattern, children, keyword_map(in_t, then_t, children.compact, nil)) end
# File lib/parser/builders/default.rb, line 1165 def index(receiver, lbrack_t, indexes, rbrack_t) if self.class.emit_kwargs rewrite_hash_args_to_kwargs(indexes) end if self.class.emit_index n(:index, [ receiver, *indexes ], index_map(receiver, lbrack_t, rbrack_t)) else n(:send, [ receiver, :[], *indexes ], send_index_map(receiver, lbrack_t, rbrack_t)) end end
# File lib/parser/builders/default.rb, line 1179 def index_asgn(receiver, lbrack_t, indexes, rbrack_t) if self.class.emit_index n(:indexasgn, [ receiver, *indexes ], index_map(receiver, lbrack_t, rbrack_t)) else # Incomplete method call. n(:send, [ receiver, :[]=, *indexes ], send_index_map(receiver, lbrack_t, rbrack_t)) end end
Numerics
# File lib/parser/builders/default.rb, line 272 def integer(integer_t) numeric(:int, integer_t) end
# File lib/parser/builders/default.rb, line 597 def ivar(token) n(:ivar, [ value(token).to_sym ], variable_map(token)) end
Keywords
# File lib/parser/builders/default.rb, line 1324 def keyword_cmd(type, keyword_t, lparen_t=nil, args=[], rparen_t=nil) if type == :yield && args.count > 0 last_arg = args.last if last_arg.type == :block_pass diagnostic :error, :block_given_to_yield, nil, loc(keyword_t), [last_arg.loc.expression] end end if %i[yield super].include?(type) && self.class.emit_kwargs rewrite_hash_args_to_kwargs(args) end n(type, args, keyword_map(keyword_t, lparen_t, args, rparen_t)) end
# File lib/parser/builders/default.rb, line 937 def kwarg(name_t) check_reserved_for_numparam(value(name_t), loc(name_t)) n(:kwarg, [ value(name_t).to_sym ], kwarg_map(name_t)) end
# File lib/parser/builders/default.rb, line 963 def kwnilarg(dstar_t, nil_t) n0(:kwnilarg, arg_prefix_map(dstar_t, nil_t)) end
# File lib/parser/builders/default.rb, line 944 def kwoptarg(name_t, value) check_reserved_for_numparam(value(name_t), loc(name_t)) n(:kwoptarg, [ value(name_t).to_sym, value ], kwarg_map(name_t, value)) end
# File lib/parser/builders/default.rb, line 951 def kwrestarg(dstar_t, name_t=nil) if name_t check_reserved_for_numparam(value(name_t), loc(name_t)) n(:kwrestarg, [ value(name_t).to_sym ], arg_prefix_map(dstar_t, name_t)) else n0(:kwrestarg, arg_prefix_map(dstar_t)) end end
# File lib/parser/builders/default.rb, line 535 def kwsplat(dstar_t, arg) n(:kwsplat, [ arg ], unary_op_map(dstar_t, arg)) end
Logical operations: and, or
# File lib/parser/builders/default.rb, line 1264 def logical_op(type, lhs, op_t, rhs) n(type, [ lhs, rhs ], binary_op_map(lhs, op_t, rhs)) end
Loops
# File lib/parser/builders/default.rb, line 1302 def loop(type, keyword_t, cond, do_t, body, end_t) n(type, [ check_condition(cond), body ], keyword_map(keyword_t, do_t, nil, end_t)) end
# File lib/parser/builders/default.rb, line 1307 def loop_mod(type, body, keyword_t, cond) if body.type == :kwbegin type = :"#{type}_post" end n(type, [ check_condition(cond), body ], keyword_mod_map(body, keyword_t, cond)) end
# File lib/parser/builders/default.rb, line 1619 def match_alt(left, pipe_t, right) source_map = binary_op_map(left, pipe_t, right) n(:match_alt, [ left, right ], source_map) end
# File lib/parser/builders/default.rb, line 1626 def match_as(value, assoc_t, as) source_map = binary_op_map(value, assoc_t, as) n(:match_as, [ value, as ], source_map) end
# File lib/parser/builders/default.rb, line 1505 def match_hash_var(name_t) name = value(name_t).to_sym expr_l = loc(name_t) name_l = expr_l.adjust(end_pos: -1) check_lvar_name(name, name_l) check_duplicate_pattern_variable(name, name_l) @parser.static_env.declare(name) n(:match_var, [ name ], Source::Map::Variable.new(name_l, expr_l)) end
# File lib/parser/builders/default.rb, line 1519 def match_hash_var_from_str(begin_t, strings, end_t) if strings.length > 1 diagnostic :error, :pm_interp_in_var_name, nil, loc(begin_t).join(loc(end_t)) end string = strings[0] case string.type when :str # MRI supports plain strings in hash pattern matching name, = *string name_l = string.loc.expression check_lvar_name(name, name_l) check_duplicate_pattern_variable(name, name_l) @parser.static_env.declare(name) if (begin_l = string.loc.begin) # exclude beginning of the string from the location of the variable name_l = name_l.adjust(begin_pos: begin_l.length) end if (end_l = string.loc.end) # exclude end of the string from the location of the variable name_l = name_l.adjust(end_pos: -end_l.length) end expr_l = loc(begin_t).join(string.loc.expression).join(loc(end_t)) n(:match_var, [ name.to_sym ], Source::Map::Variable.new(name_l, expr_l)) when :begin match_hash_var_from_str(begin_t, string.children, end_t) else # we only can get here if there is an interpolation, e.g., ``in "#{ a }":` diagnostic :error, :pm_interp_in_var_name, nil, loc(begin_t).join(loc(end_t)) end end
# File lib/parser/builders/default.rb, line 1657 def match_label(label_type, label) if label_type == :label match_hash_var(label) else # quoted label like "label": value begin_t, strings, end_t = label match_hash_var_from_str(begin_t, strings, end_t) end end
# File lib/parser/builders/default.rb, line 1633 def match_nil_pattern(dstar_t, nil_t) n0(:match_nil_pattern, arg_prefix_map(dstar_t, nil_t)) end
# File lib/parser/builders/default.rb, line 1212 def match_op(receiver, match_t, arg) source_map = send_binary_op_map(receiver, match_t, arg) if (regexp = static_regexp_node(receiver)) regexp.names.each do |name| @parser.static_env.declare(name) end n(:match_with_lvasgn, [ receiver, arg ], source_map) else n(:send, [ receiver, :=~, arg ], source_map) end end
# File lib/parser/builders/default.rb, line 1638 def match_pair(label_type, label, value) if label_type == :label check_duplicate_pattern_key(label[0], label[1]) pair_keyword(label, value) else begin_t, parts, end_t = label label_loc = loc(begin_t).join(loc(end_t)) # quoted label like "label": value if (var_name = static_string(parts)) check_duplicate_pattern_key(var_name, label_loc) else diagnostic :error, :pm_interp_in_var_name, nil, label_loc end pair_quoted(begin_t, parts, end_t, value) end end
# File lib/parser/builders/default.rb, line 1469 def match_pattern(lhs, match_t, rhs) n(:match_pattern, [lhs, rhs], binary_op_map(lhs, match_t, rhs)) end
# File lib/parser/builders/default.rb, line 1474 def match_pattern_p(lhs, match_t, rhs) n(:match_pattern_p, [lhs, rhs], binary_op_map(lhs, match_t, rhs)) end
# File lib/parser/builders/default.rb, line 1558 def match_rest(star_t, name_t = nil) if name_t.nil? n0(:match_rest, unary_op_map(star_t)) else name = match_var(name_t) n(:match_rest, [ name ], unary_op_map(star_t, name)) end end
# File lib/parser/builders/default.rb, line 1493 def match_var(name_t) name = value(name_t).to_sym name_l = loc(name_t) check_lvar_name(name, name_l) check_duplicate_pattern_variable(name, name_l) @parser.static_env.declare(name) n(:match_var, [ name ], variable_map(name_t)) end
# File lib/parser/builders/default.rb, line 1601 def match_with_trailing_comma(match, comma_t) n(:match_with_trailing_comma, [ match ], expr_map(match.loc.expression.join(loc(comma_t)))) end
# File lib/parser/builders/default.rb, line 798 def multi_assign(lhs, eql_t, rhs) n(:masgn, [ lhs, rhs ], binary_op_map(lhs, eql_t, rhs)) end
# File lib/parser/builders/default.rb, line 793 def multi_lhs(begin_t, items, end_t) n(:mlhs, [ *items ], collection_map(begin_t, items, end_t)) end
Singletons
# File lib/parser/builders/default.rb, line 255 def nil(nil_t) n0(:nil, token_map(nil_t)) end
# File lib/parser/builders/default.rb, line 1240 def not_op(not_t, begin_t=nil, receiver=nil, end_t=nil) if @parser.version == 18 n(:not, [ check_condition(receiver) ], unary_op_map(not_t, receiver)) else if receiver.nil? nil_node = n0(:begin, collection_map(begin_t, nil, end_t)) n(:send, [ nil_node, :'!' ], send_unary_op_map(not_t, nil_node)) else n(:send, [ check_condition(receiver), :'!' ], send_map(nil, nil, not_t, begin_t, [receiver], end_t)) end end end
# File lib/parser/builders/default.rb, line 617 def nth_ref(token) n(:nth_ref, [ value(token) ], token_map(token)) end
# File lib/parser/builders/default.rb, line 892 def numargs(max_numparam) n(:numargs, [ max_numparam ], nil) end
MacRuby
Objective-C arguments
# File lib/parser/builders/default.rb, line 1031 def objc_kwarg(kwname_t, assoc_t, name_t) kwname_l = loc(kwname_t) if assoc_t.nil? # a: b, not a => b kwname_l = kwname_l.resize(kwname_l.size - 1) operator_l = kwname_l.end.resize(1) else operator_l = loc(assoc_t) end n(:objc_kwarg, [ value(kwname_t).to_sym, value(name_t).to_sym ], Source::Map::ObjcKwarg.new(kwname_l, operator_l, loc(name_t), kwname_l.join(loc(name_t)))) end
# File lib/parser/builders/default.rb, line 1045 def objc_restarg(star_t, name=nil) if name.nil? n0(:restarg, arg_prefix_map(star_t)) elsif name.type == :arg # regular restarg name.updated(:restarg, nil, { :location => name.loc.with_operator(loc(star_t)) }) else # restarg with objc_kwarg inside n(:objc_restarg, [ name ], unary_op_map(star_t, name)) end end
# File lib/parser/builders/default.rb, line 1147 def objc_varargs(pair, rest_of_varargs) value, first_vararg = *pair vararg_array = array(nil, [ first_vararg, *rest_of_varargs ], nil). updated(:objc_varargs) pair.updated(nil, [ value, vararg_array ], { :location => pair.loc.with_expression( pair.loc.expression.join(vararg_array.loc.expression)) }) end
# File lib/parser/builders/default.rb, line 767 def op_assign(lhs, op_t, rhs) case lhs.type when :gvasgn, :ivasgn, :lvasgn, :cvasgn, :casgn, :send, :csend, :index operator = value(op_t)[0..-1].to_sym source_map = lhs.loc. with_operator(loc(op_t)). with_expression(join_exprs(lhs, rhs)) if lhs.type == :index lhs = lhs.updated(:indexasgn) end case operator when :'&&' n(:and_asgn, [ lhs, rhs ], source_map) when :'||' n(:or_asgn, [ lhs, rhs ], source_map) else n(:op_asgn, [ lhs, operator, rhs ], source_map) end when :back_ref, :nth_ref diagnostic :error, :backref_assignment, nil, lhs.loc.expression end end
# File lib/parser/builders/default.rb, line 917 def optarg(name_t, eql_t, value) check_reserved_for_numparam(value(name_t), loc(name_t)) n(:optarg, [ value(name_t).to_sym, value ], variable_map(name_t). with_operator(loc(eql_t)). with_expression(loc(name_t).join(value.loc.expression))) end
Hashes
# File lib/parser/builders/default.rb, line 488 def pair(key, assoc_t, value) n(:pair, [ key, value ], binary_op_map(key, assoc_t, value)) end
# File lib/parser/builders/default.rb, line 505 def pair_keyword(key_t, value) key_map, pair_map = pair_keyword_map(key_t, value) key = n(:sym, [ value(key_t).to_sym ], key_map) n(:pair, [ key, value ], pair_map) end
# File lib/parser/builders/default.rb, line 521 def pair_label(key_t) key_l = loc(key_t) value_l = key_l.adjust(end_pos: -1) label = value(key_t) value = if label =~ /\A[[:lower:]]/ n(:ident, [ label.to_sym ], Source::Map::Variable.new(value_l)) else n(:const, [ nil, label.to_sym ], Source::Map::Constant.new(nil, value_l, value_l)) end pair_keyword(key_t, accessible(value)) end
# File lib/parser/builders/default.rb, line 493 def pair_list_18(list) if list.size % 2 != 0 diagnostic :error, :odd_hash, nil, list.last.loc.expression else list. each_slice(2).map do |key, value| n(:pair, [ key, value ], binary_op_map(key, nil, value)) end end end
# File lib/parser/builders/default.rb, line 513 def pair_quoted(begin_t, parts, end_t, value) end_t, pair_map = pair_quoted_map(begin_t, end_t, value) key = symbol_compose(begin_t, parts, end_t) n(:pair, [ key, value ], pair_map) end
# File lib/parser/builders/default.rb, line 1614 def pin(pin_t, var) n(:pin, [ var ], send_unary_op_map(pin_t, var)) end
# File lib/parser/builders/default.rb, line 1347 def postexe(postexe_t, lbrace_t, compstmt, rbrace_t) n(:postexe, [ compstmt ], keyword_map(postexe_t, lbrace_t, [], rbrace_t)) end
BEGIN, END
# File lib/parser/builders/default.rb, line 1342 def preexe(preexe_t, lbrace_t, compstmt, rbrace_t) n(:preexe, [ compstmt ], keyword_map(preexe_t, lbrace_t, [], rbrace_t)) end
# File lib/parser/builders/default.rb, line 985 def procarg0(arg) if self.class.emit_procarg0 if arg.type == :arg && self.class.emit_arg_inside_procarg0 n(:procarg0, [ arg ], Source::Map::Collection.new(nil, nil, arg.location.expression)) else arg.updated(:procarg0) end else arg end end
# File lib/parser/builders/default.rb, line 578 def range_exclusive(lhs, dot3_t, rhs) n(:erange, [ lhs, rhs ], range_map(lhs, dot3_t, rhs)) end
Ranges
# File lib/parser/builders/default.rb, line 573 def range_inclusive(lhs, dot2_t, rhs) n(:irange, [ lhs, rhs ], range_map(lhs, dot2_t, rhs)) end
# File lib/parser/builders/default.rb, line 280 def rational(rational_t) numeric(:rational, rational_t) end
# File lib/parser/builders/default.rb, line 426 def regexp_compose(begin_t, parts, end_t, options) begin static_regexp(parts, options) rescue RegexpError => e diagnostic :error, :invalid_regexp, { :message => e.message }, loc(begin_t).join(loc(end_t)) end n(:regexp, (parts << options), regexp_map(begin_t, end_t, options)) end
Regular expressions
# File lib/parser/builders/default.rb, line 417 def regexp_options(regopt_t) options = value(regopt_t). each_char.sort.uniq. map(&:to_sym) n(:regopt, options, token_map(regopt_t)) end
Exception handling
# File lib/parser/builders/default.rb, line 1354 def rescue_body(rescue_t, exc_list, assoc_t, exc_var, then_t, compound_stmt) n(:resbody, [ exc_list, exc_var, compound_stmt ], rescue_body_map(rescue_t, exc_list, assoc_t, exc_var, then_t, compound_stmt)) end
# File lib/parser/builders/default.rb, line 926 def restarg(star_t, name_t=nil) if name_t check_reserved_for_numparam(value(name_t), loc(name_t)) n(:restarg, [ value(name_t).to_sym ], arg_prefix_map(star_t, name_t)) else n0(:restarg, arg_prefix_map(star_t)) end end
# File lib/parser/builders/default.rb, line 1009 def restarg_expr(star_t, expr=nil) if expr.nil? n0(:restarg, token_map(star_t)) elsif expr.type == :lvasgn expr.updated(:restarg) else n(:restarg_expr, [ expr ], expr.loc.dup) end end
Access
# File lib/parser/builders/default.rb, line 587 def self(token) n0(:self, token_map(token)) end
# File lib/parser/builders/default.rb, line 968 def shadowarg(name_t) check_reserved_for_numparam(value(name_t), loc(name_t)) n(:shadowarg, [ value(name_t).to_sym ], variable_map(name_t)) end
# File lib/parser/builders/default.rb, line 445 def splat(star_t, arg=nil) if arg.nil? n0(:splat, unary_op_map(star_t)) else n(:splat, [ arg ], unary_op_map(star_t, arg)) end end
Strings
# File lib/parser/builders/default.rb, line 319 def string(string_t) n(:str, [ string_value(string_t) ], delimited_string_map(string_t)) end
# File lib/parser/builders/default.rb, line 329 def string_compose(begin_t, parts, end_t) if collapse_string_parts?(parts) if begin_t.nil? && end_t.nil? parts.first else n(:str, parts.first.children, string_map(begin_t, parts, end_t)) end else n(:dstr, [ *parts ], string_map(begin_t, parts, end_t)) end end
# File lib/parser/builders/default.rb, line 324 def string_internal(string_t) n(:str, [ string_value(string_t) ], unquoted_map(string_t)) end
Symbols
# File lib/parser/builders/default.rb, line 355 def symbol(symbol_t) n(:sym, [ string_value(symbol_t).to_sym ], prefix_string_map(symbol_t)) end
# File lib/parser/builders/default.rb, line 365 def symbol_compose(begin_t, parts, end_t) if collapse_string_parts?(parts) str = parts.first n(:sym, [ str.children.first.to_sym ], collection_map(begin_t, str.loc.expression, end_t)) elsif @parser.version == 18 && parts.empty? diagnostic :error, :empty_symbol, nil, loc(begin_t).join(loc(end_t)) else n(:dsym, [ *parts ], collection_map(begin_t, parts, end_t)) end end
# File lib/parser/builders/default.rb, line 360 def symbol_internal(symbol_t) n(:sym, [ string_value(symbol_t).to_sym ], unquoted_map(symbol_t)) end
# File lib/parser/builders/default.rb, line 469 def symbols_compose(begin_t, parts, end_t) parts = parts.map do |part| case part.type when :str value, = *part part.updated(:sym, [ value.to_sym ]) when :dstr part.updated(:dsym) else part end end n(:array, [ *parts ], collection_map(begin_t, parts, end_t)) end
# File lib/parser/builders/default.rb, line 1282 def ternary(cond, question_t, if_true, colon_t, if_false) n(:if, [ check_condition(cond), if_true, if_false ], ternary_map(cond, question_t, if_true, colon_t, if_false)) end
# File lib/parser/builders/default.rb, line 260 def true(true_t) n0(:true, token_map(true_t)) end
# File lib/parser/builders/default.rb, line 294 def unary_num(unary_t, numeric) value, = *numeric operator_loc = loc(unary_t) case value(unary_t) when '+' value = +value when '-' value = -value end numeric.updated(nil, [ value ], :location => Source::Map::Operator.new( operator_loc, operator_loc.join(numeric.loc.expression))) end
# File lib/parser/builders/default.rb, line 1228 def unary_op(op_t, receiver) case value(op_t) when '+', '-' method = value(op_t) + '@' else method = value(op_t) end n(:send, [ receiver, method.to_sym ], send_unary_op_map(op_t, receiver)) end
# File lib/parser/builders/default.rb, line 866 def undef_method(undef_t, names) n(:undef, [ *names ], keyword_map(undef_t, nil, names, nil)) end
# File lib/parser/builders/default.rb, line 1489 def unless_guard(unless_t, unless_body) n(:unless_guard, [unless_body], guard_map(unless_t, unless_body)) end
Case matching
# File lib/parser/builders/default.rb, line 1289 def when(when_t, patterns, then_t, body) children = patterns << body n(:when, children, keyword_map(when_t, then_t, children, nil)) end
# File lib/parser/builders/default.rb, line 455 def word(parts) if collapse_string_parts?(parts) parts.first else n(:dstr, [ *parts ], collection_map(nil, parts, nil)) end end
# File lib/parser/builders/default.rb, line 464 def words_compose(begin_t, parts, end_t) n(:array, [ *parts ], collection_map(begin_t, parts, end_t)) end
Executable strings
# File lib/parser/builders/default.rb, line 381 def xstring_compose(begin_t, parts, end_t) n(:xstr, [ *parts ], string_map(begin_t, parts, end_t)) end
Private Instance Methods
# File lib/parser/builders/default.rb, line 1796 def arg_name_collides?(this_name, that_name) case @parser.version when 18 this_name == that_name when 19 # Ignore underscore. this_name != :_ && this_name == that_name else # Ignore everything beginning with underscore. this_name && this_name[0] != '_' && this_name == that_name end end
# File lib/parser/builders/default.rb, line 1992 def arg_prefix_map(op_t, name_t=nil) if name_t.nil? expr_l = loc(op_t) else expr_l = loc(op_t).join(loc(name_t)) end Source::Map::Variable.new(loc(name_t), expr_l) end
# File lib/parser/builders/default.rb, line 1966 def binary_op_map(left_e, op_t, right_e) Source::Map::Operator.new(loc(op_t), join_exprs(left_e, right_e)) end
# File lib/parser/builders/default.rb, line 2094 def block_map(receiver_l, begin_t, end_t) Source::Map::Collection.new(loc(begin_t), loc(end_t), receiver_l.join(loc(end_t))) end
# File lib/parser/builders/default.rb, line 1771 def check_assignment_to_numparam(name, loc) # MRI < 2.7 treats numbered parameters as regular variables # and so it's allowed to perform assignments like `_1 = 42`. return if @parser.version < 27 assigning_to_numparam = @parser.context.in_dynamic_block? && name =~ /\A_([1-9])\z/ && @parser.max_numparam_stack.has_numparams? if assigning_to_numparam diagnostic :error, :cant_assign_to_numparam, { :name => name }, loc end end
VERIFICATION
# File lib/parser/builders/default.rb, line 1673 def check_condition(cond) case cond.type when :masgn if @parser.version <= 23 diagnostic :error, :masgn_as_condition, nil, cond.loc.expression else cond end when :begin if cond.children.count == 1 cond.updated(nil, [ check_condition(cond.children.last) ]) else cond end when :and, :or, :irange, :erange lhs, rhs = *cond type = case cond.type when :irange then :iflipflop when :erange then :eflipflop end if [:and, :or].include?(cond.type) && @parser.version == 18 cond else cond.updated(type, [ check_condition(lhs), check_condition(rhs) ]) end when :regexp n(:match_current_line, [ cond ], expr_map(cond.loc.expression)) else cond end end
# File lib/parser/builders/default.rb, line 1742 def check_duplicate_arg(this_arg, map={}) this_name, = *this_arg that_arg = map[this_name] that_name, = *that_arg if that_arg.nil? map[this_name] = this_arg elsif arg_name_collides?(this_name, that_name) diagnostic :error, :duplicate_argument, nil, this_arg.loc.name, [ that_arg.loc.name ] end end
# File lib/parser/builders/default.rb, line 1717 def check_duplicate_args(args, map={}) args.each do |this_arg| case this_arg.type when :arg, :optarg, :restarg, :blockarg, :kwarg, :kwoptarg, :kwrestarg, :shadowarg check_duplicate_arg(this_arg, map) when :procarg0 if this_arg.children[0].is_a?(Symbol) # s(:procarg0, :a) check_duplicate_arg(this_arg, map) else # s(:procarg0, s(:arg, :a), ...) check_duplicate_args(this_arg.children, map) end when :mlhs check_duplicate_args(this_arg.children, map) end end end
# File lib/parser/builders/default.rb, line 1829 def check_duplicate_pattern_key(name, loc) if @parser.pattern_hash_keys.declared?(name) diagnostic :error, :duplicate_pattern_key, { name: name.to_s }, loc end @parser.pattern_hash_keys.declare(name) end
# File lib/parser/builders/default.rb, line 1819 def check_duplicate_pattern_variable(name, loc) return if name.to_s.start_with?('_') if @parser.pattern_variables.declared?(name) diagnostic :error, :duplicate_variable_name, { name: name.to_s }, loc end @parser.pattern_variables.declare(name) end
# File lib/parser/builders/default.rb, line 1811 def check_lvar_name(name, loc) if name =~ /\A[[[:lower:]]_][[[:alnum:]]_]*\z/ # OK else diagnostic :error, :lvar_name, { name: name }, loc end end
# File lib/parser/builders/default.rb, line 1786 def check_reserved_for_numparam(name, loc) # MRI < 3.0 accepts assignemnt to variables like _1 # if it's not a numbered parameter. MRI 3.0 and newer throws an error. return if @parser.version < 30 if name =~ /\A_([1-9])\z/ diagnostic :error, :reserved_for_numparam, { :name => name }, loc end end
# File lib/parser/builders/default.rb, line 2251 def collapse_string_parts?(parts) parts.one? && [:str, :dstr].include?(parts.first.type) end
# File lib/parser/builders/default.rb, line 1917 def collection_map(begin_t, parts, end_t) if begin_t.nil? || end_t.nil? if parts.any? expr_l = join_exprs(parts.first, parts.last) elsif !begin_t.nil? expr_l = loc(begin_t) elsif !end_t.nil? expr_l = loc(end_t) end else expr_l = loc(begin_t).join(loc(end_t)) end Source::Map::Collection.new(loc(begin_t), loc(end_t), expr_l) end
# File lib/parser/builders/default.rb, line 2121 def condition_map(keyword_t, cond_e, begin_t, body_e, else_t, else_e, end_t) if end_t end_l = loc(end_t) elsif else_e && else_e.loc.expression end_l = else_e.loc.expression elsif loc(else_t) end_l = loc(else_t) elsif body_e && body_e.loc.expression end_l = body_e.loc.expression elsif loc(begin_t) end_l = loc(begin_t) else end_l = cond_e.loc.expression end Source::Map::Condition.new(loc(keyword_t), loc(begin_t), loc(else_t), loc(end_t), loc(keyword_t).join(end_l)) end
# File lib/parser/builders/default.rb, line 1952 def constant_map(scope, colon2_t, name_t) if scope.nil? expr_l = loc(name_t) else expr_l = scope.loc.expression.join(loc(name_t)) end Source::Map::Constant.new(loc(colon2_t), loc(name_t), expr_l) end
# File lib/parser/builders/default.rb, line 2025 def definition_map(keyword_t, operator_t, name_t, end_t) Source::Map::MethodDefinition.new(loc(keyword_t), loc(operator_t), loc(name_t), loc(end_t), nil, nil) end
# File lib/parser/builders/default.rb, line 1858 def delimited_string_map(string_t) str_range = loc(string_t) begin_l = str_range.with(end_pos: str_range.begin_pos + 1) end_l = str_range.with(begin_pos: str_range.end_pos - 1) Source::Map::Collection.new(begin_l, end_l, loc(string_t)) end
# File lib/parser/builders/default.rb, line 2273 def diagnostic(type, reason, arguments, location, highlights=[]) @parser.diagnostics.process( Diagnostic.new(type, reason, arguments, location, highlights)) if type == :error @parser.send :yyerror end end
# File lib/parser/builders/default.rb, line 2165 def eh_keyword_map(compstmt_e, keyword_t, body_es, else_t, else_e) if compstmt_e.nil? if keyword_t.nil? begin_l = body_es.first.loc.expression else begin_l = loc(keyword_t) end else begin_l = compstmt_e.loc.expression end if else_t if else_e.nil? end_l = loc(else_t) else end_l = else_e.loc.expression end elsif !body_es.last.nil? end_l = body_es.last.loc.expression else end_l = loc(keyword_t) end Source::Map::Condition.new(loc(keyword_t), nil, loc(else_t), nil, begin_l.join(end_l)) end
# File lib/parser/builders/default.rb, line 2031 def endless_definition_map(keyword_t, operator_t, name_t, assignment_t, body_e) body_l = body_e.loc.expression Source::Map::MethodDefinition.new(loc(keyword_t), loc(operator_t), loc(name_t), nil, loc(assignment_t), body_l) end
# File lib/parser/builders/default.rb, line 1913 def expr_map(loc) Source::Map.new(loc) end
# File lib/parser/builders/default.rb, line 2146 def for_map(keyword_t, in_t, begin_t, end_t) Source::Map::For.new(loc(keyword_t), loc(in_t), loc(begin_t), loc(end_t), loc(keyword_t).join(loc(end_t))) end
# File lib/parser/builders/default.rb, line 2193 def guard_map(keyword_t, guard_body_e) keyword_l = loc(keyword_t) guard_body_l = guard_body_e.loc.expression Source::Map::Keyword.new(keyword_l, nil, nil, keyword_l.join(guard_body_l)) end
# File lib/parser/builders/default.rb, line 2083 def index_map(receiver_e, lbrack_t, rbrack_t) Source::Map::Index.new(loc(lbrack_t), loc(rbrack_t), receiver_e.loc.expression.join(loc(rbrack_t))) end
# File lib/parser/builders/default.rb, line 1849 def join_exprs(left_expr, right_expr) left_expr.loc.expression. join(right_expr.loc.expression) end
# File lib/parser/builders/default.rb, line 2099 def keyword_map(keyword_t, begin_t, args, end_t) args ||= [] if end_t end_l = loc(end_t) elsif args.any? && !args.last.nil? end_l = args.last.loc.expression elsif args.any? && args.count > 1 end_l = args[-2].loc.expression else end_l = loc(keyword_t) end Source::Map::Keyword.new(loc(keyword_t), loc(begin_t), loc(end_t), loc(keyword_t).join(end_l)) end
# File lib/parser/builders/default.rb, line 2116 def keyword_mod_map(pre_e, keyword_t, post_e) Source::Map::Keyword.new(loc(keyword_t), nil, nil, join_exprs(pre_e, post_e)) end
# File lib/parser/builders/default.rb, line 2002 def kwarg_map(name_t, value_e=nil) label_range = loc(name_t) name_range = label_range.adjust(end_pos: -1) if value_e expr_l = loc(name_t).join(value_e.loc.expression) else expr_l = loc(name_t) end Source::Map::Variable.new(name_range, expr_l) end
# File lib/parser/builders/default.rb, line 2304 def kwargs?(node) node.type == :hash && node.loc.begin.nil? && node.loc.end.nil? end
# File lib/parser/builders/default.rb, line 2268 def loc(token) # Pass through `nil`s and return nil for tNL. token[1] if token && token[0] end
# File lib/parser/builders/default.rb, line 2015 def module_definition_map(keyword_t, name_e, operator_t, end_t) if name_e name_l = name_e.loc.expression end Source::Map::Definition.new(loc(keyword_t), loc(operator_t), name_l, loc(end_t)) end
SOURCE MAPS
# File lib/parser/builders/default.rb, line 1841 def n(type, children, source_map) AST::Node.new(type, children, :location => source_map) end
# File lib/parser/builders/default.rb, line 1845 def n0(type, source_map) n(type, [], source_map) end
# File lib/parser/builders/default.rb, line 288 def numeric(kind, token) n(kind, [ value(token) ], Source::Map::Operator.new(nil, loc(token))) end
# File lib/parser/builders/default.rb, line 1883 def pair_keyword_map(key_t, value_e) key_range = loc(key_t) key_l = key_range.adjust(end_pos: -1) colon_l = key_range.with(begin_pos: key_range.end_pos - 1) [ # key map Source::Map::Collection.new(nil, nil, key_l), # pair map Source::Map::Operator.new(colon_l, key_range.join(value_e.loc.expression)) ] end
# File lib/parser/builders/default.rb, line 1898 def pair_quoted_map(begin_t, end_t, value_e) end_l = loc(end_t) quote_l = end_l.with(begin_pos: end_l.end_pos - 2, end_pos: end_l.end_pos - 1) colon_l = end_l.with(begin_pos: end_l.end_pos - 1) [ # modified end token [ value(end_t), quote_l ], # pair map Source::Map::Operator.new(colon_l, loc(begin_t).join(value_e.loc.expression)) ] end
# File lib/parser/builders/default.rb, line 1869 def prefix_string_map(symbol) str_range = loc(symbol) begin_l = str_range.with(end_pos: str_range.begin_pos + 1) Source::Map::Collection.new(begin_l, nil, loc(symbol)) end
# File lib/parser/builders/default.rb, line 1980 def range_map(start_e, op_t, end_e) if start_e && end_e expr_l = join_exprs(start_e, end_e) elsif start_e expr_l = start_e.loc.expression.join(loc(op_t)) elsif end_e expr_l = loc(op_t).join(end_e.loc.expression) end Source::Map::Operator.new(loc(op_t), expr_l) end
# File lib/parser/builders/default.rb, line 1947 def regexp_map(begin_t, end_t, options_e) Source::Map::Collection.new(loc(begin_t), loc(end_t), loc(begin_t).join(options_e.loc.expression)) end
# File lib/parser/builders/default.rb, line 2152 def rescue_body_map(keyword_t, exc_list_e, assoc_t, exc_var_e, then_t, compstmt_e) end_l = compstmt_e.loc.expression if compstmt_e end_l = loc(then_t) if end_l.nil? && then_t end_l = exc_var_e.loc.expression if end_l.nil? && exc_var_e end_l = exc_list_e.loc.expression if end_l.nil? && exc_list_e end_l = loc(keyword_t) if end_l.nil? Source::Map::RescueBody.new(loc(keyword_t), loc(assoc_t), loc(then_t), loc(keyword_t).join(end_l)) end
# File lib/parser/builders/default.rb, line 2294 def rewrite_hash_args_to_kwargs(args) if args.any? && kwargs?(args.last) # foo(..., bar: baz) args[args.length - 1] = args[args.length - 1].updated(:kwargs) elsif args.length > 1 && args.last.type == :block_pass && kwargs?(args[args.length - 2]) # foo(..., bar: baz, &blk) args[args.length - 2] = args[args.length - 2].updated(:kwargs) end end
# File lib/parser/builders/default.rb, line 2065 def send_binary_op_map(lhs_e, selector_t, rhs_e) Source::Map::Send.new(nil, loc(selector_t), nil, nil, join_exprs(lhs_e, rhs_e)) end
# File lib/parser/builders/default.rb, line 2088 def send_index_map(receiver_e, lbrack_t, rbrack_t) Source::Map::Send.new(nil, loc(lbrack_t).join(loc(rbrack_t)), nil, nil, receiver_e.loc.expression.join(loc(rbrack_t))) end
# File lib/parser/builders/default.rb, line 2039 def send_map(receiver_e, dot_t, selector_t, begin_t=nil, args=[], end_t=nil) if receiver_e begin_l = receiver_e.loc.expression elsif selector_t begin_l = loc(selector_t) end if end_t end_l = loc(end_t) elsif args.any? end_l = args.last.loc.expression elsif selector_t end_l = loc(selector_t) end Source::Map::Send.new(loc(dot_t), loc(selector_t), loc(begin_t), loc(end_t), begin_l.join(end_l)) end
# File lib/parser/builders/default.rb, line 2071 def send_unary_op_map(selector_t, arg_e) if arg_e.nil? expr_l = loc(selector_t) else expr_l = loc(selector_t).join(arg_e.loc.expression) end Source::Map::Send.new(nil, loc(selector_t), nil, nil, expr_l) end
# File lib/parser/builders/default.rb, line 2224 def static_regexp(parts, options) source = static_string(parts) return nil if source.nil? source = case when options.children.include?(:u) source.encode(Encoding::UTF_8) when options.children.include?(:e) source.encode(Encoding::EUC_JP) when options.children.include?(:s) source.encode(Encoding::WINDOWS_31J) when options.children.include?(:n) source.encode(Encoding::BINARY) else source end Regexp.new(source, (Regexp::EXTENDED if options.children.include?(:x))) end
# File lib/parser/builders/default.rb, line 2244 def static_regexp_node(node) if node.type == :regexp parts, options = node.children[0..-2], node.children[-1] static_regexp(parts, options) end end
Extract a static string from e.g. a regular expression, honoring the fact that MRI expands interpolations like #{“”} at parse time.
# File lib/parser/builders/default.rb, line 2207 def static_string(nodes) nodes.map do |node| case node.type when :str node.children[0] when :begin if (string = static_string(node.children)) string else return nil end else return nil end end.join end
# File lib/parser/builders/default.rb, line 1933 def string_map(begin_t, parts, end_t) if begin_t && value(begin_t).start_with?('<<') if parts.any? expr_l = join_exprs(parts.first, parts.last) else expr_l = loc(end_t).begin end Source::Map::Heredoc.new(loc(begin_t), expr_l, loc(end_t)) else collection_map(begin_t, parts, end_t) end end
# File lib/parser/builders/default.rb, line 2260 def string_value(token) unless token[0].valid_encoding? diagnostic(:error, :invalid_encoding, nil, token[1]) end token[0] end
# File lib/parser/builders/default.rb, line 2141 def ternary_map(begin_e, question_t, mid_e, colon_t, end_e) Source::Map::Ternary.new(loc(question_t), loc(colon_t), join_exprs(begin_e, end_e)) end
# File lib/parser/builders/default.rb, line 1854 def token_map(token) Source::Map.new(loc(token)) end
# File lib/parser/builders/default.rb, line 1970 def unary_op_map(op_t, arg_e=nil) if arg_e.nil? expr_l = loc(op_t) else expr_l = loc(op_t).join(arg_e.loc.expression) end Source::Map::Operator.new(loc(op_t), expr_l) end
# File lib/parser/builders/default.rb, line 1878 def unquoted_map(token) Source::Map::Collection.new(nil, nil, loc(token)) end
# File lib/parser/builders/default.rb, line 2282 def validate_definee(definee) case definee.type when :int, :str, :dstr, :sym, :dsym, :regexp, :array, :hash diagnostic :error, :singleton_literal, nil, definee.loc.expression false else true end end
# File lib/parser/builders/default.rb, line 1756 def validate_no_forward_arg_after_restarg(args) restarg = nil forward_arg = nil args.each do |arg| case arg.type when :restarg then restarg = arg when :forward_arg then forward_arg = arg end end if !forward_arg.nil? && !restarg.nil? diagnostic :error, :forward_arg_after_restarg, nil, forward_arg.loc.expression, [restarg.loc.expression] end end
# File lib/parser/builders/default.rb, line 2256 def value(token) token[0] end
# File lib/parser/builders/default.rb, line 2059 def var_send_map(variable_e) Source::Map::Send.new(nil, variable_e.loc.expression, nil, nil, variable_e.loc.expression) end
# File lib/parser/builders/default.rb, line 1962 def variable_map(name_t) Source::Map::Variable.new(loc(name_t)) end