diff options
| author | Jemma Issroff <jemmaissroff@gmail.com> | 2023-06-20 11:53:02 -0400 |
|---|---|---|
| committer | Takashi Kokubun <takashikkbn@gmail.com> | 2023-06-21 11:25:39 -0700 |
| commit | cc7f765f2c12a9ba050b0d95f9d85f3923c8d944 (patch) | |
| tree | 5b5c60c1950240900dc749773083324a0e39748a /lib | |
| parent | 08478fefca827276d68e33f2e6a5940c85957a51 (diff) | |
[Feature #19741] Sync all files in yarp
This commit is the initial sync of all files from ruby/yarp
into ruby/ruby. Notably, it does the following:
* Sync all ruby/yarp/lib/ files to ruby/ruby/lib/yarp
* Sync all ruby/yarp/src/ files to ruby/ruby/yarp/
* Sync all ruby/yarp/test/ files to ruby/ruby/test/yarp
Notes
Notes:
Merged: https://github.com/ruby/ruby/pull/7964
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/yarp.rb | 248 | ||||
| -rw-r--r-- | lib/yarp/language_server.rb | 166 | ||||
| -rw-r--r-- | lib/yarp/lex_compat.rb | 749 | ||||
| -rw-r--r-- | lib/yarp/node.rb | 6434 | ||||
| -rw-r--r-- | lib/yarp/pack.rb | 185 | ||||
| -rw-r--r-- | lib/yarp/ripper_compat.rb | 174 | ||||
| -rw-r--r-- | lib/yarp/serialize.rb | 367 |
7 files changed, 8323 insertions, 0 deletions
diff --git a/lib/yarp.rb b/lib/yarp.rb new file mode 100644 index 0000000000..dd790434cc --- /dev/null +++ b/lib/yarp.rb @@ -0,0 +1,248 @@ +# frozen_string_literal: true + +module YARP + # This represents a location in the source corresponding to a node or token. + class Location + attr_reader :start_offset, :length + + def initialize(start_offset, length) + @start_offset = start_offset + @length = length + end + + def end_offset + @start_offset + @length + end + + def deconstruct_keys(keys) + { start_offset: start_offset, end_offset: end_offset } + end + + def pretty_print(q) + q.text("(#{start_offset}...#{end_offset})") + end + + def ==(other) + other in Location[start_offset: ^(start_offset), end_offset: ^(end_offset)] + end + + def self.null + new(0, 0) + end + end + + # This represents a comment that was encountered during parsing. + class Comment + attr_reader :type, :location + + def initialize(type, location) + @type = type + @location = location + end + + def deconstruct_keys(keys) + { type: type, location: location } + end + end + + # This represents an error that was encountered during parsing. + class ParseError + attr_reader :message, :location + + def initialize(message, location) + @message = message + @location = location + end + + def deconstruct_keys(keys) + { message: message, location: location } + end + end + + # This represents a warning that was encountered during parsing. + class ParseWarning + attr_reader :message, :location + + def initialize(message, location) + @message = message + @location = location + end + + def deconstruct_keys(keys) + { message: message, location: location } + end + end + + # This represents the result of a call to ::parse or ::parse_file. It contains + # the AST, any comments that were encounters, and any errors that were + # encountered. + class ParseResult + attr_reader :value, :comments, :errors, :warnings + + def initialize(value, comments, errors, warnings) + @value = value + @comments = comments + @errors = errors + @warnings = warnings + end + + def deconstruct_keys(keys) + { value: value, comments: comments, errors: errors, warnings: warnings } + end + + def success? + errors.empty? + end + + def failure? + !success? + end + end + + # This represents a token from the Ruby source. + class Token + attr_reader :type, :value, :start_offset, :length + + def initialize(type, value, start_offset, length) + @type = type + @value = value + @start_offset = start_offset + @length = length + end + + def end_offset + @start_offset + @length + end + + def location + Location.new(@start_offset, @length) + end + + def deconstruct_keys(keys) + { type: type, value: value, location: location } + end + + def pretty_print(q) + q.group do + q.text(type.to_s) + self.location.pretty_print(q) + q.text("(") + q.nest(2) do + q.breakable("") + q.pp(value) + end + q.breakable("") + q.text(")") + end + end + + def ==(other) + other in Token[type: ^(type), value: ^(value)] + end + end + + # This represents a node in the tree. + class Node + attr_reader :start_offset, :length + + def end_offset + @start_offset + @length + end + + def location + Location.new(@start_offset, @length) + end + + def pretty_print(q) + q.group do + q.text(self.class.name.split("::").last) + self.location.pretty_print(q) + q.text("(") + q.nest(2) do + deconstructed = deconstruct_keys([]) + deconstructed.delete(:location) + + q.breakable("") + q.seplist(deconstructed, lambda { q.comma_breakable }, :each_value) { |value| q.pp(value) } + end + q.breakable("") + q.text(")") + end + end + end + + # A class that knows how to walk down the tree. None of the individual visit + # methods are implemented on this visitor, so it forces the consumer to + # implement each one that they need. For a default implementation that + # continues walking the tree, see the Visitor class. + class BasicVisitor + def visit(node) + node&.accept(self) + end + + def visit_all(nodes) + nodes.map { |node| visit(node) } + end + + def visit_child_nodes(node) + visit_all(node.child_nodes) + end + end + + # This lexes with the Ripper lex. It drops any space events but otherwise + # returns the same tokens. + # [raises SyntaxError] if the syntax in source is invalid + def self.lex_ripper(source) + previous = [] + results = [] + + Ripper.lex(source, raise_errors: true).each do |token| + case token[1] + when :on_sp + # skip + when :on_tstring_content + if previous[1] == :on_tstring_content && + (token[2].start_with?("\#$") || token[2].start_with?("\#@")) + previous[2] << token[2] + else + results << token + previous = token + end + when :on_words_sep + if previous[1] == :on_words_sep + previous[2] << token[2] + else + results << token + previous = token + end + else + results << token + previous = token + end + end + + results + end + + # Load the serialized AST using the source as a reference into a tree. + def self.load(source, serialized) + Serialize.load(source, serialized) + end + + def self.parse(source, filepath=nil) + _parse(source, filepath) + end +end + +require_relative "yarp/lex_compat" +require_relative "yarp/node" +require_relative "yarp/ripper_compat" +require_relative "yarp/serialize" +require_relative "yarp/pack" +require "yarp.so" + +module YARP + class << self + private :_parse + end +end diff --git a/lib/yarp/language_server.rb b/lib/yarp/language_server.rb new file mode 100644 index 0000000000..5a10d484a1 --- /dev/null +++ b/lib/yarp/language_server.rb @@ -0,0 +1,166 @@ +# frozen_string_literal: true + +require "cgi" +require "json" +require "uri" + +module YARP + # YARP additionally ships with a language server conforming to the + # language server protocol. It can be invoked by running the yarp-lsp + # bin script (bin/yarp-lsp) + class LanguageServer + GITHUB_TEMPLATE = <<~TEMPLATE + Reporting issue with error `%{error}`. + + ## Expected behavior + <!-- TODO: Briefly explain what the expected behavior should be on this example. --> + + ## Actual behavior + <!-- TODO: Describe here what actually happened. --> + + ## Steps to reproduce the problem + <!-- TODO: Describe how we can reproduce the problem. --> + + ## Additional information + <!-- TODO: Include any additional information, such as screenshots. --> + + TEMPLATE + + attr_reader :input, :output + + def initialize( + input: $stdin, + output: $stdout + ) + @input = input.binmode + @output = output.binmode + end + + # rubocop:disable Layout/LineLength + def run + store = + Hash.new do |hash, uri| + filepath = CGI.unescape(URI.parse(uri).path) + File.exist?(filepath) ? (hash[uri] = File.read(filepath)) : nil + end + + while (headers = input.gets("\r\n\r\n")) + source = input.read(headers[/Content-Length: (\d+)/i, 1].to_i) + request = JSON.parse(source, symbolize_names: true) + + # stree-ignore + case request + in { method: "initialize", id: } + store.clear + write(id: id, result: { capabilities: capabilities }) + in { method: "initialized" } + # ignored + in { method: "shutdown" } # tolerate missing ID to be a good citizen + store.clear + write(id: request[:id], result: {}) + in { method: "exit"} + return + in { method: "textDocument/didChange", params: { textDocument: { uri: }, contentChanges: [{ text: }, *] } } + store[uri] = text + in { method: "textDocument/didOpen", params: { textDocument: { uri:, text: } } } + store[uri] = text + in { method: "textDocument/didClose", params: { textDocument: { uri: } } } + store.delete(uri) + in { method: "textDocument/diagnostic", id:, params: { textDocument: { uri: } } } + contents = store[uri] + write(id: id, result: contents ? diagnostics(contents) : nil) + in { method: "textDocument/codeAction", id:, params: { textDocument: { uri: }, context: { diagnostics: }}} + contents = store[uri] + write(id: id, result: contents ? code_actions(contents, diagnostics) : nil) + in { method: %r{\$/.+} } + # ignored + end + end + end + # rubocop:enable Layout/LineLength + + private + + def capabilities + { + codeActionProvider: { + codeActionKinds: [ + 'quickfix', + ], + }, + diagnosticProvider: { + interFileDependencies: false, + workspaceDiagnostics: false, + }, + textDocumentSync: { + change: 1, + openClose: true + }, + } + end + + def code_actions(source, diagnostics) + diagnostics.map do |diagnostic| + message = diagnostic[:message] + issue_content = URI.encode_www_form_component(GITHUB_TEMPLATE % {error: message}) + issue_link = "https://github.com/ruby/yarp/issues/new?&labels=Bug&body=#{issue_content}" + + { + title: "Report incorrect error: `#{diagnostic[:message]}`", + kind: "quickfix", + diagnostics: [diagnostic], + command: { + title: "Report incorrect error", + command: "vscode.open", + arguments: [issue_link] + } + } + end + end + + def diagnostics(source) + offsets = Hash.new do |hash, key| + slice = source.byteslice(...key) + lineno = slice.count("\n") + + char = slice.length + newline = source.rindex("\n", [char - 1, 0].max) || -1 + hash[key] = { line: lineno, character: char - newline - 1 } + end + + parse_output = YARP.parse(source) + + { + kind: "full", + items: [ + *parse_output.errors.map do |error| + { + range: { + start: offsets[error.location.start_offset], + end: offsets[error.location.end_offset], + }, + message: error.message, + severity: 1, + } + end, + *parse_output.warnings.map do |warning| + { + range: { + start: offsets[warning.location.start_offset], + end: offsets[warning.location.end_offset], + }, + message: warning.message, + severity: 2, + } + end, + ] + } + end + + def write(value) + response = value.merge(jsonrpc: "2.0").to_json + output.print("Content-Length: #{response.bytesize}\r\n\r\n#{response}") + output.flush + end + end +end diff --git a/lib/yarp/lex_compat.rb b/lib/yarp/lex_compat.rb new file mode 100644 index 0000000000..a72f8c0aeb --- /dev/null +++ b/lib/yarp/lex_compat.rb @@ -0,0 +1,749 @@ +# frozen_string_literal: true + +require "delegate" + +module YARP + # This class is responsible for lexing the source using YARP and then + # converting those tokens to be compatible with Ripper. In the vast majority + # of cases, this is a one-to-one mapping of the token type. Everything else + # generally lines up. However, there are a few cases that require special + # handling. + class LexCompat + # This is a mapping of YARP token types to Ripper token types. This is a + # many-to-one mapping because we split up our token types, whereas Ripper + # tends to group them. + RIPPER = { + AMPERSAND: :on_op, + AMPERSAND_AMPERSAND: :on_op, + AMPERSAND_AMPERSAND_EQUAL: :on_op, + AMPERSAND_DOT: :on_op, + AMPERSAND_EQUAL: :on_op, + BACK_REFERENCE: :on_backref, + BACKTICK: :on_backtick, + BANG: :on_op, + BANG_EQUAL: :on_op, + BANG_TILDE: :on_op, + BRACE_LEFT: :on_lbrace, + BRACE_RIGHT: :on_rbrace, + BRACKET_LEFT: :on_lbracket, + BRACKET_LEFT_ARRAY: :on_lbracket, + BRACKET_LEFT_RIGHT: :on_op, + BRACKET_LEFT_RIGHT_EQUAL: :on_op, + BRACKET_RIGHT: :on_rbracket, + CARET: :on_op, + CARET_EQUAL: :on_op, + CHARACTER_LITERAL: :on_CHAR, + CLASS_VARIABLE: :on_cvar, + COLON: :on_op, + COLON_COLON: :on_op, + COMMA: :on_comma, + COMMENT: :on_comment, + CONSTANT: :on_const, + DOT: :on_period, + DOT_DOT: :on_op, + DOT_DOT_DOT: :on_op, + EMBDOC_BEGIN: :on_embdoc_beg, + EMBDOC_END: :on_embdoc_end, + EMBDOC_LINE: :on_embdoc, + EMBEXPR_BEGIN: :on_embexpr_beg, + EMBEXPR_END: :on_embexpr_end, + EMBVAR: :on_embvar, + EOF: :on_eof, + EQUAL: :on_op, + EQUAL_EQUAL: :on_op, + EQUAL_EQUAL_EQUAL: :on_op, + EQUAL_GREATER: :on_op, + EQUAL_TILDE: :on_op, + FLOAT: :on_float, + GREATER: :on_op, + GREATER_EQUAL: :on_op, + GREATER_GREATER: :on_op, + GREATER_GREATER_EQUAL: :on_op, + GLOBAL_VARIABLE: :on_gvar, + HEREDOC_END: :on_heredoc_end, + HEREDOC_START: :on_heredoc_beg, + IDENTIFIER: :on_ident, + IGNORED_NEWLINE: :on_ignored_nl, + IMAGINARY_NUMBER: :on_imaginary, + INTEGER: :on_int, + INSTANCE_VARIABLE: :on_ivar, + INVALID: :INVALID, + KEYWORD___ENCODING__: :on_kw, + KEYWORD___LINE__: :on_kw, + KEYWORD___FILE__: :on_kw, + KEYWORD_ALIAS: :on_kw, + KEYWORD_AND: :on_kw, + KEYWORD_BEGIN: :on_kw, + KEYWORD_BEGIN_UPCASE: :on_kw, + KEYWORD_BREAK: :on_kw, + KEYWORD_CASE: :on_kw, + KEYWORD_CLASS: :on_kw, + KEYWORD_DEF: :on_kw, + KEYWORD_DEFINED: :on_kw, + KEYWORD_DO: :on_kw, + KEYWORD_DO_LOOP: :on_kw, + KEYWORD_ELSE: :on_kw, + KEYWORD_ELSIF: :on_kw, + KEYWORD_END: :on_kw, + KEYWORD_END_UPCASE: :on_kw, + KEYWORD_ENSURE: :on_kw, + KEYWORD_FALSE: :on_kw, + KEYWORD_FOR: :on_kw, + KEYWORD_IF: :on_kw, + KEYWORD_IF_MODIFIER: :on_kw, + KEYWORD_IN: :on_kw, + KEYWORD_MODULE: :on_kw, + KEYWORD_NEXT: :on_kw, + KEYWORD_NIL: :on_kw, + KEYWORD_NOT: :on_kw, + KEYWORD_OR: :on_kw, + KEYWORD_REDO: :on_kw, + KEYWORD_RESCUE: :on_kw, + KEYWORD_RESCUE_MODIFIER: :on_kw, + KEYWORD_RETRY: :on_kw, + KEYWORD_RETURN: :on_kw, + KEYWORD_SELF: :on_kw, + KEYWORD_SUPER: :on_kw, + KEYWORD_THEN: :on_kw, + KEYWORD_TRUE: :on_kw, + KEYWORD_UNDEF: :on_kw, + KEYWORD_UNLESS: :on_kw, + KEYWORD_UNLESS_MODIFIER: :on_kw, + KEYWORD_UNTIL: :on_kw, + KEYWORD_UNTIL_MODIFIER: :on_kw, + KEYWORD_WHEN: :on_kw, + KEYWORD_WHILE: :on_kw, + KEYWORD_WHILE_MODIFIER: :on_kw, + KEYWORD_YIELD: :on_kw, + LABEL: :on_label, + LABEL_END: :on_label_end, + LAMBDA_BEGIN: :on_tlambeg, + LESS: :on_op, + LESS_EQUAL: :on_op, + LESS_EQUAL_GREATER: :on_op, + LESS_LESS: :on_op, + LESS_LESS_EQUAL: :on_op, + MINUS: :on_op, + MINUS_EQUAL: :on_op, + MINUS_GREATER: :on_tlambda, + NEWLINE: :on_nl, + NUMBERED_REFERENCE: :on_backref, + PARENTHESIS_LEFT: :on_lparen, + PARENTHESIS_LEFT_PARENTHESES: :on_lparen, + PARENTHESIS_RIGHT: :on_rparen, + PERCENT: :on_op, + PERCENT_EQUAL: :on_op, + PERCENT_LOWER_I: :on_qsymbols_beg, + PERCENT_LOWER_W: :on_qwords_beg, + PERCENT_LOWER_X: :on_backtick, + PERCENT_UPPER_I: :on_symbols_beg, + PERCENT_UPPER_W: :on_words_beg, + PIPE: :on_op, + PIPE_EQUAL: :on_op, + PIPE_PIPE: :on_op, + PIPE_PIPE_EQUAL: :on_op, + PLUS: :on_op, + PLUS_EQUAL: :on_op, + QUESTION_MARK: :on_op, + RATIONAL_NUMBER: :on_rational, + REGEXP_BEGIN: :on_regexp_beg, + REGEXP_END: :on_regexp_end, + SEMICOLON: :on_semicolon, + SLASH: :on_op, + SLASH_EQUAL: :on_op, + STAR: :on_op, + STAR_EQUAL: :on_op, + STAR_STAR: :on_op, + STAR_STAR_EQUAL: :on_op, + STRING_BEGIN: :on_tstring_beg, + STRING_CONTENT: :on_tstring_content, + STRING_END: :on_tstring_end, + SYMBOL_BEGIN: :on_symbeg, + TILDE: :on_op, + UCOLON_COLON: :on_op, + UDOT_DOT: :on_op, + UDOT_DOT_DOT: :on_op, + UMINUS: :on_op, + UMINUS_NUM: :on_op, + UPLUS: :on_op, + USTAR: :on_op, + USTAR_STAR: :on_op, + WORDS_SEP: :on_words_sep, + __END__: :on___end__ + }.freeze + + # When we produce tokens, we produce the same arrays that Ripper does. + # However, we add a couple of convenience methods onto them to make them a + # little easier to work with. We delegate all other methods to the array. + class Token < SimpleDelegator + def location + self[0] + end + + def event + self[1] + end + + def value + self[2] + end + + def state + self[3] + end + end + + # Ripper doesn't include the rest of the token in the event, so we need to + # trim it down to just the content on the first line when comparing. + class EndContentToken < Token + def ==(other) + [self[0], self[1], self[2][0..self[2].index("\n")], self[3]] == other + end + end + + # It is extremely non obvious which state the parser is in when comments get + # dispatched. Because of this we don't both comparing state when comparing + # against other comment tokens. + class CommentToken < Token + def ==(other) + self[0...-1] == other[0...-1] + end + end + + # Heredoc end tokens are emitted in an odd order, so we don't compare the + # state on them. + class HeredocEndToken < Token + def ==(other) + self[0...-1] == other[0...-1] + end + end + + # Ident tokens for the most part are exactly the same, except sometimes we + # know an ident is a local when ripper doesn't (when they are introduced + # through named captures in regular expressions). In that case we don't + # compare the state. + class IdentToken < Token + def ==(other) + (self[0...-1] == other[0...-1]) && ( + (other[3] == Ripper::EXPR_LABEL | Ripper::EXPR_END) || + (other[3] & Ripper::EXPR_ARG_ANY != 0) + ) + end + end + + # Ignored newlines can occasionally have a LABEL state attached to them, so + # we compare the state differently here. + class IgnoredNewlineToken < Token + def ==(other) + return false unless self[0...-1] == other[0...-1] + + if self[4] == Ripper::EXPR_ARG | Ripper::EXPR_LABELED + other[4] & Ripper::EXPR_ARG | Ripper::EXPR_LABELED > 0 + else + self[4] == other[4] + end + end + end + + # A heredoc in this case is a list of tokens that belong to the body of the + # heredoc that should be appended onto the list of tokens when the heredoc + # closes. + module Heredoc + # Heredocs that are no dash or tilde heredocs are just a list of tokens. + # We need to keep them around so that we can insert them in the correct + # order back into the token stream and set the state of the last token to + # the state that the heredoc was opened in. + class PlainHeredoc + attr_reader :tokens + + def initialize + @tokens = [] + end + + def <<(token) + tokens << token + end + + def to_a + tokens + end + end + + # Dash heredocs are a little more complicated. They are a list of tokens + # that need to be split on "\\\n" to mimic Ripper's behavior. We also need + # to keep track of the state that the heredoc was opened in. + class DashHeredoc + attr_reader :split, :tokens + + def initialize(split) + @split = split + @tokens = [] + end + + def <<(token) + tokens << token + end + + def to_a + embexpr_balance = 0 + + tokens.each_with_object([]) do |token, results| + case token.event + when :on_embexpr_beg + embexpr_balance += 1 + results << token + when :on_embexpr_end + embexpr_balance -= 1 + results << token + when :on_tstring_content + if embexpr_balance == 0 + lineno = token[0][0] + column = token[0][1] + + if split + # Split on "\\\n" to mimic Ripper's behavior. Use a lookbehind + # to keep the delimiter in the result. + token.value.split(/(?<=[^\\]\\\n)|(?<=[^\\]\\\r\n)/).each_with_index do |value, index| + column = 0 if index > 0 + results << Token.new([[lineno, column], :on_tstring_content, value, token.state]) + lineno += value.count("\n") + end + else + results << token + end + else + results << token + end + else + results << token + end + end + end + end + + # Heredocs that are dedenting heredocs are a little more complicated. + # Ripper outputs on_ignored_sp tokens for the whitespace that is being + # removed from the output. YARP only modifies the node itself and keeps + # the token the same. This simplifies YARP, but makes comparing against + # Ripper much harder because there is a length mismatch. + # + # Fortunately, we already have to pull out the heredoc tokens in order to + # insert them into the stream in the correct order. As such, we can do + # some extra manipulation on the tokens to make them match Ripper's + # output by mirroring the dedent logic that Ripper uses. + class DedentingHeredoc + TAB_WIDTH = 8 + + attr_reader :tokens, :dedent_next, :dedent, :embexpr_balance + + def initialize + @tokens = [] + @dedent_next = true + @dedent = nil + @embexpr_balance = 0 + end + + # As tokens are coming in, we track the minimum amount of common leading + # whitespace on plain string content tokens. This allows us to later + # remove that amount of whitespace from the beginning of each line. + def <<(token) + case token.event + when :on_embexpr_beg, :on_heredoc_beg + @embexpr_balance += 1 + when :on_embexpr_end, :on_heredoc_end + @embexpr_balance -= 1 + when :on_tstring_content + if embexpr_balance == 0 + token.value.split(/(?<=\n)/).each_with_index do |line, index| + next if line.strip.empty? && line.end_with?("\n") + next if !(dedent_next || index > 0) + + leading = line[/\A(\s*)\n?/, 1] + next_dedent = 0 + + leading.each_char do |char| + if char == "\t" + next_dedent = next_dedent - (next_dedent % TAB_WIDTH) + TAB_WIDTH + else + next_dedent += 1 + end + end + + @dedent = [dedent, next_dedent].compact.min + end + end + end + + @dedent_next = token.event == :on_tstring_content && embexpr_balance == 0 + tokens << token + end + + def to_a + # If every line in the heredoc is blank, we still need to split up the + # string content token into multiple tokens. + if dedent.nil? + results = [] + embexpr_balance = 0 + + tokens.each do |token| + case token.event + when :on_embexpr_beg, :on_heredoc_beg + embexpr_balance += 1 + results << token + when :on_embexpr_end, :on_heredoc_end + embexpr_balance -= 1 + results << token + when :on_tstring_content + if embexpr_balance == 0 + lineno = token[0][0] + column = token[0][1] + + token.value.split(/(?<=\n)/).each_with_index do |value, index| + column = 0 if index > 0 + results << Token.new([[lineno, column], :on_tstring_content, value, token.state]) + lineno += 1 + end + else + results << token + end + else + results << token + end + end + + return results + end + + # Otherwise, we're going to run through each token in the list and + # insert on_ignored_sp tokens for the amount of dedent that we need to + # perform. We also need to remove the dedent from the beginning of + # each line of plain string content tokens. + results = [] + dedent_next = true + embexpr_balance = 0 + + tokens.each do |token| + # Notice that the structure of this conditional largely matches the + # whitespace calculation we performed above. This is because + # checking if the subsequent token needs to be dedented is common to + # both the dedent calculation and the ignored_sp insertion. + case token.event + when :on_embexpr_beg + embexpr_balance += 1 + results << token + when :on_embexpr_end + embexpr_balance -= 1 + results << token + when :on_tstring_content + if embexpr_balance == 0 + # Here we're going to split the string on newlines, but maintain + # the newlines in the resulting array. We'll do that with a look + # behind assertion. + splits = token.value.split(/(?<=\n)/) + index = 0 + + while index < splits.length + line = splits[index] + lineno = token[0][0] + index + column = token[0][1] + + # Blank lines do not count toward common leading whitespace + # calculation and do not need to be dedented. + if dedent_next || index > 0 + column = 0 + end + + # If the dedent is 0 and we're not supposed to dedent the next + # line or this line doesn't start with whitespace, then we + # should concatenate the rest of the string to match ripper. + if dedent == 0 && (!dedent_next || !line.start_with?(/\s/)) + line = splits[index..].join + index = splits.length + end + + # If we are supposed to dedent this line or if this is not the + # first line of the string and this line isn't entirely blank, + # then we need to insert an on_ignored_sp token and remove the + # dedent from the beginning of the line. + if (dedent > 0) && (dedent_next || index > 0) + deleting = 0 + deleted_chars = [] + + # Gather up all of the characters that we're going to + # delete, stopping when you hit a character that would put + # you over the dedent amount. + line.each_char.with_index do |char, i| + case char + when "\r" + if line.chars[i + 1] == "\n" + break + end + when "\n" + break + when "\t" + deleting = deleting - (deleting % TAB_WIDTH) + TAB_WIDTH + else + deleting += 1 + end + + break if deleting > dedent + deleted_chars << char + end + + # If we have something to delete, then delete it from the + # string and insert an on_ignored_sp token. + if deleted_chars.any? + ignored = deleted_chars.join + line.delete_prefix!(ignored) + + results << Token.new([[lineno, 0], :on_ignored_sp, ignored, token[3]]) + column = ignored.length + end + end + + results << Token.new([[lineno, column], token[1], line, token[3]]) unless line.empty? + index += 1 + end + else + results << token + end + else + results << token + end + + dedent_next = + ((token.event == :on_tstring_content) || (token.event == :on_heredoc_end)) && + embexpr_balance == 0 + end + + results + end + end + + # Here we will split between the two types of heredocs and return the + # object that will store their tokens. + def self.build(opening) + case opening.value[2] + when "~" + DedentingHeredoc.new + when "-" + DashHeredoc.new(opening.value[3] != "'") + else + PlainHeredoc.new + end + end + end + + attr_reader :source, :offsets, :filepath + + def initialize(source, filepath = "") + @source = source + @filepath = filepath || "" + @offsets = find_offsets(source) + end + + def result + tokens = [] + + state = :default + heredoc_stack = [[]] + + result = YARP.lex(source, @filepath) + result_value = result.value + previous_state = nil + + # If there's a UTF-8 byte-order mark as the start of the file, then ripper + # sets every token's on the first line back by 6 bytes. It also keeps the + # byte order mark in the first token's value. This is weird, and I don't + # want to mirror that in our parser. So instead, we'll match up the values + # here, and then match up the locations as we process the tokens. + bom = source.bytes[0..2] == [0xEF, 0xBB, 0xBF] + result_value[0][0].value.prepend("\xEF\xBB\xBF") if bom + + result_value.each_with_index do |(token, lex_state), index| + (lineno, column) = find_location(token.location.start_offset) + column -= index == 0 ? 6 : 3 if bom && lineno == 1 + + event = RIPPER.fetch(token.type) + value = token.value + lex_state = Ripper::Lexer::State.new(lex_state) + + token = + case event + when :on___end__ + EndContentToken.new([[lineno, column], event, value, lex_state]) + when :on_comment + CommentToken.new([[lineno, column], event, value, lex_state]) + when :on_heredoc_end + # Heredoc end tokens can be emitted in an odd order, so we don't + # want to bother comparing the state on them. + HeredocEndToken.new([[lineno, column], event, value, lex_state]) + when :on_embexpr_end, :on_ident + if lex_state == Ripper::EXPR_END | Ripper::EXPR_LABEL + # In the event that we're comparing identifiers, we're going to + # allow a little divergence. Ripper doesn't account for local + # variables introduced through named captures in regexes, and we + # do, which accounts for this difference. + IdentToken.new([[lineno, column], event, value, lex_state]) + else + Token.new([[lineno, column], event, value, lex_state]) + end + when :on_ignored_nl + # Ignored newlines can occasionally have a LABEL state attached to + # them which doesn't actually impact anything. We don't mirror that + # state so we ignored it. + IgnoredNewlineToken.new([[lineno, column], event, value, lex_state]) + when :on_regexp_end + # On regex end, Ripper scans and then sets end state, so the ripper + # lexed output is begin, when it should be end. YARP sets lex state + # correctly to end state, but we want to be able to compare against + # Ripper's lexed state. So here, if it's a regexp end token, we + # output the state as the previous state, solely for the sake of + # comparison. + previous_token = result_value[index - 1][0] + lex_state = + if RIPPER.fetch(previous_token.type) == :on_embexpr_end + # If the previous token is embexpr_end, then we have to do even + # more processing. The end of an embedded expression sets the + # state to the state that it had at the beginning of the + # embedded expression. So we have to go and find that state and + # set it here. + counter = 1 + current_index = index - 1 + + until counter == 0 + current_index -= 1 + current_event = RIPPER.fetch(result_value[current_index][0].type) + counter += { on_embexpr_beg: -1, on_embexpr_end: 1 }[current_event] || 0 + end + + Ripper::Lexer::State.new(result_value[current_index][1]) + else + previous_state + end + + Token.new([[lineno, column], event, value, lex_state]) + else + Token.new([[lineno, column], event, value, lex_state]) + end + + previous_state = lex_state + + # The order in which tokens appear in our lexer is different from the + # order that they appear in Ripper. When we hit the declaration of a + # heredoc in YARP, we skip forward and lex the rest of the content of + # the heredoc before going back and lexing at the end of the heredoc + # identifier. + # + # To match up to ripper, we keep a small state variable around here to + # track whether we're in the middle of a heredoc or not. In this way we + # can shuffle around the token to match Ripper's output. + case state + when :default + tokens << token + + if event == :on_heredoc_beg + state = :heredoc_opened + heredoc_stack.last << Heredoc.build(token) + end + when :heredoc_opened + heredoc_stack.last.last << token + + case event + when :on_heredoc_beg + heredoc_stack << [Heredoc.build(token)] + when :on_heredoc_end + state = :heredoc_closed + end + when :heredoc_closed + if %i[on_nl on_ignored_nl on_comment].include?(event) || (event == :on_tstring_content && value.end_with?("\n")) + if heredoc_stack.size > 1 + flushing = heredoc_stack.pop + heredoc_stack.last.last << token + + flushing.each do |heredoc| + heredoc.to_a.each do |flushed_token| + heredoc_stack.last.last << flushed_token + end + end + + state = :heredoc_opened + next + end + elsif event == :on_heredoc_beg + tokens << token + state = :heredoc_opened + heredoc_stack.last << Heredoc.build(token) + next + elsif heredoc_stack.size > 1 + heredoc_stack[-2].last << token + next + end + + heredoc_stack.last.each do |heredoc| + tokens.concat(heredoc.to_a) + end + + heredoc_stack.last.clear + state = :default + + tokens << token + end + end + + tokens.reject! { |t| t.event == :on_eof } + + # We sort by location to compare against Ripper's output + tokens.sort_by!(&:location) + + if result_value.size - 1 > tokens.size + raise StandardError, "Lost tokens when performing lex_compat" + end + + ParseResult.new(tokens, result.comments, result.errors, result.warnings) + end + + private + + # YARP keeps locations around in the form of ranges of byte offsets from the + # start of the file. Ripper keeps locations around in the form of line and + # column numbers. To match the output, we keep a cache of the offsets at the + # beginning of each line. + def find_offsets(source) + last_offset = 0 + offsets = [0] + + source.each_line do |line| + last_offset += line.bytesize + offsets << last_offset + end + + offsets + end + + # Given a byte offset, find the line number and column number that it maps + # to. We use a binary search over the cached offsets to find the line number + # that the offset is on, and then subtract the offset of the previous line + # to find the column number. + def find_location(value) + line_number = offsets.bsearch_index { |offset| offset > value } + line_offset = offsets[line_number - 1] if line_number + + [ + line_number || offsets.length - 1, + value - (line_offset || offsets.last) + ] + end + end + + # The constant that wraps the behavior of the lexer to match Ripper's output + # is an implementation detail, so we don't want it to be public. + private_constant :LexCompat + + # Returns an array of tokens that closely resembles that of the Ripper lexer. + # The only difference is that since we don't keep track of lexer state in the + # same way, it's going to always return the NONE state. + def self.lex_compat(source, filepath = "") + LexCompat.new(source, filepath).result + end +end diff --git a/lib/yarp/node.rb b/lib/yarp/node.rb new file mode 100644 index 0000000000..f6f9136cd1 --- /dev/null +++ b/lib/yarp/node.rb @@ -0,0 +1,6434 @@ +# frozen_string_literal: true +=begin +This file is generated by the bin/template script and should not be +modified manually. See templates/lib/yarp/node.rb.erb +if you are looking to modify the template +=end + +module YARP + # Represents the use of the `alias` keyword. + # + # alias foo bar + # ^^^^^^^^^^^^^ + class AliasNode < 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, start_offset: Integer, length: Integer) -> void + def initialize(new_name, old_name, keyword_loc, start_offset, length) + @new_name = new_name + @old_name = old_name + @keyword_loc = keyword_loc + @start_offset = start_offset + @length = length + end + + # def accept: (visitor: Visitor) -> void + def accept(visitor) + visitor.visit_alias_node(self) + end + + # def child_nodes: () -> Array[nil | Node] + def child_nodes + [new_name, old_name] + 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 + 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, start_offset: Integer, length: Integer) -> void + def initialize(left, right, operator_loc, start_offset, length) + @left = left + @right = right + @operator_loc = operator_loc + @start_offset = start_offset + @length = length + 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 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 + 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, start_offset: Integer, length: Integer) -> void + def initialize(left, right, operator_loc, start_offset, length) + @left = left + @right = right + @operator_loc = operator_loc + @start_offset = start_offset + @length = length + 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 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 + end + + # Represents a set of arguments to a method or a keyword. + # + # return foo, bar, baz + # ^^^^^^^^^^^^^ + class ArgumentsNode < Node + # attr_reader arguments: Array[Node] + attr_reader :arguments + + # def initialize: (arguments: Array[Node], start_offset: Integer, length: Integer) -> void + def initialize(arguments, start_offset, length) + @arguments = arguments + @start_offset = start_offset + @length = length + 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 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, location: location } + 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 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: (elements: Array[Node], opening_loc: Location?, closing_loc: Location?, start_offset: Integer, length: Integer) -> void + def initialize(elements, opening_loc, closing_loc, start_offset, length) + @elements = elements + @opening_loc = opening_loc + @closing_loc = closing_loc + @start_offset = start_offset + @length = length + 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 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) + { elements: elements, opening_loc: opening_loc, closing_loc: closing_loc, location: location } + 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?, start_offset: Integer, length: Integer) -> void + def initialize(constant, requireds, rest, posts, opening_loc, closing_loc, start_offset, length) + @constant = constant + @requireds = requireds + @rest = rest + @posts = posts + @opening_loc = opening_loc + @closing_loc = closing_loc + @start_offset = start_offset + @length = length + 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 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 + 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?, start_offset: Integer, length: Integer) -> void + def initialize(key, value, operator_loc, start_offset, length) + @key = key + @value = value + @operator_loc = operator_loc + @start_offset = start_offset + @length = length + 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 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 + 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, start_offset: Integer, length: Integer) -> void + def initialize(value, operator_loc, start_offset, length) + @value = value + @operator_loc = operator_loc + @start_offset = start_offset + @length = length + 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 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 + end + + # Represents reading a reference to a field in the previous match. + # + # $' + # ^^ + class BackReferenceReadNode < Node + # def initialize: (start_offset: Integer, length: Integer) -> void + def initialize(start_offset, length) + @start_offset = start_offset + @length = length + 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 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 + 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: Node? + attr_reader :statements + + # attr_reader rescue_clause: Node? + attr_reader :rescue_clause + + # attr_reader else_clause: Node? + attr_reader :else_clause + + # attr_reader ensure_clause: Node? + attr_reader :ensure_clause + + # attr_reader end_keyword_loc: Location? + attr_reader :end_keyword_loc + + # def initialize: (begin_keyword_loc: Location?, statements: Node?, rescue_clause: Node?, else_clause: Node?, ensure_clause: Node?, end_keyword_loc: Location?, start_offset: Integer, length: Integer) -> void + def initialize(begin_keyword_loc, statements, rescue_clause, else_clause, ensure_clause, end_keyword_loc, start_offset, length) + @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 + @start_offset = start_offset + @length = length + end + + # def accept: (visitor: Visitor) -> void + def accept(visitor) + visitor.visit_begin_node(self) + end + + # def child_nodes: () -> Array[nil | Node] + def child_nodes + [statements, rescue_clause, else_clause, ensure_clause] + 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 + 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, start_offset: Integer, length: Integer) -> void + def initialize(expression, operator_loc, start_offset, length) + @expression = expression + @operator_loc = operator_loc + @start_offset = start_offset + @length = length + 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 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 + 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 parameters: Node? + attr_reader :parameters + + # attr_reader statements: Node? + attr_reader :statements + + # attr_reader opening_loc: Location + attr_reader :opening_loc + + # attr_reader closing_loc: Location + attr_reader :closing_loc + + # def initialize: (locals: Array[Symbol], parameters: Node?, statements: Node?, opening_loc: Location, closing_loc: Location, start_offset: Integer, length: Integer) -> void + def initialize(locals, parameters, statements, opening_loc, closing_loc, start_offset, length) + @locals = locals + @parameters = parameters + @statements = statements + @opening_loc = opening_loc + @closing_loc = closing_loc + @start_offset = start_offset + @length = length + 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, statements] + 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, parameters: parameters, statements: statements, opening_loc: opening_loc, closing_loc: closing_loc, location: location } + end + end + + # Represents a block parameter to a method, block, or lambda definition. + # + # def a(&b) + # ^^ + # end + class BlockParameterNode < Node + # attr_reader name_loc: Location? + attr_reader :name_loc + + # attr_reader operator_loc: Location + attr_reader :operator_loc + + # def initialize: (name_loc: Location?, operator_loc: Location, start_offset: Integer, length: Integer) -> void + def initialize(name_loc, operator_loc, start_offset, length) + @name_loc = name_loc + @operator_loc = operator_loc + @start_offset = start_offset + @length = length + 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 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, location: location } + 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: Node? + attr_reader :parameters + + # attr_reader locals: Array[Location] + attr_reader :locals + + # attr_reader opening_loc: Location? + attr_reader :opening_loc + + # attr_reader closing_loc: Location? + attr_reader :closing_loc + + # def initialize: (parameters: Node?, locals: Array[Location], opening_loc: Location?, closing_loc: Location?, start_offset: Integer, length: Integer) -> void + def initialize(parameters, locals, opening_loc, closing_loc, start_offset, length) + @parameters = parameters + @locals = locals + @opening_loc = opening_loc + @closing_loc = closing_loc + @start_offset = start_offset + @length = length + 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] + 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 + end + + # Represents the use of the `break` keyword. + # + # break foo + # ^^^^^^^^^ + class BreakNode < Node + # attr_reader arguments: Node? + attr_reader :arguments + + # attr_reader keyword_loc: Location + attr_reader :keyword_loc + + # def initialize: (arguments: Node?, keyword_loc: Location, start_offset: Integer, length: Integer) -> void + def initialize(arguments, keyword_loc, start_offset, length) + @arguments = arguments + @keyword_loc = keyword_loc + @start_offset = start_offset + @length = length + 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 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 + 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 receiver: Node? + attr_reader :receiver + + # attr_reader operator_loc: Location? + attr_reader :operator_loc + + # attr_reader message_loc: Location? + attr_reader :message_loc + + # attr_reader opening_loc: Location? + attr_reader :opening_loc + + # attr_reader arguments: Node? + attr_reader :arguments + + # attr_reader closing_loc: Location? + attr_reader :closing_loc + + # attr_reader block: Node? + attr_reader :block + + # attr_reader flags: Integer + attr_reader :flags + + # attr_reader name: String + attr_reader :name + + # def initialize: (receiver: Node?, operator_loc: Location?, message_loc: Location?, opening_loc: Location?, arguments: Node?, closing_loc: Location?, block: Node?, flags: Integer, name: String, start_offset: Integer, length: Integer) -> void + def initialize(receiver, operator_loc, message_loc, opening_loc, arguments, closing_loc, block, flags, name, start_offset, length) + @receiver = receiver + @operator_loc = operator_loc + @message_loc = message_loc + @opening_loc = opening_loc + @arguments = arguments + @closing_loc = closing_loc + @block = block + @flags = flags + @name = name + @start_offset = start_offset + @length = length + 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 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) + { receiver: receiver, operator_loc: operator_loc, message_loc: message_loc, opening_loc: opening_loc, arguments: arguments, closing_loc: closing_loc, block: block, flags: flags, name: name, location: location } + end + end + + # Represents the use of the `&&=` operator on a call. + # + # foo.bar &&= value + # ^^^^^^^^^^^^^^^^^ + class CallOperatorAndWriteNode < Node + # attr_reader target: Node + attr_reader :target + + # attr_reader operator_loc: Location + attr_reader :operator_loc + + # attr_reader value: Node + attr_reader :value + + # def initialize: (target: Node, operator_loc: Location, value: Node, start_offset: Integer, length: Integer) -> void + def initialize(target, operator_loc, value, start_offset, length) + @target = target + @operator_loc = operator_loc + @value = value + @start_offset = start_offset + @length = length + end + + # def accept: (visitor: Visitor) -> void + def accept(visitor) + visitor.visit_call_operator_and_write_node(self) + end + + # def child_nodes: () -> Array[nil | Node] + def child_nodes + [target, value] + 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 + end + + # Represents the use of the `||=` operator on a call. + # + # foo.bar ||= value + # ^^^^^^^^^^^^^^^^^ + class CallOperatorOrWriteNode < Node + # attr_reader target: Node + attr_reader :target + + # attr_reader value: Node + attr_reader :value + + # attr_reader operator_loc: Location + attr_reader :operator_loc + + # def initialize: (target: Node, value: Node, operator_loc: Location, start_offset: Integer, length: Integer) -> void + def initialize(target, value, operator_loc, start_offset, length) + @target = target + @value = value + @operator_loc = operator_loc + @start_offset = start_offset + @length = length + end + + # def accept: (visitor: Visitor) -> void + def accept(visitor) + visitor.visit_call_operator_or_write_node(self) + end + + # def child_nodes: () -> Array[nil | Node] + def child_nodes + [target, value] + 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, value: value, operator_loc: operator_loc, location: location } + end + end + + # Represents the use of an assignment operator on a call. + # + # foo.bar += baz + # ^^^^^^^^^^^^^^ + class CallOperatorWriteNode < Node + # attr_reader target: Node + attr_reader :target + + # attr_reader operator_loc: Location + attr_reader :operator_loc + + # attr_reader value: Node + attr_reader :value + + # attr_reader operator_id: Symbol + attr_reader :operator_id + + # def initialize: (target: Node, operator_loc: Location, value: Node, operator_id: Symbol, start_offset: Integer, length: Integer) -> void + def initialize(target, operator_loc, value, operator_id, start_offset, length) + @target = target + @operator_loc = operator_loc + @value = value + @operator_id = operator_id + @start_offset = start_offset + @length = length + 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 + [target, value] + 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_id: operator_id, location: location } + 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, start_offset: Integer, length: Integer) -> void + def initialize(value, target, operator_loc, start_offset, length) + @value = value + @target = target + @operator_loc = operator_loc + @start_offset = start_offset + @length = length + 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 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 + 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: Node? + 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: Node?, case_keyword_loc: Location, end_keyword_loc: Location, start_offset: Integer, length: Integer) -> void + def initialize(predicate, conditions, consequent, case_keyword_loc, end_keyword_loc, start_offset, length) + @predicate = predicate + @conditions = conditions + @consequent = consequent + @case_keyword_loc = case_keyword_loc + @end_keyword_loc = end_keyword_loc + @start_offset = start_offset + @length = length + 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 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 + 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 statements: Node? + attr_reader :statements + + # attr_reader end_keyword_loc: Location + attr_reader :end_keyword_loc + + # def initialize: (locals: Array[Symbol], class_keyword_loc: Location, constant_path: Node, inheritance_operator_loc: Location?, superclass: Node?, statements: Node?, end_keyword_loc: Location, start_offset: Integer, length: Integer) -> void + def initialize(locals, class_keyword_loc, constant_path, inheritance_operator_loc, superclass, statements, end_keyword_loc, start_offset, length) + @locals = locals + @class_keyword_loc = class_keyword_loc + @constant_path = constant_path + @inheritance_operator_loc = inheritance_operator_loc + @superclass = superclass + @statements = statements + @end_keyword_loc = end_keyword_loc + @start_offset = start_offset + @length = length + 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, statements] + 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, statements: statements, end_keyword_loc: end_keyword_loc, location: location } + end + end + + # Represents the use of the `&&=` operator for assignment to a class variable. + # + # @@target &&= value + # ^^^^^^^^^^^^^^^^ + class ClassVariableOperatorAndWriteNode < 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 + + # def initialize: (name_loc: Location, operator_loc: Location, value: Node, start_offset: Integer, length: Integer) -> void + def initialize(name_loc, operator_loc, value, start_offset, length) + @name_loc = name_loc + @operator_loc = operator_loc + @value = value + @start_offset = start_offset + @length = length + end + + # def accept: (visitor: Visitor) -> void + def accept(visitor) + visitor.visit_class_variable_operator_and_write_node(self) + end + + # def child_nodes: () -> Array[nil | Node] + def child_nodes + [value] + 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, location: location } + end + end + + # Represents the use of the `||=` operator for assignment to a class variable. + # + # @@target ||= value + # ^^^^^^^^^^^^^^^^^^ + class ClassVariableOperatorOrWriteNode < 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 + + # def initialize: (name_loc: Location, operator_loc: Location, value: Node, start_offset: Integer, length: Integer) -> void + def initialize(name_loc, operator_loc, value, start_offset, length) + @name_loc = name_loc + @operator_loc = operator_loc + @value = value + @start_offset = start_offset + @length = length + end + + # def accept: (visitor: Visitor) -> void + def accept(visitor) + visitor.visit_class_variable_operator_or_write_node(self) + end + + # def child_nodes: () -> Array[nil | Node] + def child_nodes + [value] + 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, location: location } + end + end + + # Represents assigning to a class variable using an operator that isn't `=`. + # + # @@target += value + # ^^^^^^^^^^^^^^^^^ + class ClassVariableOperatorWriteNode < 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 operator: Symbol + attr_reader :operator + + # def initialize: (name_loc: Location, operator_loc: Location, value: Node, operator: Symbol, start_offset: Integer, length: Integer) -> void + def initialize(name_loc, operator_loc, value, operator, start_offset, length) + @name_loc = name_loc + @operator_loc = operator_loc + @value = value + @operator = operator + @start_offset = start_offset + @length = length + 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 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, operator: operator, location: location } + end + end + + # Represents referencing a class variable. + # + # @@foo + # ^^^^^ + class ClassVariableReadNode < Node + # def initialize: (start_offset: Integer, length: Integer) -> void + def initialize(start_offset, length) + @start_offset = start_offset + @length = length + 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 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 + end + + # Represents writing to a class variable. + # + # @@foo = 1 + # ^^^^^^^^^ + class ClassVariableWriteNode < Node + # 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_loc: Location, value: Node?, operator_loc: Location?, start_offset: Integer, length: Integer) -> void + def initialize(name_loc, value, operator_loc, start_offset, length) + @name_loc = name_loc + @value = value + @operator_loc = operator_loc + @start_offset = start_offset + @length = length + 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 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, value: value, operator_loc: operator_loc, location: location } + end + end + + # Represents the use of the `&&=` operator for assignment to a constant. + # + # Target &&= value + # ^^^^^^^^^^^^^^^^ + class ConstantOperatorAndWriteNode < 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 + + # def initialize: (name_loc: Location, operator_loc: Location, value: Node, start_offset: Integer, length: Integer) -> void + def initialize(name_loc, operator_loc, value, start_offset, length) + @name_loc = name_loc + @operator_loc = operator_loc + @value = value + @start_offset = start_offset + @length = length + end + + # def accept: (visitor: Visitor) -> void + def accept(visitor) + visitor.visit_constant_operator_and_write_node(self) + end + + # def child_nodes: () -> Array[nil | Node] + def child_nodes + [value] + 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, location: location } + end + end + + # Represents the use of the `||=` operator for assignment to a constant. + # + # Target ||= value + # ^^^^^^^^^^^^^^^^ + class ConstantOperatorOrWriteNode < 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 + + # def initialize: (name_loc: Location, operator_loc: Location, value: Node, start_offset: Integer, length: Integer) -> void + def initialize(name_loc, operator_loc, value, start_offset, length) + @name_loc = name_loc + @operator_loc = operator_loc + @value = value + @start_offset = start_offset + @length = length + end + + # def accept: (visitor: Visitor) -> void + def accept(visitor) + visitor.visit_constant_operator_or_write_node(self) + end + + # def child_nodes: () -> Array[nil | Node] + def child_nodes + [value] + 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, location: location } + end + end + + # Represents assigning to a constant using an operator that isn't `=`. + # + # Target += value + # ^^^^^^^^^^^^^^^ + class ConstantOperatorWriteNode < 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 operator: Symbol + attr_reader :operator + + # def initialize: (name_loc: Location, operator_loc: Location, value: Node, operator: Symbol, start_offset: Integer, length: Integer) -> void + def initialize(name_loc, operator_loc, value, operator, start_offset, length) + @name_loc = name_loc + @operator_loc = operator_loc + @value = value + @operator = operator + @start_offset = start_offset + @length = length + 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 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, operator: operator, location: location } + 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, start_offset: Integer, length: Integer) -> void + def initialize(parent, child, delimiter_loc, start_offset, length) + @parent = parent + @child = child + @delimiter_loc = delimiter_loc + @start_offset = start_offset + @length = length + 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 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 + end + + # Represents the use of the `&&=` operator for assignment to a constant path. + # + # Parent::Child &&= value + # ^^^^^^^^^^^^^^^^^^^^^^^ + class ConstantPathOperatorAndWriteNode < Node + # attr_reader target: Node + attr_reader :target + + # attr_reader operator_loc: Location + attr_reader :operator_loc + + # attr_reader value: Node + attr_reader :value + + # def initialize: (target: Node, operator_loc: Location, value: Node, start_offset: Integer, length: Integer) -> void + def initialize(target, operator_loc, value, start_offset, length) + @target = target + @operator_loc = operator_loc + @value = value + @start_offset = start_offset + @length = length + end + + # def accept: (visitor: Visitor) -> void + def accept(visitor) + visitor.visit_constant_path_operator_and_write_node(self) + end + + # def child_nodes: () -> Array[nil | Node] + def child_nodes + [target, value] + 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 + end + + # Represents the use of the `||=` operator for assignment to a constant path. + # + # Parent::Child ||= value + # ^^^^^^^^^^^^^^^^^^^^^^^ + class ConstantPathOperatorOrWriteNode < Node + # attr_reader target: Node + attr_reader :target + + # attr_reader operator_loc: Location + attr_reader :operator_loc + + # attr_reader value: Node + attr_reader :value + + # def initialize: (target: Node, operator_loc: Location, value: Node, start_offset: Integer, length: Integer) -> void + def initialize(target, operator_loc, value, start_offset, length) + @target = target + @operator_loc = operator_loc + @value = value + @start_offset = start_offset + @length = length + end + + # def accept: (visitor: Visitor) -> void + def accept(visitor) + visitor.visit_constant_path_operator_or_write_node(self) + end + + # def child_nodes: () -> Array[nil | Node] + def child_nodes + [target, value] + 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 + end + + # Represents assigning to a constant path using an operator that isn't `=`. + # + # Parent::Child += value + # ^^^^^^^^^^^^^^^^^^^^^^ + class ConstantPathOperatorWriteNode < Node + # attr_reader target: Node + 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: Node, operator_loc: Location, value: Node, operator: Symbol, start_offset: Integer, length: Integer) -> void + def initialize(target, operator_loc, value, operator, start_offset, length) + @target = target + @operator_loc = operator_loc + @value = value + @operator = operator + @start_offset = start_offset + @length = length + 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 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 + end + + # Represents writing to a constant. + # + # Foo = 1 + # ^^^^^^^ + # + # Foo::Bar = 1 + # ^^^^^^^^^^^^ + class ConstantPathWriteNode < Node + # attr_reader target: Node + attr_reader :target + + # attr_reader operator_loc: Location? + attr_reader :operator_loc + + # attr_reader value: Node? + attr_reader :value + + # def initialize: (target: Node, operator_loc: Location?, value: Node?, start_offset: Integer, length: Integer) -> void + def initialize(target, operator_loc, value, start_offset, length) + @target = target + @operator_loc = operator_loc + @value = value + @start_offset = start_offset + @length = length + 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 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 + end + + # Represents referencing a constant. + # + # Foo + # ^^^ + class ConstantReadNode < Node + # def initialize: (start_offset: Integer, length: Integer) -> void + def initialize(start_offset, length) + @start_offset = start_offset + @length = length + 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 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 + end + + # Represents a method definition. + # + # def method + # end + # ^^^^^^^^^^ + class DefNode < Node + # attr_reader name_loc: Location + attr_reader :name_loc + + # attr_reader receiver: Node? + attr_reader :receiver + + # attr_reader parameters: Node? + attr_reader :parameters + + # attr_reader statements: Node? + attr_reader :statements + + # attr_reader locals: Array[Symbol] + attr_reader :locals + + # 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_loc: Location, receiver: Node?, parameters: Node?, statements: Node?, locals: Array[Symbol], def_keyword_loc: Location, operator_loc: Location?, lparen_loc: Location?, rparen_loc: Location?, equal_loc: Location?, end_keyword_loc: Location?, start_offset: Integer, length: Integer) -> void + def initialize(name_loc, receiver, parameters, statements, locals, def_keyword_loc, operator_loc, lparen_loc, rparen_loc, equal_loc, end_keyword_loc, start_offset, length) + @name_loc = name_loc + @receiver = receiver + @parameters = parameters + @statements = statements + @locals = locals + @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 + @start_offset = start_offset + @length = length + 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, statements] + 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, receiver: receiver, parameters: parameters, statements: statements, locals: locals, 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 + 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, start_offset: Integer, length: Integer) -> void + def initialize(lparen_loc, value, rparen_loc, keyword_loc, start_offset, length) + @lparen_loc = lparen_loc + @value = value + @rparen_loc = rparen_loc + @keyword_loc = keyword_loc + @start_offset = start_offset + @length = length + 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 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 + 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: Node? + attr_reader :statements + + # attr_reader end_keyword_loc: Location? + attr_reader :end_keyword_loc + + # def initialize: (else_keyword_loc: Location, statements: Node?, end_keyword_loc: Location?, start_offset: Integer, length: Integer) -> void + def initialize(else_keyword_loc, statements, end_keyword_loc, start_offset, length) + @else_keyword_loc = else_keyword_loc + @statements = statements + @end_keyword_loc = end_keyword_loc + @start_offset = start_offset + @length = length + 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 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 + end + + # Represents an interpolated set of statements. + # + # "foo #{bar}" + # ^^^^^^ + class EmbeddedStatementsNode < Node + # attr_reader opening_loc: Location + attr_reader :opening_loc + + # attr_reader statements: Node? + attr_reader :statements + + # attr_reader closing_loc: Location + attr_reader :closing_loc + + # def initialize: (opening_loc: Location, statements: Node?, closing_loc: Location, start_offset: Integer, length: Integer) -> void + def initialize(opening_loc, statements, closing_loc, start_offset, length) + @opening_loc = opening_loc + @statements = statements + @closing_loc = closing_loc + @start_offset = start_offset + @length = length + 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 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 + 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, start_offset: Integer, length: Integer) -> void + def initialize(operator_loc, variable, start_offset, length) + @operator_loc = operator_loc + @variable = variable + @start_offset = start_offset + @length = length + 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 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 + 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: Node? + attr_reader :statements + + # attr_reader end_keyword_loc: Location + attr_reader :end_keyword_loc + + # def initialize: (ensure_keyword_loc: Location, statements: Node?, end_keyword_loc: Location, start_offset: Integer, length: Integer) -> void + def initialize(ensure_keyword_loc, statements, end_keyword_loc, start_offset, length) + @ensure_keyword_loc = ensure_keyword_loc + @statements = statements + @end_keyword_loc = end_keyword_loc + @start_offset = start_offset + @length = length + 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 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 + end + + # Represents the use of the literal `false` keyword. + # + # false + # ^^^^^ + class FalseNode < Node + # def initialize: (start_offset: Integer, length: Integer) -> void + def initialize(start_offset, length) + @start_offset = start_offset + @length = length + 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 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 + 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?, start_offset: Integer, length: Integer) -> void + def initialize(constant, left, requireds, right, opening_loc, closing_loc, start_offset, length) + @constant = constant + @left = left + @requireds = requireds + @right = right + @opening_loc = opening_loc + @closing_loc = closing_loc + @start_offset = start_offset + @length = length + 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 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 + end + + # Represents a floating point number literal. + # + # 1.0 + # ^^^ + class FloatNode < Node + # def initialize: (start_offset: Integer, length: Integer) -> void + def initialize(start_offset, length) + @start_offset = start_offset + @length = length + 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 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 + 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: Node? + 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: Node?, for_keyword_loc: Location, in_keyword_loc: Location, do_keyword_loc: Location?, end_keyword_loc: Location, start_offset: Integer, length: Integer) -> void + def initialize(index, collection, statements, for_keyword_loc, in_keyword_loc, do_keyword_loc, end_keyword_loc, start_offset, length) + @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 + @start_offset = start_offset + @length = length + 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 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 + end + + # Represents forwarding all arguments to this method to another method. + # + # def foo(...) + # bar(...) + # ^^^^^^^^ + # end + class ForwardingArgumentsNode < Node + # def initialize: (start_offset: Integer, length: Integer) -> void + def initialize(start_offset, length) + @start_offset = start_offset + @length = length + 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 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 + end + + # Represents the use of the forwarding parameter in a method, block, or lambda declaration. + # + # def foo(...) + # ^^^ + # end + class ForwardingParameterNode < Node + # def initialize: (start_offset: Integer, length: Integer) -> void + def initialize(start_offset, length) + @start_offset = start_offset + @length = length + 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 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 + end + + # Represents the use of the `super` keyword without parentheses or arguments. + # + # super + # ^^^^^ + class ForwardingSuperNode < Node + # attr_reader block: Node? + attr_reader :block + + # def initialize: (block: Node?, start_offset: Integer, length: Integer) -> void + def initialize(block, start_offset, length) + @block = block + @start_offset = start_offset + @length = length + 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 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 + end + + # Represents the use of the `&&=` operator for assignment to a global variable. + # + # $target &&= value + # ^^^^^^^^^^^^^^^^^ + class GlobalVariableOperatorAndWriteNode < 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 + + # def initialize: (name_loc: Location, operator_loc: Location, value: Node, start_offset: Integer, length: Integer) -> void + def initialize(name_loc, operator_loc, value, start_offset, length) + @name_loc = name_loc + @operator_loc = operator_loc + @value = value + @start_offset = start_offset + @length = length + end + + # def accept: (visitor: Visitor) -> void + def accept(visitor) + visitor.visit_global_variable_operator_and_write_node(self) + end + + # def child_nodes: () -> Array[nil | Node] + def child_nodes + [value] + 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, location: location } + end + end + + # Represents the use of the `||=` operator for assignment to a global variable. + # + # $target ||= value + # ^^^^^^^^^^^^^^^^^ + class GlobalVariableOperatorOrWriteNode < 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 + + # def initialize: (name_loc: Location, operator_loc: Location, value: Node, start_offset: Integer, length: Integer) -> void + def initialize(name_loc, operator_loc, value, start_offset, length) + @name_loc = name_loc + @operator_loc = operator_loc + @value = value + @start_offset = start_offset + @length = length + end + + # def accept: (visitor: Visitor) -> void + def accept(visitor) + visitor.visit_global_variable_operator_or_write_node(self) + end + + # def child_nodes: () -> Array[nil | Node] + def child_nodes + [value] + 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, location: location } + end + end + + # Represents assigning to a global variable using an operator that isn't `=`. + # + # $target += value + # ^^^^^^^^^^^^^^^^ + class GlobalVariableOperatorWriteNode < 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 operator: Symbol + attr_reader :operator + + # def initialize: (name_loc: Location, operator_loc: Location, value: Node, operator: Symbol, start_offset: Integer, length: Integer) -> void + def initialize(name_loc, operator_loc, value, operator, start_offset, length) + @name_loc = name_loc + @operator_loc = operator_loc + @value = value + @operator = operator + @start_offset = start_offset + @length = length + 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 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, operator: operator, location: location } + end + end + + # Represents referencing a global variable. + # + # $foo + # ^^^^ + class GlobalVariableReadNode < Node + # def initialize: (start_offset: Integer, length: Integer) -> void + def initialize(start_offset, length) + @start_offset = start_offset + @length = length + 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 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 + end + + # Represents writing to a global variable. + # + # $foo = 1 + # ^^^^^^^^ + class GlobalVariableWriteNode < 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 + + # def initialize: (name_loc: Location, operator_loc: Location?, value: Node?, start_offset: Integer, length: Integer) -> void + def initialize(name_loc, operator_loc, value, start_offset, length) + @name_loc = name_loc + @operator_loc = operator_loc + @value = value + @start_offset = start_offset + @length = length + 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 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, location: location } + 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, start_offset: Integer, length: Integer) -> void + def initialize(opening_loc, elements, closing_loc, start_offset, length) + @opening_loc = opening_loc + @elements = elements + @closing_loc = closing_loc + @start_offset = start_offset + @length = length + 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 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 + 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 assocs: Array[Node] + attr_reader :assocs + + # attr_reader kwrest: Node? + attr_reader :kwrest + + # attr_reader opening_loc: Location? + attr_reader :opening_loc + + # attr_reader closing_loc: Location? + attr_reader :closing_loc + + # def initialize: (constant: Node?, assocs: Array[Node], kwrest: Node?, opening_loc: Location?, closing_loc: Location?, start_offset: Integer, length: Integer) -> void + def initialize(constant, assocs, kwrest, opening_loc, closing_loc, start_offset, length) + @constant = constant + @assocs = assocs + @kwrest = kwrest + @opening_loc = opening_loc + @closing_loc = closing_loc + @start_offset = start_offset + @length = length + 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, *assocs, kwrest] + 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, assocs: assocs, kwrest: kwrest, opening_loc: opening_loc, closing_loc: closing_loc, location: location } + 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 statements: Node? + 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, statements: Node?, consequent: Node?, end_keyword_loc: Location?, start_offset: Integer, length: Integer) -> void + def initialize(if_keyword_loc, predicate, statements, consequent, end_keyword_loc, start_offset, length) + @if_keyword_loc = if_keyword_loc + @predicate = predicate + @statements = statements + @consequent = consequent + @end_keyword_loc = end_keyword_loc + @start_offset = start_offset + @length = length + end + + # def accept: (visitor: Visitor) -> void + def accept(visitor) + visitor.visit_if_node(self) + end + + # def child_nodes: () -> Array[nil | Node] + def child_nodes + [predicate, statements, consequent] + 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, statements: statements, consequent: consequent, end_keyword_loc: end_keyword_loc, location: location } + end + end + + # Represents an imaginary number literal. + # + # 1.0i + # ^^^^ + class ImaginaryNode < Node + # attr_reader numeric: Node + attr_reader :numeric + + # def initialize: (numeric: Node, start_offset: Integer, length: Integer) -> void + def initialize(numeric, start_offset, length) + @numeric = numeric + @start_offset = start_offset + @length = length + 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 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 + 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: Node? + 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: Node?, in_loc: Location, then_loc: Location?, start_offset: Integer, length: Integer) -> void + def initialize(pattern, statements, in_loc, then_loc, start_offset, length) + @pattern = pattern + @statements = statements + @in_loc = in_loc + @then_loc = then_loc + @start_offset = start_offset + @length = length + 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 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 + end + + # Represents the use of the `&&=` operator for assignment to an instance variable. + # + # @target &&= value + # ^^^^^^^^^^^^^^^^^ + class InstanceVariableOperatorAndWriteNode < 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 + + # def initialize: (name_loc: Location, operator_loc: Location, value: Node, start_offset: Integer, length: Integer) -> void + def initialize(name_loc, operator_loc, value, start_offset, length) + @name_loc = name_loc + @operator_loc = operator_loc + @value = value + @start_offset = start_offset + @length = length + end + + # def accept: (visitor: Visitor) -> void + def accept(visitor) + visitor.visit_instance_variable_operator_and_write_node(self) + end + + # def child_nodes: () -> Array[nil | Node] + def child_nodes + [value] + 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, location: location } + end + end + + # Represents the use of the `||=` operator for assignment to an instance variable. + # + # @target ||= value + # ^^^^^^^^^^^^^^^^^ + class InstanceVariableOperatorOrWriteNode < 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 + + # def initialize: (name_loc: Location, operator_loc: Location, value: Node, start_offset: Integer, length: Integer) -> void + def initialize(name_loc, operator_loc, value, start_offset, length) + @name_loc = name_loc + @operator_loc = operator_loc + @value = value + @start_offset = start_offset + @length = length + end + + # def accept: (visitor: Visitor) -> void + def accept(visitor) + visitor.visit_instance_variable_operator_or_write_node(self) + end + + # def child_nodes: () -> Array[nil | Node] + def child_nodes + [value] + 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, location: location } + end + end + + # Represents assigning to an instance variable using an operator that isn't `=`. + # + # @target += value + # ^^^^^^^^^^^^^^^^ + class InstanceVariableOperatorWriteNode < 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 operator: Symbol + attr_reader :operator + + # def initialize: (name_loc: Location, operator_loc: Location, value: Node, operator: Symbol, start_offset: Integer, length: Integer) -> void + def initialize(name_loc, operator_loc, value, operator, start_offset, length) + @name_loc = name_loc + @operator_loc = operator_loc + @value = value + @operator = operator + @start_offset = start_offset + @length = length + 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 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, operator: operator, location: location } + end + end + + # Represents referencing an instance variable. + # + # @foo + # ^^^^ + class InstanceVariableReadNode < Node + # def initialize: (start_offset: Integer, length: Integer) -> void + def initialize(start_offset, length) + @start_offset = start_offset + @length = length + 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 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 + end + + # Represents writing to an instance variable. + # + # @foo = 1 + # ^^^^^^^^ + class InstanceVariableWriteNode < Node + # 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_loc: Location, value: Node?, operator_loc: Location?, start_offset: Integer, length: Integer) -> void + def initialize(name_loc, value, operator_loc, start_offset, length) + @name_loc = name_loc + @value = value + @operator_loc = operator_loc + @start_offset = start_offset + @length = length + 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 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, value: value, operator_loc: operator_loc, location: location } + end + end + + # Represents an integer number literal. + # + # 1 + # ^ + class IntegerNode < Node + # def initialize: (start_offset: Integer, length: Integer) -> void + def initialize(start_offset, length) + @start_offset = start_offset + @length = length + 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 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 + end + + # Represents a regular expression literal that contains interpolation. + # + # /foo #{bar} baz/ + # ^^^^^^^^^^^^^^^^ + class InterpolatedRegularExpressionNode < 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 + + # attr_reader flags: Integer + attr_reader :flags + + # def initialize: (opening_loc: Location, parts: Array[Node], closing_loc: Location, flags: Integer, start_offset: Integer, length: Integer) -> void + def initialize(opening_loc, parts, closing_loc, flags, start_offset, length) + @opening_loc = opening_loc + @parts = parts + @closing_loc = closing_loc + @flags = flags + @start_offset = start_offset + @length = length + end + + # def accept: (visitor: Visitor) -> void + def accept(visitor) + visitor.visit_interpolated_regular_expression_node(self) + end + + # def child_nodes: () -> Array[nil | Node] + def child_nodes + [*parts] + 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, flags: flags, location: location } + 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?, start_offset: Integer, length: Integer) -> void + def initialize(opening_loc, parts, closing_loc, start_offset, length) + @opening_loc = opening_loc + @parts = parts + @closing_loc = closing_loc + @start_offset = start_offset + @length = length + end + + # def accept: (visitor: Visitor) -> void + def accept(visitor) + visitor.visit_interpolated_string_node(self) + end + + # def child_nodes: () -> Array[nil | Node] + def child_nodes + [*parts] + 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 + 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?, start_offset: Integer, length: Integer) -> void + def initialize(opening_loc, parts, closing_loc, start_offset, length) + @opening_loc = opening_loc + @parts = parts + @closing_loc = closing_loc + @start_offset = start_offset + @length = length + end + + # def accept: (visitor: Visitor) -> void + def accept(visitor) + visitor.visit_interpolated_symbol_node(self) + end + + # def child_nodes: () -> Array[nil | Node] + def child_nodes + [*parts] + 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 + 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, start_offset: Integer, length: Integer) -> void + def initialize(opening_loc, parts, closing_loc, start_offset, length) + @opening_loc = opening_loc + @parts = parts + @closing_loc = closing_loc + @start_offset = start_offset + @length = length + end + + # def accept: (visitor: Visitor) -> void + def accept(visitor) + visitor.visit_interpolated_x_string_node(self) + end + + # def child_nodes: () -> Array[nil | Node] + def child_nodes + [*parts] + 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 + end + + # Represents a hash literal without opening and closing braces. + # + # foo(a: b) + # ^^^^ + class KeywordHashNode < Node + # attr_reader elements: Array[Node] + attr_reader :elements + + # def initialize: (elements: Array[Node], start_offset: Integer, length: Integer) -> void + def initialize(elements, start_offset, length) + @elements = elements + @start_offset = start_offset + @length = length + 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 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) + { elements: elements, location: location } + end + end + + # Represents a keyword parameter to a method, block, or lambda definition. + # + # def a(b:) + # ^^ + # end + # + # def a(b: 1) + # ^^^^ + # end + class KeywordParameterNode < Node + # attr_reader name_loc: Location + attr_reader :name_loc + + # attr_reader value: Node? + attr_reader :value + + # def initialize: (name_loc: Location, value: Node?, start_offset: Integer, length: Integer) -> void + def initialize(name_loc, value, start_offset, length) + @name_loc = name_loc + @value = value + @start_offset = start_offset + @length = length + end + + # def accept: (visitor: Visitor) -> void + def accept(visitor) + visitor.visit_keyword_parameter_node(self) + end + + # def child_nodes: () -> Array[nil | Node] + def child_nodes + [value] + 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, value: value, location: location } + end + end + + # Represents a keyword rest parameter to a method, block, or lambda definition. + # + # def a(**b) + # ^^^ + # end + class KeywordRestParameterNode < Node + # attr_reader operator_loc: Location + attr_reader :operator_loc + + # attr_reader name_loc: Location? + attr_reader :name_loc + + # def initialize: (operator_loc: Location, name_loc: Location?, start_offset: Integer, length: Integer) -> void + def initialize(operator_loc, name_loc, start_offset, length) + @operator_loc = operator_loc + @name_loc = name_loc + @start_offset = start_offset + @length = length + 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 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, name_loc: name_loc, location: location } + 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 opening_loc: Location + attr_reader :opening_loc + + # attr_reader parameters: Node? + attr_reader :parameters + + # attr_reader statements: Node? + attr_reader :statements + + # def initialize: (locals: Array[Symbol], opening_loc: Location, parameters: Node?, statements: Node?, start_offset: Integer, length: Integer) -> void + def initialize(locals, opening_loc, parameters, statements, start_offset, length) + @locals = locals + @opening_loc = opening_loc + @parameters = parameters + @statements = statements + @start_offset = start_offset + @length = length + 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, statements] + 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, opening_loc: opening_loc, parameters: parameters, statements: statements, location: location } + end + end + + # Represents the use of the `&&=` operator for assignment to a local variable. + # + # target &&= value + # ^^^^^^^^^^^^^^^^ + class LocalVariableOperatorAndWriteNode < 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 constant_id: Symbol + attr_reader :constant_id + + # def initialize: (name_loc: Location, operator_loc: Location, value: Node, constant_id: Symbol, start_offset: Integer, length: Integer) -> void + def initialize(name_loc, operator_loc, value, constant_id, start_offset, length) + @name_loc = name_loc + @operator_loc = operator_loc + @value = value + @constant_id = constant_id + @start_offset = start_offset + @length = length + end + + # def accept: (visitor: Visitor) -> void + def accept(visitor) + visitor.visit_local_variable_operator_and_write_node(self) + end + + # def child_nodes: () -> Array[nil | Node] + def child_nodes + [value] + 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, constant_id: constant_id, location: location } + end + end + + # Represents the use of the `||=` operator for assignment to a local variable. + # + # target ||= value + # ^^^^^^^^^^^^^^^^ + class LocalVariableOperatorOrWriteNode < 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 constant_id: Symbol + attr_reader :constant_id + + # def initialize: (name_loc: Location, operator_loc: Location, value: Node, constant_id: Symbol, start_offset: Integer, length: Integer) -> void + def initialize(name_loc, operator_loc, value, constant_id, start_offset, length) + @name_loc = name_loc + @operator_loc = operator_loc + @value = value + @constant_id = constant_id + @start_offset = start_offset + @length = length + end + + # def accept: (visitor: Visitor) -> void + def accept(visitor) + visitor.visit_local_variable_operator_or_write_node(self) + end + + # def child_nodes: () -> Array[nil | Node] + def child_nodes + [value] + 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, constant_id: constant_id, location: location } + 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 constant_id: Symbol + attr_reader :constant_id + + # attr_reader operator_id: Symbol + attr_reader :operator_id + + # def initialize: (name_loc: Location, operator_loc: Location, value: Node, constant_id: Symbol, operator_id: Symbol, start_offset: Integer, length: Integer) -> void + def initialize(name_loc, operator_loc, value, constant_id, operator_id, start_offset, length) + @name_loc = name_loc + @operator_loc = operator_loc + @value = value + @constant_id = constant_id + @operator_id = operator_id + @start_offset = start_offset + @length = length + 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 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, constant_id: constant_id, operator_id: operator_id, location: location } + 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 constant_id: Symbol + attr_reader :constant_id + + # attr_reader depth: Integer + attr_reader :depth + + # def initialize: (constant_id: Symbol, depth: Integer, start_offset: Integer, length: Integer) -> void + def initialize(constant_id, depth, start_offset, length) + @constant_id = constant_id + @depth = depth + @start_offset = start_offset + @length = length + 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 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_id: constant_id, depth: depth, location: location } + end + end + + # Represents writing to a local variable. + # + # foo = 1 + # ^^^^^^^ + class LocalVariableWriteNode < Node + # attr_reader constant_id: Symbol + attr_reader :constant_id + + # attr_reader depth: Integer + attr_reader :depth + + # attr_reader value: Node? + attr_reader :value + + # attr_reader name_loc: Location + attr_reader :name_loc + + # attr_reader operator_loc: Location? + attr_reader :operator_loc + + # def initialize: (constant_id: Symbol, depth: Integer, value: Node?, name_loc: Location, operator_loc: Location?, start_offset: Integer, length: Integer) -> void + def initialize(constant_id, depth, value, name_loc, operator_loc, start_offset, length) + @constant_id = constant_id + @depth = depth + @value = value + @name_loc = name_loc + @operator_loc = operator_loc + @start_offset = start_offset + @length = length + 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 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_id: constant_id, depth: depth, value: value, name_loc: name_loc, operator_loc: operator_loc, location: location } + 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, start_offset: Integer, length: Integer) -> void + def initialize(value, pattern, operator_loc, start_offset, length) + @value = value + @pattern = pattern + @operator_loc = operator_loc + @start_offset = start_offset + @length = length + 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 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 + 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, start_offset: Integer, length: Integer) -> void + def initialize(value, pattern, operator_loc, start_offset, length) + @value = value + @pattern = pattern + @operator_loc = operator_loc + @start_offset = start_offset + @length = length + 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 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 + end + + # Represents a node that is missing from the source and results in a syntax + # error. + class MissingNode < Node + # def initialize: (start_offset: Integer, length: Integer) -> void + def initialize(start_offset, length) + @start_offset = start_offset + @length = length + 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 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 + 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 statements: Node? + attr_reader :statements + + # attr_reader end_keyword_loc: Location + attr_reader :end_keyword_loc + + # def initialize: (locals: Array[Symbol], module_keyword_loc: Location, constant_path: Node, statements: Node?, end_keyword_loc: Location, start_offset: Integer, length: Integer) -> void + def initialize(locals, module_keyword_loc, constant_path, statements, end_keyword_loc, start_offset, length) + @locals = locals + @module_keyword_loc = module_keyword_loc + @constant_path = constant_path + @statements = statements + @end_keyword_loc = end_keyword_loc + @start_offset = start_offset + @length = length + 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, statements] + 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, statements: statements, end_keyword_loc: end_keyword_loc, location: location } + end + end + + # Represents a multi-target expression. + # + # a, b, c = 1, 2, 3 + # ^^^^^^^^^^^^^^^^^ + class MultiWriteNode < Node + # attr_reader targets: Array[Node] + attr_reader :targets + + # attr_reader operator_loc: Location? + attr_reader :operator_loc + + # attr_reader value: Node? + attr_reader :value + + # attr_reader lparen_loc: Location? + attr_reader :lparen_loc + + # attr_reader rparen_loc: Location? + attr_reader :rparen_loc + + # def initialize: (targets: Array[Node], operator_loc: Location?, value: Node?, lparen_loc: Location?, rparen_loc: Location?, start_offset: Integer, length: Integer) -> void + def initialize(targets, operator_loc, value, lparen_loc, rparen_loc, start_offset, length) + @targets = targets + @operator_loc = operator_loc + @value = value + @lparen_loc = lparen_loc + @rparen_loc = rparen_loc + @start_offset = start_offset + @length = length + 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 + [*targets, value] + 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) + { targets: targets, operator_loc: operator_loc, value: value, lparen_loc: lparen_loc, rparen_loc: rparen_loc, location: location } + end + end + + # Represents the use of the `next` keyword. + # + # next 1 + # ^^^^^^ + class NextNode < Node + # attr_reader arguments: Node? + attr_reader :arguments + + # attr_reader keyword_loc: Location + attr_reader :keyword_loc + + # def initialize: (arguments: Node?, keyword_loc: Location, start_offset: Integer, length: Integer) -> void + def initialize(arguments, keyword_loc, start_offset, length) + @arguments = arguments + @keyword_loc = keyword_loc + @start_offset = start_offset + @length = length + 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 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 + end + + # Represents the use of the `nil` keyword. + # + # nil + # ^^^ + class NilNode < Node + # def initialize: (start_offset: Integer, length: Integer) -> void + def initialize(start_offset, length) + @start_offset = start_offset + @length = length + 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 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 + 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, start_offset: Integer, length: Integer) -> void + def initialize(operator_loc, keyword_loc, start_offset, length) + @operator_loc = operator_loc + @keyword_loc = keyword_loc + @start_offset = start_offset + @length = length + 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 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 + end + + # Represents reading a numbered reference to a capture in the previous match. + # + # $1 + # ^^ + class NumberedReferenceReadNode < Node + # def initialize: (start_offset: Integer, length: Integer) -> void + def initialize(start_offset, length) + @start_offset = start_offset + @length = length + 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 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 + end + + # Represents an optional parameter to a method, block, or lambda definition. + # + # def a(b = 1) + # ^^^^^ + # end + class OptionalParameterNode < Node + # attr_reader constant_id: Symbol + attr_reader :constant_id + + # 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: (constant_id: Symbol, name_loc: Location, operator_loc: Location, value: Node, start_offset: Integer, length: Integer) -> void + def initialize(constant_id, name_loc, operator_loc, value, start_offset, length) + @constant_id = constant_id + @name_loc = name_loc + @operator_loc = operator_loc + @value = value + @start_offset = start_offset + @length = length + 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 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_id: constant_id, name_loc: name_loc, operator_loc: operator_loc, value: value, location: location } + 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, start_offset: Integer, length: Integer) -> void + def initialize(left, right, operator_loc, start_offset, length) + @left = left + @right = right + @operator_loc = operator_loc + @start_offset = start_offset + @length = length + 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 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 + 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 posts: Array[Node] + attr_reader :posts + + # attr_reader rest: Node? + attr_reader :rest + + # attr_reader keywords: Array[Node] + attr_reader :keywords + + # attr_reader keyword_rest: Node? + attr_reader :keyword_rest + + # attr_reader block: Node? + attr_reader :block + + # def initialize: (requireds: Array[Node], optionals: Array[Node], posts: Array[Node], rest: Node?, keywords: Array[Node], keyword_rest: Node?, block: Node?, start_offset: Integer, length: Integer) -> void + def initialize(requireds, optionals, posts, rest, keywords, keyword_rest, block, start_offset, length) + @requireds = requireds + @optionals = optionals + @posts = posts + @rest = rest + @keywords = keywords + @keyword_rest = keyword_rest + @block = block + @start_offset = start_offset + @length = length + 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, *posts, rest, *keywords, keyword_rest, block] + 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, posts: posts, rest: rest, keywords: keywords, keyword_rest: keyword_rest, block: block, location: location } + end + end + + # Represents a parentesized expression + # + # (10 + 34) + # ^^^^^^^^^ + class ParenthesesNode < Node + # attr_reader statements: Node? + attr_reader :statements + + # attr_reader opening_loc: Location + attr_reader :opening_loc + + # attr_reader closing_loc: Location + attr_reader :closing_loc + + # def initialize: (statements: Node?, opening_loc: Location, closing_loc: Location, start_offset: Integer, length: Integer) -> void + def initialize(statements, opening_loc, closing_loc, start_offset, length) + @statements = statements + @opening_loc = opening_loc + @closing_loc = closing_loc + @start_offset = start_offset + @length = length + end + + # def accept: (visitor: Visitor) -> void + def accept(visitor) + visitor.visit_parentheses_node(self) + end + + # def child_nodes: () -> Array[nil | Node] + def child_nodes + [statements] + 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, opening_loc: opening_loc, closing_loc: closing_loc, location: location } + 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, start_offset: Integer, length: Integer) -> void + def initialize(expression, operator_loc, lparen_loc, rparen_loc, start_offset, length) + @expression = expression + @operator_loc = operator_loc + @lparen_loc = lparen_loc + @rparen_loc = rparen_loc + @start_offset = start_offset + @length = length + 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 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 + 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, start_offset: Integer, length: Integer) -> void + def initialize(variable, operator_loc, start_offset, length) + @variable = variable + @operator_loc = operator_loc + @start_offset = start_offset + @length = length + 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 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 + end + + # Represents the use of the `END` keyword. + # + # END { foo } + # ^^^^^^^^^^^ + class PostExecutionNode < Node + # attr_reader statements: Node? + 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: Node?, keyword_loc: Location, opening_loc: Location, closing_loc: Location, start_offset: Integer, length: Integer) -> void + def initialize(statements, keyword_loc, opening_loc, closing_loc, start_offset, length) + @statements = statements + @keyword_loc = keyword_loc + @opening_loc = opening_loc + @closing_loc = closing_loc + @start_offset = start_offset + @length = length + 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 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 + end + + # Represents the use of the `BEGIN` keyword. + # + # BEGIN { foo } + # ^^^^^^^^^^^^^ + class PreExecutionNode < Node + # attr_reader statements: Node? + 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: Node?, keyword_loc: Location, opening_loc: Location, closing_loc: Location, start_offset: Integer, length: Integer) -> void + def initialize(statements, keyword_loc, opening_loc, closing_loc, start_offset, length) + @statements = statements + @keyword_loc = keyword_loc + @opening_loc = opening_loc + @closing_loc = closing_loc + @start_offset = start_offset + @length = length + 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 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 + end + + # The top level node of any parse tree. + class ProgramNode < Node + # attr_reader locals: Array[Symbol] + attr_reader :locals + + # attr_reader statements: Node + attr_reader :statements + + # def initialize: (locals: Array[Symbol], statements: Node, start_offset: Integer, length: Integer) -> void + def initialize(locals, statements, start_offset, length) + @locals = locals + @statements = statements + @start_offset = start_offset + @length = length + 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 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 + end + + # Represents the use of the `..` or `...` operators. + # + # 1..2 + # ^^^^ + # + # c if a =~ /left/ ... b =~ /right/ + # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + class RangeNode < Node + # attr_reader left: Node? + attr_reader :left + + # attr_reader right: Node? + attr_reader :right + + # attr_reader operator_loc: Location + attr_reader :operator_loc + + # attr_reader flags: Integer + attr_reader :flags + + # def initialize: (left: Node?, right: Node?, operator_loc: Location, flags: Integer, start_offset: Integer, length: Integer) -> void + def initialize(left, right, operator_loc, flags, start_offset, length) + @left = left + @right = right + @operator_loc = operator_loc + @flags = flags + @start_offset = start_offset + @length = length + 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 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, flags: flags, location: location } + end + end + + # Represents a rational number literal. + # + # 1.0r + # ^^^^ + class RationalNode < Node + # attr_reader numeric: Node + attr_reader :numeric + + # def initialize: (numeric: Node, start_offset: Integer, length: Integer) -> void + def initialize(numeric, start_offset, length) + @numeric = numeric + @start_offset = start_offset + @length = length + 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 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 + end + + # Represents the use of the `redo` keyword. + # + # redo + # ^^^^ + class RedoNode < Node + # def initialize: (start_offset: Integer, length: Integer) -> void + def initialize(start_offset, length) + @start_offset = start_offset + @length = length + 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 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 + end + + # Represents a regular expression literal with no interpolation. + # + # /foo/i + # ^^^^^^ + class RegularExpressionNode < Node + # 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 + + # attr_reader flags: Integer + attr_reader :flags + + # def initialize: (opening_loc: Location, content_loc: Location, closing_loc: Location, unescaped: String, flags: Integer, start_offset: Integer, length: Integer) -> void + def initialize(opening_loc, content_loc, closing_loc, unescaped, flags, start_offset, length) + @opening_loc = opening_loc + @content_loc = content_loc + @closing_loc = closing_loc + @unescaped = unescaped + @flags = flags + @start_offset = start_offset + @length = length + 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 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, content_loc: content_loc, closing_loc: closing_loc, unescaped: unescaped, flags: flags, location: location } + end + end + + # Represents a destructured required parameter node. + # + # def foo((bar, baz)) + # ^^^^^^^^^^ + # end + class RequiredDestructuredParameterNode < Node + # attr_reader parameters: Array[Node] + attr_reader :parameters + + # attr_reader opening_loc: Location + attr_reader :opening_loc + + # attr_reader closing_loc: Location + attr_reader :closing_loc + + # def initialize: (parameters: Array[Node], opening_loc: Location, closing_loc: Location, start_offset: Integer, length: Integer) -> void + def initialize(parameters, opening_loc, closing_loc, start_offset, length) + @parameters = parameters + @opening_loc = opening_loc + @closing_loc = closing_loc + @start_offset = start_offset + @length = length + end + + # def accept: (visitor: Visitor) -> void + def accept(visitor) + visitor.visit_required_destructured_parameter_node(self) + end + + # def child_nodes: () -> Array[nil | Node] + def child_nodes + [*parameters] + 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, opening_loc: opening_loc, closing_loc: closing_loc, location: location } + end + end + + # Represents a required parameter to a method, block, or lambda definition. + # + # def a(b) + # ^ + # end + class RequiredParameterNode < Node + # attr_reader constant_id: Symbol + attr_reader :constant_id + + # def initialize: (constant_id: Symbol, start_offset: Integer, length: Integer) -> void + def initialize(constant_id, start_offset, length) + @constant_id = constant_id + @start_offset = start_offset + @length = length + 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 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_id: constant_id, location: location } + 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, start_offset: Integer, length: Integer) -> void + def initialize(expression, keyword_loc, rescue_expression, start_offset, length) + @expression = expression + @keyword_loc = keyword_loc + @rescue_expression = rescue_expression + @start_offset = start_offset + @length = length + end + + # def accept: (visitor: Visitor) -> void + def accept(visitor) + visitor.visit_rescue_modifier_node(self) + end + + # def child_nodes: () -> Array[nil | Node] + def child_nodes + [expression, rescue_expression] + 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 + end + + # Represents a rescue statement. + # + # begin + # rescue + # foo + # ^^^^^^ + # end + 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 exception: Node? + attr_reader :exception + + # attr_reader statements: Node? + attr_reader :statements + + # attr_reader consequent: Node? + attr_reader :consequent + + # def initialize: (keyword_loc: Location, exceptions: Array[Node], operator_loc: Location?, exception: Node?, statements: Node?, consequent: Node?, start_offset: Integer, length: Integer) -> void + def initialize(keyword_loc, exceptions, operator_loc, exception, statements, consequent, start_offset, length) + @keyword_loc = keyword_loc + @exceptions = exceptions + @operator_loc = operator_loc + @exception = exception + @statements = statements + @consequent = consequent + @start_offset = start_offset + @length = length + 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, exception, statements, consequent] + 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, exception: exception, statements: statements, consequent: consequent, location: location } + end + end + + # Represents a rest parameter to a method, block, or lambda definition. + # + # def a(*b) + # ^^ + # end + class RestParameterNode < Node + # attr_reader operator_loc: Location + attr_reader :operator_loc + + # attr_reader name_loc: Location? + attr_reader :name_loc + + # def initialize: (operator_loc: Location, name_loc: Location?, start_offset: Integer, length: Integer) -> void + def initialize(operator_loc, name_loc, start_offset, length) + @operator_loc = operator_loc + @name_loc = name_loc + @start_offset = start_offset + @length = length + 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 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, name_loc: name_loc, location: location } + end + end + + # Represents the use of the `retry` keyword. + # + # retry + # ^^^^^ + class RetryNode < Node + # def initialize: (start_offset: Integer, length: Integer) -> void + def initialize(start_offset, length) + @start_offset = start_offset + @length = length + 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 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 + 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: Node? + attr_reader :arguments + + # def initialize: (keyword_loc: Location, arguments: Node?, start_offset: Integer, length: Integer) -> void + def initialize(keyword_loc, arguments, start_offset, length) + @keyword_loc = keyword_loc + @arguments = arguments + @start_offset = start_offset + @length = length + 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 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 + end + + # Represents the `self` keyword. + # + # self + # ^^^^ + class SelfNode < Node + # def initialize: (start_offset: Integer, length: Integer) -> void + def initialize(start_offset, length) + @start_offset = start_offset + @length = length + 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 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 + 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 statements: Node? + attr_reader :statements + + # 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, statements: Node?, end_keyword_loc: Location, start_offset: Integer, length: Integer) -> void + def initialize(locals, class_keyword_loc, operator_loc, expression, statements, end_keyword_loc, start_offset, length) + @locals = locals + @class_keyword_loc = class_keyword_loc + @operator_loc = operator_loc + @expression = expression + @statements = statements + @end_keyword_loc = end_keyword_loc + @start_offset = start_offset + @length = length + 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, statements] + 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, statements: statements, end_keyword_loc: end_keyword_loc, location: location } + end + end + + # Represents the use of the `__ENCODING__` keyword. + # + # __ENCODING__ + # ^^^^^^^^^^^^ + class SourceEncodingNode < Node + # def initialize: (start_offset: Integer, length: Integer) -> void + def initialize(start_offset, length) + @start_offset = start_offset + @length = length + 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 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 + end + + # Represents the use of the `__FILE__` keyword. + # + # __FILE__ + # ^^^^^^^^ + class SourceFileNode < Node + # attr_reader filepath: String + attr_reader :filepath + + # def initialize: (filepath: String, start_offset: Integer, length: Integer) -> void + def initialize(filepath, start_offset, length) + @filepath = filepath + @start_offset = start_offset + @length = length + 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 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 + end + + # Represents the use of the `__LINE__` keyword. + # + # __LINE__ + # ^^^^^^^^ + class SourceLineNode < Node + # def initialize: (start_offset: Integer, length: Integer) -> void + def initialize(start_offset, length) + @start_offset = start_offset + @length = length + 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 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 + 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?, start_offset: Integer, length: Integer) -> void + def initialize(operator_loc, expression, start_offset, length) + @operator_loc = operator_loc + @expression = expression + @start_offset = start_offset + @length = length + 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 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 + 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], start_offset: Integer, length: Integer) -> void + def initialize(body, start_offset, length) + @body = body + @start_offset = start_offset + @length = length + 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 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 + end + + # Represents the use of compile-time string concatenation. + # + # "foo" "bar" + # ^^^^^^^^^^^ + class StringConcatNode < Node + # attr_reader left: Node + attr_reader :left + + # attr_reader right: Node + attr_reader :right + + # def initialize: (left: Node, right: Node, start_offset: Integer, length: Integer) -> void + def initialize(left, right, start_offset, length) + @left = left + @right = right + @start_offset = start_offset + @length = length + end + + # def accept: (visitor: Visitor) -> void + def accept(visitor) + visitor.visit_string_concat_node(self) + end + + # def child_nodes: () -> Array[nil | Node] + def child_nodes + [left, right] + 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, location: location } + 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 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: (opening_loc: Location?, content_loc: Location, closing_loc: Location?, unescaped: String, start_offset: Integer, length: Integer) -> void + def initialize(opening_loc, content_loc, closing_loc, unescaped, start_offset, length) + @opening_loc = opening_loc + @content_loc = content_loc + @closing_loc = closing_loc + @unescaped = unescaped + @start_offset = start_offset + @length = length + 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 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, content_loc: content_loc, closing_loc: closing_loc, unescaped: unescaped, location: location } + 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: Node? + 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: Node?, rparen_loc: Location?, block: Node?, start_offset: Integer, length: Integer) -> void + def initialize(keyword_loc, lparen_loc, arguments, rparen_loc, block, start_offset, length) + @keyword_loc = keyword_loc + @lparen_loc = lparen_loc + @arguments = arguments + @rparen_loc = rparen_loc + @block = block + @start_offset = start_offset + @length = length + 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 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 + end + + # Represents a symbol literal or a symbol contained within a `%i` list. + # + # :foo + # ^^^^ + # + # %i[foo] + # ^^^ + class SymbolNode < Node + # 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: (opening_loc: Location?, value_loc: Location, closing_loc: Location?, unescaped: String, start_offset: Integer, length: Integer) -> void + def initialize(opening_loc, value_loc, closing_loc, unescaped, start_offset, length) + @opening_loc = opening_loc + @value_loc = value_loc + @closing_loc = closing_loc + @unescaped = unescaped + @start_offset = start_offset + @length = length + 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 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, value_loc: value_loc, closing_loc: closing_loc, unescaped: unescaped, location: location } + end + end + + # Represents the use of the literal `true` keyword. + # + # true + # ^^^^ + class TrueNode < Node + # def initialize: (start_offset: Integer, length: Integer) -> void + def initialize(start_offset, length) + @start_offset = start_offset + @length = length + 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 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 + 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, start_offset: Integer, length: Integer) -> void + def initialize(names, keyword_loc, start_offset, length) + @names = names + @keyword_loc = keyword_loc + @start_offset = start_offset + @length = length + 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 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 + 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 statements: Node? + attr_reader :statements + + # attr_reader consequent: Node? + attr_reader :consequent + + # attr_reader end_keyword_loc: Location? + attr_reader :end_keyword_loc + + # def initialize: (keyword_loc: Location, predicate: Node, statements: Node?, consequent: Node?, end_keyword_loc: Location?, start_offset: Integer, length: Integer) -> void + def initialize(keyword_loc, predicate, statements, consequent, end_keyword_loc, start_offset, length) + @keyword_loc = keyword_loc + @predicate = predicate + @statements = statements + @consequent = consequent + @end_keyword_loc = end_keyword_loc + @start_offset = start_offset + @length = length + end + + # def accept: (visitor: Visitor) -> void + def accept(visitor) + visitor.visit_unless_node(self) + end + + # def child_nodes: () -> Array[nil | Node] + def child_nodes + [predicate, statements, consequent] + 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, statements: statements, consequent: consequent, end_keyword_loc: end_keyword_loc, location: location } + 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 keyword_loc: Location + attr_reader :keyword_loc + + # attr_reader predicate: Node + attr_reader :predicate + + # attr_reader statements: Node? + attr_reader :statements + + # def initialize: (keyword_loc: Location, predicate: Node, statements: Node?, start_offset: Integer, length: Integer) -> void + def initialize(keyword_loc, predicate, statements, start_offset, length) + @keyword_loc = keyword_loc + @predicate = predicate + @statements = statements + @start_offset = start_offset + @length = length + end + + # def accept: (visitor: Visitor) -> void + def accept(visitor) + visitor.visit_until_node(self) + end + + # def child_nodes: () -> Array[nil | Node] + def child_nodes + [predicate, statements] + 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, statements: statements, location: location } + end + end + + # 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: Node? + attr_reader :statements + + # def initialize: (keyword_loc: Location, conditions: Array[Node], statements: Node?, start_offset: Integer, length: Integer) -> void + def initialize(keyword_loc, conditions, statements, start_offset, length) + @keyword_loc = keyword_loc + @conditions = conditions + @statements = statements + @start_offset = start_offset + @length = length + 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 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 + 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 keyword_loc: Location + attr_reader :keyword_loc + + # attr_reader predicate: Node + attr_reader :predicate + + # attr_reader statements: Node? + attr_reader :statements + + # def initialize: (keyword_loc: Location, predicate: Node, statements: Node?, start_offset: Integer, length: Integer) -> void + def initialize(keyword_loc, predicate, statements, start_offset, length) + @keyword_loc = keyword_loc + @predicate = predicate + @statements = statements + @start_offset = start_offset + @length = length + end + + # def accept: (visitor: Visitor) -> void + def accept(visitor) + visitor.visit_while_node(self) + end + + # def child_nodes: () -> Array[nil | Node] + def child_nodes + [predicate, statements] + 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, statements: statements, location: location } + end + end + + # Represents an xstring literal with no interpolation. + # + # `foo` + # ^^^^^ + class XStringNode < Node + # 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: (opening_loc: Location, content_loc: Location, closing_loc: Location, unescaped: String, start_offset: Integer, length: Integer) -> void + def initialize(opening_loc, content_loc, closing_loc, unescaped, start_offset, length) + @opening_loc = opening_loc + @content_loc = content_loc + @closing_loc = closing_loc + @unescaped = unescaped + @start_offset = start_offset + @length = length + 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 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, content_loc: content_loc, closing_loc: closing_loc, unescaped: unescaped, location: location } + 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: Node? + attr_reader :arguments + + # attr_reader rparen_loc: Location? + attr_reader :rparen_loc + + # def initialize: (keyword_loc: Location, lparen_loc: Location?, arguments: Node?, rparen_loc: Location?, start_offset: Integer, length: Integer) -> void + def initialize(keyword_loc, lparen_loc, arguments, rparen_loc, start_offset, length) + @keyword_loc = keyword_loc + @lparen_loc = lparen_loc + @arguments = arguments + @rparen_loc = rparen_loc + @start_offset = start_offset + @length = length + 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 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 + end + + module CallNodeFlags + # &. operator + SAFE_NAVIGATION = 1 << 0 + end + + module RangeNodeFlags + # ... operator + EXCLUDE_END = 1 << 0 + end + + module RegularExpressionFlags + # i - ignores the case of characters when matching + IGNORE_CASE = 1 << 0 + + # m - allows $ to match the end of lines within strings + MULTI_LINE = 1 << 1 + + # x - ignores whitespace and allows comments in regular expressions + EXTENDED = 1 << 2 + + # e - forces the EUC-JP encoding + EUC_JP = 1 << 3 + + # n - forces the ASCII-8BIT encoding + ASCII_8BIT = 1 << 4 + + # s - forces the Windows-31J encoding + WINDOWS_31J = 1 << 5 + + # u - forces the UTF-8 encoding + UTF_8 = 1 << 6 + + # o - only interpolates values into the regular expression once + ONCE = 1 << 7 + end + + class Visitor < BasicVisitor + # Visit a AliasNode node + alias visit_alias_node visit_child_nodes + + # Visit a AlternationPatternNode node + alias visit_alternation_pattern_node visit_child_nodes + + # Visit a AndNode node + alias visit_and_node visit_child_nodes + + # Visit a ArgumentsNode node + alias visit_arguments_node visit_child_nodes + + # Visit a ArrayNode node + alias visit_array_node visit_child_nodes + + # Visit a ArrayPatternNode node + alias visit_array_pattern_node visit_child_nodes + + # Visit a AssocNode node + alias visit_assoc_node visit_child_nodes + + # Visit a AssocSplatNode node + alias visit_assoc_splat_node visit_child_nodes + + # Visit a BackReferenceReadNode node + alias visit_back_reference_read_node visit_child_nodes + + # Visit a BeginNode node + alias visit_begin_node visit_child_nodes + + # Visit a BlockArgumentNode node + alias visit_block_argument_node visit_child_nodes + + # Visit a BlockNode node + alias visit_block_node visit_child_nodes + + # Visit a BlockParameterNode node + alias visit_block_parameter_node visit_child_nodes + + # Visit a BlockParametersNode node + alias visit_block_parameters_node visit_child_nodes + + # Visit a BreakNode node + alias visit_break_node visit_child_nodes + + # Visit a CallNode node + alias visit_call_node visit_child_nodes + + # Visit a CallOperatorAndWriteNode node + alias visit_call_operator_and_write_node visit_child_nodes + + # Visit a CallOperatorOrWriteNode node + alias visit_call_operator_or_write_node visit_child_nodes + + # Visit a CallOperatorWriteNode node + alias visit_call_operator_write_node visit_child_nodes + + # Visit a CapturePatternNode node + alias visit_capture_pattern_node visit_child_nodes + + # Visit a CaseNode node + alias visit_case_node visit_child_nodes + + # Visit a ClassNode node + alias visit_class_node visit_child_nodes + + # Visit a ClassVariableOperatorAndWriteNode node + alias visit_class_variable_operator_and_write_node visit_child_nodes + + # Visit a ClassVariableOperatorOrWriteNode node + alias visit_class_variable_operator_or_write_node visit_child_nodes + + # Visit a ClassVariableOperatorWriteNode node + alias visit_class_variable_operator_write_node visit_child_nodes + + # Visit a ClassVariableReadNode node + alias visit_class_variable_read_node visit_child_nodes + + # Visit a ClassVariableWriteNode node + alias visit_class_variable_write_node visit_child_nodes + + # Visit a ConstantOperatorAndWriteNode node + alias visit_constant_operator_and_write_node visit_child_nodes + + # Visit a ConstantOperatorOrWriteNode node + alias visit_constant_operator_or_write_node visit_child_nodes + + # Visit a ConstantOperatorWriteNode node + alias visit_constant_operator_write_node visit_child_nodes + + # Visit a ConstantPathNode node + alias visit_constant_path_node visit_child_nodes + + # Visit a ConstantPathOperatorAndWriteNode node + alias visit_constant_path_operator_and_write_node visit_child_nodes + + # Visit a ConstantPathOperatorOrWriteNode node + alias visit_constant_path_operator_or_write_node visit_child_nodes + + # Visit a ConstantPathOperatorWriteNode node + alias visit_constant_path_operator_write_node visit_child_nodes + + # Visit a ConstantPathWriteNode node + alias visit_constant_path_write_node visit_child_nodes + + # Visit a ConstantReadNode node + alias visit_constant_read_node visit_child_nodes + + # Visit a DefNode node + alias visit_def_node visit_child_nodes + + # Visit a DefinedNode node + alias visit_defined_node visit_child_nodes + + # Visit a ElseNode node + alias visit_else_node visit_child_nodes + + # Visit a EmbeddedStatementsNode node + alias visit_embedded_statements_node visit_child_nodes + + # Visit a EmbeddedVariableNode node + alias visit_embedded_variable_node visit_child_nodes + + # Visit a EnsureNode node + alias visit_ensure_node visit_child_nodes + + # Visit a FalseNode node + alias visit_false_node visit_child_nodes + + # Visit a FindPatternNode node + alias visit_find_pattern_node visit_child_nodes + + # Visit a FloatNode node + alias visit_float_node visit_child_nodes + + # Visit a ForNode node + alias visit_for_node visit_child_nodes + + # Visit a ForwardingArgumentsNode node + alias visit_forwarding_arguments_node visit_child_nodes + + # Visit a ForwardingParameterNode node + alias visit_forwarding_parameter_node visit_child_nodes + + # Visit a ForwardingSuperNode node + alias visit_forwarding_super_node visit_child_nodes + + # Visit a GlobalVariableOperatorAndWriteNode node + alias visit_global_variable_operator_and_write_node visit_child_nodes + + # Visit a GlobalVariableOperatorOrWriteNode node + alias visit_global_variable_operator_or_write_node visit_child_nodes + + # Visit a GlobalVariableOperatorWriteNode node + alias visit_global_variable_operator_write_node visit_child_nodes + + # Visit a GlobalVariableReadNode node + alias visit_global_variable_read_node visit_child_nodes + + # Visit a GlobalVariableWriteNode node + alias visit_global_variable_write_node visit_child_nodes + + # Visit a HashNode node + alias visit_hash_node visit_child_nodes + + # Visit a HashPatternNode node + alias visit_hash_pattern_node visit_child_nodes + + # Visit a IfNode node + alias visit_if_node visit_child_nodes + + # Visit a ImaginaryNode node + alias visit_imaginary_node visit_child_nodes + + # Visit a InNode node + alias visit_in_node visit_child_nodes + + # Visit a InstanceVariableOperatorAndWriteNode node + alias visit_instance_variable_operator_and_write_node visit_child_nodes + + # Visit a InstanceVariableOperatorOrWriteNode node + alias visit_instance_variable_operator_or_write_node visit_child_nodes + + # Visit a InstanceVariableOperatorWriteNode node + alias visit_instance_variable_operator_write_node visit_child_nodes + + # Visit a InstanceVariableReadNode node + alias visit_instance_variable_read_node visit_child_nodes + + # Visit a InstanceVariableWriteNode node + alias visit_instance_variable_write_node visit_child_nodes + + # Visit a IntegerNode node + alias visit_integer_node visit_child_nodes + + # Visit a InterpolatedRegularExpressionNode node + alias visit_interpolated_regular_expression_node visit_child_nodes + + # Visit a InterpolatedStringNode node + alias visit_interpolated_string_node visit_child_nodes + + # Visit a InterpolatedSymbolNode node + alias visit_interpolated_symbol_node visit_child_nodes + + # Visit a InterpolatedXStringNode node + alias visit_interpolated_x_string_node visit_child_nodes + + # Visit a KeywordHashNode node + alias visit_keyword_hash_node visit_child_nodes + + # Visit a KeywordParameterNode node + alias visit_keyword_parameter_node visit_child_nodes + + # Visit a KeywordRestParameterNode node + alias visit_keyword_rest_parameter_node visit_child_nodes + + # Visit a LambdaNode node + alias visit_lambda_node visit_child_nodes + + # Visit a LocalVariableOperatorAndWriteNode node + alias visit_local_variable_operator_and_write_node visit_child_nodes + + # Visit a LocalVariableOperatorOrWriteNode node + alias visit_local_variable_operator_or_write_node visit_child_nodes + + # Visit a LocalVariableOperatorWriteNode node + alias visit_local_variable_operator_write_node visit_child_nodes + + # Visit a LocalVariableReadNode node + alias visit_local_variable_read_node visit_child_nodes + + # Visit a LocalVariableWriteNode node + alias visit_local_variable_write_node visit_child_nodes + + # Visit a MatchPredicateNode node + alias visit_match_predicate_node visit_child_nodes + + # Visit a MatchRequiredNode node + alias visit_match_required_node visit_child_nodes + + # Visit a MissingNode node + alias visit_missing_node visit_child_nodes + + # Visit a ModuleNode node + alias visit_module_node visit_child_nodes + + # Visit a MultiWriteNode node + alias visit_multi_write_node visit_child_nodes + + # Visit a NextNode node + alias visit_next_node visit_child_nodes + + # Visit a NilNode node + alias visit_nil_node visit_child_nodes + + # Visit a NoKeywordsParameterNode node + alias visit_no_keywords_parameter_node visit_child_nodes + + # Visit a NumberedReferenceReadNode node + alias visit_numbered_reference_read_node visit_child_nodes + + # Visit a OptionalParameterNode node + alias visit_optional_parameter_node visit_child_nodes + + # Visit a OrNode node + alias visit_or_node visit_child_nodes + + # Visit a ParametersNode node + alias visit_parameters_node visit_child_nodes + + # Visit a ParenthesesNode node + alias visit_parentheses_node visit_child_nodes + + # Visit a PinnedExpressionNode node + alias visit_pinned_expression_node visit_child_nodes + + # Visit a PinnedVariableNode node + alias visit_pinned_variable_node visit_child_nodes + + # Visit a PostExecutionNode node + alias visit_post_execution_node visit_child_nodes + + # Visit a PreExecutionNode node + alias visit_pre_execution_node visit_child_nodes + + # Visit a ProgramNode node + alias visit_program_node visit_child_nodes + + # Visit a RangeNode node + alias visit_range_node visit_child_nodes + + # Visit a RationalNode node + alias visit_rational_node visit_child_nodes + + # Visit a RedoNode node + alias visit_redo_node visit_child_nodes + + # Visit a RegularExpressionNode node + alias visit_regular_expression_node visit_child_nodes + + # Visit a RequiredDestructuredParameterNode node + alias visit_required_destructured_parameter_node visit_child_nodes + + # Visit a RequiredParameterNode node + alias visit_required_parameter_node visit_child_nodes + + # Visit a RescueModifierNode node + alias visit_rescue_modifier_node visit_child_nodes + + # Visit a RescueNode node + alias visit_rescue_node visit_child_nodes + + # Visit a RestParameterNode node + alias visit_rest_parameter_node visit_child_nodes + + # Visit a RetryNode node + alias visit_retry_node visit_child_nodes + + # Visit a ReturnNode node + alias visit_return_node visit_child_nodes + + # Visit a SelfNode node + alias visit_self_node visit_child_nodes + + # Visit a SingletonClassNode node + alias visit_singleton_class_node visit_child_nodes + + # Visit a SourceEncodingNode node + alias visit_source_encoding_node visit_child_nodes + + # Visit a SourceFileNode node + alias visit_source_file_node visit_child_nodes + + # Visit a SourceLineNode node + alias visit_source_line_node visit_child_nodes + + # Visit a SplatNode node + alias visit_splat_node visit_child_nodes + + # Visit a StatementsNode node + alias visit_statements_node visit_child_nodes + + # Visit a StringConcatNode node + alias visit_string_concat_node visit_child_nodes + + # Visit a StringNode node + alias visit_string_node visit_child_nodes + + # Visit a SuperNode node + alias visit_super_node visit_child_nodes + + # Visit a SymbolNode node + alias visit_symbol_node visit_child_nodes + + # Visit a TrueNode node + alias visit_true_node visit_child_nodes + + # Visit a UndefNode node + alias visit_undef_node visit_child_nodes + + # Visit a UnlessNode node + alias visit_unless_node visit_child_nodes + + # Visit a UntilNode node + alias visit_until_node visit_child_nodes + + # Visit a WhenNode node + alias visit_when_node visit_child_nodes + + # Visit a WhileNode node + alias visit_while_node visit_child_nodes + + # Visit a XStringNode node + alias visit_x_string_node visit_child_nodes + + # Visit a YieldNode node + alias visit_yield_node visit_child_nodes + end + + module DSL + private + + # Create a new Location object + def Location(start_offset = 0, length = 0) + Location.new(start_offset, length) + end + + # Create a new AliasNode node + def AliasNode(new_name, old_name, keyword_loc) + AliasNode.new(new_name, old_name, keyword_loc, 0, 0) + end + + # Create a new AlternationPatternNode node + def AlternationPatternNode(left, right, operator_loc) + AlternationPatternNode.new(left, right, operator_loc, 0, 0) + end + + # Create a new AndNode node + def AndNode(left, right, operator_loc) + AndNode.new(left, right, operator_loc, 0, 0) + end + + # Create a new ArgumentsNode node + def ArgumentsNode(arguments) + ArgumentsNode.new(arguments, 0, 0) + end + + # Create a new ArrayNode node + def ArrayNode(elements, opening_loc, closing_loc) + ArrayNode.new(elements, opening_loc, closing_loc, 0, 0) + end + + # Create a new ArrayPatternNode node + def ArrayPatternNode(constant, requireds, rest, posts, opening_loc, closing_loc) + ArrayPatternNode.new(constant, requireds, rest, posts, opening_loc, closing_loc, 0, 0) + end + + # Create a new AssocNode node + def AssocNode(key, value, operator_loc) + AssocNode.new(key, value, operator_loc, 0, 0) + end + + # Create a new AssocSplatNode node + def AssocSplatNode(value, operator_loc) + AssocSplatNode.new(value, operator_loc, 0, 0) + end + + # Create a new BackReferenceReadNode node + def BackReferenceReadNode() + BackReferenceReadNode.new(0, 0) + end + + # Create a new BeginNode node + def BeginNode(begin_keyword_loc, statements, rescue_clause, else_clause, ensure_clause, end_keyword_loc) + BeginNode.new(begin_keyword_loc, statements, rescue_clause, else_clause, ensure_clause, end_keyword_loc, 0, 0) + end + + # Create a new BlockArgumentNode node + def BlockArgumentNode(expression, operator_loc) + BlockArgumentNode.new(expression, operator_loc, 0, 0) + end + + # Create a new BlockNode node + def BlockNode(locals, parameters, statements, opening_loc, closing_loc) + BlockNode.new(locals, parameters, statements, opening_loc, closing_loc, 0, 0) + end + + # Create a new BlockParameterNode node + def BlockParameterNode(name_loc, operator_loc) + BlockParameterNode.new(name_loc, operator_loc, 0, 0) + end + + # Create a new BlockParametersNode node + def BlockParametersNode(parameters, locals, opening_loc, closing_loc) + BlockParametersNode.new(parameters, locals, opening_loc, closing_loc, 0, 0) + end + + # Create a new BreakNode node + def BreakNode(arguments, keyword_loc) + BreakNode.new(arguments, keyword_loc, 0, 0) + end + + # Create a new CallNode node + def CallNode(receiver, operator_loc, message_loc, opening_loc, arguments, closing_loc, block, flags, name) + CallNode.new(receiver, operator_loc, message_loc, opening_loc, arguments, closing_loc, block, flags, name, 0, 0) + end + + # Create a new CallOperatorAndWriteNode node + def CallOperatorAndWriteNode(target, operator_loc, value) + CallOperatorAndWriteNode.new(target, operator_loc, value, 0, 0) + end + + # Create a new CallOperatorOrWriteNode node + def CallOperatorOrWriteNode(target, value, operator_loc) + CallOperatorOrWriteNode.new(target, value, operator_loc, 0, 0) + end + + # Create a new CallOperatorWriteNode node + def CallOperatorWriteNode(target, operator_loc, value, operator_id) + CallOperatorWriteNode.new(target, operator_loc, value, operator_id, 0, 0) + end + + # Create a new CapturePatternNode node + def CapturePatternNode(value, target, operator_loc) + CapturePatternNode.new(value, target, operator_loc, 0, 0) + end + + # Create a new CaseNode node + def CaseNode(predicate, conditions, consequent, case_keyword_loc, end_keyword_loc) + CaseNode.new(predicate, conditions, consequent, case_keyword_loc, end_keyword_loc, 0, 0) + end + + # Create a new ClassNode node + def ClassNode(locals, class_keyword_loc, constant_path, inheritance_operator_loc, superclass, statements, end_keyword_loc) + ClassNode.new(locals, class_keyword_loc, constant_path, inheritance_operator_loc, superclass, statements, end_keyword_loc, 0, 0) + end + + # Create a new ClassVariableOperatorAndWriteNode node + def ClassVariableOperatorAndWriteNode(name_loc, operator_loc, value) + ClassVariableOperatorAndWriteNode.new(name_loc, operator_loc, value, 0, 0) + end + + # Create a new ClassVariableOperatorOrWriteNode node + def ClassVariableOperatorOrWriteNode(name_loc, operator_loc, value) + ClassVariableOperatorOrWriteNode.new(name_loc, operator_loc, value, 0, 0) + end + + # Create a new ClassVariableOperatorWriteNode node + def ClassVariableOperatorWriteNode(name_loc, operator_loc, value, operator) + ClassVariableOperatorWriteNode.new(name_loc, operator_loc, value, operator, 0, 0) + end + + # Create a new ClassVariableReadNode node + def ClassVariableReadNode() + ClassVariableReadNode.new(0, 0) + end + + # Create a new ClassVariableWriteNode node + def ClassVariableWriteNode(name_loc, value, operator_loc) + ClassVariableWriteNode.new(name_loc, value, operator_loc, 0, 0) + end + + # Create a new ConstantOperatorAndWriteNode node + def ConstantOperatorAndWriteNode(name_loc, operator_loc, value) + ConstantOperatorAndWriteNode.new(name_loc, operator_loc, value, 0, 0) + end + + # Create a new ConstantOperatorOrWriteNode node + def ConstantOperatorOrWriteNode(name_loc, operator_loc, value) + ConstantOperatorOrWriteNode.new(name_loc, operator_loc, value, 0, 0) + end + + # Create a new ConstantOperatorWriteNode node + def ConstantOperatorWriteNode(name_loc, operator_loc, value, operator) + ConstantOperatorWriteNode.new(name_loc, operator_loc, value, operator, 0, 0) + end + + # Create a new ConstantPathNode node + def ConstantPathNode(parent, child, delimiter_loc) + ConstantPathNode.new(parent, child, delimiter_loc, 0, 0) + end + + # Create a new ConstantPathOperatorAndWriteNode node + def ConstantPathOperatorAndWriteNode(target, operator_loc, value) + ConstantPathOperatorAndWriteNode.new(target, operator_loc, value, 0, 0) + end + + # Create a new ConstantPathOperatorOrWriteNode node + def ConstantPathOperatorOrWriteNode(target, operator_loc, value) + ConstantPathOperatorOrWriteNode.new(target, operator_loc, value, 0, 0) + end + + # Create a new ConstantPathOperatorWriteNode node + def ConstantPathOperatorWriteNode(target, operator_loc, value, operator) + ConstantPathOperatorWriteNode.new(target, operator_loc, value, operator, 0, 0) + end + + # Create a new ConstantPathWriteNode node + def ConstantPathWriteNode(target, operator_loc, value) + ConstantPathWriteNode.new(target, operator_loc, value, 0, 0) + end + + # Create a new ConstantReadNode node + def ConstantReadNode() + ConstantReadNode.new(0, 0) + end + + # Create a new DefNode node + def DefNode(name_loc, receiver, parameters, statements, locals, def_keyword_loc, operator_loc, lparen_loc, rparen_loc, equal_loc, end_keyword_loc) + DefNode.new(name_loc, receiver, parameters, statements, locals, def_keyword_loc, operator_loc, lparen_loc, rparen_loc, equal_loc, end_keyword_loc, 0, 0) + end + + # Create a new DefinedNode node + def DefinedNode(lparen_loc, value, rparen_loc, keyword_loc) + DefinedNode.new(lparen_loc, value, rparen_loc, keyword_loc, 0, 0) + end + + # Create a new ElseNode node + def ElseNode(else_keyword_loc, statements, end_keyword_loc) + ElseNode.new(else_keyword_loc, statements, end_keyword_loc, 0, 0) + end + + # Create a new EmbeddedStatementsNode node + def EmbeddedStatementsNode(opening_loc, statements, closing_loc) + EmbeddedStatementsNode.new(opening_loc, statements, closing_loc, 0, 0) + end + + # Create a new EmbeddedVariableNode node + def EmbeddedVariableNode(operator_loc, variable) + EmbeddedVariableNode.new(operator_loc, variable, 0, 0) + end + + # Create a new EnsureNode node + def EnsureNode(ensure_keyword_loc, statements, end_keyword_loc) + EnsureNode.new(ensure_keyword_loc, statements, end_keyword_loc, 0, 0) + end + + # Create a new FalseNode node + def FalseNode() + FalseNode.new(0, 0) + end + + # Create a new FindPatternNode node + def FindPatternNode(constant, left, requireds, right, opening_loc, closing_loc) + FindPatternNode.new(constant, left, requireds, right, opening_loc, closing_loc, 0, 0) + end + + # Create a new FloatNode node + def FloatNode() + FloatNode.new(0, 0) + end + + # Create a new ForNode node + def ForNode(index, collection, statements, for_keyword_loc, in_keyword_loc, do_keyword_loc, end_keyword_loc) + ForNode.new(index, collection, statements, for_keyword_loc, in_keyword_loc, do_keyword_loc, end_keyword_loc, 0, 0) + end + + # Create a new ForwardingArgumentsNode node + def ForwardingArgumentsNode() + ForwardingArgumentsNode.new(0, 0) + end + + # Create a new ForwardingParameterNode node + def ForwardingParameterNode() + ForwardingParameterNode.new(0, 0) + end + + # Create a new ForwardingSuperNode node + def ForwardingSuperNode(block) + ForwardingSuperNode.new(block, 0, 0) + end + + # Create a new GlobalVariableOperatorAndWriteNode node + def GlobalVariableOperatorAndWriteNode(name_loc, operator_loc, value) + GlobalVariableOperatorAndWriteNode.new(name_loc, operator_loc, value, 0, 0) + end + + # Create a new GlobalVariableOperatorOrWriteNode node + def GlobalVariableOperatorOrWriteNode(name_loc, operator_loc, value) + GlobalVariableOperatorOrWriteNode.new(name_loc, operator_loc, value, 0, 0) + end + + # Create a new GlobalVariableOperatorWriteNode node + def GlobalVariableOperatorWriteNode(name_loc, operator_loc, value, operator) + GlobalVariableOperatorWriteNode.new(name_loc, operator_loc, value, operator, 0, 0) + end + + # Create a new GlobalVariableReadNode node + def GlobalVariableReadNode() + GlobalVariableReadNode.new(0, 0) + end + + # Create a new GlobalVariableWriteNode node + def GlobalVariableWriteNode(name_loc, operator_loc, value) + GlobalVariableWriteNode.new(name_loc, operator_loc, value, 0, 0) + end + + # Create a new HashNode node + def HashNode(opening_loc, elements, closing_loc) + HashNode.new(opening_loc, elements, closing_loc, 0, 0) + end + + # Create a new HashPatternNode node + def HashPatternNode(constant, assocs, kwrest, opening_loc, closing_loc) + HashPatternNode.new(constant, assocs, kwrest, opening_loc, closing_loc, 0, 0) + end + + # Create a new IfNode node + def IfNode(if_keyword_loc, predicate, statements, consequent, end_keyword_loc) + IfNode.new(if_keyword_loc, predicate, statements, consequent, end_keyword_loc, 0, 0) + end + + # Create a new ImaginaryNode node + def ImaginaryNode(numeric) + ImaginaryNode.new(numeric, 0, 0) + end + + # Create a new InNode node + def InNode(pattern, statements, in_loc, then_loc) + InNode.new(pattern, statements, in_loc, then_loc, 0, 0) + end + + # Create a new InstanceVariableOperatorAndWriteNode node + def InstanceVariableOperatorAndWriteNode(name_loc, operator_loc, value) + InstanceVariableOperatorAndWriteNode.new(name_loc, operator_loc, value, 0, 0) + end + + # Create a new InstanceVariableOperatorOrWriteNode node + def InstanceVariableOperatorOrWriteNode(name_loc, operator_loc, value) + InstanceVariableOperatorOrWriteNode.new(name_loc, operator_loc, value, 0, 0) + end + + # Create a new InstanceVariableOperatorWriteNode node + def InstanceVariableOperatorWriteNode(name_loc, operator_loc, value, operator) + InstanceVariableOperatorWriteNode.new(name_loc, operator_loc, value, operator, 0, 0) + end + + # Create a new InstanceVariableReadNode node + def InstanceVariableReadNode() + InstanceVariableReadNode.new(0, 0) + end + + # Create a new InstanceVariableWriteNode node + def InstanceVariableWriteNode(name_loc, value, operator_loc) + InstanceVariableWriteNode.new(name_loc, value, operator_loc, 0, 0) + end + + # Create a new IntegerNode node + def IntegerNode() + IntegerNode.new(0, 0) + end + + # Create a new InterpolatedRegularExpressionNode node + def InterpolatedRegularExpressionNode(opening_loc, parts, closing_loc, flags) + InterpolatedRegularExpressionNode.new(opening_loc, parts, closing_loc, flags, 0, 0) + end + + # Create a new InterpolatedStringNode node + def InterpolatedStringNode(opening_loc, parts, closing_loc) + InterpolatedStringNode.new(opening_loc, parts, closing_loc, 0, 0) + end + + # Create a new InterpolatedSymbolNode node + def InterpolatedSymbolNode(opening_loc, parts, closing_loc) + InterpolatedSymbolNode.new(opening_loc, parts, closing_loc, 0, 0) + end + + # Create a new InterpolatedXStringNode node + def InterpolatedXStringNode(opening_loc, parts, closing_loc) + InterpolatedXStringNode.new(opening_loc, parts, closing_loc, 0, 0) + end + + # Create a new KeywordHashNode node + def KeywordHashNode(elements) + KeywordHashNode.new(elements, 0, 0) + end + + # Create a new KeywordParameterNode node + def KeywordParameterNode(name_loc, value) + KeywordParameterNode.new(name_loc, value, 0, 0) + end + + # Create a new KeywordRestParameterNode node + def KeywordRestParameterNode(operator_loc, name_loc) + KeywordRestParameterNode.new(operator_loc, name_loc, 0, 0) + end + + # Create a new LambdaNode node + def LambdaNode(locals, opening_loc, parameters, statements) + LambdaNode.new(locals, opening_loc, parameters, statements, 0, 0) + end + + # Create a new LocalVariableOperatorAndWriteNode node + def LocalVariableOperatorAndWriteNode(name_loc, operator_loc, value, constant_id) + LocalVariableOperatorAndWriteNode.new(name_loc, operator_loc, value, constant_id, 0, 0) + end + + # Create a new LocalVariableOperatorOrWriteNode node + def LocalVariableOperatorOrWriteNode(name_loc, operator_loc, value, constant_id) + LocalVariableOperatorOrWriteNode.new(name_loc, operator_loc, value, constant_id, 0, 0) + end + + # Create a new LocalVariableOperatorWriteNode node + def LocalVariableOperatorWriteNode(name_loc, operator_loc, value, constant_id, operator_id) + LocalVariableOperatorWriteNode.new(name_loc, operator_loc, value, constant_id, operator_id, 0, 0) + end + + # Create a new LocalVariableReadNode node + def LocalVariableReadNode(constant_id, depth) + LocalVariableReadNode.new(constant_id, depth, 0, 0) + end + + # Create a new LocalVariableWriteNode node + def LocalVariableWriteNode(constant_id, depth, value, name_loc, operator_loc) + LocalVariableWriteNode.new(constant_id, depth, value, name_loc, operator_loc, 0, 0) + end + + # Create a new MatchPredicateNode node + def MatchPredicateNode(value, pattern, operator_loc) + MatchPredicateNode.new(value, pattern, operator_loc, 0, 0) + end + + # Create a new MatchRequiredNode node + def MatchRequiredNode(value, pattern, operator_loc) + MatchRequiredNode.new(value, pattern, operator_loc, 0, 0) + end + + # Create a new MissingNode node + def MissingNode() + MissingNode.new(0, 0) + end + + # Create a new ModuleNode node + def ModuleNode(locals, module_keyword_loc, constant_path, statements, end_keyword_loc) + ModuleNode.new(locals, module_keyword_loc, constant_path, statements, end_keyword_loc, 0, 0) + end + + # Create a new MultiWriteNode node + def MultiWriteNode(targets, operator_loc, value, lparen_loc, rparen_loc) + MultiWriteNode.new(targets, operator_loc, value, lparen_loc, rparen_loc, 0, 0) + end + + # Create a new NextNode node + def NextNode(arguments, keyword_loc) + NextNode.new(arguments, keyword_loc, 0, 0) + end + + # Create a new NilNode node + def NilNode() + NilNode.new(0, 0) + end + + # Create a new NoKeywordsParameterNode node + def NoKeywordsParameterNode(operator_loc, keyword_loc) + NoKeywordsParameterNode.new(operator_loc, keyword_loc, 0, 0) + end + + # Create a new NumberedReferenceReadNode node + def NumberedReferenceReadNode() + NumberedReferenceReadNode.new(0, 0) + end + + # Create a new OptionalParameterNode node + def OptionalParameterNode(constant_id, name_loc, operator_loc, value) + OptionalParameterNode.new(constant_id, name_loc, operator_loc, value, 0, 0) + end + + # Create a new OrNode node + def OrNode(left, right, operator_loc) + OrNode.new(left, right, operator_loc, 0, 0) + end + + # Create a new ParametersNode node + def ParametersNode(requireds, optionals, posts, rest, keywords, keyword_rest, block) + ParametersNode.new(requireds, optionals, posts, rest, keywords, keyword_rest, block, 0, 0) + end + + # Create a new ParenthesesNode node + def ParenthesesNode(statements, opening_loc, closing_loc) + ParenthesesNode.new(statements, opening_loc, closing_loc, 0, 0) + end + + # Create a new PinnedExpressionNode node + def PinnedExpressionNode(expression, operator_loc, lparen_loc, rparen_loc) + PinnedExpressionNode.new(expression, operator_loc, lparen_loc, rparen_loc, 0, 0) + end + + # Create a new PinnedVariableNode node + def PinnedVariableNode(variable, operator_loc) + PinnedVariableNode.new(variable, operator_loc, 0, 0) + end + + # Create a new PostExecutionNode node + def PostExecutionNode(statements, keyword_loc, opening_loc, closing_loc) + PostExecutionNode.new(statements, keyword_loc, opening_loc, closing_loc, 0, 0) + end + + # Create a new PreExecutionNode node + def PreExecutionNode(statements, keyword_loc, opening_loc, closing_loc) + PreExecutionNode.new(statements, keyword_loc, opening_loc, closing_loc, 0, 0) + end + + # Create a new ProgramNode node + def ProgramNode(locals, statements) + ProgramNode.new(locals, statements, 0, 0) + end + + # Create a new RangeNode node + def RangeNode(left, right, operator_loc, flags) + RangeNode.new(left, right, operator_loc, flags, 0, 0) + end + + # Create a new RationalNode node + def RationalNode(numeric) + RationalNode.new(numeric, 0, 0) + end + + # Create a new RedoNode node + def RedoNode() + RedoNode.new(0, 0) + end + + # Create a new RegularExpressionNode node + def RegularExpressionNode(opening_loc, content_loc, closing_loc, unescaped, flags) + RegularExpressionNode.new(opening_loc, content_loc, closing_loc, unescaped, flags, 0, 0) + end + + # Create a new RequiredDestructuredParameterNode node + def RequiredDestructuredParameterNode(parameters, opening_loc, closing_loc) + RequiredDestructuredParameterNode.new(parameters, opening_loc, closing_loc, 0, 0) + end + + # Create a new RequiredParameterNode node + def RequiredParameterNode(constant_id) + RequiredParameterNode.new(constant_id, 0, 0) + end + + # Create a new RescueModifierNode node + def RescueModifierNode(expression, keyword_loc, rescue_expression) + RescueModifierNode.new(expression, keyword_loc, rescue_expression, 0, 0) + end + + # Create a new RescueNode node + def RescueNode(keyword_loc, exceptions, operator_loc, exception, statements, consequent) + RescueNode.new(keyword_loc, exceptions, operator_loc, exception, statements, consequent, 0, 0) + end + + # Create a new RestParameterNode node + def RestParameterNode(operator_loc, name_loc) + RestParameterNode.new(operator_loc, name_loc, 0, 0) + end + + # Create a new RetryNode node + def RetryNode() + RetryNode.new(0, 0) + end + + # Create a new ReturnNode node + def ReturnNode(keyword_loc, arguments) + ReturnNode.new(keyword_loc, arguments, 0, 0) + end + + # Create a new SelfNode node + def SelfNode() + SelfNode.new(0, 0) + end + + # Create a new SingletonClassNode node + def SingletonClassNode(locals, class_keyword_loc, operator_loc, expression, statements, end_keyword_loc) + SingletonClassNode.new(locals, class_keyword_loc, operator_loc, expression, statements, end_keyword_loc, 0, 0) + end + + # Create a new SourceEncodingNode node + def SourceEncodingNode() + SourceEncodingNode.new(0, 0) + end + + # Create a new SourceFileNode node + def SourceFileNode(filepath) + SourceFileNode.new(filepath, 0, 0) + end + + # Create a new SourceLineNode node + def SourceLineNode() + SourceLineNode.new(0, 0) + end + + # Create a new SplatNode node + def SplatNode(operator_loc, expression) + SplatNode.new(operator_loc, expression, 0, 0) + end + + # Create a new StatementsNode node + def StatementsNode(body) + StatementsNode.new(body, 0, 0) + end + + # Create a new StringConcatNode node + def StringConcatNode(left, right) + StringConcatNode.new(left, right, 0, 0) + end + + # Create a new StringNode node + def StringNode(opening_loc, content_loc, closing_loc, unescaped) + StringNode.new(opening_loc, content_loc, closing_loc, unescaped, 0, 0) + end + + # Create a new SuperNode node + def SuperNode(keyword_loc, lparen_loc, arguments, rparen_loc, block) + SuperNode.new(keyword_loc, lparen_loc, arguments, rparen_loc, block, 0, 0) + end + + # Create a new SymbolNode node + def SymbolNode(opening_loc, value_loc, closing_loc, unescaped) + SymbolNode.new(opening_loc, value_loc, closing_loc, unescaped, 0, 0) + end + + # Create a new TrueNode node + def TrueNode() + TrueNode.new(0, 0) + end + + # Create a new UndefNode node + def UndefNode(names, keyword_loc) + UndefNode.new(names, keyword_loc, 0, 0) + end + + # Create a new UnlessNode node + def UnlessNode(keyword_loc, predicate, statements, consequent, end_keyword_loc) + UnlessNode.new(keyword_loc, predicate, statements, consequent, end_keyword_loc, 0, 0) + end + + # Create a new UntilNode node + def UntilNode(keyword_loc, predicate, statements) + UntilNode.new(keyword_loc, predicate, statements, 0, 0) + end + + # Create a new WhenNode node + def WhenNode(keyword_loc, conditions, statements) + WhenNode.new(keyword_loc, conditions, statements, 0, 0) + end + + # Create a new WhileNode node + def WhileNode(keyword_loc, predicate, statements) + WhileNode.new(keyword_loc, predicate, statements, 0, 0) + end + + # Create a new XStringNode node + def XStringNode(opening_loc, content_loc, closing_loc, unescaped) + XStringNode.new(opening_loc, content_loc, closing_loc, unescaped, 0, 0) + end + + # Create a new YieldNode node + def YieldNode(keyword_loc, lparen_loc, arguments, rparen_loc) + YieldNode.new(keyword_loc, lparen_loc, arguments, rparen_loc, 0, 0) + end + end +end diff --git a/lib/yarp/pack.rb b/lib/yarp/pack.rb new file mode 100644 index 0000000000..83f5569923 --- /dev/null +++ b/lib/yarp/pack.rb @@ -0,0 +1,185 @@ +# frozen_string_literal: true + +module YARP + module Pack + %i[ + SPACE + COMMENT + INTEGER + UTF8 + BER + FLOAT + STRING_SPACE_PADDED + STRING_NULL_PADDED + STRING_NULL_TERMINATED + STRING_MSB + STRING_LSB + STRING_HEX_HIGH + STRING_HEX_LOW + STRING_UU + STRING_MIME + STRING_BASE64 + STRING_FIXED + STRING_POINTER + MOVE + BACK + NULL + + UNSIGNED + SIGNED + SIGNED_NA + + AGNOSTIC_ENDIAN + LITTLE_ENDIAN + BIG_ENDIAN + NATIVE_ENDIAN + ENDIAN_NA + + SIZE_SHORT + SIZE_INT + SIZE_LONG + SIZE_LONG_LONG + SIZE_8 + SIZE_16 + SIZE_32 + SIZE_64 + SIZE_P + SIZE_NA + + LENGTH_FIXED + LENGTH_MAX + LENGTH_RELATIVE + LENGTH_NA + ].each do |const| + const_set(const, const) + end + + class Directive + attr_reader :version, :variant, :source, :type, :signed, :endian, :size, :length_type, :length + + def initialize(version, variant, source, type, signed, endian, size, length_type, length) + @version = version + @variant = variant + @source = source + @type = type + @signed = signed + @endian = endian + @size = size + @length_type = length_type + @length = length + end + + ENDIAN_DESCRIPTIONS = { + AGNOSTIC_ENDIAN: 'agnostic', + LITTLE_ENDIAN: 'little-endian (VAX)', + BIG_ENDIAN: 'big-endian (network)', + NATIVE_ENDIAN: 'native-endian', + ENDIAN_NA: 'n/a' + } + + SIGNED_DESCRIPTIONS = { + UNSIGNED: 'unsigned', + SIGNED: 'signed', + SIGNED_NA: 'n/a' + } + + SIZE_DESCRIPTIONS = { + SIZE_SHORT: 'short', + SIZE_INT: 'int-width', + SIZE_LONG: 'long', + SIZE_LONG_LONG: 'long long', + SIZE_8: '8-bit', + SIZE_16: '16-bit', + SIZE_32: '32-bit', + SIZE_64: '64-bit', + SIZE_P: 'pointer-width' + } + + def describe + case type + when SPACE + 'whitespace' + when COMMENT + 'comment' + when INTEGER + if size == SIZE_8 + base = "#{SIGNED_DESCRIPTIONS[signed]} #{SIZE_DESCRIPTIONS[size]} integer" + else + base = "#{SIGNED_DESCRIPTIONS[signed]} #{SIZE_DESCRIPTIONS[size]} #{ENDIAN_DESCRIPTIONS[endian]} integer" + end + case length_type + when LENGTH_FIXED + if length > 1 + base + ", x#{length}" + else + base + end + when LENGTH_MAX + base + ', as many as possible' + end + when UTF8 + 'UTF-8 character' + when BER + 'BER-compressed integer' + when FLOAT + "#{SIZE_DESCRIPTIONS[size]} #{ENDIAN_DESCRIPTIONS[endian]} float" + when STRING_SPACE_PADDED + 'arbitrary binary string (space padded)' + when STRING_NULL_PADDED + 'arbitrary binary string (null padded, count is width)' + when STRING_NULL_TERMINATED + 'arbitrary binary string (null padded, count is width), except that null is added with *' + when STRING_MSB + 'bit string (MSB first)' + when STRING_LSB + 'bit string (LSB first)' + when STRING_HEX_HIGH + 'hex string (high nibble first)' + when STRING_HEX_LOW + 'hex string (low nibble first)' + when STRING_UU + 'UU-encoded string' + when STRING_MIME + 'quoted printable, MIME encoding' + when STRING_BASE64 + 'base64 encoded string' + when STRING_FIXED + 'pointer to a structure (fixed-length string)' + when STRING_POINTER + 'pointer to a null-terminated string' + when MOVE + 'move to absolute position' + when BACK + 'back up a byte' + when NULL + 'null byte' + else + raise + end + end + end + + class Format + attr_reader :directives, :encoding + + def initialize(directives, encoding) + @directives = directives + @encoding = encoding + end + + def describe + source_width = directives.map { |d| d.source.inspect.length }.max + directive_lines = directives.map do |directive| + if directive.type == SPACE + source = directive.source.inspect + else + source = directive.source + end + " #{source.ljust(source_width)} #{directive.describe}" + end + + (['Directives:'] + directive_lines + ['Encoding:', " #{encoding}"]).join("\n") + end + end + end +end diff --git a/lib/yarp/ripper_compat.rb b/lib/yarp/ripper_compat.rb new file mode 100644 index 0000000000..f29f7a1bf1 --- /dev/null +++ b/lib/yarp/ripper_compat.rb @@ -0,0 +1,174 @@ +# frozen_string_literal: true + +require "ripper" + +module YARP + # This class is meant to provide a compatibility layer between YARP and + # Ripper. It functions by parsing the entire tree first and then walking it + # and executing each of the Ripper callbacks as it goes. + # + # This class is going to necessarily be slower than the native Ripper API. It + # is meant as a stopgap until developers migrate to using YARP. It is also + # meant as a test harness for the YARP parser. + class RipperCompat + # This class mirrors the ::Ripper::SexpBuilder subclass of ::Ripper that + # returns the arrays of [type, *children]. + class SexpBuilder < RipperCompat + private + + Ripper::PARSER_EVENTS.each do |event| + define_method(:"on_#{event}") do |*args| + [event, *args] + end + end + + Ripper::SCANNER_EVENTS.each do |event| + define_method(:"on_#{event}") do |value| + [:"@#{event}", value, [lineno, column]] + end + end + end + + # This class mirrors the ::Ripper::SexpBuilderPP subclass of ::Ripper that + # returns the same values as ::Ripper::SexpBuilder except with a couple of + # niceties that flatten linked lists into arrays. + class SexpBuilderPP < SexpBuilder + private + + def _dispatch_event_new + [] + end + + def _dispatch_event_push(list, item) + list << item + list + end + + Ripper::PARSER_EVENT_TABLE.each do |event, arity| + case event + when /_new\z/ + alias :"on_#{event}" :_dispatch_event_new if arity == 0 + when /_add\z/ + alias :"on_#{event}" :_dispatch_event_push + end + end + end + + attr_reader :source, :lineno, :column + + def initialize(source) + @source = source + @result = nil + @lineno = nil + @column = nil + end + + ############################################################################ + # Public interface + ############################################################################ + + def error? + result.errors.any? + end + + def parse + result.value.accept(self) unless error? + end + + ############################################################################ + # Visitor methods + ############################################################################ + + def visit(node) + node&.accept(self) + end + + def visit_call_node(node) + if !node.opening_loc && node.arguments.arguments.length == 1 + bounds(node.receiver.location) + left = visit(node.receiver) + + bounds(node.arguments.arguments.first.location) + right = visit(node.arguments.arguments.first) + + on_binary(left, source[node.message_loc.start_offset...node.message_loc.end_offset].to_sym, right) + else + raise NotImplementedError + end + end + + def visit_integer_node(node) + bounds(node.location) + on_int(source[node.location.start_offset...node.location.end_offset]) + end + + def visit_statements_node(node) + bounds(node.location) + node.body.inject(on_stmts_new) do |stmts, stmt| + on_stmts_add(stmts, visit(stmt)) + end + end + + def visit_token(node) + bounds(node.location) + + case node.type + when :MINUS + on_op(node.value) + when :PLUS + on_op(node.value) + else + raise NotImplementedError, "Unknown token: #{node.type}" + end + end + + def visit_program_node(node) + bounds(node.location) + on_program(visit(node.statements)) + end + + ############################################################################ + # Entrypoints for subclasses + ############################################################################ + + # This is a convenience method that runs the SexpBuilder subclass parser. + def self.sexp_raw(source) + SexpBuilder.new(source).parse + end + + # This is a convenience method that runs the SexpBuilderPP subclass parser. + def self.sexp(source) + SexpBuilderPP.new(source).parse + end + + private + + # This method is responsible for updating lineno and column information + # to reflect the current node. + # + # This method could be drastically improved with some caching on the start + # of every line, but for now it's good enough. + def bounds(location) + start_offset = location.start_offset + + @lineno = source[0..start_offset].count("\n") + 1 + @column = start_offset - (source.rindex("\n", start_offset) || 0) + end + + def result + @result ||= YARP.parse(source) + end + + def _dispatch0; end + def _dispatch1(_); end + def _dispatch2(_, _); end + def _dispatch3(_, _, _); end + def _dispatch4(_, _, _, _); end + def _dispatch5(_, _, _, _, _); end + def _dispatch7(_, _, _, _, _, _, _); end + + (Ripper::SCANNER_EVENT_TABLE.merge(Ripper::PARSER_EVENT_TABLE)).each do |event, arity| + alias :"on_#{event}" :"_dispatch#{arity}" + end + end +end diff --git a/lib/yarp/serialize.rb b/lib/yarp/serialize.rb new file mode 100644 index 0000000000..f6861f24b5 --- /dev/null +++ b/lib/yarp/serialize.rb @@ -0,0 +1,367 @@ +# frozen_string_literal: true +=begin +This file is generated by the bin/template script and should not be +modified manually. See templates/lib/yarp/serialize.rb.erb +if you are looking to modify the template +=end + +require "stringio" + +module YARP + module Serialize + def self.load(source, serialized) + io = StringIO.new(serialized) + io.set_encoding(Encoding::BINARY) + + Loader.new(source, serialized, io).load + end + + class Loader + attr_reader :encoding, :source, :serialized, :io + attr_reader :constant_pool_offset, :constant_pool + + def initialize(source, serialized, io) + @encoding = Encoding::UTF_8 + + @source = source.dup + @serialized = serialized + @io = io + + @constant_pool_offset = nil + @constant_pool = nil + end + + def load + io.read(4) => "YARP" + io.read(3).unpack("C3") => [0, 4, 0] + + @encoding = Encoding.find(io.read(load_varint)) + @source = source.force_encoding(@encoding).freeze + + @constant_pool_offset = io.read(4).unpack1("L") + @constant_pool = Array.new(load_varint, nil) + + load_node + end + + private + + # variable-length integer using https://en.wikipedia.org/wiki/LEB128 + # This is also what protobuf uses: https://protobuf.dev/programming-guides/encoding/#varints + def load_varint + n = io.getbyte + if n < 128 + n + else + n -= 128 + shift = 0 + while (b = io.getbyte) >= 128 + n += (b - 128) << (shift += 7) + end + n + (b << (shift + 7)) + end + end + + def load_serialized_length + io.read(4).unpack1("L") + end + + def load_optional_node + if io.getbyte != 0 + io.pos -= 1 + load_node + end + end + + def load_string + io.read(load_varint).force_encoding(encoding) + end + + def load_location + Location.new(load_varint, load_varint) + end + + def load_optional_location + load_location if io.getbyte != 0 + end + + def load_constant + index = load_varint - 1 + constant = constant_pool[index] + + unless constant + offset = constant_pool_offset + index * 8 + + start = serialized.unpack1("L", offset: offset) + length = serialized.unpack1("L", offset: offset + 4) + + constant = source.byteslice(start, length).to_sym + constant_pool[index] = constant + end + + constant + end + + def load_node + type = io.getbyte + start_offset, length = load_varint, load_varint + + case type + when 1 then + AliasNode.new(load_node, load_node, load_location, start_offset, length) + when 2 then + AlternationPatternNode.new(load_node, load_node, load_location, start_offset, length) + when 3 then + AndNode.new(load_node, load_node, load_location, start_offset, length) + when 4 then + ArgumentsNode.new(Array.new(load_varint) { load_node }, start_offset, length) + when 5 then + ArrayNode.new(Array.new(load_varint) { load_node }, load_optional_location, load_optional_location, start_offset, length) + when 6 then + ArrayPatternNode.new(load_optional_node, Array.new(load_varint) { load_node }, load_optional_node, Array.new(load_varint) { load_node }, load_optional_location, load_optional_location, start_offset, length) + when 7 then + AssocNode.new(load_node, load_optional_node, load_optional_location, start_offset, length) + when 8 then + AssocSplatNode.new(load_optional_node, load_location, start_offset, length) + when 9 then + BackReferenceReadNode.new(start_offset, length) + when 10 then + BeginNode.new(load_optional_location, load_optional_node, load_optional_node, load_optional_node, load_optional_node, load_optional_location, start_offset, length) + when 11 then + BlockArgumentNode.new(load_optional_node, load_location, start_offset, length) + when 12 then + BlockNode.new(Array.new(load_varint) { load_constant }, load_optional_node, load_optional_node, load_location, load_location, start_offset, length) + when 13 then + BlockParameterNode.new(load_optional_location, load_location, start_offset, length) + when 14 then + BlockParametersNode.new(load_optional_node, Array.new(load_varint) { load_location }, load_optional_location, load_optional_location, start_offset, length) + when 15 then + BreakNode.new(load_optional_node, load_location, start_offset, length) + when 16 then + CallNode.new(load_optional_node, load_optional_location, load_optional_location, load_optional_location, load_optional_node, load_optional_location, load_optional_node, load_varint, load_string, start_offset, length) + when 17 then + CallOperatorAndWriteNode.new(load_node, load_location, load_node, start_offset, length) + when 18 then + CallOperatorOrWriteNode.new(load_node, load_node, load_location, start_offset, length) + when 19 then + CallOperatorWriteNode.new(load_node, load_location, load_node, load_constant, start_offset, length) + when 20 then + CapturePatternNode.new(load_node, load_node, load_location, start_offset, length) + when 21 then + CaseNode.new(load_optional_node, Array.new(load_varint) { load_node }, load_optional_node, load_location, load_location, start_offset, length) + when 22 then + ClassNode.new(Array.new(load_varint) { load_constant }, load_location, load_node, load_optional_location, load_optional_node, load_optional_node, load_location, start_offset, length) + when 23 then + ClassVariableOperatorAndWriteNode.new(load_location, load_location, load_node, start_offset, length) + when 24 then + ClassVariableOperatorOrWriteNode.new(load_location, load_location, load_node, start_offset, length) + when 25 then + ClassVariableOperatorWriteNode.new(load_location, load_location, load_node, load_constant, start_offset, length) + when 26 then + ClassVariableReadNode.new(start_offset, length) + when 27 then + ClassVariableWriteNode.new(load_location, load_optional_node, load_optional_location, start_offset, length) + when 28 then + ConstantOperatorAndWriteNode.new(load_location, load_location, load_node, start_offset, length) + when 29 then + ConstantOperatorOrWriteNode.new(load_location, load_location, load_node, start_offset, length) + when 30 then + ConstantOperatorWriteNode.new(load_location, load_location, load_node, load_constant, start_offset, length) + when 31 then + ConstantPathNode.new(load_optional_node, load_node, load_location, start_offset, length) + when 32 then + ConstantPathOperatorAndWriteNode.new(load_node, load_location, load_node, start_offset, length) + when 33 then + ConstantPathOperatorOrWriteNode.new(load_node, load_location, load_node, start_offset, length) + when 34 then + ConstantPathOperatorWriteNode.new(load_node, load_location, load_node, load_constant, start_offset, length) + when 35 then + ConstantPathWriteNode.new(load_node, load_optional_location, load_optional_node, start_offset, length) + when 36 then + ConstantReadNode.new(start_offset, length) + when 37 then + load_serialized_length + DefNode.new(load_location, load_optional_node, load_optional_node, load_optional_node, Array.new(load_varint) { load_constant }, load_location, load_optional_location, load_optional_location, load_optional_location, load_optional_location, load_optional_location, start_offset, length) + when 38 then + DefinedNode.new(load_optional_location, load_node, load_optional_location, load_location, start_offset, length) + when 39 then + ElseNode.new(load_location, load_optional_node, load_optional_location, start_offset, length) + when 40 then + EmbeddedStatementsNode.new(load_location, load_optional_node, load_location, start_offset, length) + when 41 then + EmbeddedVariableNode.new(load_location, load_node, start_offset, length) + when 42 then + EnsureNode.new(load_location, load_optional_node, load_location, start_offset, length) + when 43 then + FalseNode.new(start_offset, length) + when 44 then + FindPatternNode.new(load_optional_node, load_node, Array.new(load_varint) { load_node }, load_node, load_optional_location, load_optional_location, start_offset, length) + when 45 then + FloatNode.new(start_offset, length) + when 46 then + ForNode.new(load_node, load_node, load_optional_node, load_location, load_location, load_optional_location, load_location, start_offset, length) + when 47 then + ForwardingArgumentsNode.new(start_offset, length) + when 48 then + ForwardingParameterNode.new(start_offset, length) + when 49 then + ForwardingSuperNode.new(load_optional_node, start_offset, length) + when 50 then + GlobalVariableOperatorAndWriteNode.new(load_location, load_location, load_node, start_offset, length) + when 51 then + GlobalVariableOperatorOrWriteNode.new(load_location, load_location, load_node, start_offset, length) + when 52 then + GlobalVariableOperatorWriteNode.new(load_location, load_location, load_node, load_constant, start_offset, length) + when 53 then + GlobalVariableReadNode.new(start_offset, length) + when 54 then + GlobalVariableWriteNode.new(load_location, load_optional_location, load_optional_node, start_offset, length) + when 55 then + HashNode.new(load_location, Array.new(load_varint) { load_node }, load_location, start_offset, length) + when 56 then + HashPatternNode.new(load_optional_node, Array.new(load_varint) { load_node }, load_optional_node, load_optional_location, load_optional_location, start_offset, length) + when 57 then + IfNode.new(load_optional_location, load_node, load_optional_node, load_optional_node, load_optional_location, start_offset, length) + when 58 then + ImaginaryNode.new(load_node, start_offset, length) + when 59 then + InNode.new(load_node, load_optional_node, load_location, load_optional_location, start_offset, length) + when 60 then + InstanceVariableOperatorAndWriteNode.new(load_location, load_location, load_node, start_offset, length) + when 61 then + InstanceVariableOperatorOrWriteNode.new(load_location, load_location, load_node, start_offset, length) + when 62 then + InstanceVariableOperatorWriteNode.new(load_location, load_location, load_node, load_constant, start_offset, length) + when 63 then + InstanceVariableReadNode.new(start_offset, length) + when 64 then + InstanceVariableWriteNode.new(load_location, load_optional_node, load_optional_location, start_offset, length) + when 65 then + IntegerNode.new(start_offset, length) + when 66 then + InterpolatedRegularExpressionNode.new(load_location, Array.new(load_varint) { load_node }, load_location, load_varint, start_offset, length) + when 67 then + InterpolatedStringNode.new(load_optional_location, Array.new(load_varint) { load_node }, load_optional_location, start_offset, length) + when 68 then + InterpolatedSymbolNode.new(load_optional_location, Array.new(load_varint) { load_node }, load_optional_location, start_offset, length) + when 69 then + InterpolatedXStringNode.new(load_location, Array.new(load_varint) { load_node }, load_location, start_offset, length) + when 70 then + KeywordHashNode.new(Array.new(load_varint) { load_node }, start_offset, length) + when 71 then + KeywordParameterNode.new(load_location, load_optional_node, start_offset, length) + when 72 then + KeywordRestParameterNode.new(load_location, load_optional_location, start_offset, length) + when 73 then + LambdaNode.new(Array.new(load_varint) { load_constant }, load_location, load_optional_node, load_optional_node, start_offset, length) + when 74 then + LocalVariableOperatorAndWriteNode.new(load_location, load_location, load_node, load_constant, start_offset, length) + when 75 then + LocalVariableOperatorOrWriteNode.new(load_location, load_location, load_node, load_constant, start_offset, length) + when 76 then + LocalVariableOperatorWriteNode.new(load_location, load_location, load_node, load_constant, load_constant, start_offset, length) + when 77 then + LocalVariableReadNode.new(load_constant, load_varint, start_offset, length) + when 78 then + LocalVariableWriteNode.new(load_constant, load_varint, load_optional_node, load_location, load_optional_location, start_offset, length) + when 79 then + MatchPredicateNode.new(load_node, load_node, load_location, start_offset, length) + when 80 then + MatchRequiredNode.new(load_node, load_node, load_location, start_offset, length) + when 81 then + MissingNode.new(start_offset, length) + when 82 then + ModuleNode.new(Array.new(load_varint) { load_constant }, load_location, load_node, load_optional_node, load_location, start_offset, length) + when 83 then + MultiWriteNode.new(Array.new(load_varint) { load_node }, load_optional_location, load_optional_node, load_optional_location, load_optional_location, start_offset, length) + when 84 then + NextNode.new(load_optional_node, load_location, start_offset, length) + when 85 then + NilNode.new(start_offset, length) + when 86 then + NoKeywordsParameterNode.new(load_location, load_location, start_offset, length) + when 87 then + NumberedReferenceReadNode.new(start_offset, length) + when 88 then + OptionalParameterNode.new(load_constant, load_location, load_location, load_node, start_offset, length) + when 89 then + OrNode.new(load_node, load_node, load_location, start_offset, length) + when 90 then + ParametersNode.new(Array.new(load_varint) { load_node }, Array.new(load_varint) { load_node }, Array.new(load_varint) { load_node }, load_optional_node, Array.new(load_varint) { load_node }, load_optional_node, load_optional_node, start_offset, length) + when 91 then + ParenthesesNode.new(load_optional_node, load_location, load_location, start_offset, length) + when 92 then + PinnedExpressionNode.new(load_node, load_location, load_location, load_location, start_offset, length) + when 93 then + PinnedVariableNode.new(load_node, load_location, start_offset, length) + when 94 then + PostExecutionNode.new(load_optional_node, load_location, load_location, load_location, start_offset, length) + when 95 then + PreExecutionNode.new(load_optional_node, load_location, load_location, load_location, start_offset, length) + when 96 then + ProgramNode.new(Array.new(load_varint) { load_constant }, load_node, start_offset, length) + when 97 then + RangeNode.new(load_optional_node, load_optional_node, load_location, load_varint, start_offset, length) + when 98 then + RationalNode.new(load_node, start_offset, length) + when 99 then + RedoNode.new(start_offset, length) + when 100 then + RegularExpressionNode.new(load_location, load_location, load_location, load_string, load_varint, start_offset, length) + when 101 then + RequiredDestructuredParameterNode.new(Array.new(load_varint) { load_node }, load_location, load_location, start_offset, length) + when 102 then + RequiredParameterNode.new(load_constant, start_offset, length) + when 103 then + RescueModifierNode.new(load_node, load_location, load_node, start_offset, length) + when 104 then + RescueNode.new(load_location, Array.new(load_varint) { load_node }, load_optional_location, load_optional_node, load_optional_node, load_optional_node, start_offset, length) + when 105 then + RestParameterNode.new(load_location, load_optional_location, start_offset, length) + when 106 then + RetryNode.new(start_offset, length) + when 107 then + ReturnNode.new(load_location, load_optional_node, start_offset, length) + when 108 then + SelfNode.new(start_offset, length) + when 109 then + SingletonClassNode.new(Array.new(load_varint) { load_constant }, load_location, load_location, load_node, load_optional_node, load_location, start_offset, length) + when 110 then + SourceEncodingNode.new(start_offset, length) + when 111 then + SourceFileNode.new(load_string, start_offset, length) + when 112 then + SourceLineNode.new(start_offset, length) + when 113 then + SplatNode.new(load_location, load_optional_node, start_offset, length) + when 114 then + StatementsNode.new(Array.new(load_varint) { load_node }, start_offset, length) + when 115 then + StringConcatNode.new(load_node, load_node, start_offset, length) + when 116 then + StringNode.new(load_optional_location, load_location, load_optional_location, load_string, start_offset, length) + when 117 then + SuperNode.new(load_location, load_optional_location, load_optional_node, load_optional_location, load_optional_node, start_offset, length) + when 118 then + SymbolNode.new(load_optional_location, load_location, load_optional_location, load_string, start_offset, length) + when 119 then + TrueNode.new(start_offset, length) + when 120 then + UndefNode.new(Array.new(load_varint) { load_node }, load_location, start_offset, length) + when 121 then + UnlessNode.new(load_location, load_node, load_optional_node, load_optional_node, load_optional_location, start_offset, length) + when 122 then + UntilNode.new(load_location, load_node, load_optional_node, start_offset, length) + when 123 then + WhenNode.new(load_location, Array.new(load_varint) { load_node }, load_optional_node, start_offset, length) + when 124 then + WhileNode.new(load_location, load_node, load_optional_node, start_offset, length) + when 125 then + XStringNode.new(load_location, load_location, load_location, load_string, start_offset, length) + when 126 then + YieldNode.new(load_location, load_optional_location, load_optional_node, load_optional_location, start_offset, length) + end + end + end + end +end |
