diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3fcd1c7c6..95b02f68e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -32,7 +32,7 @@ env: # Unlike CI, which follows prism's main branch, a release is built from the prism # revision Src/Prism/Generated was generated from (Src/Prism/README.md), the one the # vendored Ruby half of prism in Src/StdLib belongs to. - PRISM_REF: c53699f7f20f6b6aa4704216fbfecec897fe419a + PRISM_REF: cd76b0d130a6f0311d168a69618197f15a912c69 jobs: package: diff --git a/README.md b/README.md index 13231e383..a99342c55 100644 --- a/README.md +++ b/README.md @@ -489,7 +489,7 @@ that has only the **runtime** installed. Build prism with the RubyInstaller DevK ``` C:\> git clone https://github.com/ruby/prism C:\prism -C:\> cd C:\prism && git checkout 531cd5e~1 +C:\> cd C:\prism && git checkout cd76b0d1 C:\prism> ruby templates\template.rb C:\prism> ridk exec make shared -j4 :: -> C:\prism\build\libprism.dll ``` diff --git a/Src/Prism/Generated/PrismLoader.Generated.cs b/Src/Prism/Generated/PrismLoader.Generated.cs index 349fa4ad7..b1a6c43c8 100644 --- a/Src/Prism/Generated/PrismLoader.Generated.cs +++ b/Src/Prism/Generated/PrismLoader.Generated.cs @@ -1349,7 +1349,7 @@ private PmNode LoadNode() { NodeId = nodeId, StartOffset = location.Start, Length = location.Length, Flags = LoadVarUInt(), OpeningLoc = LoadOptionalLocation(), - ValueLoc = LoadOptionalLocation(), + ContentLoc = LoadLocation(), ClosingLoc = LoadOptionalLocation(), Unescaped = LoadStringBytes(), }; diff --git a/Src/Prism/Generated/PrismMeta.Generated.cs b/Src/Prism/Generated/PrismMeta.Generated.cs index 7e33377a8..59599627e 100644 --- a/Src/Prism/Generated/PrismMeta.Generated.cs +++ b/Src/Prism/Generated/PrismMeta.Generated.cs @@ -173,6 +173,7 @@ public static class PrismMeta { "USTAR", "USTAR_STAR", "WORDS_SEP", + "WORDS_SEP_IMPLICIT", "XSTRING_BEGIN", "__END__", }; @@ -322,7 +323,7 @@ public static class PrismMeta { { "StatementsNode", new string[][] { new string[] { "body", "Body" } } }, { "StringNode", new string[][] { new string[] { "opening_loc", "OpeningLoc" }, new string[] { "content_loc", "ContentLoc" }, new string[] { "closing_loc", "ClosingLoc" }, new string[] { "unescaped", "Unescaped" } } }, { "SuperNode", new string[][] { new string[] { "keyword_loc", "KeywordLoc" }, new string[] { "lparen_loc", "LparenLoc" }, new string[] { "arguments", "Arguments" }, new string[] { "rparen_loc", "RparenLoc" }, new string[] { "block", "Block" } } }, - { "SymbolNode", new string[][] { new string[] { "opening_loc", "OpeningLoc" }, new string[] { "value_loc", "ValueLoc" }, new string[] { "closing_loc", "ClosingLoc" }, new string[] { "unescaped", "Unescaped" } } }, + { "SymbolNode", new string[][] { new string[] { "opening_loc", "OpeningLoc" }, new string[] { "content_loc", "ContentLoc" }, new string[] { "closing_loc", "ClosingLoc" }, new string[] { "unescaped", "Unescaped" } } }, { "TrueNode", new string[][] { } }, { "UndefNode", new string[][] { new string[] { "names", "Names" }, new string[] { "keyword_loc", "KeywordLoc" } } }, { "UnlessNode", new string[][] { new string[] { "unless_keyword_loc", "UnlessKeywordLoc" }, new string[] { "predicate", "Predicate" }, new string[] { "then_keyword_loc", "ThenKeywordLoc" }, new string[] { "statements", "Statements" }, new string[] { "else_clause", "ElseClause" }, new string[] { "end_keyword_loc", "EndKeywordLoc" } } }, diff --git a/Src/Prism/Generated/PrismNodes.Generated.cs b/Src/Prism/Generated/PrismNodes.Generated.cs index 9654bfff1..fa03bb968 100644 --- a/Src/Prism/Generated/PrismNodes.Generated.cs +++ b/Src/Prism/Generated/PrismNodes.Generated.cs @@ -1010,7 +1010,7 @@ public sealed class SuperNode : PmNode { public sealed class SymbolNode : PmNode { public PmLocation? OpeningLoc; - public PmLocation? ValueLoc; + public PmLocation ContentLoc; public PmLocation? ClosingLoc; public byte[] Unescaped; } diff --git a/Src/Prism/PrismLoader.cs b/Src/Prism/PrismLoader.cs index be3ca6565..c384bf515 100644 --- a/Src/Prism/PrismLoader.cs +++ b/Src/Prism/PrismLoader.cs @@ -74,6 +74,15 @@ private PrismLoader(byte[]/*!*/ buffer) { uint commentCount = LoadVarUInt(); for (uint i = 0; i < commentCount; i++) { LoadByte(); LoadLocation(); } + // Comment attachments: node id, comment count, then each comment's index. The + // options never ask for attach_comments, so this is empty, but the count is there. + uint attachedNodeCount = LoadVarUInt(); + for (uint i = 0; i < attachedNodeCount; i++) { + LoadVarUInt(); + uint attachedCount = LoadVarUInt(); + for (uint j = 0; j < attachedCount; j++) LoadVarUInt(); + } + uint magicCommentCount = LoadVarUInt(); for (uint i = 0; i < magicCommentCount; i++) { LoadLocation(); LoadLocation(); } diff --git a/Src/Prism/PrismParser.cs b/Src/Prism/PrismParser.cs index fdfb6c996..fe75b85f4 100644 --- a/Src/Prism/PrismParser.cs +++ b/Src/Prism/PrismParser.cs @@ -168,6 +168,7 @@ private static int ComputeDataOffset(IronRuby.Prism.Ast.PmLocation? dataLocation writer.Write((byte)(mainScript ? 1 : 0)); // main script writer.Write((byte)0); // partial script writer.Write((byte)0); // freeze + writer.Write((byte)0); // attach comments if (outerLocals != null) { writer.Write(1); // one scope writer.Write(outerLocals.Count); diff --git a/Src/Prism/README.md b/Src/Prism/README.md index b2781b5d3..9455b46b8 100644 --- a/Src/Prism/README.md +++ b/Src/Prism/README.md @@ -79,7 +79,7 @@ Build the native library first: ```sh git clone https://github.com/ruby/prism ../../../prism -cd ../../../prism && git checkout 531cd5e~1 +cd ../../../prism && git checkout cd76b0d1 ruby templates/template.rb && make shared # -> build/libprism.so ``` @@ -89,9 +89,13 @@ serializes its nodes differently and the loader walks off the end of the buffer - the symptom is a mid-parse `ArgumentError: Offset and length were out of bounds` or `TypeError: Unknown prism node type: 0` in whichever stdlib file trips over the changed node first, not a clean version error. -The tree as it stands matches prism just before -[`531cd5e`](https://github.com/ruby/prism/commit/531cd5e) ("Make -`SymbolNode#value_loc` non-optional"), which is v1.9.0 plus a few commits. +The tree as it stands matches prism +[`cd76b0d1`](https://github.com/ruby/prism/commit/cd76b0d1), v1.9.0 plus the +commits up to 2026-10-12 - including `attach_comments`, which added a byte to +the options blob and a comment-attachment list to the serialized header +without changing the serialization version, so `PrismParser.BuildOptionsData` +and `PrismLoader.Load` had to follow by hand. `release.yml`'s `PRISM_REF` +names the same commit. To check a checkout instead of guessing, regenerate into a scratch directory and diff - identical output means the shared library from that checkout is safe: diff --git a/Src/StdLib/ironruby/prism/ironruby.rb b/Src/StdLib/ironruby/prism/ironruby.rb index 523a65b4d..342c59cf6 100644 --- a/Src/StdLib/ironruby/prism/ironruby.rb +++ b/Src/StdLib/ironruby/prism/ironruby.rb @@ -44,8 +44,7 @@ def dump(source, **options) # Mirror the Prism.dump_file API by using the serialization API. def dump_file(filepath, **options) - options[:filepath] = filepath - dump_common(read_file(filepath), options) + dump_common(read_file(filepath, options), options) end # Mirror the Prism.lex API by using the serialization API. @@ -55,8 +54,7 @@ def lex(code, **options) # Mirror the Prism.lex_file API by using the serialization API. def lex_file(filepath, **options) - options[:filepath] = filepath - source = read_file(filepath) + source = read_file(filepath, options) lex_common(source, source, options) end @@ -67,8 +65,7 @@ def parse(code, **options) # Mirror the Prism.parse_file API by using the serialization API. def parse_file(filepath, **options) - options[:filepath] = filepath - source = read_file(filepath) + source = read_file(filepath, options) parse_common(source, source, options) end @@ -86,8 +83,7 @@ def parse_comments(code, **options) # Mirror the Prism.parse_file_comments API by using the serialization API. def parse_file_comments(filepath, **options) - options[:filepath] = filepath - source = read_file(filepath) + source = read_file(filepath, options) parse_comments_common(source, source, options) end @@ -98,8 +94,7 @@ def parse_lex(code, **options) # Mirror the Prism.parse_lex_file API by using the serialization API. def parse_lex_file(filepath, **options) - options[:filepath] = filepath - source = read_file(filepath) + source = read_file(filepath, options) parse_lex_common(source, source, options) end @@ -115,8 +110,7 @@ def parse_failure?(code, **options) # Mirror the Prism.parse_file_success? API by using the serialization API. def parse_file_success?(filepath, **options) - options[:filepath] = filepath - parse_success_common(read_file(filepath), options) + parse_success_common(read_file(filepath, options), options) end # Mirror the Prism.parse_file_failure? API by using the serialization API. @@ -132,8 +126,7 @@ def profile(source, **options) # Mirror the Prism.profile_file API by using the serialization API. def profile_file(filepath, **options) - options[:filepath] = filepath - LibRubyParser.serialize_parse(read_file(filepath), dump_options(options)) + LibRubyParser.serialize_parse(read_file(filepath, options), dump_options(options)) nil end @@ -147,8 +140,15 @@ def string_source(source) # Upstream maps the file through pm_source_mapped_init, which raises # Errno::EISDIR for a directory and a SystemCallError otherwise; File.binread - # raises the same errors. - def read_file(filepath) + # raises the same errors. Like upstream's PrismSource.with_file, a Pathname + # (or anything else with to_path or to_str) is accepted and the String it + # stands for is what goes into options[:filepath]. + def read_file(filepath, options) + unless filepath.is_a?(String) + filepath = filepath.to_path if filepath.respond_to?(:to_path) + filepath = filepath.to_str if filepath.respond_to?(:to_str) + end + options[:filepath] = filepath raise TypeError unless filepath.is_a?(String) File.binread(filepath) end @@ -326,7 +326,7 @@ def version_string_to_number(version) # The set of options that are understood by the parsing APIs. Note that # raise_error is not listed here because it is deleted from the options # hash by raise_error_format_type before the options are dumped. - DUMP_OPTIONS_KEYS = [:command_line, :encoding, :filepath, :freeze, :frozen_string_literal, :line, :main_script, :partial_script, :scopes, :version].freeze + DUMP_OPTIONS_KEYS = [:attach_comments, :command_line, :encoding, :filepath, :freeze, :frozen_string_literal, :line, :main_script, :partial_script, :scopes, :version].freeze private_constant :DUMP_OPTIONS_KEYS # Convert the given options into a serialized options string. @@ -378,6 +378,9 @@ def dump_options(options) template << "C" values << (options.fetch(:freeze, false) ? 1 : 0) + template << "C" + values << (options.fetch(:attach_comments, false) ? 1 : 0) + template << "L" if (scopes = options[:scopes]) values << scopes.length diff --git a/Src/StdLib/ruby/4.0/prism.rb b/Src/StdLib/ruby/4.0/prism.rb index 61540d767..922a277bd 100644 --- a/Src/StdLib/ruby/4.0/prism.rb +++ b/Src/StdLib/ruby/4.0/prism.rb @@ -103,23 +103,23 @@ def self.find(callable) # def gets: (?Integer integer) -> (String | nil) # end # - # def self.parse: (String source, ?filepath: String, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> ParseResult - # def self.profile: (String source, ?filepath: String, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> void - # def self.lex: (String source, ?filepath: String, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> LexResult - # def self.parse_lex: (String source, ?filepath: String, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> ParseLexResult - # def self.dump: (String source, ?filepath: String, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> String - # def self.parse_comments: (String source, ?filepath: String, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> Array[Comment] - # def self.parse_success?: (String source, ?filepath: String, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> bool - # def self.parse_failure?: (String source, ?filepath: String, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> bool - # def self.parse_stream: (_Stream stream, ?filepath: String, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> ParseResult - # def self.parse_file: (String filepath, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> ParseResult - # def self.profile_file: (String filepath, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> void - # def self.lex_file: (String filepath, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> LexResult - # def self.parse_lex_file: (String filepath, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> ParseLexResult - # def self.dump_file: (String filepath, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> String - # def self.parse_file_comments: (String filepath, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> Array[Comment] - # def self.parse_file_success?: (String filepath, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> bool - # def self.parse_file_failure?: (String filepath, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> bool + # def self.parse: (String source, ?filepath: String, ?attach_comments: bool, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> ParseResult + # def self.profile: (String source, ?filepath: String, ?attach_comments: bool, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> void + # def self.lex: (String source, ?filepath: String, ?attach_comments: bool, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> LexResult + # def self.parse_lex: (String source, ?filepath: String, ?attach_comments: bool, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> ParseLexResult + # def self.dump: (String source, ?filepath: String, ?attach_comments: bool, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> String + # def self.parse_comments: (String source, ?filepath: String, ?attach_comments: bool, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> Array[Comment] + # def self.parse_success?: (String source, ?filepath: String, ?attach_comments: bool, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> bool + # def self.parse_failure?: (String source, ?filepath: String, ?attach_comments: bool, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> bool + # def self.parse_stream: (_Stream stream, ?filepath: String, ?attach_comments: bool, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> ParseResult + # def self.parse_file: (path filepath, ?attach_comments: bool, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> ParseResult + # def self.profile_file: (path filepath, ?attach_comments: bool, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> void + # def self.lex_file: (path filepath, ?attach_comments: bool, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> LexResult + # def self.parse_lex_file: (path filepath, ?attach_comments: bool, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> ParseLexResult + # def self.dump_file: (path filepath, ?attach_comments: bool, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> String + # def self.parse_file_comments: (path filepath, ?attach_comments: bool, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> Array[Comment] + # def self.parse_file_success?: (path filepath, ?attach_comments: bool, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> bool + # def self.parse_file_failure?: (path filepath, ?attach_comments: bool, ?command_line: String, ?encoding: Encoding | false, ?freeze: bool, ?frozen_string_literal: bool, ?line: Integer, ?main_script: bool, ?partial_script: bool, ?raise_error: Symbol | true, ?scopes: Array[Array[Symbol]], ?version: String) -> bool end require_relative "prism/polyfill/byteindex" diff --git a/Src/StdLib/ruby/4.0/prism/dot_visitor.rb b/Src/StdLib/ruby/4.0/prism/dot_visitor.rb index 2567d6efc..d28642f3a 100644 --- a/Src/StdLib/ruby/4.0/prism/dot_visitor.rb +++ b/Src/StdLib/ruby/4.0/prism/dot_visitor.rb @@ -4360,10 +4360,8 @@ def visit_symbol_node(node) # :nodoc: table.field("opening_loc", location_inspect(opening_loc)) end - # value_loc - unless (value_loc = node.value_loc).nil? - table.field("value_loc", location_inspect(value_loc)) - end + # content_loc + table.field("content_loc", location_inspect(node.content_loc)) # closing_loc unless (closing_loc = node.closing_loc).nil? diff --git a/Src/StdLib/ruby/4.0/prism/dsl.rb b/Src/StdLib/ruby/4.0/prism/dsl.rb index e13098b0e..b501a7e9d 100644 --- a/Src/StdLib/ruby/4.0/prism/dsl.rb +++ b/Src/StdLib/ruby/4.0/prism/dsl.rb @@ -1086,9 +1086,9 @@ def super_node(source: default_source, node_id: 0, location: default_location, f # Create a new SymbolNode node. # - #: (?source: Source, ?node_id: Integer, ?location: Location, ?flags: Integer, ?opening_loc: Location?, ?value_loc: Location?, ?closing_loc: Location?, ?unescaped: String) -> SymbolNode - def symbol_node(source: default_source, node_id: 0, location: default_location, flags: 0, opening_loc: nil, value_loc: nil, closing_loc: nil, unescaped: "") - SymbolNode.new(source, node_id, location, flags, opening_loc, value_loc, closing_loc, unescaped) + #: (?source: Source, ?node_id: Integer, ?location: Location, ?flags: Integer, ?opening_loc: Location?, ?content_loc: Location, ?closing_loc: Location?, ?unescaped: String) -> SymbolNode + def symbol_node(source: default_source, node_id: 0, location: default_location, flags: 0, opening_loc: nil, content_loc: location, closing_loc: nil, unescaped: "") + SymbolNode.new(source, node_id, location, flags, opening_loc, content_loc, closing_loc, unescaped) end # Create a new TrueNode node. diff --git a/Src/StdLib/ruby/4.0/prism/ffi.rb b/Src/StdLib/ruby/4.0/prism/ffi.rb index d717925cc..013f02ca8 100644 --- a/Src/StdLib/ruby/4.0/prism/ffi.rb +++ b/Src/StdLib/ruby/4.0/prism/ffi.rb @@ -54,16 +54,18 @@ def self.resolve_type(type, callbacks) def self.load_exported_functions_from(header, *functions, callbacks) File.foreach("#{INCLUDE_DIR}/#{header}") do |line| # We only want to attempt to load exported functions. - next unless line.start_with?("PRISM_EXPORTED_FUNCTION ") + next unless line.include?("PRISM_EXPORTED_FUNCTION ") # We only want to load the functions that we are interested in. next unless functions.any? { |function| line.include?(function) } + # Strip leading attributes (PRISM_EXPORTED_FUNCTION, PRISM_NODISCARD, etc.) + line = line.sub(/\A(PRISM_\w+(?:\([^)]*\))?)+/, "") # Strip trailing attributes (PRISM_NODISCARD, PRISM_NONNULL(...), etc.) line = line.sub(/\)(\s+PRISM_\w+(?:\([^)]*\))?)+\s*;/, ");") # Parse the function declaration. - unless /^PRISM_EXPORTED_FUNCTION (?.+) (?\w+)\((?.+)\);$/ =~ line + unless /^(?.+) (?\w+)\((?.+)\);$/ =~ line raise "Could not parse #{line}" end @@ -184,7 +186,7 @@ def self.with # pointer directly; for files it uses a pm_source_t under the hood. class PrismSource # :nodoc: PLATFORM_EXPECTS_UTF8 = - RbConfig::CONFIG["host_os"].match?(/bccwin|cygwin|djgpp|mingw|mswin|wince|darwin/i) + RbConfig::CONFIG["host_os"].match?(/cygwin|mingw|mswin|darwin/i) attr_reader :pointer, :length @@ -214,7 +216,12 @@ def self.with_string(string) end # Yields a PrismSource to the given block, backed by a pm_source_t. - def self.with_file(filepath) + def self.with_file(filepath, options) + unless filepath.is_a?(String) + filepath = filepath.to_path if filepath.respond_to?(:to_path) + filepath = filepath.to_str if filepath.respond_to?(:to_str) + end + options[:filepath] = filepath raise TypeError unless filepath.is_a?(String) # On Windows and Mac, it's expected that filepaths will be encoded in @@ -265,8 +272,7 @@ def dump(source, **options) # Mirror the Prism.dump_file API by using the serialization API. def dump_file(filepath, **options) - options[:filepath] = filepath - LibRubyParser::PrismSource.with_file(filepath) { |string| dump_common(string, options) } + LibRubyParser::PrismSource.with_file(filepath, options) { |string| dump_common(string, options) } end # Mirror the Prism.lex API by using the serialization API. @@ -276,8 +282,7 @@ def lex(code, **options) # Mirror the Prism.lex_file API by using the serialization API. def lex_file(filepath, **options) - options[:filepath] = filepath - LibRubyParser::PrismSource.with_file(filepath) { |string| lex_common(string, string.read, options) } + LibRubyParser::PrismSource.with_file(filepath, options) { |string| lex_common(string, string.read, options) } end # Mirror the Prism.parse API by using the serialization API. @@ -289,8 +294,7 @@ def parse(code, **options) # native strings instead of Ruby strings because it allows us to use mmap # when it is available. def parse_file(filepath, **options) - options[:filepath] = filepath - LibRubyParser::PrismSource.with_file(filepath) { |string| parse_common(string, string.read, options) } + LibRubyParser::PrismSource.with_file(filepath, options) { |string| parse_common(string, string.read, options) } end # Mirror the Prism.parse_stream API by using the serialization API. @@ -349,8 +353,7 @@ def parse_comments(code, **options) # API. This uses native strings instead of Ruby strings because it allows us # to use mmap when it is available. def parse_file_comments(filepath, **options) - options[:filepath] = filepath - LibRubyParser::PrismSource.with_file(filepath) { |string| parse_comments_common(string, string.read, options) } + LibRubyParser::PrismSource.with_file(filepath, options) { |string| parse_comments_common(string, string.read, options) } end # Mirror the Prism.parse_lex API by using the serialization API. @@ -360,8 +363,7 @@ def parse_lex(code, **options) # Mirror the Prism.parse_lex_file API by using the serialization API. def parse_lex_file(filepath, **options) - options[:filepath] = filepath - LibRubyParser::PrismSource.with_file(filepath) { |string| parse_lex_common(string, string.read, options) } + LibRubyParser::PrismSource.with_file(filepath, options) { |string| parse_lex_common(string, string.read, options) } end # Mirror the Prism.parse_success? API by using the serialization API. @@ -376,8 +378,7 @@ def parse_failure?(code, **options) # Mirror the Prism.parse_file_success? API by using the serialization API. def parse_file_success?(filepath, **options) - options[:filepath] = filepath - LibRubyParser::PrismSource.with_file(filepath) { |string| parse_file_success_common(string, options) } + LibRubyParser::PrismSource.with_file(filepath, options) { |string| parse_file_success_common(string, options) } end # Mirror the Prism.parse_file_failure? API by using the serialization API. @@ -401,9 +402,7 @@ def profile(source, **options) # Mirror the Prism.profile_file API by using the serialization API. def profile_file(filepath, **options) - LibRubyParser::PrismSource.with_file(filepath) do |string| - options[:filepath] = filepath - + LibRubyParser::PrismSource.with_file(filepath, options) do |string| if (format_type = raise_error_format_type(options)) raise_error(string, options, format_type) end @@ -599,7 +598,7 @@ def version_string_to_number(version) # The set of options that are understood by the parsing APIs. Note that # raise_error is not listed here because it is deleted from the options # hash by raise_error_format_type before the options are dumped. - DUMP_OPTIONS_KEYS = [:command_line, :encoding, :filepath, :freeze, :frozen_string_literal, :line, :main_script, :partial_script, :scopes, :version].freeze + DUMP_OPTIONS_KEYS = [:attach_comments, :command_line, :encoding, :filepath, :freeze, :frozen_string_literal, :line, :main_script, :partial_script, :scopes, :version].freeze private_constant :DUMP_OPTIONS_KEYS # Convert the given options into a serialized options string. @@ -651,6 +650,9 @@ def dump_options(options) template << "C" values << (options.fetch(:freeze, false) ? 1 : 0) + template << "C" + values << (options.fetch(:attach_comments, false) ? 1 : 0) + template << "L" if (scopes = options[:scopes]) values << scopes.length diff --git a/Src/StdLib/ruby/4.0/prism/inspect_visitor.rb b/Src/StdLib/ruby/4.0/prism/inspect_visitor.rb index 7852c9baf..66a81d26b 100644 --- a/Src/StdLib/ruby/4.0/prism/inspect_visitor.rb +++ b/Src/StdLib/ruby/4.0/prism/inspect_visitor.rb @@ -2261,7 +2261,7 @@ def visit_symbol_node(node) # :nodoc: flags = [("newline" if node.newline?), ("static_literal" if node.static_literal?), ("forced_utf8_encoding" if node.forced_utf8_encoding?), ("forced_binary_encoding" if node.forced_binary_encoding?), ("forced_us_ascii_encoding" if node.forced_us_ascii_encoding?)].compact commands << ["├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n", indent] commands << ["├── opening_loc: #{inspect_location(node.opening_loc)}\n", indent] - commands << ["├── value_loc: #{inspect_location(node.value_loc)}\n", indent] + commands << ["├── content_loc: #{inspect_location(node.content_loc)}\n", indent] commands << ["├── closing_loc: #{inspect_location(node.closing_loc)}\n", indent] commands << ["└── unescaped: #{node.unescaped.inspect}\n", indent] end diff --git a/Src/StdLib/ruby/4.0/prism/lex_compat.rb b/Src/StdLib/ruby/4.0/prism/lex_compat.rb index b7921b8d9..478d08db3 100644 --- a/Src/StdLib/ruby/4.0/prism/lex_compat.rb +++ b/Src/StdLib/ruby/4.0/prism/lex_compat.rb @@ -49,10 +49,10 @@ class Result < Prism::Result # Create a new lex compat result object with the given values. # - #: (Array[lex_compat_token] value, Array[Comment] comments, Array[MagicComment] magic_comments, Location? data_loc, Array[ParseError] errors, Array[ParseWarning] warnings, bool continuable, Source source) -> void - def initialize(value, comments, magic_comments, data_loc, errors, warnings, continuable, source) + #: (Array[lex_compat_token] value, Array[MagicComment] magic_comments, Location? data_loc, Array[ParseError] errors, Array[ParseWarning] warnings, bool continuable, Source source) -> void + def initialize(value, magic_comments, data_loc, errors, warnings, continuable, source) @value = value - super(comments, magic_comments, data_loc, errors, warnings, continuable, source) + super(magic_comments, data_loc, errors, warnings, continuable, source) end # Implement the hash pattern matching interface for Result. @@ -616,6 +616,19 @@ def result last_heredoc_end = nil #: Integer? eof_token = nil #: Token? + # The two tokens Ripper scanned most recently, oldest last. Tokens that + # this loop does not emit are not part of Ripper's view, so they never + # become either one. + previous_token = nil #: Token? + previous_previous_token = nil #: Token? + + # The lex state in effect at each embedded expression that is still open, + # innermost last, and the state at the opener of the one that closed most + # recently. Ending an embedded expression restores the state its opener + # had, which on_regexp_end below has to reproduce. + embexpr_states = [] #: Array[Integer] + last_embexpr_state = nil #: Integer? + bom = source.slice(0, 3) == "\xEF\xBB\xBF" last_comment_token = nil #: lex_compat_token? @@ -625,6 +638,10 @@ def result lineno = prism_token.location.start_line column = prism_token.location.start_column + # Ripper is a scanner, so every event it emits corresponds to source + # characters. Implicit word separators have none. + next if prism_token.type == :WORDS_SEP_IMPLICIT + event = RIPPER.fetch(prism_token.type) value = prism_token.value lex_state = Translation::Ripper::Lexer::State[prism_token._ripper_state] @@ -636,6 +653,12 @@ def result last_comment_token[2] += value last_comment_token = nil last_comment_end = nil + + # The newline's characters are part of the comment Ripper emits, so + # it is still the token Ripper scanned most recently, and the trailing + # whitespace check at on_eof measures from its end. + previous_previous_token = previous_token + previous_token = prism_token next end @@ -682,7 +705,11 @@ def result # want to bother comparing the state on them. last_heredoc_end = prism_token.location.end_offset [[lineno, column], event, value, lex_state] + when :on_embexpr_beg + embexpr_states.push(prism_token._ripper_state) + [[lineno, column], event, value, lex_state] when :on_embexpr_end + last_embexpr_state = embexpr_states.pop [[lineno, column], event, value, lex_state] when :on_words_sep # Ripper emits one token each per line. @@ -701,24 +728,11 @@ def result # 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] 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].type) - counter += { on_embexpr_beg: -1, on_embexpr_end: 1 }[current_event] || 0 - end - - Translation::Ripper::Lexer::State[result_value[current_index]._ripper_state] + if previous_token&.type == :EMBEXPR_END && last_embexpr_state + # An embedded expression that just closed restored the state its + # opener had, so that is the state Ripper reports here. + Translation::Ripper::Lexer::State[last_embexpr_state] else previous_state end @@ -726,34 +740,36 @@ def result [[lineno, column], event, value, lex_state] when :on_eof eof_token = prism_token - previous_token = result_value[index - 1] - - # A newline that was folded back into a comment still marks the - # comment boundary for the check below. - comment_boundary = previous_token.type == :COMMENT || - (index >= 2 && %i[NEWLINE NEWLINE_TERMINATOR IGNORED_NEWLINE].include?(previous_token.type) && result_value[index - 2].type == :COMMENT && result_value[index - 2].location.end_offset == previous_token.location.start_offset) - - # If we're at the end of the file and the previous token was a - # comment and there is still whitespace after the comment, then - # Ripper will append a on_nl token (even though there isn't - # necessarily a newline). We mirror that here. - if comment_boundary - # If the comment is at the start of a heredoc: < Array[Comment] - def leading_comments - location.leading_comments - end - - # Delegates to [`trailing_comments`](rdoc-ref:Location#trailing_comments) of the associated location object. - # - #: () -> Array[Comment] - def trailing_comments - location.trailing_comments - end - - # Delegates to [`comments`](rdoc-ref:Location#comments) of the associated location object. + # The comments attached to this node, ordered by start offset. Comments are + # only attached when the source is parsed with the attach_comments option. # #: () -> Array[Comment] def comments - location.comments + source.comments_for(node_id) end # :section: @@ -391,14 +378,6 @@ def compact_child_nodes raise NoMethodError, "undefined method `compact_child_nodes' for #{inspect}" end - # Returns an array of child nodes and locations that could potentially have - # comments attached to them. - # - #: () -> Array[node | Location] - def comment_targets - raise NoMethodError, "undefined method `comment_targets' for #{inspect}" - end - # Returns a string representation of the node. # #: () -> String @@ -500,13 +479,6 @@ def compact_child_nodes [new_name, old_name] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [new_name, old_name, keyword_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> AliasGlobalVariableNode # @@ -695,13 +667,6 @@ def compact_child_nodes [new_name, old_name] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [new_name, old_name, keyword_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> AliasMethodNode # @@ -902,13 +867,6 @@ def compact_child_nodes [left, right] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [left, right, operator_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> AlternationPatternNode # @@ -1097,13 +1055,6 @@ def compact_child_nodes [left, right] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [left, right, operator_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> AndNode # @@ -1293,13 +1244,6 @@ def compact_child_nodes [*arguments] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [*arguments] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> ArgumentsNode # @@ -1476,13 +1420,6 @@ def compact_child_nodes [*elements] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [*elements, *opening_loc, *closing_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> ArrayNode # @@ -1740,13 +1677,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [*constant, *requireds, *rest, *posts, *opening_loc, *closing_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> ArrayPatternNode # @@ -2021,13 +1951,6 @@ def compact_child_nodes [key, value] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [key, value, *operator_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> AssocNode # @@ -2229,13 +2152,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [*value, operator_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> AssocSplatNode # @@ -2403,13 +2319,6 @@ def compact_child_nodes [] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> BackReferenceReadNode # @@ -2561,13 +2470,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [*begin_keyword_loc, *statements, *rescue_clause, *else_clause, *ensure_clause, *end_keyword_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> BeginNode # @@ -2833,13 +2735,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [*expression, operator_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> BlockArgumentNode # @@ -3007,13 +2902,6 @@ def compact_child_nodes [] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> BlockLocalVariableNode # @@ -3165,13 +3053,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [*parameters, *body, opening_loc, closing_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> BlockNode # @@ -3417,13 +3298,6 @@ def compact_child_nodes [] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [*name_loc, operator_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> BlockParameterNode # @@ -3649,13 +3523,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [*parameters, *locals, *opening_loc, *closing_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> BlockParametersNode # @@ -3908,13 +3775,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [*arguments, keyword_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> BreakNode # @@ -4099,13 +3959,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [*receiver, *call_operator_loc, *message_loc, operator_loc, value] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> CallAndWriteNode # @@ -4475,13 +4328,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [*receiver, *call_operator_loc, *message_loc, *opening_loc, *arguments, *closing_loc, *equal_loc, *block] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> CallNode # @@ -4935,13 +4781,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [*receiver, *call_operator_loc, *message_loc, binary_operator_loc, value] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> CallOperatorWriteNode # @@ -5294,13 +5133,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [*receiver, *call_operator_loc, *message_loc, operator_loc, value] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> CallOrWriteNode # @@ -5647,13 +5479,6 @@ def compact_child_nodes [receiver] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [receiver, call_operator_loc, message_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> CallTargetNode # @@ -5913,13 +5738,6 @@ def compact_child_nodes [value, target] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [value, target, operator_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> CapturePatternNode # @@ -6119,13 +5937,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [*predicate, *conditions, *else_clause, case_keyword_loc, end_keyword_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> CaseMatchNode # @@ -6379,13 +6190,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [*predicate, *conditions, *else_clause, case_keyword_loc, end_keyword_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> CaseNode # @@ -6643,13 +6447,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [class_keyword_loc, constant_path, *inheritance_operator_loc, *superclass, *body, end_keyword_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> ClassNode # @@ -6959,13 +6756,6 @@ def compact_child_nodes [value] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [name_loc, operator_loc, value] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> ClassVariableAndWriteNode # @@ -7184,13 +6974,6 @@ def compact_child_nodes [value] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [name_loc, binary_operator_loc, value] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> ClassVariableOperatorWriteNode # @@ -7396,13 +7179,6 @@ def compact_child_nodes [value] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [name_loc, operator_loc, value] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> ClassVariableOrWriteNode # @@ -7600,13 +7376,6 @@ def compact_child_nodes [] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> ClassVariableReadNode # @@ -7737,13 +7506,6 @@ def compact_child_nodes [] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> ClassVariableTargetNode # @@ -7877,13 +7639,6 @@ def compact_child_nodes [value] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [name_loc, value, operator_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> ClassVariableWriteNode # @@ -8104,13 +7859,6 @@ def compact_child_nodes [value] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [name_loc, operator_loc, value] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> ConstantAndWriteNode # @@ -8317,13 +8065,6 @@ def compact_child_nodes [value] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [name_loc, binary_operator_loc, value] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> ConstantOperatorWriteNode # @@ -8529,13 +8270,6 @@ def compact_child_nodes [value] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [name_loc, operator_loc, value] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> ConstantOrWriteNode # @@ -8739,13 +8473,6 @@ def compact_child_nodes [target, value] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [target, operator_loc, value] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> ConstantPathAndWriteNode # @@ -8928,13 +8655,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [*parent, delimiter_loc, name_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> ConstantPathNode # @@ -9161,13 +8881,6 @@ def compact_child_nodes [target, value] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [target, binary_operator_loc, value] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> ConstantPathOperatorWriteNode # @@ -9348,13 +9061,6 @@ def compact_child_nodes [target, value] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [target, operator_loc, value] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> ConstantPathOrWriteNode # @@ -9537,13 +9243,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [*parent, delimiter_loc, name_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> ConstantPathTargetNode # @@ -9753,13 +9452,6 @@ def compact_child_nodes [target, value] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [target, operator_loc, value] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> ConstantPathWriteNode # @@ -9945,13 +9637,6 @@ def compact_child_nodes [] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> ConstantReadNode # @@ -10082,13 +9767,6 @@ def compact_child_nodes [] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> ConstantTargetNode # @@ -10222,13 +9900,6 @@ def compact_child_nodes [value] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [name_loc, value, operator_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> ConstantWriteNode # @@ -10472,13 +10143,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [name_loc, *receiver, *parameters, *body, def_keyword_loc, *operator_loc, *lparen_loc, *rparen_loc, *equal_loc, *end_keyword_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> DefNode # @@ -10920,13 +10584,6 @@ def compact_child_nodes [value] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [*lparen_loc, value, *rparen_loc, keyword_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> DefinedNode # @@ -11175,13 +10832,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [else_keyword_loc, *statements, *end_keyword_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> ElseNode # @@ -11390,13 +11040,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [opening_loc, *statements, closing_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> EmbeddedStatementsNode # @@ -11596,13 +11239,6 @@ def compact_child_nodes [variable] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [operator_loc, variable] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> EmbeddedVariableNode # @@ -11775,13 +11411,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [ensure_keyword_loc, *statements, end_keyword_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> EnsureNode # @@ -11978,13 +11607,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [*unexpected] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> ErrorRecoveryNode # @@ -12109,13 +11731,6 @@ def compact_child_nodes [] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> FalseNode # @@ -12258,13 +11873,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [*constant, left, *requireds, right, *opening_loc, *closing_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> FindPatternNode # @@ -12550,13 +12158,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [*left, *right, operator_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> FlipFlopNode # @@ -12739,13 +12340,6 @@ def compact_child_nodes [] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> FloatNode # @@ -12891,13 +12485,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [index, collection, *statements, for_keyword_loc, in_keyword_loc, *do_keyword_loc, end_keyword_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> ForNode # @@ -13216,13 +12803,6 @@ def compact_child_nodes [] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> ForwardingArgumentsNode # @@ -13336,13 +12916,6 @@ def compact_child_nodes [] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> ForwardingParameterNode # @@ -13467,13 +13040,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [keyword_loc, *block] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> ForwardingSuperNode # @@ -13646,13 +13212,6 @@ def compact_child_nodes [value] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [name_loc, operator_loc, value] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> GlobalVariableAndWriteNode # @@ -13859,13 +13418,6 @@ def compact_child_nodes [value] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [name_loc, binary_operator_loc, value] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> GlobalVariableOperatorWriteNode # @@ -14071,13 +13623,6 @@ def compact_child_nodes [value] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [name_loc, operator_loc, value] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> GlobalVariableOrWriteNode # @@ -14275,13 +13820,6 @@ def compact_child_nodes [] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> GlobalVariableReadNode # @@ -14412,13 +13950,6 @@ def compact_child_nodes [] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> GlobalVariableTargetNode # @@ -14552,13 +14083,6 @@ def compact_child_nodes [value] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [name_loc, value, operator_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> GlobalVariableWriteNode # @@ -14777,13 +14301,6 @@ def compact_child_nodes [*elements] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [opening_loc, *elements, closing_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> HashNode # @@ -15017,13 +14534,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [*constant, *elements, *rest, *opening_loc, *closing_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> HashPatternNode # @@ -15308,13 +14818,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [*if_keyword_loc, predicate, *then_keyword_loc, *statements, *subsequent, *end_keyword_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> IfNode # @@ -15632,13 +15135,6 @@ def compact_child_nodes [numeric] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [numeric] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> ImaginaryNode # @@ -15772,13 +15268,6 @@ def compact_child_nodes [value] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [value] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> ImplicitNode # @@ -15912,13 +15401,6 @@ def compact_child_nodes [] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> ImplicitRestNode # @@ -16044,13 +15526,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [pattern, *statements, in_keyword_loc, *then_keyword_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> InNode # @@ -16287,13 +15762,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [*receiver, *call_operator_loc, opening_loc, *arguments, closing_loc, *block, operator_loc, value] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> IndexAndWriteNode # @@ -16659,13 +16127,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [*receiver, *call_operator_loc, opening_loc, *arguments, closing_loc, *block, binary_operator_loc, value] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> IndexOperatorWriteNode # @@ -17030,13 +16491,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [*receiver, *call_operator_loc, opening_loc, *arguments, closing_loc, *block, operator_loc, value] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> IndexOrWriteNode # @@ -17400,13 +16854,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [receiver, opening_loc, *arguments, closing_loc, *block] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> IndexTargetNode # @@ -17667,13 +17114,6 @@ def compact_child_nodes [value] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [name_loc, operator_loc, value] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> InstanceVariableAndWriteNode # @@ -17880,13 +17320,6 @@ def compact_child_nodes [value] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [name_loc, binary_operator_loc, value] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> InstanceVariableOperatorWriteNode # @@ -18092,13 +17525,6 @@ def compact_child_nodes [value] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [name_loc, operator_loc, value] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> InstanceVariableOrWriteNode # @@ -18296,13 +17722,6 @@ def compact_child_nodes [] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> InstanceVariableReadNode # @@ -18433,13 +17852,6 @@ def compact_child_nodes [] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> InstanceVariableTargetNode # @@ -18573,13 +17985,6 @@ def compact_child_nodes [value] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [name_loc, value, operator_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> InstanceVariableWriteNode # @@ -18793,13 +18198,6 @@ def compact_child_nodes [] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> IntegerNode # @@ -18964,13 +18362,6 @@ def compact_child_nodes [*parts] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [opening_loc, *parts, closing_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> InterpolatedMatchLastLineNode # @@ -19262,13 +18653,6 @@ def compact_child_nodes [*parts] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [opening_loc, *parts, closing_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> InterpolatedRegularExpressionNode # @@ -19560,13 +18944,6 @@ def compact_child_nodes [*parts] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [*opening_loc, *parts, *closing_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> InterpolatedStringNode # @@ -19796,13 +19173,6 @@ def compact_child_nodes [*parts] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [*opening_loc, *parts, *closing_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> InterpolatedSymbolNode # @@ -20015,13 +19385,6 @@ def compact_child_nodes [*parts] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [opening_loc, *parts, closing_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> InterpolatedXStringNode # @@ -20217,13 +19580,6 @@ def compact_child_nodes [] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> ItLocalVariableReadNode # @@ -20336,13 +19692,6 @@ def compact_child_nodes [] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> ItParametersNode # @@ -20458,13 +19807,6 @@ def compact_child_nodes [*elements] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [*elements] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> KeywordHashNode # @@ -20606,13 +19948,6 @@ def compact_child_nodes [] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [*name_loc, operator_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> KeywordRestParameterNode # @@ -20827,13 +20162,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [operator_loc, opening_loc, closing_loc, *parameters, *body] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> LambdaNode # @@ -21099,13 +20427,6 @@ def compact_child_nodes [value] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [name_loc, operator_loc, value] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> LocalVariableAndWriteNode # @@ -21326,13 +20647,6 @@ def compact_child_nodes [value] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [name_loc, binary_operator_loc, value] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> LocalVariableOperatorWriteNode # @@ -21552,13 +20866,6 @@ def compact_child_nodes [value] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [name_loc, operator_loc, value] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> LocalVariableOrWriteNode # @@ -21770,13 +21077,6 @@ def compact_child_nodes [] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> LocalVariableReadNode # @@ -21934,13 +21234,6 @@ def compact_child_nodes [] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> LocalVariableTargetNode # @@ -22088,13 +21381,6 @@ def compact_child_nodes [value] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [name_loc, value, operator_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> LocalVariableWriteNode # @@ -22336,13 +21622,6 @@ def compact_child_nodes [] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [opening_loc, content_loc, closing_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> MatchLastLineNode # @@ -22669,13 +21948,6 @@ def compact_child_nodes [value, pattern] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [value, pattern, keyword_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> MatchPredicateNode # @@ -22855,13 +22127,6 @@ def compact_child_nodes [value, pattern] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [value, pattern, operator_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> MatchRequiredNode # @@ -23087,13 +22352,6 @@ def compact_child_nodes [call, *targets] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [call, *targets] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> MatchWriteNode # @@ -23248,13 +22506,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [module_keyword_loc, constant_path, *body, end_keyword_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> ModuleNode # @@ -23508,13 +22759,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [*lefts, *rest, *rights, *lparen_loc, *rparen_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> MultiTargetNode # @@ -23798,13 +23042,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [*lefts, *rest, *rights, *lparen_loc, *rparen_loc, operator_loc, value] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> MultiWriteNode # @@ -24125,13 +23362,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [*arguments, keyword_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> NextNode # @@ -24291,13 +23521,6 @@ def compact_child_nodes [] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> NilNode # @@ -24415,13 +23638,6 @@ def compact_child_nodes [] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [operator_loc, keyword_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> NoBlockParameterNode # @@ -24609,13 +23825,6 @@ def compact_child_nodes [] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [operator_loc, keyword_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> NoKeywordsParameterNode # @@ -24800,13 +24009,6 @@ def compact_child_nodes [] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> NumberedParametersNode # @@ -24933,13 +24135,6 @@ def compact_child_nodes [] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> NumberedReferenceReadNode # @@ -25078,13 +24273,6 @@ def compact_child_nodes [value] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [name_loc, value] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> OptionalKeywordParameterNode # @@ -25264,13 +24452,6 @@ def compact_child_nodes [value] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [name_loc, operator_loc, value] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> OptionalParameterNode # @@ -25483,13 +24664,6 @@ def compact_child_nodes [left, right] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [left, right, operator_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> OrNode # @@ -25706,13 +24880,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [*requireds, *optionals, *rest, *posts, *keywords, *keyword_rest, *block] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> ParametersNode # @@ -25922,13 +25089,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [*body, opening_loc, closing_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> ParenthesesNode # @@ -26141,13 +25301,6 @@ def compact_child_nodes [expression] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [expression, operator_loc, lparen_loc, rparen_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> PinnedExpressionNode # @@ -26394,13 +25547,6 @@ def compact_child_nodes [variable] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [variable, operator_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> PinnedVariableNode # @@ -26577,13 +25723,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [*statements, keyword_loc, opening_loc, closing_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> PostExecutionNode # @@ -26824,13 +25963,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [*statements, keyword_loc, opening_loc, closing_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> PreExecutionNode # @@ -27062,13 +26194,6 @@ def compact_child_nodes [statements] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [statements] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> ProgramNode # @@ -27220,13 +26345,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [*left, *right, operator_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> RangeNode # @@ -27424,13 +26542,6 @@ def compact_child_nodes [] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> RationalNode # @@ -27604,13 +26715,6 @@ def compact_child_nodes [] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> RedoNode # @@ -27731,13 +26835,6 @@ def compact_child_nodes [] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [opening_loc, content_loc, closing_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> RegularExpressionNode # @@ -28061,13 +27158,6 @@ def compact_child_nodes [] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [name_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> RequiredKeywordParameterNode # @@ -28228,13 +27318,6 @@ def compact_child_nodes [] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> RequiredParameterNode # @@ -28376,13 +27459,6 @@ def compact_child_nodes [expression, rescue_expression] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [expression, keyword_loc, rescue_expression] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> RescueModifierNode # @@ -28582,13 +27658,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [keyword_loc, *exceptions, *operator_loc, *reference, *then_keyword_loc, *statements, *subsequent] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> RescueNode # @@ -28872,13 +27941,6 @@ def compact_child_nodes [] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [*name_loc, operator_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> RestParameterNode # @@ -29076,13 +28138,6 @@ def compact_child_nodes [] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> RetryNode # @@ -29202,13 +28257,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [keyword_loc, *arguments] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> ReturnNode # @@ -29368,13 +28416,6 @@ def compact_child_nodes [] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> SelfNode # @@ -29491,13 +28532,6 @@ def compact_child_nodes [write] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [write] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> ShareableConstantNode # @@ -29664,13 +28698,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [class_keyword_loc, operator_loc, expression, *body, end_keyword_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> SingletonClassNode # @@ -29925,13 +28952,6 @@ def compact_child_nodes [] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> SourceEncodingNode # @@ -30046,13 +29066,6 @@ def compact_child_nodes [] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> SourceFileNode # @@ -30210,13 +29223,6 @@ def compact_child_nodes [] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> SourceLineNode # @@ -30336,13 +29342,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [operator_loc, *expression] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> SplatNode # @@ -30505,13 +29504,6 @@ def compact_child_nodes [*body] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [*body] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> StatementsNode # @@ -30651,13 +29643,6 @@ def compact_child_nodes [] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [*opening_loc, content_loc, *closing_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> StringNode # @@ -30950,13 +29935,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [keyword_loc, *lparen_loc, *arguments, *rparen_loc, *block] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> SuperNode # @@ -31160,20 +30138,20 @@ def ===(other) # :nodoc: # ^^^ class SymbolNode < Node # @rbs @opening_loc: Location? - # @rbs @value_loc: Location? + # @rbs @content_loc: Location # @rbs @closing_loc: Location? # @rbs @unescaped: String # Initialize a new SymbolNode node. # - #: (Source source, Integer node_id, Location location, Integer flags, Location? opening_loc, Location? value_loc, Location? closing_loc, String unescaped) -> void - def initialize(source, node_id, location, flags, opening_loc, value_loc, closing_loc, unescaped) + #: (Source source, Integer node_id, Location location, Integer flags, Location? opening_loc, Location content_loc, Location? closing_loc, String unescaped) -> void + def initialize(source, node_id, location, flags, opening_loc, content_loc, closing_loc, unescaped) @source = source @node_id = node_id @location = location @flags = flags @opening_loc = opening_loc - @value_loc = value_loc + @content_loc = content_loc @closing_loc = closing_loc @unescaped = unescaped end @@ -31219,39 +30197,32 @@ def compact_child_nodes [] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [*opening_loc, *value_loc, *closing_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> SymbolNode # # Creates a copy of self with the given fields, using self as the template. # - #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?opening_loc: Location?, ?value_loc: Location?, ?closing_loc: Location?, ?unescaped: String) -> SymbolNode - def copy(node_id: self.node_id, location: self.location, flags: self.flags, opening_loc: self.opening_loc, value_loc: self.value_loc, closing_loc: self.closing_loc, unescaped: self.unescaped) - SymbolNode.new(source, node_id, location, flags, opening_loc, value_loc, closing_loc, unescaped) + #: (?node_id: Integer, ?location: Location, ?flags: Integer, ?opening_loc: Location?, ?content_loc: Location, ?closing_loc: Location?, ?unescaped: String) -> SymbolNode + def copy(node_id: self.node_id, location: self.location, flags: self.flags, opening_loc: self.opening_loc, content_loc: self.content_loc, closing_loc: self.closing_loc, unescaped: self.unescaped) + SymbolNode.new(source, node_id, location, flags, opening_loc, content_loc, closing_loc, unescaped) end alias deconstruct child_nodes #: (Array[Symbol]? keys) -> Hash[Symbol, untyped] def deconstruct_keys(keys) # :nodoc: - (keys || %i[node_id location opening_loc value_loc closing_loc unescaped opening value closing]).each_with_object( + (keys || %i[node_id location opening_loc content_loc closing_loc unescaped opening content closing]).each_with_object( {} #: Hash[Symbol, untyped] ) do |key, deconstructed| case key when :node_id then deconstructed[:node_id] = self.node_id when :location then deconstructed[:location] = self.location when :opening_loc then deconstructed[:opening_loc] = self.opening_loc - when :value_loc then deconstructed[:value_loc] = self.value_loc + when :content_loc then deconstructed[:content_loc] = self.content_loc when :closing_loc then deconstructed[:closing_loc] = self.closing_loc when :unescaped then deconstructed[:unescaped] = self.unescaped when :opening then deconstructed[:opening] = self.opening - when :value then deconstructed[:value] = self.value + when :content then deconstructed[:content] = self.content when :closing then deconstructed[:closing] = self.closing end end @@ -31331,31 +30302,26 @@ def save_opening_loc(repository) end # :category: Locations # :call-seq: - # value_loc -> Location | nil + # content_loc -> Location # - # Returns the Location represented by `value_loc`. + # Returns the Location represented by `content_loc`. # - #: () -> Location? - def value_loc - location = @value_loc - case location - when nil - nil - when Location - location - else - @value_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF) - end + #: () -> Location + def content_loc + location = @content_loc + return location if location.is_a?(Location) + @content_loc = Location.new(source, location >> 32, location & 0xFFFFFFFF) end # :category: Repository - # Save the value_loc location using the given saved source so that + # Save the content_loc location using the given saved source so that # it can be retrieved later. # - #: (_Repository repository) -> Relocation::Entry? - def save_value_loc(repository) - repository.enter(node_id, :value_loc) unless @value_loc.nil? + #: (_Repository repository) -> Relocation::Entry + def save_content_loc(repository) + repository.enter(node_id, :content_loc) end + # :category: Locations # :call-seq: # closing_loc -> Location | nil @@ -31406,13 +30372,13 @@ def opening end # :call-seq: - # value -> String | nil + # content -> String # - # Slice the location of value_loc from the source. + # Slice the location of content_loc from the source. # - #: () -> String? - def value - value_loc&.slice + #: () -> String + def content + content_loc.slice end # :call-seq: @@ -31432,7 +30398,7 @@ def ===(other) # :nodoc: other.is_a?(SymbolNode) && (flags === other.flags) && (opening_loc.nil? == other.opening_loc.nil?) && - (value_loc.nil? == other.value_loc.nil?) && + (content_loc.nil? == other.content_loc.nil?) && (closing_loc.nil? == other.closing_loc.nil?) && (unescaped === other.unescaped) end @@ -31495,13 +30461,6 @@ def compact_child_nodes [] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> TrueNode # @@ -31619,13 +30578,6 @@ def compact_child_nodes [*names] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [*names, keyword_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> UndefNode # @@ -31808,13 +30760,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [unless_keyword_loc, predicate, *then_keyword_loc, *statements, *else_clause, *end_keyword_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> UnlessNode # @@ -32121,13 +31066,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [until_keyword_loc, *do_keyword_loc, *end_keyword_loc, predicate, *statements] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> UntilNode # @@ -32403,13 +31341,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [when_keyword_loc, *conditions, *then_keyword_loc, *statements] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> WhenNode # @@ -32640,13 +31571,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [while_keyword_loc, *do_keyword_loc, *end_keyword_loc, predicate, *statements] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> WhileNode # @@ -32915,13 +31839,6 @@ def compact_child_nodes [] end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [opening_loc, content_loc, closing_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> XStringNode # @@ -33179,13 +32096,6 @@ def compact_child_nodes compact end - # See Node.comment_targets. - # - #: () -> Array[node | Location] - def comment_targets - [keyword_loc, *lparen_loc, *arguments, *rparen_loc] #: Array[Prism::node | Location] - end - # :call-seq: # copy(**fields) -> YieldNode # diff --git a/Src/StdLib/ruby/4.0/prism/node_ext.rb b/Src/StdLib/ruby/4.0/prism/node_ext.rb index 03826b9a4..bf1e0cc65 100644 --- a/Src/StdLib/ruby/4.0/prism/node_ext.rb +++ b/Src/StdLib/ruby/4.0/prism/node_ext.rb @@ -488,5 +488,17 @@ def closing_loc # :nodoc end_keyword_loc end end + + class SymbolNode < Node + #: () -> String + def value # :nodoc + content + end + + #: () -> Location + def value_loc # :nodoc + content_loc + end + end # :startdoc: end diff --git a/Src/StdLib/ruby/4.0/prism/node_find.rb b/Src/StdLib/ruby/4.0/prism/node_find.rb index 8f82cda9e..301aaf158 100644 --- a/Src/StdLib/ruby/4.0/prism/node_find.rb +++ b/Src/StdLib/ruby/4.0/prism/node_find.rb @@ -16,6 +16,10 @@ module NodeFind # :nodoc: # #: (Method | UnboundMethod | Proc | Thread::Backtrace::Location callable) -> Node? def self.find(callable) + if callable.respond_to?(:source_range) && !defined?(::RubyVM) + return SourceRangeFind.new.find(callable) + end + case callable when Proc if defined?(::RubyVM) @@ -56,6 +60,32 @@ def parse_file(file) end end + # Finds the AST node for a Method, UnboundMethod, Proc or Thread::Backtrace::Location + # using the #source_range + class SourceRangeFind < Find + # Find the node for the given callable using the #source_range. + # + #: (Method | UnboundMethod | Proc | Thread::Backtrace::Location callable) -> Node? + def find(callable) + begin + range = callable.source_range + rescue ArgumentError # eval + return + end + return unless range + return unless (result = parse_file(range.absolute_path)) + + start_offset = result.source.byte_offset(range.start_line, range.start_column) + end_offset = result.source.byte_offset(range.end_line, range.end_column) + result.value.tunnel(range.start_line, range.start_column).reverse_each do |node| + if node.start_offset == start_offset && node.end_offset == end_offset + return node + end + end + nil + end + end + # Finds the AST node for a Method, UnboundMethod, or Proc using the node_id # from the instruction sequence. class RubyVMCallableFind < Find diff --git a/Src/StdLib/ruby/4.0/prism/parse_result.rb b/Src/StdLib/ruby/4.0/prism/parse_result.rb index e9380d0f0..7c5bcdccc 100644 --- a/Src/StdLib/ruby/4.0/prism/parse_result.rb +++ b/Src/StdLib/ruby/4.0/prism/parse_result.rb @@ -29,15 +29,20 @@ class Source # byte offset whenever a newline character is encountered. The first # element is always 0 to mark the first line. # - #: (String source, Integer start_line, Array[Integer] offsets) -> Source - def self.for(source, start_line, offsets) + # The comments, comment_attachments, and comment_ranges parameters are the + # lists described by the attributes of the same names. They are passed in + # empty when the source is created by the parser and filled in afterward, + # because the comments themselves refer to the source. + # + #: (String source, Integer start_line, Array[Integer] offsets, ?Array[Comment] comments, ?Array[Comment] comment_attachments, ?Array[Integer?] comment_ranges) -> Source + def self.for(source, start_line, offsets, comments = [], comment_attachments = [], comment_ranges = []) if source.ascii_only? - ASCIISource.new(source, start_line, offsets) + ASCIISource.new(source, start_line, offsets, comments, comment_attachments, comment_ranges) elsif source.encoding == Encoding::BINARY source.force_encoding(Encoding::UTF_8) if source.valid_encoding? - new(source, start_line, offsets) + new(source, start_line, offsets, comments, comment_attachments, comment_ranges) else # This is an extremely niche use case where the file is marked as # binary, contains multi-byte characters, and those characters are not @@ -46,10 +51,10 @@ def self.for(source, start_line, offsets) # problems when asking for code units, but it appears to be the # cleanest solution at the moment. source.force_encoding(Encoding::BINARY) - ASCIISource.new(source, start_line, offsets) + ASCIISource.new(source, start_line, offsets, comments, comment_attachments, comment_ranges) end else - new(source, start_line, offsets) + new(source, start_line, offsets, comments, comment_attachments, comment_ranges) end end @@ -59,6 +64,22 @@ def self.for(source, start_line, offsets) # The line number where this source starts. attr_reader :start_line #: Integer + # The list of comments that were encountered during parsing. When the source + # is parsed with the attach_comments option, these are sorted by start + # offset. + attr_reader :comments #: Array[Comment] + + # The comments attached to nodes, grouped by node in order of node id. This + # is empty unless the source was parsed with the attach_comments option. + attr_reader :comment_attachments #: Array[Comment] + + # Indices into comment_attachments, indexed by node id. For each node that + # owns comments, the index at which its comments begin is stored at its node + # id and the index at which they end is stored at the following node id. The + # other entries are nil. This is empty unless the source was parsed with the + # attach_comments option. + attr_reader :comment_ranges #: Array[Integer?] + # The list of newline byte offsets in the source code. When initialized from # the C extension, this may be a packed binary string of uint32_t values # that is lazily unpacked on first access. @@ -74,11 +95,14 @@ def offsets # parameter can be either an Array of Integer byte offsets or a packed # binary string of uint32_t values (from the C extension). # - #: (String source, Integer start_line, Array[Integer] | String offsets) -> void - def initialize(source, start_line, offsets) + #: (String source, Integer start_line, Array[Integer] | String offsets, ?Array[Comment] comments, ?Array[Comment] comment_attachments, ?Array[Integer?] comment_ranges) -> void + def initialize(source, start_line, offsets, comments = [], comment_attachments = [], comment_ranges = []) @source = source @start_line = start_line @offsets = offsets + @comments = comments + @comment_attachments = comment_attachments + @comment_ranges = comment_ranges end # Replace the value of start_line with the given value. @@ -95,6 +119,19 @@ def replace_offsets(offsets) @offsets = offsets end + # The comments attached to the node with the given id, ordered by start + # offset. Comments are only attached when the source is parsed with the + # attach_comments option. + # + #: (Integer node_id) -> Array[Comment] + def comments_for(node_id) + start = comment_ranges[node_id] + finish = comment_ranges[node_id + 1] + return [] if start.nil? || finish.nil? + + comment_attachments[start...finish] || [] + end + # Returns the encoding of the source code, which is set by parameters to the # parser or by the encoding magic comment. # @@ -222,6 +259,9 @@ def code_units_column(byte_offset, encoding) def deep_freeze source.freeze offsets.freeze + comments.freeze + comment_attachments.freeze + comment_ranges.freeze freeze end @@ -406,9 +446,6 @@ class Location # The length of this location in bytes. attr_reader :length #: Integer - # @rbs @leading_comments: Array[Comment]? - # @rbs @trailing_comments: Array[Comment]? - # Create a new location object with the given source, start byte offset, and # byte length. # @@ -417,50 +454,6 @@ def initialize(source, start_offset, length) @source = source @start_offset = start_offset @length = length - - # These are used to store comments that are associated with this location. - # They are initialized to `nil` to save on memory when there are no - # comments to be attached and/or the comment-related APIs are not used. - @leading_comments = nil - @trailing_comments = nil - end - - # These are the comments that are associated with this location that exist - # before the start of this location. - # - #: () -> Array[Comment] - def leading_comments - @leading_comments ||= [] - end - - # Attach a comment to the leading comments of this location. - # - #: (Comment comment) -> void - def leading_comment(comment) - leading_comments << comment - end - - # These are the comments that are associated with this location that exist - # after the end of this location. - # - #: () -> Array[Comment] - def trailing_comments - @trailing_comments ||= [] - end - - # Attach a comment to the trailing comments of this location. - # - #: (Comment comment) -> void - def trailing_comment(comment) - trailing_comments << comment - end - - # Returns all comments that are associated with this location (both leading - # and trailing comments). - # - #: () -> Array[Comment] - def comments - [*@leading_comments, *@trailing_comments] #: Array[Comment] end # Create a new location object with the given options. @@ -903,9 +896,6 @@ def inspect # :nodoc: # It contains the requested structure, any comments that were encounters, # and any errors that were encountered. class Result - # The list of comments that were encountered during parsing. - attr_reader :comments #: Array[Comment] - # The list of magic comments that were encountered during parsing. attr_reader :magic_comments #: Array[MagicComment] @@ -925,9 +915,8 @@ class Result # Create a new result object with the given values. # - #: (Array[Comment] comments, Array[MagicComment] magic_comments, Location? data_loc, Array[ParseError] errors, Array[ParseWarning] warnings, bool continuable, Source source) -> void - def initialize(comments, magic_comments, data_loc, errors, warnings, continuable, source) - @comments = comments + #: (Array[MagicComment] magic_comments, Location? data_loc, Array[ParseError] errors, Array[ParseWarning] warnings, bool continuable, Source source) -> void + def initialize(magic_comments, data_loc, errors, warnings, continuable, source) @magic_comments = magic_comments @data_loc = data_loc @errors = errors @@ -936,6 +925,13 @@ def initialize(comments, magic_comments, data_loc, errors, warnings, continuable @source = source end + # The list of comments that were encountered during parsing. + # + #: () -> Array[Comment] + def comments + source.comments + end + # Implement the hash pattern matching interface for Result. # #: (Array[Symbol]? keys) -> Hash[Symbol, untyped] @@ -1001,11 +997,9 @@ def code_units_cache(encoding) # This is a result specific to the `parse` and `parse_file` methods. class ParseResult < Result - autoload :Comments, "prism/parse_result/comments" autoload :Errors, "prism/parse_result/errors" autoload :Newlines, "prism/parse_result/newlines" - private_constant :Comments private_constant :Errors private_constant :Newlines @@ -1014,10 +1008,10 @@ class ParseResult < Result # Create a new parse result object with the given values. # - #: (ProgramNode value, Array[Comment] comments, Array[MagicComment] magic_comments, Location? data_loc, Array[ParseError] errors, Array[ParseWarning] warnings, bool continuable, Source source) -> void - def initialize(value, comments, magic_comments, data_loc, errors, warnings, continuable, source) + #: (ProgramNode value, Array[MagicComment] magic_comments, Location? data_loc, Array[ParseError] errors, Array[ParseWarning] warnings, bool continuable, Source source) -> void + def initialize(value, magic_comments, data_loc, errors, warnings, continuable, source) @value = value - super(comments, magic_comments, data_loc, errors, warnings, continuable, source) + super(magic_comments, data_loc, errors, warnings, continuable, source) end # Implement the hash pattern matching interface for ParseResult. @@ -1027,13 +1021,6 @@ def deconstruct_keys(keys) # :nodoc: super.merge!(value: value) end - # Attach the list of comments to their respective locations in the tree. - # - #: () -> void - def attach_comments! - Comments.new(self).attach! # steep:ignore - end - # Walk the tree and mark nodes that are on a new line, loosely emulating # the behavior of CRuby's `:line` tracepoint event. # @@ -1058,10 +1045,10 @@ class LexResult < Result # Create a new lex result object with the given values. # - #: (Array[Token] value, Array[Comment] comments, Array[MagicComment] magic_comments, Location? data_loc, Array[ParseError] errors, Array[ParseWarning] warnings, bool continuable, Source source) -> void - def initialize(value, comments, magic_comments, data_loc, errors, warnings, continuable, source) + #: (Array[Token] value, Array[MagicComment] magic_comments, Location? data_loc, Array[ParseError] errors, Array[ParseWarning] warnings, bool continuable, Source source) -> void + def initialize(value, magic_comments, data_loc, errors, warnings, continuable, source) @value = value - super(comments, magic_comments, data_loc, errors, warnings, continuable, source) + super(magic_comments, data_loc, errors, warnings, continuable, source) end # Implement the hash pattern matching interface for LexResult. @@ -1080,10 +1067,10 @@ class ParseLexResult < Result # Create a new parse lex result object with the given values. # - #: ([ProgramNode, Array[Token]] value, Array[Comment] comments, Array[MagicComment] magic_comments, Location? data_loc, Array[ParseError] errors, Array[ParseWarning] warnings, bool continuable, Source source) -> void - def initialize(value, comments, magic_comments, data_loc, errors, warnings, continuable, source) + #: ([ProgramNode, Array[Token]] value, Array[MagicComment] magic_comments, Location? data_loc, Array[ParseError] errors, Array[ParseWarning] warnings, bool continuable, Source source) -> void + def initialize(value, magic_comments, data_loc, errors, warnings, continuable, source) @value = value - super(comments, magic_comments, data_loc, errors, warnings, continuable, source) + super(magic_comments, data_loc, errors, warnings, continuable, source) end # Implement the hash pattern matching interface for ParseLexResult. diff --git a/Src/StdLib/ruby/4.0/prism/parse_result/comments.rb b/Src/StdLib/ruby/4.0/prism/parse_result/comments.rb deleted file mode 100644 index b5943496e..000000000 --- a/Src/StdLib/ruby/4.0/prism/parse_result/comments.rb +++ /dev/null @@ -1,219 +0,0 @@ -# frozen_string_literal: true -# :markup: markdown -#-- -# rbs_inline: enabled - -module Prism - class ParseResult < Result - # When we've parsed the source, we have both the syntax tree and the list of - # comments that we found in the source. This class is responsible for - # walking the tree and finding the nearest location to attach each comment. - # - # It does this by first finding the nearest locations to each comment. - # Locations can either come from nodes directly or from location fields on - # nodes. For example, a `ClassNode` has an overall location encompassing the - # entire class, but it also has a location for the `class` keyword. - # - # Once the nearest locations are found, it determines which one to attach - # to. If it's a trailing comment (a comment on the same line as other source - # code), it will favor attaching to the nearest location that occurs before - # the comment. Otherwise it will favor attaching to the nearest location - # that is after the comment. - class Comments - # @rbs! - # # An internal interface for a target that comments can be attached - # # to. This is either going to be a NodeTarget or a CommentTarget. - # interface _CommentTarget - # def start_offset: () -> Integer - # def end_offset: () -> Integer - # def encloses?: (Comment) -> bool - # def leading_comment: (Comment) -> void - # def trailing_comment: (Comment) -> void - # end - - # A target for attaching comments that is based on a specific node's - # location. - class NodeTarget # :nodoc: - attr_reader :node #: node - - #: (node node) -> void - def initialize(node) - @node = node - end - - #: () -> Integer - def start_offset - node.start_offset - end - - #: () -> Integer - def end_offset - node.end_offset - end - - #: (Comment comment) -> bool - def encloses?(comment) - start_offset <= comment.location.start_offset && - comment.location.end_offset <= end_offset - end - - #: (Comment comment) -> void - def leading_comment(comment) - node.location.leading_comment(comment) - end - - #: (Comment comment) -> void - def trailing_comment(comment) - node.location.trailing_comment(comment) - end - end - - # A target for attaching comments that is based on a location field on a - # node. For example, the `end` token of a ClassNode. - class LocationTarget # :nodoc: - attr_reader :location #: Location - - #: (Location location) -> void - def initialize(location) - @location = location - end - - #: () -> Integer - def start_offset - location.start_offset - end - - #: () -> Integer - def end_offset - location.end_offset - end - - #: (Comment comment) -> bool - def encloses?(comment) - false - end - - #: (Comment comment) -> void - def leading_comment(comment) - location.leading_comment(comment) - end - - #: (Comment comment) -> void - def trailing_comment(comment) - location.trailing_comment(comment) - end - end - - # The parse result that we are attaching comments to. - attr_reader :parse_result #: ParseResult - - # Create a new Comments object that will attach comments to the given - # parse result. - # - #: (ParseResult parse_result) -> void - def initialize(parse_result) - @parse_result = parse_result - end - - # Attach the comments to their respective locations in the tree by - # mutating the parse result. - # - #: () -> void - def attach! - parse_result.comments.each do |comment| - preceding, enclosing, following = nearest_targets(parse_result.value, comment) - - if comment.trailing? - if preceding - preceding.trailing_comment(comment) - else - (following || enclosing || NodeTarget.new(parse_result.value)).leading_comment(comment) - end - else - # If a comment exists on its own line, prefer a leading comment. - if following - following.leading_comment(comment) - elsif preceding - preceding.trailing_comment(comment) - else - (enclosing || NodeTarget.new(parse_result.value)).leading_comment(comment) - end - end - end - end - - private - - # Responsible for finding the nearest targets to the given comment within - # the context of the given encapsulating node. - # - #: (node node, Comment comment) -> [_CommentTarget?, _CommentTarget?, _CommentTarget?] - def nearest_targets(node, comment) - comment_start = comment.location.start_offset - comment_end = comment.location.end_offset - - targets = [] #: Array[_CommentTarget] - node.comment_targets.map do |value| - case value - when StatementsNode - targets.concat(value.body.map { |node| NodeTarget.new(node) }) - when Node - targets << NodeTarget.new(value) - when Location - targets << LocationTarget.new(value) - end - end - - targets.sort_by!(&:start_offset) - preceding = nil #: _CommentTarget? - following = nil #: _CommentTarget? - - left = 0 - right = targets.length - - # This is a custom binary search that finds the nearest nodes to the - # given comment. When it finds a node that completely encapsulates the - # comment, it recurses downward into the tree. - while left < right - middle = (left + right) / 2 - target = targets[middle] - - target_start = target.start_offset - target_end = target.end_offset - - if target.encloses?(comment) - # @type var target: NodeTarget - # The comment is completely contained by this target. Abandon the - # binary search at this level. - return nearest_targets(target.node, comment) - end - - if target_end <= comment_start - # This target falls completely before the comment. Because we will - # never consider this target or any targets before it again, this - # target must be the closest preceding target we have encountered so - # far. - preceding = target - left = middle + 1 - next - end - - if comment_end <= target_start - # This target falls completely after the comment. Because we will - # never consider this target or any targets after it again, this - # target must be the closest following target we have encountered so - # far. - following = target - right = middle - next - end - - # This should only happen if there is a bug in this parser. - raise "Comment location overlaps with a target location" - end - - [preceding, NodeTarget.new(node), following] - end - end - end -end diff --git a/Src/StdLib/ruby/4.0/prism/parse_result/newlines.rb b/Src/StdLib/ruby/4.0/prism/parse_result/newlines.rb index ad8d8b6f5..41729bf81 100644 --- a/Src/StdLib/ruby/4.0/prism/parse_result/newlines.rb +++ b/Src/StdLib/ruby/4.0/prism/parse_result/newlines.rb @@ -65,6 +65,117 @@ def visit_lambda_node(node) end end + # Permit def nodes to mark newlines within themselves. The body of an + # endless method definition never emits newline events, so in that case + # mark every line as already seen while visiting it instead. Nested + # scopes (blocks, lambdas, etc.) reset the lines and emit events again. + # + #: (DefNode node) -> void + def visit_def_node(node) + old_lines = @lines + @lines = Array.new(old_lines.size, !node.equal_loc.nil?) + + begin + super(node) + ensure + @lines = old_lines + end + end + + # Permit class nodes to mark newlines within themselves. + # + #: (ClassNode node) -> void + def visit_class_node(node) + old_lines = @lines + @lines = Array.new(old_lines.size, false) + + begin + super(node) + ensure + @lines = old_lines + end + end + + # Permit module nodes to mark newlines within themselves. + # + #: (ModuleNode node) -> void + def visit_module_node(node) + old_lines = @lines + @lines = Array.new(old_lines.size, false) + + begin + super(node) + ensure + @lines = old_lines + end + end + + # Permit singleton class nodes to mark newlines within themselves. + # + #: (SingletonClassNode node) -> void + def visit_singleton_class_node(node) + old_lines = @lines + @lines = Array.new(old_lines.size, false) + + begin + super(node) + ensure + @lines = old_lines + end + end + + # Statements inside string interpolation do not emit newline events, so + # mark every line as already seen while visiting them. Nested scopes + # (blocks, lambdas, defs, etc.) reset the lines and emit events again. + # + #: (EmbeddedStatementsNode node) -> void + def visit_embedded_statements_node(node) + old_lines = @lines + @lines = Array.new(old_lines.size, true) + + begin + super(node) + ensure + @lines = old_lines + end + end + + # The predicate of a while loop is compiled at the end of the loop, + # after the body, so any statements it contains (from parentheses) + # emit their line events again even if the lines were already seen. + # + #: (WhileNode node) -> void + def visit_while_node(node) + old_lines = @lines + @lines = Array.new(old_lines.size, false) + + begin + visit(node.predicate) + ensure + @lines = old_lines + end + + visit(node.statements) + end + + # The predicate of an until loop is compiled at the end of the loop, + # after the body, so any statements it contains (from parentheses) + # emit their line events again even if the lines were already seen. + # + #: (UntilNode node) -> void + def visit_until_node(node) + old_lines = @lines + @lines = Array.new(old_lines.size, false) + + begin + visit(node.predicate) + ensure + @lines = old_lines + end + + visit(node.statements) + end + # Mark if nodes as newlines. # #: (IfNode node) -> void @@ -144,14 +255,26 @@ def newline_flag!(lines) # :nodoc: class UntilNode < Node #: (Array[bool] lines) -> void def newline_flag!(lines) # :nodoc: - predicate.newline_flag!(lines) + if location.start_offset == keyword_loc.start_offset && predicate.is_a?(ParenthesesNode) + # A parenthesized predicate emits its own line event when it is + # compiled at the end of the loop, in addition to this one. + super + else + predicate.newline_flag!(lines) + end end end class WhileNode < Node #: (Array[bool] lines) -> void def newline_flag!(lines) # :nodoc: - predicate.newline_flag!(lines) + if location.start_offset == keyword_loc.start_offset && predicate.is_a?(ParenthesesNode) + # A parenthesized predicate emits its own line event when it is + # compiled at the end of the loop, in addition to this one. + super + else + predicate.newline_flag!(lines) + end end end @@ -162,6 +285,98 @@ def newline_flag!(lines) # :nodoc: end end + # The line event for a statement is emitted where its first instruction is + # compiled, so nodes whose first instruction comes from a sub-expression + # delegate their newline flag to that sub-expression: assignments to their + # value, calls to their receiver, and array, hash, and interpolated string + # literals to their first element. Static literals are the exception: they + # are compiled to a single instruction on the first line of the literal, so + # they do not delegate. + + class LocalVariableWriteNode < Node + #: (Array[bool] lines) -> void + def newline_flag!(lines) # :nodoc: + value.newline_flag!(lines) + end + end + + class InstanceVariableWriteNode < Node + #: (Array[bool] lines) -> void + def newline_flag!(lines) # :nodoc: + value.newline_flag!(lines) + end + end + + class ClassVariableWriteNode < Node + #: (Array[bool] lines) -> void + def newline_flag!(lines) # :nodoc: + value.newline_flag!(lines) + end + end + + class GlobalVariableWriteNode < Node + #: (Array[bool] lines) -> void + def newline_flag!(lines) # :nodoc: + value.newline_flag!(lines) + end + end + + class ConstantWriteNode < Node + #: (Array[bool] lines) -> void + def newline_flag!(lines) # :nodoc: + value.newline_flag!(lines) + end + end + + class ConstantPathWriteNode < Node + #: (Array[bool] lines) -> void + def newline_flag!(lines) # :nodoc: + value.newline_flag!(lines) + end + end + + class MultiWriteNode < Node + #: (Array[bool] lines) -> void + def newline_flag!(lines) # :nodoc: + value.newline_flag!(lines) + end + end + + class CallNode < Node + #: (Array[bool] lines) -> void + def newline_flag!(lines) # :nodoc: + if (receiver = self.receiver) + receiver.newline_flag!(lines) + else + super + end + end + end + + class ArrayNode < Node + #: (Array[bool] lines) -> void + def newline_flag!(lines) # :nodoc: + first = elements.first + if first && !static_literal? + first.newline_flag!(lines) + else + super + end + end + end + + class HashNode < Node + #: (Array[bool] lines) -> void + def newline_flag!(lines) # :nodoc: + first = elements.first + if first && !static_literal? + first.newline_flag!(lines) + else + super + end + end + end + class InterpolatedMatchLastLineNode < Node #: (Array[bool] lines) -> void def newline_flag!(lines) # :nodoc: @@ -182,7 +397,11 @@ class InterpolatedStringNode < Node #: (Array[bool] lines) -> void def newline_flag!(lines) # :nodoc: first = parts.first - first.newline_flag!(lines) if first + if first && !static_literal? + first.newline_flag!(lines) + else + super + end end end diff --git a/Src/StdLib/ruby/4.0/prism/pattern.rb b/Src/StdLib/ruby/4.0/prism/pattern.rb index 2b1437314..50a3626fb 100644 --- a/Src/StdLib/ruby/4.0/prism/pattern.rb +++ b/Src/StdLib/ruby/4.0/prism/pattern.rb @@ -175,7 +175,7 @@ def compile_alternation_pattern_node(node) # :nodoc: def compile_constant_path_node(node) # :nodoc: parent = node.parent - if parent.is_a?(ConstantReadNode) && parent.slice == "Prism" + if (parent.is_a?(ConstantReadNode) || parent.is_a?(ConstantPathNode)) && parent.slice == Prism.name name = node.name raise CompilationError, node.inspect if name.nil? diff --git a/Src/StdLib/ruby/4.0/prism/reflection.rb b/Src/StdLib/ruby/4.0/prism/reflection.rb index 83fcbd274..7ca3b0207 100644 --- a/Src/StdLib/ruby/4.0/prism/reflection.rb +++ b/Src/StdLib/ruby/4.0/prism/reflection.rb @@ -402,7 +402,7 @@ def self.fields_for(node) when :super_node [LocationField.new(:keyword_loc), OptionalLocationField.new(:lparen_loc), OptionalNodeField.new(:arguments), OptionalLocationField.new(:rparen_loc), OptionalNodeField.new(:block)] when :symbol_node - [FlagsField.new(:flags, [:forced_utf8_encoding?, :forced_binary_encoding?, :forced_us_ascii_encoding?]), OptionalLocationField.new(:opening_loc), OptionalLocationField.new(:value_loc), OptionalLocationField.new(:closing_loc), StringField.new(:unescaped)] + [FlagsField.new(:flags, [:forced_utf8_encoding?, :forced_binary_encoding?, :forced_us_ascii_encoding?]), OptionalLocationField.new(:opening_loc), LocationField.new(:content_loc), OptionalLocationField.new(:closing_loc), StringField.new(:unescaped)] when :true_node [] when :undef_node diff --git a/Src/StdLib/ruby/4.0/prism/relocation.rb b/Src/StdLib/ruby/4.0/prism/relocation.rb index fcf51f247..37b60d004 100644 --- a/Src/StdLib/ruby/4.0/prism/relocation.rb +++ b/Src/StdLib/ruby/4.0/prism/relocation.rb @@ -33,8 +33,6 @@ module Relocation # def end_character_column: () -> Integer # def cached_start_code_units_column: (_CodeUnitsCache cache) -> Integer # def cached_end_code_units_column: (_CodeUnitsCache cache) -> Integer - # def leading_comments: () -> Array[Comment] - # def trailing_comments: () -> Array[Comment] # end # # interface _Field @@ -170,27 +168,6 @@ def end_code_units_column fetch_value(:end_code_units_column) end - # Fetch the leading comments of the value. - # - #: () -> Array[CommentsField::Comment] - def leading_comments - fetch_value(:leading_comments) - end - - # Fetch the trailing comments of the value. - # - #: () -> Array[CommentsField::Comment] - def trailing_comments - fetch_value(:trailing_comments) - end - - # Fetch the leading and trailing comments of the value. - # - #: () -> Array[CommentsField::Comment] - def comments - [*leading_comments, *trailing_comments] - end - # Reify the values on this entry with the given values. This is an # internal-only API that is called from the repository when it is time to # reify the values. @@ -427,51 +404,6 @@ def cache end end - # An abstract field used as the parent class of the two comments fields. - class CommentsField - # An object that represents a slice of a comment. - class Comment - # The slice of the comment. - attr_reader :slice #: String - - # Initialize a new comment with the given slice. - # - #: (String slice) -> void - def initialize(slice) - @slice = slice - end - end - - private - - # Create comment objects from the given values. - # - #: (entry_value values) -> Array[Comment] - def comments(values) - values.map { |value| Comment.new(value.slice) } - end - end - - # A field representing the leading comments. - class LeadingCommentsField < CommentsField - # Fetches the leading comments of a value. - # - #: (_Value value) -> entry_values - def fields(value) - { leading_comments: comments(value.leading_comments) } - end - end - - # A field representing the trailing comments. - class TrailingCommentsField < CommentsField - # Fetches the trailing comments of a value. - # - #: (_Value value) -> entry_values - def fields(value) - { trailing_comments: comments(value.trailing_comments) } - end - end - # A repository is a configured collection of fields and a set of entries # that knows how to reparse a source and reify the values. class Repository @@ -567,30 +499,6 @@ def code_unit_columns(encoding) field(:code_unit_columns, CodeUnitColumnsField.new(self, encoding)) end - # Configure the leading comments field for this repository and return - # self. - # - #: () -> self - def leading_comments - field(:leading_comments, LeadingCommentsField.new) - end - - # Configure the trailing comments field for this repository and return - # self. - # - #: () -> self - def trailing_comments - field(:trailing_comments, TrailingCommentsField.new) - end - - # Configure both the leading and trailing comment fields for this - # repository and return self. - # - #: () -> self - def comments - leading_comments.trailing_comments - end - # This method is called from nodes and locations when they want to enter # themselves into the repository. It it internal-only and meant to be # called from the #save* APIs. @@ -610,12 +518,6 @@ def enter(node_id, field_name) # :nodoc: def reify! # :nodoc: result = source.result - # Attach the comments if they have been requested as part of the - # configuration of this repository. - if fields.key?(:leading_comments) || fields.key?(:trailing_comments) - result.attach_comments! - end - queue = [result.value] #: Array[Prism::node] while (node = queue.shift) @entries[node.node_id].each do |field_name, entry| diff --git a/Src/StdLib/ruby/4.0/prism/serialize.rb b/Src/StdLib/ruby/4.0/prism/serialize.rb index 12e06db9e..e6bd3da09 100644 --- a/Src/StdLib/ruby/4.0/prism/serialize.rb +++ b/Src/StdLib/ruby/4.0/prism/serialize.rb @@ -49,7 +49,8 @@ def self.load_parse(input, serialized, freeze) source.replace_start_line(start_line) source.replace_offsets(offsets) - comments = loader.load_comments(freeze) + loader.load_comments(source.comments, freeze) + loader.load_comment_attachments(source, freeze) magic_comments = loader.load_magic_comments(freeze) data_loc = loader.load_optional_location_object(freeze) errors = loader.load_errors(encoding, freeze) @@ -64,7 +65,7 @@ def self.load_parse(input, serialized, freeze) loader.load_constant_pool(constant_pool) raise unless loader.eof? - result = ParseResult.new(node, comments, magic_comments, data_loc, errors, warnings, continuable, source) + result = ParseResult.new(node, magic_comments, data_loc, errors, warnings, continuable, source) result.freeze if freeze input.force_encoding(encoding) @@ -104,7 +105,8 @@ def self.load_lex(input, serialized, freeze) source.replace_start_line(start_line) source.replace_offsets(offsets) - comments = loader.load_comments(freeze) + loader.load_comments(source.comments, freeze) + loader.load_comment_attachments(source, freeze) magic_comments = loader.load_magic_comments(freeze) data_loc = loader.load_optional_location_object(freeze) errors = loader.load_errors(encoding, freeze) @@ -112,7 +114,7 @@ def self.load_lex(input, serialized, freeze) continuable = loader.load_bool raise unless loader.eof? - result = LexResult.new(tokens, comments, magic_comments, data_loc, errors, warnings, continuable, source) + result = LexResult.new(tokens, magic_comments, data_loc, errors, warnings, continuable, source) tokens.each do |token| token[0].value.force_encoding(encoding) @@ -151,7 +153,7 @@ def self.load_parse_comments(input, serialized, freeze) source.replace_start_line(start_line) source.replace_offsets(offsets) - result = loader.load_comments(freeze) + result = loader.load_comments(source.comments, freeze) raise unless loader.eof? source.deep_freeze if freeze @@ -178,7 +180,8 @@ def self.load_parse_lex(input, serialized, freeze) source.replace_start_line(start_line) source.replace_offsets(offsets) - comments = loader.load_comments(freeze) + loader.load_comments(source.comments, freeze) + loader.load_comment_attachments(source, freeze) magic_comments = loader.load_magic_comments(freeze) data_loc = loader.load_optional_location_object(freeze) errors = loader.load_errors(encoding, freeze) @@ -194,7 +197,7 @@ def self.load_parse_lex(input, serialized, freeze) raise unless loader.eof? value = [node, tokens] #: [ProgramNode, Array[Token]] - result = ParseLexResult.new(value, comments, magic_comments, data_loc, errors, warnings, continuable, source) + result = ParseLexResult.new(value, magic_comments, data_loc, errors, warnings, continuable, source) tokens.each do |token| token[0].value.force_encoding(encoding) @@ -327,20 +330,46 @@ def load_line_offsets(freeze) offsets end - #: (bool freeze) -> Array[Comment] - def load_comments(freeze) - comments = - Array.new(load_varuint) do - comment = - case load_varuint - when 0 then InlineComment.new(load_location_object(freeze)) - when 1 then EmbDocComment.new(load_location_object(freeze)) - else raise - end + # Load the comments attached to each node into the comment attachments and + # comment ranges of the given source. For each node that owns comments, the + # index at which its comments begin is stored at its node id and the index + # at which they end at the following node id. + # + #: (Source source, bool freeze) -> void + def load_comment_attachments(source, freeze) + comments = source.comments + attachments = source.comment_attachments + ranges = source.comment_ranges - comment.freeze if freeze - comment - end + load_varuint.times do + node_id = load_varuint + ranges[node_id] = attachments.length + load_varuint.times { attachments << comments[load_varuint] } + ranges[node_id + 1] = attachments.length + end + + if freeze + attachments.freeze + ranges.freeze + end + end + + # Load the comments into the given list, which belongs to the source that + # the comments refer to. + # + #: (Array[Comment] comments, bool freeze) -> Array[Comment] + def load_comments(comments, freeze) + load_varuint.times do + comment = + case load_varuint + when 0 then InlineComment.new(load_location_object(freeze)) + when 1 then EmbDocComment.new(load_location_object(freeze)) + else raise + end + + comment.freeze if freeze + comments << comment + end comments.freeze if freeze comments @@ -2434,7 +2463,7 @@ def load_node(constant_pool, encoding, freeze) location, load_varuint, load_optional_location(freeze), - load_optional_location(freeze), + load_location(freeze), load_optional_location(freeze), load_string(encoding), ) @@ -4942,7 +4971,7 @@ def define_load_node_lambdas location, load_varuint, load_optional_location(freeze), - load_optional_location(freeze), + load_location(freeze), load_optional_location(freeze), load_string(encoding), ) @@ -5266,6 +5295,7 @@ def define_load_node_lambdas :USTAR, :USTAR_STAR, :WORDS_SEP, + :WORDS_SEP_IMPLICIT, :XSTRING_BEGIN, :__END__, ].freeze #: Array[Symbol?] diff --git a/Src/StdLib/ruby/4.0/prism/translation/parser/compiler.rb b/Src/StdLib/ruby/4.0/prism/translation/parser/compiler.rb index 1ef30dab1..b62b1da4c 100644 --- a/Src/StdLib/ruby/4.0/prism/translation/parser/compiler.rb +++ b/Src/StdLib/ruby/4.0/prism/translation/parser/compiler.rb @@ -140,7 +140,7 @@ def visit_assoc_node(node) if key.opening.nil? builder.match_hash_var([key.unescaped, srange(key.location)]) else - builder.match_hash_var_from_str(token(key.opening_loc), [builder.string_internal([key.unescaped, srange(key.value_loc)])], token(key.closing_loc)) + builder.match_hash_var_from_str(token(key.opening_loc), [builder.string_internal([key.unescaped, srange(key.content_loc)])], token(key.closing_loc)) end else builder.match_hash_var_from_str(token(key.opening_loc), visit_all(key.parts), token(key.closing_loc)) @@ -151,9 +151,9 @@ def visit_assoc_node(node) implicit_value = if value.is_a?(CallNode) builder.call_method(nil, nil, [value.name, srange(value.message_loc)]) elsif value.is_a?(ConstantReadNode) - builder.const([value.name, srange(key.value_loc)]) + builder.const([value.name, srange(key.content_loc)]) else - builder.ident([value.name, srange(key.value_loc)]).updated(:lvar) + builder.ident([value.name, srange(key.content_loc)]).updated(:lvar) end builder.pair_keyword([key.unescaped, srange(key)], implicit_value) @@ -165,13 +165,13 @@ def visit_assoc_node(node) else parts = if key.is_a?(SymbolNode) - value_loc = key.value_loc - if value_loc.nil? + content = key.content + if content == "" [] - elsif value_loc.slice.include?("\n") - string_nodes_from_line_continuations(key.unescaped, value_loc.slice, value_loc.start_offset, key.opening) + elsif content.include?("\n") + string_nodes_from_line_continuations(key.unescaped, content, key.content_loc.start_offset, key.opening) else - [builder.string_internal([key.unescaped, srange(value_loc)])] + [builder.string_internal([key.unescaped, srange(key.content_loc)])] end else visit_all(key.parts) @@ -1775,12 +1775,12 @@ def visit_symbol_node(node) end else parts = - if node.value_loc.nil? + if node.content == "" [] - elsif node.value.include?("\n") - string_nodes_from_line_continuations(node.unescaped, node.value, node.value_loc.start_offset, node.opening) + elsif node.content.include?("\n") + string_nodes_from_line_continuations(node.unescaped, node.content, node.content_loc.start_offset, node.opening) else - [builder.string_internal([node.unescaped, srange(node.value_loc)])] + [builder.string_internal([node.unescaped, srange(node.content_loc)])] end builder.symbol_compose( diff --git a/Src/StdLib/ruby/4.0/prism/translation/parser/lexer.rb b/Src/StdLib/ruby/4.0/prism/translation/parser/lexer.rb index a2f517298..226128cda 100644 --- a/Src/StdLib/ruby/4.0/prism/translation/parser/lexer.rb +++ b/Src/StdLib/ruby/4.0/prism/translation/parser/lexer.rb @@ -185,6 +185,7 @@ class Lexer # :nodoc: USTAR: :tSTAR, USTAR_STAR: :tDSTAR, WORDS_SEP: :tSPACE, + WORDS_SEP_IMPLICIT: :tSPACE, XSTRING_BEGIN: :tXSTRING_BEG } @@ -443,15 +444,7 @@ def to_a location = range(token.location.start_offset, token.location.start_offset + 1) end - if percent_array?(quote_stack.pop) - prev_token = lexed[index - 2] if index - 2 >= 0 - empty = %i[PERCENT_LOWER_I PERCENT_LOWER_W PERCENT_UPPER_I PERCENT_UPPER_W].include?(prev_token&.type) - ends_with_whitespace = prev_token&.type == :WORDS_SEP - # parser always emits a space token after content in a percent array, even if no actual whitespace is present. - if !empty && !ends_with_whitespace - tokens << [:tSPACE, [nil, range(token.location.start_offset, token.location.start_offset)]] - end - end + quote_stack.pop when :tSYMBEG if (next_token = lexed[index]) && next_token.type != :STRING_CONTENT && next_token.type != :EMBEXPR_BEGIN && next_token.type != :EMBVAR && next_token.type != :STRING_END next_location = token.location.join(next_token.location) @@ -470,7 +463,9 @@ def to_a when :tXSTRING_BEG quote_stack.push(value) when :tSYMBOLS_BEG, :tQSYMBOLS_BEG, :tWORDS_BEG, :tQWORDS_BEG - if (next_token = lexed[index]) && next_token.type == :WORDS_SEP + # The separator that delimits the opener from the first word is + # part of the opener for parser, so it is not emitted separately. + if (next_token = lexed[index]) && %i[WORDS_SEP WORDS_SEP_IMPLICIT].include?(next_token.type) index += 1 end diff --git a/Src/StdLib/ruby/4.0/prism/translation/ripper.rb b/Src/StdLib/ruby/4.0/prism/translation/ripper.rb index d9c1e69f9..b47df7434 100644 --- a/Src/StdLib/ruby/4.0/prism/translation/ripper.rb +++ b/Src/StdLib/ruby/4.0/prism/translation/ripper.rb @@ -789,7 +789,7 @@ def visit_array_node(node) visit_words_sep(opening_loc, previous, element) bounds(element.location) - elements = on_qsymbols_add(elements, on_tstring_content(element.value)) + elements = on_qsymbols_add(elements, on_tstring_content(element.content)) previous = element end @@ -853,7 +853,7 @@ def visit_array_node(node) on_symbols_add( elements, if element.is_a?(SymbolNode) - on_word_add(on_word_new, on_tstring_content(element.value)) + on_word_add(on_word_new, on_tstring_content(element.content)) else element.parts.inject(on_word_new) do |word, part| word_part = @@ -2351,8 +2351,8 @@ def visit_hash_pattern_node(node) if (key = element.key).opening_loc.nil? visit(key) else - bounds(key.value_loc) - if (value = key.value).empty? + bounds(key.content_loc) + if (value = key.content).empty? on_string_content else on_string_add(on_string_content, on_tstring_content(value)) @@ -3840,23 +3840,25 @@ def visit_super_node(node) # ^^^^ def visit_symbol_node(node) with_string_bounds(node) do - if node.value_loc.nil? - bounds(node.location) - on_dyna_symbol(on_string_content) - elsif (opening = node.opening)&.match?(/^%s|['"]:?$/) - bounds(node.value_loc) - content = on_string_add(on_string_content, on_tstring_content(node.value)) + if (opening = node.opening)&.match?(/^%s|['"]:?$/) + bounds(node.content_loc) + content = on_string_content + + if !(value = node.content).empty? + content = on_string_add(content, on_tstring_content(value)) + end + bounds(node.location) on_dyna_symbol(content) elsif (closing = node.closing) == ":" bounds(node.location) - on_label("#{node.value}:") + on_label("#{node.content}:") elsif opening.nil? && node.closing_loc.nil? - bounds(node.value_loc) - on_symbol_literal(visit_token(node.value)) + bounds(node.content_loc) + on_symbol_literal(visit_token(node.content)) else - bounds(node.value_loc) - on_symbol_literal(on_symbol(visit_token(node.value))) + bounds(node.content_loc) + on_symbol_literal(on_symbol(visit_token(node.content))) end end end diff --git a/Src/StdLib/ruby/4.0/prism/translation/ruby_parser.rb b/Src/StdLib/ruby/4.0/prism/translation/ruby_parser.rb index edb3f3bf0..213464a77 100644 --- a/Src/StdLib/ruby/4.0/prism/translation/ruby_parser.rb +++ b/Src/StdLib/ruby/4.0/prism/translation/ruby_parser.rb @@ -35,11 +35,19 @@ class Compiler < ::Prism::Compiler # :nodoc: # pattern, so we need to track that state. attr_reader :in_pattern + # The list of comments from the parse result, sorted by start offset. + attr_reader :parse_comments + + # The source string being compiled. + attr_reader :source_string + # Initialize a new compiler with the given file name. - def initialize(file, in_def: false, in_pattern: false) + def initialize(file, in_def: false, in_pattern: false, parse_comments: [], source_string: "") @file = file @in_def = in_def @in_pattern = in_pattern + @parse_comments = parse_comments + @source_string = source_string end # alias foo bar @@ -1476,7 +1484,7 @@ def visit_super_node(node) # :foo # ^^^^ def visit_symbol_node(node) - node.value == "!@" ? s(node, :lit, :"!@") : s(node, :lit, node.unescaped.to_sym) + node.content == "!@" ? s(node, :lit, :"!@") : s(node, :lit, node.unescaped.to_sym) end # true @@ -1549,20 +1557,48 @@ def visit_yield_node(node) private - # Attach prism comments to the given sexp. + # Attach leading comments to the given sexp, mirroring ruby_parser's + # behavior: all comments preceding the class/module/def keyword are + # attached as long as no source code appears between the last comment + # and the keyword. Blank lines between comments are preserved. def attach_comments(sexp, node) - return unless node.comments - return if node.comments.empty? + node_start = node.location.start_offset + leading = [] + + parse_comments.each do |comment| + if comment.location.start_offset < node_start + leading << comment + end + end + + return if leading.empty? + + # Walk backwards and drop comments that have source code between + # them and the node (or between them and the next kept comment). + result = [] + boundary = node_start + + leading.reverse_each do |comment| + gap = source_string[comment.location.end_offset...boundary] + + if gap.match?(/\S/) + break + end + + result.unshift(comment) + boundary = comment.location.start_offset + end + + return if result.empty? - extra = node.location.start_line - node.comments.last.location.start_line - comments = node.comments.map(&:slice) - comments.concat([nil] * [0, extra].max) - sexp.comments = comments.join("\n") + # Build the comment string from the first comment through to the + # keyword, preserving blank lines (mirroring ruby_parser's lexer). + sexp.comments = source_string[result.first.location.start_offset...node_start].gsub(/^ +#/, "#").gsub(/^ +$/, "") end # Create a new compiler with the given options. def copy_compiler(in_def: self.in_def, in_pattern: self.in_pattern) - self.class.new(file, in_def: in_def, in_pattern: in_pattern) + self.class.new(file, in_def: in_def, in_pattern: in_pattern, parse_comments: parse_comments, source_string: source_string) end # Create a new Sexp object from the given prism node and arguments. @@ -1678,8 +1714,7 @@ def translate(result, filepath) raise ::RubyParser::SyntaxError, "#{filepath}:#{error.location.start_line} :: #{error.message}" end - result.attach_comments! - result.value.accept(self.class::Compiler.new(filepath)) + result.value.accept(self.class::Compiler.new(filepath, parse_comments: result.comments, source_string: result.source.source)) end end end diff --git a/ir.cmd b/ir.cmd index c4ec32584..c45646278 100644 --- a/ir.cmd +++ b/ir.cmd @@ -33,7 +33,12 @@ if not exist "%IR_BIN%" ( set "S=%IR_ROOT%\Src\StdLib" rem -S searches RUBYPATH before PATH, so `ir.cmd -S irb` runs the irb shipped here. -if "%RUBYPATH%"=="" (set "RUBYPATH=%S%\bin") else (set "RUBYPATH=%S%\bin;%RUBYPATH%") +rem The directory ir.exe is in comes next: it is RubyGems' bindir (RbConfig's bindir), +rem where `igem install` writes the binstubs of installed gems, so `ir.cmd -S ` finds the one written for IronRuby before a host Ruby's - as in ir.sh. +for %%I in ("%IR_BIN%") do set "IR_BINDIR=%%~dpI" +set "IR_BINDIR=%IR_BINDIR:~0,-1%" +if "%RUBYPATH%"=="" (set "RUBYPATH=%S%\bin;%IR_BINDIR%") else (set "RUBYPATH=%S%\bin;%IR_BINDIR%;%RUBYPATH%") rem -X:StdLib is split on Path.PathSeparator, which is ';' on Windows - a ':' list would rem be cut apart at every drive letter.