72 Commits

Author SHA1 Message Date
Paweł Świątkowski 13d9d770fc Correctly handle empty hash as default named argument
```
def func(arg: {})
  p arg
end
```

This used to work in earlier mruby versions, but broke somewhere recently.
2026-03-18 08:53:20 +01:00
Yukihiro "Matz" Matsumoto d8de35b635 codegen.c: raise NoMatchingPatternError in case/in without else
case/in without else clause now raises NoMatchingPatternError
when no pattern matches, matching CRuby behavior. Fixes #6741.

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-12 14:28:17 +09:00
Yukihiro "Matz" Matsumoto a1ee420aea test/t/syntax.rb: add test for &nil in formal parameters
Co-authored-by: Claude <noreply@anthropic.com>
2026-02-19 17:26:04 +09:00
Yukihiro "Matz" Matsumoto 9b66ec82c4 mruby-compiler: fix hash pattern matching for CRuby compatibility
Add key existence check using key?() before value access, so that
missing keys correctly fail to match (e.g. {b: 1} no longer matches
{a: nil} pattern). Implement **nil and empty {} exact match via
hash.size == num_keys check. Fix **rest to properly exclude matched
keys using dup + __delete instead of copying the entire hash.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-16 17:33:41 +09:00
Yukihiro "Matz" Matsumoto 56d4dab6ed test/syntax.rb: add find pattern tests
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-18 16:27:27 +09:00
Yukihiro "Matz" Matsumoto 42f5215466 test/syntax.rb: add pattern matching test cases
add comprehensive tests for pattern matching features:
- basic case/in with literals and variables
- array patterns with rest and nested structures
- hash patterns with shorthand and rest
- guard clauses (if/unless)
- alternative patterns (|)
- pin operator (^)
- as pattern (=>)
- one-line pattern matching (in and =>)
- NoMatchingPatternError handling

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-18 16:27:26 +09:00
Yukihiro "Matz" Matsumoto 451f67e0ae test/syntax.rb: add at-least-once loop tests
Co-authored-by: Claude <noreply@anthropic.com>
2025-07-11 10:09:34 +09:00
Yukihiro "Matz" Matsumoto 1dfd3d9043 Merge pull request #6442 from dearblue/jmpuw 2024-12-06 23:43:31 +09:00
dearblue 95e2f8e844 Fixed wrong range condition in OP_JMPUW
fixed #6441
2024-12-03 22:14:50 +09:00
dearblue 01ea2c088d Add more tests for redo keyword 2024-12-01 11:33:23 +09:00
Hoshiumi Arata 386cd771e7 Fix numbered parameters when used as hash keys 2024-11-20 00:31:44 +09:00
Yukihiro "Matz" Matsumoto 628f057482 Merge pull request #6419 from hoshiumiarata/fix_numparams_in_lambda 2024-11-15 16:17:03 +09:00
Hoshiumi Arata 9fe2a5c46a parser: setup numbered parameters in new_lambda and adjust dump_prefix offset 2024-11-13 22:19:27 +09:00
Hoshiumi Arata cc2ec53807 parser: support numbered parameters when used as a singleton 2024-11-13 00:22:49 +09:00
dearblue 9c9be44a98 Don't switch constant search path from modules to Object
Previously, for example, it was possible to retrieve the `String` class as follows:

```console
% bin/mruby -e 'p Comparable::Enumerable::Errno::GC::Kernel::Math::ObjectSpace::String'
String
```

Note that this patch affects the API function `mrb_const_get()`.
2023-03-05 20:32:56 +09:00
John Bampton aab7bc0023 pre-commit: add hooks forbid-tabs and remove-tabs
The indentation settings have been taken from the `.editorconfig` file

https://github.com/Lucas-C/pre-commit-hooks
2022-10-26 21:33:32 +10:00
Yukihiro "Matz" Matsumoto 4e3df65d6f test/syntax.rb: test argument forwarding without parentheses. 2021-11-12 15:02:49 +09:00
Yukihiro "Matz" Matsumoto dccd66f9ef Support Ruby3.0 keyword arguments.
The Difference

Since Ruby1.9, the keyword arguments were emulated by Ruby using the hash
object at the bottom of the arguments. But we have gradually moved toward
keyword arguments separated from normal (positinal) arguments.

At the same time, we value compatibility, so that Ruby3.0 keyword
arguments are somewhat compromise. Basically, keyword arguments are
separated from positional arguments, except when the method does not
take any formal keyword arguments, given keyword arguments (packed
in the hash object) are considered as the last argument.

And we also allow non symbol keys in the keyword arguments. In that
case, those keys are just passed in the `**` hash (or raise
`ArgumentError` for unknown keys).

The Instruction Changes

We have changed `OP_SEND` instruction. `OP_SEND` instruction used to
take 3 operands, the register, the symbol, the number of (positional)
arguments. The meaning of the third operand has been changed. It is now
considered as `n|(nk<<4)`, where `n` is the number of positional
arguments, and `nk` is the number of keyword arguments, both occupies
4 bits in the operand.

The number `15` in both `n` and `nk` means variable sized arguments are
packed in the object. Positional arguments will be packed in the array,
and keyword arguments will be packed in the hash object. That means
arguments more than 14 values are always packed in the object.

Arguments information for other instructions (`OP_SENDB` and `OP_SUPER`)
are also changed. It works as the third operand of `OP_SEND`. the
difference between `OP_SEND` and `OP_SENDB` is just trivial. It assigns
`nil` to the block hidden arguments (right after arguments).

The instruction `OP_SENDV` and `OP_SENDVB` are removed. Those
instructions are replaced by `OP_SEND` and `OP_SENDB` respectively with
the `15` (variable sized) argument information.

Calling Convention

When calling a method, the stack elements shall be in the order of the
receiver of the method, positional arguments, keyword arguments and the
block argument. If the number of positional or keyword arugument (`n` or
`nk`) is zero, corresponding arguments will be empty. So when `n=0` and
`nk=0` the stack layout (from bottom to top) will be:

+-----------------------+
| recv | block (or nil) |
+-----------------------+

The last elements `block` should be explicitly filled before `OP_SEND`
or assigned to `nil` by `OP_SENDB` internally. In other words, the
following have exactly same behavior:

OP_SENDB clears `block` implicitly:

```
OP_SENDB reg sym 0
```

OP_SEND clears `block` implicitly:

```
OP_LOADNIL  R2
OP_SEND     R2 sym 0
```

When calling a method with only positional arguments (n=0..14) without
keyword arguments, the stack layout will be like following:

+--------------------------------------------+
| recv | arg1 | ... | arg_n | block (or nil) |
+--------------------------------------------+

When calling a method with arguments packed in the array (n=15) which
means argument splat (*) is used in the actual arguments, or more than
14 arguments are passed the stack layout will be like following:

+-------------------------------+
| recv | array | block (or nil) |
+-------------------------------+

The number of the actual arguments is determined by the length of the
argument array.

When keyword arguments are given (nk>0), keyword arguments are passed
between positional arguments and the block argument. For example, when
we pass one positional argument `1` and one keyword argument `a: 2`,
the stack layout will be like:

+------------------------------------+
| recv | 1 | :a | 2 | block (or nil) |
+------------------------------------+

Note that keyword arguments consume `2*nk` elements in the stack when
`nk=0..14` (unpacked).

When calling a method with keyword arguments packed in the hash object
(nk=15) which means keyword argument splat (**) is used or more than
14 keyword arguments in the actual arguments, the stack layout will
be like:

+------------------------------+
| recv | hash | block (or nil) |
+------------------------------+

Note for mruby/c

When mruby/c authors try to support new keyword arguments, they need
to handle the new meaning of the argument information operand. If they
choose not to support keyword arguments in mruby/c, it just raise
error when `nk` (taken by `(c>>4)&0xf`) is not zero. And combine
`OP_SENDV` behavior with `OP_SEND` when `n` is `15`.

If they want to support keyword arguments seriously, contact me at
<matz@ruby.or.jp> or `@yukihiro_matz`. I can help you.
2021-10-12 20:16:36 +09:00
Yukihiro "Matz" Matsumoto d4abbf1b77 test/syntax.rb: add tests for break and redo. 2021-07-15 15:22:23 +09:00
Yukihiro "Matz" Matsumoto b8863c69dc Merge pull request #4141 from udzura/add-test-for-attr-nil-guard
Add a testcase of #4137 fix
2021-07-15 07:27:48 +09:00
Yukihiro "Matz" Matsumoto 03c4e114a9 test/syntax.rb: fix endless def warning (no assertion). 2021-05-21 08:13:37 +09:00
Yukihiro "Matz" Matsumoto 07c8470278 parse.y: allow "command" syntax in endless method definition.
This change allows `def hello = puts "Hello"` without parentheses.
This syntax has been introduced since Ruby3.1.
2021-05-18 16:26:36 +09:00
Yukihiro "Matz" Matsumoto 9f85c5e483 codegen.c: yield outside of method is now SyntaxError. 2021-03-31 15:57:43 +09:00
Yukihiro "Matz" Matsumoto 092dd4a667 Argument forwarding with ... now supports leading arguments.
```ruby
def method_missing(meth, ...)
  send(:"do_#{meth}", ...)
end
```
2020-12-09 11:56:54 +09:00
Yukihiro "Matz" Matsumoto dc886873bc Replace R-assignment by single-line pattern matching.
Since `R-assignment` in CRuby is abandoned.  Single-line pattern matching
in `mruby` only matches single local variable at the moment. Currently
it works as a right assignment to a local variable. It will be enhanced
in the future.
2020-11-02 15:14:36 +09:00
Yukihiro "Matz" Matsumoto 6e86e290e4 Rightward-assign by ASSOC.
[ruby-bugs:15921]
2020-10-12 16:21:18 +09:00
Yukihiro "Matz" Matsumoto 06e09fc7a9 Numbered parameters should not be available in the lambda bodies.
`mruby` does not warn like `CRuby` for cases like #4893.
Fix #4890, fix #4891, fix #4893.
2019-12-21 22:41:32 +09:00
KOBAYASHI Shuji 74f564b0bb _0 is not numbered parameter
#### Before this patch:

  ```console
  $ bin/mruby rb -e '_0=:l; p ->{_0}.()'
  -e:1:13: _0 is not available
  -e:1:13: syntax error, unexpected $end, expecting '}'
  ```

#### After this patch (same as Ruby):

  ```console
  $ bin/mruby rb -e '_0=:l; p ->{_0}.()'
  :l
  ```
2019-12-21 18:54:15 +09:00
Yukihiro "Matz" Matsumoto 0011652a28 Support new numbered parameter syntax _1 instead of @1. 2019-12-09 20:50:41 +09:00
Ukrainskiy Sergey 72d57ad094 Implement numbered parameters 2019-12-09 20:50:41 +09:00
KOBAYASHI Shuji 882bc80dd0 Add tests for #4746 2019-10-03 16:59:18 +09:00
KOBAYASHI Shuji ffb700dea0 Fix missing assertions in test/t/syntax.rb 2019-06-09 18:27:28 +09:00
Yukihiro "Matz" Matsumoto d47003aea4 Fixed a bug in argument number check with kwargs; fix #4159 2018-11-05 07:44:25 +09:00
Uchio KONDO 7c52734243 Add a testcase of #4137 fix 2018-10-15 14:46:24 +09:00
dearblue 366848996a Clear terminated space 2018-09-07 22:32:34 +09:00
Yukihiro "Matz" Matsumoto 889f0f5f36 Add test case corresponding to 53e2723. 2018-07-31 17:27:59 +09:00
Yukihiro "Matz" Matsumoto 8c9e712784 Keyword argument implemented. 2018-07-30 22:58:01 +09:00
Yukihiro "Matz" Matsumoto aec121f755 Update NODE_XSTR, NODE_DSXTR tests; ref #3605 2017-04-13 07:54:51 +09:00
Yutaka HARA 3f83ec64a8 Add test for recently fixed bugs 2016-12-01 14:55:26 +09:00
ksss d467022347 Add testing for regression 2016-09-08 16:35:41 +09:00
ksss 9dc820590f Should raise LocalJumpError when no block given 2016-07-14 13:03:25 +09:00
mimaki 22464fe5a0 mruby-1.2.0 2015-11-17 18:02:30 +09:00
Zachary Scott 87564dc98f Make travis happy
We have do this because mruby's test files are found using MRUBY_ROOT, like this:
    mrbs = Dir.glob("#{MRUBY_ROOT}/test/t/*.rb")
2015-09-02 09:56:27 -04:00
cremno 5cd877be7f fix masgn nosplat array rhs bug
The rest lhs variable has to be an empty array if rhs is an array with
less elements than pre + post lhs variables. The codegen generated
OP_ARRAY with an invalid length (such as 127 for *a, b = []) because rn
was negative.
2015-05-31 13:30:49 +02:00
Yukihiro "Matz" Matsumoto 9ef4bbb10d update test/t/syntax.rb to success on CRuby 2015-05-31 18:29:26 +09:00
cremno ba3a0c22a5 add multiple assignment with rest tests 2015-05-29 12:17:13 +02:00
cremno 2aa59393ba fix splat without assignment; fix #2781
The parser generates NODE_NIL for tSTAR without argument in masgns. The
codegen didn't handle that.
2015-05-07 16:58:43 +02:00
Kouhei Sutou 4b4ddd5a28 Fix a bug that no expression case doesn't return valid value
Here is a script that reproduces this problem:

     x = case
         when true; 1
         end
     p x # => main # 1 is expected
2015-02-24 20:53:12 +09:00
Kouhei Sutou 584d6de3c2 Fix a bug that if and no return value case can't return true clause value
Here is a script that reproduce this problem:

     x = if true
           1
         else
           case 2
           when 3
           end
           4
         end
     p x # => nil # 1 is expected
2015-02-24 00:16:41 +09:00
Kouhei Sutou 5ec676aa37 Fix splat and multiple assignments
Case1: From variable

Code:

    a = [1, 2, 3, 4, 5]
    b, c, *d = a

    p [a, b, c, d]

Before:

    [[1, 2, 3, 4, 5], 1, 2, []]

After:

    [[1, 2, 3, 4, 5], 1, 2, [3, 4, 5]]

Ruby:

    [[1, 2, 3, 4, 5], 1, 2, [3, 4, 5]]

Case2: From variables

Code:

    a = [1, 2, 3]
    b = [4, 5, 6, 7]
    c, d, *e, f, g = *a, *b

    p [a, b, c, d, e, f, g]

Before:

    [[1, 2, 3], [4, 5, 6, 7], 1, 2, [], 6, 7]

After:

    [[1, 2, 3], [4, 5, 6, 7], 1, 2, [3, 4, 5], 6, 7]

Ruby:

    [[1, 2, 3], [4, 5, 6, 7], 1, 2, [3, 4, 5], 6, 7]

Case 3: "for"

Code:

    a = [1, 2, 3, 4, 5, 6, 7]
    for b, c, *d, e, f in [a] do
      p [a, b, c, d, e, f]
    end

Before:

    [[1, 2, 3, 4, 5, 6, 7], 1, 2, [], nil, nil]

After:

    [[1, 2, 3, 4, 5, 6, 7], 1, 2, [3, 4, 5], 6, 7]

Ruby:

    [[1, 2, 3, 4, 5, 6, 7], 1, 2, [3, 4, 5], 6, 7]
2014-12-23 21:16:01 +09:00