Commit graph

555 commits

Author SHA1 Message Date
Ufuk Kayserilioglu
0562c246eb Add handling of implicit hash arguments
Arguments that are passed as a hash need special consideration since in certain case they are not treated as keyword arguments. For example, if a call is passing `"a" => 1` as an argument, this will be turned into an implicit hash argument and not a keyword argument.

The existing compiler checks to see if all hash nodes can be treated as keyword arguments. If they can, then it will treat them as keyword arguments. If not, then it will treat them as implicit hash arguments.

This commit implements the same logic inside the Prism compiler.
2023-12-11 09:47:33 -05:00
eileencodes
1cbe114d1c [PRISM] Fix PM_CALL_NODE assignment
This PR fixes ruby/prism#1963. Array and variable assignment was broken
for call nodes. The change checks if the `method_id` is related to
assignment and if is adds a `putnil`, `setn` and a `pop`.

The incorrect instructions meant that in some cases (demonstrated in
tests) the wrong value would be returned.

I verified that this fixes the test mentioned in the issue
(run: `RUBY_ISEQ_DUMP_DEBUG=prism make test/-ext-/st/test_numhash.rb`)

Incorrect instructions:

```
"********* Ruby *************"
== disasm: #<ISeq:<compiled>@<compiled>:1 (1,0)-(4,10)>
0000 putnil                                                           (   4)[Li]
0001 putself
0002 send                                   <calldata!mid:tbl, argc:0, FCALL|VCALL|ARGS_SIMPLE>, nil
0005 putself
0006 send                                   <calldata!mid:i, argc:0, FCALL|VCALL|ARGS_SIMPLE>, nil
0009 putself
0010 send                                   <calldata!mid:j, argc:0, FCALL|VCALL|ARGS_SIMPLE>, nil
0013 setn                                   3
0015 send                                   <calldata!mid:[]=, argc:2, ARGS_SIMPLE>, nil
0018 pop
0019 leave

"********* PRISM *************"
== disasm: #<ISeq:<compiled>@<compiled>:3 (3,0)-(3,10)>
0000 putself                                                          (   3)[Li]
0001 send                                   <calldata!mid:tbl, argc:0, FCALL|VCALL|ARGS_SIMPLE>, nil
0004 putself
0005 send                                   <calldata!mid:i, argc:0, FCALL|VCALL|ARGS_SIMPLE>, nil
0008 putself
0009 send                                   <calldata!mid:j, argc:0, FCALL|VCALL|ARGS_SIMPLE>, nil
0012 send                                   <calldata!mid:[]=, argc:2, ARGS_SIMPLE>, nil
0015 leave
```

Fixed instructions:

```
"********* Ruby *************"
== disasm: #<ISeq:<compiled>@<compiled>:1 (1,0)-(4,10)>
0000 putnil                                                           (   4)[Li]
0001 putself
0002 send                                   <calldata!mid:tbl, argc:0, FCALL|VCALL|ARGS_SIMPLE>, nil
0005 putself
0006 send                                   <calldata!mid:i, argc:0, FCALL|VCALL|ARGS_SIMPLE>, nil
0009 putself
0010 send                                   <calldata!mid:j, argc:0, FCALL|VCALL|ARGS_SIMPLE>, nil
0013 setn                                   3
0015 send                                   <calldata!mid:[]=, argc:2, ARGS_SIMPLE>, nil
0018 pop
0019 leave

"********* PRISM *************"
== disasm: #<ISeq:<compiled>@<compiled>:3 (3,0)-(3,10)>
0000 putnil                                                           (   3)[Li]
0001 putself
0002 send                                   <calldata!mid:tbl, argc:0, FCALL|VCALL|ARGS_SIMPLE>, nil
0005 putself
0006 send                                   <calldata!mid:i, argc:0, FCALL|VCALL|ARGS_SIMPLE>, nil
0009 putself
0010 send                                   <calldata!mid:j, argc:0, FCALL|VCALL|ARGS_SIMPLE>, nil
0013 setn                                   3
0015 send                                   <calldata!mid:[]=, argc:2, ARGS_SIMPLE>, nil
0018 pop
0019 leave
```

Fixes ruby/prism#1963
2023-12-08 12:45:40 -08:00
Aaron Patterson
9d696aa204 Support method calls inside defined?
This commit supports all kinds of method calls (including methods with
parameters) inside `defined?` calls.
2023-12-07 14:07:09 -08:00
Jemma Issroff
b361a800c2 Added comment 2023-12-07 15:29:35 -05:00
Jemma Issroff
a0c7bb4328 [PRISM] Account for multiple arguments when compiling ArgumentsNode
BreakNode, ReturnNode and NextNode all compile the ArgumentsNode
directly, but we weren't accounting for multiple arguments. If there
is more than one argument, we need to also emit a newarray
instruction to put the arguments onto the stack
2023-12-07 15:29:35 -05:00
Matt Valentine-House
41b299d639 [PRISM] Stop catch table entries being deleted by the optimiser 2023-12-07 14:12:20 -05:00
Jemma Issroff
b8df6b9e01 [PRISM] Don't pop arguments on a return node
Since ReturnNodes don't get popped, their arguments shouldn't either
2023-12-07 10:34:39 -05:00
Matt Valentine-House
8e86a4347e [PRISM] Ensure should set correct end_label 2023-12-07 09:38:24 -05:00
Matt Valentine-House
c4b9695350 [PRISM] Rescue should set correct end_label
In order for a break inside the rescue to have the correct jump target
2023-12-07 09:38:24 -05:00
Matt Valentine-House
c8b60c8ac2 [PRISM] Correct depth offset for block local vars
Blocks should always look at their own local table first, even when
defined inside an ensure/rescue or something else that uses depth
offset. We can ignore the depth offset if we're doing local lookups
inside a block
2023-12-06 21:12:08 +00:00
Kevin Newton
153c09f24b [prism] Handle string and xstring encodings 2023-12-06 14:23:38 -05:00
Jemma Issroff
9620ca6789 [PRISM] Extract a PM_NOP helper 2023-12-06 13:05:03 -05:00
Jemma Issroff
0316e666c0 [PRISM] Fix ReturnNodes
This code is almost exactly the same (fixed variable names) as
what exists already in compile.c
2023-12-06 12:25:49 -05:00
Jemma Issroff
f80262b14d [PRISM] Account for nil parent in Call{Operator,And,Or}PathWriteNodes
Prior to this commit, we were not accounting for the case of a nil
parent in a CallXPathWriteNode, for example ::A ||= 1. This commit
checks if the parent exists, and if not, uses Object as the inferred
parent
2023-12-06 11:31:43 -05:00
eileencodes
da1519b223 [PRISM] Implement PM_MATCH_PREDICATE_NODE for defined?
Ruby code:

```ruby
defined? 1 in 1
```

Instructions:

```
"********* Ruby *************"
== disasm: #<ISeq:<compiled>@<compiled>:0 (0,0)-(0,16)>
0000 putobject                              "expression"
0002 leave

"********* PRISM *************"
== disasm: #<ISeq:<compiled>@<compiled>:0 (0,0)-(0,16)>
0000 putobject                              "expression"
0002 leave
```
2023-12-06 09:46:19 -05:00
eileencodes
4547108448 [PRISM] Implement PM_KEYWORD_HASH_NODE for defined?
Ruby code:

```ruby
defined? [a: [:b, :c]]
```

Instructions (without optimizations):

```
"********* Ruby *************"
== disasm: #<ISeq:<compiled>@<compiled>:0 (0,0)-(0,23)>
== catch table
| catch type: rescue st: 0001 ed: 0007 sp: 0000 cont: 0009
| == disasm: #<ISeq:defined guard in <compiled>@<compiled>:0 (0,0)-(-1,-1)>
| local table (size: 1, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
| [ 1] "$!"@0
| 0000 putnil
| 0001 leave
|------------------------------------------------------------------------
0000 putnil
0001 putobject                              true
0003 branchunless                           9
0005 putobject                              "expression"
0007 swap
0008 pop
0009 leave

"********* PRISM *************"
== disasm: #<ISeq:<compiled>@<compiled>:0 (0,0)-(0,23)>
== catch table
| catch type: rescue st: 0000 ed: 0009 sp: 0000 cont: 0009
| == disasm: #<ISeq:defined guard in <compiled>@<compiled>:0 (0,0)-(-1,-1)>
| local table (size: 1, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
| [ 1] "$!"@0
| 0000 putnil
| 0001 leave
|------------------------------------------------------------------------
0000 putnil
0001 putobject                              true
0003 branchunless                           9
0005 putobject                              "expression"
0007 swap
0008 pop
0009 leave
```

Instructions (with optimizations):

```
"********* Ruby *************"
== disasm: #<ISeq:<compiled>@<compiled>:0 (0,0)-(0,23)>
== catch table
| catch type: rescue st: 0001 ed: 0003 sp: 0000 cont: 0005
| == disasm: #<ISeq:defined guard in <compiled>@<compiled>:0 (0,0)-(-1,-1)>
| local table (size: 1, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
| [ 1] "$!"@0
| 0000 putnil
| 0001 leave
|------------------------------------------------------------------------
0000 putnil
0001 putobject                              "expression"
0003 swap
0004 pop
0005 leave

"********* PRISM *************"
== disasm: #<ISeq:<compiled>@<compiled>:0 (0,0)-(0,23)>
== catch table
| catch type: rescue st: 0000 ed: 0005 sp: 0000 cont: 0005
| == disasm: #<ISeq:defined guard in <compiled>@<compiled>:0 (0,0)-(-1,-1)>
| local table (size: 1, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
| [ 1] "$!"@0
| 0000 putnil
| 0001 leave
|------------------------------------------------------------------------
0000 putnil
0001 putobject                              "expression"
0003 swap
0004 pop
0005 leave
```
2023-12-06 09:46:19 -05:00
eileencodes
8649764522 [PRISM] Implement PM_SPLAT_NODE for defined?
In an array for `defined?` we need to check if there is a
`contains_splat` flag, if so bail early.

Ruby code:

```ruby
defined?([[*1..2], 3, *4..5])
```

Instructions:

```
"********* Ruby *************"
== disasm: #<ISeq:<compiled>@<compiled>:0 (0,0)-(0,29)>
0000 putobject                              "expression"
0002 leave

"********* PRISM *************"
== disasm: #<ISeq:<compiled>@<compiled>:0 (0,0)-(0,29)>
0000 putobject                              "expression"
0002 leave
```
2023-12-06 09:46:19 -05:00
eileencodes
02961fdbab [PRISM] Implement PM_SOURCE_LINE_NODE for defined?
Ruby code:

```ruby
defined?(__LINE__)
```

Instructions:

```
"********* Ruby *************"
== disasm: #<ISeq:<compiled>@<compiled>:0 (0,0)-(0,18)>
0000 putobject                              "expression"
0002 leave

"********* PRISM *************"
== disasm: #<ISeq:<compiled>@<compiled>:0 (0,0)-(0,18)>
0000 putobject                              "expression"
0002 leave
```
2023-12-06 09:46:19 -05:00
eileencodes
d474239537 [PRISM] Implement PM_SOURCE_FILE_NODE for defined?
Ruby code:

```ruby
defined?(__FILE__)
```

Instructions:

```
"********* Ruby *************"
== disasm: #<ISeq:<compiled>@<compiled>:0 (0,0)-(0,18)>
0000 putobject                              "expression"
0002 leave

"********* PRISM *************"
== disasm: #<ISeq:<compiled>@<compiled>:0 (0,0)-(0,18)>
0000 putobject                              "expression"
0002 leave
```
2023-12-06 09:46:19 -05:00
eileencodes
41b117e50c [PRISM] Implement PM_SOURCE_ENCODING_NODE for `defined?
Ruby code:

```ruby
defined?(__ENCODING__)
```

Instructions:

```
"********* Ruby *************"
== disasm: #<ISeq:<compiled>@<compiled>:0 (0,0)-(0,22)>
0000 putobject                              "expression"
0002 leave

"********* PRISM *************"
== disasm: #<ISeq:<compiled>@<compiled>:0 (0,0)-(0,22)>
0000 putobject                              "expression"
0002 leave
```
2023-12-06 09:46:19 -05:00
eileencodes
b04255deff [PRISM] Implement PM_IMAGINARY_NODE for defined?
Ruby Code:

```
defined?(1i)
```

Instructions:

```
"********* Ruby *************"
== disasm: #<ISeq:<compiled>@<compiled>:0 (0,0)-(0,12)>
0000 putobject                              "expression"
0002 leave

"********* PRISM *************"
== disasm: #<ISeq:<compiled>@<compiled>:0 (0,0)-(0,12)>
0000 putobject                              "expression"
0002 leave
```
2023-12-06 09:46:19 -05:00
Matt Valentine-House
d6ec1aa0a7 [PRISM] Compile Rescue Modifier nodes 2023-12-06 07:02:04 -05:00
Matt Valentine-House
6b9622ebdf [PRISM] Implement Retry node. 2023-12-05 08:56:22 -05:00
Jemma Issroff
81a700853d [PRISM] Fixed redo node 2023-12-04 17:02:04 -05:00
eileencodes
7d371ca25d [PRISM] Handle percent literals for defined?
Tests all the possible percent literal with `defined?`. Implements the
missing `PM_X_STRING_NODE` for the `%x` literal.

Code:

```ruby
defined?(%x[1,2,3])
```

```
"********* Ruby *************"
== disasm: #<ISeq:<compiled>@<compiled>:0 (0,0)-(0,19)>
0000 putobject                              "expression"
0002 leave

"********* PRISM *************"
== disasm: #<ISeq:<compiled>@<compiled>:0 (0,0)-(0,19)>
0000 putobject                              "expression"
0002 leave
```
2023-12-04 16:45:18 -05:00
eileencodes
09e8d37f5b [PRISM] Implement PM_INTERPOLATED_REGULAR_EXPRESSION_NODE
Implements `PM_INTERPOLATED_REGULAR_EXPRESSION_NODE` for `defined?`

Code:

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

```
"********* Ruby *************"
== disasm: #<ISeq:<compiled>@<compiled>:0 (0,0)-(0,16)>
0000 putobject                              "expression"
0002 leave

"********* PRISM *************"
== disasm: #<ISeq:<compiled>@<compiled>:0 (0,0)-(0,16)>
0000 putobject                              "expression"
0002 leave
```
2023-12-04 16:45:18 -05:00
eileencodes
33bc22efe5 [PRISM] Implement PM_INTERPOLATED_STRING_NODE
Implements `PM_INTERPOLATED_STRING_NODE` for `defined?`

Code:

```ruby
defined?("#{expr}")
```

```
"********* Ruby *************"
== disasm: #<ISeq:<compiled>@<compiled>:0 (0,0)-(0,19)>
0000 putobject                              "expression"
0002 leave

"********* PRISM *************"
== disasm: #<ISeq:<compiled>@<compiled>:0 (0,0)-(0,19)>
0000 putobject                              "expression"
0002 leave
```
2023-12-04 16:45:18 -05:00
eileencodes
c23b2e5353 [PRISM] Fix PM_PARENTHESES_NODE
In #9101 I only accounted for an empty paren. This change implements the
`PM_PARENTHESES_NODE` for when it's `nil` and when it's an expression.

Code:

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

```
"********* Ruby *************"
== disasm: #<ISeq:<compiled>@<compiled>:0 (0,0)-(0,15)>
0000 putobject                              "expression"
0002 leave

"********* PRISM *************"
== disasm: #<ISeq:<compiled>@<compiled>:0 (0,0)-(0,15)>
0000 putobject                              "expression"
0002 leave
```
2023-12-04 16:45:18 -05:00
eileencodes
569750f624 [Prism] Implement backref and numbered reference for defined?
This PR implements `PM_BACK_REFERENCE_READ_NODE` and
`PM_NUMBERED_REFERENCE_READ_NODE` for `defined?`. The following now
works:

* `PM_NUMBERED_REFERENCE_READ_NODE`

```
defined? $1
defined? $2
```

Instructions:

```
"********* RUBY *************"
== disasm: #<ISeq:<compiled>@<compiled>:0 (0,0)-(0,12)>
0000 putnil
0001 defined                                ref, :$1, "global-variable"
0005 leave

"********* PRISM *************"
== disasm: #<ISeq:<compiled>@<compiled>:0 (0,0)-(0,12)>
0000 putnil
0001 defined                                ref, :$1, "global-variable"
0005 leave
```

* `PM_BACK_REFERENCE_READ_NODE`

```
defined? $'
defined? $`
defined? $&
```

Instructions:

```
"********* RUBY *************"
== disasm: #<ISeq:<compiled>@<compiled>:0 (0,0)-(0,12)>
0000 putnil
0001 defined                                ref, :$`, "global-variable"
0005 leave

"********* PRISM *************"
== disasm: #<ISeq:<compiled>@<compiled>:0 (0,0)-(0,12)>
0000 putnil
0001 defined                                ref, :$`, "global-variable"
0005 leave
```
2023-12-04 12:03:22 -08:00
Jemma Issroff
e3ca50b02f [PRISM] Fix compilation for NextNode
This code was almost enitrely the same as the existing compiler's
code for its NextNode.
2023-12-04 14:03:00 -05:00
eileencodes
818813c2bd Implement paren node for defined?
Implements and adds a test for passing a parentheses node to `defined?`.
2023-12-01 14:56:25 -08:00
eileencodes
39238888bc Implements missing literals for defined?
This PR implements the following literals:

- String
- Symbols
- Integers
- Floats
- Regexs
- Ranges
- Lambdas
- Hashes

and tests for them.
2023-12-01 12:05:22 -08:00
Jemma Issroff
2a8d9c59ff [PRISM] Account for RescueNodes with no statements
We need a PUTNIL if a RescueNode has no statements.
2023-12-01 13:23:23 -05:00
Jemma Issroff
d6584a0201 [PRISM] Fix behavior of BlockParameters with only one parameter
This commit sets the ambiguous param flag if there is only one
parameter on a block node. It also fixes a small bug with a trailing
comma on params.
2023-12-01 13:07:59 -05:00
Jemma Issroff
9d20909342
[PRISM] Clean up trailing comment 2023-12-01 12:20:16 -05:00
Jemma Issroff
d224618bea [PRISM] Restructure parameters
Prior to this commit, we weren't accounting for hidden variables
on the locals table, so we would have inconsistencies on the stack.
This commit fixes params, and introduces a hidden_variable_count
on the scope, both of which fix parameters.
2023-12-01 12:14:54 -05:00
Kevin Newton
5150ba0dbe [prism] Update to latest numbered parameters 2023-12-01 12:03:09 -05:00
Matt Valentine-House
90d9c20a0c [PRISM] Compile RescueNode 2023-12-01 16:40:25 +00:00
Matt Valentine-House
3b21932d14 [PRISM] Use depth_offset not transparent scopes for FOR 2023-12-01 15:04:13 +00:00
Matt Valentine-House
0c7c654b4d [Prism] Fix local variable access for POST_EXECUTION_NODE 2023-11-30 21:31:57 +00:00
Matt Valentine-House
57782d3d47 Store depth offset inside the scope node.
Instead of incrementing the depth using call by reference as we're
recursing up the stack we could instead store an offset for each known
scope where we know the depth is going to represented differently in the
Prism ast.
2023-11-30 21:31:57 +00:00
Aaron Patterson
630c97acc7 Add a rescue for defined?(A::B::C)
It's possible for `defined?(A::B::C)` to raise an exception.  `defined?`
must swallow the exception and return nil, so this commit adds a rescue
entry for `defined?` expressions on constant paths
2023-11-30 09:48:14 -05:00
Jemma Issroff
8234763816 [PRISM] Compile empty array as newarray 0
Prior to this commit, we were compiling an empty array as a
duparray of [] which meant we were allocating a new value
unnecessarily. With this commit, we emit a newarray with size 0
instead.
2023-11-29 16:20:30 -05:00
Jemma Issroff
853fd44745 [PRISM] Implement CallNodes with splat followed by args 2023-11-29 16:19:14 -05:00
Jemma Issroff
2233204cc1 [PRISM] Account for ImplicitRestNode
Prism introduced a new ImplicitRestNode. This adds tests for the
ImplicitRestNode cases, and changes one assert which is no longer
accurate.
2023-11-29 16:14:28 -05:00
Jemma Issroff
53841941f0 [PRISM] Fix EnsureNode, pass depth to get locals
This commit fixes a bug with locals in ensure nodes by setting
the local tables correctly. It also changes accessing locals to
look at local tables in parent scopes, and account for this
correctly on depths of get or setlocals.
2023-11-29 16:00:00 -05:00
Jemma Issroff
a9c07cbd21 [PRISM] Don't calculate params size based on locals
Prior to this commit, we were conflating the size of the locals
list with the number of parameters. This commit distinguishes
the two, and fixes a related bug which would occur if we set a local
that was not a parameter
2023-11-28 17:01:34 -05:00
Jemma Issroff
7bd172744f [PRISM] Implement more compilation of SplatNodes
There was a bug with the rest argument in SplatNodes, this commit
fixes it, and adds more tests illustrating the behavior of
SplatNodes
2023-11-28 14:03:57 -05:00
Jemma Issroff
2760f23774 [PRISM] Compile YieldNode with different arguments 2023-11-28 14:02:53 -05:00
Jemma Issroff
1acea50100 [PRISM] Small fixes to parameters ordering and methods 2023-11-27 16:02:38 -05:00