Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

arr.spliceを追加 #621

Merged
merged 13 commits into from
May 12, 2024
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# 未リリース分
- `Date:year`系の関数に0を渡すと現在時刻になる問題を修正
- シンタックスエラーなどの位置情報を修正
- `arr.splice`を追加

# 0.18.0
- `Core:abort`でプログラムを緊急停止できるように
Expand Down
9 changes: 9 additions & 0 deletions docs/primitive-props.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,15 @@ _fromIndex_ および _toIndex_ に関する挙動は`arr.slice`に準拠しま
`arr.copy`同様シャローコピーであり、配列やオブジェクトの参照は維持されます。
_times_ には0以上の整数値を指定します。それ以外ではエラーになります。

### @(_v_: arr).splice(_index_: num, _remove_count_?: num, _items_?: arr\<value>): arr\<value>
**【この操作は配列を書き換えます】**
配列の _index_ から _remove_count_ 個の要素を取り除き、その位置に _items_ の要素を挿入します。
返り値として、取り除いた要素の配列を返します。\
_index_ が負の場合は末尾から数えます。\
_index_ が最後の要素より後の場合は要素を取り除かず、挿入は末尾に追加します。\
_remove_count_ を省略した場合、末尾まで取り除きます。\
_items_ を省略した場合、何も挿入しません。

### @(_v_: arr).every(_func_: @(_item_: value, _index_: num) { bool }): bool
配列の全ての要素に対して _func_ が true を返す時のみ true 返します。空配列には常に true を返します。

Expand Down
16 changes: 16 additions & 0 deletions src/interpreter/primitive-props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@
split: (target: VStr): VFn => FN_NATIVE(async ([splitter], _opts) => {
if (splitter) assertString(splitter);
if (splitter) {
return ARR(target.value.split(splitter ? splitter.value : '').map(s => STR(s)));

Check warning on line 89 in src/interpreter/primitive-props.ts

View workflow job for this annotation

GitHub Actions / lint

Unnecessary conditional, value is always truthy
} else {
return ARR(toArray(target.value).map(s => STR(s)));
}
Expand Down Expand Up @@ -279,6 +279,22 @@
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);
}),

every: (target: VArr): VFn => FN_NATIVE(async ([fn], opts) => {
assertFunction(fn);
Expand Down
48 changes: 48 additions & 0 deletions test/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2890,7 +2890,55 @@ 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('every', async () => {
const res = await exe(`
let arr1 = [0, 1, 2, 3]
Expand Down
Loading