Commit graph

669 commits

Author SHA1 Message Date
Aaron Patterson
89d89fa49d When reading from stdin, put a wrapper around the IO object
The purpose of this commit is to fix Bug #21188.  We need to detect when
stdin has run in to an EOF case.  Unfortunately we can't _call_ the eof
function on IO because it will block.

Here is a short script to demonstrate the issue:

```ruby
x = STDIN.gets
puts x
puts x.eof?
```

If you run the script, then type some characters (but _NOT_ a newline),
then hit Ctrl-D twice, it will print the input string.  Unfortunately,
calling `eof?` will try to read from STDIN again causing us to need a
3rd Ctrl-D to exit the program.

Before introducing the EOF callback to Prism, the input loop looked
kind of like this:

```ruby
loop do
  str = STDIN.gets
  process(str)

  if str.nil?
    p :DONE
  end
end
```

Which required 3 Ctrl-D to exit.  If we naively changed it to something
like this:

```ruby
loop do
  str = STDIN.gets
  process(str)

  if STDIN.eof?
    p :DONE
  end
end
```

It would still require 3 Ctrl-D because `eof?` would block.  In this
patch, we're wrapping the IO object, checking the buffer for a newline
and length, and then using that to simulate a non-blocking eof? method.

This commit wraps STDIN and emulates a non-blocking `eof` function.

[Bug #21188]
2025-08-04 12:34:33 -07:00
Stan Lo
2eab962c53 [ruby/prism] Allow command calls in endless method bodies within assignments
Previously, endless method definitions in assignment contexts like
`x = def f = p 1` would fail to parse because command calls (method
calls without parentheses) were only accepted when the surrounding
binding power was less than `PM_BINDING_POWER_COMPOSITION`.

This fix specifically checks for assignment context and allows command
calls in those cases while maintaining the existing behavior for other
contexts. This ensures that:

- `x = def f = p 1` parses correctly (previously failed)
- `private def f = puts "Hello"` still produces the expected error

722af59ba3
2025-07-29 17:18:41 +00:00
Earlopain
026079925c [ruby/prism] Do not use 0 to indicate the latest ruby version to parse
This makes it hard to do version checks against this value. The current version checks work because there are so few possible values at the moment.

As an example, PR 3337 introduces new syntax for ruby 3.5 and uses `PM_OPTIONS_VERSION_LATEST` as its version guard. Because what is considered the latest changes every year, it must later be changed to `parser->version == parser->version == PM_OPTIONS_VERSION_CRUBY_3_5 || parser->version == PM_OPTIONS_VERSION_LATEST`, with one extra version each year.

With this change, the PR can instead write `parser->version >= PM_OPTIONS_VERSION_CRUBY_3_5` which is self-explanatory
and works for future versions.

8318a113ca
2025-07-29 17:17:28 +00:00
Aaron Patterson
a1403fb7cb Interpolated strings must not be frozen
Strings concatenated with backslash may end up being frozen when they
shouldn't be.  This commit fixes the issue.  It required a change
upstream in Prism, but also a change to the Prism compiler in CRuby.

  https://github.com/ruby/prism/pull/3606

[Bug #21187]
2025-07-22 08:10:55 -07:00
Hiroshi SHIBATA
7dbd9c2636
Revert "[ruby/prism] Clear flags on interpolated strings"
This reverts commit a495e6a44c.

This break extension builds:

```
/Users/hsbt/Documents/github.com/ruby/ruby/rbconfig.rb:321:in 'String#replace': can't modify frozen String: "$(SDKROOT)$(prefix)/include" (FrozenError)
        from /Users/hsbt/Documents/github.com/ruby/ruby/rbconfig.rb:321:in 'RbConfig.expand'
        from /Users/hsbt/Documents/github.com/ruby/ruby/rbconfig.rb:314:in 'block in RbConfig.expand'
        from /Users/hsbt/Documents/github.com/ruby/ruby/rbconfig.rb:307:in 'String#gsub'
        from /Users/hsbt/Documents/github.com/ruby/ruby/rbconfig.rb:307:in 'RbConfig.expand'
        from /Users/hsbt/Documents/github.com/ruby/ruby/rbconfig.rb:314:in 'block in RbConfig.expand'
        from /Users/hsbt/Documents/github.com/ruby/ruby/rbconfig.rb:307:in 'String#gsub'
        from /Users/hsbt/Documents/github.com/ruby/ruby/rbconfig.rb:307:in 'RbConfig.expand'
        from /Users/hsbt/Documents/github.com/ruby/ruby/rbconfig.rb:314:in 'block in RbConfig.expand'
        from /Users/hsbt/Documents/github.com/ruby/ruby/rbconfig.rb:307:in 'String#gsub'
        from /Users/hsbt/Documents/github.com/ruby/ruby/rbconfig.rb:307:in 'RbConfig.expand'
        from /Users/hsbt/Documents/github.com/ruby/ruby/rbconfig.rb:325:in 'block in <module:RbConfig>'
        from /Users/hsbt/Documents/github.com/ruby/ruby/rbconfig.rb:324:in 'Hash#each_value'
        from /Users/hsbt/Documents/github.com/ruby/ruby/rbconfig.rb:324:in '<module:RbConfig>'
        from /Users/hsbt/Documents/github.com/ruby/ruby/rbconfig.rb:11:in '<top (required)>'
        from ./ext/extmk.rb:42:in 'Kernel#require'
        from ./ext/extmk.rb:42:in '<main>'
make[1]: *** [ext/configure-ext.mk:70: ext/json/exts.mk] Error 1
```
2025-07-22 09:07:04 +09:00
Aaron Patterson
a495e6a44c [ruby/prism] Clear flags on interpolated strings
When inner strings aren't frozen, we need to clear the flags on
interpolated string nodes so that we don't emit wrong instructions.

The compiler is currently incorrectly emitting frozen strings because
the parser is erroneously declaring interpolated strings as "frozen".
We need to fix this behavior in the parser so we can fix the compiler in
CRuby.  This patch is a partial fix for [this bug](https://bugs.ruby-lang.org/issues/21187)

eda693f056
2025-07-21 23:04:42 +00:00
Aaron Patterson
c1c9deea83 [ruby/prism] Revert "Merge pull request #3598 from Shopify/fix-3473"
This reverts commit bc446fb979, reversing
changes made to 71432af1eb.

e5ca485f4e
2025-07-17 16:23:17 +00:00
Stan Lo
13de248f39 [ruby/prism] Allow command calls in endless method bodies regardless of context
Previously, endless method definitions like `x = def f = p 1` would fail
to parse because command calls (method calls without parentheses) were
only accepted when the surrounding binding power was less than
`PM_BINDING_POWER_COMPOSITION` (8). In assignment contexts with binding
power 18, this condition was false, causing parse errors.

This fix ensures command calls are always accepted in endless method
bodies by passing `true` for `accepts_command_call`, making the method
body parse consistently regardless of where the method is defined.

70413ed4dd
2025-07-17 16:06:34 +00:00
Earlopain
133cf95618 [ruby/prism] [Bug #21345] Fix accepting multiple rest patterns with leading match
Related:
* https://bugs.ruby-lang.org/issues/20765
* https://github.com/ruby/prism/issues/2915

de56fa4a34
2025-07-16 18:12:06 +00:00
Stan Lo
2591b93593 [ruby/prism] Fix crash when using arithmetic expressions in pattern matching
When arithmetic expressions like `-1**2` are used in pattern matching contexts,
Ruby crashes with "Unexpected node type in pattern matching expression: PM_CALL_NODE".
This happens because the Prism parser creates `PM_CALL_NODE` for arithmetic operations,
but Ruby's pattern matching compiler doesn't handle call nodes.

This fix adds validation to reject `PM_CALL_NODE` in pattern contexts with a proper
syntax error.

365049a767
2025-07-16 17:08:28 +00:00
ydah
4eb0a6cd4d [ruby/prism] Improve error handling for missing parentheses after 'not' in command calls
d9151b8a82
2025-07-16 15:48:09 +00:00
Yusuke Endoh
4cf85fe214 [ruby/prism] Reject true && not true
A command-call-like `not true` must be rejected after `&&` and `||`.

https://bugs.ruby-lang.org/issues/21337

0513cf22ad
2025-07-16 15:48:09 +00:00
Dmitry Dygalo
4e5c8c19a7 [ruby/prism] fix: sigsegv on malformed shebang
Signed-off-by: Dmitry Dygalo <dmitry@dygalo.dev>

e23292120e
2025-06-30 12:31:53 +00:00
Alexander Momchilov
0fad0ce35c [ruby/prism] Use xmalloc()/xfree()
bd9027f0ab
2025-03-31 19:57:33 +00:00
Kevin Newton
052794bfe1 [ruby/prism] Accept a newline after the defined? keyword
[Bug #21197]

22be955ce9
2025-03-30 13:22:41 -04:00
Nobuyoshi Nakada
820c541671 [Bug #21026] no singleton method on pseudo variable literal 2025-03-20 17:32:26 +09:00
Kevin Newton
dc48c1aca3 [ruby/prism] Add a multiple statements flag to parentheses
This can get triggered even if the list of statements only contains
a single statement. This is necessary to properly support compiling

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

as "expression". Previously these were parsed as statements lists
with single statements in them.

b63b5d67a9
2025-03-18 13:36:53 -04:00
Kevin Newton
12541d2cc0 [ruby/prism] Track then keyword on rescue nodes
bde8ccc038
2025-03-18 13:36:53 -04:00
Kevin Newton
3d6fc29169 [ruby/prism] Make xstrings concat syntax error
f734350499
2025-03-18 16:00:03 +00:00
Kevin Newton
617e8608b2 [ruby/prism] Rename fgets parameter to fix NetBSD
Fixes [Bug #21165]

3f0acf7560
2025-03-02 18:14:36 +00:00
Kevin Newton
2db365dc83 [ruby/prism] Fix escape unicode curly inline whitespace
Fixes [Bug #21145]

be2d845639
2025-02-17 18:12:03 +00:00
Kevin Newton
ee181d1bb7 [ruby/prism] Fix up it indirect writes
Fixes [Bug #21137]

ca493e6797
2025-02-14 16:49:52 +00:00
Kevin Newton
127325a4ba [ruby/prism] No writing to numbered parameters
Fixes [Bug #21117]

19d4bab5a0
2025-02-13 20:04:02 +00:00
Kevin Newton
b21e1aed2e [ruby/prism] Fix infinite loop in error recovery
When recovering from a depth error that occurs at the end of the
file, we need to break out of parsing statements.

Fixes [Bug #21114]

a32e268787
2025-02-13 19:12:10 +00:00
Nobuyoshi Nakada
2b92172894 [ruby/prism] Split assertion per expressions
Expressions joined with `&&` are better asserted separately, so that
it is clear from the failure message which expression is false.

Also, `unsigned long` may not be enough for `ptrdiff_t`, e.g., Windows.
Saying that `ptrdiff_t` can be larger than `SIZE_MAX` means that
`PTRDIFF_MAX` is larger than `SIZE_MAX` and `ptrdiff_t` is sufficient
to represent `SIZE_MAX`, otherwise if `PTRDIFF_MAX` is smaller than
`SIZE_MAX`, `diff` will always be smaller than `SIZE_MAX` as well.
`diff` could be equal to `SIZE_MAX` only if `PTRDIFF_MAX` is equal to
`SIZE_MAX` and these assertions would pass, but I don't think there is
any platform where that is the case.

1fc6dfcada
2025-02-13 17:49:48 +00:00
Kevin Newton
c290861336 [ruby/prism] Fix rescue modifier precedence
Fixes [Bug #21048]

07202005cb
2025-01-22 19:58:27 +00:00
Kevin Newton
241ada7b1c [ruby/prism] Do not put empty statements in while because of -n
Fixes [Bug #21085]

ebb9c36a10
2025-01-22 19:09:42 +00:00
Kevin Newton
51d3d6ac8c [ruby/prism] Support forwarding flags on scopes
When parent scopes around an eval are forwarding parameters (like
*, **, &, or ...) we need to know that information when we are in
the parser. As such, we need to support passing that information
into the scopes option. In order to do this, unfortunately we need
a bunch of changes.

The scopes option was previously an array of array of strings.
These corresponded to the names of the locals in the parent scopes.
We still support this, but now additionally support passing in a
Prism::Scope instance at each index in the array. This Prism::Scope
class holds both the names of the locals as well as an array of
forwarding parameter names (symbols corresponding to the forwarding
parameters). There is convenience function on the Prism module that
creates a Prism::Scope object using Prism.scope.

In JavaScript, we now additionally support an object much the same
as the Ruby side. In Java, we now have a ParsingOptions.Scope class
that holds that information. In the dump APIs, these objects in all
3 languages will add an additional byte for the forwarding flags in
the middle of the scopes serialization.

All of this is in service of properly parsing the following code:

```ruby
def foo(*) = eval("bar(*)")
```

21abb6b7c4
2025-01-14 20:31:38 +00:00
Kevin Newton
117d6e145a [ruby/prism] Fix not receiver
`not foo` should be `!foo`
`not()` should be `!nil`

Fixes [Bug #21027]

871ed4b462
2025-01-11 19:09:05 -05:00
Alexander Momchilov
fa1427a63e [ruby/prism] Enable implicit fall-through errors
03797b84d3
2025-01-11 19:09:05 -05:00
Kevin Newton
96f23306f0 [ruby/prism] Revert "Reject pattern match with unexpected double splat inside array"
51e7c84124
2025-01-08 20:42:35 +00:00
Kevin Newton
c4534c9fe8 [ruby/prism] Handle escapes in named capture names
b4b7a69ce7
2025-01-08 20:36:06 +00:00
ydah
500a87756f [ruby/prism] Reject pattern match with unexpected double splat inside array
`a => [-2**b]` should be SyntaxError

Fixes: https://github.com/ruby/prism/issues/3381

ae8e83b389
2025-01-08 17:23:51 +00:00
eileencodes
ad96c5a729 [ruby/prism] Throw syntax error for endless method with []=
Prism shoudld throw a syntax error for endless methods when the method
name uses brackets. Previously it would not. This matches the behavior
of parse.y.

Fixes https://bugs.ruby-lang.org/issues/21010

43c16a89ef
2025-01-07 19:35:01 +00:00
Kevin Newton
179e2cfa91 [ruby/prism] Fix global variable read off end
3f2c34b53d
2025-01-05 18:05:35 +00:00
Nobuyoshi Nakada
a33c944ba8
[Bug #20988] [prism] Fix escaped octal character literals 2024-12-29 10:32:33 +09:00
Nobuyoshi Nakada
e4ec2128ae
[Bug #20990] Reject escaped multibyte char with control/meta prefix 2024-12-28 18:40:37 +09:00
Nobuyoshi Nakada
f226bc20f6
[Bug #20986] [Prism] Allow escaped multibyte character 2024-12-27 09:01:08 +09:00
Kevin Newton
4d8c9c1310 [ruby/prism] Handle escaped characters after controls
Fixes [Bug #20986]

fd0c563e9e
2024-12-26 22:35:28 +00:00
Kevin Newton
db78ab5ed2 [ruby/prism] Update src/prism.c
544df5835f
2024-12-16 10:51:22 -05:00
ydah
f6e0a037aa [ruby/prism] [Bug #20785] Allow , and and , or after patterns
Partially: https://bugs.ruby-lang.org/issues/20785

71c9102d02
2024-12-16 10:51:22 -05:00
Haldun Bayhantopcu
0dc35f0d30 [ruby/prism] Ignore newlines in labelled lambda arguments
4ce6bcf182
2024-12-16 10:51:22 -05:00
eileencodes
a21237571e [ruby/prism] Fix 3112 - disallow commas after block arg
Prism was already disallowing arguments after block args, but in
parse.y, any comma after a block arg is a syntax error. This moves the
error handling into `PM_TOKEN_UAMPERSAND` where we can check if the
current type is `PM_TOKEN_COMMA`then raise an error. I've also updated
the tests to include the examplesfrom ruby/prism#3112.

Fixes: ruby/prism#3112

754cf8eddc
2024-12-16 10:51:22 -05:00
Kevin Newton
cc967a470b [ruby/prism] Add do keyword tracking for While/Until
9686897290
2024-12-16 10:51:22 -05:00
Matt Valentine-House
b37777c36f [PRISM] Blocks are also a syntax error in array assignment
Actually close [Bug #20952]
2024-12-13 22:02:06 +00:00
Matt Valentine-House
e194665720 [PRISM] using []= to set kwargs is a syntax error
Fixes [Bug #20952]
2024-12-13 21:22:35 +00:00
Kevin Newton
29caae9991 [ruby/prism] Use isinf on non-mingw windows
2f903d7865
2024-12-12 01:10:13 +00:00
Aaron Patterson
9181e8bc87 [ruby/prism] Decode %r like % strings
%r regular expressions need to be decoded like strings.  This commit
fixes %r decoding so it works like strings.

85bfd9c0cd
2024-12-12 00:42:44 +00:00
Aaron Patterson
0a1fa99482 [ruby/prism] Same numbered param cannot be used in child blocks
Raise an exception when the same numbered param is used inside a child
block.  For example, the following code should be a syntax error:

```ruby
-> { _1 + -> { _1 } }
```

Fixes https://github.com/ruby/prism/pull/3291

d4fc441838
2024-12-12 00:42:27 +00:00
eileencodes
9fe6fd8693 [ruby/prism] Fix percent delimiter strings with crlfs
parse.y treats CRLF as a LF and basically "normalizes" them before
parsing.  That means a string like `%\nfoo\r\n` is actually treated as
`%\nfoo\n` for the purposes of parsing.  This happens on both the
opening side of the percent string as well as on the closing side.  So
for example `%\r\nfoo\n` must be treated as `%\nfoo\n`.

To handle this in Prism, when we start a % string, we check if it starts
with `\r\n`, and then consider the terminator to actually be `\n`.  Then
we check if there are `\r\n` as we lex the string and treat those as
`\n`, but only in the case the start was a `\n`.

Fixes: #3230

[Bug #20938]

e573ceaad6

Co-authored-by: John Hawthorn <jhawthorn@github.com>
Co-authored-by: eileencodes <eileencodes@gmail.com>
Co-authored-by: Kevin Newton <kddnewton@gmail.com>
2024-12-11 23:06:32 +00:00