Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
```
Expand Down
2 changes: 1 addition & 1 deletion Src/Prism/Generated/PrismLoader.Generated.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
};
Expand Down
3 changes: 2 additions & 1 deletion Src/Prism/Generated/PrismMeta.Generated.cs
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ public static class PrismMeta {
"USTAR",
"USTAR_STAR",
"WORDS_SEP",
"WORDS_SEP_IMPLICIT",
"XSTRING_BEGIN",
"__END__",
};
Expand Down Expand Up @@ -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" } } },
Expand Down
2 changes: 1 addition & 1 deletion Src/Prism/Generated/PrismNodes.Generated.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
9 changes: 9 additions & 0 deletions Src/Prism/PrismLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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(); }

Expand Down
1 change: 1 addition & 0 deletions Src/Prism/PrismParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
12 changes: 8 additions & 4 deletions Src/Prism/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
```

Expand All @@ -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:
Expand Down
37 changes: 20 additions & 17 deletions Src/StdLib/ironruby/prism/ironruby.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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

Expand All @@ -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

Expand All @@ -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

Expand All @@ -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

Expand All @@ -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.
Expand All @@ -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

Expand All @@ -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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down
Loading
Loading