mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
Compare commits
43 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3a5c45f282 | |||
| ac9f7aedd2 | |||
| 919cbd8fea | |||
| 801eefeab6 | |||
| 8f71887e46 | |||
| 3f52ef6cfc | |||
| 28c5b1b17b | |||
| d50932c50f | |||
| b7e3743130 | |||
| 805e6dbc33 | |||
| e8c5e7c0cd | |||
| ab249864cc | |||
| c2b588139f | |||
| 21dc829903 | |||
| 6c4a8c09db | |||
| c52faebb7f | |||
| f61ab96689 | |||
| 07a6c6e56b | |||
| 45ebb3d0c8 | |||
| 2135088ada | |||
| 04f998238e | |||
| affcbb000b | |||
| ff5e6a2491 | |||
| e8d0750458 | |||
| 88e356e7da | |||
| 95ece95e37 | |||
| 98d763603c | |||
| 01ce2f8c71 | |||
| f08dede1d9 | |||
| 3bfe703f80 | |||
| e82fa70004 | |||
| 8d53f65b96 | |||
| c0b1e87c09 | |||
| 8441eaf633 | |||
| 736a72cdc9 | |||
| 5e9eed2d0c | |||
| 80d84188fd | |||
| 55ef8e1728 | |||
| 13d9d770fc | |||
| a41eeaed33 | |||
| 4ed4326dd5 | |||
| 000acedc35 | |||
| 14e98c60c3 |
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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: |
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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.11
|
||||
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
|
||||
|
||||
@@ -23,6 +23,8 @@ mruby now supports pattern matching (case/in) syntax:
|
||||
- Trailing comma in method definition parameters: `def foo(a, b,)` ([f78334b](https://github.com/mruby/mruby/commit/f78334b))
|
||||
- Array/Hash/String subclasses can now override `[]` and `[]=` methods ([#6675](https://github.com/mruby/mruby/pull/6675))
|
||||
- `OP_SETIDX` optimization for Array and Hash ([ddd8fe1](https://github.com/mruby/mruby/commit/ddd8fe1))
|
||||
- `case`/`in` without `else` now raises `NoMatchingPatternError` ([d8de35b](https://github.com/mruby/mruby/commit/d8de35b))
|
||||
- Allow compound statement in parenthesized argument context ([919cbd8](https://github.com/mruby/mruby/commit/919cbd8))
|
||||
|
||||
# Changes in C API
|
||||
|
||||
@@ -37,6 +39,8 @@ mruby now supports pattern matching (case/in) syntax:
|
||||
- `mrb_open()` returns mrb_state with exc set on init failure ([05ffe0c](https://github.com/mruby/mruby/commit/05ffe0c))
|
||||
- `mrb_utf8_to_buf()` for UTF-8 encoding consolidation ([7e28e68](https://github.com/mruby/mruby/commit/7e28e68))
|
||||
- `kh_is_end()` macro for safe khash iteration ([893cc75](https://github.com/mruby/mruby/commit/893cc75))
|
||||
- `mrb_bigint_p()` always defined regardless of bigint gem presence ([6c4a8c0](https://github.com/mruby/mruby/commit/6c4a8c0))
|
||||
- `RInteger` and `RFloat` added to `RVALUE` union ([13dbca0](https://github.com/mruby/mruby/commit/13dbca0))
|
||||
|
||||
# ROM Method Tables
|
||||
|
||||
@@ -76,6 +80,7 @@ mruby-symbol-ext, mruby-range-ext, mruby-object-ext.
|
||||
- Emscripten: use native WASM exception handling ([ca364e3](https://github.com/mruby/mruby/commit/ca364e3))
|
||||
- HAL (Hardware Abstraction Layer) for platform abstraction in mruby-io, mruby-socket, mruby-dir, mruby-task ([74ca22f](https://github.com/mruby/mruby/commit/74ca22f))
|
||||
- `MRUBY_MIRB_READLINE` environment variable to control readline library selection ([0aafb83](https://github.com/mruby/mruby/commit/0aafb83))
|
||||
- MSYS2 drive letter support in build script ([77f6ffe](https://github.com/mruby/mruby/commit/77f6ffe))
|
||||
- Inter-gem headers separated from external API headers ([#6671](https://github.com/mruby/mruby/pull/6671))
|
||||
|
||||
# Changes in mrbgems
|
||||
@@ -110,6 +115,7 @@ mruby-symbol-ext, mruby-range-ext, mruby-object-ext.
|
||||
## Other Gem Changes
|
||||
|
||||
- **_NOTE_**: `Hash#deconstruct_keys` removed for CRuby compatibility ([34b9412](https://github.com/mruby/mruby/commit/34b9412))
|
||||
- **mruby-enum-lazy**: Fix `Lazy#flat_map` to handle non-enumerable block return values ([#6765](https://github.com/mruby/mruby/pull/6765))
|
||||
- **mruby-array-ext**: Add `Array#find` and `Array#rfind` methods
|
||||
- **mruby-io**: Add `IO#putc` and `Kernel#putc` ([baff6e6](https://github.com/mruby/mruby/commit/baff6e6))
|
||||
- **mruby-random**: Replace xoshiro with PCG for better memory efficiency ([f1bab01](https://github.com/mruby/mruby/commit/f1bab01))
|
||||
@@ -125,6 +131,8 @@ mruby-symbol-ext, mruby-range-ext, mruby-object-ext.
|
||||
- Optimized masgn to generate literals directly into target registers ([fb5d966](https://github.com/mruby/mruby/commit/fb5d966))
|
||||
- Optimized splat of literal arrays in args/literals ([1cb8d73](https://github.com/mruby/mruby/commit/1cb8d73))
|
||||
- Early termination after too many parse errors ([510ebd7](https://github.com/mruby/mruby/commit/510ebd7))
|
||||
- Chunk array literals at 64 elements to reduce register pressure ([f98d641](https://github.com/mruby/mruby/commit/f98d641))
|
||||
- Chunk `%w()` and `%i()` literals to reduce register pressure ([62cf0dc](https://github.com/mruby/mruby/commit/62cf0dc))
|
||||
|
||||
# VM Optimizations
|
||||
|
||||
@@ -185,6 +193,10 @@ Other optimizations:
|
||||
- [#6705](https://github.com/mruby/mruby/issues/6705) Can't get outer class of an object in C
|
||||
- [#6713](https://github.com/mruby/mruby/issues/6713) mruby-polarssl not work
|
||||
- [#6720](https://github.com/mruby/mruby/issues/6720) Random float range: different behavior from CRuby
|
||||
- [#6722](https://github.com/mruby/mruby/issues/6722) RBreak size overflow on 32-bit platforms with MRB_NO_BOXING
|
||||
- [#6740](https://github.com/mruby/mruby/issues/6740) `%w()`/`%i()` register pressure with large literals
|
||||
- [#6741](https://github.com/mruby/mruby/issues/6741) `case`/`in` without `else` should raise `NoMatchingPatternError`
|
||||
- [#6760](https://github.com/mruby/mruby/issues/6760) `mrb_gc_unregister()` not removing all matching entries
|
||||
|
||||
# Merged Pull Requests
|
||||
|
||||
@@ -260,6 +272,7 @@ Other optimizations:
|
||||
- [#6589](https://github.com/mruby/mruby/pull/6589) Add pre-commit hook `check-zip-file-is-not-committed`
|
||||
- [#6591](https://github.com/mruby/mruby/pull/6591) mruby-eval fix license link in README
|
||||
- [#6593](https://github.com/mruby/mruby/pull/6593) README: Add Contributors Avatars, Star History, Table of Contents
|
||||
- [#6598](https://github.com/mruby/mruby/pull/6598) Fix heap buffer overflow in `#method_missing`
|
||||
- [#6599](https://github.com/mruby/mruby/pull/6599) pre-commit: run `markdown-link-check`, `oxipng`, `prettier` manually
|
||||
- [#6600](https://github.com/mruby/mruby/pull/6600) `dreamcast_shelf build config`: update to use KallistiOS wrappers
|
||||
- [#6601](https://github.com/mruby/mruby/pull/6601) fix: skip local build_config.rb when working in MRUBY_ROOT
|
||||
@@ -303,6 +316,30 @@ Other optimizations:
|
||||
- [#6716](https://github.com/mruby/mruby/pull/6716) Fixes identity for proc object
|
||||
- [#6717](https://github.com/mruby/mruby/pull/6717) Fix mruby-task: wrapping by critical section and setting initial task receiver
|
||||
- [#6718](https://github.com/mruby/mruby/pull/6718) Add installation instructions for conda and Homebrew
|
||||
- [#6723](https://github.com/mruby/mruby/pull/6723) Add `RInteger` and `RFloat` to `RVALUE`
|
||||
- [#6727](https://github.com/mruby/mruby/pull/6727) Language documentation: update wording of "overloading" section
|
||||
- [#6729](https://github.com/mruby/mruby/pull/6729) Simplifying dependency addition for gensym task
|
||||
- [#6730](https://github.com/mruby/mruby/pull/6730) Simplifying presym file generation actions
|
||||
- [#6733](https://github.com/mruby/mruby/pull/6733) Include `mruby/presym.h` for all source files
|
||||
- [#6734](https://github.com/mruby/mruby/pull/6734) Chunk array literals at 64 elements to reduce register pressure
|
||||
- [#6735](https://github.com/mruby/mruby/pull/6735) Prevent full recompilation without changes to presym file
|
||||
- [#6739](https://github.com/mruby/mruby/pull/6739) Fix MSYS2 build error with drive letters
|
||||
- [#6743](https://github.com/mruby/mruby/pull/6743) Chunk `%w()` and `%i()` literals to reduce register pressure
|
||||
- [#6744](https://github.com/mruby/mruby/pull/6744) Raise `NoMatchingPatternError` in `case`/`in` without `else`
|
||||
- [#6747](https://github.com/mruby/mruby/pull/6747) Correctly handle empty hash as default named argument
|
||||
- [#6749](https://github.com/mruby/mruby/pull/6749) Fix microcontroller profile
|
||||
- [#6750](https://github.com/mruby/mruby/pull/6750) Fix out-of-bounds read and divide-by-zero in `Array#product`
|
||||
- [#6752](https://github.com/mruby/mruby/pull/6752) Fix `attr_reader`-generated methods accepting extra arguments
|
||||
- [#6753](https://github.com/mruby/mruby/pull/6753) Further optimize `Array#product`
|
||||
- [#6754](https://github.com/mruby/mruby/pull/6754) Mark `attr_reader` procs as noarg
|
||||
- [#6755](https://github.com/mruby/mruby/pull/6755) Reload `ci` after `mrb_hash_delete_key()` in keyword argument handling
|
||||
- [#6756](https://github.com/mruby/mruby/pull/6756) Avoid impact of object modifications caused by `mrb_vm_exec()` calls
|
||||
- [#6758](https://github.com/mruby/mruby/pull/6758) Don't assign result of `mrb_funcall()` directly to `regs`
|
||||
- [#6759](https://github.com/mruby/mruby/pull/6759) Define `mrb_bigint_p()` always
|
||||
- [#6761](https://github.com/mruby/mruby/pull/6761) Fix `mrb_gc_unregister()` to remove all matching entries
|
||||
- [#6762](https://github.com/mruby/mruby/pull/6762) Write generated test C files atomically to avoid build race condition
|
||||
- [#6765](https://github.com/mruby/mruby/pull/6765) Fix `Lazy#flat_map` to handle non-enumerable block return values
|
||||
- [#6767](https://github.com/mruby/mruby/pull/6767) Allow compound statement in parenthesized argument context
|
||||
|
||||
# Security Fixes
|
||||
|
||||
@@ -320,4 +357,6 @@ Other optimizations:
|
||||
- Heap-use-after-free in insertion_sort ([099d2c47](https://github.com/mruby/mruby/commit/099d2c47))
|
||||
- Integer overflow in str_check_length ([6afff1c3](https://github.com/mruby/mruby/commit/6afff1c3))
|
||||
- Integer overflow in Integer#lcm ([070bef24](https://github.com/mruby/mruby/commit/070bef24))
|
||||
- Heap buffer overflow in `#method_missing` ([550d10a](https://github.com/mruby/mruby/commit/550d10a))
|
||||
- Out-of-bounds read and divide-by-zero in `Array#product` ([8441eaf](https://github.com/mruby/mruby/commit/8441eaf))
|
||||
- Multiple memory leak fixes in bigint, Set, Array, and Task gems
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
|
||||
##
|
||||
|
||||
@@ -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, ¤t_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)),
|
||||
};
|
||||
|
||||
@@ -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 */
|
||||
}
|
||||
;
|
||||
|
||||
|
||||
+2618
-2588
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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));
|
||||
}
|
||||
|
||||
@@ -2703,11 +2703,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 +3112,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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user