Compare commits

...

52 Commits

Author SHA1 Message Date
mimaki 6c121b9708 Update version to 4.0.0RC3. 2026-04-02 11:23:31 +09:00
mimaki d06cb40725 Merge branch 'master' into stable 2026-04-02 10:31:49 +09:00
Yukihiro "Matz" Matsumoto 0cc4caad2b Merge pull request #6769 from khasinski/fix-socket-recvfrom-nonblock 2026-04-01 09:23:00 +09:00
Yukihiro "Matz" Matsumoto 0cef3e5414 Merge pull request #6770 from jbampton/patch-2 2026-04-01 09:17:38 +09:00
Yukihiro "Matz" Matsumoto 825d4c388e Merge pull request #6771 from mruby/dependabot/pre_commit/pre-commit-hooks-820b35f878 2026-04-01 09:16:17 +09:00
dependabot[bot] 141a8bc406 build(deps): bump https://github.com/rhysd/actionlint
Bumps the pre-commit-hooks group with 1 update: [https://github.com/rhysd/actionlint](https://github.com/rhysd/actionlint).


Updates `https://github.com/rhysd/actionlint` from v1.7.11 to 1.7.12
- [Release notes](https://github.com/rhysd/actionlint/releases)
- [Changelog](https://github.com/rhysd/actionlint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rhysd/actionlint/compare/v1.7.11...v1.7.12)

---
updated-dependencies:
- dependency-name: https://github.com/rhysd/actionlint
  dependency-version: 1.7.12
  dependency-type: direct:production
  dependency-group: pre-commit-hooks
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-31 15:00:01 +00:00
John Bampton a6aa0fdb24 Dependabot: add cooldown to pre-commit ecosystem 2026-04-01 00:46:24 +10:00
Chris Hasiński b85c520843 Remove stale self-corruption workaround in recvfrom_nonblock
The s = self workaround and XXX comment in recvfrom_nonblock date back
to the initial import of mruby-socket. The underlying bug where self
became a SystemcallException inside ensure blocks has since been fixed.

Verified that self correctly refers to the socket object in ensure
blocks after exceptions from recvfrom.
2026-03-30 22:14:26 +02:00
Yukihiro "Matz" Matsumoto d522bd5aa2 Merge pull request #6768 from hasumikin/fix/envadjust 2026-03-30 21:18:06 +09:00
HASUMI Hitoshi d95ebe4a23 Fix stack extension bug causing HardFault
This patch fixes a bug in the stack extension logic that could cause a HardFault on certain configurations when the stack is reallocated to a new address.

## Background

When the mruby VM's stack runs out, stack_extend_alloc() calls mrb_realloc to grow it.
If reallocation moves the block to a new address, envadjust() adjusts all ci->stack pointers to point into the new allocation.

## The bug

The bug happened under the configuration below:

- MRB_INT64 on MRB_32BIT (`sizeof(mrb_value) == 16` because MRB_NO_BOXING is now mandatory)
- Allocator with 8-byte alignment (eg. PICORB_ALLOC_ALIGN=8 in PicoRuby for Raspi Pico)

The delta was computed via mrb_value* pointer subtraction:

```c
ptrdiff_t delta = newbase - oldbase;  // units of sizeof(mrb_value)
```

If :
- Old address: 0x2004c508
- New address: 0x2004c510 (8-byte difference)

The pointer subtraction truncated: 8 / 16 = 0.
envadjust() was misleaded as `delta == 0` and returned early without adjusting any ci->stack pointers.
The stbase was updated to the new address, but all stack pointers still pointed 8 bytes before it.
Every register access was shifted, reading garbage, ultimately causing a HardFault.

## The fix

Byte-level char* calculation instead of mrb_value* calculation:

```c
ptrdiff_t off = (char*)newbase - (char*)oldbase;
// ...
ci->stack = (mrb_value*)((char*)ci->stack + off);
```

This ensures the adjustment is exact regardless of sizeof(mrb_value) and allocator alignment.
2026-03-30 16:25:46 +09:00
Yukihiro "Matz" Matsumoto ac9f7aedd2 Merge pull request #6767 from mruby/fix/lparen-arg-compstmt 2026-03-30 07:54:31 +09:00
Yukihiro "Matz" Matsumoto 919cbd8fea mruby-compiler: allow compound statement in tLPAREN_ARG
Change the grammar rule for tLPAREN_ARG from accepting only a
single stmt to accepting compstmt. This allows compound
statements with semicolons inside parenthesized arguments when
the parenthesis is preceded by a space, e.g., `p (f1; f2)`.

This matches the behavior of CRuby 3.3+.

Fixes #6766.

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-30 07:06:30 +09:00
Yukihiro "Matz" Matsumoto 801eefeab6 Merge pull request #6765 from khasinski/fix-lazy-flat-map 2026-03-29 22:55:13 +09:00
Chris Hasiński 8f71887e46 Improve flat_map test descriptions for clarity 2026-03-28 23:14:46 +01:00
Chris Hasiński 3f52ef6cfc Fix Lazy#flat_map to handle non-enumerable block return values
When the block passed to Lazy#flat_map returns a non-enumerable value
(e.g. an Integer), mruby raised NoMethodError because it unconditionally
called #each on the result. CRuby yields non-enumerable values directly.

Use respond_to?(:each) to match CRuby behavior: iterate enumerable
results, yield non-enumerable results as-is.
2026-03-28 22:59:11 +01:00
Yukihiro "Matz" Matsumoto 28c5b1b17b Merge pull request #6763 from mruby/dependabot/github_actions/github-actions-dependencies-19ba90ca6e 2026-03-26 14:27:05 +09:00
dependabot[bot] d50932c50f build(deps): bump j178/prek-action
Bumps the github-actions-dependencies group with 1 update: [j178/prek-action](https://github.com/j178/prek-action).


Updates `j178/prek-action` from 1 to 2
- [Release notes](https://github.com/j178/prek-action/releases)
- [Commits](https://github.com/j178/prek-action/compare/v1...v2)

---
updated-dependencies:
- dependency-name: j178/prek-action
  dependency-version: '2'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-25 14:54:41 +00:00
Yukihiro "Matz" Matsumoto b7e3743130 Merge pull request #6762 from mruby/fix-test-build-race 2026-03-25 15:49:46 +09:00
Yukihiro "Matz" Matsumoto 805e6dbc33 Merge pull request #6761 from mruby/fix-gc-unregister-leak 2026-03-25 15:44:44 +09:00
Yukihiro "Matz" Matsumoto e8c5e7c0cd mruby-test: write generated C files atomically to avoid race condition
With `rake -m`, the C compiler can start reading a partially-written
gem_test.c before generation completes. Write to a .tmp file first,
then rename to the final path.

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-25 15:32:36 +09:00
Yukihiro "Matz" Matsumoto ab249864cc gc.c: remove all matching entries in mrb_gc_unregister()
Previously only the first match was removed, leaking duplicate
entries when the same object was registered multiple times.
Use two-pointer compaction for O(N) removal.

Fixes #6760.

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-25 15:29:27 +09:00
Yukihiro "Matz" Matsumoto c2b588139f Merge pull request #6758 from dearblue/vm 2026-03-25 15:17:02 +09:00
Yukihiro "Matz" Matsumoto 21dc829903 Merge pull request #6759 from dearblue/bigint 2026-03-25 15:15:49 +09:00
dearblue 6c4a8c09db Define mrb_bigint_p() always.
Define the `mrb_bigint_p()` macro function, which returns false if `MRB_USE_BIGINT` is undefined.
2026-03-24 22:16:15 +09:00
dearblue c52faebb7f Don't assign the result of mrb_funcall() directly to regs
There are two reasons:

  - If the mruby call stack is extended, the `ci` variable may become invalid.
  - The C language does not specify the order in which the left-hand and right-hand sides of an assignment expression are evaluated.
    Therefore, if the mruby data stack is extended, `ci->stack` may become invalid.
2026-03-24 21:25:46 +09:00
Yukihiro "Matz" Matsumoto f61ab96689 Merge pull request #6756 from dearblue/array-ext 2026-03-24 15:04:58 +09:00
Yukihiro "Matz" Matsumoto 07a6c6e56b Merge pull request #6757 from mruby/dependabot/pre_commit/pre-commit-hooks-ae77450b09 2026-03-24 09:30:46 +09:00
dependabot[bot] 45ebb3d0c8 build(deps): bump https://github.com/rubocop/rubocop
Bumps the pre-commit-hooks group with 1 update: [https://github.com/rubocop/rubocop](https://github.com/rubocop/rubocop).


Updates `https://github.com/rubocop/rubocop` from v1.85.1 to 1.86.0
- [Release notes](https://github.com/rubocop/rubocop/releases)
- [Changelog](https://github.com/rubocop/rubocop/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rubocop/rubocop/compare/v1.85.1...v1.86.0)

---
updated-dependencies:
- dependency-name: https://github.com/rubocop/rubocop
  dependency-version: 1.86.0
  dependency-type: direct:production
  dependency-group: pre-commit-hooks
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-23 15:23:09 +00:00
dearblue 2135088ada Avoid the impact of object modifications caused by calls to mrb_vm_exec()
Several methods defined in mruby-array-ext are written in C and may call `mrb_vm_exec()`.
If array objects are modified on the Ruby side, problems may arise in subsequent processing.

  - Using objects that have been removed from the array and garbage collected
  - Using pointers or array lengths that have become invalid due to changes to the array object
  - Modifying the contents of a shared array object directly

ref: https://github.com/mruby/mruby/issues/6662
2026-03-22 23:05:37 +09:00
Yukihiro "Matz" Matsumoto 04f998238e Merge pull request #6755 from leviongit/vm/karg/delete-return 2026-03-21 17:03:27 +09:00
Yukihiro "Matz" Matsumoto affcbb000b Merge pull request #6754 from leviongit/core/attr_accessor/nullary 2026-03-21 17:02:24 +09:00
Yukihiro "Matz" Matsumoto ff5e6a2491 Merge pull request #6753 from dearblue/array.product 2026-03-21 16:57:49 +09:00
leviongit e8d0750458 reload ci after mrb_hash_delete_key 2026-03-20 21:35:26 +01:00
leviongit 88e356e7da remove redundant mrb_hash_get call
`mrb_hash_delete` returns the removed element (which is guaranteed to
exist due to the `mrb_hash_key_p` check), this prevents the hash from
being searched twice.
2026-03-20 21:20:18 +01:00
leviongit 95ece95e37 prefer marking the procs implementing attr_reader methods as noarg
this commit works on #6752 so it doesn't require a call to
`mrb_get_args`
2026-03-20 19:14:54 +01:00
dearblue 98d763603c Further optimize Array#product
Replace `__product_group` method with `__product_generate` and `__product_next`.
This change eliminates the need for Ruby to perform internal state calculations, allowing it to simply receive the results.
2026-03-20 21:13:52 +09:00
Yukihiro "Matz" Matsumoto 01ce2f8c71 Merge pull request #6747 from katafrakt/handle-hash-default-arg 2026-03-20 16:44:27 +09:00
Yukihiro "Matz" Matsumoto f08dede1d9 Merge pull request #6752 from khasinski/fix-attr-reader-arity 2026-03-20 16:40:45 +09:00
Yukihiro "Matz" Matsumoto 3bfe703f80 Merge pull request #6750 from dearblue/array.product 2026-03-20 10:24:10 +09:00
Yukihiro "Matz" Matsumoto e82fa70004 Merge pull request #6749 from hasumikin/fix/microcontroller-profile 2026-03-20 10:22:32 +09:00
Yukihiro "Matz" Matsumoto 8d53f65b96 Merge pull request #6748 from jbampton/clean-up-workflows 2026-03-20 10:21:45 +09:00
Chris Hasiński c0b1e87c09 Fix attr_reader-generated methods accepting extra arguments
attr_reader-generated getter methods silently ignored any arguments
passed to them. CRuby raises ArgumentError in this case.

Add mrb_get_args(mrb, "") to enforce zero arguments, matching CRuby.
2026-03-19 23:12:14 +01:00
dearblue 8441eaf633 Fixed "Out-of-bounds Read" and "Divide-by-Zero" in ary_product_group()
Reproduction:

  - Out-of-bounds Read

    ```console
    % build/host/bin/mruby -e '([nil] * 256).__product_group([[nil] * 256], 1 << 32, 256)'
    zsh: segmentation fault (core dumped)  build/host/bin/mruby -e
    ```

  - Divide-by-Zero

    ```console
    % build/host/bin/mruby -e '([nil] * 256).__product_group([[]], 1 << 32, 256)'
    zsh: floating point exception (core dumped)  build/host/bin/mruby -e '([nil] * 256).__product_group([[]], 1 << 32, 256)'
    ```
2026-03-19 23:11:06 +09:00
HASUMI Hitoshi 736a72cdc9 [skip ci] Update include/mrbconf.h
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-03-19 09:50:15 +09:00
HASUMI Hitoshi 5e9eed2d0c Fix KHASH_DEFAULT_SIZE to KHASH_INITIAL_SIZE rename inconsistencies
Commit 250bf6edd renamed KHASH_DEFAULT_SIZE to KHASH_INITIAL_SIZE but
missed updating build_config files and documentation. Also restore the
default value in khash.h to 32, consistent with the documented default
and the profile hierarchy (MRB_CONSTRAINED_BASELINE_PROFILE reduces it
to 16).
2026-03-19 09:38:36 +09:00
John Bampton 80d84188fd pre-commit bump Node.js 2026-03-18 17:57:33 +10:00
John Bampton 55ef8e1728 Update workflows 2026-03-18 17:57:05 +10:00
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 a41eeaed33 Merge pull request #6735 from dearblue/presym 2026-03-16 21:55:22 +09:00
Yukihiro "Matz" Matsumoto 4ed4326dd5 Merge pull request #6746 from mruby/dependabot/pre_commit/pre-commit-hooks-6e50fbf5c1 2026-03-16 21:47:31 +09:00
dearblue 000acedc35 Prevent full recompilation without changes to presym file
Commit b9a1a1fb23 is a revert of commit 8df9a22a85, differing only in the comment.
This means the issue from https://github.com/mruby/mruby/issues/6721 has reappeared.

The cause of https://github.com/mruby/mruby/issues/6721, as stated in the commit message for commit 8df9a22a85, is that each ".o" file has an indirect dependency on all ".pi" files through the presym file.

This patch therefore adds a proxy-like task `gensym:update:#{build.name}` between tasks.
Its purpose is to hide the direct dependency from ".o" files to the presym file from the rake system.
2026-03-14 17:14:37 +09:00
dependabot[bot] 14e98c60c3 build(deps): bump the pre-commit-hooks group across 1 directory with 8 updates
Bumps the pre-commit-hooks group with 8 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [https://github.com/gitleaks/gitleaks](https://github.com/gitleaks/gitleaks) | `v8.30.0` | `8.30.1` |
| [https://github.com/oxipng/oxipng](https://github.com/oxipng/oxipng) | `v10.0.0` | `10.1.0` |
| [https://github.com/Lucas-C/pre-commit-hooks](https://github.com/Lucas-C/pre-commit-hooks) | `v1.5.5` | `1.5.6` |
| [https://github.com/rhysd/actionlint](https://github.com/rhysd/actionlint) | `v1.7.9` | `1.7.11` |
| [https://github.com/codespell-project/codespell](https://github.com/codespell-project/codespell) | `v2.4.1` | `2.4.2` |
| [https://github.com/igorshubovych/markdownlint-cli](https://github.com/igorshubovych/markdownlint-cli) | `v0.46.0` | `0.48.0` |
| [https://github.com/rubocop/rubocop](https://github.com/rubocop/rubocop) | `v1.81.7` | `1.85.1` |
| [https://github.com/adrienverge/yamllint](https://github.com/adrienverge/yamllint) | `v1.37.1` | `1.38.0` |



Updates `https://github.com/gitleaks/gitleaks` from v8.30.0 to 8.30.1
- [Release notes](https://github.com/gitleaks/gitleaks/releases)
- [Commits](https://github.com/gitleaks/gitleaks/compare/v8.30.0...v8.30.1)

Updates `https://github.com/oxipng/oxipng` from v10.0.0 to 10.1.0
- [Release notes](https://github.com/oxipng/oxipng/releases)
- [Changelog](https://github.com/oxipng/oxipng/blob/master/CHANGELOG.md)
- [Commits](https://github.com/oxipng/oxipng/compare/v10.0.0...v10.1.0)

Updates `https://github.com/Lucas-C/pre-commit-hooks` from v1.5.5 to 1.5.6
- [Release notes](https://github.com/Lucas-C/pre-commit-hooks/releases)
- [Commits](https://github.com/Lucas-C/pre-commit-hooks/compare/v1.5.5...v1.5.6)

Updates `https://github.com/rhysd/actionlint` from v1.7.9 to 1.7.11
- [Release notes](https://github.com/rhysd/actionlint/releases)
- [Changelog](https://github.com/rhysd/actionlint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rhysd/actionlint/compare/v1.7.9...v1.7.11)

Updates `https://github.com/codespell-project/codespell` from v2.4.1 to 2.4.2
- [Release notes](https://github.com/codespell-project/codespell/releases)
- [Commits](https://github.com/codespell-project/codespell/compare/v2.4.1...v2.4.2)

Updates `https://github.com/igorshubovych/markdownlint-cli` from v0.46.0 to 0.48.0
- [Release notes](https://github.com/igorshubovych/markdownlint-cli/releases)
- [Commits](https://github.com/igorshubovych/markdownlint-cli/compare/v0.46.0...v0.48.0)

Updates `https://github.com/rubocop/rubocop` from v1.81.7 to 1.85.1
- [Release notes](https://github.com/rubocop/rubocop/releases)
- [Changelog](https://github.com/rubocop/rubocop/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rubocop/rubocop/compare/v1.81.7...v1.85.1)

Updates `https://github.com/adrienverge/yamllint` from v1.37.1 to 1.38.0
- [Release notes](https://github.com/adrienverge/yamllint/releases)
- [Changelog](https://github.com/adrienverge/yamllint/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/adrienverge/yamllint/compare/v1.37.1...v1.38.0)

---
updated-dependencies:
- dependency-name: https://github.com/gitleaks/gitleaks
  dependency-version: 8.30.1
  dependency-type: direct:production
  dependency-group: pre-commit-hooks
- dependency-name: https://github.com/oxipng/oxipng
  dependency-version: 10.1.0
  dependency-type: direct:production
  dependency-group: pre-commit-hooks
- dependency-name: https://github.com/Lucas-C/pre-commit-hooks
  dependency-version: 1.5.6
  dependency-type: direct:production
  dependency-group: pre-commit-hooks
- dependency-name: https://github.com/rhysd/actionlint
  dependency-version: 1.7.11
  dependency-type: direct:production
  dependency-group: pre-commit-hooks
- dependency-name: https://github.com/codespell-project/codespell
  dependency-version: 2.4.2
  dependency-type: direct:production
  dependency-group: pre-commit-hooks
- dependency-name: https://github.com/igorshubovych/markdownlint-cli
  dependency-version: 0.48.0
  dependency-type: direct:production
  dependency-group: pre-commit-hooks
- dependency-name: https://github.com/rubocop/rubocop
  dependency-version: 1.85.1
  dependency-type: direct:production
  dependency-group: pre-commit-hooks
- dependency-name: https://github.com/adrienverge/yamllint
  dependency-version: 1.38.0
  dependency-type: direct:production
  dependency-group: pre-commit-hooks
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-13 14:57:23 +00:00
35 changed files with 2923 additions and 2728 deletions
+2
View File
@@ -29,3 +29,5 @@ updates:
pre-commit-hooks:
patterns:
- "*"
cooldown:
default-days: 7
+6
View File
@@ -32,6 +32,8 @@ jobs:
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@v6
with:
persist-credentials: false
- name: Ruby version
run: ruby -v
- name: Compiler version
@@ -45,6 +47,8 @@ jobs:
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@v6
with:
persist-credentials: false
- name: Ruby version
run: ruby -v
- name: Cache cosmocc
@@ -71,6 +75,8 @@ jobs:
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@v6
with:
persist-credentials: false
- name: Ruby version
run: ruby -v
- name: Build and test
+2
View File
@@ -19,6 +19,8 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
persist-credentials: false
- name: Initialize CodeQL
uses: github/codeql-action/init@v4
with:
+5
View File
@@ -2,6 +2,9 @@ name: Coverage
on: [push]
permissions:
contents: read
jobs:
coverage:
name: Coverage
@@ -17,6 +20,8 @@ jobs:
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@v6
with:
persist-credentials: false
- name: Ruby version
run: ruby -v
- name: Compiler version
+2
View File
@@ -12,6 +12,8 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- uses: ls-lint/action@v2.3.1
with:
config: .github/linters/.ls-lint.yml
+3 -1
View File
@@ -13,7 +13,9 @@ jobs:
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@v6
- uses: j178/prek-action@v1
with:
persist-credentials: false
- uses: j178/prek-action@v2
with:
install-only: true
- name: Run manual pre-commit hooks
+3 -1
View File
@@ -13,6 +13,8 @@ jobs:
steps:
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@v6
- uses: j178/prek-action@v1
with:
persist-credentials: false
- uses: j178/prek-action@v2
with:
extra-args: --all-files
+2
View File
@@ -20,6 +20,8 @@ jobs:
steps:
- name: "Checkout ${{ github.ref_name }} ( ${{ github.sha }} )"
uses: actions/checkout@v6
with:
persist-credentials: false
- name: Builds
id: builds
run: |
+1
View File
@@ -19,6 +19,7 @@ jobs:
with:
# Full git history is needed to get a proper list of changed files within `super-linter`
fetch-depth: 0
persist-credentials: false
- name: Lint Code Base
uses: super-linter/super-linter/slim@v8.5.0
env:
+9 -9
View File
@@ -3,7 +3,7 @@
default_stages: [pre-commit, pre-push]
default_language_version:
python: python3
node: 24.11.1
node: 24.14.0
minimum_pre_commit_version: "3.2.0"
exclude: "^tools/lrama/"
repos:
@@ -35,13 +35,13 @@ repos:
track and have security implications. Please remove the zip file from the repository.
files: \.zip$
- repo: https://github.com/gitleaks/gitleaks
rev: v8.30.0
rev: v8.30.1
hooks:
- id: gitleaks
name: run gitleaks
description: detect hardcoded secrets with gitleaks
- repo: https://github.com/oxipng/oxipng
rev: v10.0.0
rev: v10.1.0
hooks:
- id: oxipng
name: run oxipng
@@ -73,7 +73,7 @@ repos:
- id: mixed-line-ending
- id: trailing-whitespace
- repo: https://github.com/Lucas-C/pre-commit-hooks
rev: v1.5.5
rev: v1.5.6
hooks:
- id: forbid-tabs
name: run no-tabs checker
@@ -85,19 +85,19 @@ repos:
args: [--whitespaces-count, "2"]
exclude: Makefile$
- repo: https://github.com/rhysd/actionlint
rev: v1.7.9
rev: v1.7.12
hooks:
- id: actionlint
name: run actionlint
description: lint GitHub Actions workflow files
- repo: https://github.com/codespell-project/codespell
rev: v2.4.1
rev: v2.4.2
hooks:
- id: codespell
name: run codespell
description: check spelling with codespell
- repo: https://github.com/igorshubovych/markdownlint-cli
rev: v0.46.0
rev: v0.48.0
hooks:
- id: markdownlint
name: run markdownlint
@@ -106,7 +106,7 @@ repos:
types: [markdown]
files: \.md$
- repo: https://github.com/rubocop/rubocop
rev: v1.81.7
rev: v1.86.0
hooks:
- id: rubocop
name: run rubocop
@@ -120,7 +120,7 @@ repos:
name: run shellcheck
description: check shell scripts with a static analysis tool
- repo: https://github.com/adrienverge/yamllint
rev: v1.37.1
rev: v1.38.0
hooks:
- id: yamllint
name: run yamllint
+1 -1
View File
@@ -51,7 +51,7 @@ To get mruby, you can download the stable version 4.0.0 from the official mruby
GitHub repository or clone the trunk of the mruby source tree with the "git
clone" command. You can also install and compile mruby using [ruby-install](https://github.com/postmodern/ruby-install), [ruby-build](https://github.com/rbenv/ruby-build), [rvm](https://github.com/rvm/rvm), [conda](https://anaconda.org/channels/conda-forge/packages/mruby/overview) or [Homebrew](https://formulae.brew.sh/formula/mruby).
The release candidate version 4.0.0 of mruby can be downloaded via the following URL: [https://github.com/mruby/mruby/archive/4.0.0-rc2.zip](https://github.com/mruby/mruby/archive/4.0.0-rc2.zip)
The release candidate version 4.0.0 of mruby can be downloaded via the following URL: [https://github.com/mruby/mruby/archive/4.0.0-rc3.zip](https://github.com/mruby/mruby/archive/4.0.0-rc3.zip)
The latest development version of mruby can be downloaded via the following URL: [https://github.com/mruby/mruby/zipball/master](https://github.com/mruby/mruby/zipball/master)
+1 -1
View File
@@ -30,7 +30,7 @@ MRuby::CrossBuild.new("ArduinoDue") do |conf|
#configuration for low memory environment
cc.defines << %w(MRB_HEAP_PAGE_SIZE=64)
cc.defines << %w(KHASH_DEFAULT_SIZE=8)
cc.defines << %w(KHASH_INITIAL_SIZE=8)
cc.defines << %w(MRB_GC_STRESS)
#cc.defines << %w(MRB_NO_STDIO) #if you don't need stdio.
#cc.defines << %w(POOL_PAGE_SIZE=1000) #effective only for use with mruby-eval
+1 -1
View File
@@ -16,7 +16,7 @@ MRuby::CrossBuild.new("RX630") do |conf|
#configuration for low memory environment
cc.defines << %w(MRB_USE_FLOAT32)
cc.defines << %w(MRB_HEAP_PAGE_SIZE=64)
cc.defines << %w(KHASH_DEFAULT_SIZE=8)
cc.defines << %w(KHASH_INITIAL_SIZE=8)
cc.defines << %w(MRB_GC_STRESS)
cc.defines << %w(MRB_NO_STDIO) #if you don't need stdio.
#cc.defines << %w(POOL_PAGE_SIZE=1000) #effective only for use with mruby-eval
+1 -1
View File
@@ -27,7 +27,7 @@ MRuby::CrossBuild.new("chipKITMax32") do |conf|
#configuration for low memory environment
cc.defines << %w(MRB_HEAP_PAGE_SIZE=64)
cc.defines << %w(KHASH_DEFAULT_SIZE=8)
cc.defines << %w(KHASH_INITIAL_SIZE=8)
cc.defines << %w(MRB_GC_STRESS)
#cc.defines << %w(MRB_NO_STDIO) #if you don't need stdio.
#cc.defines << %w(POOL_PAGE_SIZE=1000) #effective only for use with mruby-eval
+3 -3
View File
@@ -233,10 +233,10 @@ end
- Specifies 4th argument(`argc`) max value of `mrb_funcall`.
- Raises `ArgumentError` when the `argc` argument is bigger then this value `mrb_funcall`.
`KHASH_DEFAULT_SIZE`
`KHASH_INITIAL_SIZE`
- Default value is `32`.
- Specifies default size of khash table bucket.
- Specifies initial size of khash table bucket.
- Used in `kh_init_ ## name` function.
`MRB_NO_METHOD_CACHE`
@@ -272,7 +272,7 @@ deployment targets. Define one of the following:
`MRB_CONSTRAINED_BASELINE_PROFILE`
- For micro controllers.
- Enables `MRB_NO_METHOD_CACHE`, reduces `KHASH_DEFAULT_SIZE` to `16`,
- Enables `MRB_NO_METHOD_CACHE`, reduces `KHASH_INITIAL_SIZE` to `16`,
and `MRB_HEAP_PAGE_SIZE` to `256`.
`MRB_BASELINE_PROFILE`
+4 -4
View File
@@ -138,8 +138,8 @@
/* turn off generational GC by default */
//#define MRB_GC_TURN_OFF_GENERATIONAL
/* default size of khash table bucket */
//#define KHASH_DEFAULT_SIZE 32
/* initial size of khash table bucket */
//#define KHASH_INITIAL_SIZE 32
/* allocated memory address alignment */
//#define POOL_ALIGNMENT 4
@@ -208,8 +208,8 @@
# define MRB_NO_METHOD_CACHE
# endif
# ifndef KHASH_DEFAULT_SIZE
# define KHASH_DEFAULT_SIZE 16
# ifndef KHASH_INITIAL_SIZE
# define KHASH_INITIAL_SIZE 16
# endif
# ifndef MRB_HEAP_PAGE_SIZE
+1 -1
View File
@@ -21,7 +21,7 @@ typedef uint32_t khint_t;
typedef khint_t khiter_t;
#ifndef KHASH_INITIAL_SIZE
# define KHASH_INITIAL_SIZE 8
# define KHASH_INITIAL_SIZE 32
#endif
#define KHASH_MIN_SIZE 8
#define KHASH_SMALL_LIMIT 4
+4
View File
@@ -316,7 +316,11 @@ struct RCptr {
#endif
#define mrb_test(o) mrb_bool(o)
#ifndef mrb_bigint_p
#ifdef MRB_USE_BIGINT
#define mrb_bigint_p(o) (mrb_type(o) == MRB_TT_BIGINT)
#else
#define mrb_bigint_p(o) FALSE
#endif
#endif
/**
+3 -3
View File
@@ -57,7 +57,7 @@ MRB_BEGIN_DECL
/*
* Patch level string. (optional)
*/
#define MRUBY_PATCHLEVEL_STR "RC2"
#define MRUBY_PATCHLEVEL_STR "RC3"
#ifndef MRUBY_PATCHLEVEL_STR
# if MRUBY_PATCHLEVEL < 0
@@ -85,12 +85,12 @@ MRB_BEGIN_DECL
/*
* Release month.
*/
#define MRUBY_RELEASE_MONTH 3
#define MRUBY_RELEASE_MONTH 4
/*
* Release day.
*/
#define MRUBY_RELEASE_DAY 12
#define MRUBY_RELEASE_DAY 2
/*
* Release date as a string.
+7 -29
View File
@@ -611,37 +611,15 @@ class Array
# ary.product(*arys) -> array
# ary.product(*arys) { |item| ... } -> self
def product(*arys, &block)
size = arys.size
i = size
while i > 0
i -= 1
unless arys[i].kind_of?(Array)
raise TypeError, "no implicit conversion into Array"
gen = __product_generate(arys, &block)
return gen unless block
if gen
while group = __product_next(arys, gen)
yield group
end
end
i = size
total = self.size
total *= arys[i -= 1].size while i > 0
if block
i = 0
while i < total
group = self.__product_group(arys, i, size + 1)
block.call(group)
i += 1
end
return self
else
result = [nil] * total
i = 0
while i < total
group = self.__product_group(arys, i, size + 1)
result[i] = group
i += 1
end
return result
end
self
end
##
+147 -41
View File
@@ -6,6 +6,7 @@
#include <mruby/hash.h>
#include <mruby/data.h>
#include <mruby/class.h>
#include <mruby/numeric.h>
#include <mruby/internal.h>
#include <mruby/khash.h>
#include <mruby/error.h>
@@ -78,11 +79,14 @@ ary_assoc(mrb_state *mrb, mrb_value ary)
{
mrb_value k = mrb_get_arg1(mrb);
int ai = mrb_gc_arena_save(mrb);
for (mrb_int i = 0; i < RARRAY_LEN(ary); i++) {
mrb_value v = mrb_check_array_type(mrb, RARRAY_PTR(ary)[i]);
mrb_gc_protect(mrb, v); // v may be removed from ary by mrb_equal()
if (!mrb_nil_p(v) && RARRAY_LEN(v) > 0 &&
mrb_equal(mrb, RARRAY_PTR(v)[0], k))
return v;
mrb_gc_arena_restore(mrb, ai);
}
return mrb_nil_value();
}
@@ -106,12 +110,15 @@ ary_rassoc(mrb_state *mrb, mrb_value ary)
{
mrb_value value = mrb_get_arg1(mrb);
int ai = mrb_gc_arena_save(mrb);
for (mrb_int i = 0; i < RARRAY_LEN(ary); i++) {
mrb_value v = RARRAY_PTR(ary)[i];
mrb_gc_protect(mrb, v); // v may be removed from ary by mrb_equal()
if (mrb_array_p(v) &&
RARRAY_LEN(v) > 1 &&
mrb_equal(mrb, RARRAY_PTR(v)[1], value))
return v;
mrb_gc_arena_restore(mrb, ai);
}
return mrb_nil_value();
}
@@ -409,9 +416,12 @@ ary_init_temp_set(mrb_state *mrb, ary_set_t *set, mrb_int capacity)
static void
ary_populate_temp_set(mrb_state *mrb, ary_set_t *set, mrb_value ary)
{
mrb_int len = RARRAY_LEN(ary);
for (mrb_int i = 0; i < len; i++) {
kh_put(ary_set, mrb, set, RARRAY_PTR(ary)[i]);
int ai = mrb_gc_arena_save(mrb);
for (mrb_int i = 0; i < RARRAY_LEN(ary); i++) {
mrb_value p = RARRAY_PTR(ary)[i];
mrb_gc_protect(mrb, p); // p may be removed from ary by kh_put(ary_set, ...)
kh_put(ary_set, mrb, set, p);
mrb_gc_arena_restore(mrb, ai);
}
}
@@ -460,12 +470,15 @@ ary_subtract_body(mrb_state *mrb, void *data)
ary_populate_temp_set(mrb, ctx->set, ctx->argv[i]);
}
int ai = mrb_gc_arena_save(mrb);
for (mrb_int i = 0; i < RARRAY_LEN(ctx->self); i++) {
mrb_value p = RARRAY_PTR(ctx->self)[i];
mrb_gc_protect(mrb, p); // p may be removed from self by kh_get(ary_set, ...)
khiter_t k = kh_get(ary_set, mrb, ctx->set, p);
if (kh_is_end(ctx->set, k)) { /* key doesn't exist in any ary */
mrb_ary_push(mrb, ctx->result, p);
}
mrb_gc_arena_restore(mrb, ai);
}
return ctx->result;
@@ -499,13 +512,13 @@ ary_subtract_internal(mrb_state *mrb, mrb_value self, mrb_int argc, const mrb_va
}
}
else {
mrb_int self_len = RARRAY_LEN(self);
for (mrb_int i = 0; i < self_len; i++) {
int ai = mrb_gc_arena_save(mrb);
for (mrb_int i = 0; i < RARRAY_LEN(self); i++) {
mrb_value p = RARRAY_PTR(self)[i];
mrb_gc_protect(mrb, p); // p may be removed from self by mrb_equal()
mrb_bool found = FALSE;
for (mrb_int j = 0; j < argc; j++) {
mrb_int len = RARRAY_LEN(argv[j]);
for (mrb_int k = 0; k < len; k++) {
for (mrb_int k = 0; k < RARRAY_LEN(argv[j]); k++) {
if (mrb_equal(mrb, p, RARRAY_PTR(argv[j])[k])) {
found = TRUE;
break;
@@ -516,6 +529,7 @@ ary_subtract_internal(mrb_state *mrb, mrb_value self, mrb_int argc, const mrb_va
if (!found) {
mrb_ary_push(mrb, result, p);
}
mrb_gc_arena_restore(mrb, ai);
}
}
@@ -559,12 +573,10 @@ ary_difference(mrb_state *mrb, mrb_value self)
return ary_subtract_internal(mrb, self, argc, argv);
}
static void
add_uniq(mrb_state *mrb, mrb_value item, mrb_value result)
{
const mrb_int len = RARRAY_LEN(result);
for (mrb_int i = 0; i < len; i++) {
for (mrb_int i = 0; i < RARRAY_LEN(result); i++) {
if (mrb_eql(mrb, item, RARRAY_PTR(result)[i])) {
return;
}
@@ -584,15 +596,18 @@ static mrb_value
ary_union_body(mrb_state *mrb, void *data)
{
struct ary_union_ctx *ctx = (struct ary_union_ctx *)data;
int ai = mrb_gc_arena_save(mrb);
/* Add unique elements from self */
for (mrb_int i = 0; i < RARRAY_LEN(ctx->self_copy); i++) {
mrb_value elem = RARRAY_PTR(ctx->self_copy)[i];
mrb_gc_protect(mrb, elem); // elem may be removed from self_copy by kh_get(ary_set, ...)
khiter_t k = kh_get(ary_set, mrb, ctx->set, elem);
if (kh_is_end(ctx->set, k)) {
kh_put(ary_set, mrb, ctx->set, elem);
mrb_ary_push(mrb, ctx->result, elem);
}
mrb_gc_arena_restore(mrb, ai);
}
/* Add unique elements from others */
@@ -600,11 +615,13 @@ ary_union_body(mrb_state *mrb, void *data)
mrb_value other = ctx->argv[i];
for (mrb_int j = 0; j < RARRAY_LEN(other); j++) {
mrb_value elem = RARRAY_PTR(other)[j];
mrb_gc_protect(mrb, elem); // elem may be removed from other by kh_get(ary_set, ...)
khiter_t k = kh_get(ary_set, mrb, ctx->set, elem);
if (kh_is_end(ctx->set, k)) {
kh_put(ary_set, mrb, ctx->set, elem);
mrb_ary_push(mrb, ctx->result, elem);
}
mrb_gc_arena_restore(mrb, ai);
}
}
@@ -636,19 +653,25 @@ ary_union_internal(mrb_state *mrb, mrb_value self, mrb_int argc, const mrb_value
}
}
else {
int ai = mrb_gc_arena_save(mrb);
/* Use linear search for small arrays */
/* Add unique elements from self */
mrb_int alen = RARRAY_LEN(self);
for (mrb_int i = 0; i < alen; i++) {
add_uniq(mrb, RARRAY_PTR(self)[i], result);
for (mrb_int i = 0; i < RARRAY_LEN(self); i++) {
mrb_value p = RARRAY_PTR(self)[i];
mrb_gc_protect(mrb, p); // p may be removed from self by add_uniq()
add_uniq(mrb, p, result);
mrb_gc_arena_restore(mrb, ai);
}
/* Add unique elements from others */
for (mrb_int i = 0; i < argc; i++) {
mrb_value other = argv[i];
mrb_int olen = RARRAY_LEN(other);
for (mrb_int j = 0; j < olen; j++) {
add_uniq(mrb, RARRAY_PTR(other)[j], result);
for (mrb_int j = 0; j < RARRAY_LEN(other); j++) {
mrb_value p = RARRAY_PTR(other)[j];
mrb_gc_protect(mrb, p); // p may be removed from other by add_uniq()
add_uniq(mrb, p, result);
mrb_gc_arena_restore(mrb, ai);
}
}
}
@@ -711,13 +734,16 @@ ary_intersection_body(mrb_state *mrb, void *data)
ary_populate_temp_set(mrb, ctx->set, ctx->argv[i]);
}
int ai = mrb_gc_arena_save(mrb);
for (mrb_int i = 0; i < RARRAY_LEN(ctx->self); i++) {
mrb_value p = RARRAY_PTR(ctx->self)[i];
mrb_gc_protect(mrb, p); // p may be removed from self by kh_get(ary_set, ...)
khiter_t k = kh_get(ary_set, mrb, ctx->set, p);
if (!kh_is_end(ctx->set, k)) {
mrb_ary_push(mrb, ctx->result, p);
kh_del(ary_set, mrb, ctx->set, k);
}
mrb_gc_arena_restore(mrb, ai);
}
return ctx->result;
@@ -751,15 +777,15 @@ ary_intersection_internal(mrb_state *mrb, mrb_value self, mrb_int argc, const mr
}
}
else {
mrb_int self_len = RARRAY_LEN(self);
for (mrb_int i = 0; i < self_len; i++) {
int ai = mrb_gc_arena_save(mrb);
for (mrb_int i = 0; i < RARRAY_LEN(self); i++) {
mrb_value p = RARRAY_PTR(self)[i];
mrb_gc_protect(mrb, p); // p may be removed from self by mrb_equal()
mrb_bool found_in_all = TRUE;
for (mrb_int j = 0; j < argc; j++) {
mrb_bool found_in_current_other = FALSE;
mrb_int len = RARRAY_LEN(argv[j]);
for (mrb_int k = 0; k < len; k++) {
for (mrb_int k = 0; k < RARRAY_LEN(argv[j]); k++) {
if (mrb_equal(mrb, p, RARRAY_PTR(argv[j])[k])) {
found_in_current_other = TRUE;
break;
@@ -773,8 +799,7 @@ ary_intersection_internal(mrb_state *mrb, mrb_value self, mrb_int argc, const mr
if (found_in_all) {
mrb_bool already_added = FALSE;
mrb_int result_len = RARRAY_LEN(result);
for (mrb_int j = 0; j < result_len; j++) {
for (mrb_int j = 0; j < RARRAY_LEN(result); j++) {
if (mrb_equal(mrb, p, RARRAY_PTR(result)[j])) {
already_added = TRUE;
break;
@@ -784,6 +809,7 @@ ary_intersection_internal(mrb_state *mrb, mrb_value self, mrb_int argc, const mr
mrb_ary_push(mrb, result, p);
}
}
mrb_gc_arena_restore(mrb, ai);
}
}
return result;
@@ -854,8 +880,12 @@ ary_intersect_p_body(mrb_state *mrb, void *data)
ary_populate_temp_set(mrb, ctx->set, ctx->shorter_ary_copy);
int ai = mrb_gc_arena_save(mrb);
for (mrb_int i = 0; i < RARRAY_LEN(ctx->longer_ary); i++) {
khiter_t k = kh_get(ary_set, mrb, ctx->set, RARRAY_PTR(ctx->longer_ary)[i]);
mrb_value p = RARRAY_PTR(ctx->longer_ary)[i];
mrb_gc_protect(mrb, p); // p may be removed from longer_ary by kh_get(ary_set, ...)
khiter_t k = kh_get(ary_set, mrb, ctx->set, p);
mrb_gc_arena_restore(mrb, ai);
if (!kh_is_end(ctx->set, k)) {
*ctx->found = TRUE;
break;
@@ -905,12 +935,16 @@ ary_intersect_p(mrb_state *mrb, mrb_value self)
}
}
else {
int ai = mrb_gc_arena_save(mrb);
for (mrb_int i = 0; i < RARRAY_LEN(longer_ary); i++) {
mrb_value p = RARRAY_PTR(longer_ary)[i];
mrb_gc_protect(mrb, p); // p may be removed from longer_ary by mrb_equal()
for (mrb_int j = 0; j < RARRAY_LEN(shorter_ary); j++) {
if (mrb_equal(mrb, RARRAY_PTR(longer_ary)[i], RARRAY_PTR(shorter_ary)[j])) {
if (mrb_equal(mrb, p, RARRAY_PTR(shorter_ary)[j])) {
return mrb_true_value();
}
}
mrb_gc_arena_restore(mrb, ai);
}
}
@@ -1041,6 +1075,7 @@ ary_fill_exec(mrb_state *mrb, mrb_value self)
}
/* Fill the array */
mrb_ary_modify(mrb, ary);
mrb_value *ptr = ARY_PTR(ary) + start;
for (mrb_int i = 0; i < length; i++) {
ptr[i] = obj;
@@ -1058,7 +1093,6 @@ struct ary_uniq_bang_ctx {
mrb_value self_copy;
mrb_value self;
mrb_int *write_pos;
mrb_int len;
};
static mrb_value
@@ -1068,15 +1102,19 @@ ary_uniq_bang_body(mrb_state *mrb, void *data)
ary_populate_temp_set(mrb, ctx->set, ctx->self_copy);
for (mrb_int read_pos = 0; read_pos < ctx->len; read_pos++) {
int ai = mrb_gc_arena_save(mrb);
for (mrb_int read_pos = 0; read_pos < RARRAY_LEN(ctx->self); read_pos++) {
mrb_value elem = RARRAY_PTR(ctx->self)[read_pos];
mrb_gc_protect(mrb, elem); // elem may be removed from self by kh_get(ary_set, ...)
khiter_t k = kh_get(ary_set, mrb, ctx->set, elem);
if (!kh_is_end(ctx->set, k)) {
if (*ctx->write_pos != read_pos) {
if (*ctx->write_pos != read_pos && *ctx->write_pos < RARRAY_LEN(ctx->self)) {
mrb_ary_modify(mrb, mrb_ary_ptr(ctx->self));
RARRAY_PTR(ctx->self)[*ctx->write_pos] = elem;
}
(*ctx->write_pos)++;
kh_del(ary_set, mrb, ctx->set, k);
mrb_gc_arena_restore(mrb, ai);
}
}
@@ -1103,28 +1141,32 @@ ary_uniq_bang(mrb_state *mrb, mrb_value self)
ary_set_t *set = &set_struct;
ary_init_temp_set(mrb, set, len);
struct ary_uniq_bang_ctx ctx = { set, self_copy, self, &write_pos, len };
struct ary_uniq_bang_ctx ctx = { set, self_copy, self, &write_pos };
mrb_value result;
MRB_ENSURE(mrb, result, ary_uniq_bang_body, &ctx) {
ary_destroy_temp_set(mrb, set);
}
}
else {
for (mrb_int read_pos = 0; read_pos < len; read_pos++) {
int ai = mrb_gc_arena_save(mrb);
for (mrb_int read_pos = 0; read_pos < RARRAY_LEN(self); read_pos++) {
mrb_value elem = RARRAY_PTR(self)[read_pos];
mrb_gc_protect(mrb, elem); // elem may be removed from self by mrb_equal()
mrb_bool found = FALSE;
for (mrb_int j = 0; j < write_pos; j++) {
for (mrb_int j = 0; j < write_pos && j < RARRAY_LEN(self); j++) {
if (mrb_equal(mrb, elem, RARRAY_PTR(self)[j])) {
found = TRUE;
break;
}
}
if (!found) {
if (write_pos != read_pos) {
if (write_pos != read_pos && write_pos < RARRAY_LEN(self)) {
mrb_ary_modify(mrb, mrb_ary_ptr(self));
RARRAY_PTR(self)[write_pos] = elem;
}
write_pos++;
}
mrb_gc_arena_restore(mrb, ai);
}
}
@@ -1373,6 +1415,13 @@ ary_insert(mrb_state *mrb, mrb_value self)
return self;
}
struct ary_product_generator {
mrb_int total;
mrb_int cursor;
};
static struct mrb_data_type ary_product_generator_type = { "ary_product_generator", mrb_free };
/*
* Internal helper for Array#product to construct a group array.
* Takes the base array (self), the array of other arrays (arys),
@@ -1380,29 +1429,85 @@ ary_insert(mrb_state *mrb, mrb_value self)
* of the group array (group_len).
*/
static mrb_value
ary_product_group(mrb_state *mrb, mrb_value self_ary)
ary_product_fetch(mrb_state *mrb, mrb_value self_ary, mrb_value arys_ary, mrb_int n)
{
mrb_value arys_ary;
mrb_int current_i, group_len;
mrb_get_args(mrb, "Aii", &arys_ary, &current_i, &group_len);
mrb_value group = mrb_ary_new_capa(mrb, group_len);
mrb_int j = RARRAY_LEN(arys_ary); // Corresponds to 'size' in Ruby
mrb_int n = current_i;
mrb_value group = mrb_ary_new_capa(mrb, j + 1 /* self_ary */);
while (j > 0) {
j -= 1;
while (j-- > 0) {
mrb_value a = RARRAY_PTR(arys_ary)[j]; // arys[j]
mrb_check_type(mrb, a, MRB_TT_ARRAY);
mrb_int b = RARRAY_LEN(a); // a.size
if (b <= 0) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "cannot compute product with an empty array");
}
mrb_ary_set(mrb, group, j + 1, RARRAY_PTR(a)[n % b]);
n /= b;
}
if (n >= RARRAY_LEN(self_ary)) {
mrb_raise(mrb, E_INDEX_ERROR, "index out of range");
}
mrb_ary_set(mrb, group, 0, RARRAY_PTR(self_ary)[n]);
return group;
}
static mrb_value
ary_product_generate(mrb_state *mrb, mrb_value self)
{
mrb_value arys_ary, block;
mrb_get_args(mrb, "A&", &arys_ary, &block);
mrb_int total = RARRAY_LEN(self);
for (mrb_int i = 0; i < RARRAY_LEN(arys_ary); i++) {
mrb_value a = RARRAY_PTR(arys_ary)[i];
mrb_check_type(mrb, a, MRB_TT_ARRAY);
mrb_int n = RARRAY_LEN(a);
if (n == 0) {
total = 0;
break;
}
if (mrb_int_mul_overflow(total, n, &total)) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "result too big");
}
}
if (mrb_nil_p(block)) {
mrb_value result = mrb_ary_new_capa(mrb, total);
for (mrb_int i = 0; i < total; i++) {
mrb_value group = ary_product_fetch(mrb, self, arys_ary, i);
mrb_ary_push(mrb, result, group);
}
return result;
}
else if (total > 0) {
struct RData *d;
struct ary_product_generator *g;
Data_Make_Struct(mrb, mrb->object_class, struct ary_product_generator,
&ary_product_generator_type, g, d);
g->total = total;
g->cursor = 0;
return mrb_obj_value(d);
}
else {
return mrb_nil_value();
}
}
static mrb_value
ary_product_next(mrb_state *mrb, mrb_value self)
{
mrb_value arys;
struct ary_product_generator *g;
mrb_get_args(mrb, "Ad", &arys, &g, &ary_product_generator_type);
if (g->cursor >= g->total) {
return mrb_nil_value();
}
return ary_product_fetch(mrb, self, arys, g->cursor++);
}
/*
* call-seq:
* ary.deconstruct -> ary
@@ -1563,7 +1668,8 @@ static const mrb_mt_entry array_ext_rom_entries[] = {
MRB_MT_ENTRY(ary_fetch, MRB_SYM(__fetch), MRB_ARGS_REQ(3)),
MRB_MT_ENTRY(ary_insert, MRB_SYM(insert), MRB_ARGS_ARG(1,-1)),
MRB_MT_ENTRY(ary_deconstruct, MRB_SYM(deconstruct), MRB_ARGS_NONE()),
MRB_MT_ENTRY(ary_product_group, MRB_SYM(__product_group), MRB_ARGS_REQ(3)),
MRB_MT_ENTRY(ary_product_generate, MRB_SYM(__product_generate), MRB_ARGS_REQ(1)),
MRB_MT_ENTRY(ary_product_next, MRB_SYM(__product_next), MRB_ARGS_REQ(2)),
MRB_MT_ENTRY(ary_combination_init, MRB_SYM(__combination_init), MRB_ARGS_REQ(2)),
MRB_MT_ENTRY(ary_combination_next, MRB_SYM(__combination_next), MRB_ARGS_REQ(1)),
};
+3 -3
View File
@@ -3260,7 +3260,7 @@ primary : literal
$<stack>$ = p->cmdarg_stack;
p->cmdarg_stack = 0;
}
stmt {p->lstate = EXPR_ENDARG;} rparen
compstmt {p->lstate = EXPR_ENDARG;} rparen
{
p->cmdarg_stack = $<stack>2;
$$ = $3;
@@ -4563,13 +4563,13 @@ f_label : tIDENTIFIER tLABEL_TAG
{
$$ = $1;
local_nest(p);
p->lstate = EXPR_ARG; /* make newlines significant after label */
p->lstate = EXPR_MID; /* make newlines significant after label */
}
| tNUMPARAM tLABEL_TAG
{
$$ = intern_numparam($1);
local_nest(p);
p->lstate = EXPR_ARG; /* make newlines significant after label */
p->lstate = EXPR_MID; /* make newlines significant after label */
}
;
File diff suppressed because it is too large Load Diff
+6 -5
View File
@@ -291,11 +291,12 @@ class Enumerator
#
def flat_map(&block)
Lazy.new(self){|yielder, val|
ary = block.call(val)
# TODO: check ary is an Array
ary.each {|x|
yielder << x
}
result = block.call(val)
if result.respond_to?(:each)
result.each {|x| yielder << x }
else
yielder << result
end
}
end
alias collect_concat flat_map
+12
View File
@@ -46,6 +46,18 @@ assert("Enumerator::Lazy#to_enum") do
assert_equal [0*1, 2*3, 4*5, 6*7], lazy_enum.map { |a| a.first * a.last }.first(4)
end
assert("Enumerator::Lazy#flat_map with array from block") do
assert_equal [1, 10, 2, 20, 3, 30], [1, 2, 3].lazy.flat_map {|x| [x, x*10]}.force
end
assert("Enumerator::Lazy#flat_map with non-enumerable from block") do
assert_equal [1, 2, 3], [1, 2, 3].lazy.flat_map {|x| x}.force
end
assert("Enumerator::Lazy#flat_map with nested array from block") do
assert_equal [[1, 2], [3, 4]], [1, 3].lazy.flat_map {|x| [[x, x+1]]}.force
end
assert("Enumerator::Lazy#grep_v") do
lazy_grep_v = (0..).lazy.grep_v(2..4)
assert_kind_of Enumerator::Lazy, lazy_grep_v
+1 -5
View File
@@ -190,11 +190,7 @@ int_powm(mrb_state *mrb, mrb_value x)
return mrb_int_pow(mrb, x, mrb_get_arg1(mrb));
}
mrb_get_args(mrb, "oo", &e, &m);
if (!mrb_integer_p(e)
#ifdef MRB_USE_BIGINT
&& !mrb_bigint_p(e)
#endif
) {
if (!mrb_integer_p(e) && !mrb_bigint_p(e)) {
mrb_raise(mrb, E_TYPE_ERROR, "int.pow(n,m): 2nd argument not allowed unless 1st argument is an integer");
}
#ifdef MRB_USE_BIGINT
+1 -3
View File
@@ -701,13 +701,11 @@ class UDPSocket < IPSocket
# data, addr = sock.recvfrom_nonblock(1024)
#
def recvfrom_nonblock(*args)
s = self
begin
self._setnonblock(true)
self.recvfrom(*args)
ensure
# XXX: self is a SystemcallException here! (should be bug)
s._setnonblock(false)
self._setnonblock(false)
end
end
+9 -3
View File
@@ -19,9 +19,11 @@ MRuby::Gem::Specification.new('mruby-test') do |spec|
file assert_c => [assert_rb, build.mrbcfile] do |t|
_pp "GEN", t.name.relative_path
mkdir_p File.dirname(t.name)
open(t.name, 'w') do |f|
tmpfile = t.name + ".tmp"
open(tmpfile, 'w') do |f|
mrbc.run f, assert_rb, 'mrbtest_assert_irep', cdump: false
end
File.rename(tmpfile, t.name)
end
gem_table = build.gems.generate_gem_table build
@@ -36,7 +38,8 @@ MRuby::Gem::Specification.new('mruby-test') do |spec|
file g.test_rbireps => [g.test_rbfiles, build.mrbcfile].flatten do |t|
_pp "GEN", t.name.relative_path
mkdir_p File.dirname(t.name)
open(t.name, 'w') do |f|
tmpfile = t.name + ".tmp"
open(tmpfile, 'w') do |f|
g.print_gem_test_header(f)
test_preload = g.test_preload and [g.dir, MRUBY_ROOT].map {|dir|
File.expand_path(g.test_preload, dir)
@@ -117,6 +120,7 @@ MRuby::Gem::Specification.new('mruby-test') do |spec|
end
f.puts %Q[}]
end
File.rename(tmpfile, t.name)
end
end
@@ -134,7 +138,8 @@ MRuby::Gem::Specification.new('mruby-test') do |spec|
file clib => ["#{build.build_dir}/mrbgems/active_gems.txt", build.mrbcfile, __FILE__] do |_t|
_pp "GEN", clib.relative_path
mkdir_p File.dirname(clib)
open(clib, 'w') do |f|
tmpfile = clib + ".tmp"
open(tmpfile, 'w') do |f|
f.puts %Q[/*]
f.puts %Q[ * This file contains a list of all]
f.puts %Q[ * test functions.]
@@ -169,5 +174,6 @@ MRuby::Gem::Specification.new('mruby-test') do |spec|
end
f.puts %Q[}]
end
File.rename(tmpfile, clib)
end
end
+4 -3
View File
@@ -2748,7 +2748,7 @@ prepare_writer_name(mrb_state *mrb, mrb_sym sym)
}
static mrb_value
mod_attr_define(mrb_state *mrb, mrb_value mod, mrb_value (*accessor)(mrb_state*, mrb_value), mrb_sym (*access_name)(mrb_state*, mrb_sym))
mod_attr_define(mrb_state *mrb, mrb_value mod, mrb_int aargc, mrb_value (*accessor)(mrb_state*, mrb_value), mrb_sym (*access_name)(mrb_state*, mrb_sym))
{
struct RClass *c = mrb_class_ptr(mod);
const mrb_value *argv;
@@ -2765,6 +2765,7 @@ mod_attr_define(mrb_state *mrb, mrb_value mod, mrb_value (*accessor)(mrb_state*,
}
struct RProc *p = mrb_proc_new_cfunc_with_env(mrb, accessor, 1, &name);
p->flags |= aargc == 0 ? MRB_PROC_NOARG : 0;
mrb_method_t m;
MRB_METHOD_FROM_PROC(m, p);
mrb_define_method_raw(mrb, c, method, m);
@@ -2783,7 +2784,7 @@ attr_reader(mrb_state *mrb, mrb_value obj)
static mrb_value
mrb_mod_attr_reader(mrb_state *mrb, mrb_value mod)
{
return mod_attr_define(mrb, mod, attr_reader, NULL);
return mod_attr_define(mrb, mod, 0, attr_reader, NULL);
}
static mrb_value
@@ -2799,7 +2800,7 @@ attr_writer(mrb_state *mrb, mrb_value obj)
static mrb_value
mrb_mod_attr_writer(mrb_state *mrb, mrb_value mod)
{
return mod_attr_define(mrb, mod, attr_writer, prepare_writer_name);
return mod_attr_define(mrb, mod, 1, attr_writer, prepare_writer_name);
}
static mrb_value
+6 -6
View File
@@ -541,15 +541,15 @@ mrb_gc_unregister(mrb_state *mrb, mrb_value obj)
if (!mrb_array_p(table)) return;
struct RArray *a = mrb_ary_ptr(table);
mrb_ary_modify(mrb, a);
mrb_int len = ARY_LEN(a)-1;
mrb_int len = ARY_LEN(a);
mrb_value *ptr = ARY_PTR(a);
for (mrb_int i = 0; i <= len; i++) {
if (mrb_ptr(ptr[i]) == mrb_ptr(obj)) {
ARY_SET_LEN(a, len);
memmove(&ptr[i], &ptr[i + 1], (len - i) * sizeof(mrb_value));
break;
mrb_int w = 0;
for (mrb_int r = 0; r < len; r++) {
if (mrb_ptr(ptr[r]) != mrb_ptr(obj)) {
ptr[w++] = ptr[r];
}
}
ARY_SET_LEN(a, w);
}
MRB_API struct RBasic*
+1 -5
View File
@@ -432,11 +432,7 @@ mrb_get_values_at(mrb_state *mrb, mrb_value obj, mrb_int olen, mrb_int argc, con
for (mrb_int i = 0; i < argc; i++) {
mrb_value v = argv[i];
if (mrb_integer_p(v)
#ifdef MRB_USE_BIGINT
|| mrb_bigint_p(v)
#endif
) {
if (mrb_integer_p(v) || mrb_bigint_p(v)) {
mrb_int i = mrb_as_int(mrb, v);
mrb_ary_push(mrb, result, func(mrb, obj, i));
}
+20 -9
View File
@@ -134,19 +134,29 @@ static inline void
envadjust(mrb_state *mrb, mrb_value *oldbase, mrb_value *newbase)
{
mrb_callinfo *ci = mrb->c->cibase;
ptrdiff_t delta = newbase - oldbase;
/*
* Byte-level calculation to avoid truncation when allocator alignment is
* smaller than sizeof(mrb_value).
* eg: MRB_NO_BOXING + MRB_INT64 with MRB_32BIT => sizeof(mrb_value)=16
* And when memory allocator's alignment is 8 bytes
* Pointer subtraction on mrb_value* would truncate (8/16 -> 0).
* So, we use char* for pointer calculation to get the correct offset in bytes,
* then apply that offset to mrb_value* pointers.
*/
ptrdiff_t off = (char *)newbase - (char *)oldbase;
if (delta == 0) return;
if (off == 0) return;
while (ci <= mrb->c->ci) {
struct REnv *e = mrb_vm_ci_env(ci);
mrb_value *new_stack = (mrb_value *)((char *)ci->stack + off);
if (e) {
mrb_assert(e->cxt == mrb->c && MRB_ENV_ONSTACK_P(e));
mrb_assert(e->stack == ci->stack);
e->stack += delta;
e->stack = new_stack;
}
ci->stack += delta;
ci->stack = new_stack;
ci++;
}
}
@@ -2703,11 +2713,10 @@ RETRY_TRY_BLOCK:
if (kidx < 0 || !mrb_hash_p(kdict=regs[kidx]) || !mrb_hash_key_p(mrb, kdict, k)) {
RAISE_FORMAT(mrb, E_ARGUMENT_ERROR, "missing keyword: %v", k);
}
v = mrb_hash_get(mrb, kdict, k);
v = mrb_hash_delete_key(mrb, kdict, k);
ci = mrb->c->ci;
regs[a] = v;
mrb_hash_delete_key(mrb, kdict, k);
ci = mrb->c->ci;
NEXT;
}
@@ -3113,7 +3122,9 @@ RETRY_TRY_BLOCK:
{ \
mrb_value arg = mrb_int_value(mrb, c); \
mrb_sym mid = MRB_OPSYM(op_name); \
regs[a] = mrb_funcall_argv(mrb, regs[a], mid, 1, &arg); \
mrb_value v = mrb_funcall_argv(mrb, regs[a], mid, 1, &arg); \
ci = mrb->c->ci; \
regs[a] = v; \
mrb_gc_arena_restore(mrb, ai); \
} \
break; \
+17 -2
View File
@@ -29,7 +29,7 @@ MRuby.each_target do |build|
end
end
file presym.list_path => ppps do
presym_task = file presym.list_path => ppps do
presyms = presym.scan(ppps)
current_presyms = presym.read_list if File.exist?(presym.list_path)
if presyms != current_presyms
@@ -41,6 +41,21 @@ MRuby.each_target do |build|
end
end
# Don't directly write dependency tasks in the "task" arguments.
# The rake system tracks dependencies recursively
# (see Rake::Task#all_prerequisite_tasks and #collect_prerequisites).
# Therefore, indirect dependencies from ".o" to ".pi" must be eliminated.
# ref. https://github.com/mruby/mruby/issues/6721
# This task acts a proxy-like for the "presym.list_path" task.
presym_proxy = task "gensym:update:#{build.name}" do
presym_task.invoke
end
# Override the "timestamp" method to reflect the presym file.
presym_proxy.define_singleton_method :timestamp do
presym_task.timestamp
end
# Ensure .o files depend on presym headers being generated.
# This is critical when a build's .o files are compiled during another
# build's presym scanning chain (before :gensym completes), e.g.:
@@ -50,7 +65,7 @@ MRuby.each_target do |build|
next unless File.extname(prereq) == build.exts.object
next unless prereq.start_with?(build_dir)
next if mrbc_build_dir && prereq.start_with?(mrbc_build_dir)
file prereq => presym.list_path
file prereq => presym_proxy
end
task gensym: presym.list_path
+3
View File
@@ -163,6 +163,9 @@ assert('Module#attr_reader', '15.2.2.4.13') do
AttrTestReader.cattr_val = 'test'
assert_equal 'test', AttrTestReader.cattr
assert_raise(ArgumentError) { attr_instance.iattr(1) }
assert_raise(ArgumentError) { attr_instance.iattr(1, 2, 3) }
end
assert('Module#attr_writer', '15.2.2.4.14') do
+14
View File
@@ -680,6 +680,20 @@ assert 'keyword arguments' do
assert_equal [{a: 1}, {b: 2}], m({a: 1}, b: 2)
assert_raise(ArgumentError) { m({a: 1}, {b: 2}) }
def m1(a: {}) a end
assert_equal({}, m1)
assert_equal(:abc, m1(a: :abc))
def m2(a: +1) a end
assert_equal(1, m2)
assert_nothing_raised do
def m3 arg:
123
end
end
assert_equal(123, m3(arg: 456))
def m(*, a:) a end
assert_equal 1, m(a: 1)
assert_equal 3, m(1, 2, a: 3)