Commit graph

637 commits

Author SHA1 Message Date
eileencodes
98d6f50312 [Prism] Implement defined? for PM_CONSTANT_PATH_AND_WRITE_NODE
Ruby code:

```ruby
defined?(Prism::CPAWN &&= 1)
```

Instructions:

```
"********* Ruby *************"
== disasm: #<ISeq:<compiled>@<compiled>:1 (1,0)-(59,58)>
0000 putobject                              "assignment"              (  59)[Li]
0002 leave
"********* PRISM *************"
== disasm: #<ISeq:<compiled>@<compiled>:58 (58,0)-(58,58)>
0000 putobject                              "assignment"              (  58)[Li]
0002 leave
```

Related: ruby/prism#2188
2024-01-17 13:08:49 -08:00
eileencodes
7522e867ee [Prism] Implement defined? for PM_CALL_OR_WRITE_NODE
Ruby code:

```ruby
defined?(PrismTestSubclass.test_call_or_write_node ||= 1)
```

Instructions:

```
"********* Ruby *************"
== disasm: #<ISeq:<compiled>@<compiled>:1 (1,0)-(59,58)>
0000 putobject                              "assignment"              (  59)[Li]
0002 leave
"********* PRISM *************"
== disasm: #<ISeq:<compiled>@<compiled>:58 (58,0)-(58,58)>
0000 putobject                              "assignment"              (  58)[Li]
0002 leave
```

Related: ruby/prism#2188
2024-01-17 13:08:49 -08:00
eileencodes
9c5391d7dc [Prism] Implement defined? for PM_CALL_OPERATOR_WRITE_NODE
Ruby code:

```ruby
defined?(PrismTestSubclass.test_call_operator_write_node += 1)
```

Instructions:

```
"********* Ruby *************"
== disasm: #<ISeq:<compiled>@<compiled>:1 (1,0)-(59,58)>
0000 putobject                              "assignment"              (  59)[Li]
0002 leave
"********* PRISM *************"
== disasm: #<ISeq:<compiled>@<compiled>:58 (58,0)-(58,58)>
0000 putobject                              "assignment"              (  58)[Li]
0002 leave
```

Related: ruby/prism#2188
2024-01-17 13:08:49 -08:00
eileencodes
f657fd150f [Prism] Implement defined? for PM_CALL_AND_WRITE_NODE
Ruby code:

```ruby
defined?(PrismTestSubclass.test_call_and_write_node &&= 1)
```

Instructions:

```
"********* Ruby *************"
== disasm: #<ISeq:<compiled>@<compiled>:1 (1,0)-(59,58)>
0000 putobject                              "assignment"              (  59)[Li]
0002 leave
"********* PRISM *************"
== disasm: #<ISeq:<compiled>@<compiled>:58 (58,0)-(58,58)>
0000 putobject                              "assignment"              (  58)[Li]
0002 leave
```

Related: ruby/prism#2188
2024-01-17 13:08:49 -08:00
Peter Zhu
ebc4704696 [PRISM] Fix indentation in pm_setup_args [ci skip] 2024-01-17 14:45:05 -05:00
Peter Zhu
f43a919be4 [PRISM] Fix fallthrough for PM_ENSURE_NODE
This caused it to fall into PM_ELSE_NODE which caused ensure nodes to be
compiled twice.

Fixes ruby/prism#2176.
2024-01-17 13:17:44 -05:00
Peter Zhu
947194aacb [PRISM] Fix memory leak of ST table
This commit fixes a memory leak in rb_translate_prism because the ST
table is never freed. There are still more memory leaks which still need
to be fixed.

For example:

    10.times do
      100_000.times do
        RubyVM::InstructionSequence.compile_prism("")
      end

      puts `ps -o rss= -p #{$$}`
    end

Before:

    34544
    57120
    79360
    102176
    123712
    146320
    168192
    190592
    212192
    234896

After:

    18336
    24592
    31488
    37648
    44592
    50944
    57280
    63632
    69904
    76160
2024-01-17 11:35:30 -05:00
eileencodes
78ad91f83f [Prism] Fix more method call argumnents
In #2087 it was noted that there was a bug in the number of arguments in
`SplatNode` and `KeywordHashNode`. I looked into this with Aaron before
the linked PR was merged and we found a bunch of cases that weren't
working quite right. This PR aims to fix some of those cases, but there
may be more.

A splat argument followed by a positional argument will concat the array
until the end or unless the argument is a kwarg or splat kwarg. For
example

```
foo(a, *b, c, *d, e)
```

Will have an `argc` of 2, because `b`, `c`, `d`, and `e` will be
concatenated together.

```
foo(a, *b, c, *d, **e)
```

Will have an `argc` of 3, because `b`, `c`, and `d` will be concatenated
together and `e` is a separate argument.
2024-01-17 10:57:19 -05:00
eileencodes
dcf9d77b45 [Prism] Implement defined? for PM_BEGIN_NODE
Ruby code:

```ruby
defined?(begin; 1; end)
```

Instructions:

```
"********* Ruby *************"
== disasm: #<ISeq:<compiled>@<compiled>:1 (1,0)-(59,23)>
0000 putobject                              "expression"              (  59)[Li]
0002 leave
"********* PRISM *************"
== disasm: #<ISeq:<compiled>@<compiled>:58 (58,0)-(58,23)>
0000 putobject                              "expression"              (  58)[Li]
0002 leave
```

Related: ruby/prism#2188
2024-01-17 10:17:59 -05:00
eileencodes
338aa465c0 [Prism] Implement defined? for PM_RETRY_NODE
Ruby code:

```ruby
defined?(retry)
```

Instructions:

```
"********* Ruby *************"
== disasm: #<ISeq:<compiled>@<compiled>:1 (1,0)-(59,15)>
0000 putobject                              "expression"              (  59)[Li]
0002 leave
"********* PRISM *************"
== disasm: #<ISeq:<compiled>@<compiled>:58 (58,0)-(58,15)>
0000 putobject                              "expression"              (  58)[Li]
0002 leave
```

Related: ruby/prism#2188
2024-01-17 10:17:59 -05:00
eileencodes
8774abad55 [Prism] Implement defined? for PM_RETURN_NODE
Ruby code:

```ruby
defined?(return)
```

Instructions:

```
"********* Ruby *************"
== disasm: #<ISeq:<compiled>@<compiled>:1 (1,0)-(59,16)>
0000 putobject                              "expression"              (  59)[Li]
0002 leave
"********* PRISM *************"
== disasm: #<ISeq:<compiled>@<compiled>:58 (58,0)-(58,16)>
0000 putobject                              "expression"              (  58)[Li]
0002 leave
```

Related: ruby/prism#2188
2024-01-17 10:17:59 -05:00
eileencodes
d0a7c33f05 [Prism] Implement defined? for PM_REDO_NODE
Ruby code:

```ruby
defined?(redo)
```

Instructions:

```
"********* Ruby *************"
== disasm: #<ISeq:<compiled>@<compiled>:1 (1,0)-(59,14)>
0000 putobject                              "expression"              (  59)[Li]
0002 leave
"********* PRISM *************"
== disasm: #<ISeq:<compiled>@<compiled>:58 (58,0)-(58,14)>
0000 putobject                              "expression"              (  58)[Li]
0002 leave
```

Related: ruby/prism#2188
2024-01-17 10:17:59 -05:00
eileencodes
2697acf7ff [Prism] Implement defined? for PM_INTERPOLATED_X_STRING_NODE
Ruby code:

```ruby
defined?(`echo #{1}`)
```

Instructions:

```
"********* Ruby *************"
== disasm: #<ISeq:<compiled>@<compiled>:1 (1,0)-(59,21)>
0000 putobject                              "expression"              (  59)[Li]
0002 leave
"********* PRISM *************"
== disasm: #<ISeq:<compiled>@<compiled>:58 (58,0)-(58,21)>
0000 putobject                              "expression"              (  58)[Li]
0002 leave
```

Related: ruby/prism#2188
2024-01-17 10:17:59 -05:00
eileencodes
e0c90199c9 [Prism] Implement defined? for PM_INTERPOLATED_SYMBOL_NODE
Ruby code:

```ruby
defined?(:"1 #{1 + 2} 1")
```

Instructions:

```
"********* Ruby *************"
== disasm: #<ISeq:<compiled>@<compiled>:1 (1,0)-(59,25)>
0000 putobject                              "expression"              (  59)[Li]
0002 leave
"********* PRISM *************"
== disasm: #<ISeq:<compiled>@<compiled>:58 (58,0)-(58,25)>
0000 putobject                              "expression"              (  58)[Li]
0002 leave
```

Related: ruby/prism#2188
2024-01-17 10:17:59 -05:00
eileencodes
25f1a8e447 [Prism] Implement defined? for PM_DEFINED_NODE
Ruby code:

```ruby
defined?(defined?(a))
```

Instructions:

```
"********* Ruby *************"
== disasm: #<ISeq:<compiled>@<compiled>:1 (1,0)-(59,21)>
0000 putobject                              "expression"              (  59)[Li]
0002 leave
"********* PRISM *************"
== disasm: #<ISeq:<compiled>@<compiled>:58 (58,0)-(58,21)>
0000 putobject                              "expression"              (  58)[Li]
0002 leave
```

Related: ruby/prism#2188
2024-01-17 10:17:59 -05:00
eileencodes
82ed90950e [Prism] Implement defined? for PM_BREAK_NODE
Ruby code:

```ruby
defined?(break)
```

Instructions:

```
"********* Ruby *************"
== disasm: #<ISeq:<compiled>@<compiled>:1 (1,0)-(59,15)>
0000 putobject                              "expression"              (  59)[Li]
0002 leave
"********* PRISM *************"
== disasm: #<ISeq:<compiled>@<compiled>:58 (58,0)-(58,15)>
0000 putobject                              "expression"              (  58)[Li]
0002 leave
```

Related: ruby/prism#2188
2024-01-17 10:17:59 -05:00
eileencodes
0c814092ee [Prism] Implement defined for PM_NEXT_NODE
Ruby code:

```ruby
defined?(next)
```

Instructions

```
"********* Ruby *************"
== disasm: #<ISeq:<compiled>@<compiled>:1 (1,0)-(59,15)>
0000 putobject                              "expression"              (  59)[Li]
0002 leave
"********* PRISM *************"
== disasm: #<ISeq:<compiled>@<compiled>:58 (58,0)-(58,15)>
0000 putobject                              "expression"              (  58)[Li]
0002 leave
```

Related: ruby/prism#2188
2024-01-17 10:17:59 -05:00
Matt Valentine-House
ef4a08eb65 [PRISM] Fix stack inconsistency in MultiWriteNode 2024-01-17 14:48:46 +00:00
Peter Zhu
07b9b53459 [PRISM] Fix crash with empty ensure blocks
Fixes ruby/prism#2179.
2024-01-16 12:55:57 -05:00
Matt Valentine-House
7bd7030a96 [PRISM] Replace local lookup recursion with loop 2024-01-16 12:43:53 -05:00
Peter Zhu
70a8ed0775 [PRISM] Don't allocate labels when not needed
The labels lstart, lend, lcont are only needed when there is a rescue
clause. They are not needed when there is only an ensure clause or
neither.
2024-01-16 12:43:14 -05:00
Peter Zhu
1caa881a56 [PRISM] Fix splat assignment
Fixes ruby/prism#2177
2024-01-16 11:12:06 -05:00
Matt Valentine-House
fef8ccff11 Rename pm_lookup_local_index_any_scope
Now it's the only local lookup function we can just call it
pm_lookup_local_index
2024-01-16 14:58:55 +00:00
Matt Valentine-House
543bd7f3db Remove scope_node->local_depth_offset 2024-01-16 14:58:55 +00:00
Matt Valentine-House
1b97f61168 Remove pm_lookup_local_index_with_depth 2024-01-16 14:58:55 +00:00
Matt Valentine-House
0d705b342f Remove the found_depth pointer
Now that we're returning pm_local_index_t
2024-01-16 14:58:55 +00:00
Matt Valentine-House
da383c0d74 Return pm_local_index_t when looking up local indexes
instead of returning the index and updating found_depth in the parent
scope
2024-01-16 14:58:55 +00:00
Matt Valentine-House
f4b299a1ed Bind index & depth together into pm_local_index_t 2024-01-16 14:58:55 +00:00
Matt Valentine-House
3d45b743e4 Replace pm_lookup_local_index with lookup_local_index_with_depth 2024-01-16 14:58:55 +00:00
Peter Zhu
0520e9675b [PRISM] Fix defined? for chained calls
Fixes ruby/prism#2148.
2024-01-16 08:32:21 -05:00
Peter Zhu
6a175902f4 [PRISM] Fix keyword splat inside of array
Fixes ruby/prism#2155.
2024-01-15 17:12:53 -05:00
Peter Zhu
7c6d7fbc28 [PRISM] Fix case without predicate
Fixes ruby/prism#2149.
2024-01-15 09:58:44 -05:00
Aaron Patterson
475663f039 Only intern constants upon compilation entry
Before this commit the Prism compiler would try to intern constants
every time it re-entered. This pool of constants is "constant" (there is
only one pool per parser instance), so we should do it only once: upon
the top level entry to the compiler.

This change does just that: it populates the interned constants once.

Fixes: https://github.com/ruby/prism/issues/2152
2024-01-12 14:53:14 -08:00
Aaron Patterson
2c27a3a0dd Fix splat assigns with no lefties
We still need to emit an expand array even if there's no "left side"
variables

Fixes: https://github.com/ruby/prism/issues/2153
2024-01-12 12:46:28 -08:00
Aaron Patterson
774eef692c Always freeze strings that are in the instructions
Any objects that the instructions reference should be frozen.

Co-Authored-By: Matt Valentine-House <matt@eightbitraptor.com>
2024-01-12 12:20:04 -08:00
Jemma Issroff
84f14ff089 [PRISM] Pre-concatenate Strings in InterpolatedStringNode
This commit concatenates String VALUEs within
InterpolatedStringNodes to allow us to preserve frozenness of
concatenated strings such as `"a""b"`

Co-authored-by: Aaron Patterson <tenderlove@ruby-lang.org>
2024-01-12 12:20:04 -08:00
Peter Zhu
0462b1b350 [PRISM] Fix splat in when
Fixes ruby/prism#2147.
2024-01-12 13:04:23 -05:00
Kevin Newton
2d9db72d37 Write to constant path, call, and index in rescue
When compiling a rescue reference, you can write to a constant
path, a call, or an index. In these cases we need to compile the
prefix expression first, then handle actually doing the write/call.
2024-01-12 11:30:25 -05:00
Aaron Patterson
371256775f Anonymous rest nodes should increase the local table size
When we calculate the local table size, we need to account for anonymous
"rest" parameters.  Since they don't have a name, they won't be in the
"locals" table that Prism provides, but we need to reserve room for them
anyway.

Fixes: https://github.com/ruby/prism/issues/2154
2024-01-11 15:53:52 -08:00
Peter Zhu
45dd8edf82 [PRISM] Fix splat inside of aset
Fixes ruby/prism#2146.
2024-01-11 14:58:24 -05:00
Aaron Patterson
f2149dc094 [PRISM] Support repeated required parameter names.
Fixes: https://github.com/ruby/prism/issues/2062

This patch only fixes positional parameters, we still need to fix the
other cases spelled out in test/prism/fixtures/repeat_parameters.txt
2024-01-11 11:31:59 -08:00
Peter Zhu
51061b6631 [PRISM] Don't increment argc for PM_ASSOC_SPLAT_NODE
Fixes ruby/prism#2087.
2024-01-10 13:32:19 -05:00
Peter Zhu
55b7121358 [PRISM] Frozen string literals should be fstrings
Frozen string literals should not just be frozen, but deduplicated as an
fstring so that two string literals with the same contents are the exact
same object.

Fixes ruby/prism#2095.
2024-01-09 12:24:18 -05:00
Matt Valentine-House
47ff4a1658 [PRISM] Blocks should track the found local depth
Rather than rely purely on local depth offset. This is because we can't
assume a specific depth offset for all variable accesses happening
within a block in the same way that we can for rescue/ensure/for or
other nodes that push scopes.

This is because block parameters are defined in the scope level, so we
always need to start from the top most scope and walk backwards.

Fixes ruby/prism@2053
2024-01-08 19:55:26 +00:00
Kevin Newton
04f64608e8 Sync to latest prism 2024-01-02 09:13:43 -08:00
Matt Valentine-House
3d984366ca [PRISM] Correct the jump target for redo in FOR_NODE 2023-12-19 22:50:59 +00:00
Matt Valentine-House
371ff80840 [PRISM] Fix parameter numbering in For Node 2023-12-19 22:50:59 +00:00
eileencodes
b8074c2f04 [PRISM] Fix incorrect instructions for default_proc=
This is kind of specific and was found via debugging ruby/prism#2061 but
does not actually fix that issue.

The change here checks for `!popped` for the additional instructions
that are normally added for nodes with the `attribute_write` flag.

I also removed the extra catch table by deleting the
`ISEQ_COMPILE_DATA(iseq)->catch_except_p = true;` line. I'm...not
entirely sure why it was added but it doesn't match the upstream
compiler
[code](92b10f5be7/compile.c (L887-L892)).

The changes here unfortunately don't improve the test failures mentioned in
the linked issue so we still have other issues with instructions for
hashes.

Instructions before:

```
"********* Ruby *************"
== disasm: #<ISeq:<compiled>@<compiled>:1 (1,0)-(34,8)>
local table (size: 1, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
[ 1] h@0
0000 putnil                                                           (  32)[Li]
0001 putobject                              true
0003 getconstant                            :Hash
0005 send                                   <calldata!mid:new, argc:0, ARGS_SIMPLE>, nil
0008 setlocal                               h@0, 0
0011 getlocal                               h@0, 0                    (  33)[Li]
0014 putspecialobject                       1
0016 send                                   <calldata!mid:lambda, argc:0, FCALL>, block in <compiled>
0019 send                                   <calldata!mid:default_proc=, argc:1, ARGS_SIMPLE>, nil
0022 pop
0023 getlocal                               h@0, 0                    (  34)[Li]
0026 putobject                              :nope
0028 send                                   <calldata!mid:[], argc:1, ARGS_SIMPLE>, nil
0031 leave

== disasm: #<ISeq:block in <compiled>@<compiled>:33 (33,19)-(33,32)>
local table (size: 2, argc: 2 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
[ 2] _@0<Arg>   [ 1] _@1<Arg>
0000 putobject                              true                      (  33)[LiBc]
0002 leave                                  [Br]
true
"********* PRISM *************"
== disasm: #<ISeq:<compiled>@<compiled>:31 (31,0)-(33,8)>
local table (size: 1, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
[ 1] h@0
0000 putnil                                                           (  31)[Li]
0001 putobject                              true
0003 getconstant                            :Hash
0005 send                                   <calldata!mid:new, argc:0, ARGS_SIMPLE>, nil
0008 setlocal                               h@0, 0
0011 putnil                                                           (  32)[Li]
0012 getlocal                               h@0, 0
0015 putspecialobject                       1
0017 send                                   <calldata!mid:lambda, argc:0, FCALL>, block in <compiled>
0020 setn                                   2
0022 send                                   <calldata!mid:default_proc=, argc:1, ARGS_SIMPLE>, nil
0025 pop
0026 pop
0027 getlocal                               h@0, 0                    (  33)[Li]
0030 putobject                              :nope
0032 send                                   <calldata!mid:[], argc:1, ARGS_SIMPLE>, nil
0035 leave                                                            (  31)

== disasm: #<ISeq:block in <compiled>@<compiled>:32 (32,17)-(32,32)>
== catch table
| catch type: redo   st: 0000 ed: 0002 sp: 0000 cont: 0000
| catch type: next   st: 0000 ed: 0002 sp: 0000 cont: 0002
|------------------------------------------------------------------------
local table (size: 2, argc: 2 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
[ 2] _@0<Arg>   [ 1] _@1<Arg>
0000 putobject                              true                      (  32)[LiBc]
0002 leave                                  [Br]
```

Instructions after:

```
"********* Ruby *************"
== disasm: #<ISeq:<compiled>@<compiled>:1 (1,0)-(34,8)>
local table (size: 1, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
[ 1] h@0
0000 putnil                                                           (  32)[Li]
0001 putobject                              true
0003 getconstant                            :Hash
0005 send                                   <calldata!mid:new, argc:0, ARGS_SIMPLE>, nil
0008 setlocal                               h@0, 0
0011 getlocal                               h@0, 0                    (  33)[Li]
0014 putspecialobject                       1
0016 send                                   <calldata!mid:lambda, argc:0, FCALL>, block in <compiled>
0019 send                                   <calldata!mid:default_proc=, argc:1, ARGS_SIMPLE>, nil
0022 pop
0023 getlocal                               h@0, 0                    (  34)[Li]
0026 putobject                              :nope
0028 send                                   <calldata!mid:[], argc:1, ARGS_SIMPLE>, nil
0031 leave

== disasm: #<ISeq:block in <compiled>@<compiled>:33 (33,19)-(33,32)>
local table (size: 2, argc: 2 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
[ 2] _@0<Arg>   [ 1] _@1<Arg>
0000 putobject                              true                      (  33)[LiBc]
0002 leave                                  [Br]

"********* PRISM *************"
== disasm: #<ISeq:<compiled>@<compiled>:31 (31,0)-(33,8)>
local table (size: 1, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
[ 1] h@0
0000 putnil                                                           (  31)[Li]
0001 putobject                              true
0003 getconstant                            :Hash
0005 send                                   <calldata!mid:new, argc:0, ARGS_SIMPLE>, nil
0008 setlocal                               h@0, 0
0011 getlocal                               h@0, 0                    (  32)[Li]
0014 putspecialobject                       1
0016 send                                   <calldata!mid:lambda, argc:0, FCALL>, block in <compiled>
0019 send                                   <calldata!mid:default_proc=, argc:1, ARGS_SIMPLE>, nil
0022 pop
0023 getlocal                               h@0, 0                    (  33)[Li]
0026 putobject                              :nope
0028 send                                   <calldata!mid:[], argc:1, ARGS_SIMPLE>, nil
0031 leave                                                            (  31)

== disasm: #<ISeq:block in <compiled>@<compiled>:32 (32,17)-(32,32)>
local table (size: 2, argc: 2 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
[ 2] _@0<Arg>   [ 1] _@1<Arg>
0000 putobject                              true                      (  32)[LiBc]
0002 leave                                  [Br]
```
2023-12-15 16:23:06 -05:00
Matt Valentine-House
161787f9be [PRISM] Compile CallTargetNode 2023-12-15 16:15:10 -05:00
Matt Valentine-House
5b6a4d8c12 [PRISM] Compile IndexTargetNode 2023-12-15 16:15:10 -05:00