Server IP : 66.29.132.122 / Your IP : 3.22.79.55 Web Server : LiteSpeed System : Linux business142.web-hosting.com 4.18.0-553.lve.el8.x86_64 #1 SMP Mon May 27 15:27:34 UTC 2024 x86_64 User : admazpex ( 531) PHP Version : 7.2.34 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : OFF | Pkexec : OFF Directory : /proc/self/root/opt/alt/ruby33/share/ruby/prism/ |
Upload File : |
# frozen_string_literal: true =begin This file is generated by the templates/template.rb script and should not be modified manually. See templates/lib/prism/node.rb.erb if you are looking to modify the template =end module Prism # This represents a node in the tree. It is the parent class of all of the # various node types. class Node # A Location instance that represents the location of this node in the # source. attr_reader :location def newline? # :nodoc: @newline ? true : false end def set_newline_flag(newline_marked) # :nodoc: line = location.start_line unless newline_marked[line] newline_marked[line] = true @newline = true end end # Slice the location of the node from the source. def slice location.slice end # Similar to inspect, but respects the current level of indentation given by # the pretty print object. def pretty_print(q) q.seplist(inspect.chomp.each_line, -> { q.breakable }) do |line| q.text(line.chomp) end q.current_group.break end # Convert this node into a graphviz dot graph string. def to_dot DotVisitor.new.tap { |visitor| accept(visitor) }.to_dot end end # Represents the use of the `alias` keyword to alias a global variable. # # alias $foo $bar # ^^^^^^^^^^^^^^^ class AliasGlobalVariableNode < Node # attr_reader new_name: Node attr_reader :new_name # attr_reader old_name: Node attr_reader :old_name # attr_reader keyword_loc: Location attr_reader :keyword_loc # def initialize: (new_name: Node, old_name: Node, keyword_loc: Location, location: Location) -> void def initialize(new_name, old_name, keyword_loc, location) @new_name = new_name @old_name = old_name @keyword_loc = keyword_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_alias_global_variable_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [new_name, old_name] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [new_name, old_name] end # def comment_targets: () -> Array[Node | Location] def comment_targets [new_name, old_name, keyword_loc] end # def copy: (**params) -> AliasGlobalVariableNode def copy(**params) AliasGlobalVariableNode.new( params.fetch(:new_name) { new_name }, params.fetch(:old_name) { old_name }, params.fetch(:keyword_loc) { keyword_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { new_name: new_name, old_name: old_name, keyword_loc: keyword_loc, location: location } end # def keyword: () -> String def keyword keyword_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── new_name:\n" inspector << inspector.child_node(new_name, "│ ") inspector << "├── old_name:\n" inspector << inspector.child_node(old_name, "│ ") inspector << "└── keyword_loc: #{inspector.location(keyword_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :alias_global_variable_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :alias_global_variable_node end end # Represents the use of the `alias` keyword to alias a method. # # alias foo bar # ^^^^^^^^^^^^^ class AliasMethodNode < Node # attr_reader new_name: Node attr_reader :new_name # attr_reader old_name: Node attr_reader :old_name # attr_reader keyword_loc: Location attr_reader :keyword_loc # def initialize: (new_name: Node, old_name: Node, keyword_loc: Location, location: Location) -> void def initialize(new_name, old_name, keyword_loc, location) @new_name = new_name @old_name = old_name @keyword_loc = keyword_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_alias_method_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [new_name, old_name] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [new_name, old_name] end # def comment_targets: () -> Array[Node | Location] def comment_targets [new_name, old_name, keyword_loc] end # def copy: (**params) -> AliasMethodNode def copy(**params) AliasMethodNode.new( params.fetch(:new_name) { new_name }, params.fetch(:old_name) { old_name }, params.fetch(:keyword_loc) { keyword_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { new_name: new_name, old_name: old_name, keyword_loc: keyword_loc, location: location } end # def keyword: () -> String def keyword keyword_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── new_name:\n" inspector << inspector.child_node(new_name, "│ ") inspector << "├── old_name:\n" inspector << inspector.child_node(old_name, "│ ") inspector << "└── keyword_loc: #{inspector.location(keyword_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :alias_method_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :alias_method_node end end # Represents an alternation pattern in pattern matching. # # foo => bar | baz # ^^^^^^^^^ class AlternationPatternNode < Node # attr_reader left: Node attr_reader :left # attr_reader right: Node attr_reader :right # attr_reader operator_loc: Location attr_reader :operator_loc # def initialize: (left: Node, right: Node, operator_loc: Location, location: Location) -> void def initialize(left, right, operator_loc, location) @left = left @right = right @operator_loc = operator_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_alternation_pattern_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [left, right] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [left, right] end # def comment_targets: () -> Array[Node | Location] def comment_targets [left, right, operator_loc] end # def copy: (**params) -> AlternationPatternNode def copy(**params) AlternationPatternNode.new( params.fetch(:left) { left }, params.fetch(:right) { right }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { left: left, right: right, operator_loc: operator_loc, location: location } end # def operator: () -> String def operator operator_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── left:\n" inspector << inspector.child_node(left, "│ ") inspector << "├── right:\n" inspector << inspector.child_node(right, "│ ") inspector << "└── operator_loc: #{inspector.location(operator_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :alternation_pattern_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :alternation_pattern_node end end # Represents the use of the `&&` operator or the `and` keyword. # # left and right # ^^^^^^^^^^^^^^ class AndNode < Node # attr_reader left: Node attr_reader :left # attr_reader right: Node attr_reader :right # attr_reader operator_loc: Location attr_reader :operator_loc # def initialize: (left: Node, right: Node, operator_loc: Location, location: Location) -> void def initialize(left, right, operator_loc, location) @left = left @right = right @operator_loc = operator_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_and_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [left, right] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [left, right] end # def comment_targets: () -> Array[Node | Location] def comment_targets [left, right, operator_loc] end # def copy: (**params) -> AndNode def copy(**params) AndNode.new( params.fetch(:left) { left }, params.fetch(:right) { right }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { left: left, right: right, operator_loc: operator_loc, location: location } end # def operator: () -> String def operator operator_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── left:\n" inspector << inspector.child_node(left, "│ ") inspector << "├── right:\n" inspector << inspector.child_node(right, "│ ") inspector << "└── operator_loc: #{inspector.location(operator_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :and_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :and_node end end # Represents a set of arguments to a method or a keyword. # # return foo, bar, baz # ^^^^^^^^^^^^^ class ArgumentsNode < Node # attr_reader flags: Integer private attr_reader :flags # attr_reader arguments: Array[Node] attr_reader :arguments # def initialize: (flags: Integer, arguments: Array[Node], location: Location) -> void def initialize(flags, arguments, location) @flags = flags @arguments = arguments @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_arguments_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [*arguments] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [*arguments] end # def comment_targets: () -> Array[Node | Location] def comment_targets [*arguments] end # def copy: (**params) -> ArgumentsNode def copy(**params) ArgumentsNode.new( params.fetch(:flags) { flags }, params.fetch(:arguments) { arguments }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { flags: flags, arguments: arguments, location: location } end # def contains_keyword_splat?: () -> bool def contains_keyword_splat? flags.anybits?(ArgumentsNodeFlags::CONTAINS_KEYWORD_SPLAT) end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) flags = [("contains_keyword_splat" if contains_keyword_splat?)].compact inspector << "├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n" inspector << "└── arguments: #{inspector.list("#{inspector.prefix} ", arguments)}" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :arguments_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :arguments_node end end # Represents an array literal. This can be a regular array using brackets or # a special array using % like %w or %i. # # [1, 2, 3] # ^^^^^^^^^ class ArrayNode < Node # attr_reader flags: Integer private attr_reader :flags # attr_reader elements: Array[Node] attr_reader :elements # attr_reader opening_loc: Location? attr_reader :opening_loc # attr_reader closing_loc: Location? attr_reader :closing_loc # def initialize: (flags: Integer, elements: Array[Node], opening_loc: Location?, closing_loc: Location?, location: Location) -> void def initialize(flags, elements, opening_loc, closing_loc, location) @flags = flags @elements = elements @opening_loc = opening_loc @closing_loc = closing_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_array_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [*elements] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [*elements] end # def comment_targets: () -> Array[Node | Location] def comment_targets [*elements, *opening_loc, *closing_loc] end # def copy: (**params) -> ArrayNode def copy(**params) ArrayNode.new( params.fetch(:flags) { flags }, params.fetch(:elements) { elements }, params.fetch(:opening_loc) { opening_loc }, params.fetch(:closing_loc) { closing_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { flags: flags, elements: elements, opening_loc: opening_loc, closing_loc: closing_loc, location: location } end # def contains_splat?: () -> bool def contains_splat? flags.anybits?(ArrayNodeFlags::CONTAINS_SPLAT) end # def opening: () -> String? def opening opening_loc&.slice end # def closing: () -> String? def closing closing_loc&.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) flags = [("contains_splat" if contains_splat?)].compact inspector << "├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n" inspector << "├── elements: #{inspector.list("#{inspector.prefix}│ ", elements)}" inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n" inspector << "└── closing_loc: #{inspector.location(closing_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :array_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :array_node end end # Represents an array pattern in pattern matching. # # foo in 1, 2 # ^^^^^^^^^^^ # # foo in [1, 2] # ^^^^^^^^^^^^^ # # foo in *1 # ^^^^^^^^^ # # foo in Bar[] # ^^^^^^^^^^^^ # # foo in Bar[1, 2, 3] # ^^^^^^^^^^^^^^^^^^^ class ArrayPatternNode < Node # attr_reader constant: Node? attr_reader :constant # attr_reader requireds: Array[Node] attr_reader :requireds # attr_reader rest: Node? attr_reader :rest # attr_reader posts: Array[Node] attr_reader :posts # attr_reader opening_loc: Location? attr_reader :opening_loc # attr_reader closing_loc: Location? attr_reader :closing_loc # def initialize: (constant: Node?, requireds: Array[Node], rest: Node?, posts: Array[Node], opening_loc: Location?, closing_loc: Location?, location: Location) -> void def initialize(constant, requireds, rest, posts, opening_loc, closing_loc, location) @constant = constant @requireds = requireds @rest = rest @posts = posts @opening_loc = opening_loc @closing_loc = closing_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_array_pattern_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [constant, *requireds, rest, *posts] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact << constant if constant compact.concat(requireds) compact << rest if rest compact.concat(posts) compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [*constant, *requireds, *rest, *posts, *opening_loc, *closing_loc] end # def copy: (**params) -> ArrayPatternNode def copy(**params) ArrayPatternNode.new( params.fetch(:constant) { constant }, params.fetch(:requireds) { requireds }, params.fetch(:rest) { rest }, params.fetch(:posts) { posts }, params.fetch(:opening_loc) { opening_loc }, params.fetch(:closing_loc) { closing_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { constant: constant, requireds: requireds, rest: rest, posts: posts, opening_loc: opening_loc, closing_loc: closing_loc, location: location } end # def opening: () -> String? def opening opening_loc&.slice end # def closing: () -> String? def closing closing_loc&.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) if (constant = self.constant).nil? inspector << "├── constant: ∅\n" else inspector << "├── constant:\n" inspector << constant.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "├── requireds: #{inspector.list("#{inspector.prefix}│ ", requireds)}" if (rest = self.rest).nil? inspector << "├── rest: ∅\n" else inspector << "├── rest:\n" inspector << rest.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "├── posts: #{inspector.list("#{inspector.prefix}│ ", posts)}" inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n" inspector << "└── closing_loc: #{inspector.location(closing_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :array_pattern_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :array_pattern_node end end # Represents a hash key/value pair. # # { a => b } # ^^^^^^ class AssocNode < Node # attr_reader key: Node attr_reader :key # attr_reader value: Node? attr_reader :value # attr_reader operator_loc: Location? attr_reader :operator_loc # def initialize: (key: Node, value: Node?, operator_loc: Location?, location: Location) -> void def initialize(key, value, operator_loc, location) @key = key @value = value @operator_loc = operator_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_assoc_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [key, value] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact << key compact << value if value compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [key, *value, *operator_loc] end # def copy: (**params) -> AssocNode def copy(**params) AssocNode.new( params.fetch(:key) { key }, params.fetch(:value) { value }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { key: key, value: value, operator_loc: operator_loc, location: location } end # def operator: () -> String? def operator operator_loc&.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── key:\n" inspector << inspector.child_node(key, "│ ") if (value = self.value).nil? inspector << "├── value: ∅\n" else inspector << "├── value:\n" inspector << value.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "└── operator_loc: #{inspector.location(operator_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :assoc_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :assoc_node end end # Represents a splat in a hash literal. # # { **foo } # ^^^^^ class AssocSplatNode < Node # attr_reader value: Node? attr_reader :value # attr_reader operator_loc: Location attr_reader :operator_loc # def initialize: (value: Node?, operator_loc: Location, location: Location) -> void def initialize(value, operator_loc, location) @value = value @operator_loc = operator_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_assoc_splat_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [value] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact << value if value compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [*value, operator_loc] end # def copy: (**params) -> AssocSplatNode def copy(**params) AssocSplatNode.new( params.fetch(:value) { value }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { value: value, operator_loc: operator_loc, location: location } end # def operator: () -> String def operator operator_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) if (value = self.value).nil? inspector << "├── value: ∅\n" else inspector << "├── value:\n" inspector << value.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "└── operator_loc: #{inspector.location(operator_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :assoc_splat_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :assoc_splat_node end end # Represents reading a reference to a field in the previous match. # # $' # ^^ class BackReferenceReadNode < Node # attr_reader name: Symbol attr_reader :name # def initialize: (name: Symbol, location: Location) -> void def initialize(name, location) @name = name @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_back_reference_read_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [] end # def comment_targets: () -> Array[Node | Location] def comment_targets [] end # def copy: (**params) -> BackReferenceReadNode def copy(**params) BackReferenceReadNode.new( params.fetch(:name) { name }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { name: name, location: location } end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "└── name: #{name.inspect}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :back_reference_read_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :back_reference_read_node end end # Represents a begin statement. # # begin # foo # end # ^^^^^ class BeginNode < Node # attr_reader begin_keyword_loc: Location? attr_reader :begin_keyword_loc # attr_reader statements: StatementsNode? attr_reader :statements # attr_reader rescue_clause: RescueNode? attr_reader :rescue_clause # attr_reader else_clause: ElseNode? attr_reader :else_clause # attr_reader ensure_clause: EnsureNode? attr_reader :ensure_clause # attr_reader end_keyword_loc: Location? attr_reader :end_keyword_loc # def initialize: (begin_keyword_loc: Location?, statements: StatementsNode?, rescue_clause: RescueNode?, else_clause: ElseNode?, ensure_clause: EnsureNode?, end_keyword_loc: Location?, location: Location) -> void def initialize(begin_keyword_loc, statements, rescue_clause, else_clause, ensure_clause, end_keyword_loc, location) @begin_keyword_loc = begin_keyword_loc @statements = statements @rescue_clause = rescue_clause @else_clause = else_clause @ensure_clause = ensure_clause @end_keyword_loc = end_keyword_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_begin_node(self) end def set_newline_flag(newline_marked) # :nodoc: # Never mark BeginNode with a newline flag, mark children instead end # def child_nodes: () -> Array[nil | Node] def child_nodes [statements, rescue_clause, else_clause, ensure_clause] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact << statements if statements compact << rescue_clause if rescue_clause compact << else_clause if else_clause compact << ensure_clause if ensure_clause compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [*begin_keyword_loc, *statements, *rescue_clause, *else_clause, *ensure_clause, *end_keyword_loc] end # def copy: (**params) -> BeginNode def copy(**params) BeginNode.new( params.fetch(:begin_keyword_loc) { begin_keyword_loc }, params.fetch(:statements) { statements }, params.fetch(:rescue_clause) { rescue_clause }, params.fetch(:else_clause) { else_clause }, params.fetch(:ensure_clause) { ensure_clause }, params.fetch(:end_keyword_loc) { end_keyword_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { begin_keyword_loc: begin_keyword_loc, statements: statements, rescue_clause: rescue_clause, else_clause: else_clause, ensure_clause: ensure_clause, end_keyword_loc: end_keyword_loc, location: location } end # def begin_keyword: () -> String? def begin_keyword begin_keyword_loc&.slice end # def end_keyword: () -> String? def end_keyword end_keyword_loc&.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── begin_keyword_loc: #{inspector.location(begin_keyword_loc)}\n" if (statements = self.statements).nil? inspector << "├── statements: ∅\n" else inspector << "├── statements:\n" inspector << statements.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end if (rescue_clause = self.rescue_clause).nil? inspector << "├── rescue_clause: ∅\n" else inspector << "├── rescue_clause:\n" inspector << rescue_clause.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end if (else_clause = self.else_clause).nil? inspector << "├── else_clause: ∅\n" else inspector << "├── else_clause:\n" inspector << else_clause.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end if (ensure_clause = self.ensure_clause).nil? inspector << "├── ensure_clause: ∅\n" else inspector << "├── ensure_clause:\n" inspector << ensure_clause.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "└── end_keyword_loc: #{inspector.location(end_keyword_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :begin_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :begin_node end end # Represents block method arguments. # # bar(&args) # ^^^^^^^^^^ class BlockArgumentNode < Node # attr_reader expression: Node? attr_reader :expression # attr_reader operator_loc: Location attr_reader :operator_loc # def initialize: (expression: Node?, operator_loc: Location, location: Location) -> void def initialize(expression, operator_loc, location) @expression = expression @operator_loc = operator_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_block_argument_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [expression] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact << expression if expression compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [*expression, operator_loc] end # def copy: (**params) -> BlockArgumentNode def copy(**params) BlockArgumentNode.new( params.fetch(:expression) { expression }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { expression: expression, operator_loc: operator_loc, location: location } end # def operator: () -> String def operator operator_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) if (expression = self.expression).nil? inspector << "├── expression: ∅\n" else inspector << "├── expression:\n" inspector << expression.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "└── operator_loc: #{inspector.location(operator_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :block_argument_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :block_argument_node end end # Represents a block local variable. # # a { |; b| } # ^ class BlockLocalVariableNode < Node # attr_reader name: Symbol attr_reader :name # def initialize: (name: Symbol, location: Location) -> void def initialize(name, location) @name = name @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_block_local_variable_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [] end # def comment_targets: () -> Array[Node | Location] def comment_targets [] end # def copy: (**params) -> BlockLocalVariableNode def copy(**params) BlockLocalVariableNode.new( params.fetch(:name) { name }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { name: name, location: location } end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "└── name: #{name.inspect}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :block_local_variable_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :block_local_variable_node end end # Represents a block of ruby code. # # [1, 2, 3].each { |i| puts x } # ^^^^^^^^^^^^^^ class BlockNode < Node # attr_reader locals: Array[Symbol] attr_reader :locals # attr_reader locals_body_index: Integer attr_reader :locals_body_index # attr_reader parameters: Node? attr_reader :parameters # attr_reader body: Node? attr_reader :body # attr_reader opening_loc: Location attr_reader :opening_loc # attr_reader closing_loc: Location attr_reader :closing_loc # def initialize: (locals: Array[Symbol], locals_body_index: Integer, parameters: Node?, body: Node?, opening_loc: Location, closing_loc: Location, location: Location) -> void def initialize(locals, locals_body_index, parameters, body, opening_loc, closing_loc, location) @locals = locals @locals_body_index = locals_body_index @parameters = parameters @body = body @opening_loc = opening_loc @closing_loc = closing_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_block_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [parameters, body] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact << parameters if parameters compact << body if body compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [*parameters, *body, opening_loc, closing_loc] end # def copy: (**params) -> BlockNode def copy(**params) BlockNode.new( params.fetch(:locals) { locals }, params.fetch(:locals_body_index) { locals_body_index }, params.fetch(:parameters) { parameters }, params.fetch(:body) { body }, params.fetch(:opening_loc) { opening_loc }, params.fetch(:closing_loc) { closing_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { locals: locals, locals_body_index: locals_body_index, parameters: parameters, body: body, opening_loc: opening_loc, closing_loc: closing_loc, location: location } end # def opening: () -> String def opening opening_loc.slice end # def closing: () -> String def closing closing_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── locals: #{locals.inspect}\n" inspector << "├── locals_body_index: #{locals_body_index.inspect}\n" if (parameters = self.parameters).nil? inspector << "├── parameters: ∅\n" else inspector << "├── parameters:\n" inspector << parameters.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end if (body = self.body).nil? inspector << "├── body: ∅\n" else inspector << "├── body:\n" inspector << body.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n" inspector << "└── closing_loc: #{inspector.location(closing_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :block_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :block_node end end # Represents a block parameter to a method, block, or lambda definition. # # def a(&b) # ^^ # end class BlockParameterNode < Node # attr_reader name: Symbol? attr_reader :name # attr_reader name_loc: Location? attr_reader :name_loc # attr_reader operator_loc: Location attr_reader :operator_loc # def initialize: (name: Symbol?, name_loc: Location?, operator_loc: Location, location: Location) -> void def initialize(name, name_loc, operator_loc, location) @name = name @name_loc = name_loc @operator_loc = operator_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_block_parameter_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [] end # def comment_targets: () -> Array[Node | Location] def comment_targets [*name_loc, operator_loc] end # def copy: (**params) -> BlockParameterNode def copy(**params) BlockParameterNode.new( params.fetch(:name) { name }, params.fetch(:name_loc) { name_loc }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { name: name, name_loc: name_loc, operator_loc: operator_loc, location: location } end # def operator: () -> String def operator operator_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) if (name = self.name).nil? inspector << "├── name: ∅\n" else inspector << "├── name: #{name.inspect}\n" end inspector << "├── name_loc: #{inspector.location(name_loc)}\n" inspector << "└── operator_loc: #{inspector.location(operator_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :block_parameter_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :block_parameter_node end end # Represents a block's parameters declaration. # # -> (a, b = 1; local) { } # ^^^^^^^^^^^^^^^^^ # # foo do |a, b = 1; local| # ^^^^^^^^^^^^^^^^^ # end class BlockParametersNode < Node # attr_reader parameters: ParametersNode? attr_reader :parameters # attr_reader locals: Array[Node] attr_reader :locals # attr_reader opening_loc: Location? attr_reader :opening_loc # attr_reader closing_loc: Location? attr_reader :closing_loc # def initialize: (parameters: ParametersNode?, locals: Array[Node], opening_loc: Location?, closing_loc: Location?, location: Location) -> void def initialize(parameters, locals, opening_loc, closing_loc, location) @parameters = parameters @locals = locals @opening_loc = opening_loc @closing_loc = closing_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_block_parameters_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [parameters, *locals] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact << parameters if parameters compact.concat(locals) compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [*parameters, *locals, *opening_loc, *closing_loc] end # def copy: (**params) -> BlockParametersNode def copy(**params) BlockParametersNode.new( params.fetch(:parameters) { parameters }, params.fetch(:locals) { locals }, params.fetch(:opening_loc) { opening_loc }, params.fetch(:closing_loc) { closing_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { parameters: parameters, locals: locals, opening_loc: opening_loc, closing_loc: closing_loc, location: location } end # def opening: () -> String? def opening opening_loc&.slice end # def closing: () -> String? def closing closing_loc&.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) if (parameters = self.parameters).nil? inspector << "├── parameters: ∅\n" else inspector << "├── parameters:\n" inspector << parameters.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "├── locals: #{inspector.list("#{inspector.prefix}│ ", locals)}" inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n" inspector << "└── closing_loc: #{inspector.location(closing_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :block_parameters_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :block_parameters_node end end # Represents the use of the `break` keyword. # # break foo # ^^^^^^^^^ class BreakNode < Node # attr_reader arguments: ArgumentsNode? attr_reader :arguments # attr_reader keyword_loc: Location attr_reader :keyword_loc # def initialize: (arguments: ArgumentsNode?, keyword_loc: Location, location: Location) -> void def initialize(arguments, keyword_loc, location) @arguments = arguments @keyword_loc = keyword_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_break_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [arguments] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact << arguments if arguments compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [*arguments, keyword_loc] end # def copy: (**params) -> BreakNode def copy(**params) BreakNode.new( params.fetch(:arguments) { arguments }, params.fetch(:keyword_loc) { keyword_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { arguments: arguments, keyword_loc: keyword_loc, location: location } end # def keyword: () -> String def keyword keyword_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) if (arguments = self.arguments).nil? inspector << "├── arguments: ∅\n" else inspector << "├── arguments:\n" inspector << arguments.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "└── keyword_loc: #{inspector.location(keyword_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :break_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :break_node end end # Represents the use of the `&&=` operator on a call. # # foo.bar &&= value # ^^^^^^^^^^^^^^^^^ class CallAndWriteNode < Node # attr_reader flags: Integer private attr_reader :flags # attr_reader receiver: Node? attr_reader :receiver # attr_reader call_operator_loc: Location? attr_reader :call_operator_loc # attr_reader message_loc: Location? attr_reader :message_loc # attr_reader read_name: Symbol attr_reader :read_name # attr_reader write_name: Symbol attr_reader :write_name # attr_reader operator_loc: Location attr_reader :operator_loc # attr_reader value: Node attr_reader :value # def initialize: (flags: Integer, receiver: Node?, call_operator_loc: Location?, message_loc: Location?, read_name: Symbol, write_name: Symbol, operator_loc: Location, value: Node, location: Location) -> void def initialize(flags, receiver, call_operator_loc, message_loc, read_name, write_name, operator_loc, value, location) @flags = flags @receiver = receiver @call_operator_loc = call_operator_loc @message_loc = message_loc @read_name = read_name @write_name = write_name @operator_loc = operator_loc @value = value @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_call_and_write_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [receiver, value] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact << receiver if receiver compact << value compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [*receiver, *call_operator_loc, *message_loc, operator_loc, value] end # def copy: (**params) -> CallAndWriteNode def copy(**params) CallAndWriteNode.new( params.fetch(:flags) { flags }, params.fetch(:receiver) { receiver }, params.fetch(:call_operator_loc) { call_operator_loc }, params.fetch(:message_loc) { message_loc }, params.fetch(:read_name) { read_name }, params.fetch(:write_name) { write_name }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:value) { value }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { flags: flags, receiver: receiver, call_operator_loc: call_operator_loc, message_loc: message_loc, read_name: read_name, write_name: write_name, operator_loc: operator_loc, value: value, location: location } end # def safe_navigation?: () -> bool def safe_navigation? flags.anybits?(CallNodeFlags::SAFE_NAVIGATION) end # def variable_call?: () -> bool def variable_call? flags.anybits?(CallNodeFlags::VARIABLE_CALL) end # def attribute_write?: () -> bool def attribute_write? flags.anybits?(CallNodeFlags::ATTRIBUTE_WRITE) end # def call_operator: () -> String? def call_operator call_operator_loc&.slice end # def message: () -> String? def message message_loc&.slice end # def operator: () -> String def operator operator_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) flags = [("safe_navigation" if safe_navigation?), ("variable_call" if variable_call?), ("attribute_write" if attribute_write?)].compact inspector << "├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n" if (receiver = self.receiver).nil? inspector << "├── receiver: ∅\n" else inspector << "├── receiver:\n" inspector << receiver.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "├── call_operator_loc: #{inspector.location(call_operator_loc)}\n" inspector << "├── message_loc: #{inspector.location(message_loc)}\n" inspector << "├── read_name: #{read_name.inspect}\n" inspector << "├── write_name: #{write_name.inspect}\n" inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n" inspector << "└── value:\n" inspector << inspector.child_node(value, " ") inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :call_and_write_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :call_and_write_node end end # Represents a method call, in all of the various forms that can take. # # foo # ^^^ # # foo() # ^^^^^ # # +foo # ^^^^ # # foo + bar # ^^^^^^^^^ # # foo.bar # ^^^^^^^ # # foo&.bar # ^^^^^^^^ class CallNode < Node # attr_reader flags: Integer private attr_reader :flags # attr_reader receiver: Node? attr_reader :receiver # attr_reader call_operator_loc: Location? attr_reader :call_operator_loc # attr_reader name: Symbol attr_reader :name # attr_reader message_loc: Location? attr_reader :message_loc # attr_reader opening_loc: Location? attr_reader :opening_loc # attr_reader arguments: ArgumentsNode? attr_reader :arguments # attr_reader closing_loc: Location? attr_reader :closing_loc # attr_reader block: Node? attr_reader :block # def initialize: (flags: Integer, receiver: Node?, call_operator_loc: Location?, name: Symbol, message_loc: Location?, opening_loc: Location?, arguments: ArgumentsNode?, closing_loc: Location?, block: Node?, location: Location) -> void def initialize(flags, receiver, call_operator_loc, name, message_loc, opening_loc, arguments, closing_loc, block, location) @flags = flags @receiver = receiver @call_operator_loc = call_operator_loc @name = name @message_loc = message_loc @opening_loc = opening_loc @arguments = arguments @closing_loc = closing_loc @block = block @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_call_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [receiver, arguments, block] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact << receiver if receiver compact << arguments if arguments compact << block if block compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [*receiver, *call_operator_loc, *message_loc, *opening_loc, *arguments, *closing_loc, *block] end # def copy: (**params) -> CallNode def copy(**params) CallNode.new( params.fetch(:flags) { flags }, params.fetch(:receiver) { receiver }, params.fetch(:call_operator_loc) { call_operator_loc }, params.fetch(:name) { name }, params.fetch(:message_loc) { message_loc }, params.fetch(:opening_loc) { opening_loc }, params.fetch(:arguments) { arguments }, params.fetch(:closing_loc) { closing_loc }, params.fetch(:block) { block }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { flags: flags, receiver: receiver, call_operator_loc: call_operator_loc, name: name, message_loc: message_loc, opening_loc: opening_loc, arguments: arguments, closing_loc: closing_loc, block: block, location: location } end # def safe_navigation?: () -> bool def safe_navigation? flags.anybits?(CallNodeFlags::SAFE_NAVIGATION) end # def variable_call?: () -> bool def variable_call? flags.anybits?(CallNodeFlags::VARIABLE_CALL) end # def attribute_write?: () -> bool def attribute_write? flags.anybits?(CallNodeFlags::ATTRIBUTE_WRITE) end # def call_operator: () -> String? def call_operator call_operator_loc&.slice end # def message: () -> String? def message message_loc&.slice end # def opening: () -> String? def opening opening_loc&.slice end # def closing: () -> String? def closing closing_loc&.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) flags = [("safe_navigation" if safe_navigation?), ("variable_call" if variable_call?), ("attribute_write" if attribute_write?)].compact inspector << "├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n" if (receiver = self.receiver).nil? inspector << "├── receiver: ∅\n" else inspector << "├── receiver:\n" inspector << receiver.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "├── call_operator_loc: #{inspector.location(call_operator_loc)}\n" inspector << "├── name: #{name.inspect}\n" inspector << "├── message_loc: #{inspector.location(message_loc)}\n" inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n" if (arguments = self.arguments).nil? inspector << "├── arguments: ∅\n" else inspector << "├── arguments:\n" inspector << arguments.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "├── closing_loc: #{inspector.location(closing_loc)}\n" if (block = self.block).nil? inspector << "└── block: ∅\n" else inspector << "└── block:\n" inspector << block.inspect(inspector.child_inspector(" ")).delete_prefix(inspector.prefix) end inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :call_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :call_node end end # Represents the use of an assignment operator on a call. # # foo.bar += baz # ^^^^^^^^^^^^^^ class CallOperatorWriteNode < Node # attr_reader flags: Integer private attr_reader :flags # attr_reader receiver: Node? attr_reader :receiver # attr_reader call_operator_loc: Location? attr_reader :call_operator_loc # attr_reader message_loc: Location? attr_reader :message_loc # attr_reader read_name: Symbol attr_reader :read_name # attr_reader write_name: Symbol attr_reader :write_name # attr_reader operator: Symbol attr_reader :operator # attr_reader operator_loc: Location attr_reader :operator_loc # attr_reader value: Node attr_reader :value # def initialize: (flags: Integer, receiver: Node?, call_operator_loc: Location?, message_loc: Location?, read_name: Symbol, write_name: Symbol, operator: Symbol, operator_loc: Location, value: Node, location: Location) -> void def initialize(flags, receiver, call_operator_loc, message_loc, read_name, write_name, operator, operator_loc, value, location) @flags = flags @receiver = receiver @call_operator_loc = call_operator_loc @message_loc = message_loc @read_name = read_name @write_name = write_name @operator = operator @operator_loc = operator_loc @value = value @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_call_operator_write_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [receiver, value] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact << receiver if receiver compact << value compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [*receiver, *call_operator_loc, *message_loc, operator_loc, value] end # def copy: (**params) -> CallOperatorWriteNode def copy(**params) CallOperatorWriteNode.new( params.fetch(:flags) { flags }, params.fetch(:receiver) { receiver }, params.fetch(:call_operator_loc) { call_operator_loc }, params.fetch(:message_loc) { message_loc }, params.fetch(:read_name) { read_name }, params.fetch(:write_name) { write_name }, params.fetch(:operator) { operator }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:value) { value }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { flags: flags, receiver: receiver, call_operator_loc: call_operator_loc, message_loc: message_loc, read_name: read_name, write_name: write_name, operator: operator, operator_loc: operator_loc, value: value, location: location } end # def safe_navigation?: () -> bool def safe_navigation? flags.anybits?(CallNodeFlags::SAFE_NAVIGATION) end # def variable_call?: () -> bool def variable_call? flags.anybits?(CallNodeFlags::VARIABLE_CALL) end # def attribute_write?: () -> bool def attribute_write? flags.anybits?(CallNodeFlags::ATTRIBUTE_WRITE) end # def call_operator: () -> String? def call_operator call_operator_loc&.slice end # def message: () -> String? def message message_loc&.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) flags = [("safe_navigation" if safe_navigation?), ("variable_call" if variable_call?), ("attribute_write" if attribute_write?)].compact inspector << "├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n" if (receiver = self.receiver).nil? inspector << "├── receiver: ∅\n" else inspector << "├── receiver:\n" inspector << receiver.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "├── call_operator_loc: #{inspector.location(call_operator_loc)}\n" inspector << "├── message_loc: #{inspector.location(message_loc)}\n" inspector << "├── read_name: #{read_name.inspect}\n" inspector << "├── write_name: #{write_name.inspect}\n" inspector << "├── operator: #{operator.inspect}\n" inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n" inspector << "└── value:\n" inspector << inspector.child_node(value, " ") inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :call_operator_write_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :call_operator_write_node end end # Represents the use of the `||=` operator on a call. # # foo.bar ||= value # ^^^^^^^^^^^^^^^^^ class CallOrWriteNode < Node # attr_reader flags: Integer private attr_reader :flags # attr_reader receiver: Node? attr_reader :receiver # attr_reader call_operator_loc: Location? attr_reader :call_operator_loc # attr_reader message_loc: Location? attr_reader :message_loc # attr_reader read_name: Symbol attr_reader :read_name # attr_reader write_name: Symbol attr_reader :write_name # attr_reader operator_loc: Location attr_reader :operator_loc # attr_reader value: Node attr_reader :value # def initialize: (flags: Integer, receiver: Node?, call_operator_loc: Location?, message_loc: Location?, read_name: Symbol, write_name: Symbol, operator_loc: Location, value: Node, location: Location) -> void def initialize(flags, receiver, call_operator_loc, message_loc, read_name, write_name, operator_loc, value, location) @flags = flags @receiver = receiver @call_operator_loc = call_operator_loc @message_loc = message_loc @read_name = read_name @write_name = write_name @operator_loc = operator_loc @value = value @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_call_or_write_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [receiver, value] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact << receiver if receiver compact << value compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [*receiver, *call_operator_loc, *message_loc, operator_loc, value] end # def copy: (**params) -> CallOrWriteNode def copy(**params) CallOrWriteNode.new( params.fetch(:flags) { flags }, params.fetch(:receiver) { receiver }, params.fetch(:call_operator_loc) { call_operator_loc }, params.fetch(:message_loc) { message_loc }, params.fetch(:read_name) { read_name }, params.fetch(:write_name) { write_name }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:value) { value }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { flags: flags, receiver: receiver, call_operator_loc: call_operator_loc, message_loc: message_loc, read_name: read_name, write_name: write_name, operator_loc: operator_loc, value: value, location: location } end # def safe_navigation?: () -> bool def safe_navigation? flags.anybits?(CallNodeFlags::SAFE_NAVIGATION) end # def variable_call?: () -> bool def variable_call? flags.anybits?(CallNodeFlags::VARIABLE_CALL) end # def attribute_write?: () -> bool def attribute_write? flags.anybits?(CallNodeFlags::ATTRIBUTE_WRITE) end # def call_operator: () -> String? def call_operator call_operator_loc&.slice end # def message: () -> String? def message message_loc&.slice end # def operator: () -> String def operator operator_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) flags = [("safe_navigation" if safe_navigation?), ("variable_call" if variable_call?), ("attribute_write" if attribute_write?)].compact inspector << "├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n" if (receiver = self.receiver).nil? inspector << "├── receiver: ∅\n" else inspector << "├── receiver:\n" inspector << receiver.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "├── call_operator_loc: #{inspector.location(call_operator_loc)}\n" inspector << "├── message_loc: #{inspector.location(message_loc)}\n" inspector << "├── read_name: #{read_name.inspect}\n" inspector << "├── write_name: #{write_name.inspect}\n" inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n" inspector << "└── value:\n" inspector << inspector.child_node(value, " ") inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :call_or_write_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :call_or_write_node end end # Represents assigning to a method call. # # foo.bar, = 1 # ^^^^^^^ # # begin # rescue => foo.bar # ^^^^^^^ # end # # for foo.bar in baz do end # ^^^^^^^ class CallTargetNode < Node # attr_reader flags: Integer private attr_reader :flags # attr_reader receiver: Node attr_reader :receiver # attr_reader call_operator_loc: Location attr_reader :call_operator_loc # attr_reader name: Symbol attr_reader :name # attr_reader message_loc: Location attr_reader :message_loc # def initialize: (flags: Integer, receiver: Node, call_operator_loc: Location, name: Symbol, message_loc: Location, location: Location) -> void def initialize(flags, receiver, call_operator_loc, name, message_loc, location) @flags = flags @receiver = receiver @call_operator_loc = call_operator_loc @name = name @message_loc = message_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_call_target_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [receiver] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [receiver] end # def comment_targets: () -> Array[Node | Location] def comment_targets [receiver, call_operator_loc, message_loc] end # def copy: (**params) -> CallTargetNode def copy(**params) CallTargetNode.new( params.fetch(:flags) { flags }, params.fetch(:receiver) { receiver }, params.fetch(:call_operator_loc) { call_operator_loc }, params.fetch(:name) { name }, params.fetch(:message_loc) { message_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { flags: flags, receiver: receiver, call_operator_loc: call_operator_loc, name: name, message_loc: message_loc, location: location } end # def safe_navigation?: () -> bool def safe_navigation? flags.anybits?(CallNodeFlags::SAFE_NAVIGATION) end # def variable_call?: () -> bool def variable_call? flags.anybits?(CallNodeFlags::VARIABLE_CALL) end # def attribute_write?: () -> bool def attribute_write? flags.anybits?(CallNodeFlags::ATTRIBUTE_WRITE) end # def call_operator: () -> String def call_operator call_operator_loc.slice end # def message: () -> String def message message_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) flags = [("safe_navigation" if safe_navigation?), ("variable_call" if variable_call?), ("attribute_write" if attribute_write?)].compact inspector << "├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n" inspector << "├── receiver:\n" inspector << inspector.child_node(receiver, "│ ") inspector << "├── call_operator_loc: #{inspector.location(call_operator_loc)}\n" inspector << "├── name: #{name.inspect}\n" inspector << "└── message_loc: #{inspector.location(message_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :call_target_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :call_target_node end end # Represents assigning to a local variable in pattern matching. # # foo => [bar => baz] # ^^^^^^^^^^^^ class CapturePatternNode < Node # attr_reader value: Node attr_reader :value # attr_reader target: Node attr_reader :target # attr_reader operator_loc: Location attr_reader :operator_loc # def initialize: (value: Node, target: Node, operator_loc: Location, location: Location) -> void def initialize(value, target, operator_loc, location) @value = value @target = target @operator_loc = operator_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_capture_pattern_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [value, target] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [value, target] end # def comment_targets: () -> Array[Node | Location] def comment_targets [value, target, operator_loc] end # def copy: (**params) -> CapturePatternNode def copy(**params) CapturePatternNode.new( params.fetch(:value) { value }, params.fetch(:target) { target }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { value: value, target: target, operator_loc: operator_loc, location: location } end # def operator: () -> String def operator operator_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── value:\n" inspector << inspector.child_node(value, "│ ") inspector << "├── target:\n" inspector << inspector.child_node(target, "│ ") inspector << "└── operator_loc: #{inspector.location(operator_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :capture_pattern_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :capture_pattern_node end end # Represents the use of a case statement for pattern matching. # # case true # in false # end # ^^^^^^^^^ class CaseMatchNode < Node # attr_reader predicate: Node? attr_reader :predicate # attr_reader conditions: Array[Node] attr_reader :conditions # attr_reader consequent: ElseNode? attr_reader :consequent # attr_reader case_keyword_loc: Location attr_reader :case_keyword_loc # attr_reader end_keyword_loc: Location attr_reader :end_keyword_loc # def initialize: (predicate: Node?, conditions: Array[Node], consequent: ElseNode?, case_keyword_loc: Location, end_keyword_loc: Location, location: Location) -> void def initialize(predicate, conditions, consequent, case_keyword_loc, end_keyword_loc, location) @predicate = predicate @conditions = conditions @consequent = consequent @case_keyword_loc = case_keyword_loc @end_keyword_loc = end_keyword_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_case_match_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [predicate, *conditions, consequent] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact << predicate if predicate compact.concat(conditions) compact << consequent if consequent compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [*predicate, *conditions, *consequent, case_keyword_loc, end_keyword_loc] end # def copy: (**params) -> CaseMatchNode def copy(**params) CaseMatchNode.new( params.fetch(:predicate) { predicate }, params.fetch(:conditions) { conditions }, params.fetch(:consequent) { consequent }, params.fetch(:case_keyword_loc) { case_keyword_loc }, params.fetch(:end_keyword_loc) { end_keyword_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { predicate: predicate, conditions: conditions, consequent: consequent, case_keyword_loc: case_keyword_loc, end_keyword_loc: end_keyword_loc, location: location } end # def case_keyword: () -> String def case_keyword case_keyword_loc.slice end # def end_keyword: () -> String def end_keyword end_keyword_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) if (predicate = self.predicate).nil? inspector << "├── predicate: ∅\n" else inspector << "├── predicate:\n" inspector << predicate.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "├── conditions: #{inspector.list("#{inspector.prefix}│ ", conditions)}" if (consequent = self.consequent).nil? inspector << "├── consequent: ∅\n" else inspector << "├── consequent:\n" inspector << consequent.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "├── case_keyword_loc: #{inspector.location(case_keyword_loc)}\n" inspector << "└── end_keyword_loc: #{inspector.location(end_keyword_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :case_match_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :case_match_node end end # Represents the use of a case statement. # # case true # when false # end # ^^^^^^^^^^ class CaseNode < Node # attr_reader predicate: Node? attr_reader :predicate # attr_reader conditions: Array[Node] attr_reader :conditions # attr_reader consequent: ElseNode? attr_reader :consequent # attr_reader case_keyword_loc: Location attr_reader :case_keyword_loc # attr_reader end_keyword_loc: Location attr_reader :end_keyword_loc # def initialize: (predicate: Node?, conditions: Array[Node], consequent: ElseNode?, case_keyword_loc: Location, end_keyword_loc: Location, location: Location) -> void def initialize(predicate, conditions, consequent, case_keyword_loc, end_keyword_loc, location) @predicate = predicate @conditions = conditions @consequent = consequent @case_keyword_loc = case_keyword_loc @end_keyword_loc = end_keyword_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_case_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [predicate, *conditions, consequent] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact << predicate if predicate compact.concat(conditions) compact << consequent if consequent compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [*predicate, *conditions, *consequent, case_keyword_loc, end_keyword_loc] end # def copy: (**params) -> CaseNode def copy(**params) CaseNode.new( params.fetch(:predicate) { predicate }, params.fetch(:conditions) { conditions }, params.fetch(:consequent) { consequent }, params.fetch(:case_keyword_loc) { case_keyword_loc }, params.fetch(:end_keyword_loc) { end_keyword_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { predicate: predicate, conditions: conditions, consequent: consequent, case_keyword_loc: case_keyword_loc, end_keyword_loc: end_keyword_loc, location: location } end # def case_keyword: () -> String def case_keyword case_keyword_loc.slice end # def end_keyword: () -> String def end_keyword end_keyword_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) if (predicate = self.predicate).nil? inspector << "├── predicate: ∅\n" else inspector << "├── predicate:\n" inspector << predicate.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "├── conditions: #{inspector.list("#{inspector.prefix}│ ", conditions)}" if (consequent = self.consequent).nil? inspector << "├── consequent: ∅\n" else inspector << "├── consequent:\n" inspector << consequent.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "├── case_keyword_loc: #{inspector.location(case_keyword_loc)}\n" inspector << "└── end_keyword_loc: #{inspector.location(end_keyword_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :case_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :case_node end end # Represents a class declaration involving the `class` keyword. # # class Foo end # ^^^^^^^^^^^^^ class ClassNode < Node # attr_reader locals: Array[Symbol] attr_reader :locals # attr_reader class_keyword_loc: Location attr_reader :class_keyword_loc # attr_reader constant_path: Node attr_reader :constant_path # attr_reader inheritance_operator_loc: Location? attr_reader :inheritance_operator_loc # attr_reader superclass: Node? attr_reader :superclass # attr_reader body: Node? attr_reader :body # attr_reader end_keyword_loc: Location attr_reader :end_keyword_loc # attr_reader name: Symbol attr_reader :name # def initialize: (locals: Array[Symbol], class_keyword_loc: Location, constant_path: Node, inheritance_operator_loc: Location?, superclass: Node?, body: Node?, end_keyword_loc: Location, name: Symbol, location: Location) -> void def initialize(locals, class_keyword_loc, constant_path, inheritance_operator_loc, superclass, body, end_keyword_loc, name, location) @locals = locals @class_keyword_loc = class_keyword_loc @constant_path = constant_path @inheritance_operator_loc = inheritance_operator_loc @superclass = superclass @body = body @end_keyword_loc = end_keyword_loc @name = name @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_class_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [constant_path, superclass, body] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact << constant_path compact << superclass if superclass compact << body if body compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [class_keyword_loc, constant_path, *inheritance_operator_loc, *superclass, *body, end_keyword_loc] end # def copy: (**params) -> ClassNode def copy(**params) ClassNode.new( params.fetch(:locals) { locals }, params.fetch(:class_keyword_loc) { class_keyword_loc }, params.fetch(:constant_path) { constant_path }, params.fetch(:inheritance_operator_loc) { inheritance_operator_loc }, params.fetch(:superclass) { superclass }, params.fetch(:body) { body }, params.fetch(:end_keyword_loc) { end_keyword_loc }, params.fetch(:name) { name }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { locals: locals, class_keyword_loc: class_keyword_loc, constant_path: constant_path, inheritance_operator_loc: inheritance_operator_loc, superclass: superclass, body: body, end_keyword_loc: end_keyword_loc, name: name, location: location } end # def class_keyword: () -> String def class_keyword class_keyword_loc.slice end # def inheritance_operator: () -> String? def inheritance_operator inheritance_operator_loc&.slice end # def end_keyword: () -> String def end_keyword end_keyword_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── locals: #{locals.inspect}\n" inspector << "├── class_keyword_loc: #{inspector.location(class_keyword_loc)}\n" inspector << "├── constant_path:\n" inspector << inspector.child_node(constant_path, "│ ") inspector << "├── inheritance_operator_loc: #{inspector.location(inheritance_operator_loc)}\n" if (superclass = self.superclass).nil? inspector << "├── superclass: ∅\n" else inspector << "├── superclass:\n" inspector << superclass.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end if (body = self.body).nil? inspector << "├── body: ∅\n" else inspector << "├── body:\n" inspector << body.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "├── end_keyword_loc: #{inspector.location(end_keyword_loc)}\n" inspector << "└── name: #{name.inspect}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :class_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :class_node end end # Represents the use of the `&&=` operator for assignment to a class variable. # # @@target &&= value # ^^^^^^^^^^^^^^^^^^ class ClassVariableAndWriteNode < Node # attr_reader name: Symbol attr_reader :name # attr_reader name_loc: Location attr_reader :name_loc # attr_reader operator_loc: Location attr_reader :operator_loc # attr_reader value: Node attr_reader :value # def initialize: (name: Symbol, name_loc: Location, operator_loc: Location, value: Node, location: Location) -> void def initialize(name, name_loc, operator_loc, value, location) @name = name @name_loc = name_loc @operator_loc = operator_loc @value = value @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_class_variable_and_write_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [value] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [value] end # def comment_targets: () -> Array[Node | Location] def comment_targets [name_loc, operator_loc, value] end # def copy: (**params) -> ClassVariableAndWriteNode def copy(**params) ClassVariableAndWriteNode.new( params.fetch(:name) { name }, params.fetch(:name_loc) { name_loc }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:value) { value }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { name: name, name_loc: name_loc, operator_loc: operator_loc, value: value, location: location } end # def operator: () -> String def operator operator_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── name: #{name.inspect}\n" inspector << "├── name_loc: #{inspector.location(name_loc)}\n" inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n" inspector << "└── value:\n" inspector << inspector.child_node(value, " ") inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :class_variable_and_write_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :class_variable_and_write_node end end # Represents assigning to a class variable using an operator that isn't `=`. # # @@target += value # ^^^^^^^^^^^^^^^^^ class ClassVariableOperatorWriteNode < Node # attr_reader name: Symbol attr_reader :name # attr_reader name_loc: Location attr_reader :name_loc # attr_reader operator_loc: Location attr_reader :operator_loc # attr_reader value: Node attr_reader :value # attr_reader operator: Symbol attr_reader :operator # def initialize: (name: Symbol, name_loc: Location, operator_loc: Location, value: Node, operator: Symbol, location: Location) -> void def initialize(name, name_loc, operator_loc, value, operator, location) @name = name @name_loc = name_loc @operator_loc = operator_loc @value = value @operator = operator @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_class_variable_operator_write_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [value] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [value] end # def comment_targets: () -> Array[Node | Location] def comment_targets [name_loc, operator_loc, value] end # def copy: (**params) -> ClassVariableOperatorWriteNode def copy(**params) ClassVariableOperatorWriteNode.new( params.fetch(:name) { name }, params.fetch(:name_loc) { name_loc }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:value) { value }, params.fetch(:operator) { operator }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { name: name, name_loc: name_loc, operator_loc: operator_loc, value: value, operator: operator, location: location } end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── name: #{name.inspect}\n" inspector << "├── name_loc: #{inspector.location(name_loc)}\n" inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n" inspector << "├── value:\n" inspector << inspector.child_node(value, "│ ") inspector << "└── operator: #{operator.inspect}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :class_variable_operator_write_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :class_variable_operator_write_node end end # Represents the use of the `||=` operator for assignment to a class variable. # # @@target ||= value # ^^^^^^^^^^^^^^^^^^ class ClassVariableOrWriteNode < Node # attr_reader name: Symbol attr_reader :name # attr_reader name_loc: Location attr_reader :name_loc # attr_reader operator_loc: Location attr_reader :operator_loc # attr_reader value: Node attr_reader :value # def initialize: (name: Symbol, name_loc: Location, operator_loc: Location, value: Node, location: Location) -> void def initialize(name, name_loc, operator_loc, value, location) @name = name @name_loc = name_loc @operator_loc = operator_loc @value = value @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_class_variable_or_write_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [value] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [value] end # def comment_targets: () -> Array[Node | Location] def comment_targets [name_loc, operator_loc, value] end # def copy: (**params) -> ClassVariableOrWriteNode def copy(**params) ClassVariableOrWriteNode.new( params.fetch(:name) { name }, params.fetch(:name_loc) { name_loc }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:value) { value }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { name: name, name_loc: name_loc, operator_loc: operator_loc, value: value, location: location } end # def operator: () -> String def operator operator_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── name: #{name.inspect}\n" inspector << "├── name_loc: #{inspector.location(name_loc)}\n" inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n" inspector << "└── value:\n" inspector << inspector.child_node(value, " ") inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :class_variable_or_write_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :class_variable_or_write_node end end # Represents referencing a class variable. # # @@foo # ^^^^^ class ClassVariableReadNode < Node # attr_reader name: Symbol attr_reader :name # def initialize: (name: Symbol, location: Location) -> void def initialize(name, location) @name = name @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_class_variable_read_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [] end # def comment_targets: () -> Array[Node | Location] def comment_targets [] end # def copy: (**params) -> ClassVariableReadNode def copy(**params) ClassVariableReadNode.new( params.fetch(:name) { name }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { name: name, location: location } end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "└── name: #{name.inspect}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :class_variable_read_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :class_variable_read_node end end # Represents writing to a class variable in a context that doesn't have an explicit value. # # @@foo, @@bar = baz # ^^^^^ ^^^^^ class ClassVariableTargetNode < Node # attr_reader name: Symbol attr_reader :name # def initialize: (name: Symbol, location: Location) -> void def initialize(name, location) @name = name @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_class_variable_target_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [] end # def comment_targets: () -> Array[Node | Location] def comment_targets [] end # def copy: (**params) -> ClassVariableTargetNode def copy(**params) ClassVariableTargetNode.new( params.fetch(:name) { name }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { name: name, location: location } end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "└── name: #{name.inspect}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :class_variable_target_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :class_variable_target_node end end # Represents writing to a class variable. # # @@foo = 1 # ^^^^^^^^^ class ClassVariableWriteNode < Node # attr_reader name: Symbol attr_reader :name # attr_reader name_loc: Location attr_reader :name_loc # attr_reader value: Node attr_reader :value # attr_reader operator_loc: Location? attr_reader :operator_loc # def initialize: (name: Symbol, name_loc: Location, value: Node, operator_loc: Location?, location: Location) -> void def initialize(name, name_loc, value, operator_loc, location) @name = name @name_loc = name_loc @value = value @operator_loc = operator_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_class_variable_write_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [value] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [value] end # def comment_targets: () -> Array[Node | Location] def comment_targets [name_loc, value, *operator_loc] end # def copy: (**params) -> ClassVariableWriteNode def copy(**params) ClassVariableWriteNode.new( params.fetch(:name) { name }, params.fetch(:name_loc) { name_loc }, params.fetch(:value) { value }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { name: name, name_loc: name_loc, value: value, operator_loc: operator_loc, location: location } end # def operator: () -> String? def operator operator_loc&.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── name: #{name.inspect}\n" inspector << "├── name_loc: #{inspector.location(name_loc)}\n" inspector << "├── value:\n" inspector << inspector.child_node(value, "│ ") inspector << "└── operator_loc: #{inspector.location(operator_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :class_variable_write_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :class_variable_write_node end end # Represents the use of the `&&=` operator for assignment to a constant. # # Target &&= value # ^^^^^^^^^^^^^^^^ class ConstantAndWriteNode < Node # attr_reader name: Symbol attr_reader :name # attr_reader name_loc: Location attr_reader :name_loc # attr_reader operator_loc: Location attr_reader :operator_loc # attr_reader value: Node attr_reader :value # def initialize: (name: Symbol, name_loc: Location, operator_loc: Location, value: Node, location: Location) -> void def initialize(name, name_loc, operator_loc, value, location) @name = name @name_loc = name_loc @operator_loc = operator_loc @value = value @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_constant_and_write_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [value] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [value] end # def comment_targets: () -> Array[Node | Location] def comment_targets [name_loc, operator_loc, value] end # def copy: (**params) -> ConstantAndWriteNode def copy(**params) ConstantAndWriteNode.new( params.fetch(:name) { name }, params.fetch(:name_loc) { name_loc }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:value) { value }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { name: name, name_loc: name_loc, operator_loc: operator_loc, value: value, location: location } end # def operator: () -> String def operator operator_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── name: #{name.inspect}\n" inspector << "├── name_loc: #{inspector.location(name_loc)}\n" inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n" inspector << "└── value:\n" inspector << inspector.child_node(value, " ") inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :constant_and_write_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :constant_and_write_node end end # Represents assigning to a constant using an operator that isn't `=`. # # Target += value # ^^^^^^^^^^^^^^^ class ConstantOperatorWriteNode < Node # attr_reader name: Symbol attr_reader :name # attr_reader name_loc: Location attr_reader :name_loc # attr_reader operator_loc: Location attr_reader :operator_loc # attr_reader value: Node attr_reader :value # attr_reader operator: Symbol attr_reader :operator # def initialize: (name: Symbol, name_loc: Location, operator_loc: Location, value: Node, operator: Symbol, location: Location) -> void def initialize(name, name_loc, operator_loc, value, operator, location) @name = name @name_loc = name_loc @operator_loc = operator_loc @value = value @operator = operator @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_constant_operator_write_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [value] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [value] end # def comment_targets: () -> Array[Node | Location] def comment_targets [name_loc, operator_loc, value] end # def copy: (**params) -> ConstantOperatorWriteNode def copy(**params) ConstantOperatorWriteNode.new( params.fetch(:name) { name }, params.fetch(:name_loc) { name_loc }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:value) { value }, params.fetch(:operator) { operator }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { name: name, name_loc: name_loc, operator_loc: operator_loc, value: value, operator: operator, location: location } end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── name: #{name.inspect}\n" inspector << "├── name_loc: #{inspector.location(name_loc)}\n" inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n" inspector << "├── value:\n" inspector << inspector.child_node(value, "│ ") inspector << "└── operator: #{operator.inspect}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :constant_operator_write_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :constant_operator_write_node end end # Represents the use of the `||=` operator for assignment to a constant. # # Target ||= value # ^^^^^^^^^^^^^^^^ class ConstantOrWriteNode < Node # attr_reader name: Symbol attr_reader :name # attr_reader name_loc: Location attr_reader :name_loc # attr_reader operator_loc: Location attr_reader :operator_loc # attr_reader value: Node attr_reader :value # def initialize: (name: Symbol, name_loc: Location, operator_loc: Location, value: Node, location: Location) -> void def initialize(name, name_loc, operator_loc, value, location) @name = name @name_loc = name_loc @operator_loc = operator_loc @value = value @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_constant_or_write_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [value] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [value] end # def comment_targets: () -> Array[Node | Location] def comment_targets [name_loc, operator_loc, value] end # def copy: (**params) -> ConstantOrWriteNode def copy(**params) ConstantOrWriteNode.new( params.fetch(:name) { name }, params.fetch(:name_loc) { name_loc }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:value) { value }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { name: name, name_loc: name_loc, operator_loc: operator_loc, value: value, location: location } end # def operator: () -> String def operator operator_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── name: #{name.inspect}\n" inspector << "├── name_loc: #{inspector.location(name_loc)}\n" inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n" inspector << "└── value:\n" inspector << inspector.child_node(value, " ") inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :constant_or_write_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :constant_or_write_node end end # Represents the use of the `&&=` operator for assignment to a constant path. # # Parent::Child &&= value # ^^^^^^^^^^^^^^^^^^^^^^^ class ConstantPathAndWriteNode < Node # attr_reader target: ConstantPathNode attr_reader :target # attr_reader operator_loc: Location attr_reader :operator_loc # attr_reader value: Node attr_reader :value # def initialize: (target: ConstantPathNode, operator_loc: Location, value: Node, location: Location) -> void def initialize(target, operator_loc, value, location) @target = target @operator_loc = operator_loc @value = value @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_constant_path_and_write_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [target, value] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [target, value] end # def comment_targets: () -> Array[Node | Location] def comment_targets [target, operator_loc, value] end # def copy: (**params) -> ConstantPathAndWriteNode def copy(**params) ConstantPathAndWriteNode.new( params.fetch(:target) { target }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:value) { value }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { target: target, operator_loc: operator_loc, value: value, location: location } end # def operator: () -> String def operator operator_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── target:\n" inspector << inspector.child_node(target, "│ ") inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n" inspector << "└── value:\n" inspector << inspector.child_node(value, " ") inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :constant_path_and_write_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :constant_path_and_write_node end end # Represents accessing a constant through a path of `::` operators. # # Foo::Bar # ^^^^^^^^ class ConstantPathNode < Node # attr_reader parent: Node? attr_reader :parent # attr_reader child: Node attr_reader :child # attr_reader delimiter_loc: Location attr_reader :delimiter_loc # def initialize: (parent: Node?, child: Node, delimiter_loc: Location, location: Location) -> void def initialize(parent, child, delimiter_loc, location) @parent = parent @child = child @delimiter_loc = delimiter_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_constant_path_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [parent, child] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact << parent if parent compact << child compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [*parent, child, delimiter_loc] end # def copy: (**params) -> ConstantPathNode def copy(**params) ConstantPathNode.new( params.fetch(:parent) { parent }, params.fetch(:child) { child }, params.fetch(:delimiter_loc) { delimiter_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { parent: parent, child: child, delimiter_loc: delimiter_loc, location: location } end # def delimiter: () -> String def delimiter delimiter_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) if (parent = self.parent).nil? inspector << "├── parent: ∅\n" else inspector << "├── parent:\n" inspector << parent.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "├── child:\n" inspector << inspector.child_node(child, "│ ") inspector << "└── delimiter_loc: #{inspector.location(delimiter_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :constant_path_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :constant_path_node end end # Represents assigning to a constant path using an operator that isn't `=`. # # Parent::Child += value # ^^^^^^^^^^^^^^^^^^^^^^ class ConstantPathOperatorWriteNode < Node # attr_reader target: ConstantPathNode attr_reader :target # attr_reader operator_loc: Location attr_reader :operator_loc # attr_reader value: Node attr_reader :value # attr_reader operator: Symbol attr_reader :operator # def initialize: (target: ConstantPathNode, operator_loc: Location, value: Node, operator: Symbol, location: Location) -> void def initialize(target, operator_loc, value, operator, location) @target = target @operator_loc = operator_loc @value = value @operator = operator @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_constant_path_operator_write_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [target, value] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [target, value] end # def comment_targets: () -> Array[Node | Location] def comment_targets [target, operator_loc, value] end # def copy: (**params) -> ConstantPathOperatorWriteNode def copy(**params) ConstantPathOperatorWriteNode.new( params.fetch(:target) { target }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:value) { value }, params.fetch(:operator) { operator }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { target: target, operator_loc: operator_loc, value: value, operator: operator, location: location } end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── target:\n" inspector << inspector.child_node(target, "│ ") inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n" inspector << "├── value:\n" inspector << inspector.child_node(value, "│ ") inspector << "└── operator: #{operator.inspect}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :constant_path_operator_write_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :constant_path_operator_write_node end end # Represents the use of the `||=` operator for assignment to a constant path. # # Parent::Child ||= value # ^^^^^^^^^^^^^^^^^^^^^^^ class ConstantPathOrWriteNode < Node # attr_reader target: ConstantPathNode attr_reader :target # attr_reader operator_loc: Location attr_reader :operator_loc # attr_reader value: Node attr_reader :value # def initialize: (target: ConstantPathNode, operator_loc: Location, value: Node, location: Location) -> void def initialize(target, operator_loc, value, location) @target = target @operator_loc = operator_loc @value = value @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_constant_path_or_write_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [target, value] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [target, value] end # def comment_targets: () -> Array[Node | Location] def comment_targets [target, operator_loc, value] end # def copy: (**params) -> ConstantPathOrWriteNode def copy(**params) ConstantPathOrWriteNode.new( params.fetch(:target) { target }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:value) { value }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { target: target, operator_loc: operator_loc, value: value, location: location } end # def operator: () -> String def operator operator_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── target:\n" inspector << inspector.child_node(target, "│ ") inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n" inspector << "└── value:\n" inspector << inspector.child_node(value, " ") inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :constant_path_or_write_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :constant_path_or_write_node end end # Represents writing to a constant path in a context that doesn't have an explicit value. # # Foo::Foo, Bar::Bar = baz # ^^^^^^^^ ^^^^^^^^ class ConstantPathTargetNode < Node # attr_reader parent: Node? attr_reader :parent # attr_reader child: Node attr_reader :child # attr_reader delimiter_loc: Location attr_reader :delimiter_loc # def initialize: (parent: Node?, child: Node, delimiter_loc: Location, location: Location) -> void def initialize(parent, child, delimiter_loc, location) @parent = parent @child = child @delimiter_loc = delimiter_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_constant_path_target_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [parent, child] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact << parent if parent compact << child compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [*parent, child, delimiter_loc] end # def copy: (**params) -> ConstantPathTargetNode def copy(**params) ConstantPathTargetNode.new( params.fetch(:parent) { parent }, params.fetch(:child) { child }, params.fetch(:delimiter_loc) { delimiter_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { parent: parent, child: child, delimiter_loc: delimiter_loc, location: location } end # def delimiter: () -> String def delimiter delimiter_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) if (parent = self.parent).nil? inspector << "├── parent: ∅\n" else inspector << "├── parent:\n" inspector << parent.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "├── child:\n" inspector << inspector.child_node(child, "│ ") inspector << "└── delimiter_loc: #{inspector.location(delimiter_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :constant_path_target_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :constant_path_target_node end end # Represents writing to a constant path. # # ::Foo = 1 # ^^^^^^^^^ # # Foo::Bar = 1 # ^^^^^^^^^^^^ # # ::Foo::Bar = 1 # ^^^^^^^^^^^^^^ class ConstantPathWriteNode < Node # attr_reader target: ConstantPathNode attr_reader :target # attr_reader operator_loc: Location attr_reader :operator_loc # attr_reader value: Node attr_reader :value # def initialize: (target: ConstantPathNode, operator_loc: Location, value: Node, location: Location) -> void def initialize(target, operator_loc, value, location) @target = target @operator_loc = operator_loc @value = value @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_constant_path_write_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [target, value] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [target, value] end # def comment_targets: () -> Array[Node | Location] def comment_targets [target, operator_loc, value] end # def copy: (**params) -> ConstantPathWriteNode def copy(**params) ConstantPathWriteNode.new( params.fetch(:target) { target }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:value) { value }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { target: target, operator_loc: operator_loc, value: value, location: location } end # def operator: () -> String def operator operator_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── target:\n" inspector << inspector.child_node(target, "│ ") inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n" inspector << "└── value:\n" inspector << inspector.child_node(value, " ") inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :constant_path_write_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :constant_path_write_node end end # Represents referencing a constant. # # Foo # ^^^ class ConstantReadNode < Node # attr_reader name: Symbol attr_reader :name # def initialize: (name: Symbol, location: Location) -> void def initialize(name, location) @name = name @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_constant_read_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [] end # def comment_targets: () -> Array[Node | Location] def comment_targets [] end # def copy: (**params) -> ConstantReadNode def copy(**params) ConstantReadNode.new( params.fetch(:name) { name }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { name: name, location: location } end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "└── name: #{name.inspect}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :constant_read_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :constant_read_node end end # Represents writing to a constant in a context that doesn't have an explicit value. # # Foo, Bar = baz # ^^^ ^^^ class ConstantTargetNode < Node # attr_reader name: Symbol attr_reader :name # def initialize: (name: Symbol, location: Location) -> void def initialize(name, location) @name = name @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_constant_target_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [] end # def comment_targets: () -> Array[Node | Location] def comment_targets [] end # def copy: (**params) -> ConstantTargetNode def copy(**params) ConstantTargetNode.new( params.fetch(:name) { name }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { name: name, location: location } end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "└── name: #{name.inspect}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :constant_target_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :constant_target_node end end # Represents writing to a constant. # # Foo = 1 # ^^^^^^^ class ConstantWriteNode < Node # attr_reader name: Symbol attr_reader :name # attr_reader name_loc: Location attr_reader :name_loc # attr_reader value: Node attr_reader :value # attr_reader operator_loc: Location attr_reader :operator_loc # def initialize: (name: Symbol, name_loc: Location, value: Node, operator_loc: Location, location: Location) -> void def initialize(name, name_loc, value, operator_loc, location) @name = name @name_loc = name_loc @value = value @operator_loc = operator_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_constant_write_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [value] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [value] end # def comment_targets: () -> Array[Node | Location] def comment_targets [name_loc, value, operator_loc] end # def copy: (**params) -> ConstantWriteNode def copy(**params) ConstantWriteNode.new( params.fetch(:name) { name }, params.fetch(:name_loc) { name_loc }, params.fetch(:value) { value }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { name: name, name_loc: name_loc, value: value, operator_loc: operator_loc, location: location } end # def operator: () -> String def operator operator_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── name: #{name.inspect}\n" inspector << "├── name_loc: #{inspector.location(name_loc)}\n" inspector << "├── value:\n" inspector << inspector.child_node(value, "│ ") inspector << "└── operator_loc: #{inspector.location(operator_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :constant_write_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :constant_write_node end end # Represents a method definition. # # def method # end # ^^^^^^^^^^ class DefNode < Node # attr_reader name: Symbol attr_reader :name # attr_reader name_loc: Location attr_reader :name_loc # attr_reader receiver: Node? attr_reader :receiver # attr_reader parameters: ParametersNode? attr_reader :parameters # attr_reader body: Node? attr_reader :body # attr_reader locals: Array[Symbol] attr_reader :locals # attr_reader locals_body_index: Integer attr_reader :locals_body_index # attr_reader def_keyword_loc: Location attr_reader :def_keyword_loc # attr_reader operator_loc: Location? attr_reader :operator_loc # attr_reader lparen_loc: Location? attr_reader :lparen_loc # attr_reader rparen_loc: Location? attr_reader :rparen_loc # attr_reader equal_loc: Location? attr_reader :equal_loc # attr_reader end_keyword_loc: Location? attr_reader :end_keyword_loc # def initialize: (name: Symbol, name_loc: Location, receiver: Node?, parameters: ParametersNode?, body: Node?, locals: Array[Symbol], locals_body_index: Integer, def_keyword_loc: Location, operator_loc: Location?, lparen_loc: Location?, rparen_loc: Location?, equal_loc: Location?, end_keyword_loc: Location?, location: Location) -> void def initialize(name, name_loc, receiver, parameters, body, locals, locals_body_index, def_keyword_loc, operator_loc, lparen_loc, rparen_loc, equal_loc, end_keyword_loc, location) @name = name @name_loc = name_loc @receiver = receiver @parameters = parameters @body = body @locals = locals @locals_body_index = locals_body_index @def_keyword_loc = def_keyword_loc @operator_loc = operator_loc @lparen_loc = lparen_loc @rparen_loc = rparen_loc @equal_loc = equal_loc @end_keyword_loc = end_keyword_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_def_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [receiver, parameters, body] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact << receiver if receiver compact << parameters if parameters compact << body if body compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [name_loc, *receiver, *parameters, *body, def_keyword_loc, *operator_loc, *lparen_loc, *rparen_loc, *equal_loc, *end_keyword_loc] end # def copy: (**params) -> DefNode def copy(**params) DefNode.new( params.fetch(:name) { name }, params.fetch(:name_loc) { name_loc }, params.fetch(:receiver) { receiver }, params.fetch(:parameters) { parameters }, params.fetch(:body) { body }, params.fetch(:locals) { locals }, params.fetch(:locals_body_index) { locals_body_index }, params.fetch(:def_keyword_loc) { def_keyword_loc }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:lparen_loc) { lparen_loc }, params.fetch(:rparen_loc) { rparen_loc }, params.fetch(:equal_loc) { equal_loc }, params.fetch(:end_keyword_loc) { end_keyword_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { name: name, name_loc: name_loc, receiver: receiver, parameters: parameters, body: body, locals: locals, locals_body_index: locals_body_index, def_keyword_loc: def_keyword_loc, operator_loc: operator_loc, lparen_loc: lparen_loc, rparen_loc: rparen_loc, equal_loc: equal_loc, end_keyword_loc: end_keyword_loc, location: location } end # def def_keyword: () -> String def def_keyword def_keyword_loc.slice end # def operator: () -> String? def operator operator_loc&.slice end # def lparen: () -> String? def lparen lparen_loc&.slice end # def rparen: () -> String? def rparen rparen_loc&.slice end # def equal: () -> String? def equal equal_loc&.slice end # def end_keyword: () -> String? def end_keyword end_keyword_loc&.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── name: #{name.inspect}\n" inspector << "├── name_loc: #{inspector.location(name_loc)}\n" if (receiver = self.receiver).nil? inspector << "├── receiver: ∅\n" else inspector << "├── receiver:\n" inspector << receiver.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end if (parameters = self.parameters).nil? inspector << "├── parameters: ∅\n" else inspector << "├── parameters:\n" inspector << parameters.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end if (body = self.body).nil? inspector << "├── body: ∅\n" else inspector << "├── body:\n" inspector << body.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "├── locals: #{locals.inspect}\n" inspector << "├── locals_body_index: #{locals_body_index.inspect}\n" inspector << "├── def_keyword_loc: #{inspector.location(def_keyword_loc)}\n" inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n" inspector << "├── lparen_loc: #{inspector.location(lparen_loc)}\n" inspector << "├── rparen_loc: #{inspector.location(rparen_loc)}\n" inspector << "├── equal_loc: #{inspector.location(equal_loc)}\n" inspector << "└── end_keyword_loc: #{inspector.location(end_keyword_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :def_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :def_node end end # Represents the use of the `defined?` keyword. # # defined?(a) # ^^^^^^^^^^^ class DefinedNode < Node # attr_reader lparen_loc: Location? attr_reader :lparen_loc # attr_reader value: Node attr_reader :value # attr_reader rparen_loc: Location? attr_reader :rparen_loc # attr_reader keyword_loc: Location attr_reader :keyword_loc # def initialize: (lparen_loc: Location?, value: Node, rparen_loc: Location?, keyword_loc: Location, location: Location) -> void def initialize(lparen_loc, value, rparen_loc, keyword_loc, location) @lparen_loc = lparen_loc @value = value @rparen_loc = rparen_loc @keyword_loc = keyword_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_defined_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [value] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [value] end # def comment_targets: () -> Array[Node | Location] def comment_targets [*lparen_loc, value, *rparen_loc, keyword_loc] end # def copy: (**params) -> DefinedNode def copy(**params) DefinedNode.new( params.fetch(:lparen_loc) { lparen_loc }, params.fetch(:value) { value }, params.fetch(:rparen_loc) { rparen_loc }, params.fetch(:keyword_loc) { keyword_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { lparen_loc: lparen_loc, value: value, rparen_loc: rparen_loc, keyword_loc: keyword_loc, location: location } end # def lparen: () -> String? def lparen lparen_loc&.slice end # def rparen: () -> String? def rparen rparen_loc&.slice end # def keyword: () -> String def keyword keyword_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── lparen_loc: #{inspector.location(lparen_loc)}\n" inspector << "├── value:\n" inspector << inspector.child_node(value, "│ ") inspector << "├── rparen_loc: #{inspector.location(rparen_loc)}\n" inspector << "└── keyword_loc: #{inspector.location(keyword_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :defined_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :defined_node end end # Represents an `else` clause in a `case`, `if`, or `unless` statement. # # if a then b else c end # ^^^^^^^^^^ class ElseNode < Node # attr_reader else_keyword_loc: Location attr_reader :else_keyword_loc # attr_reader statements: StatementsNode? attr_reader :statements # attr_reader end_keyword_loc: Location? attr_reader :end_keyword_loc # def initialize: (else_keyword_loc: Location, statements: StatementsNode?, end_keyword_loc: Location?, location: Location) -> void def initialize(else_keyword_loc, statements, end_keyword_loc, location) @else_keyword_loc = else_keyword_loc @statements = statements @end_keyword_loc = end_keyword_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_else_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [statements] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact << statements if statements compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [else_keyword_loc, *statements, *end_keyword_loc] end # def copy: (**params) -> ElseNode def copy(**params) ElseNode.new( params.fetch(:else_keyword_loc) { else_keyword_loc }, params.fetch(:statements) { statements }, params.fetch(:end_keyword_loc) { end_keyword_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { else_keyword_loc: else_keyword_loc, statements: statements, end_keyword_loc: end_keyword_loc, location: location } end # def else_keyword: () -> String def else_keyword else_keyword_loc.slice end # def end_keyword: () -> String? def end_keyword end_keyword_loc&.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── else_keyword_loc: #{inspector.location(else_keyword_loc)}\n" if (statements = self.statements).nil? inspector << "├── statements: ∅\n" else inspector << "├── statements:\n" inspector << statements.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "└── end_keyword_loc: #{inspector.location(end_keyword_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :else_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :else_node end end # Represents an interpolated set of statements. # # "foo #{bar}" # ^^^^^^ class EmbeddedStatementsNode < Node # attr_reader opening_loc: Location attr_reader :opening_loc # attr_reader statements: StatementsNode? attr_reader :statements # attr_reader closing_loc: Location attr_reader :closing_loc # def initialize: (opening_loc: Location, statements: StatementsNode?, closing_loc: Location, location: Location) -> void def initialize(opening_loc, statements, closing_loc, location) @opening_loc = opening_loc @statements = statements @closing_loc = closing_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_embedded_statements_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [statements] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact << statements if statements compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [opening_loc, *statements, closing_loc] end # def copy: (**params) -> EmbeddedStatementsNode def copy(**params) EmbeddedStatementsNode.new( params.fetch(:opening_loc) { opening_loc }, params.fetch(:statements) { statements }, params.fetch(:closing_loc) { closing_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { opening_loc: opening_loc, statements: statements, closing_loc: closing_loc, location: location } end # def opening: () -> String def opening opening_loc.slice end # def closing: () -> String def closing closing_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n" if (statements = self.statements).nil? inspector << "├── statements: ∅\n" else inspector << "├── statements:\n" inspector << statements.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "└── closing_loc: #{inspector.location(closing_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :embedded_statements_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :embedded_statements_node end end # Represents an interpolated variable. # # "foo #@bar" # ^^^^^ class EmbeddedVariableNode < Node # attr_reader operator_loc: Location attr_reader :operator_loc # attr_reader variable: Node attr_reader :variable # def initialize: (operator_loc: Location, variable: Node, location: Location) -> void def initialize(operator_loc, variable, location) @operator_loc = operator_loc @variable = variable @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_embedded_variable_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [variable] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [variable] end # def comment_targets: () -> Array[Node | Location] def comment_targets [operator_loc, variable] end # def copy: (**params) -> EmbeddedVariableNode def copy(**params) EmbeddedVariableNode.new( params.fetch(:operator_loc) { operator_loc }, params.fetch(:variable) { variable }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { operator_loc: operator_loc, variable: variable, location: location } end # def operator: () -> String def operator operator_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n" inspector << "└── variable:\n" inspector << inspector.child_node(variable, " ") inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :embedded_variable_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :embedded_variable_node end end # Represents an `ensure` clause in a `begin` statement. # # begin # foo # ensure # ^^^^^^ # bar # end class EnsureNode < Node # attr_reader ensure_keyword_loc: Location attr_reader :ensure_keyword_loc # attr_reader statements: StatementsNode? attr_reader :statements # attr_reader end_keyword_loc: Location attr_reader :end_keyword_loc # def initialize: (ensure_keyword_loc: Location, statements: StatementsNode?, end_keyword_loc: Location, location: Location) -> void def initialize(ensure_keyword_loc, statements, end_keyword_loc, location) @ensure_keyword_loc = ensure_keyword_loc @statements = statements @end_keyword_loc = end_keyword_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_ensure_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [statements] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact << statements if statements compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [ensure_keyword_loc, *statements, end_keyword_loc] end # def copy: (**params) -> EnsureNode def copy(**params) EnsureNode.new( params.fetch(:ensure_keyword_loc) { ensure_keyword_loc }, params.fetch(:statements) { statements }, params.fetch(:end_keyword_loc) { end_keyword_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { ensure_keyword_loc: ensure_keyword_loc, statements: statements, end_keyword_loc: end_keyword_loc, location: location } end # def ensure_keyword: () -> String def ensure_keyword ensure_keyword_loc.slice end # def end_keyword: () -> String def end_keyword end_keyword_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── ensure_keyword_loc: #{inspector.location(ensure_keyword_loc)}\n" if (statements = self.statements).nil? inspector << "├── statements: ∅\n" else inspector << "├── statements:\n" inspector << statements.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "└── end_keyword_loc: #{inspector.location(end_keyword_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :ensure_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :ensure_node end end # Represents the use of the literal `false` keyword. # # false # ^^^^^ class FalseNode < Node # def initialize: (location: Location) -> void def initialize(location) @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_false_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [] end # def comment_targets: () -> Array[Node | Location] def comment_targets [] end # def copy: (**params) -> FalseNode def copy(**params) FalseNode.new( params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { location: location } end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :false_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :false_node end end # Represents a find pattern in pattern matching. # # foo in *bar, baz, *qux # ^^^^^^^^^^^^^^^ # # foo in [*bar, baz, *qux] # ^^^^^^^^^^^^^^^^^ # # foo in Foo(*bar, baz, *qux) # ^^^^^^^^^^^^^^^^^^^^ class FindPatternNode < Node # attr_reader constant: Node? attr_reader :constant # attr_reader left: Node attr_reader :left # attr_reader requireds: Array[Node] attr_reader :requireds # attr_reader right: Node attr_reader :right # attr_reader opening_loc: Location? attr_reader :opening_loc # attr_reader closing_loc: Location? attr_reader :closing_loc # def initialize: (constant: Node?, left: Node, requireds: Array[Node], right: Node, opening_loc: Location?, closing_loc: Location?, location: Location) -> void def initialize(constant, left, requireds, right, opening_loc, closing_loc, location) @constant = constant @left = left @requireds = requireds @right = right @opening_loc = opening_loc @closing_loc = closing_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_find_pattern_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [constant, left, *requireds, right] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact << constant if constant compact << left compact.concat(requireds) compact << right compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [*constant, left, *requireds, right, *opening_loc, *closing_loc] end # def copy: (**params) -> FindPatternNode def copy(**params) FindPatternNode.new( params.fetch(:constant) { constant }, params.fetch(:left) { left }, params.fetch(:requireds) { requireds }, params.fetch(:right) { right }, params.fetch(:opening_loc) { opening_loc }, params.fetch(:closing_loc) { closing_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { constant: constant, left: left, requireds: requireds, right: right, opening_loc: opening_loc, closing_loc: closing_loc, location: location } end # def opening: () -> String? def opening opening_loc&.slice end # def closing: () -> String? def closing closing_loc&.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) if (constant = self.constant).nil? inspector << "├── constant: ∅\n" else inspector << "├── constant:\n" inspector << constant.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "├── left:\n" inspector << inspector.child_node(left, "│ ") inspector << "├── requireds: #{inspector.list("#{inspector.prefix}│ ", requireds)}" inspector << "├── right:\n" inspector << inspector.child_node(right, "│ ") inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n" inspector << "└── closing_loc: #{inspector.location(closing_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :find_pattern_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :find_pattern_node end end # Represents the use of the `..` or `...` operators to create flip flops. # # baz if foo .. bar # ^^^^^^^^^^ class FlipFlopNode < Node # attr_reader flags: Integer private attr_reader :flags # attr_reader left: Node? attr_reader :left # attr_reader right: Node? attr_reader :right # attr_reader operator_loc: Location attr_reader :operator_loc # def initialize: (flags: Integer, left: Node?, right: Node?, operator_loc: Location, location: Location) -> void def initialize(flags, left, right, operator_loc, location) @flags = flags @left = left @right = right @operator_loc = operator_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_flip_flop_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [left, right] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact << left if left compact << right if right compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [*left, *right, operator_loc] end # def copy: (**params) -> FlipFlopNode def copy(**params) FlipFlopNode.new( params.fetch(:flags) { flags }, params.fetch(:left) { left }, params.fetch(:right) { right }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { flags: flags, left: left, right: right, operator_loc: operator_loc, location: location } end # def exclude_end?: () -> bool def exclude_end? flags.anybits?(RangeFlags::EXCLUDE_END) end # def operator: () -> String def operator operator_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) flags = [("exclude_end" if exclude_end?)].compact inspector << "├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n" if (left = self.left).nil? inspector << "├── left: ∅\n" else inspector << "├── left:\n" inspector << left.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end if (right = self.right).nil? inspector << "├── right: ∅\n" else inspector << "├── right:\n" inspector << right.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "└── operator_loc: #{inspector.location(operator_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :flip_flop_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :flip_flop_node end end # Represents a floating point number literal. # # 1.0 # ^^^ class FloatNode < Node # def initialize: (location: Location) -> void def initialize(location) @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_float_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [] end # def comment_targets: () -> Array[Node | Location] def comment_targets [] end # def copy: (**params) -> FloatNode def copy(**params) FloatNode.new( params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { location: location } end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :float_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :float_node end end # Represents the use of the `for` keyword. # # for i in a end # ^^^^^^^^^^^^^^ class ForNode < Node # attr_reader index: Node attr_reader :index # attr_reader collection: Node attr_reader :collection # attr_reader statements: StatementsNode? attr_reader :statements # attr_reader for_keyword_loc: Location attr_reader :for_keyword_loc # attr_reader in_keyword_loc: Location attr_reader :in_keyword_loc # attr_reader do_keyword_loc: Location? attr_reader :do_keyword_loc # attr_reader end_keyword_loc: Location attr_reader :end_keyword_loc # def initialize: (index: Node, collection: Node, statements: StatementsNode?, for_keyword_loc: Location, in_keyword_loc: Location, do_keyword_loc: Location?, end_keyword_loc: Location, location: Location) -> void def initialize(index, collection, statements, for_keyword_loc, in_keyword_loc, do_keyword_loc, end_keyword_loc, location) @index = index @collection = collection @statements = statements @for_keyword_loc = for_keyword_loc @in_keyword_loc = in_keyword_loc @do_keyword_loc = do_keyword_loc @end_keyword_loc = end_keyword_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_for_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [index, collection, statements] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact << index compact << collection compact << statements if statements compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [index, collection, *statements, for_keyword_loc, in_keyword_loc, *do_keyword_loc, end_keyword_loc] end # def copy: (**params) -> ForNode def copy(**params) ForNode.new( params.fetch(:index) { index }, params.fetch(:collection) { collection }, params.fetch(:statements) { statements }, params.fetch(:for_keyword_loc) { for_keyword_loc }, params.fetch(:in_keyword_loc) { in_keyword_loc }, params.fetch(:do_keyword_loc) { do_keyword_loc }, params.fetch(:end_keyword_loc) { end_keyword_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { index: index, collection: collection, statements: statements, for_keyword_loc: for_keyword_loc, in_keyword_loc: in_keyword_loc, do_keyword_loc: do_keyword_loc, end_keyword_loc: end_keyword_loc, location: location } end # def for_keyword: () -> String def for_keyword for_keyword_loc.slice end # def in_keyword: () -> String def in_keyword in_keyword_loc.slice end # def do_keyword: () -> String? def do_keyword do_keyword_loc&.slice end # def end_keyword: () -> String def end_keyword end_keyword_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── index:\n" inspector << inspector.child_node(index, "│ ") inspector << "├── collection:\n" inspector << inspector.child_node(collection, "│ ") if (statements = self.statements).nil? inspector << "├── statements: ∅\n" else inspector << "├── statements:\n" inspector << statements.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "├── for_keyword_loc: #{inspector.location(for_keyword_loc)}\n" inspector << "├── in_keyword_loc: #{inspector.location(in_keyword_loc)}\n" inspector << "├── do_keyword_loc: #{inspector.location(do_keyword_loc)}\n" inspector << "└── end_keyword_loc: #{inspector.location(end_keyword_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :for_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :for_node end end # Represents forwarding all arguments to this method to another method. # # def foo(...) # bar(...) # ^^^ # end class ForwardingArgumentsNode < Node # def initialize: (location: Location) -> void def initialize(location) @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_forwarding_arguments_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [] end # def comment_targets: () -> Array[Node | Location] def comment_targets [] end # def copy: (**params) -> ForwardingArgumentsNode def copy(**params) ForwardingArgumentsNode.new( params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { location: location } end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :forwarding_arguments_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :forwarding_arguments_node end end # Represents the use of the forwarding parameter in a method, block, or lambda declaration. # # def foo(...) # ^^^ # end class ForwardingParameterNode < Node # def initialize: (location: Location) -> void def initialize(location) @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_forwarding_parameter_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [] end # def comment_targets: () -> Array[Node | Location] def comment_targets [] end # def copy: (**params) -> ForwardingParameterNode def copy(**params) ForwardingParameterNode.new( params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { location: location } end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :forwarding_parameter_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :forwarding_parameter_node end end # Represents the use of the `super` keyword without parentheses or arguments. # # super # ^^^^^ class ForwardingSuperNode < Node # attr_reader block: BlockNode? attr_reader :block # def initialize: (block: BlockNode?, location: Location) -> void def initialize(block, location) @block = block @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_forwarding_super_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [block] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact << block if block compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [*block] end # def copy: (**params) -> ForwardingSuperNode def copy(**params) ForwardingSuperNode.new( params.fetch(:block) { block }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { block: block, location: location } end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) if (block = self.block).nil? inspector << "└── block: ∅\n" else inspector << "└── block:\n" inspector << block.inspect(inspector.child_inspector(" ")).delete_prefix(inspector.prefix) end inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :forwarding_super_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :forwarding_super_node end end # Represents the use of the `&&=` operator for assignment to a global variable. # # $target &&= value # ^^^^^^^^^^^^^^^^^ class GlobalVariableAndWriteNode < Node # attr_reader name: Symbol attr_reader :name # attr_reader name_loc: Location attr_reader :name_loc # attr_reader operator_loc: Location attr_reader :operator_loc # attr_reader value: Node attr_reader :value # def initialize: (name: Symbol, name_loc: Location, operator_loc: Location, value: Node, location: Location) -> void def initialize(name, name_loc, operator_loc, value, location) @name = name @name_loc = name_loc @operator_loc = operator_loc @value = value @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_global_variable_and_write_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [value] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [value] end # def comment_targets: () -> Array[Node | Location] def comment_targets [name_loc, operator_loc, value] end # def copy: (**params) -> GlobalVariableAndWriteNode def copy(**params) GlobalVariableAndWriteNode.new( params.fetch(:name) { name }, params.fetch(:name_loc) { name_loc }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:value) { value }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { name: name, name_loc: name_loc, operator_loc: operator_loc, value: value, location: location } end # def operator: () -> String def operator operator_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── name: #{name.inspect}\n" inspector << "├── name_loc: #{inspector.location(name_loc)}\n" inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n" inspector << "└── value:\n" inspector << inspector.child_node(value, " ") inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :global_variable_and_write_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :global_variable_and_write_node end end # Represents assigning to a global variable using an operator that isn't `=`. # # $target += value # ^^^^^^^^^^^^^^^^ class GlobalVariableOperatorWriteNode < Node # attr_reader name: Symbol attr_reader :name # attr_reader name_loc: Location attr_reader :name_loc # attr_reader operator_loc: Location attr_reader :operator_loc # attr_reader value: Node attr_reader :value # attr_reader operator: Symbol attr_reader :operator # def initialize: (name: Symbol, name_loc: Location, operator_loc: Location, value: Node, operator: Symbol, location: Location) -> void def initialize(name, name_loc, operator_loc, value, operator, location) @name = name @name_loc = name_loc @operator_loc = operator_loc @value = value @operator = operator @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_global_variable_operator_write_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [value] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [value] end # def comment_targets: () -> Array[Node | Location] def comment_targets [name_loc, operator_loc, value] end # def copy: (**params) -> GlobalVariableOperatorWriteNode def copy(**params) GlobalVariableOperatorWriteNode.new( params.fetch(:name) { name }, params.fetch(:name_loc) { name_loc }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:value) { value }, params.fetch(:operator) { operator }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { name: name, name_loc: name_loc, operator_loc: operator_loc, value: value, operator: operator, location: location } end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── name: #{name.inspect}\n" inspector << "├── name_loc: #{inspector.location(name_loc)}\n" inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n" inspector << "├── value:\n" inspector << inspector.child_node(value, "│ ") inspector << "└── operator: #{operator.inspect}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :global_variable_operator_write_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :global_variable_operator_write_node end end # Represents the use of the `||=` operator for assignment to a global variable. # # $target ||= value # ^^^^^^^^^^^^^^^^^ class GlobalVariableOrWriteNode < Node # attr_reader name: Symbol attr_reader :name # attr_reader name_loc: Location attr_reader :name_loc # attr_reader operator_loc: Location attr_reader :operator_loc # attr_reader value: Node attr_reader :value # def initialize: (name: Symbol, name_loc: Location, operator_loc: Location, value: Node, location: Location) -> void def initialize(name, name_loc, operator_loc, value, location) @name = name @name_loc = name_loc @operator_loc = operator_loc @value = value @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_global_variable_or_write_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [value] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [value] end # def comment_targets: () -> Array[Node | Location] def comment_targets [name_loc, operator_loc, value] end # def copy: (**params) -> GlobalVariableOrWriteNode def copy(**params) GlobalVariableOrWriteNode.new( params.fetch(:name) { name }, params.fetch(:name_loc) { name_loc }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:value) { value }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { name: name, name_loc: name_loc, operator_loc: operator_loc, value: value, location: location } end # def operator: () -> String def operator operator_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── name: #{name.inspect}\n" inspector << "├── name_loc: #{inspector.location(name_loc)}\n" inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n" inspector << "└── value:\n" inspector << inspector.child_node(value, " ") inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :global_variable_or_write_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :global_variable_or_write_node end end # Represents referencing a global variable. # # $foo # ^^^^ class GlobalVariableReadNode < Node # attr_reader name: Symbol attr_reader :name # def initialize: (name: Symbol, location: Location) -> void def initialize(name, location) @name = name @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_global_variable_read_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [] end # def comment_targets: () -> Array[Node | Location] def comment_targets [] end # def copy: (**params) -> GlobalVariableReadNode def copy(**params) GlobalVariableReadNode.new( params.fetch(:name) { name }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { name: name, location: location } end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "└── name: #{name.inspect}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :global_variable_read_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :global_variable_read_node end end # Represents writing to a global variable in a context that doesn't have an explicit value. # # $foo, $bar = baz # ^^^^ ^^^^ class GlobalVariableTargetNode < Node # attr_reader name: Symbol attr_reader :name # def initialize: (name: Symbol, location: Location) -> void def initialize(name, location) @name = name @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_global_variable_target_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [] end # def comment_targets: () -> Array[Node | Location] def comment_targets [] end # def copy: (**params) -> GlobalVariableTargetNode def copy(**params) GlobalVariableTargetNode.new( params.fetch(:name) { name }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { name: name, location: location } end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "└── name: #{name.inspect}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :global_variable_target_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :global_variable_target_node end end # Represents writing to a global variable. # # $foo = 1 # ^^^^^^^^ class GlobalVariableWriteNode < Node # attr_reader name: Symbol attr_reader :name # attr_reader name_loc: Location attr_reader :name_loc # attr_reader value: Node attr_reader :value # attr_reader operator_loc: Location attr_reader :operator_loc # def initialize: (name: Symbol, name_loc: Location, value: Node, operator_loc: Location, location: Location) -> void def initialize(name, name_loc, value, operator_loc, location) @name = name @name_loc = name_loc @value = value @operator_loc = operator_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_global_variable_write_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [value] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [value] end # def comment_targets: () -> Array[Node | Location] def comment_targets [name_loc, value, operator_loc] end # def copy: (**params) -> GlobalVariableWriteNode def copy(**params) GlobalVariableWriteNode.new( params.fetch(:name) { name }, params.fetch(:name_loc) { name_loc }, params.fetch(:value) { value }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { name: name, name_loc: name_loc, value: value, operator_loc: operator_loc, location: location } end # def operator: () -> String def operator operator_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── name: #{name.inspect}\n" inspector << "├── name_loc: #{inspector.location(name_loc)}\n" inspector << "├── value:\n" inspector << inspector.child_node(value, "│ ") inspector << "└── operator_loc: #{inspector.location(operator_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :global_variable_write_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :global_variable_write_node end end # Represents a hash literal. # # { a => b } # ^^^^^^^^^^ class HashNode < Node # attr_reader opening_loc: Location attr_reader :opening_loc # attr_reader elements: Array[Node] attr_reader :elements # attr_reader closing_loc: Location attr_reader :closing_loc # def initialize: (opening_loc: Location, elements: Array[Node], closing_loc: Location, location: Location) -> void def initialize(opening_loc, elements, closing_loc, location) @opening_loc = opening_loc @elements = elements @closing_loc = closing_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_hash_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [*elements] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [*elements] end # def comment_targets: () -> Array[Node | Location] def comment_targets [opening_loc, *elements, closing_loc] end # def copy: (**params) -> HashNode def copy(**params) HashNode.new( params.fetch(:opening_loc) { opening_loc }, params.fetch(:elements) { elements }, params.fetch(:closing_loc) { closing_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { opening_loc: opening_loc, elements: elements, closing_loc: closing_loc, location: location } end # def opening: () -> String def opening opening_loc.slice end # def closing: () -> String def closing closing_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n" inspector << "├── elements: #{inspector.list("#{inspector.prefix}│ ", elements)}" inspector << "└── closing_loc: #{inspector.location(closing_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :hash_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :hash_node end end # Represents a hash pattern in pattern matching. # # foo => { a: 1, b: 2 } # ^^^^^^^^^^^^^^ # # foo => { a: 1, b: 2, **c } # ^^^^^^^^^^^^^^^^^^^ class HashPatternNode < Node # attr_reader constant: Node? attr_reader :constant # attr_reader elements: Array[Node] attr_reader :elements # attr_reader rest: Node? attr_reader :rest # attr_reader opening_loc: Location? attr_reader :opening_loc # attr_reader closing_loc: Location? attr_reader :closing_loc # def initialize: (constant: Node?, elements: Array[Node], rest: Node?, opening_loc: Location?, closing_loc: Location?, location: Location) -> void def initialize(constant, elements, rest, opening_loc, closing_loc, location) @constant = constant @elements = elements @rest = rest @opening_loc = opening_loc @closing_loc = closing_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_hash_pattern_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [constant, *elements, rest] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact << constant if constant compact.concat(elements) compact << rest if rest compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [*constant, *elements, *rest, *opening_loc, *closing_loc] end # def copy: (**params) -> HashPatternNode def copy(**params) HashPatternNode.new( params.fetch(:constant) { constant }, params.fetch(:elements) { elements }, params.fetch(:rest) { rest }, params.fetch(:opening_loc) { opening_loc }, params.fetch(:closing_loc) { closing_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { constant: constant, elements: elements, rest: rest, opening_loc: opening_loc, closing_loc: closing_loc, location: location } end # def opening: () -> String? def opening opening_loc&.slice end # def closing: () -> String? def closing closing_loc&.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) if (constant = self.constant).nil? inspector << "├── constant: ∅\n" else inspector << "├── constant:\n" inspector << constant.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "├── elements: #{inspector.list("#{inspector.prefix}│ ", elements)}" if (rest = self.rest).nil? inspector << "├── rest: ∅\n" else inspector << "├── rest:\n" inspector << rest.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n" inspector << "└── closing_loc: #{inspector.location(closing_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :hash_pattern_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :hash_pattern_node end end # Represents the use of the `if` keyword, either in the block form or the modifier form. # # bar if foo # ^^^^^^^^^^ # # if foo then bar end # ^^^^^^^^^^^^^^^^^^^ class IfNode < Node # attr_reader if_keyword_loc: Location? attr_reader :if_keyword_loc # attr_reader predicate: Node attr_reader :predicate # attr_reader then_keyword_loc: Location? attr_reader :then_keyword_loc # attr_reader statements: StatementsNode? attr_reader :statements # attr_reader consequent: Node? attr_reader :consequent # attr_reader end_keyword_loc: Location? attr_reader :end_keyword_loc # def initialize: (if_keyword_loc: Location?, predicate: Node, then_keyword_loc: Location?, statements: StatementsNode?, consequent: Node?, end_keyword_loc: Location?, location: Location) -> void def initialize(if_keyword_loc, predicate, then_keyword_loc, statements, consequent, end_keyword_loc, location) @if_keyword_loc = if_keyword_loc @predicate = predicate @then_keyword_loc = then_keyword_loc @statements = statements @consequent = consequent @end_keyword_loc = end_keyword_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_if_node(self) end def set_newline_flag(newline_marked) # :nodoc: predicate.set_newline_flag(newline_marked) end # def child_nodes: () -> Array[nil | Node] def child_nodes [predicate, statements, consequent] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact << predicate compact << statements if statements compact << consequent if consequent compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [*if_keyword_loc, predicate, *then_keyword_loc, *statements, *consequent, *end_keyword_loc] end # def copy: (**params) -> IfNode def copy(**params) IfNode.new( params.fetch(:if_keyword_loc) { if_keyword_loc }, params.fetch(:predicate) { predicate }, params.fetch(:then_keyword_loc) { then_keyword_loc }, params.fetch(:statements) { statements }, params.fetch(:consequent) { consequent }, params.fetch(:end_keyword_loc) { end_keyword_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { if_keyword_loc: if_keyword_loc, predicate: predicate, then_keyword_loc: then_keyword_loc, statements: statements, consequent: consequent, end_keyword_loc: end_keyword_loc, location: location } end # def if_keyword: () -> String? def if_keyword if_keyword_loc&.slice end # def then_keyword: () -> String? def then_keyword then_keyword_loc&.slice end # def end_keyword: () -> String? def end_keyword end_keyword_loc&.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── if_keyword_loc: #{inspector.location(if_keyword_loc)}\n" inspector << "├── predicate:\n" inspector << inspector.child_node(predicate, "│ ") inspector << "├── then_keyword_loc: #{inspector.location(then_keyword_loc)}\n" if (statements = self.statements).nil? inspector << "├── statements: ∅\n" else inspector << "├── statements:\n" inspector << statements.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end if (consequent = self.consequent).nil? inspector << "├── consequent: ∅\n" else inspector << "├── consequent:\n" inspector << consequent.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "└── end_keyword_loc: #{inspector.location(end_keyword_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :if_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :if_node end end # Represents an imaginary number literal. # # 1.0i # ^^^^ class ImaginaryNode < Node # attr_reader numeric: Node attr_reader :numeric # def initialize: (numeric: Node, location: Location) -> void def initialize(numeric, location) @numeric = numeric @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_imaginary_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [numeric] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [numeric] end # def comment_targets: () -> Array[Node | Location] def comment_targets [numeric] end # def copy: (**params) -> ImaginaryNode def copy(**params) ImaginaryNode.new( params.fetch(:numeric) { numeric }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { numeric: numeric, location: location } end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "└── numeric:\n" inspector << inspector.child_node(numeric, " ") inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :imaginary_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :imaginary_node end end # Represents a node that is implicitly being added to the tree but doesn't # correspond directly to a node in the source. # # { foo: } # ^^^^ # # { Foo: } # ^^^^ class ImplicitNode < Node # attr_reader value: Node attr_reader :value # def initialize: (value: Node, location: Location) -> void def initialize(value, location) @value = value @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_implicit_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [value] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [value] end # def comment_targets: () -> Array[Node | Location] def comment_targets [value] end # def copy: (**params) -> ImplicitNode def copy(**params) ImplicitNode.new( params.fetch(:value) { value }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { value: value, location: location } end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "└── value:\n" inspector << inspector.child_node(value, " ") inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :implicit_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :implicit_node end end # Represents using a trailing comma to indicate an implicit rest parameter. # # foo { |bar,| } # ^ # # foo in [bar,] # ^ # # for foo, in bar do end # ^ # # foo, = bar # ^ class ImplicitRestNode < Node # def initialize: (location: Location) -> void def initialize(location) @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_implicit_rest_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [] end # def comment_targets: () -> Array[Node | Location] def comment_targets [] end # def copy: (**params) -> ImplicitRestNode def copy(**params) ImplicitRestNode.new( params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { location: location } end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :implicit_rest_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :implicit_rest_node end end # Represents the use of the `in` keyword in a case statement. # # case a; in b then c end # ^^^^^^^^^^^ class InNode < Node # attr_reader pattern: Node attr_reader :pattern # attr_reader statements: StatementsNode? attr_reader :statements # attr_reader in_loc: Location attr_reader :in_loc # attr_reader then_loc: Location? attr_reader :then_loc # def initialize: (pattern: Node, statements: StatementsNode?, in_loc: Location, then_loc: Location?, location: Location) -> void def initialize(pattern, statements, in_loc, then_loc, location) @pattern = pattern @statements = statements @in_loc = in_loc @then_loc = then_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_in_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [pattern, statements] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact << pattern compact << statements if statements compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [pattern, *statements, in_loc, *then_loc] end # def copy: (**params) -> InNode def copy(**params) InNode.new( params.fetch(:pattern) { pattern }, params.fetch(:statements) { statements }, params.fetch(:in_loc) { in_loc }, params.fetch(:then_loc) { then_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { pattern: pattern, statements: statements, in_loc: in_loc, then_loc: then_loc, location: location } end # def in: () -> String def in in_loc.slice end # def then: () -> String? def then then_loc&.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── pattern:\n" inspector << inspector.child_node(pattern, "│ ") if (statements = self.statements).nil? inspector << "├── statements: ∅\n" else inspector << "├── statements:\n" inspector << statements.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "├── in_loc: #{inspector.location(in_loc)}\n" inspector << "└── then_loc: #{inspector.location(then_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :in_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :in_node end end # Represents the use of the `&&=` operator on a call to the `[]` method. # # foo.bar[baz] &&= value # ^^^^^^^^^^^^^^^^^^^^^^ class IndexAndWriteNode < Node # attr_reader flags: Integer private attr_reader :flags # attr_reader receiver: Node? attr_reader :receiver # attr_reader call_operator_loc: Location? attr_reader :call_operator_loc # attr_reader opening_loc: Location attr_reader :opening_loc # attr_reader arguments: ArgumentsNode? attr_reader :arguments # attr_reader closing_loc: Location attr_reader :closing_loc # attr_reader block: Node? attr_reader :block # attr_reader operator_loc: Location attr_reader :operator_loc # attr_reader value: Node attr_reader :value # def initialize: (flags: Integer, receiver: Node?, call_operator_loc: Location?, opening_loc: Location, arguments: ArgumentsNode?, closing_loc: Location, block: Node?, operator_loc: Location, value: Node, location: Location) -> void def initialize(flags, receiver, call_operator_loc, opening_loc, arguments, closing_loc, block, operator_loc, value, location) @flags = flags @receiver = receiver @call_operator_loc = call_operator_loc @opening_loc = opening_loc @arguments = arguments @closing_loc = closing_loc @block = block @operator_loc = operator_loc @value = value @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_index_and_write_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [receiver, arguments, block, value] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact << receiver if receiver compact << arguments if arguments compact << block if block compact << value compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [*receiver, *call_operator_loc, opening_loc, *arguments, closing_loc, *block, operator_loc, value] end # def copy: (**params) -> IndexAndWriteNode def copy(**params) IndexAndWriteNode.new( params.fetch(:flags) { flags }, params.fetch(:receiver) { receiver }, params.fetch(:call_operator_loc) { call_operator_loc }, params.fetch(:opening_loc) { opening_loc }, params.fetch(:arguments) { arguments }, params.fetch(:closing_loc) { closing_loc }, params.fetch(:block) { block }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:value) { value }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { flags: flags, receiver: receiver, call_operator_loc: call_operator_loc, opening_loc: opening_loc, arguments: arguments, closing_loc: closing_loc, block: block, operator_loc: operator_loc, value: value, location: location } end # def safe_navigation?: () -> bool def safe_navigation? flags.anybits?(CallNodeFlags::SAFE_NAVIGATION) end # def variable_call?: () -> bool def variable_call? flags.anybits?(CallNodeFlags::VARIABLE_CALL) end # def attribute_write?: () -> bool def attribute_write? flags.anybits?(CallNodeFlags::ATTRIBUTE_WRITE) end # def call_operator: () -> String? def call_operator call_operator_loc&.slice end # def opening: () -> String def opening opening_loc.slice end # def closing: () -> String def closing closing_loc.slice end # def operator: () -> String def operator operator_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) flags = [("safe_navigation" if safe_navigation?), ("variable_call" if variable_call?), ("attribute_write" if attribute_write?)].compact inspector << "├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n" if (receiver = self.receiver).nil? inspector << "├── receiver: ∅\n" else inspector << "├── receiver:\n" inspector << receiver.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "├── call_operator_loc: #{inspector.location(call_operator_loc)}\n" inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n" if (arguments = self.arguments).nil? inspector << "├── arguments: ∅\n" else inspector << "├── arguments:\n" inspector << arguments.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "├── closing_loc: #{inspector.location(closing_loc)}\n" if (block = self.block).nil? inspector << "├── block: ∅\n" else inspector << "├── block:\n" inspector << block.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n" inspector << "└── value:\n" inspector << inspector.child_node(value, " ") inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :index_and_write_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :index_and_write_node end end # Represents the use of an assignment operator on a call to `[]`. # # foo.bar[baz] += value # ^^^^^^^^^^^^^^^^^^^^^ class IndexOperatorWriteNode < Node # attr_reader flags: Integer private attr_reader :flags # attr_reader receiver: Node? attr_reader :receiver # attr_reader call_operator_loc: Location? attr_reader :call_operator_loc # attr_reader opening_loc: Location attr_reader :opening_loc # attr_reader arguments: ArgumentsNode? attr_reader :arguments # attr_reader closing_loc: Location attr_reader :closing_loc # attr_reader block: Node? attr_reader :block # attr_reader operator: Symbol attr_reader :operator # attr_reader operator_loc: Location attr_reader :operator_loc # attr_reader value: Node attr_reader :value # def initialize: (flags: Integer, receiver: Node?, call_operator_loc: Location?, opening_loc: Location, arguments: ArgumentsNode?, closing_loc: Location, block: Node?, operator: Symbol, operator_loc: Location, value: Node, location: Location) -> void def initialize(flags, receiver, call_operator_loc, opening_loc, arguments, closing_loc, block, operator, operator_loc, value, location) @flags = flags @receiver = receiver @call_operator_loc = call_operator_loc @opening_loc = opening_loc @arguments = arguments @closing_loc = closing_loc @block = block @operator = operator @operator_loc = operator_loc @value = value @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_index_operator_write_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [receiver, arguments, block, value] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact << receiver if receiver compact << arguments if arguments compact << block if block compact << value compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [*receiver, *call_operator_loc, opening_loc, *arguments, closing_loc, *block, operator_loc, value] end # def copy: (**params) -> IndexOperatorWriteNode def copy(**params) IndexOperatorWriteNode.new( params.fetch(:flags) { flags }, params.fetch(:receiver) { receiver }, params.fetch(:call_operator_loc) { call_operator_loc }, params.fetch(:opening_loc) { opening_loc }, params.fetch(:arguments) { arguments }, params.fetch(:closing_loc) { closing_loc }, params.fetch(:block) { block }, params.fetch(:operator) { operator }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:value) { value }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { flags: flags, receiver: receiver, call_operator_loc: call_operator_loc, opening_loc: opening_loc, arguments: arguments, closing_loc: closing_loc, block: block, operator: operator, operator_loc: operator_loc, value: value, location: location } end # def safe_navigation?: () -> bool def safe_navigation? flags.anybits?(CallNodeFlags::SAFE_NAVIGATION) end # def variable_call?: () -> bool def variable_call? flags.anybits?(CallNodeFlags::VARIABLE_CALL) end # def attribute_write?: () -> bool def attribute_write? flags.anybits?(CallNodeFlags::ATTRIBUTE_WRITE) end # def call_operator: () -> String? def call_operator call_operator_loc&.slice end # def opening: () -> String def opening opening_loc.slice end # def closing: () -> String def closing closing_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) flags = [("safe_navigation" if safe_navigation?), ("variable_call" if variable_call?), ("attribute_write" if attribute_write?)].compact inspector << "├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n" if (receiver = self.receiver).nil? inspector << "├── receiver: ∅\n" else inspector << "├── receiver:\n" inspector << receiver.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "├── call_operator_loc: #{inspector.location(call_operator_loc)}\n" inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n" if (arguments = self.arguments).nil? inspector << "├── arguments: ∅\n" else inspector << "├── arguments:\n" inspector << arguments.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "├── closing_loc: #{inspector.location(closing_loc)}\n" if (block = self.block).nil? inspector << "├── block: ∅\n" else inspector << "├── block:\n" inspector << block.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "├── operator: #{operator.inspect}\n" inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n" inspector << "└── value:\n" inspector << inspector.child_node(value, " ") inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :index_operator_write_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :index_operator_write_node end end # Represents the use of the `||=` operator on a call to `[]`. # # foo.bar[baz] ||= value # ^^^^^^^^^^^^^^^^^^^^^^ class IndexOrWriteNode < Node # attr_reader flags: Integer private attr_reader :flags # attr_reader receiver: Node? attr_reader :receiver # attr_reader call_operator_loc: Location? attr_reader :call_operator_loc # attr_reader opening_loc: Location attr_reader :opening_loc # attr_reader arguments: ArgumentsNode? attr_reader :arguments # attr_reader closing_loc: Location attr_reader :closing_loc # attr_reader block: Node? attr_reader :block # attr_reader operator_loc: Location attr_reader :operator_loc # attr_reader value: Node attr_reader :value # def initialize: (flags: Integer, receiver: Node?, call_operator_loc: Location?, opening_loc: Location, arguments: ArgumentsNode?, closing_loc: Location, block: Node?, operator_loc: Location, value: Node, location: Location) -> void def initialize(flags, receiver, call_operator_loc, opening_loc, arguments, closing_loc, block, operator_loc, value, location) @flags = flags @receiver = receiver @call_operator_loc = call_operator_loc @opening_loc = opening_loc @arguments = arguments @closing_loc = closing_loc @block = block @operator_loc = operator_loc @value = value @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_index_or_write_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [receiver, arguments, block, value] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact << receiver if receiver compact << arguments if arguments compact << block if block compact << value compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [*receiver, *call_operator_loc, opening_loc, *arguments, closing_loc, *block, operator_loc, value] end # def copy: (**params) -> IndexOrWriteNode def copy(**params) IndexOrWriteNode.new( params.fetch(:flags) { flags }, params.fetch(:receiver) { receiver }, params.fetch(:call_operator_loc) { call_operator_loc }, params.fetch(:opening_loc) { opening_loc }, params.fetch(:arguments) { arguments }, params.fetch(:closing_loc) { closing_loc }, params.fetch(:block) { block }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:value) { value }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { flags: flags, receiver: receiver, call_operator_loc: call_operator_loc, opening_loc: opening_loc, arguments: arguments, closing_loc: closing_loc, block: block, operator_loc: operator_loc, value: value, location: location } end # def safe_navigation?: () -> bool def safe_navigation? flags.anybits?(CallNodeFlags::SAFE_NAVIGATION) end # def variable_call?: () -> bool def variable_call? flags.anybits?(CallNodeFlags::VARIABLE_CALL) end # def attribute_write?: () -> bool def attribute_write? flags.anybits?(CallNodeFlags::ATTRIBUTE_WRITE) end # def call_operator: () -> String? def call_operator call_operator_loc&.slice end # def opening: () -> String def opening opening_loc.slice end # def closing: () -> String def closing closing_loc.slice end # def operator: () -> String def operator operator_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) flags = [("safe_navigation" if safe_navigation?), ("variable_call" if variable_call?), ("attribute_write" if attribute_write?)].compact inspector << "├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n" if (receiver = self.receiver).nil? inspector << "├── receiver: ∅\n" else inspector << "├── receiver:\n" inspector << receiver.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "├── call_operator_loc: #{inspector.location(call_operator_loc)}\n" inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n" if (arguments = self.arguments).nil? inspector << "├── arguments: ∅\n" else inspector << "├── arguments:\n" inspector << arguments.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "├── closing_loc: #{inspector.location(closing_loc)}\n" if (block = self.block).nil? inspector << "├── block: ∅\n" else inspector << "├── block:\n" inspector << block.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n" inspector << "└── value:\n" inspector << inspector.child_node(value, " ") inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :index_or_write_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :index_or_write_node end end # Represents assigning to an index. # # foo[bar], = 1 # ^^^^^^^^ # # begin # rescue => foo[bar] # ^^^^^^^^ # end # # for foo[bar] in baz do end # ^^^^^^^^ class IndexTargetNode < Node # attr_reader flags: Integer private attr_reader :flags # attr_reader receiver: Node attr_reader :receiver # attr_reader opening_loc: Location attr_reader :opening_loc # attr_reader arguments: ArgumentsNode? attr_reader :arguments # attr_reader closing_loc: Location attr_reader :closing_loc # attr_reader block: Node? attr_reader :block # def initialize: (flags: Integer, receiver: Node, opening_loc: Location, arguments: ArgumentsNode?, closing_loc: Location, block: Node?, location: Location) -> void def initialize(flags, receiver, opening_loc, arguments, closing_loc, block, location) @flags = flags @receiver = receiver @opening_loc = opening_loc @arguments = arguments @closing_loc = closing_loc @block = block @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_index_target_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [receiver, arguments, block] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact << receiver compact << arguments if arguments compact << block if block compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [receiver, opening_loc, *arguments, closing_loc, *block] end # def copy: (**params) -> IndexTargetNode def copy(**params) IndexTargetNode.new( params.fetch(:flags) { flags }, params.fetch(:receiver) { receiver }, params.fetch(:opening_loc) { opening_loc }, params.fetch(:arguments) { arguments }, params.fetch(:closing_loc) { closing_loc }, params.fetch(:block) { block }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { flags: flags, receiver: receiver, opening_loc: opening_loc, arguments: arguments, closing_loc: closing_loc, block: block, location: location } end # def safe_navigation?: () -> bool def safe_navigation? flags.anybits?(CallNodeFlags::SAFE_NAVIGATION) end # def variable_call?: () -> bool def variable_call? flags.anybits?(CallNodeFlags::VARIABLE_CALL) end # def attribute_write?: () -> bool def attribute_write? flags.anybits?(CallNodeFlags::ATTRIBUTE_WRITE) end # def opening: () -> String def opening opening_loc.slice end # def closing: () -> String def closing closing_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) flags = [("safe_navigation" if safe_navigation?), ("variable_call" if variable_call?), ("attribute_write" if attribute_write?)].compact inspector << "├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n" inspector << "├── receiver:\n" inspector << inspector.child_node(receiver, "│ ") inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n" if (arguments = self.arguments).nil? inspector << "├── arguments: ∅\n" else inspector << "├── arguments:\n" inspector << arguments.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "├── closing_loc: #{inspector.location(closing_loc)}\n" if (block = self.block).nil? inspector << "└── block: ∅\n" else inspector << "└── block:\n" inspector << block.inspect(inspector.child_inspector(" ")).delete_prefix(inspector.prefix) end inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :index_target_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :index_target_node end end # Represents the use of the `&&=` operator for assignment to an instance variable. # # @target &&= value # ^^^^^^^^^^^^^^^^^ class InstanceVariableAndWriteNode < Node # attr_reader name: Symbol attr_reader :name # attr_reader name_loc: Location attr_reader :name_loc # attr_reader operator_loc: Location attr_reader :operator_loc # attr_reader value: Node attr_reader :value # def initialize: (name: Symbol, name_loc: Location, operator_loc: Location, value: Node, location: Location) -> void def initialize(name, name_loc, operator_loc, value, location) @name = name @name_loc = name_loc @operator_loc = operator_loc @value = value @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_instance_variable_and_write_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [value] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [value] end # def comment_targets: () -> Array[Node | Location] def comment_targets [name_loc, operator_loc, value] end # def copy: (**params) -> InstanceVariableAndWriteNode def copy(**params) InstanceVariableAndWriteNode.new( params.fetch(:name) { name }, params.fetch(:name_loc) { name_loc }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:value) { value }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { name: name, name_loc: name_loc, operator_loc: operator_loc, value: value, location: location } end # def operator: () -> String def operator operator_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── name: #{name.inspect}\n" inspector << "├── name_loc: #{inspector.location(name_loc)}\n" inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n" inspector << "└── value:\n" inspector << inspector.child_node(value, " ") inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :instance_variable_and_write_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :instance_variable_and_write_node end end # Represents assigning to an instance variable using an operator that isn't `=`. # # @target += value # ^^^^^^^^^^^^^^^^ class InstanceVariableOperatorWriteNode < Node # attr_reader name: Symbol attr_reader :name # attr_reader name_loc: Location attr_reader :name_loc # attr_reader operator_loc: Location attr_reader :operator_loc # attr_reader value: Node attr_reader :value # attr_reader operator: Symbol attr_reader :operator # def initialize: (name: Symbol, name_loc: Location, operator_loc: Location, value: Node, operator: Symbol, location: Location) -> void def initialize(name, name_loc, operator_loc, value, operator, location) @name = name @name_loc = name_loc @operator_loc = operator_loc @value = value @operator = operator @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_instance_variable_operator_write_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [value] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [value] end # def comment_targets: () -> Array[Node | Location] def comment_targets [name_loc, operator_loc, value] end # def copy: (**params) -> InstanceVariableOperatorWriteNode def copy(**params) InstanceVariableOperatorWriteNode.new( params.fetch(:name) { name }, params.fetch(:name_loc) { name_loc }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:value) { value }, params.fetch(:operator) { operator }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { name: name, name_loc: name_loc, operator_loc: operator_loc, value: value, operator: operator, location: location } end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── name: #{name.inspect}\n" inspector << "├── name_loc: #{inspector.location(name_loc)}\n" inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n" inspector << "├── value:\n" inspector << inspector.child_node(value, "│ ") inspector << "└── operator: #{operator.inspect}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :instance_variable_operator_write_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :instance_variable_operator_write_node end end # Represents the use of the `||=` operator for assignment to an instance variable. # # @target ||= value # ^^^^^^^^^^^^^^^^^ class InstanceVariableOrWriteNode < Node # attr_reader name: Symbol attr_reader :name # attr_reader name_loc: Location attr_reader :name_loc # attr_reader operator_loc: Location attr_reader :operator_loc # attr_reader value: Node attr_reader :value # def initialize: (name: Symbol, name_loc: Location, operator_loc: Location, value: Node, location: Location) -> void def initialize(name, name_loc, operator_loc, value, location) @name = name @name_loc = name_loc @operator_loc = operator_loc @value = value @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_instance_variable_or_write_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [value] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [value] end # def comment_targets: () -> Array[Node | Location] def comment_targets [name_loc, operator_loc, value] end # def copy: (**params) -> InstanceVariableOrWriteNode def copy(**params) InstanceVariableOrWriteNode.new( params.fetch(:name) { name }, params.fetch(:name_loc) { name_loc }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:value) { value }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { name: name, name_loc: name_loc, operator_loc: operator_loc, value: value, location: location } end # def operator: () -> String def operator operator_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── name: #{name.inspect}\n" inspector << "├── name_loc: #{inspector.location(name_loc)}\n" inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n" inspector << "└── value:\n" inspector << inspector.child_node(value, " ") inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :instance_variable_or_write_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :instance_variable_or_write_node end end # Represents referencing an instance variable. # # @foo # ^^^^ class InstanceVariableReadNode < Node # attr_reader name: Symbol attr_reader :name # def initialize: (name: Symbol, location: Location) -> void def initialize(name, location) @name = name @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_instance_variable_read_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [] end # def comment_targets: () -> Array[Node | Location] def comment_targets [] end # def copy: (**params) -> InstanceVariableReadNode def copy(**params) InstanceVariableReadNode.new( params.fetch(:name) { name }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { name: name, location: location } end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "└── name: #{name.inspect}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :instance_variable_read_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :instance_variable_read_node end end # Represents writing to an instance variable in a context that doesn't have an explicit value. # # @foo, @bar = baz # ^^^^ ^^^^ class InstanceVariableTargetNode < Node # attr_reader name: Symbol attr_reader :name # def initialize: (name: Symbol, location: Location) -> void def initialize(name, location) @name = name @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_instance_variable_target_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [] end # def comment_targets: () -> Array[Node | Location] def comment_targets [] end # def copy: (**params) -> InstanceVariableTargetNode def copy(**params) InstanceVariableTargetNode.new( params.fetch(:name) { name }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { name: name, location: location } end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "└── name: #{name.inspect}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :instance_variable_target_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :instance_variable_target_node end end # Represents writing to an instance variable. # # @foo = 1 # ^^^^^^^^ class InstanceVariableWriteNode < Node # attr_reader name: Symbol attr_reader :name # attr_reader name_loc: Location attr_reader :name_loc # attr_reader value: Node attr_reader :value # attr_reader operator_loc: Location attr_reader :operator_loc # def initialize: (name: Symbol, name_loc: Location, value: Node, operator_loc: Location, location: Location) -> void def initialize(name, name_loc, value, operator_loc, location) @name = name @name_loc = name_loc @value = value @operator_loc = operator_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_instance_variable_write_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [value] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [value] end # def comment_targets: () -> Array[Node | Location] def comment_targets [name_loc, value, operator_loc] end # def copy: (**params) -> InstanceVariableWriteNode def copy(**params) InstanceVariableWriteNode.new( params.fetch(:name) { name }, params.fetch(:name_loc) { name_loc }, params.fetch(:value) { value }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { name: name, name_loc: name_loc, value: value, operator_loc: operator_loc, location: location } end # def operator: () -> String def operator operator_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── name: #{name.inspect}\n" inspector << "├── name_loc: #{inspector.location(name_loc)}\n" inspector << "├── value:\n" inspector << inspector.child_node(value, "│ ") inspector << "└── operator_loc: #{inspector.location(operator_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :instance_variable_write_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :instance_variable_write_node end end # Represents an integer number literal. # # 1 # ^ class IntegerNode < Node # attr_reader flags: Integer private attr_reader :flags # def initialize: (flags: Integer, location: Location) -> void def initialize(flags, location) @flags = flags @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_integer_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [] end # def comment_targets: () -> Array[Node | Location] def comment_targets [] end # def copy: (**params) -> IntegerNode def copy(**params) IntegerNode.new( params.fetch(:flags) { flags }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { flags: flags, location: location } end # def binary?: () -> bool def binary? flags.anybits?(IntegerBaseFlags::BINARY) end # def decimal?: () -> bool def decimal? flags.anybits?(IntegerBaseFlags::DECIMAL) end # def octal?: () -> bool def octal? flags.anybits?(IntegerBaseFlags::OCTAL) end # def hexadecimal?: () -> bool def hexadecimal? flags.anybits?(IntegerBaseFlags::HEXADECIMAL) end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) flags = [("binary" if binary?), ("decimal" if decimal?), ("octal" if octal?), ("hexadecimal" if hexadecimal?)].compact inspector << "└── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :integer_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :integer_node end end # Represents a regular expression literal that contains interpolation that # is being used in the predicate of a conditional to implicitly match # against the last line read by an IO object. # # if /foo #{bar} baz/ then end # ^^^^^^^^^^^^^^^^ class InterpolatedMatchLastLineNode < Node # attr_reader flags: Integer private attr_reader :flags # attr_reader opening_loc: Location attr_reader :opening_loc # attr_reader parts: Array[Node] attr_reader :parts # attr_reader closing_loc: Location attr_reader :closing_loc # def initialize: (flags: Integer, opening_loc: Location, parts: Array[Node], closing_loc: Location, location: Location) -> void def initialize(flags, opening_loc, parts, closing_loc, location) @flags = flags @opening_loc = opening_loc @parts = parts @closing_loc = closing_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_interpolated_match_last_line_node(self) end def set_newline_flag(newline_marked) # :nodoc: first = parts.first first.set_newline_flag(newline_marked) if first end # def child_nodes: () -> Array[nil | Node] def child_nodes [*parts] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [*parts] end # def comment_targets: () -> Array[Node | Location] def comment_targets [opening_loc, *parts, closing_loc] end # def copy: (**params) -> InterpolatedMatchLastLineNode def copy(**params) InterpolatedMatchLastLineNode.new( params.fetch(:flags) { flags }, params.fetch(:opening_loc) { opening_loc }, params.fetch(:parts) { parts }, params.fetch(:closing_loc) { closing_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { flags: flags, opening_loc: opening_loc, parts: parts, closing_loc: closing_loc, location: location } end # def ignore_case?: () -> bool def ignore_case? flags.anybits?(RegularExpressionFlags::IGNORE_CASE) end # def extended?: () -> bool def extended? flags.anybits?(RegularExpressionFlags::EXTENDED) end # def multi_line?: () -> bool def multi_line? flags.anybits?(RegularExpressionFlags::MULTI_LINE) end # def once?: () -> bool def once? flags.anybits?(RegularExpressionFlags::ONCE) end # def euc_jp?: () -> bool def euc_jp? flags.anybits?(RegularExpressionFlags::EUC_JP) end # def ascii_8bit?: () -> bool def ascii_8bit? flags.anybits?(RegularExpressionFlags::ASCII_8BIT) end # def windows_31j?: () -> bool def windows_31j? flags.anybits?(RegularExpressionFlags::WINDOWS_31J) end # def utf_8?: () -> bool def utf_8? flags.anybits?(RegularExpressionFlags::UTF_8) end # def forced_utf8_encoding?: () -> bool def forced_utf8_encoding? flags.anybits?(RegularExpressionFlags::FORCED_UTF8_ENCODING) end # def forced_binary_encoding?: () -> bool def forced_binary_encoding? flags.anybits?(RegularExpressionFlags::FORCED_BINARY_ENCODING) end # def forced_us_ascii_encoding?: () -> bool def forced_us_ascii_encoding? flags.anybits?(RegularExpressionFlags::FORCED_US_ASCII_ENCODING) end # def opening: () -> String def opening opening_loc.slice end # def closing: () -> String def closing closing_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) flags = [("ignore_case" if ignore_case?), ("extended" if extended?), ("multi_line" if multi_line?), ("once" if once?), ("euc_jp" if euc_jp?), ("ascii_8bit" if ascii_8bit?), ("windows_31j" if windows_31j?), ("utf_8" if utf_8?), ("forced_utf8_encoding" if forced_utf8_encoding?), ("forced_binary_encoding" if forced_binary_encoding?), ("forced_us_ascii_encoding" if forced_us_ascii_encoding?)].compact inspector << "├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n" inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n" inspector << "├── parts: #{inspector.list("#{inspector.prefix}│ ", parts)}" inspector << "└── closing_loc: #{inspector.location(closing_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :interpolated_match_last_line_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :interpolated_match_last_line_node end end # Represents a regular expression literal that contains interpolation. # # /foo #{bar} baz/ # ^^^^^^^^^^^^^^^^ class InterpolatedRegularExpressionNode < Node # attr_reader flags: Integer private attr_reader :flags # attr_reader opening_loc: Location attr_reader :opening_loc # attr_reader parts: Array[Node] attr_reader :parts # attr_reader closing_loc: Location attr_reader :closing_loc # def initialize: (flags: Integer, opening_loc: Location, parts: Array[Node], closing_loc: Location, location: Location) -> void def initialize(flags, opening_loc, parts, closing_loc, location) @flags = flags @opening_loc = opening_loc @parts = parts @closing_loc = closing_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_interpolated_regular_expression_node(self) end def set_newline_flag(newline_marked) # :nodoc: first = parts.first first.set_newline_flag(newline_marked) if first end # def child_nodes: () -> Array[nil | Node] def child_nodes [*parts] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [*parts] end # def comment_targets: () -> Array[Node | Location] def comment_targets [opening_loc, *parts, closing_loc] end # def copy: (**params) -> InterpolatedRegularExpressionNode def copy(**params) InterpolatedRegularExpressionNode.new( params.fetch(:flags) { flags }, params.fetch(:opening_loc) { opening_loc }, params.fetch(:parts) { parts }, params.fetch(:closing_loc) { closing_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { flags: flags, opening_loc: opening_loc, parts: parts, closing_loc: closing_loc, location: location } end # def ignore_case?: () -> bool def ignore_case? flags.anybits?(RegularExpressionFlags::IGNORE_CASE) end # def extended?: () -> bool def extended? flags.anybits?(RegularExpressionFlags::EXTENDED) end # def multi_line?: () -> bool def multi_line? flags.anybits?(RegularExpressionFlags::MULTI_LINE) end # def once?: () -> bool def once? flags.anybits?(RegularExpressionFlags::ONCE) end # def euc_jp?: () -> bool def euc_jp? flags.anybits?(RegularExpressionFlags::EUC_JP) end # def ascii_8bit?: () -> bool def ascii_8bit? flags.anybits?(RegularExpressionFlags::ASCII_8BIT) end # def windows_31j?: () -> bool def windows_31j? flags.anybits?(RegularExpressionFlags::WINDOWS_31J) end # def utf_8?: () -> bool def utf_8? flags.anybits?(RegularExpressionFlags::UTF_8) end # def forced_utf8_encoding?: () -> bool def forced_utf8_encoding? flags.anybits?(RegularExpressionFlags::FORCED_UTF8_ENCODING) end # def forced_binary_encoding?: () -> bool def forced_binary_encoding? flags.anybits?(RegularExpressionFlags::FORCED_BINARY_ENCODING) end # def forced_us_ascii_encoding?: () -> bool def forced_us_ascii_encoding? flags.anybits?(RegularExpressionFlags::FORCED_US_ASCII_ENCODING) end # def opening: () -> String def opening opening_loc.slice end # def closing: () -> String def closing closing_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) flags = [("ignore_case" if ignore_case?), ("extended" if extended?), ("multi_line" if multi_line?), ("once" if once?), ("euc_jp" if euc_jp?), ("ascii_8bit" if ascii_8bit?), ("windows_31j" if windows_31j?), ("utf_8" if utf_8?), ("forced_utf8_encoding" if forced_utf8_encoding?), ("forced_binary_encoding" if forced_binary_encoding?), ("forced_us_ascii_encoding" if forced_us_ascii_encoding?)].compact inspector << "├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n" inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n" inspector << "├── parts: #{inspector.list("#{inspector.prefix}│ ", parts)}" inspector << "└── closing_loc: #{inspector.location(closing_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :interpolated_regular_expression_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :interpolated_regular_expression_node end end # Represents a string literal that contains interpolation. # # "foo #{bar} baz" # ^^^^^^^^^^^^^^^^ class InterpolatedStringNode < Node # attr_reader opening_loc: Location? attr_reader :opening_loc # attr_reader parts: Array[Node] attr_reader :parts # attr_reader closing_loc: Location? attr_reader :closing_loc # def initialize: (opening_loc: Location?, parts: Array[Node], closing_loc: Location?, location: Location) -> void def initialize(opening_loc, parts, closing_loc, location) @opening_loc = opening_loc @parts = parts @closing_loc = closing_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_interpolated_string_node(self) end def set_newline_flag(newline_marked) # :nodoc: first = parts.first first.set_newline_flag(newline_marked) if first end # def child_nodes: () -> Array[nil | Node] def child_nodes [*parts] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [*parts] end # def comment_targets: () -> Array[Node | Location] def comment_targets [*opening_loc, *parts, *closing_loc] end # def copy: (**params) -> InterpolatedStringNode def copy(**params) InterpolatedStringNode.new( params.fetch(:opening_loc) { opening_loc }, params.fetch(:parts) { parts }, params.fetch(:closing_loc) { closing_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { opening_loc: opening_loc, parts: parts, closing_loc: closing_loc, location: location } end # def opening: () -> String? def opening opening_loc&.slice end # def closing: () -> String? def closing closing_loc&.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n" inspector << "├── parts: #{inspector.list("#{inspector.prefix}│ ", parts)}" inspector << "└── closing_loc: #{inspector.location(closing_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :interpolated_string_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :interpolated_string_node end end # Represents a symbol literal that contains interpolation. # # :"foo #{bar} baz" # ^^^^^^^^^^^^^^^^^ class InterpolatedSymbolNode < Node # attr_reader opening_loc: Location? attr_reader :opening_loc # attr_reader parts: Array[Node] attr_reader :parts # attr_reader closing_loc: Location? attr_reader :closing_loc # def initialize: (opening_loc: Location?, parts: Array[Node], closing_loc: Location?, location: Location) -> void def initialize(opening_loc, parts, closing_loc, location) @opening_loc = opening_loc @parts = parts @closing_loc = closing_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_interpolated_symbol_node(self) end def set_newline_flag(newline_marked) # :nodoc: first = parts.first first.set_newline_flag(newline_marked) if first end # def child_nodes: () -> Array[nil | Node] def child_nodes [*parts] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [*parts] end # def comment_targets: () -> Array[Node | Location] def comment_targets [*opening_loc, *parts, *closing_loc] end # def copy: (**params) -> InterpolatedSymbolNode def copy(**params) InterpolatedSymbolNode.new( params.fetch(:opening_loc) { opening_loc }, params.fetch(:parts) { parts }, params.fetch(:closing_loc) { closing_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { opening_loc: opening_loc, parts: parts, closing_loc: closing_loc, location: location } end # def opening: () -> String? def opening opening_loc&.slice end # def closing: () -> String? def closing closing_loc&.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n" inspector << "├── parts: #{inspector.list("#{inspector.prefix}│ ", parts)}" inspector << "└── closing_loc: #{inspector.location(closing_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :interpolated_symbol_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :interpolated_symbol_node end end # Represents an xstring literal that contains interpolation. # # `foo #{bar} baz` # ^^^^^^^^^^^^^^^^ class InterpolatedXStringNode < Node # attr_reader opening_loc: Location attr_reader :opening_loc # attr_reader parts: Array[Node] attr_reader :parts # attr_reader closing_loc: Location attr_reader :closing_loc # def initialize: (opening_loc: Location, parts: Array[Node], closing_loc: Location, location: Location) -> void def initialize(opening_loc, parts, closing_loc, location) @opening_loc = opening_loc @parts = parts @closing_loc = closing_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_interpolated_x_string_node(self) end def set_newline_flag(newline_marked) # :nodoc: first = parts.first first.set_newline_flag(newline_marked) if first end # def child_nodes: () -> Array[nil | Node] def child_nodes [*parts] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [*parts] end # def comment_targets: () -> Array[Node | Location] def comment_targets [opening_loc, *parts, closing_loc] end # def copy: (**params) -> InterpolatedXStringNode def copy(**params) InterpolatedXStringNode.new( params.fetch(:opening_loc) { opening_loc }, params.fetch(:parts) { parts }, params.fetch(:closing_loc) { closing_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { opening_loc: opening_loc, parts: parts, closing_loc: closing_loc, location: location } end # def opening: () -> String def opening opening_loc.slice end # def closing: () -> String def closing closing_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n" inspector << "├── parts: #{inspector.list("#{inspector.prefix}│ ", parts)}" inspector << "└── closing_loc: #{inspector.location(closing_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :interpolated_x_string_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :interpolated_x_string_node end end # Represents a hash literal without opening and closing braces. # # foo(a: b) # ^^^^ class KeywordHashNode < Node # attr_reader flags: Integer private attr_reader :flags # attr_reader elements: Array[Node] attr_reader :elements # def initialize: (flags: Integer, elements: Array[Node], location: Location) -> void def initialize(flags, elements, location) @flags = flags @elements = elements @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_keyword_hash_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [*elements] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [*elements] end # def comment_targets: () -> Array[Node | Location] def comment_targets [*elements] end # def copy: (**params) -> KeywordHashNode def copy(**params) KeywordHashNode.new( params.fetch(:flags) { flags }, params.fetch(:elements) { elements }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { flags: flags, elements: elements, location: location } end # def static_keys?: () -> bool def static_keys? flags.anybits?(KeywordHashNodeFlags::STATIC_KEYS) end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) flags = [("static_keys" if static_keys?)].compact inspector << "├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n" inspector << "└── elements: #{inspector.list("#{inspector.prefix} ", elements)}" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :keyword_hash_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :keyword_hash_node end end # Represents a keyword rest parameter to a method, block, or lambda definition. # # def a(**b) # ^^^ # end class KeywordRestParameterNode < Node # attr_reader name: Symbol? attr_reader :name # attr_reader name_loc: Location? attr_reader :name_loc # attr_reader operator_loc: Location attr_reader :operator_loc # def initialize: (name: Symbol?, name_loc: Location?, operator_loc: Location, location: Location) -> void def initialize(name, name_loc, operator_loc, location) @name = name @name_loc = name_loc @operator_loc = operator_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_keyword_rest_parameter_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [] end # def comment_targets: () -> Array[Node | Location] def comment_targets [*name_loc, operator_loc] end # def copy: (**params) -> KeywordRestParameterNode def copy(**params) KeywordRestParameterNode.new( params.fetch(:name) { name }, params.fetch(:name_loc) { name_loc }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { name: name, name_loc: name_loc, operator_loc: operator_loc, location: location } end # def operator: () -> String def operator operator_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) if (name = self.name).nil? inspector << "├── name: ∅\n" else inspector << "├── name: #{name.inspect}\n" end inspector << "├── name_loc: #{inspector.location(name_loc)}\n" inspector << "└── operator_loc: #{inspector.location(operator_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :keyword_rest_parameter_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :keyword_rest_parameter_node end end # Represents using a lambda literal (not the lambda method call). # # ->(value) { value * 2 } # ^^^^^^^^^^^^^^^^^^^^^^^ class LambdaNode < Node # attr_reader locals: Array[Symbol] attr_reader :locals # attr_reader locals_body_index: Integer attr_reader :locals_body_index # attr_reader operator_loc: Location attr_reader :operator_loc # attr_reader opening_loc: Location attr_reader :opening_loc # attr_reader closing_loc: Location attr_reader :closing_loc # attr_reader parameters: Node? attr_reader :parameters # attr_reader body: Node? attr_reader :body # def initialize: (locals: Array[Symbol], locals_body_index: Integer, operator_loc: Location, opening_loc: Location, closing_loc: Location, parameters: Node?, body: Node?, location: Location) -> void def initialize(locals, locals_body_index, operator_loc, opening_loc, closing_loc, parameters, body, location) @locals = locals @locals_body_index = locals_body_index @operator_loc = operator_loc @opening_loc = opening_loc @closing_loc = closing_loc @parameters = parameters @body = body @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_lambda_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [parameters, body] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact << parameters if parameters compact << body if body compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [operator_loc, opening_loc, closing_loc, *parameters, *body] end # def copy: (**params) -> LambdaNode def copy(**params) LambdaNode.new( params.fetch(:locals) { locals }, params.fetch(:locals_body_index) { locals_body_index }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:opening_loc) { opening_loc }, params.fetch(:closing_loc) { closing_loc }, params.fetch(:parameters) { parameters }, params.fetch(:body) { body }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { locals: locals, locals_body_index: locals_body_index, operator_loc: operator_loc, opening_loc: opening_loc, closing_loc: closing_loc, parameters: parameters, body: body, location: location } end # def operator: () -> String def operator operator_loc.slice end # def opening: () -> String def opening opening_loc.slice end # def closing: () -> String def closing closing_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── locals: #{locals.inspect}\n" inspector << "├── locals_body_index: #{locals_body_index.inspect}\n" inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n" inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n" inspector << "├── closing_loc: #{inspector.location(closing_loc)}\n" if (parameters = self.parameters).nil? inspector << "├── parameters: ∅\n" else inspector << "├── parameters:\n" inspector << parameters.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end if (body = self.body).nil? inspector << "└── body: ∅\n" else inspector << "└── body:\n" inspector << body.inspect(inspector.child_inspector(" ")).delete_prefix(inspector.prefix) end inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :lambda_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :lambda_node end end # Represents the use of the `&&=` operator for assignment to a local variable. # # target &&= value # ^^^^^^^^^^^^^^^^ class LocalVariableAndWriteNode < Node # attr_reader name_loc: Location attr_reader :name_loc # attr_reader operator_loc: Location attr_reader :operator_loc # attr_reader value: Node attr_reader :value # attr_reader name: Symbol attr_reader :name # attr_reader depth: Integer attr_reader :depth # def initialize: (name_loc: Location, operator_loc: Location, value: Node, name: Symbol, depth: Integer, location: Location) -> void def initialize(name_loc, operator_loc, value, name, depth, location) @name_loc = name_loc @operator_loc = operator_loc @value = value @name = name @depth = depth @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_local_variable_and_write_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [value] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [value] end # def comment_targets: () -> Array[Node | Location] def comment_targets [name_loc, operator_loc, value] end # def copy: (**params) -> LocalVariableAndWriteNode def copy(**params) LocalVariableAndWriteNode.new( params.fetch(:name_loc) { name_loc }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:value) { value }, params.fetch(:name) { name }, params.fetch(:depth) { depth }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { name_loc: name_loc, operator_loc: operator_loc, value: value, name: name, depth: depth, location: location } end # def operator: () -> String def operator operator_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── name_loc: #{inspector.location(name_loc)}\n" inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n" inspector << "├── value:\n" inspector << inspector.child_node(value, "│ ") inspector << "├── name: #{name.inspect}\n" inspector << "└── depth: #{depth.inspect}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :local_variable_and_write_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :local_variable_and_write_node end end # Represents assigning to a local variable using an operator that isn't `=`. # # target += value # ^^^^^^^^^^^^^^^ class LocalVariableOperatorWriteNode < Node # attr_reader name_loc: Location attr_reader :name_loc # attr_reader operator_loc: Location attr_reader :operator_loc # attr_reader value: Node attr_reader :value # attr_reader name: Symbol attr_reader :name # attr_reader operator: Symbol attr_reader :operator # attr_reader depth: Integer attr_reader :depth # def initialize: (name_loc: Location, operator_loc: Location, value: Node, name: Symbol, operator: Symbol, depth: Integer, location: Location) -> void def initialize(name_loc, operator_loc, value, name, operator, depth, location) @name_loc = name_loc @operator_loc = operator_loc @value = value @name = name @operator = operator @depth = depth @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_local_variable_operator_write_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [value] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [value] end # def comment_targets: () -> Array[Node | Location] def comment_targets [name_loc, operator_loc, value] end # def copy: (**params) -> LocalVariableOperatorWriteNode def copy(**params) LocalVariableOperatorWriteNode.new( params.fetch(:name_loc) { name_loc }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:value) { value }, params.fetch(:name) { name }, params.fetch(:operator) { operator }, params.fetch(:depth) { depth }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { name_loc: name_loc, operator_loc: operator_loc, value: value, name: name, operator: operator, depth: depth, location: location } end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── name_loc: #{inspector.location(name_loc)}\n" inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n" inspector << "├── value:\n" inspector << inspector.child_node(value, "│ ") inspector << "├── name: #{name.inspect}\n" inspector << "├── operator: #{operator.inspect}\n" inspector << "└── depth: #{depth.inspect}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :local_variable_operator_write_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :local_variable_operator_write_node end end # Represents the use of the `||=` operator for assignment to a local variable. # # target ||= value # ^^^^^^^^^^^^^^^^ class LocalVariableOrWriteNode < Node # attr_reader name_loc: Location attr_reader :name_loc # attr_reader operator_loc: Location attr_reader :operator_loc # attr_reader value: Node attr_reader :value # attr_reader name: Symbol attr_reader :name # attr_reader depth: Integer attr_reader :depth # def initialize: (name_loc: Location, operator_loc: Location, value: Node, name: Symbol, depth: Integer, location: Location) -> void def initialize(name_loc, operator_loc, value, name, depth, location) @name_loc = name_loc @operator_loc = operator_loc @value = value @name = name @depth = depth @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_local_variable_or_write_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [value] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [value] end # def comment_targets: () -> Array[Node | Location] def comment_targets [name_loc, operator_loc, value] end # def copy: (**params) -> LocalVariableOrWriteNode def copy(**params) LocalVariableOrWriteNode.new( params.fetch(:name_loc) { name_loc }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:value) { value }, params.fetch(:name) { name }, params.fetch(:depth) { depth }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { name_loc: name_loc, operator_loc: operator_loc, value: value, name: name, depth: depth, location: location } end # def operator: () -> String def operator operator_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── name_loc: #{inspector.location(name_loc)}\n" inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n" inspector << "├── value:\n" inspector << inspector.child_node(value, "│ ") inspector << "├── name: #{name.inspect}\n" inspector << "└── depth: #{depth.inspect}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :local_variable_or_write_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :local_variable_or_write_node end end # Represents reading a local variable. Note that this requires that a local # variable of the same name has already been written to in the same scope, # otherwise it is parsed as a method call. # # foo # ^^^ class LocalVariableReadNode < Node # attr_reader name: Symbol attr_reader :name # attr_reader depth: Integer attr_reader :depth # def initialize: (name: Symbol, depth: Integer, location: Location) -> void def initialize(name, depth, location) @name = name @depth = depth @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_local_variable_read_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [] end # def comment_targets: () -> Array[Node | Location] def comment_targets [] end # def copy: (**params) -> LocalVariableReadNode def copy(**params) LocalVariableReadNode.new( params.fetch(:name) { name }, params.fetch(:depth) { depth }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { name: name, depth: depth, location: location } end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── name: #{name.inspect}\n" inspector << "└── depth: #{depth.inspect}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :local_variable_read_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :local_variable_read_node end end # Represents writing to a local variable in a context that doesn't have an explicit value. # # foo, bar = baz # ^^^ ^^^ class LocalVariableTargetNode < Node # attr_reader name: Symbol attr_reader :name # attr_reader depth: Integer attr_reader :depth # def initialize: (name: Symbol, depth: Integer, location: Location) -> void def initialize(name, depth, location) @name = name @depth = depth @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_local_variable_target_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [] end # def comment_targets: () -> Array[Node | Location] def comment_targets [] end # def copy: (**params) -> LocalVariableTargetNode def copy(**params) LocalVariableTargetNode.new( params.fetch(:name) { name }, params.fetch(:depth) { depth }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { name: name, depth: depth, location: location } end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── name: #{name.inspect}\n" inspector << "└── depth: #{depth.inspect}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :local_variable_target_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :local_variable_target_node end end # Represents writing to a local variable. # # foo = 1 # ^^^^^^^ class LocalVariableWriteNode < Node # attr_reader name: Symbol attr_reader :name # attr_reader depth: Integer attr_reader :depth # attr_reader name_loc: Location attr_reader :name_loc # attr_reader value: Node attr_reader :value # attr_reader operator_loc: Location attr_reader :operator_loc # def initialize: (name: Symbol, depth: Integer, name_loc: Location, value: Node, operator_loc: Location, location: Location) -> void def initialize(name, depth, name_loc, value, operator_loc, location) @name = name @depth = depth @name_loc = name_loc @value = value @operator_loc = operator_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_local_variable_write_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [value] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [value] end # def comment_targets: () -> Array[Node | Location] def comment_targets [name_loc, value, operator_loc] end # def copy: (**params) -> LocalVariableWriteNode def copy(**params) LocalVariableWriteNode.new( params.fetch(:name) { name }, params.fetch(:depth) { depth }, params.fetch(:name_loc) { name_loc }, params.fetch(:value) { value }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { name: name, depth: depth, name_loc: name_loc, value: value, operator_loc: operator_loc, location: location } end # def operator: () -> String def operator operator_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── name: #{name.inspect}\n" inspector << "├── depth: #{depth.inspect}\n" inspector << "├── name_loc: #{inspector.location(name_loc)}\n" inspector << "├── value:\n" inspector << inspector.child_node(value, "│ ") inspector << "└── operator_loc: #{inspector.location(operator_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :local_variable_write_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :local_variable_write_node end end # Represents a regular expression literal used in the predicate of a # conditional to implicitly match against the last line read by an IO # object. # # if /foo/i then end # ^^^^^^ class MatchLastLineNode < Node # attr_reader flags: Integer private attr_reader :flags # attr_reader opening_loc: Location attr_reader :opening_loc # attr_reader content_loc: Location attr_reader :content_loc # attr_reader closing_loc: Location attr_reader :closing_loc # attr_reader unescaped: String attr_reader :unescaped # def initialize: (flags: Integer, opening_loc: Location, content_loc: Location, closing_loc: Location, unescaped: String, location: Location) -> void def initialize(flags, opening_loc, content_loc, closing_loc, unescaped, location) @flags = flags @opening_loc = opening_loc @content_loc = content_loc @closing_loc = closing_loc @unescaped = unescaped @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_match_last_line_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [] end # def comment_targets: () -> Array[Node | Location] def comment_targets [opening_loc, content_loc, closing_loc] end # def copy: (**params) -> MatchLastLineNode def copy(**params) MatchLastLineNode.new( params.fetch(:flags) { flags }, params.fetch(:opening_loc) { opening_loc }, params.fetch(:content_loc) { content_loc }, params.fetch(:closing_loc) { closing_loc }, params.fetch(:unescaped) { unescaped }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { flags: flags, opening_loc: opening_loc, content_loc: content_loc, closing_loc: closing_loc, unescaped: unescaped, location: location } end # def ignore_case?: () -> bool def ignore_case? flags.anybits?(RegularExpressionFlags::IGNORE_CASE) end # def extended?: () -> bool def extended? flags.anybits?(RegularExpressionFlags::EXTENDED) end # def multi_line?: () -> bool def multi_line? flags.anybits?(RegularExpressionFlags::MULTI_LINE) end # def once?: () -> bool def once? flags.anybits?(RegularExpressionFlags::ONCE) end # def euc_jp?: () -> bool def euc_jp? flags.anybits?(RegularExpressionFlags::EUC_JP) end # def ascii_8bit?: () -> bool def ascii_8bit? flags.anybits?(RegularExpressionFlags::ASCII_8BIT) end # def windows_31j?: () -> bool def windows_31j? flags.anybits?(RegularExpressionFlags::WINDOWS_31J) end # def utf_8?: () -> bool def utf_8? flags.anybits?(RegularExpressionFlags::UTF_8) end # def forced_utf8_encoding?: () -> bool def forced_utf8_encoding? flags.anybits?(RegularExpressionFlags::FORCED_UTF8_ENCODING) end # def forced_binary_encoding?: () -> bool def forced_binary_encoding? flags.anybits?(RegularExpressionFlags::FORCED_BINARY_ENCODING) end # def forced_us_ascii_encoding?: () -> bool def forced_us_ascii_encoding? flags.anybits?(RegularExpressionFlags::FORCED_US_ASCII_ENCODING) end # def opening: () -> String def opening opening_loc.slice end # def content: () -> String def content content_loc.slice end # def closing: () -> String def closing closing_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) flags = [("ignore_case" if ignore_case?), ("extended" if extended?), ("multi_line" if multi_line?), ("once" if once?), ("euc_jp" if euc_jp?), ("ascii_8bit" if ascii_8bit?), ("windows_31j" if windows_31j?), ("utf_8" if utf_8?), ("forced_utf8_encoding" if forced_utf8_encoding?), ("forced_binary_encoding" if forced_binary_encoding?), ("forced_us_ascii_encoding" if forced_us_ascii_encoding?)].compact inspector << "├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n" inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n" inspector << "├── content_loc: #{inspector.location(content_loc)}\n" inspector << "├── closing_loc: #{inspector.location(closing_loc)}\n" inspector << "└── unescaped: #{unescaped.inspect}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :match_last_line_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :match_last_line_node end end # Represents the use of the modifier `in` operator. # # foo in bar # ^^^^^^^^^^ class MatchPredicateNode < Node # attr_reader value: Node attr_reader :value # attr_reader pattern: Node attr_reader :pattern # attr_reader operator_loc: Location attr_reader :operator_loc # def initialize: (value: Node, pattern: Node, operator_loc: Location, location: Location) -> void def initialize(value, pattern, operator_loc, location) @value = value @pattern = pattern @operator_loc = operator_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_match_predicate_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [value, pattern] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [value, pattern] end # def comment_targets: () -> Array[Node | Location] def comment_targets [value, pattern, operator_loc] end # def copy: (**params) -> MatchPredicateNode def copy(**params) MatchPredicateNode.new( params.fetch(:value) { value }, params.fetch(:pattern) { pattern }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { value: value, pattern: pattern, operator_loc: operator_loc, location: location } end # def operator: () -> String def operator operator_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── value:\n" inspector << inspector.child_node(value, "│ ") inspector << "├── pattern:\n" inspector << inspector.child_node(pattern, "│ ") inspector << "└── operator_loc: #{inspector.location(operator_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :match_predicate_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :match_predicate_node end end # Represents the use of the `=>` operator. # # foo => bar # ^^^^^^^^^^ class MatchRequiredNode < Node # attr_reader value: Node attr_reader :value # attr_reader pattern: Node attr_reader :pattern # attr_reader operator_loc: Location attr_reader :operator_loc # def initialize: (value: Node, pattern: Node, operator_loc: Location, location: Location) -> void def initialize(value, pattern, operator_loc, location) @value = value @pattern = pattern @operator_loc = operator_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_match_required_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [value, pattern] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [value, pattern] end # def comment_targets: () -> Array[Node | Location] def comment_targets [value, pattern, operator_loc] end # def copy: (**params) -> MatchRequiredNode def copy(**params) MatchRequiredNode.new( params.fetch(:value) { value }, params.fetch(:pattern) { pattern }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { value: value, pattern: pattern, operator_loc: operator_loc, location: location } end # def operator: () -> String def operator operator_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── value:\n" inspector << inspector.child_node(value, "│ ") inspector << "├── pattern:\n" inspector << inspector.child_node(pattern, "│ ") inspector << "└── operator_loc: #{inspector.location(operator_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :match_required_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :match_required_node end end # Represents writing local variables using a regular expression match with # named capture groups. # # /(?<foo>bar)/ =~ baz # ^^^^^^^^^^^^^^^^^^^^ class MatchWriteNode < Node # attr_reader call: CallNode attr_reader :call # attr_reader targets: Array[Node] attr_reader :targets # def initialize: (call: CallNode, targets: Array[Node], location: Location) -> void def initialize(call, targets, location) @call = call @targets = targets @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_match_write_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [call, *targets] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [call, *targets] end # def comment_targets: () -> Array[Node | Location] def comment_targets [call, *targets] end # def copy: (**params) -> MatchWriteNode def copy(**params) MatchWriteNode.new( params.fetch(:call) { call }, params.fetch(:targets) { targets }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { call: call, targets: targets, location: location } end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── call:\n" inspector << inspector.child_node(call, "│ ") inspector << "└── targets: #{inspector.list("#{inspector.prefix} ", targets)}" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :match_write_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :match_write_node end end # Represents a node that is missing from the source and results in a syntax # error. class MissingNode < Node # def initialize: (location: Location) -> void def initialize(location) @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_missing_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [] end # def comment_targets: () -> Array[Node | Location] def comment_targets [] end # def copy: (**params) -> MissingNode def copy(**params) MissingNode.new( params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { location: location } end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :missing_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :missing_node end end # Represents a module declaration involving the `module` keyword. # # module Foo end # ^^^^^^^^^^^^^^ class ModuleNode < Node # attr_reader locals: Array[Symbol] attr_reader :locals # attr_reader module_keyword_loc: Location attr_reader :module_keyword_loc # attr_reader constant_path: Node attr_reader :constant_path # attr_reader body: Node? attr_reader :body # attr_reader end_keyword_loc: Location attr_reader :end_keyword_loc # attr_reader name: Symbol attr_reader :name # def initialize: (locals: Array[Symbol], module_keyword_loc: Location, constant_path: Node, body: Node?, end_keyword_loc: Location, name: Symbol, location: Location) -> void def initialize(locals, module_keyword_loc, constant_path, body, end_keyword_loc, name, location) @locals = locals @module_keyword_loc = module_keyword_loc @constant_path = constant_path @body = body @end_keyword_loc = end_keyword_loc @name = name @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_module_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [constant_path, body] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact << constant_path compact << body if body compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [module_keyword_loc, constant_path, *body, end_keyword_loc] end # def copy: (**params) -> ModuleNode def copy(**params) ModuleNode.new( params.fetch(:locals) { locals }, params.fetch(:module_keyword_loc) { module_keyword_loc }, params.fetch(:constant_path) { constant_path }, params.fetch(:body) { body }, params.fetch(:end_keyword_loc) { end_keyword_loc }, params.fetch(:name) { name }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { locals: locals, module_keyword_loc: module_keyword_loc, constant_path: constant_path, body: body, end_keyword_loc: end_keyword_loc, name: name, location: location } end # def module_keyword: () -> String def module_keyword module_keyword_loc.slice end # def end_keyword: () -> String def end_keyword end_keyword_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── locals: #{locals.inspect}\n" inspector << "├── module_keyword_loc: #{inspector.location(module_keyword_loc)}\n" inspector << "├── constant_path:\n" inspector << inspector.child_node(constant_path, "│ ") if (body = self.body).nil? inspector << "├── body: ∅\n" else inspector << "├── body:\n" inspector << body.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "├── end_keyword_loc: #{inspector.location(end_keyword_loc)}\n" inspector << "└── name: #{name.inspect}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :module_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :module_node end end # Represents a multi-target expression. # # a, (b, c) = 1, 2, 3 # ^^^^^^ class MultiTargetNode < Node # attr_reader lefts: Array[Node] attr_reader :lefts # attr_reader rest: Node? attr_reader :rest # attr_reader rights: Array[Node] attr_reader :rights # attr_reader lparen_loc: Location? attr_reader :lparen_loc # attr_reader rparen_loc: Location? attr_reader :rparen_loc # def initialize: (lefts: Array[Node], rest: Node?, rights: Array[Node], lparen_loc: Location?, rparen_loc: Location?, location: Location) -> void def initialize(lefts, rest, rights, lparen_loc, rparen_loc, location) @lefts = lefts @rest = rest @rights = rights @lparen_loc = lparen_loc @rparen_loc = rparen_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_multi_target_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [*lefts, rest, *rights] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact.concat(lefts) compact << rest if rest compact.concat(rights) compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [*lefts, *rest, *rights, *lparen_loc, *rparen_loc] end # def copy: (**params) -> MultiTargetNode def copy(**params) MultiTargetNode.new( params.fetch(:lefts) { lefts }, params.fetch(:rest) { rest }, params.fetch(:rights) { rights }, params.fetch(:lparen_loc) { lparen_loc }, params.fetch(:rparen_loc) { rparen_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { lefts: lefts, rest: rest, rights: rights, lparen_loc: lparen_loc, rparen_loc: rparen_loc, location: location } end # def lparen: () -> String? def lparen lparen_loc&.slice end # def rparen: () -> String? def rparen rparen_loc&.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── lefts: #{inspector.list("#{inspector.prefix}│ ", lefts)}" if (rest = self.rest).nil? inspector << "├── rest: ∅\n" else inspector << "├── rest:\n" inspector << rest.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "├── rights: #{inspector.list("#{inspector.prefix}│ ", rights)}" inspector << "├── lparen_loc: #{inspector.location(lparen_loc)}\n" inspector << "└── rparen_loc: #{inspector.location(rparen_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :multi_target_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :multi_target_node end end # Represents a write to a multi-target expression. # # a, b, c = 1, 2, 3 # ^^^^^^^^^^^^^^^^^ class MultiWriteNode < Node # attr_reader lefts: Array[Node] attr_reader :lefts # attr_reader rest: Node? attr_reader :rest # attr_reader rights: Array[Node] attr_reader :rights # attr_reader lparen_loc: Location? attr_reader :lparen_loc # attr_reader rparen_loc: Location? attr_reader :rparen_loc # attr_reader operator_loc: Location attr_reader :operator_loc # attr_reader value: Node attr_reader :value # def initialize: (lefts: Array[Node], rest: Node?, rights: Array[Node], lparen_loc: Location?, rparen_loc: Location?, operator_loc: Location, value: Node, location: Location) -> void def initialize(lefts, rest, rights, lparen_loc, rparen_loc, operator_loc, value, location) @lefts = lefts @rest = rest @rights = rights @lparen_loc = lparen_loc @rparen_loc = rparen_loc @operator_loc = operator_loc @value = value @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_multi_write_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [*lefts, rest, *rights, value] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact.concat(lefts) compact << rest if rest compact.concat(rights) compact << value compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [*lefts, *rest, *rights, *lparen_loc, *rparen_loc, operator_loc, value] end # def copy: (**params) -> MultiWriteNode def copy(**params) MultiWriteNode.new( params.fetch(:lefts) { lefts }, params.fetch(:rest) { rest }, params.fetch(:rights) { rights }, params.fetch(:lparen_loc) { lparen_loc }, params.fetch(:rparen_loc) { rparen_loc }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:value) { value }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { lefts: lefts, rest: rest, rights: rights, lparen_loc: lparen_loc, rparen_loc: rparen_loc, operator_loc: operator_loc, value: value, location: location } end # def lparen: () -> String? def lparen lparen_loc&.slice end # def rparen: () -> String? def rparen rparen_loc&.slice end # def operator: () -> String def operator operator_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── lefts: #{inspector.list("#{inspector.prefix}│ ", lefts)}" if (rest = self.rest).nil? inspector << "├── rest: ∅\n" else inspector << "├── rest:\n" inspector << rest.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "├── rights: #{inspector.list("#{inspector.prefix}│ ", rights)}" inspector << "├── lparen_loc: #{inspector.location(lparen_loc)}\n" inspector << "├── rparen_loc: #{inspector.location(rparen_loc)}\n" inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n" inspector << "└── value:\n" inspector << inspector.child_node(value, " ") inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :multi_write_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :multi_write_node end end # Represents the use of the `next` keyword. # # next 1 # ^^^^^^ class NextNode < Node # attr_reader arguments: ArgumentsNode? attr_reader :arguments # attr_reader keyword_loc: Location attr_reader :keyword_loc # def initialize: (arguments: ArgumentsNode?, keyword_loc: Location, location: Location) -> void def initialize(arguments, keyword_loc, location) @arguments = arguments @keyword_loc = keyword_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_next_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [arguments] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact << arguments if arguments compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [*arguments, keyword_loc] end # def copy: (**params) -> NextNode def copy(**params) NextNode.new( params.fetch(:arguments) { arguments }, params.fetch(:keyword_loc) { keyword_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { arguments: arguments, keyword_loc: keyword_loc, location: location } end # def keyword: () -> String def keyword keyword_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) if (arguments = self.arguments).nil? inspector << "├── arguments: ∅\n" else inspector << "├── arguments:\n" inspector << arguments.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "└── keyword_loc: #{inspector.location(keyword_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :next_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :next_node end end # Represents the use of the `nil` keyword. # # nil # ^^^ class NilNode < Node # def initialize: (location: Location) -> void def initialize(location) @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_nil_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [] end # def comment_targets: () -> Array[Node | Location] def comment_targets [] end # def copy: (**params) -> NilNode def copy(**params) NilNode.new( params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { location: location } end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :nil_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :nil_node end end # Represents the use of `**nil` inside method arguments. # # def a(**nil) # ^^^^^ # end class NoKeywordsParameterNode < Node # attr_reader operator_loc: Location attr_reader :operator_loc # attr_reader keyword_loc: Location attr_reader :keyword_loc # def initialize: (operator_loc: Location, keyword_loc: Location, location: Location) -> void def initialize(operator_loc, keyword_loc, location) @operator_loc = operator_loc @keyword_loc = keyword_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_no_keywords_parameter_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [] end # def comment_targets: () -> Array[Node | Location] def comment_targets [operator_loc, keyword_loc] end # def copy: (**params) -> NoKeywordsParameterNode def copy(**params) NoKeywordsParameterNode.new( params.fetch(:operator_loc) { operator_loc }, params.fetch(:keyword_loc) { keyword_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { operator_loc: operator_loc, keyword_loc: keyword_loc, location: location } end # def operator: () -> String def operator operator_loc.slice end # def keyword: () -> String def keyword keyword_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n" inspector << "└── keyword_loc: #{inspector.location(keyword_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :no_keywords_parameter_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :no_keywords_parameter_node end end # Represents an implicit set of parameters through the use of numbered # parameters within a block or lambda. # # -> { _1 + _2 } # ^^^^^^^^^^^^^^ class NumberedParametersNode < Node # attr_reader maximum: Integer attr_reader :maximum # def initialize: (maximum: Integer, location: Location) -> void def initialize(maximum, location) @maximum = maximum @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_numbered_parameters_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [] end # def comment_targets: () -> Array[Node | Location] def comment_targets [] end # def copy: (**params) -> NumberedParametersNode def copy(**params) NumberedParametersNode.new( params.fetch(:maximum) { maximum }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { maximum: maximum, location: location } end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "└── maximum: #{maximum.inspect}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :numbered_parameters_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :numbered_parameters_node end end # Represents reading a numbered reference to a capture in the previous match. # # $1 # ^^ class NumberedReferenceReadNode < Node # attr_reader number: Integer attr_reader :number # def initialize: (number: Integer, location: Location) -> void def initialize(number, location) @number = number @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_numbered_reference_read_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [] end # def comment_targets: () -> Array[Node | Location] def comment_targets [] end # def copy: (**params) -> NumberedReferenceReadNode def copy(**params) NumberedReferenceReadNode.new( params.fetch(:number) { number }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { number: number, location: location } end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "└── number: #{number.inspect}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :numbered_reference_read_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :numbered_reference_read_node end end # Represents an optional keyword parameter to a method, block, or lambda definition. # # def a(b: 1) # ^^^^ # end class OptionalKeywordParameterNode < Node # attr_reader name: Symbol attr_reader :name # attr_reader name_loc: Location attr_reader :name_loc # attr_reader value: Node attr_reader :value # def initialize: (name: Symbol, name_loc: Location, value: Node, location: Location) -> void def initialize(name, name_loc, value, location) @name = name @name_loc = name_loc @value = value @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_optional_keyword_parameter_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [value] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [value] end # def comment_targets: () -> Array[Node | Location] def comment_targets [name_loc, value] end # def copy: (**params) -> OptionalKeywordParameterNode def copy(**params) OptionalKeywordParameterNode.new( params.fetch(:name) { name }, params.fetch(:name_loc) { name_loc }, params.fetch(:value) { value }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { name: name, name_loc: name_loc, value: value, location: location } end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── name: #{name.inspect}\n" inspector << "├── name_loc: #{inspector.location(name_loc)}\n" inspector << "└── value:\n" inspector << inspector.child_node(value, " ") inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :optional_keyword_parameter_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :optional_keyword_parameter_node end end # Represents an optional parameter to a method, block, or lambda definition. # # def a(b = 1) # ^^^^^ # end class OptionalParameterNode < Node # attr_reader name: Symbol attr_reader :name # attr_reader name_loc: Location attr_reader :name_loc # attr_reader operator_loc: Location attr_reader :operator_loc # attr_reader value: Node attr_reader :value # def initialize: (name: Symbol, name_loc: Location, operator_loc: Location, value: Node, location: Location) -> void def initialize(name, name_loc, operator_loc, value, location) @name = name @name_loc = name_loc @operator_loc = operator_loc @value = value @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_optional_parameter_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [value] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [value] end # def comment_targets: () -> Array[Node | Location] def comment_targets [name_loc, operator_loc, value] end # def copy: (**params) -> OptionalParameterNode def copy(**params) OptionalParameterNode.new( params.fetch(:name) { name }, params.fetch(:name_loc) { name_loc }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:value) { value }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { name: name, name_loc: name_loc, operator_loc: operator_loc, value: value, location: location } end # def operator: () -> String def operator operator_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── name: #{name.inspect}\n" inspector << "├── name_loc: #{inspector.location(name_loc)}\n" inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n" inspector << "└── value:\n" inspector << inspector.child_node(value, " ") inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :optional_parameter_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :optional_parameter_node end end # Represents the use of the `||` operator or the `or` keyword. # # left or right # ^^^^^^^^^^^^^ class OrNode < Node # attr_reader left: Node attr_reader :left # attr_reader right: Node attr_reader :right # attr_reader operator_loc: Location attr_reader :operator_loc # def initialize: (left: Node, right: Node, operator_loc: Location, location: Location) -> void def initialize(left, right, operator_loc, location) @left = left @right = right @operator_loc = operator_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_or_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [left, right] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [left, right] end # def comment_targets: () -> Array[Node | Location] def comment_targets [left, right, operator_loc] end # def copy: (**params) -> OrNode def copy(**params) OrNode.new( params.fetch(:left) { left }, params.fetch(:right) { right }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { left: left, right: right, operator_loc: operator_loc, location: location } end # def operator: () -> String def operator operator_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── left:\n" inspector << inspector.child_node(left, "│ ") inspector << "├── right:\n" inspector << inspector.child_node(right, "│ ") inspector << "└── operator_loc: #{inspector.location(operator_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :or_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :or_node end end # Represents the list of parameters on a method, block, or lambda definition. # # def a(b, c, d) # ^^^^^^^ # end class ParametersNode < Node # attr_reader requireds: Array[Node] attr_reader :requireds # attr_reader optionals: Array[Node] attr_reader :optionals # attr_reader rest: Node? attr_reader :rest # attr_reader posts: Array[Node] attr_reader :posts # attr_reader keywords: Array[Node] attr_reader :keywords # attr_reader keyword_rest: Node? attr_reader :keyword_rest # attr_reader block: BlockParameterNode? attr_reader :block # def initialize: (requireds: Array[Node], optionals: Array[Node], rest: Node?, posts: Array[Node], keywords: Array[Node], keyword_rest: Node?, block: BlockParameterNode?, location: Location) -> void def initialize(requireds, optionals, rest, posts, keywords, keyword_rest, block, location) @requireds = requireds @optionals = optionals @rest = rest @posts = posts @keywords = keywords @keyword_rest = keyword_rest @block = block @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_parameters_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [*requireds, *optionals, rest, *posts, *keywords, keyword_rest, block] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact.concat(requireds) compact.concat(optionals) compact << rest if rest compact.concat(posts) compact.concat(keywords) compact << keyword_rest if keyword_rest compact << block if block compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [*requireds, *optionals, *rest, *posts, *keywords, *keyword_rest, *block] end # def copy: (**params) -> ParametersNode def copy(**params) ParametersNode.new( params.fetch(:requireds) { requireds }, params.fetch(:optionals) { optionals }, params.fetch(:rest) { rest }, params.fetch(:posts) { posts }, params.fetch(:keywords) { keywords }, params.fetch(:keyword_rest) { keyword_rest }, params.fetch(:block) { block }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { requireds: requireds, optionals: optionals, rest: rest, posts: posts, keywords: keywords, keyword_rest: keyword_rest, block: block, location: location } end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── requireds: #{inspector.list("#{inspector.prefix}│ ", requireds)}" inspector << "├── optionals: #{inspector.list("#{inspector.prefix}│ ", optionals)}" if (rest = self.rest).nil? inspector << "├── rest: ∅\n" else inspector << "├── rest:\n" inspector << rest.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "├── posts: #{inspector.list("#{inspector.prefix}│ ", posts)}" inspector << "├── keywords: #{inspector.list("#{inspector.prefix}│ ", keywords)}" if (keyword_rest = self.keyword_rest).nil? inspector << "├── keyword_rest: ∅\n" else inspector << "├── keyword_rest:\n" inspector << keyword_rest.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end if (block = self.block).nil? inspector << "└── block: ∅\n" else inspector << "└── block:\n" inspector << block.inspect(inspector.child_inspector(" ")).delete_prefix(inspector.prefix) end inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :parameters_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :parameters_node end end # Represents a parenthesized expression # # (10 + 34) # ^^^^^^^^^ class ParenthesesNode < Node # attr_reader body: Node? attr_reader :body # attr_reader opening_loc: Location attr_reader :opening_loc # attr_reader closing_loc: Location attr_reader :closing_loc # def initialize: (body: Node?, opening_loc: Location, closing_loc: Location, location: Location) -> void def initialize(body, opening_loc, closing_loc, location) @body = body @opening_loc = opening_loc @closing_loc = closing_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_parentheses_node(self) end def set_newline_flag(newline_marked) # :nodoc: # Never mark ParenthesesNode with a newline flag, mark children instead end # def child_nodes: () -> Array[nil | Node] def child_nodes [body] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact << body if body compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [*body, opening_loc, closing_loc] end # def copy: (**params) -> ParenthesesNode def copy(**params) ParenthesesNode.new( params.fetch(:body) { body }, params.fetch(:opening_loc) { opening_loc }, params.fetch(:closing_loc) { closing_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { body: body, opening_loc: opening_loc, closing_loc: closing_loc, location: location } end # def opening: () -> String def opening opening_loc.slice end # def closing: () -> String def closing closing_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) if (body = self.body).nil? inspector << "├── body: ∅\n" else inspector << "├── body:\n" inspector << body.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n" inspector << "└── closing_loc: #{inspector.location(closing_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :parentheses_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :parentheses_node end end # Represents the use of the `^` operator for pinning an expression in a # pattern matching expression. # # foo in ^(bar) # ^^^^^^ class PinnedExpressionNode < Node # attr_reader expression: Node attr_reader :expression # attr_reader operator_loc: Location attr_reader :operator_loc # attr_reader lparen_loc: Location attr_reader :lparen_loc # attr_reader rparen_loc: Location attr_reader :rparen_loc # def initialize: (expression: Node, operator_loc: Location, lparen_loc: Location, rparen_loc: Location, location: Location) -> void def initialize(expression, operator_loc, lparen_loc, rparen_loc, location) @expression = expression @operator_loc = operator_loc @lparen_loc = lparen_loc @rparen_loc = rparen_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_pinned_expression_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [expression] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [expression] end # def comment_targets: () -> Array[Node | Location] def comment_targets [expression, operator_loc, lparen_loc, rparen_loc] end # def copy: (**params) -> PinnedExpressionNode def copy(**params) PinnedExpressionNode.new( params.fetch(:expression) { expression }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:lparen_loc) { lparen_loc }, params.fetch(:rparen_loc) { rparen_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { expression: expression, operator_loc: operator_loc, lparen_loc: lparen_loc, rparen_loc: rparen_loc, location: location } end # def operator: () -> String def operator operator_loc.slice end # def lparen: () -> String def lparen lparen_loc.slice end # def rparen: () -> String def rparen rparen_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── expression:\n" inspector << inspector.child_node(expression, "│ ") inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n" inspector << "├── lparen_loc: #{inspector.location(lparen_loc)}\n" inspector << "└── rparen_loc: #{inspector.location(rparen_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :pinned_expression_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :pinned_expression_node end end # Represents the use of the `^` operator for pinning a variable in a pattern # matching expression. # # foo in ^bar # ^^^^ class PinnedVariableNode < Node # attr_reader variable: Node attr_reader :variable # attr_reader operator_loc: Location attr_reader :operator_loc # def initialize: (variable: Node, operator_loc: Location, location: Location) -> void def initialize(variable, operator_loc, location) @variable = variable @operator_loc = operator_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_pinned_variable_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [variable] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [variable] end # def comment_targets: () -> Array[Node | Location] def comment_targets [variable, operator_loc] end # def copy: (**params) -> PinnedVariableNode def copy(**params) PinnedVariableNode.new( params.fetch(:variable) { variable }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { variable: variable, operator_loc: operator_loc, location: location } end # def operator: () -> String def operator operator_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── variable:\n" inspector << inspector.child_node(variable, "│ ") inspector << "└── operator_loc: #{inspector.location(operator_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :pinned_variable_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :pinned_variable_node end end # Represents the use of the `END` keyword. # # END { foo } # ^^^^^^^^^^^ class PostExecutionNode < Node # attr_reader statements: StatementsNode? attr_reader :statements # attr_reader keyword_loc: Location attr_reader :keyword_loc # attr_reader opening_loc: Location attr_reader :opening_loc # attr_reader closing_loc: Location attr_reader :closing_loc # def initialize: (statements: StatementsNode?, keyword_loc: Location, opening_loc: Location, closing_loc: Location, location: Location) -> void def initialize(statements, keyword_loc, opening_loc, closing_loc, location) @statements = statements @keyword_loc = keyword_loc @opening_loc = opening_loc @closing_loc = closing_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_post_execution_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [statements] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact << statements if statements compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [*statements, keyword_loc, opening_loc, closing_loc] end # def copy: (**params) -> PostExecutionNode def copy(**params) PostExecutionNode.new( params.fetch(:statements) { statements }, params.fetch(:keyword_loc) { keyword_loc }, params.fetch(:opening_loc) { opening_loc }, params.fetch(:closing_loc) { closing_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { statements: statements, keyword_loc: keyword_loc, opening_loc: opening_loc, closing_loc: closing_loc, location: location } end # def keyword: () -> String def keyword keyword_loc.slice end # def opening: () -> String def opening opening_loc.slice end # def closing: () -> String def closing closing_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) if (statements = self.statements).nil? inspector << "├── statements: ∅\n" else inspector << "├── statements:\n" inspector << statements.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "├── keyword_loc: #{inspector.location(keyword_loc)}\n" inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n" inspector << "└── closing_loc: #{inspector.location(closing_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :post_execution_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :post_execution_node end end # Represents the use of the `BEGIN` keyword. # # BEGIN { foo } # ^^^^^^^^^^^^^ class PreExecutionNode < Node # attr_reader statements: StatementsNode? attr_reader :statements # attr_reader keyword_loc: Location attr_reader :keyword_loc # attr_reader opening_loc: Location attr_reader :opening_loc # attr_reader closing_loc: Location attr_reader :closing_loc # def initialize: (statements: StatementsNode?, keyword_loc: Location, opening_loc: Location, closing_loc: Location, location: Location) -> void def initialize(statements, keyword_loc, opening_loc, closing_loc, location) @statements = statements @keyword_loc = keyword_loc @opening_loc = opening_loc @closing_loc = closing_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_pre_execution_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [statements] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact << statements if statements compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [*statements, keyword_loc, opening_loc, closing_loc] end # def copy: (**params) -> PreExecutionNode def copy(**params) PreExecutionNode.new( params.fetch(:statements) { statements }, params.fetch(:keyword_loc) { keyword_loc }, params.fetch(:opening_loc) { opening_loc }, params.fetch(:closing_loc) { closing_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { statements: statements, keyword_loc: keyword_loc, opening_loc: opening_loc, closing_loc: closing_loc, location: location } end # def keyword: () -> String def keyword keyword_loc.slice end # def opening: () -> String def opening opening_loc.slice end # def closing: () -> String def closing closing_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) if (statements = self.statements).nil? inspector << "├── statements: ∅\n" else inspector << "├── statements:\n" inspector << statements.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "├── keyword_loc: #{inspector.location(keyword_loc)}\n" inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n" inspector << "└── closing_loc: #{inspector.location(closing_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :pre_execution_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :pre_execution_node end end # The top level node of any parse tree. class ProgramNode < Node # attr_reader locals: Array[Symbol] attr_reader :locals # attr_reader statements: StatementsNode attr_reader :statements # def initialize: (locals: Array[Symbol], statements: StatementsNode, location: Location) -> void def initialize(locals, statements, location) @locals = locals @statements = statements @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_program_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [statements] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [statements] end # def comment_targets: () -> Array[Node | Location] def comment_targets [statements] end # def copy: (**params) -> ProgramNode def copy(**params) ProgramNode.new( params.fetch(:locals) { locals }, params.fetch(:statements) { statements }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { locals: locals, statements: statements, location: location } end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── locals: #{locals.inspect}\n" inspector << "└── statements:\n" inspector << inspector.child_node(statements, " ") inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :program_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :program_node end end # Represents the use of the `..` or `...` operators. # # 1..2 # ^^^^ # # c if a =~ /left/ ... b =~ /right/ # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ class RangeNode < Node # attr_reader flags: Integer private attr_reader :flags # attr_reader left: Node? attr_reader :left # attr_reader right: Node? attr_reader :right # attr_reader operator_loc: Location attr_reader :operator_loc # def initialize: (flags: Integer, left: Node?, right: Node?, operator_loc: Location, location: Location) -> void def initialize(flags, left, right, operator_loc, location) @flags = flags @left = left @right = right @operator_loc = operator_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_range_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [left, right] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact << left if left compact << right if right compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [*left, *right, operator_loc] end # def copy: (**params) -> RangeNode def copy(**params) RangeNode.new( params.fetch(:flags) { flags }, params.fetch(:left) { left }, params.fetch(:right) { right }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { flags: flags, left: left, right: right, operator_loc: operator_loc, location: location } end # def exclude_end?: () -> bool def exclude_end? flags.anybits?(RangeFlags::EXCLUDE_END) end # def operator: () -> String def operator operator_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) flags = [("exclude_end" if exclude_end?)].compact inspector << "├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n" if (left = self.left).nil? inspector << "├── left: ∅\n" else inspector << "├── left:\n" inspector << left.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end if (right = self.right).nil? inspector << "├── right: ∅\n" else inspector << "├── right:\n" inspector << right.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "└── operator_loc: #{inspector.location(operator_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :range_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :range_node end end # Represents a rational number literal. # # 1.0r # ^^^^ class RationalNode < Node # attr_reader numeric: Node attr_reader :numeric # def initialize: (numeric: Node, location: Location) -> void def initialize(numeric, location) @numeric = numeric @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_rational_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [numeric] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [numeric] end # def comment_targets: () -> Array[Node | Location] def comment_targets [numeric] end # def copy: (**params) -> RationalNode def copy(**params) RationalNode.new( params.fetch(:numeric) { numeric }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { numeric: numeric, location: location } end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "└── numeric:\n" inspector << inspector.child_node(numeric, " ") inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :rational_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :rational_node end end # Represents the use of the `redo` keyword. # # redo # ^^^^ class RedoNode < Node # def initialize: (location: Location) -> void def initialize(location) @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_redo_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [] end # def comment_targets: () -> Array[Node | Location] def comment_targets [] end # def copy: (**params) -> RedoNode def copy(**params) RedoNode.new( params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { location: location } end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :redo_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :redo_node end end # Represents a regular expression literal with no interpolation. # # /foo/i # ^^^^^^ class RegularExpressionNode < Node # attr_reader flags: Integer private attr_reader :flags # attr_reader opening_loc: Location attr_reader :opening_loc # attr_reader content_loc: Location attr_reader :content_loc # attr_reader closing_loc: Location attr_reader :closing_loc # attr_reader unescaped: String attr_reader :unescaped # def initialize: (flags: Integer, opening_loc: Location, content_loc: Location, closing_loc: Location, unescaped: String, location: Location) -> void def initialize(flags, opening_loc, content_loc, closing_loc, unescaped, location) @flags = flags @opening_loc = opening_loc @content_loc = content_loc @closing_loc = closing_loc @unescaped = unescaped @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_regular_expression_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [] end # def comment_targets: () -> Array[Node | Location] def comment_targets [opening_loc, content_loc, closing_loc] end # def copy: (**params) -> RegularExpressionNode def copy(**params) RegularExpressionNode.new( params.fetch(:flags) { flags }, params.fetch(:opening_loc) { opening_loc }, params.fetch(:content_loc) { content_loc }, params.fetch(:closing_loc) { closing_loc }, params.fetch(:unescaped) { unescaped }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { flags: flags, opening_loc: opening_loc, content_loc: content_loc, closing_loc: closing_loc, unescaped: unescaped, location: location } end # def ignore_case?: () -> bool def ignore_case? flags.anybits?(RegularExpressionFlags::IGNORE_CASE) end # def extended?: () -> bool def extended? flags.anybits?(RegularExpressionFlags::EXTENDED) end # def multi_line?: () -> bool def multi_line? flags.anybits?(RegularExpressionFlags::MULTI_LINE) end # def once?: () -> bool def once? flags.anybits?(RegularExpressionFlags::ONCE) end # def euc_jp?: () -> bool def euc_jp? flags.anybits?(RegularExpressionFlags::EUC_JP) end # def ascii_8bit?: () -> bool def ascii_8bit? flags.anybits?(RegularExpressionFlags::ASCII_8BIT) end # def windows_31j?: () -> bool def windows_31j? flags.anybits?(RegularExpressionFlags::WINDOWS_31J) end # def utf_8?: () -> bool def utf_8? flags.anybits?(RegularExpressionFlags::UTF_8) end # def forced_utf8_encoding?: () -> bool def forced_utf8_encoding? flags.anybits?(RegularExpressionFlags::FORCED_UTF8_ENCODING) end # def forced_binary_encoding?: () -> bool def forced_binary_encoding? flags.anybits?(RegularExpressionFlags::FORCED_BINARY_ENCODING) end # def forced_us_ascii_encoding?: () -> bool def forced_us_ascii_encoding? flags.anybits?(RegularExpressionFlags::FORCED_US_ASCII_ENCODING) end # def opening: () -> String def opening opening_loc.slice end # def content: () -> String def content content_loc.slice end # def closing: () -> String def closing closing_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) flags = [("ignore_case" if ignore_case?), ("extended" if extended?), ("multi_line" if multi_line?), ("once" if once?), ("euc_jp" if euc_jp?), ("ascii_8bit" if ascii_8bit?), ("windows_31j" if windows_31j?), ("utf_8" if utf_8?), ("forced_utf8_encoding" if forced_utf8_encoding?), ("forced_binary_encoding" if forced_binary_encoding?), ("forced_us_ascii_encoding" if forced_us_ascii_encoding?)].compact inspector << "├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n" inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n" inspector << "├── content_loc: #{inspector.location(content_loc)}\n" inspector << "├── closing_loc: #{inspector.location(closing_loc)}\n" inspector << "└── unescaped: #{unescaped.inspect}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :regular_expression_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :regular_expression_node end end # Represents a required keyword parameter to a method, block, or lambda definition. # # def a(b: ) # ^^ # end class RequiredKeywordParameterNode < Node # attr_reader name: Symbol attr_reader :name # attr_reader name_loc: Location attr_reader :name_loc # def initialize: (name: Symbol, name_loc: Location, location: Location) -> void def initialize(name, name_loc, location) @name = name @name_loc = name_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_required_keyword_parameter_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [] end # def comment_targets: () -> Array[Node | Location] def comment_targets [name_loc] end # def copy: (**params) -> RequiredKeywordParameterNode def copy(**params) RequiredKeywordParameterNode.new( params.fetch(:name) { name }, params.fetch(:name_loc) { name_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { name: name, name_loc: name_loc, location: location } end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── name: #{name.inspect}\n" inspector << "└── name_loc: #{inspector.location(name_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :required_keyword_parameter_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :required_keyword_parameter_node end end # Represents a required parameter to a method, block, or lambda definition. # # def a(b) # ^ # end class RequiredParameterNode < Node # attr_reader name: Symbol attr_reader :name # def initialize: (name: Symbol, location: Location) -> void def initialize(name, location) @name = name @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_required_parameter_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [] end # def comment_targets: () -> Array[Node | Location] def comment_targets [] end # def copy: (**params) -> RequiredParameterNode def copy(**params) RequiredParameterNode.new( params.fetch(:name) { name }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { name: name, location: location } end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "└── name: #{name.inspect}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :required_parameter_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :required_parameter_node end end # Represents an expression modified with a rescue. # # foo rescue nil # ^^^^^^^^^^^^^^ class RescueModifierNode < Node # attr_reader expression: Node attr_reader :expression # attr_reader keyword_loc: Location attr_reader :keyword_loc # attr_reader rescue_expression: Node attr_reader :rescue_expression # def initialize: (expression: Node, keyword_loc: Location, rescue_expression: Node, location: Location) -> void def initialize(expression, keyword_loc, rescue_expression, location) @expression = expression @keyword_loc = keyword_loc @rescue_expression = rescue_expression @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_rescue_modifier_node(self) end def set_newline_flag(newline_marked) # :nodoc: expression.set_newline_flag(newline_marked) end # def child_nodes: () -> Array[nil | Node] def child_nodes [expression, rescue_expression] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [expression, rescue_expression] end # def comment_targets: () -> Array[Node | Location] def comment_targets [expression, keyword_loc, rescue_expression] end # def copy: (**params) -> RescueModifierNode def copy(**params) RescueModifierNode.new( params.fetch(:expression) { expression }, params.fetch(:keyword_loc) { keyword_loc }, params.fetch(:rescue_expression) { rescue_expression }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { expression: expression, keyword_loc: keyword_loc, rescue_expression: rescue_expression, location: location } end # def keyword: () -> String def keyword keyword_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── expression:\n" inspector << inspector.child_node(expression, "│ ") inspector << "├── keyword_loc: #{inspector.location(keyword_loc)}\n" inspector << "└── rescue_expression:\n" inspector << inspector.child_node(rescue_expression, " ") inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :rescue_modifier_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :rescue_modifier_node end end # Represents a rescue statement. # # begin # rescue Foo, *splat, Bar => ex # foo # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ # end # # `Foo, *splat, Bar` are in the `exceptions` field. # `ex` is in the `exception` field. class RescueNode < Node # attr_reader keyword_loc: Location attr_reader :keyword_loc # attr_reader exceptions: Array[Node] attr_reader :exceptions # attr_reader operator_loc: Location? attr_reader :operator_loc # attr_reader reference: Node? attr_reader :reference # attr_reader statements: StatementsNode? attr_reader :statements # attr_reader consequent: RescueNode? attr_reader :consequent # def initialize: (keyword_loc: Location, exceptions: Array[Node], operator_loc: Location?, reference: Node?, statements: StatementsNode?, consequent: RescueNode?, location: Location) -> void def initialize(keyword_loc, exceptions, operator_loc, reference, statements, consequent, location) @keyword_loc = keyword_loc @exceptions = exceptions @operator_loc = operator_loc @reference = reference @statements = statements @consequent = consequent @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_rescue_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [*exceptions, reference, statements, consequent] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact.concat(exceptions) compact << reference if reference compact << statements if statements compact << consequent if consequent compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [keyword_loc, *exceptions, *operator_loc, *reference, *statements, *consequent] end # def copy: (**params) -> RescueNode def copy(**params) RescueNode.new( params.fetch(:keyword_loc) { keyword_loc }, params.fetch(:exceptions) { exceptions }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:reference) { reference }, params.fetch(:statements) { statements }, params.fetch(:consequent) { consequent }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { keyword_loc: keyword_loc, exceptions: exceptions, operator_loc: operator_loc, reference: reference, statements: statements, consequent: consequent, location: location } end # def keyword: () -> String def keyword keyword_loc.slice end # def operator: () -> String? def operator operator_loc&.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── keyword_loc: #{inspector.location(keyword_loc)}\n" inspector << "├── exceptions: #{inspector.list("#{inspector.prefix}│ ", exceptions)}" inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n" if (reference = self.reference).nil? inspector << "├── reference: ∅\n" else inspector << "├── reference:\n" inspector << reference.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end if (statements = self.statements).nil? inspector << "├── statements: ∅\n" else inspector << "├── statements:\n" inspector << statements.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end if (consequent = self.consequent).nil? inspector << "└── consequent: ∅\n" else inspector << "└── consequent:\n" inspector << consequent.inspect(inspector.child_inspector(" ")).delete_prefix(inspector.prefix) end inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :rescue_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :rescue_node end end # Represents a rest parameter to a method, block, or lambda definition. # # def a(*b) # ^^ # end class RestParameterNode < Node # attr_reader name: Symbol? attr_reader :name # attr_reader name_loc: Location? attr_reader :name_loc # attr_reader operator_loc: Location attr_reader :operator_loc # def initialize: (name: Symbol?, name_loc: Location?, operator_loc: Location, location: Location) -> void def initialize(name, name_loc, operator_loc, location) @name = name @name_loc = name_loc @operator_loc = operator_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_rest_parameter_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [] end # def comment_targets: () -> Array[Node | Location] def comment_targets [*name_loc, operator_loc] end # def copy: (**params) -> RestParameterNode def copy(**params) RestParameterNode.new( params.fetch(:name) { name }, params.fetch(:name_loc) { name_loc }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { name: name, name_loc: name_loc, operator_loc: operator_loc, location: location } end # def operator: () -> String def operator operator_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) if (name = self.name).nil? inspector << "├── name: ∅\n" else inspector << "├── name: #{name.inspect}\n" end inspector << "├── name_loc: #{inspector.location(name_loc)}\n" inspector << "└── operator_loc: #{inspector.location(operator_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :rest_parameter_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :rest_parameter_node end end # Represents the use of the `retry` keyword. # # retry # ^^^^^ class RetryNode < Node # def initialize: (location: Location) -> void def initialize(location) @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_retry_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [] end # def comment_targets: () -> Array[Node | Location] def comment_targets [] end # def copy: (**params) -> RetryNode def copy(**params) RetryNode.new( params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { location: location } end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :retry_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :retry_node end end # Represents the use of the `return` keyword. # # return 1 # ^^^^^^^^ class ReturnNode < Node # attr_reader keyword_loc: Location attr_reader :keyword_loc # attr_reader arguments: ArgumentsNode? attr_reader :arguments # def initialize: (keyword_loc: Location, arguments: ArgumentsNode?, location: Location) -> void def initialize(keyword_loc, arguments, location) @keyword_loc = keyword_loc @arguments = arguments @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_return_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [arguments] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact << arguments if arguments compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [keyword_loc, *arguments] end # def copy: (**params) -> ReturnNode def copy(**params) ReturnNode.new( params.fetch(:keyword_loc) { keyword_loc }, params.fetch(:arguments) { arguments }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { keyword_loc: keyword_loc, arguments: arguments, location: location } end # def keyword: () -> String def keyword keyword_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── keyword_loc: #{inspector.location(keyword_loc)}\n" if (arguments = self.arguments).nil? inspector << "└── arguments: ∅\n" else inspector << "└── arguments:\n" inspector << arguments.inspect(inspector.child_inspector(" ")).delete_prefix(inspector.prefix) end inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :return_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :return_node end end # Represents the `self` keyword. # # self # ^^^^ class SelfNode < Node # def initialize: (location: Location) -> void def initialize(location) @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_self_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [] end # def comment_targets: () -> Array[Node | Location] def comment_targets [] end # def copy: (**params) -> SelfNode def copy(**params) SelfNode.new( params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { location: location } end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :self_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :self_node end end # Represents a singleton class declaration involving the `class` keyword. # # class << self end # ^^^^^^^^^^^^^^^^^ class SingletonClassNode < Node # attr_reader locals: Array[Symbol] attr_reader :locals # attr_reader class_keyword_loc: Location attr_reader :class_keyword_loc # attr_reader operator_loc: Location attr_reader :operator_loc # attr_reader expression: Node attr_reader :expression # attr_reader body: Node? attr_reader :body # attr_reader end_keyword_loc: Location attr_reader :end_keyword_loc # def initialize: (locals: Array[Symbol], class_keyword_loc: Location, operator_loc: Location, expression: Node, body: Node?, end_keyword_loc: Location, location: Location) -> void def initialize(locals, class_keyword_loc, operator_loc, expression, body, end_keyword_loc, location) @locals = locals @class_keyword_loc = class_keyword_loc @operator_loc = operator_loc @expression = expression @body = body @end_keyword_loc = end_keyword_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_singleton_class_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [expression, body] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact << expression compact << body if body compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [class_keyword_loc, operator_loc, expression, *body, end_keyword_loc] end # def copy: (**params) -> SingletonClassNode def copy(**params) SingletonClassNode.new( params.fetch(:locals) { locals }, params.fetch(:class_keyword_loc) { class_keyword_loc }, params.fetch(:operator_loc) { operator_loc }, params.fetch(:expression) { expression }, params.fetch(:body) { body }, params.fetch(:end_keyword_loc) { end_keyword_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { locals: locals, class_keyword_loc: class_keyword_loc, operator_loc: operator_loc, expression: expression, body: body, end_keyword_loc: end_keyword_loc, location: location } end # def class_keyword: () -> String def class_keyword class_keyword_loc.slice end # def operator: () -> String def operator operator_loc.slice end # def end_keyword: () -> String def end_keyword end_keyword_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── locals: #{locals.inspect}\n" inspector << "├── class_keyword_loc: #{inspector.location(class_keyword_loc)}\n" inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n" inspector << "├── expression:\n" inspector << inspector.child_node(expression, "│ ") if (body = self.body).nil? inspector << "├── body: ∅\n" else inspector << "├── body:\n" inspector << body.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "└── end_keyword_loc: #{inspector.location(end_keyword_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :singleton_class_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :singleton_class_node end end # Represents the use of the `__ENCODING__` keyword. # # __ENCODING__ # ^^^^^^^^^^^^ class SourceEncodingNode < Node # def initialize: (location: Location) -> void def initialize(location) @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_source_encoding_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [] end # def comment_targets: () -> Array[Node | Location] def comment_targets [] end # def copy: (**params) -> SourceEncodingNode def copy(**params) SourceEncodingNode.new( params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { location: location } end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :source_encoding_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :source_encoding_node end end # Represents the use of the `__FILE__` keyword. # # __FILE__ # ^^^^^^^^ class SourceFileNode < Node # attr_reader filepath: String attr_reader :filepath # def initialize: (filepath: String, location: Location) -> void def initialize(filepath, location) @filepath = filepath @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_source_file_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [] end # def comment_targets: () -> Array[Node | Location] def comment_targets [] end # def copy: (**params) -> SourceFileNode def copy(**params) SourceFileNode.new( params.fetch(:filepath) { filepath }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { filepath: filepath, location: location } end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "└── filepath: #{filepath.inspect}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :source_file_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :source_file_node end end # Represents the use of the `__LINE__` keyword. # # __LINE__ # ^^^^^^^^ class SourceLineNode < Node # def initialize: (location: Location) -> void def initialize(location) @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_source_line_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [] end # def comment_targets: () -> Array[Node | Location] def comment_targets [] end # def copy: (**params) -> SourceLineNode def copy(**params) SourceLineNode.new( params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { location: location } end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :source_line_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :source_line_node end end # Represents the use of the splat operator. # # [*a] # ^^ class SplatNode < Node # attr_reader operator_loc: Location attr_reader :operator_loc # attr_reader expression: Node? attr_reader :expression # def initialize: (operator_loc: Location, expression: Node?, location: Location) -> void def initialize(operator_loc, expression, location) @operator_loc = operator_loc @expression = expression @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_splat_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [expression] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact << expression if expression compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [operator_loc, *expression] end # def copy: (**params) -> SplatNode def copy(**params) SplatNode.new( params.fetch(:operator_loc) { operator_loc }, params.fetch(:expression) { expression }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { operator_loc: operator_loc, expression: expression, location: location } end # def operator: () -> String def operator operator_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── operator_loc: #{inspector.location(operator_loc)}\n" if (expression = self.expression).nil? inspector << "└── expression: ∅\n" else inspector << "└── expression:\n" inspector << expression.inspect(inspector.child_inspector(" ")).delete_prefix(inspector.prefix) end inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :splat_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :splat_node end end # Represents a set of statements contained within some scope. # # foo; bar; baz # ^^^^^^^^^^^^^ class StatementsNode < Node # attr_reader body: Array[Node] attr_reader :body # def initialize: (body: Array[Node], location: Location) -> void def initialize(body, location) @body = body @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_statements_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [*body] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [*body] end # def comment_targets: () -> Array[Node | Location] def comment_targets [*body] end # def copy: (**params) -> StatementsNode def copy(**params) StatementsNode.new( params.fetch(:body) { body }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { body: body, location: location } end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "└── body: #{inspector.list("#{inspector.prefix} ", body)}" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :statements_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :statements_node end end # Represents a string literal, a string contained within a `%w` list, or # plain string content within an interpolated string. # # "foo" # ^^^^^ # # %w[foo] # ^^^ # # "foo #{bar} baz" # ^^^^ ^^^^ class StringNode < Node # attr_reader flags: Integer private attr_reader :flags # attr_reader opening_loc: Location? attr_reader :opening_loc # attr_reader content_loc: Location attr_reader :content_loc # attr_reader closing_loc: Location? attr_reader :closing_loc # attr_reader unescaped: String attr_reader :unescaped # def initialize: (flags: Integer, opening_loc: Location?, content_loc: Location, closing_loc: Location?, unescaped: String, location: Location) -> void def initialize(flags, opening_loc, content_loc, closing_loc, unescaped, location) @flags = flags @opening_loc = opening_loc @content_loc = content_loc @closing_loc = closing_loc @unescaped = unescaped @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_string_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [] end # def comment_targets: () -> Array[Node | Location] def comment_targets [*opening_loc, content_loc, *closing_loc] end # def copy: (**params) -> StringNode def copy(**params) StringNode.new( params.fetch(:flags) { flags }, params.fetch(:opening_loc) { opening_loc }, params.fetch(:content_loc) { content_loc }, params.fetch(:closing_loc) { closing_loc }, params.fetch(:unescaped) { unescaped }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { flags: flags, opening_loc: opening_loc, content_loc: content_loc, closing_loc: closing_loc, unescaped: unescaped, location: location } end # def forced_utf8_encoding?: () -> bool def forced_utf8_encoding? flags.anybits?(StringFlags::FORCED_UTF8_ENCODING) end # def forced_binary_encoding?: () -> bool def forced_binary_encoding? flags.anybits?(StringFlags::FORCED_BINARY_ENCODING) end # def frozen?: () -> bool def frozen? flags.anybits?(StringFlags::FROZEN) end # def opening: () -> String? def opening opening_loc&.slice end # def content: () -> String def content content_loc.slice end # def closing: () -> String? def closing closing_loc&.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) flags = [("forced_utf8_encoding" if forced_utf8_encoding?), ("forced_binary_encoding" if forced_binary_encoding?), ("frozen" if frozen?)].compact inspector << "├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n" inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n" inspector << "├── content_loc: #{inspector.location(content_loc)}\n" inspector << "├── closing_loc: #{inspector.location(closing_loc)}\n" inspector << "└── unescaped: #{unescaped.inspect}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :string_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :string_node end end # Represents the use of the `super` keyword with parentheses or arguments. # # super() # ^^^^^^^ # # super foo, bar # ^^^^^^^^^^^^^^ class SuperNode < Node # attr_reader keyword_loc: Location attr_reader :keyword_loc # attr_reader lparen_loc: Location? attr_reader :lparen_loc # attr_reader arguments: ArgumentsNode? attr_reader :arguments # attr_reader rparen_loc: Location? attr_reader :rparen_loc # attr_reader block: Node? attr_reader :block # def initialize: (keyword_loc: Location, lparen_loc: Location?, arguments: ArgumentsNode?, rparen_loc: Location?, block: Node?, location: Location) -> void def initialize(keyword_loc, lparen_loc, arguments, rparen_loc, block, location) @keyword_loc = keyword_loc @lparen_loc = lparen_loc @arguments = arguments @rparen_loc = rparen_loc @block = block @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_super_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [arguments, block] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact << arguments if arguments compact << block if block compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [keyword_loc, *lparen_loc, *arguments, *rparen_loc, *block] end # def copy: (**params) -> SuperNode def copy(**params) SuperNode.new( params.fetch(:keyword_loc) { keyword_loc }, params.fetch(:lparen_loc) { lparen_loc }, params.fetch(:arguments) { arguments }, params.fetch(:rparen_loc) { rparen_loc }, params.fetch(:block) { block }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { keyword_loc: keyword_loc, lparen_loc: lparen_loc, arguments: arguments, rparen_loc: rparen_loc, block: block, location: location } end # def keyword: () -> String def keyword keyword_loc.slice end # def lparen: () -> String? def lparen lparen_loc&.slice end # def rparen: () -> String? def rparen rparen_loc&.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── keyword_loc: #{inspector.location(keyword_loc)}\n" inspector << "├── lparen_loc: #{inspector.location(lparen_loc)}\n" if (arguments = self.arguments).nil? inspector << "├── arguments: ∅\n" else inspector << "├── arguments:\n" inspector << arguments.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "├── rparen_loc: #{inspector.location(rparen_loc)}\n" if (block = self.block).nil? inspector << "└── block: ∅\n" else inspector << "└── block:\n" inspector << block.inspect(inspector.child_inspector(" ")).delete_prefix(inspector.prefix) end inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :super_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :super_node end end # Represents a symbol literal or a symbol contained within a `%i` list. # # :foo # ^^^^ # # %i[foo] # ^^^ class SymbolNode < Node # attr_reader flags: Integer private attr_reader :flags # attr_reader opening_loc: Location? attr_reader :opening_loc # attr_reader value_loc: Location? attr_reader :value_loc # attr_reader closing_loc: Location? attr_reader :closing_loc # attr_reader unescaped: String attr_reader :unescaped # def initialize: (flags: Integer, opening_loc: Location?, value_loc: Location?, closing_loc: Location?, unescaped: String, location: Location) -> void def initialize(flags, opening_loc, value_loc, closing_loc, unescaped, location) @flags = flags @opening_loc = opening_loc @value_loc = value_loc @closing_loc = closing_loc @unescaped = unescaped @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_symbol_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [] end # def comment_targets: () -> Array[Node | Location] def comment_targets [*opening_loc, *value_loc, *closing_loc] end # def copy: (**params) -> SymbolNode def copy(**params) SymbolNode.new( params.fetch(:flags) { flags }, params.fetch(:opening_loc) { opening_loc }, params.fetch(:value_loc) { value_loc }, params.fetch(:closing_loc) { closing_loc }, params.fetch(:unescaped) { unescaped }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { flags: flags, opening_loc: opening_loc, value_loc: value_loc, closing_loc: closing_loc, unescaped: unescaped, location: location } end # def forced_utf8_encoding?: () -> bool def forced_utf8_encoding? flags.anybits?(SymbolFlags::FORCED_UTF8_ENCODING) end # def forced_binary_encoding?: () -> bool def forced_binary_encoding? flags.anybits?(SymbolFlags::FORCED_BINARY_ENCODING) end # def forced_us_ascii_encoding?: () -> bool def forced_us_ascii_encoding? flags.anybits?(SymbolFlags::FORCED_US_ASCII_ENCODING) end # def opening: () -> String? def opening opening_loc&.slice end # def value: () -> String? def value value_loc&.slice end # def closing: () -> String? def closing closing_loc&.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) flags = [("forced_utf8_encoding" if forced_utf8_encoding?), ("forced_binary_encoding" if forced_binary_encoding?), ("forced_us_ascii_encoding" if forced_us_ascii_encoding?)].compact inspector << "├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n" inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n" inspector << "├── value_loc: #{inspector.location(value_loc)}\n" inspector << "├── closing_loc: #{inspector.location(closing_loc)}\n" inspector << "└── unescaped: #{unescaped.inspect}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :symbol_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :symbol_node end end # Represents the use of the literal `true` keyword. # # true # ^^^^ class TrueNode < Node # def initialize: (location: Location) -> void def initialize(location) @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_true_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [] end # def comment_targets: () -> Array[Node | Location] def comment_targets [] end # def copy: (**params) -> TrueNode def copy(**params) TrueNode.new( params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { location: location } end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :true_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :true_node end end # Represents the use of the `undef` keyword. # # undef :foo, :bar, :baz # ^^^^^^^^^^^^^^^^^^^^^^ class UndefNode < Node # attr_reader names: Array[Node] attr_reader :names # attr_reader keyword_loc: Location attr_reader :keyword_loc # def initialize: (names: Array[Node], keyword_loc: Location, location: Location) -> void def initialize(names, keyword_loc, location) @names = names @keyword_loc = keyword_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_undef_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [*names] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [*names] end # def comment_targets: () -> Array[Node | Location] def comment_targets [*names, keyword_loc] end # def copy: (**params) -> UndefNode def copy(**params) UndefNode.new( params.fetch(:names) { names }, params.fetch(:keyword_loc) { keyword_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { names: names, keyword_loc: keyword_loc, location: location } end # def keyword: () -> String def keyword keyword_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── names: #{inspector.list("#{inspector.prefix}│ ", names)}" inspector << "└── keyword_loc: #{inspector.location(keyword_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :undef_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :undef_node end end # Represents the use of the `unless` keyword, either in the block form or the modifier form. # # bar unless foo # ^^^^^^^^^^^^^^ # # unless foo then bar end # ^^^^^^^^^^^^^^^^^^^^^^^ class UnlessNode < Node # attr_reader keyword_loc: Location attr_reader :keyword_loc # attr_reader predicate: Node attr_reader :predicate # attr_reader then_keyword_loc: Location? attr_reader :then_keyword_loc # attr_reader statements: StatementsNode? attr_reader :statements # attr_reader consequent: ElseNode? attr_reader :consequent # attr_reader end_keyword_loc: Location? attr_reader :end_keyword_loc # def initialize: (keyword_loc: Location, predicate: Node, then_keyword_loc: Location?, statements: StatementsNode?, consequent: ElseNode?, end_keyword_loc: Location?, location: Location) -> void def initialize(keyword_loc, predicate, then_keyword_loc, statements, consequent, end_keyword_loc, location) @keyword_loc = keyword_loc @predicate = predicate @then_keyword_loc = then_keyword_loc @statements = statements @consequent = consequent @end_keyword_loc = end_keyword_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_unless_node(self) end def set_newline_flag(newline_marked) # :nodoc: predicate.set_newline_flag(newline_marked) end # def child_nodes: () -> Array[nil | Node] def child_nodes [predicate, statements, consequent] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact << predicate compact << statements if statements compact << consequent if consequent compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [keyword_loc, predicate, *then_keyword_loc, *statements, *consequent, *end_keyword_loc] end # def copy: (**params) -> UnlessNode def copy(**params) UnlessNode.new( params.fetch(:keyword_loc) { keyword_loc }, params.fetch(:predicate) { predicate }, params.fetch(:then_keyword_loc) { then_keyword_loc }, params.fetch(:statements) { statements }, params.fetch(:consequent) { consequent }, params.fetch(:end_keyword_loc) { end_keyword_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { keyword_loc: keyword_loc, predicate: predicate, then_keyword_loc: then_keyword_loc, statements: statements, consequent: consequent, end_keyword_loc: end_keyword_loc, location: location } end # def keyword: () -> String def keyword keyword_loc.slice end # def then_keyword: () -> String? def then_keyword then_keyword_loc&.slice end # def end_keyword: () -> String? def end_keyword end_keyword_loc&.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── keyword_loc: #{inspector.location(keyword_loc)}\n" inspector << "├── predicate:\n" inspector << inspector.child_node(predicate, "│ ") inspector << "├── then_keyword_loc: #{inspector.location(then_keyword_loc)}\n" if (statements = self.statements).nil? inspector << "├── statements: ∅\n" else inspector << "├── statements:\n" inspector << statements.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end if (consequent = self.consequent).nil? inspector << "├── consequent: ∅\n" else inspector << "├── consequent:\n" inspector << consequent.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "└── end_keyword_loc: #{inspector.location(end_keyword_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :unless_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :unless_node end end # Represents the use of the `until` keyword, either in the block form or the modifier form. # # bar until foo # ^^^^^^^^^^^^^ # # until foo do bar end # ^^^^^^^^^^^^^^^^^^^^ class UntilNode < Node # attr_reader flags: Integer private attr_reader :flags # attr_reader keyword_loc: Location attr_reader :keyword_loc # attr_reader closing_loc: Location? attr_reader :closing_loc # attr_reader predicate: Node attr_reader :predicate # attr_reader statements: StatementsNode? attr_reader :statements # def initialize: (flags: Integer, keyword_loc: Location, closing_loc: Location?, predicate: Node, statements: StatementsNode?, location: Location) -> void def initialize(flags, keyword_loc, closing_loc, predicate, statements, location) @flags = flags @keyword_loc = keyword_loc @closing_loc = closing_loc @predicate = predicate @statements = statements @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_until_node(self) end def set_newline_flag(newline_marked) # :nodoc: predicate.set_newline_flag(newline_marked) end # def child_nodes: () -> Array[nil | Node] def child_nodes [predicate, statements] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact << predicate compact << statements if statements compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [keyword_loc, *closing_loc, predicate, *statements] end # def copy: (**params) -> UntilNode def copy(**params) UntilNode.new( params.fetch(:flags) { flags }, params.fetch(:keyword_loc) { keyword_loc }, params.fetch(:closing_loc) { closing_loc }, params.fetch(:predicate) { predicate }, params.fetch(:statements) { statements }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { flags: flags, keyword_loc: keyword_loc, closing_loc: closing_loc, predicate: predicate, statements: statements, location: location } end # def begin_modifier?: () -> bool def begin_modifier? flags.anybits?(LoopFlags::BEGIN_MODIFIER) end # def keyword: () -> String def keyword keyword_loc.slice end # def closing: () -> String? def closing closing_loc&.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) flags = [("begin_modifier" if begin_modifier?)].compact inspector << "├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n" inspector << "├── keyword_loc: #{inspector.location(keyword_loc)}\n" inspector << "├── closing_loc: #{inspector.location(closing_loc)}\n" inspector << "├── predicate:\n" inspector << inspector.child_node(predicate, "│ ") if (statements = self.statements).nil? inspector << "└── statements: ∅\n" else inspector << "└── statements:\n" inspector << statements.inspect(inspector.child_inspector(" ")).delete_prefix(inspector.prefix) end inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :until_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :until_node end end # Represents the use of the `when` keyword within a case statement. # # case true # when true # ^^^^^^^^^ # end class WhenNode < Node # attr_reader keyword_loc: Location attr_reader :keyword_loc # attr_reader conditions: Array[Node] attr_reader :conditions # attr_reader statements: StatementsNode? attr_reader :statements # def initialize: (keyword_loc: Location, conditions: Array[Node], statements: StatementsNode?, location: Location) -> void def initialize(keyword_loc, conditions, statements, location) @keyword_loc = keyword_loc @conditions = conditions @statements = statements @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_when_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [*conditions, statements] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact.concat(conditions) compact << statements if statements compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [keyword_loc, *conditions, *statements] end # def copy: (**params) -> WhenNode def copy(**params) WhenNode.new( params.fetch(:keyword_loc) { keyword_loc }, params.fetch(:conditions) { conditions }, params.fetch(:statements) { statements }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { keyword_loc: keyword_loc, conditions: conditions, statements: statements, location: location } end # def keyword: () -> String def keyword keyword_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── keyword_loc: #{inspector.location(keyword_loc)}\n" inspector << "├── conditions: #{inspector.list("#{inspector.prefix}│ ", conditions)}" if (statements = self.statements).nil? inspector << "└── statements: ∅\n" else inspector << "└── statements:\n" inspector << statements.inspect(inspector.child_inspector(" ")).delete_prefix(inspector.prefix) end inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :when_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :when_node end end # Represents the use of the `while` keyword, either in the block form or the modifier form. # # bar while foo # ^^^^^^^^^^^^^ # # while foo do bar end # ^^^^^^^^^^^^^^^^^^^^ class WhileNode < Node # attr_reader flags: Integer private attr_reader :flags # attr_reader keyword_loc: Location attr_reader :keyword_loc # attr_reader closing_loc: Location? attr_reader :closing_loc # attr_reader predicate: Node attr_reader :predicate # attr_reader statements: StatementsNode? attr_reader :statements # def initialize: (flags: Integer, keyword_loc: Location, closing_loc: Location?, predicate: Node, statements: StatementsNode?, location: Location) -> void def initialize(flags, keyword_loc, closing_loc, predicate, statements, location) @flags = flags @keyword_loc = keyword_loc @closing_loc = closing_loc @predicate = predicate @statements = statements @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_while_node(self) end def set_newline_flag(newline_marked) # :nodoc: predicate.set_newline_flag(newline_marked) end # def child_nodes: () -> Array[nil | Node] def child_nodes [predicate, statements] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact << predicate compact << statements if statements compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [keyword_loc, *closing_loc, predicate, *statements] end # def copy: (**params) -> WhileNode def copy(**params) WhileNode.new( params.fetch(:flags) { flags }, params.fetch(:keyword_loc) { keyword_loc }, params.fetch(:closing_loc) { closing_loc }, params.fetch(:predicate) { predicate }, params.fetch(:statements) { statements }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { flags: flags, keyword_loc: keyword_loc, closing_loc: closing_loc, predicate: predicate, statements: statements, location: location } end # def begin_modifier?: () -> bool def begin_modifier? flags.anybits?(LoopFlags::BEGIN_MODIFIER) end # def keyword: () -> String def keyword keyword_loc.slice end # def closing: () -> String? def closing closing_loc&.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) flags = [("begin_modifier" if begin_modifier?)].compact inspector << "├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n" inspector << "├── keyword_loc: #{inspector.location(keyword_loc)}\n" inspector << "├── closing_loc: #{inspector.location(closing_loc)}\n" inspector << "├── predicate:\n" inspector << inspector.child_node(predicate, "│ ") if (statements = self.statements).nil? inspector << "└── statements: ∅\n" else inspector << "└── statements:\n" inspector << statements.inspect(inspector.child_inspector(" ")).delete_prefix(inspector.prefix) end inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :while_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :while_node end end # Represents an xstring literal with no interpolation. # # `foo` # ^^^^^ class XStringNode < Node # attr_reader flags: Integer private attr_reader :flags # attr_reader opening_loc: Location attr_reader :opening_loc # attr_reader content_loc: Location attr_reader :content_loc # attr_reader closing_loc: Location attr_reader :closing_loc # attr_reader unescaped: String attr_reader :unescaped # def initialize: (flags: Integer, opening_loc: Location, content_loc: Location, closing_loc: Location, unescaped: String, location: Location) -> void def initialize(flags, opening_loc, content_loc, closing_loc, unescaped, location) @flags = flags @opening_loc = opening_loc @content_loc = content_loc @closing_loc = closing_loc @unescaped = unescaped @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_x_string_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes [] end # def comment_targets: () -> Array[Node | Location] def comment_targets [opening_loc, content_loc, closing_loc] end # def copy: (**params) -> XStringNode def copy(**params) XStringNode.new( params.fetch(:flags) { flags }, params.fetch(:opening_loc) { opening_loc }, params.fetch(:content_loc) { content_loc }, params.fetch(:closing_loc) { closing_loc }, params.fetch(:unescaped) { unescaped }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { flags: flags, opening_loc: opening_loc, content_loc: content_loc, closing_loc: closing_loc, unescaped: unescaped, location: location } end # def forced_utf8_encoding?: () -> bool def forced_utf8_encoding? flags.anybits?(EncodingFlags::FORCED_UTF8_ENCODING) end # def forced_binary_encoding?: () -> bool def forced_binary_encoding? flags.anybits?(EncodingFlags::FORCED_BINARY_ENCODING) end # def opening: () -> String def opening opening_loc.slice end # def content: () -> String def content content_loc.slice end # def closing: () -> String def closing closing_loc.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) flags = [("forced_utf8_encoding" if forced_utf8_encoding?), ("forced_binary_encoding" if forced_binary_encoding?)].compact inspector << "├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n" inspector << "├── opening_loc: #{inspector.location(opening_loc)}\n" inspector << "├── content_loc: #{inspector.location(content_loc)}\n" inspector << "├── closing_loc: #{inspector.location(closing_loc)}\n" inspector << "└── unescaped: #{unescaped.inspect}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :x_string_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :x_string_node end end # Represents the use of the `yield` keyword. # # yield 1 # ^^^^^^^ class YieldNode < Node # attr_reader keyword_loc: Location attr_reader :keyword_loc # attr_reader lparen_loc: Location? attr_reader :lparen_loc # attr_reader arguments: ArgumentsNode? attr_reader :arguments # attr_reader rparen_loc: Location? attr_reader :rparen_loc # def initialize: (keyword_loc: Location, lparen_loc: Location?, arguments: ArgumentsNode?, rparen_loc: Location?, location: Location) -> void def initialize(keyword_loc, lparen_loc, arguments, rparen_loc, location) @keyword_loc = keyword_loc @lparen_loc = lparen_loc @arguments = arguments @rparen_loc = rparen_loc @location = location end # def accept: (visitor: Visitor) -> void def accept(visitor) visitor.visit_yield_node(self) end # def child_nodes: () -> Array[nil | Node] def child_nodes [arguments] end # def compact_child_nodes: () -> Array[Node] def compact_child_nodes compact = [] compact << arguments if arguments compact end # def comment_targets: () -> Array[Node | Location] def comment_targets [keyword_loc, *lparen_loc, *arguments, *rparen_loc] end # def copy: (**params) -> YieldNode def copy(**params) YieldNode.new( params.fetch(:keyword_loc) { keyword_loc }, params.fetch(:lparen_loc) { lparen_loc }, params.fetch(:arguments) { arguments }, params.fetch(:rparen_loc) { rparen_loc }, params.fetch(:location) { location }, ) end # def deconstruct: () -> Array[nil | Node] alias deconstruct child_nodes # def deconstruct_keys: (keys: Array[Symbol]) -> Hash[Symbol, nil | Node | Array[Node] | String | Token | Array[Token] | Location] def deconstruct_keys(keys) { keyword_loc: keyword_loc, lparen_loc: lparen_loc, arguments: arguments, rparen_loc: rparen_loc, location: location } end # def keyword: () -> String def keyword keyword_loc.slice end # def lparen: () -> String? def lparen lparen_loc&.slice end # def rparen: () -> String? def rparen rparen_loc&.slice end # def inspect(inspector: NodeInspector) -> String def inspect(inspector = NodeInspector.new) inspector << inspector.header(self) inspector << "├── keyword_loc: #{inspector.location(keyword_loc)}\n" inspector << "├── lparen_loc: #{inspector.location(lparen_loc)}\n" if (arguments = self.arguments).nil? inspector << "├── arguments: ∅\n" else inspector << "├── arguments:\n" inspector << arguments.inspect(inspector.child_inspector("│ ")).delete_prefix(inspector.prefix) end inspector << "└── rparen_loc: #{inspector.location(rparen_loc)}\n" inspector.to_str end # Sometimes you want to check an instance of a node against a list of # classes to see what kind of behavior to perform. Usually this is done by # calling `[cls1, cls2].include?(node.class)` or putting the node into a # case statement and doing `case node; when cls1; when cls2; end`. Both of # these approaches are relatively slow because of the constant lookups, # method calls, and/or array allocations. # # Instead, you can call #type, which will return to you a symbol that you # can use for comparison. This is faster than the other approaches because # it uses a single integer comparison, but also because if you're on CRuby # you can take advantage of the fact that case statements with all symbol # keys will use a jump table. # # def type: () -> Symbol def type :yield_node end # Similar to #type, this method returns a symbol that you can use for # splitting on the type of the node without having to do a long === chain. # Note that like #type, it will still be slower than using == for a single # class, but should be faster in a case statement or an array comparison. # # def self.type: () -> Symbol def self.type :yield_node end end # Flags for arguments nodes. module ArgumentsNodeFlags # if arguments contain keyword splat CONTAINS_KEYWORD_SPLAT = 1 << 0 end # Flags for array nodes. module ArrayNodeFlags # if array contains splat nodes CONTAINS_SPLAT = 1 << 0 end # Flags for call nodes. module CallNodeFlags # &. operator SAFE_NAVIGATION = 1 << 0 # a call that could have been a local variable VARIABLE_CALL = 1 << 1 # a call that is an attribute write, so the value being written should be returned ATTRIBUTE_WRITE = 1 << 2 end # Flags for nodes that have unescaped content. module EncodingFlags # internal bytes forced the encoding to UTF-8 FORCED_UTF8_ENCODING = 1 << 0 # internal bytes forced the encoding to binary FORCED_BINARY_ENCODING = 1 << 1 end # Flags for integer nodes that correspond to the base of the integer. module IntegerBaseFlags # 0b prefix BINARY = 1 << 0 # 0d or no prefix DECIMAL = 1 << 1 # 0o or 0 prefix OCTAL = 1 << 2 # 0x prefix HEXADECIMAL = 1 << 3 end # Flags for keyword hash nodes. module KeywordHashNodeFlags # a keyword hash which only has `AssocNode` elements all with static literal keys, which means the elements can be treated as keyword arguments STATIC_KEYS = 1 << 0 end # Flags for while and until loop nodes. module LoopFlags # a loop after a begin statement, so the body is executed first before the condition BEGIN_MODIFIER = 1 << 0 end # Flags for range and flip-flop nodes. module RangeFlags # ... operator EXCLUDE_END = 1 << 0 end # Flags for regular expression and match last line nodes. module RegularExpressionFlags # i - ignores the case of characters when matching IGNORE_CASE = 1 << 0 # x - ignores whitespace and allows comments in regular expressions EXTENDED = 1 << 1 # m - allows $ to match the end of lines within strings MULTI_LINE = 1 << 2 # o - only interpolates values into the regular expression once ONCE = 1 << 3 # e - forces the EUC-JP encoding EUC_JP = 1 << 4 # n - forces the ASCII-8BIT encoding ASCII_8BIT = 1 << 5 # s - forces the Windows-31J encoding WINDOWS_31J = 1 << 6 # u - forces the UTF-8 encoding UTF_8 = 1 << 7 # internal bytes forced the encoding to UTF-8 FORCED_UTF8_ENCODING = 1 << 8 # internal bytes forced the encoding to binary FORCED_BINARY_ENCODING = 1 << 9 # internal bytes forced the encoding to US-ASCII FORCED_US_ASCII_ENCODING = 1 << 10 end # Flags for string nodes. module StringFlags # internal bytes forced the encoding to UTF-8 FORCED_UTF8_ENCODING = 1 << 0 # internal bytes forced the encoding to binary FORCED_BINARY_ENCODING = 1 << 1 # frozen by virtue of a `frozen_string_literal` comment FROZEN = 1 << 2 end # Flags for symbol nodes. module SymbolFlags # internal bytes forced the encoding to UTF-8 FORCED_UTF8_ENCODING = 1 << 0 # internal bytes forced the encoding to binary FORCED_BINARY_ENCODING = 1 << 1 # internal bytes forced the encoding to US-ASCII FORCED_US_ASCII_ENCODING = 1 << 2 end end