diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e87821e..73bb875f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ - JavaScriptのように分割代入ができるように(現段階では機能は最小限) - スコープおよび名前が同一である変数が宣言された際のエラーメッセージを修正 - ネストされた名前空間下の変数を参照できるように +- `arr.every`, `arr.some`を追加 # 0.17.0 - `package.json`を修正 diff --git a/docs/primitive-props.md b/docs/primitive-props.md index 0c9c2919..609cc6ee 100644 --- a/docs/primitive-props.md +++ b/docs/primitive-props.md @@ -184,6 +184,12 @@ _fromIndex_ および _toIndex_ に関する挙動は`arr.slice`に準拠しま `arr.copy`同様シャローコピーであり、配列やオブジェクトの参照は維持されます。 _times_ には0以上の整数値を指定します。それ以外ではエラーになります。 +### @(_v_: arr).every(_func_: @(_item_: value, _index_: num) { bool }): bool +配列の全ての要素に対して _func_ が true を返す時のみ true 返します。空配列には常に true を返します。 + +### @(_v_: arr).some(_func_: @(_item_: value, _index_: num) { bool }): bool +配列の要素に対して _func_ が true を返す要素が存在する時のみ true 返します。 + ## エラー型 ### #(_v_: error).name 型: `str` diff --git a/src/interpreter/primitive-props.ts b/src/interpreter/primitive-props.ts index 911313ac..c154c45a 100644 --- a/src/interpreter/primitive-props.ts +++ b/src/interpreter/primitive-props.ts @@ -279,6 +279,28 @@ const PRIMITIVE_PROPS: { throw e; } }), + + every: (target: VArr): VFn => FN_NATIVE(async ([fn], opts) => { + assertFunction(fn); + for (let i = 0; i < target.value.length; i++) { + const item = target.value[i]!; + const res = await opts.call(fn, [item, NUM(i)]); + assertBoolean(res); + if (!res.value) return FALSE; + } + return TRUE; + }), + + some: (target: VArr): VFn => FN_NATIVE(async ([fn], opts) => { + assertFunction(fn); + for (let i = 0; i < target.value.length; i++) { + const item = target.value[i]!; + const res = await opts.call(fn, [item, NUM(i)]); + assertBoolean(res); + if (res.value) return TRUE; + } + return FALSE; + }), }, error: { diff --git a/test/index.ts b/test/index.ts index dd3121bf..c28f41f2 100644 --- a/test/index.ts +++ b/test/index.ts @@ -2876,6 +2876,36 @@ describe('primitive props', () => { ARR([]), ])); }); + + test.concurrent('every', async () => { + const res = await exe(` + let arr1 = [0, 1, 2, 3] + let res1 = arr1.every(@(v,i){v==0 || i > 0}) + let res2 = arr1.every(@(v,i){v==0 && i > 0}) + let res3 = [].every(@(v,i){false}) + <: [arr1, res1, res2, res3] + `); + eq(res, ARR([ + ARR([NUM(0), NUM(1), NUM(2), NUM(3)]), // target not changed + TRUE, + FALSE, + TRUE, + ])); + }); + + test.concurrent('some', async () => { + const res = await exe(` + let arr1 = [0, 1, 2, 3] + let res1 = arr1.some(@(v,i){v%2==0 && i <= 2}) + let res2 = arr1.some(@(v,i){v%2==0 && i > 2}) + <: [arr1, res1, res2] + `); + eq(res, ARR([ + ARR([NUM(0), NUM(1), NUM(2), NUM(3)]), // target not changed + TRUE, + FALSE, + ])); + }); }); });