Kevin Newton
5c9c69bbe6
[PRISM] Use Prism checksum for hash comparison
2026-10-19 17:30:05 -04:00
Hiroshi SHIBATA and Claude Opus 5
454c9df847
Use rb_len_t to iterate over Array elements
...
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-10-09 14:00:15 +09:00
Luke Gruber
6e3061c7d3
Add accessors for ISEQ_BODY(iseq)->variable fields
2026-08-24 14:25:12 -04:00
Luke Gruber
5552e2c57f
Shrink iseq->body struct: allocate iseq->body->variable lazily
...
Most of the time in a production app most iseqs won't have iseq->body->variable
set to anything non-default. We can allocate it lazily and save 32 bytes per iseq.
Some large apps have millions of iseqs, so it adds up.
32B saved per iseq * 2mil iseqs =~ 64 MB
2026-08-24 14:25:12 -04:00
Yusuke Endoh and Claude Fable 5
6408f147b1
Add Thread::Backtrace::Location#syntax_tree
...
Returns the AST node at the location: the node of the surrounding
method or block is retrieved and validated in the same way as
Proc#syntax_tree, and then the node at the program counter is searched
within it ([Feature #21795 ]).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-08-07 20:56:33 +09:00
Yusuke Endoh and Claude Fable 5
6e65742a9f
Add Proc#syntax_tree, Method#syntax_tree, and UnboundMethod#syntax_tree
...
Returns the AST node that the proc or method was compiled from, by
re-parsing the source ([Feature #21795 ]). Returns nil if the node
cannot be retrieved reliably: the stored source hash guarantees that
the re-parsed source is likely the same code before the node is looked
up by its node id. For a proc defined by a block, the outer node that
owns the block (such as the method call with the block) is returned
rather than the block node itself.
The source is re-parsed by the same parser that compiled it. For
prism, the default gem prism is expected, because it is the same
parser as the one built into the interpreter; when another prism gem
is loaded, a warning is emitted in verbose mode since it may parse the
source differently. `version: "current"` is passed so that the source
is parsed with the grammar of the running Ruby.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-08-07 20:56:33 +09:00
Benoit Daloze
eb0254e115
Check the source hash for Thread::Backtrace::Location#source_range
2026-08-06 13:20:23 +02:00
Benoit Daloze
84a9e6bed7
[Feature #22212 ] Add Thread::Backtrace::Location#source_range
2026-08-06 13:20:23 +02:00
John Hawthorn and Luke Gruber
daffaaee73
Mark most TypedData types as THREAD_SAFE_FREE
...
Set RUBY_TYPED_THREAD_SAFE_FREE on TypedData types whose dfree function
is trivially safe, and only frees its own memory
Types not yet marked as THREAD_SAFE_FREE:
- id2ref_tbl_type: sets the process-global id2ref_tbl to NULL.
- mutex_data_type: unlinks itself from another thread's keeping_mutexes list.
- autoload_data_type: deletes nodes from a shared intrusive list.
- autoload_const_type: deletes itself from a shared list.
- rb_cont_data_type: mutates the shared fiber pool and the global first_jit_cont list.
- rb_fiber_data_type: delegates to cont_free.
- FiberPoolDataType: mutates shared fiber pool free-lists.
- ractor_data_type: reconfigures global VM event-hook flags and call caches.
- exported_object_registry: frees a global table under the VM lock.
- rb_box_data_type (Box::Entry): unlinks classext from other live class and module objects.
- box_ext_cleanup_type: dereferences another String object and calls unlink.
- monitor_data_type: uses the default free, so the flag has no effect.
Co-authored-by: Luke Gruber <luke.gruber@shopify.com >
2026-06-23 13:30:26 -07:00
Nobuyoshi Nakada
13926009ba
[Bug #21983 ] Make &nil distinguishable from nonexistent block arg
2026-04-07 17:23:43 +09:00
Andrii Furmanets
4009b713a6
[Bug #21974 ] Fix RubyVM::AST inspection for ::Foo = 1 ( #16642 )
...
* Fix AST CDECL children for top-level constants
* Simplify cdecl AST regression test
2026-04-02 11:08:17 +00:00
Luke Gruber
aace29d485
Check for NULL fields in TYPEDDATA memsize functions ( #15633 )
...
Some TYPEDDATA objects allocate struct fields using the GC right after
they get created, and in that case the VM can try to perform a GC and join
a barrier if another ractor started one. If we're dumping the heap in another
ractor, this acquires a barrier and it will call the `rb_obj_memsize` function on this
object. We can't assume these struct fields are non-null. This also goes for C extensions,
which may cause problems with heap dumping from a ractor if their memsize functions aren't
coded correctly to check for NULL fields. Because dumping the heap from a ractor is likely a
rare scenario and it has only recently been introduced, we'll have to see how this works in
practice and if it causes bugs.
2025-12-18 15:42:49 -05:00
S-H-GAMELINKS
dd4e7801f3
Add NODE SCLASS locations
...
Add locations to struct `RNode_SCLASS`.
memo:
```
@ ProgramNode (location: (1,0)-(1,18))
+-- locals: []
+-- statements:
@ StatementsNode (location: (1,0)-(1,18))
+-- body: (length: 1)
+-- @ SingletonClassNode (location: (1,0)-(1,18))
+-- locals: []
+-- class_keyword_loc: (1,0)-(1,5) = "class"
+-- operator_loc: (1,6)-(1,8) = "<<"
+-- expression:
| @ SelfNode (location: (1,9)-(1,13))
+-- body: nil
+-- end_keyword_loc: (1,15)-(1,18) = "end"
```
2025-08-30 22:41:23 +09:00
S-H-GAMELINKS
4775d1ffa8
Add NODE IN locations
...
Add locations to struct `RNode_IN`.
memo:
```bash
> ruby -e 'case 1; in 2 then 3; end' --parser=prism --dump=parsetree
@ ProgramNode (location: (1,0)-(1,24))
+-- locals: []
+-- statements:
@ StatementsNode (location: (1,0)-(1,24))
+-- body: (length: 1)
+-- @ CaseMatchNode (location: (1,0)-(1,24))
+-- predicate:
| @ IntegerNode (location: (1,5)-(1,6))
| +-- IntegerBaseFlags: decimal
| +-- value: 1
+-- conditions: (length: 1)
| +-- @ InNode (location: (1,8)-(1,19))
| +-- pattern:
| | @ IntegerNode (location: (1,11)-(1,12))
| | +-- IntegerBaseFlags: decimal
| | +-- value: 2
| +-- statements:
| | @ StatementsNode (location: (1,18)-(1,19))
| | +-- body: (length: 1)
| | +-- @ IntegerNode (location: (1,18)-(1,19))
| | +-- IntegerBaseFlags: decimal
| | +-- value: 3
| +-- in_loc: (1,8)-(1,10) = "in"
| +-- then_loc: (1,13)-(1,17) = "then"
+-- else_clause: nil
+-- case_keyword_loc: (1,0)-(1,4) = "case"
+-- end_keyword_loc: (1,21)-(1,24) = "end"
```
2025-08-11 22:25:47 +09:00
S-H-GAMELINKS
bcd21053f7
Add MODULE NODE locations
...
Add `keyword_module` amd `keyword_end` locations to struct `RNode_MODULE`.
memo:
```
>ruby --dump=parsetree -e 'module A end'
@ ProgramNode (location: (1,0)-(1,12))
+-- locals: []
+-- statements:
@ StatementsNode (location: (1,0)-(1,12))
+-- body: (length: 1)
+-- @ ModuleNode (location: (1,0)-(1,12))
+-- locals: []
+-- module_keyword_loc: (1,0)-(1,6) = "module"
+-- constant_path:
| @ ConstantReadNode (location: (1,7)-(1,8))
| +-- name: :A
+-- body: nil
+-- end_keyword_loc: (1,9)-(1,12) = "end"
+-- name: :A
```
2025-08-07 01:07:16 +09:00
ydah
b2838bef69
Add NODE_DEFINED tests for cases with parentheses to test_ast.rb
2025-07-25 01:07:32 +09:00
S-H-GAMELINKS
fd492a45eb
Add DEFINED NODE locations
...
Add keyword_defined locations to struct RNode_DEFINED
2025-07-24 23:30:23 +09:00
ydah
d60144a490
Implement COLON3 NODE locations
2025-06-15 22:37:20 +09:00
ydah
c584790bde
Implement COLON2 NODE locations
2025-06-15 22:37:20 +09:00
ydah
eae0fe37c0
Implement CLASS NODE locations
...
The following Location information has been added This is the information required for parse.y to be a universal parser:
```
❯ ruby --parser=prism --dump=parsetree -e "class A < B; end"
@ ProgramNode (location: (1,0)-(1,16))
+-- locals: []
+-- statements:
@ StatementsNode (location: (1,0)-(1,16))
+-- body: (length: 1)
+-- @ ClassNode (location: (1,0)-(1,16))
+-- locals: []
+-- class_keyword_loc: (1,0)-(1,5) = "class"
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+-- constant_path:
| @ ConstantReadNode (location: (1,6)-(1,7))
| +-- name: :A
+-- inheritance_operator_loc: (1,8)-(1,9) = "<"
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+-- superclass:
| @ ConstantReadNode (location: (1,10)-(1,11))
| +-- name: :B
+-- body: nil
+-- end_keyword_loc: (1,13)-(1,16) = "end"
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+-- name: :A
```
2025-03-08 18:26:40 +09:00
ydah
a47e686cb6
Implement POSTEXE NODE locations
...
The following Location information has been added This is the information required for parse.y to be a universal parser:
```
❯ ruby --parser=prism --dump=parsetree -e "END { }"
@ ProgramNode (location: (1,0)-(1,8))
+-- locals: []
+-- statements:
@ StatementsNode (location: (1,0)-(1,8))
+-- body: (length: 1)
+-- @ PostExecutionNode (location: (1,0)-(1,8))
+-- statements: nil
+-- keyword_loc: (1,0)-(1,3) = "END"
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+-- opening_loc: (1,4)-(1,5) = "{"
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+-- closing_loc: (1,7)-(1,8) = "}"
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
```
2025-03-03 11:17:14 +09:00
ydah
c721301132
Implement FOR NODE locations
...
The following Location information has been added This is the information required for parse.y to be a universal parser:
```
❯ ruby --parser=prism --dump=parsetree -e "for a in b do end"
@ ProgramNode (location: (1,0)-(1,17))
+-- locals: [:a]
+-- statements:
@ StatementsNode (location: (1,0)-(1,17))
+-- body: (length: 1)
+-- @ ForNode (location: (1,0)-(1,17))
+-- index:
| @ LocalVariableTargetNode (location: (1,4)-(1,5))
| +-- name: :a
| +-- depth: 0
+-- collection:
| @ CallNode (location: (1,9)-(1,10))
| +-- CallNodeFlags: variable_call, ignore_visibility
| +-- receiver: nil
| +-- call_operator_loc: nil
| +-- name: :b
| +-- message_loc: (1,9)-(1,10) = "b"
| +-- opening_loc: nil
| +-- arguments: nil
| +-- closing_loc: nil
| +-- block: nil
+-- statements: nil
+-- for_keyword_loc: (1,0)-(1,3) = "for"
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+-- in_keyword_loc: (1,6)-(1,8) = "in"
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+-- do_keyword_loc: (1,11)-(1,13) = "do"
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+-- end_keyword_loc: (1,14)-(1,17) = "end"
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
```
2025-01-09 18:24:56 +09:00
ydah
c936699431
Implement FLIP3 NODE locations
2025-01-04 20:27:40 +09:00
ydah
24653430cd
Implement FLIP2 NODE locations
2025-01-04 20:27:40 +09:00
ydah
61c4907458
Implement DOT3 NODE locations
2025-01-04 20:27:40 +09:00
ydah
88da6856a3
Implement DOT2 NODE locations
2025-01-04 20:27:40 +09:00
ydah
5fcc3ab534
Implement REGX NODE locations
...
The following Location information has been added This is the information required for parse.y to be a universal parser:
```
❯ ruby --parser=prism --dump=parsetree -e '/foo/'
@ ProgramNode (location: (1,0)-(1,5))
+-- locals: []
+-- statements:
@ StatementsNode (location: (1,0)-(1,5))
+-- body: (length: 1)
+-- @ RegularExpressionNode (location: (1,0)-(1,5))
+-- RegularExpressionFlags: forced_us_ascii_encoding
+-- opening_loc: (1,0)-(1,1) = "/"
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+-- content_loc: (1,1)-(1,4) = "foo"
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+-- closing_loc: (1,4)-(1,5) = "/"
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+-- unescaped: "foo"
```
2025-01-04 13:53:13 +09:00
ydah
fa2517451e
Implement LAMBDA NODE locations
...
The following Location information has been added This is the information required for parse.y to be a universal parser:
```
❯ ruby --parser=prism --dump=parsetree -e "-> (a, b) do foo end"
@ ProgramNode (location: (1,0)-(1,20))
+-- locals: []
+-- statements:
@ StatementsNode (location: (1,0)-(1,20))
+-- body: (length: 1)
+-- @ LambdaNode (location: (1,0)-(1,20))
+-- locals: [:a, :b]
+-- operator_loc: (1,0)-(1,2) = "->"
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+-- opening_loc: (1,10)-(1,12) = "do"
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+-- closing_loc: (1,17)-(1,20) = "end"
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
: (snip)
```
2025-01-04 13:52:35 +09:00
ydah
607b1b3d76
Implement YIELD NODE locations
...
The following Location information has been added This is the information required for parse.y to be a universal parser:
```
❯ ruby --parser=prism --dump=parsetree -e 'def foo; yield end'
@ ProgramNode (location: (1,0)-(1,18))
+-- locals: []
+-- statements:
@ StatementsNode (location: (1,0)-(1,18))
+-- body: (length: 1)
+-- @ DefNode (location: (1,0)-(1,18))
+-- name: :foo
+-- name_loc: (1,4)-(1,7) = "foo"
+-- receiver: nil
+-- parameters: nil
+-- body:
| @ StatementsNode (location: (1,9)-(1,14))
| +-- body: (length: 1)
| +-- @ YieldNode (location: (1,9)-(1,14))
| +-- keyword_loc: (1,9)-(1,14) = "yield"
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| +-- lparen_loc: nil
^^^^^^^^^^^^^^^^^^^
| +-- arguments: nil
| +-- rparen_loc: nil
^^^^^^^^^^^^^^^^^^^
+-- locals: []
+-- def_keyword_loc: (1,0)-(1,3) = "def"
+-- operator_loc: nil
+-- lparen_loc: nil
+-- rparen_loc: nil
+-- equal_loc: nil
+-- end_keyword_loc: (1,15)-(1,18) = "end"
```
2025-01-04 07:34:49 +09:00
ydah
4c19201142
Implement EVSTR NODE locations
...
The following Location information has been added This is the information required for parse.y to be a universal parser:
```
❯ ruby --parser=prism --dump=parsetree -e '"#{foo}"'
@ ProgramNode (location: (1,0)-(1,8))
+-- locals: []
+-- statements:
@ StatementsNode (location: (1,0)-(1,8))
+-- body: (length: 1)
+-- @ InterpolatedStringNode (location: (1,0)-(1,8))
+-- InterpolatedStringNodeFlags: nil
+-- opening_loc: (1,0)-(1,1) = "\""
+-- parts: (length: 1)
| +-- @ EmbeddedStatementsNode (location: (1,1)-(1,7))
| +-- opening_loc: (1,1)-(1,3) = "\#{"
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| +-- statements:
| | @ StatementsNode (location: (1,3)-(1,6))
| | +-- body: (length: 1)
| | +-- @ CallNode (location: (1,3)-(1,6))
| | +-- CallNodeFlags: variable_call, ignore_visibility
| | +-- receiver: nil
| | +-- call_operator_loc: nil
| | +-- name: :foo
| | +-- message_loc: (1,3)-(1,6) = "foo"
| | +-- opening_loc: nil
| | +-- arguments: nil
| | +-- closing_loc: nil
| | +-- block: nil
| +-- closing_loc: (1,6)-(1,7) = "}"
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+-- closing_loc: (1,7)-(1,8) = "\""
```
2025-01-04 07:34:25 +09:00
ydah
c22b0598b0
Implement SUPER NODE locations
2025-01-03 23:03:04 +09:00
Yudai Takada and Nobuyoshi Nakada
d4009d939c
Remove spaces
...
Co-authored-by: Nobuyoshi Nakada <nobu.nakada@gmail.com >
2025-01-03 21:26:21 +09:00
ydah
4b02a7b794
Change rb_ast_compile to a function that simply creates a parser and sets options
2025-01-03 21:26:21 +09:00
ydah
b33c1e4bb2
Extract rb_ast_compile
...
From duplicate code in `rb_ast_parse_str`, `rb_ast_parse_file` and `rb_ast_parse_array`.
2025-01-03 21:26:21 +09:00
ydah
0643f08187
Implement IF NODE locations
...
The following Location information has been added This is the information required for parse.y to be a universal parser:
```
❯ ruby --parser=prism --dump=parsetree -y -e "if a; elsif b; else end"
@ ProgramNode (location: (1,0)-(1,23))
+-- locals: []
+-- statements:
@ StatementsNode (location: (1,0)-(1,23))
+-- body: (length: 1)
+-- @ IfNode (location: (1,0)-(1,23))
+-- if_keyword_loc: (1,0)-(1,2) = "if"
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+-- predicate:
| @ CallNode (location: (1,3)-(1,4))
| +-- CallNodeFlags: variable_call, ignore_visibility
| +-- receiver: nil
| +-- call_operator_loc: nil
| +-- name: :a
| +-- message_loc: (1,3)-(1,4) = "a"
| +-- opening_loc: nil
| +-- arguments: nil
| +-- closing_loc: nil
| +-- block: nil
+-- then_keyword_loc: nil
^^^^^^^^^^^^^^^^^^^^^^^^^
+-- statements: nil
+-- subsequent:
| @ IfNode (location: (1,6)-(1,23))
| +-- if_keyword_loc: (1,6)-(1,11) = "elsif"
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| +-- predicate:
| | @ CallNode (location: (1,12)-(1,13))
| | +-- CallNodeFlags: variable_call, ignore_visibility
| | +-- receiver: nil
| | +-- call_operator_loc: nil
| | +-- name: :b
| | +-- message_loc: (1,12)-(1,13) = "b"
| | +-- opening_loc: nil
| | +-- arguments: nil
| | +-- closing_loc: nil
| | +-- block: nil
| +-- then_keyword_loc: nil
^^^^^^^^^^^^^^^^^^^^^^^^^
| +-- statements: nil
| +-- subsequent:
| | @ ElseNode (location: (1,15)-(1,23))
| | +-- else_keyword_loc: (1,15)-(1,19) = "else"
| | +-- statements: nil
| | +-- end_keyword_loc: (1,20)-(1,23) = "end"
| +-- end_keyword_loc: (1,20)-(1,23) = "end"
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+-- end_keyword_loc: (1,20)-(1,23) = "end"
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
```
2025-01-03 20:34:19 +09:00
ydah
044e57ed7c
Implement SPLAT NODE keyword locations
2024-09-30 18:04:41 +09:00
ydah
8f678d6989
Implement OP_ASGN2 NODE locations
2024-09-28 20:53:09 +09:00
ydah
eff16d9302
Implement OP_ASGN1 NODE locations
2024-09-27 18:20:00 +09:00
ydah
509b577e01
Implement BLOCK_PASS NODE keyword locations
2024-09-25 09:15:43 +09:00
ydah
31a88d1554
Implement RETURN NODE keyword locations
2024-09-25 09:06:42 +09:00
ydah
b811a9a097
Implement CASE3 NODE keyword locations
2024-09-23 09:19:37 +09:00
ydah
5334766beb
Implement CASE2 NODE keyword locations
2024-09-23 09:19:37 +09:00
ydah
feac2b4b77
Implement CASE NODE keyword locations
2024-09-23 09:19:37 +09:00
ydah
d03e0d1c35
Implement BREAK, NEXT and REDO NODE locations
2024-09-11 18:01:16 +09:00
ydah
4e6091ce09
Implement WHILE and UNTIL NODE locations
2024-09-11 09:28:55 +09:00
ydah
d52e599538
Implement WHEN NODE locations
2024-09-09 10:34:02 +09:00
ydah
32680f543c
Implement AND/OR NODE operator locations
2024-09-05 13:03:28 +09:00
ydah
ab18b1b4f5
Implement VALIAS NODE keyword locations
2024-09-04 14:36:35 +09:00
ydah
a2243ee48b
Implement ALIAS NODE keyword locations
2024-09-03 22:09:08 +09:00
ydah
af143d8a74
Implement UNDEF NODE keyword locations
2024-09-03 21:15:12 +09:00