Граф коммитов

163 Коммитов

Автор SHA1 Сообщение Дата
Jemma Issroff 68753e4408 [PRISM] Allow rest parameter to be `*`
Prior to this commit, if a rest parameters was `*`, we did not add
it to the locals table correctly. This commit fixes that.
2023-12-12 13:45:21 -05:00
Nobuyoshi Nakada f466afa176
[PRISM] Do not hide syntactically required parentheses within macros
It makes code formatters confused when auto indenting.
2023-12-12 23:57:27 +09:00
Jemma Issroff 69d60cc67b [PRISM] Properly compile MultiTargetNodes within parameters
If there are MultiTargetNodes within parameters, we need to
iterate over them and compile them individually correctly, once
the locals are all in the correct spaces. We need to add one
getlocal for the hidden variable, and then can recurse into the
MultiTargetNodes themselves
2023-12-11 17:04:46 -05:00
Jemma Issroff 5c8e1911ca [PRISM] Fixed rest in MultiTargetNodes 2023-12-11 17:04:46 -05:00
Jemma Issroff aaeccc2924 [PRISM] Correctly implemented forwarding parameters in methods 2023-12-11 17:04:46 -05:00
Jemma Issroff 85ad5be9ee [PRISM] Restructure parameters on ScopeNodes
This commit completely restructures how we handle parameters. The
motivation for this commit was the fix compilation of MultiTargetNodes
within parameters, including nested MultiTargetNodes. A subsequent
commit will actually do the compilation for the MultiTargetNodes.

This commit's main accomplishment is restructuring the locals table
and how we account for it on the ScopeNode, specifically with regards
to hidden variables.

It has multiple steps, all commented within the code, to calculate
the locals table correctly and compile the parameters:
- Step 1: Caculate the table size for the locals
- Step 2: Populate iv index table and local table
- Step 3: Fill in parameter names of MultiTargetNodes on local table
- Step 4: Fill in method body locals on local table
- Step 5: Compile any locals
2023-12-11 17:04:46 -05:00
Jemma Issroff fb93535070 [PRISM] Define and use a pm_add_ensure_iseq
Prior to this commit, we were using `add_ensure_iseq` which compiled
a node as if it was a CRuby node. This commit defines
`pm_add_ensure_iseq` which compiles the Prism node appropriately.
2023-12-11 12:53:47 -05:00
Jemma Issroff c69d1367a7 [PRISM] Fix ElseNode within CaseNode
The logic within the consequent for the CaseNodes in popped cases
was incorrect as it wouldn't emit consequent instructions for a
popped CaseNode. This commit fixes that.
2023-12-11 09:47:59 -05:00
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