diff --git a/CHANGELOG.md b/CHANGELOG.md index 85af36fa..65815163 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ - `arr.flat`,`arr.flat_map`を追加 - `Uri:encode_full`, `Uri:encode_component`, `Uri:decode_full`, `Uri:decode_component`を追加 - `str.starts_with`,`str.ends_with`を追加 +- `arr.splice`を追加 # 0.18.0 - `Core:abort`でプログラムを緊急停止できるように diff --git a/docs/primitive-props.md b/docs/primitive-props.md index 37fb6b05..25b42f01 100644 --- a/docs/primitive-props.md +++ b/docs/primitive-props.md @@ -210,6 +210,15 @@ _fromIndex_ および _toIndex_ に関する挙動は`arr.slice`に準拠しま `arr.copy`同様シャローコピーであり、配列やオブジェクトの参照は維持されます。 _times_ には0以上の整数値を指定します。それ以外ではエラーになります。 +### @(_v_: arr).splice(_index_: num, _remove_count_?: num, _items_?: arr\): arr\ +**【この操作は配列を書き換えます】** +配列の _index_ から _remove_count_ 個の要素を取り除き、その位置に _items_ の要素を挿入します。 +返り値として、取り除いた要素の配列を返します。\ +_index_ が負の場合は末尾から数えます。\ +_index_ が最後の要素より後の場合は要素を取り除かず、挿入は末尾に追加します。\ +_remove_count_ を省略した場合、末尾まで取り除きます。\ +_items_ を省略した場合、何も挿入しません。 + ### @(_v_: arr).flat(_depth_?: num): arr 配列に含まれる配列を _depth_ で指定した深さの階層まで結合した新しい配列を作成します。 _depth_ には0以上の整数値を指定します。省略時は1になります。 diff --git a/src/interpreter/primitive-props.ts b/src/interpreter/primitive-props.ts index 2ec7476a..9c25f7cf 100644 --- a/src/interpreter/primitive-props.ts +++ b/src/interpreter/primitive-props.ts @@ -326,6 +326,22 @@ const PRIMITIVE_PROPS: { throw e; } }), + + splice: (target: VArr): VFn => FN_NATIVE(async ([idx, rc, vs], opts) => { + assertNumber(idx); + const index = (idx.value < -target.value.length) ? 0 + : (idx.value < 0) ? target.value.length + idx.value + : (idx.value >= target.value.length) ? target.value.length + : idx.value; + + const remove_count = (rc != null) ? (assertNumber(rc), rc.value) + : target.value.length - index; + + const items = (vs != null) ? (assertArray(vs), vs.value) : []; + + const result = target.value.splice(index, remove_count, ...items); + return ARR(result); + }), flat: (target: VArr): VFn => FN_NATIVE(async ([depth], opts) => { depth = depth ?? NUM(1); diff --git a/test/index.ts b/test/index.ts index cf5fb90e..18e215b9 100644 --- a/test/index.ts +++ b/test/index.ts @@ -3014,6 +3014,54 @@ describe('primitive props', () => { ARR([]), ])); }); + + test.concurrent('splice (full)', async () => { + const res = await exe(` + let arr1 = [0, 1, 2, 3] + let arr2 = arr1.splice(1, 2, [10]) + <: [arr1, arr2] + `); + eq(res, ARR([ + ARR([NUM(0), NUM(10), NUM(3)]), + ARR([NUM(1), NUM(2)]), + ])); + }); + + test.concurrent('splice (negative-index)', async () => { + const res = await exe(` + let arr1 = [0, 1, 2, 3] + let arr2 = arr1.splice(-1, 0, [10, 20]) + <: [arr1, arr2] + `); + eq(res, ARR([ + ARR([NUM(0), NUM(1), NUM(2), NUM(10), NUM(20), NUM(3)]), + ARR([]), + ])); + }); + + test.concurrent('splice (larger-index)', async () => { + const res = await exe(` + let arr1 = [0, 1, 2, 3] + let arr2 = arr1.splice(4, 100, [10, 20]) + <: [arr1, arr2] + `); + eq(res, ARR([ + ARR([NUM(0), NUM(1), NUM(2), NUM(3), NUM(10), NUM(20)]), + ARR([]), + ])); + }); + + test.concurrent('splice (single argument)', async () => { + const res = await exe(` + let arr1 = [0, 1, 2, 3] + let arr2 = arr1.splice(1) + <: [arr1, arr2] + `); + eq(res, ARR([ + ARR([NUM(0)]), + ARR([NUM(1), NUM(2), NUM(3)]), + ])); + }); test.concurrent('flat', async () => { const res = await exe(`