From 60a1f1ed53e0b157d50b99b5a246a47943a1233b Mon Sep 17 00:00:00 2001 From: Largo Date: Tue, 13 Oct 2026 15:29:42 +0200 Subject: [PATCH 1/2] ir.cmd: put RubyGems' bindir on RUBYPATH, so `ir -S ` finds its binstub The Windows twin of the ir.sh change in #18. RubyGems writes a gem's binstubs to Gem.bindir, which for IronRuby is the directory ir.exe itself is in (RbConfig's bindir). ir.cmd only put Src\StdLib\bin on RUBYPATH, so `ir.cmd -S ` after `igem.cmd install ` skipped the binstub RubyGems had just written and took whatever came first on PATH - a host Ruby's command of the same name, if there was one. The directory of ir.exe now comes after Src\StdLib\bin and before an existing RUBYPATH, the same order ir.sh uses. --- ir.cmd | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ir.cmd b/ir.cmd index c4ec3258..c4564627 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. From 1ba19360a5763086e40dcadbe6f4c5fd95185979 Mon Sep 17 00:00:00 2001 From: Largo Date: Tue, 13 Oct 2026 15:37:59 +0200 Subject: [PATCH 2/2] prism: follow ruby/prism cd76b0d1 (attach_comments) CI builds libprism from prism's main branch, and since ruby/prism#4255 (attach_comments, merged 2026-10-12) every build job has failed in the smoke test with "Unknown prism node type: 0 (TypeError)" - master, #17, #18 and #19 alike. That change altered prism's serialization in two places without moving the serialization version off 1.9, so the version check in PrismLoader could not catch it: - the options blob has a new attach_comments byte after freeze. The blob IronRuby wrote was one byte short, so prism read the scope count from the wrong offset; - the serialized header has a comment-attachment list after the comments (node id, count, comment indices). PrismLoader read its count as the magic comment count and walked off from there. PrismParser.BuildOptionsData writes the byte (0: IronRuby never asks for attachments) and PrismLoader.Load skips the list. PrismLex only reads the token stream, which ends before the header, so it needs nothing. The rest of the revision comes along so that every piece names the same prism commit, as Src/Prism/README.md asks: - Src/Prism/Generated is regenerated from cd76b0d1's config.yml: SymbolNode#value_loc became the non-optional content_loc (the bridge reads neither), and a WORDS_SEP_IMPLICIT token was added after WORDS_SEP. Ripper looks tokens up by name and skips the ones it has no event for, which is what prism's own lex_compat does with this one. - Src/StdLib/ruby/4.0/prism is prism's lib/ at cd76b0d1, generated files included; prism.rb keeps IronRuby's backend branch. parse_result/comments.rb is gone upstream - attaching comments moved into libprism. - Src/StdLib/ironruby/prism/ironruby.rb follows ffi.rb: attach_comments is a known option and is dumped after freeze, and the *_file APIs take a Pathname (to_path / to_str) the way PrismSource.with_file now does. - release.yml's PRISM_REF and the README build instructions move to cd76b0d1. --- .github/workflows/release.yml | 2 +- README.md | 2 +- Src/Prism/Generated/PrismLoader.Generated.cs | 2 +- Src/Prism/Generated/PrismMeta.Generated.cs | 3 +- Src/Prism/Generated/PrismNodes.Generated.cs | 2 +- Src/Prism/PrismLoader.cs | 9 + Src/Prism/PrismParser.cs | 1 + Src/Prism/README.md | 12 +- Src/StdLib/ironruby/prism/ironruby.rb | 37 +- Src/StdLib/ruby/4.0/prism.rb | 34 +- Src/StdLib/ruby/4.0/prism/dot_visitor.rb | 6 +- Src/StdLib/ruby/4.0/prism/dsl.rb | 6 +- Src/StdLib/ruby/4.0/prism/ffi.rb | 42 +- Src/StdLib/ruby/4.0/prism/inspect_visitor.rb | 2 +- Src/StdLib/ruby/4.0/prism/lex_compat.rb | 114 +- Src/StdLib/ruby/4.0/prism/node.rb | 1152 +---------------- Src/StdLib/ruby/4.0/prism/node_ext.rb | 12 + Src/StdLib/ruby/4.0/prism/node_find.rb | 30 + Src/StdLib/ruby/4.0/prism/parse_result.rb | 145 +-- .../ruby/4.0/prism/parse_result/comments.rb | 219 ---- .../ruby/4.0/prism/parse_result/newlines.rb | 225 +++- Src/StdLib/ruby/4.0/prism/pattern.rb | 2 +- Src/StdLib/ruby/4.0/prism/reflection.rb | 2 +- Src/StdLib/ruby/4.0/prism/relocation.rb | 98 -- Src/StdLib/ruby/4.0/prism/serialize.rb | 74 +- .../4.0/prism/translation/parser/compiler.rb | 24 +- .../4.0/prism/translation/parser/lexer.rb | 15 +- .../ruby/4.0/prism/translation/ripper.rb | 32 +- .../ruby/4.0/prism/translation/ruby_parser.rb | 59 +- 29 files changed, 651 insertions(+), 1712 deletions(-) delete mode 100644 Src/StdLib/ruby/4.0/prism/parse_result/comments.rb diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3fcd1c7c..95b02f68 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 13231e38..a99342c5 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 349fa4ad..b1a6c43c 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 7e33377a..59599627 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 9654bfff..fa03bb96 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 be3ca656..c384bf51 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 fdfb6c99..fe75b85f 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 b2781b5d..9455b46b 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 523a65b4..342c59cf 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 61540d76..922a277b 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 2567d6ef..d28642f3 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 e13098b0..b501a7e9 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 d717925c..013f02ca 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 7852c9ba..66a81d26 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 b7921b8d..478d08db 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 03826b9a..bf1e0cc6 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 8f82cda9..301aaf15 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 e9380d0f..7c5bcdcc 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 b5943496..00000000 --- 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 ad8d8b6f..41729bf8 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 2b143731..50a3626f 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 83fcbd27..7ca3b020 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 fcf51f24..37b60d00 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 12e06db9..e6bd3da0 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 1ef30dab..b62b1da4 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 a2f51729..226128cd 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 d9c1e69f..b47df743 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 edb3f3bf..213464a7 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