From 84437df8a794f317bcc7a59990329d3ce260b5da Mon Sep 17 00:00:00 2001 From: salano_ym <53254905+salano-ym@users.noreply.github.com> Date: Thu, 11 Apr 2024 14:27:37 +0000 Subject: [PATCH 1/4] arr.flat --- CHANGELOG.md | 1 + docs/primitive-props.md | 4 ++++ src/interpreter/primitive-props.ts | 25 ++++++++++++++++++++++++- test/index.ts | 23 +++++++++++++++++++++++ 4 files changed, 52 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 89464f88..464836ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - `Date:millisecond`を追加 - `arr.fill`, `arr.repeat`, `Arr:create`を追加 - JavaScriptのように分割代入ができるように(現段階では機能は最小限) +- `arr.flat`を追加 # 0.17.0 - `package.json`を修正 diff --git a/docs/primitive-props.md b/docs/primitive-props.md index 0c9c2919..db3d73e4 100644 --- a/docs/primitive-props.md +++ b/docs/primitive-props.md @@ -184,6 +184,10 @@ _fromIndex_ および _toIndex_ に関する挙動は`arr.slice`に準拠しま `arr.copy`同様シャローコピーであり、配列やオブジェクトの参照は維持されます。 _times_ には0以上の整数値を指定します。それ以外ではエラーになります。 +### @(_v_: arr).flat(_depth_: num): arr +配列に含まれる配列を _depth_ で指定した深さの階層まで結合した新しい配列を作成します。 +_depth_ には0以上の整数値を指定します。省略時は1になります。 + ## エラー型 ### #(_v_: error).name 型: `str` diff --git a/src/interpreter/primitive-props.ts b/src/interpreter/primitive-props.ts index 911313ac..8a2cdb81 100644 --- a/src/interpreter/primitive-props.ts +++ b/src/interpreter/primitive-props.ts @@ -2,7 +2,7 @@ import { substring, length, indexOf, toArray } from 'stringz'; import { AiScriptRuntimeError } from '../error.js'; import { textEncoder } from '../const.js'; -import { assertArray, assertBoolean, assertFunction, assertNumber, assertString, expectAny, eq } from './util.js'; +import { assertArray, assertBoolean, assertFunction, assertNumber, assertString, expectAny, eq, isArray } from './util.js'; import { ARR, FALSE, FN_NATIVE, NULL, NUM, STR, TRUE } from './value.js'; import type { Value, VArr, VFn, VNum, VStr, VError } from './value.js'; @@ -279,6 +279,29 @@ const PRIMITIVE_PROPS: { throw e; } }), + + flat: (target: VArr): VFn => FN_NATIVE(async ([depth], opts) => { + depth = depth ?? NUM(1); + assertNumber(depth); + if (!Number.isInteger(depth.value)) throw new AiScriptRuntimeError('arr.flat expected integer, got non-integer'); + if (depth.value < 0) throw new AiScriptRuntimeError('arr.flat expected non-negative number, got negative'); + const flat = (arr: Value[], depth: number, result: Value[]) => { + if (depth === 0) { + result.push(...arr); + return; + } + for (const v of arr) { + if (isArray(v)) { + flat(v.value, depth - 1, result); + } else { + result.push(v); + } + } + }; + const result: Value[] = []; + flat(target.value, depth.value, result); + return ARR(result); + }), }, error: { diff --git a/test/index.ts b/test/index.ts index 5d4634e9..bb60464c 100644 --- a/test/index.ts +++ b/test/index.ts @@ -2849,6 +2849,29 @@ describe('primitive props', () => { ARR([]), ])); }); + + test.concurrent('flat', async () => { + const res = await exe(` + var arr1 = [0, [1], [2, 3], [4, [5, 6]]] + let arr2 = arr1.flat() + let arr3 = arr1.flat(2) + <: [arr1, arr2, arr3] + `); + eq(res, ARR([ + ARR([ + NUM(0), ARR([NUM(1)]), ARR([NUM(2), NUM(3)]), + ARR([NUM(4), ARR([NUM(5), NUM(6)])]) + ]), // target not changed + ARR([ + NUM(0), NUM(1), NUM(2), NUM(3), + NUM(4), ARR([NUM(5), NUM(6)]), + ]), + ARR([ + NUM(0), NUM(1), NUM(2), NUM(3), + NUM(4), NUM(5), NUM(6), + ]), + ])); + }); }); }); From 19d3d9f0372a9982df6145d3a5d160ab65d5fa55 Mon Sep 17 00:00:00 2001 From: salano_ym <53254905+salano-ym@users.noreply.github.com> Date: Thu, 11 Apr 2024 15:26:08 +0000 Subject: [PATCH 2/4] =?UTF-8?q?arr.flat=5Fmap=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 2 +- docs/primitive-props.md | 4 ++++ src/interpreter/primitive-props.ts | 10 ++++++++++ test/index.ts | 20 ++++++++++++++++++++ 4 files changed, 35 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 464836ad..61aac3b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ - `Date:millisecond`を追加 - `arr.fill`, `arr.repeat`, `Arr:create`を追加 - JavaScriptのように分割代入ができるように(現段階では機能は最小限) -- `arr.flat`を追加 +- `arr.flat`,`arr.flat_map`を追加 # 0.17.0 - `package.json`を修正 diff --git a/docs/primitive-props.md b/docs/primitive-props.md index db3d73e4..b993b1f0 100644 --- a/docs/primitive-props.md +++ b/docs/primitive-props.md @@ -188,6 +188,10 @@ _times_ には0以上の整数値を指定します。それ以外ではエラ 配列に含まれる配列を _depth_ で指定した深さの階層まで結合した新しい配列を作成します。 _depth_ には0以上の整数値を指定します。省略時は1になります。 +### @(_v_: arr).flat_map(_func_: @(_item_: value, _index_: num) { value }): arr +配列の各要素を _func_ の返り値で置き換えた後、1階層平坦化した新しい配列を作成します。 +_func_ は非同期的に呼び出されます。 + ## エラー型 ### #(_v_: error).name 型: `str` diff --git a/src/interpreter/primitive-props.ts b/src/interpreter/primitive-props.ts index 8a2cdb81..920d0853 100644 --- a/src/interpreter/primitive-props.ts +++ b/src/interpreter/primitive-props.ts @@ -302,6 +302,16 @@ const PRIMITIVE_PROPS: { flat(target.value, depth.value, result); return ARR(result); }), + + flat_map: (target: VArr): VFn => FN_NATIVE(async ([fn], opts) => { + assertFunction(fn); + const vals = target.value.map(async (item, i) => { + const result = await opts.call(fn, [item, NUM(i)]); + return isArray(result) ? result.value : result; + }); + const mapped_vals = await Promise.all(vals); + return ARR(mapped_vals.flat()); + }), }, error: { diff --git a/test/index.ts b/test/index.ts index bb60464c..962a34d9 100644 --- a/test/index.ts +++ b/test/index.ts @@ -2872,6 +2872,26 @@ describe('primitive props', () => { ]), ])); }); + + test.concurrent('flat_map', async () => { + const res = await exe(` + let arr1 = [0, 1, 2] + let arr2 = ["a", "b"] + let arr3 = arr1.flat_map(@(x){ arr2.map(@(y){ [x, y] }) }) + <: [arr1, arr3] + `); + eq(res, ARR([ + ARR([NUM(0), NUM(1), NUM(2)]), // target not changed + ARR([ + ARR([NUM(0), STR("a")]), + ARR([NUM(0), STR("b")]), + ARR([NUM(1), STR("a")]), + ARR([NUM(1), STR("b")]), + ARR([NUM(2), STR("a")]), + ARR([NUM(2), STR("b")]), + ]), + ])); + }); }); }); From 35d7e7ff3f6a67a0a1f6282179706e7c8907237b Mon Sep 17 00:00:00 2001 From: salano_ym <53254905+salano-ym@users.noreply.github.com> Date: Thu, 11 Apr 2024 18:21:46 +0000 Subject: [PATCH 3/4] =?UTF-8?q?doc=E4=BF=AE=E6=AD=A3(arr.flat)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/primitive-props.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/primitive-props.md b/docs/primitive-props.md index b993b1f0..438160e9 100644 --- a/docs/primitive-props.md +++ b/docs/primitive-props.md @@ -184,7 +184,7 @@ _fromIndex_ および _toIndex_ に関する挙動は`arr.slice`に準拠しま `arr.copy`同様シャローコピーであり、配列やオブジェクトの参照は維持されます。 _times_ には0以上の整数値を指定します。それ以外ではエラーになります。 -### @(_v_: arr).flat(_depth_: num): arr +### @(_v_: arr).flat(_depth_?: num): arr 配列に含まれる配列を _depth_ で指定した深さの階層まで結合した新しい配列を作成します。 _depth_ には0以上の整数値を指定します。省略時は1になります。 From a402ab44094f14d16640120be55b19e7e25d14ad Mon Sep 17 00:00:00 2001 From: salano_ym <53254905+salano-ym@users.noreply.github.com> Date: Thu, 25 Apr 2024 16:55:29 +0000 Subject: [PATCH 4/4] fix CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e88625cd..d0f1b4b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ [Read translated version (en)](./translations/en/CHANGELOG.md) # 未リリース分 +- `arr.flat`,`arr.flat_map`を追加 # 0.18.0 - `Core:abort`でプログラムを緊急停止できるように @@ -14,7 +15,6 @@ - ネストされた名前空間下の変数を参照できるように - `arr.every`, `arr.some`を追加 - `Date:to_iso_str`を追加 -- `arr.flat`,`arr.flat_map`を追加 # 0.17.0 - `package.json`を修正