From b444057ab8d70de5c510ee5e40fe69f84b431f7f Mon Sep 17 00:00:00 2001
From: salano_ym <53254905+salano-ym@users.noreply.github.com>
Date: Sat, 30 Mar 2024 17:26:36 +0000
Subject: [PATCH 01/47] Str:encode_uri
---
docs/std.md | 4 ++++
src/interpreter/lib/std.ts | 5 +++++
test/index.ts | 7 +++++++
3 files changed, 16 insertions(+)
diff --git a/docs/std.md b/docs/std.md
index 4e888add..99fe7365 100644
--- a/docs/std.md
+++ b/docs/std.md
@@ -131,6 +131,10 @@ _codePoints_の各要素は 0 以上、10FFFF16 以下である必要
UTF-8のバイト列を表す数値の配列から文字を生成します。
_bytes_の各要素は 0 以上、255 以下である必要があります。
+### #Str:encode_uri(v: str): str
+v をURIとしてエンコードした文字列を返します。ただし以下の文字はエンコードされません。
+`A-Z a-z 0-9 - _ . ! ~ * ' ( ) ; , / ? : @ & = + $ #`
+
## :: Arr
### @Arr:create(_length_: num, _initial_?: value): arr
長さが`length`の配列を作成します。
diff --git a/src/interpreter/lib/std.ts b/src/interpreter/lib/std.ts
index 469cba07..2aa7af86 100644
--- a/src/interpreter/lib/std.ts
+++ b/src/interpreter/lib/std.ts
@@ -498,6 +498,11 @@ export const std: Record = {
return a.value;
}))));
}),
+
+ 'Str:encode_uri': FN_NATIVE(([v]) => {
+ assertString(v);
+ return STR(encodeURI(v.value));
+ }),
//#endregion
//#region Arr
diff --git a/test/index.ts b/test/index.ts
index 3c62c840..cb32cf10 100644
--- a/test/index.ts
+++ b/test/index.ts
@@ -3057,6 +3057,13 @@ describe('std', () => {
`);
eq(res, NULL);
});
+
+ test.concurrent('encode_uri', async () => {
+ const res = await exe(`
+ <: Str:encode_uri("https://example.com/?q=あいちゃん")
+ `);
+ eq(res, STR('https://example.com/?q=%E3%81%82%E3%81%84%E3%81%A1%E3%82%83%E3%82%93'));
+ });
});
describe('Error', () => {
From d4a5cc77708cb9a09383260e62bd90acba0070cd Mon Sep 17 00:00:00 2001
From: salano_ym <53254905+salano-ym@users.noreply.github.com>
Date: Sat, 30 Mar 2024 17:28:51 +0000
Subject: [PATCH 02/47] Str:encode_uri_component
---
docs/std.md | 4 ++++
src/interpreter/lib/std.ts | 5 +++++
test/index.ts | 7 +++++++
3 files changed, 16 insertions(+)
diff --git a/docs/std.md b/docs/std.md
index 99fe7365..db1d8514 100644
--- a/docs/std.md
+++ b/docs/std.md
@@ -135,6 +135,10 @@ _bytes_の各要素は 0 以上、255 以下である必要があります。
v をURIとしてエンコードした文字列を返します。ただし以下の文字はエンコードされません。
`A-Z a-z 0-9 - _ . ! ~ * ' ( ) ; , / ? : @ & = + $ #`
+### #Str:encode_uri_component(v: str): str
+v をURIとしてエンコードした文字列を返します。ただし以下の文字はエンコードされません。
+`A-Z a-z 0-9 - _ . ! ~ * ' ( )`
+
## :: Arr
### @Arr:create(_length_: num, _initial_?: value): arr
長さが`length`の配列を作成します。
diff --git a/src/interpreter/lib/std.ts b/src/interpreter/lib/std.ts
index 2aa7af86..a41eb7da 100644
--- a/src/interpreter/lib/std.ts
+++ b/src/interpreter/lib/std.ts
@@ -502,6 +502,11 @@ export const std: Record = {
'Str:encode_uri': FN_NATIVE(([v]) => {
assertString(v);
return STR(encodeURI(v.value));
+ }),
+
+ 'Str:encode_uri_component': FN_NATIVE(([v]) => {
+ assertString(v);
+ return STR(encodeURIComponent(v.value));
}),
//#endregion
diff --git a/test/index.ts b/test/index.ts
index cb32cf10..d53e13e1 100644
--- a/test/index.ts
+++ b/test/index.ts
@@ -3064,6 +3064,13 @@ describe('std', () => {
`);
eq(res, STR('https://example.com/?q=%E3%81%82%E3%81%84%E3%81%A1%E3%82%83%E3%82%93'));
});
+
+ test.concurrent('encode_uri_component', async () => {
+ const res = await exe(`
+ <: Str:encode_uri_component("https://example.com/?q=あいちゃん")
+ `);
+ eq(res, STR('https%3A%2F%2Fexample.com%2F%3Fq%3D%E3%81%82%E3%81%84%E3%81%A1%E3%82%83%E3%82%93'));
+ });
});
describe('Error', () => {
From 0cfbaf7db26895588912ae2bc213f53e424a700e Mon Sep 17 00:00:00 2001
From: salano_ym <53254905+salano-ym@users.noreply.github.com>
Date: Sat, 30 Mar 2024 17:29:47 +0000
Subject: [PATCH 03/47] Str:decode_uri
---
docs/std.md | 4 ++++
src/interpreter/lib/std.ts | 5 +++++
test/index.ts | 7 +++++++
3 files changed, 16 insertions(+)
diff --git a/docs/std.md b/docs/std.md
index db1d8514..35343f18 100644
--- a/docs/std.md
+++ b/docs/std.md
@@ -139,6 +139,10 @@ v をURIとしてエンコードした文字列を返します。ただし以下
v をURIとしてエンコードした文字列を返します。ただし以下の文字はエンコードされません。
`A-Z a-z 0-9 - _ . ! ~ * ' ( )`
+### #Str:decode_uri(v: str): str
+v をURIとしてエスケープシーケンスをデコードした文字列を返します。
+ただし`Str:encode_uri`でエンコードされないエスケープシーケンスはデコードされません。
+
## :: Arr
### @Arr:create(_length_: num, _initial_?: value): arr
長さが`length`の配列を作成します。
diff --git a/src/interpreter/lib/std.ts b/src/interpreter/lib/std.ts
index a41eb7da..71439105 100644
--- a/src/interpreter/lib/std.ts
+++ b/src/interpreter/lib/std.ts
@@ -507,6 +507,11 @@ export const std: Record = {
'Str:encode_uri_component': FN_NATIVE(([v]) => {
assertString(v);
return STR(encodeURIComponent(v.value));
+ }),
+
+ 'Str:decode_uri': FN_NATIVE(([v]) => {
+ assertString(v);
+ return STR(decodeURI(v.value));
}),
//#endregion
diff --git a/test/index.ts b/test/index.ts
index d53e13e1..07e0a149 100644
--- a/test/index.ts
+++ b/test/index.ts
@@ -3071,6 +3071,13 @@ describe('std', () => {
`);
eq(res, STR('https%3A%2F%2Fexample.com%2F%3Fq%3D%E3%81%82%E3%81%84%E3%81%A1%E3%82%83%E3%82%93'));
});
+
+ test.concurrent('decode_uri', async () => {
+ const res = await exe(`
+ <: Str:decode_uri("https%3A%2F%2Fexample.com%2F%3Fq%3D%E3%81%82%E3%81%84%E3%81%A1%E3%82%83%E3%82%93")
+ `);
+ eq(res, STR('https%3A%2F%2Fexample.com%2F%3Fq%3Dあいちゃん'));
+ });
});
describe('Error', () => {
From bbecdf65707301910fdd29addba43c454b8574be Mon Sep 17 00:00:00 2001
From: salano_ym <53254905+salano-ym@users.noreply.github.com>
Date: Sat, 30 Mar 2024 17:30:50 +0000
Subject: [PATCH 04/47] Str:decode_uri_component
---
docs/std.md | 3 +++
src/interpreter/lib/std.ts | 5 +++++
test/index.ts | 7 +++++++
3 files changed, 15 insertions(+)
diff --git a/docs/std.md b/docs/std.md
index 35343f18..a8fccf07 100644
--- a/docs/std.md
+++ b/docs/std.md
@@ -143,6 +143,9 @@ v をURIとしてエンコードした文字列を返します。ただし以下
v をURIとしてエスケープシーケンスをデコードした文字列を返します。
ただし`Str:encode_uri`でエンコードされないエスケープシーケンスはデコードされません。
+### #Str:decode_uri_component(v: str): str
+v をURIとしてエスケープシーケンスをデコードした文字列を返します。
+
## :: Arr
### @Arr:create(_length_: num, _initial_?: value): arr
長さが`length`の配列を作成します。
diff --git a/src/interpreter/lib/std.ts b/src/interpreter/lib/std.ts
index 71439105..e7d530cd 100644
--- a/src/interpreter/lib/std.ts
+++ b/src/interpreter/lib/std.ts
@@ -513,6 +513,11 @@ export const std: Record = {
assertString(v);
return STR(decodeURI(v.value));
}),
+
+ 'Str:decode_uri_component': FN_NATIVE(([v]) => {
+ assertString(v);
+ return STR(decodeURIComponent(v.value));
+ }),
//#endregion
//#region Arr
diff --git a/test/index.ts b/test/index.ts
index 07e0a149..fc1b5805 100644
--- a/test/index.ts
+++ b/test/index.ts
@@ -3078,6 +3078,13 @@ describe('std', () => {
`);
eq(res, STR('https%3A%2F%2Fexample.com%2F%3Fq%3Dあいちゃん'));
});
+
+ test.concurrent('decode_uri_component', async () => {
+ const res = await exe(`
+ <: Str:decode_uri_component("https%3A%2F%2Fexample.com%2F%3Fq%3D%E3%81%82%E3%81%84%E3%81%A1%E3%82%83%E3%82%93")
+ `);
+ eq(res, STR('https://example.com/?q=あいちゃん'));
+ });
});
describe('Error', () => {
From d599f8f3ce7dcafbf449eda42186aec7f8f9b2fb Mon Sep 17 00:00:00 2001
From: salano_ym <53254905+salano-ym@users.noreply.github.com>
Date: Sat, 30 Mar 2024 17:32:40 +0000
Subject: [PATCH 05/47] Update CHANGELOG.md Str:encode_uri
Str:encode_uri_component Str:decode_uri Str:decode_uri_component
---
CHANGELOG.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4a54dd98..3987e087 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,7 @@
- `arr.incl`の引数の型制限を廃止
- `Date:millisecond`を追加
- `arr.fill`, `arr.repeat`, `Arr:create`を追加
+- `Str:encode_uri`, `Str:encode_uri_component`, `Str:decode_uri`, `Str:decode_uri_component`を追加
# 0.17.0
- `package.json`を修正
From 1d094fd3838daf7f1accbf3d0abb5233d76b16b8 Mon Sep 17 00:00:00 2001
From: salano_ym <53254905+salano-ym@users.noreply.github.com>
Date: Sat, 30 Mar 2024 17:38:12 +0000
Subject: [PATCH 06/47] =?UTF-8?q?doc=E3=81=AE=E6=9B=B8=E5=BC=8F=E3=81=8C?=
=?UTF-8?q?=E9=96=93=E9=81=95=E3=81=A3=E3=81=A6=E3=81=84=E3=82=8B=E3=81=AE?=
=?UTF-8?q?=E3=82=92=E4=BF=AE=E6=AD=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
docs/std.md | 18 +++++++++---------
translations/en/docs/std.md | 6 +++---
2 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/docs/std.md b/docs/std.md
index a8fccf07..fc4f9a91 100644
--- a/docs/std.md
+++ b/docs/std.md
@@ -110,40 +110,40 @@ _date_ を渡した場合、_date_に対応するミリ秒、
型: `str`
改行コード(LF)です。
-### #Str:lt(a: str, b: str): num
+### @Str:lt(a: str, b: str): num
a < b ならば -1、a == b ならば 0、a > b ならば 1 を返します。
arr.sortの比較関数として使用できます。
-### #Str:gt(a: str, b: str): num
+### @Str:gt(a: str, b: str): num
a > b ならば -1、a == b ならば 0、a < b ならば 1 を返します。
arr.sortの比較関数として使用できます。
-### #Str:from_codepoint(codepoint: num): str
+### @Str:from_codepoint(codepoint: num): str
Unicodeのコードポイントから文字を生成します。
_codepoint_ は 0 以上、10FFFF16 以下である必要があります。
-### #Str:from_unicode_codepoints(_codePoints_: `arr`): str
+### @Str:from_unicode_codepoints(_codePoints_: `arr`): str
Unicodeのコードポイント列を表す数値の配列から文字を生成します。
_codePoints_の各要素は 0 以上、10FFFF16 以下である必要があります。
-### #Str:from_utf8_bytes(_bytes_: `arr`): str
+### @Str:from_utf8_bytes(_bytes_: `arr`): str
UTF-8のバイト列を表す数値の配列から文字を生成します。
_bytes_の各要素は 0 以上、255 以下である必要があります。
-### #Str:encode_uri(v: str): str
+### @Str:encode_uri(v: str): str
v をURIとしてエンコードした文字列を返します。ただし以下の文字はエンコードされません。
`A-Z a-z 0-9 - _ . ! ~ * ' ( ) ; , / ? : @ & = + $ #`
-### #Str:encode_uri_component(v: str): str
+### @Str:encode_uri_component(v: str): str
v をURIとしてエンコードした文字列を返します。ただし以下の文字はエンコードされません。
`A-Z a-z 0-9 - _ . ! ~ * ' ( )`
-### #Str:decode_uri(v: str): str
+### @Str:decode_uri(v: str): str
v をURIとしてエスケープシーケンスをデコードした文字列を返します。
ただし`Str:encode_uri`でエンコードされないエスケープシーケンスはデコードされません。
-### #Str:decode_uri_component(v: str): str
+### @Str:decode_uri_component(v: str): str
v をURIとしてエスケープシーケンスをデコードした文字列を返します。
## :: Arr
diff --git a/translations/en/docs/std.md b/translations/en/docs/std.md
index 67d36237..32098a9e 100644
--- a/translations/en/docs/std.md
+++ b/translations/en/docs/std.md
@@ -113,19 +113,19 @@ Generates a numeric value from a hexadecimal string.
Type: `str`.
Newline code (LF).
-### #Str:lt(a: str, b: str): num
+### @Str:lt(a: str, b: str): num
Returns -1 if a < b,
0 if a == b,
or 1 if a > b.
Using this as a comparison function for `arr.sort`, the array is sorted in ascending lexicographic order.
-### #Str:gt(a: str, b: str): num
+### @Str:gt(a: str, b: str): num
Returns -1 if a > b,
0 if a == b,
or 1 if a < b.
Using this as the comparison function for `arr.sort`, the array is sorted in descending lexicographic order.
-### #Str:from_codepoint(codepoint: num): str
+### @Str:from_codepoint(codepoint: num): str
Generates character from unicode code point.
_codepoint_ must be greater than or equal to 0 and less than or equal to 10FFFFFF16.
Multiple arguments are not supported yet.
From 7458adccd8e6adceeebd5305da7e2f5ae53f8c12 Mon Sep 17 00:00:00 2001
From: salano_ym <53254905+salano-ym@users.noreply.github.com>
Date: Sun, 31 Mar 2024 09:32:13 +0000
Subject: [PATCH 07/47] =?UTF-8?q?encode=E7=B3=BB=E3=81=AEdoc=E3=82=92?=
=?UTF-8?q?=E4=BF=AE=E6=AD=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
docs/std.md | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/docs/std.md b/docs/std.md
index fc4f9a91..759ed24d 100644
--- a/docs/std.md
+++ b/docs/std.md
@@ -131,20 +131,20 @@ _codePoints_の各要素は 0 以上、10FFFF16 以下である必要
UTF-8のバイト列を表す数値の配列から文字を生成します。
_bytes_の各要素は 0 以上、255 以下である必要があります。
-### @Str:encode_uri(v: str): str
-v をURIとしてエンコードした文字列を返します。ただし以下の文字はエンコードされません。
+### @Str:encode_uri(uri: str): str
+uri をURIとしてエンコードした文字列を返します。以下の文字はエンコードされません。
`A-Z a-z 0-9 - _ . ! ~ * ' ( ) ; , / ? : @ & = + $ #`
-### @Str:encode_uri_component(v: str): str
-v をURIとしてエンコードした文字列を返します。ただし以下の文字はエンコードされません。
+### @Str:encode_uri_component(text: str): str
+text をURI構成要素としてエンコードした文字列を返します。以下の文字はエンコードされません。
`A-Z a-z 0-9 - _ . ! ~ * ' ( )`
-### @Str:decode_uri(v: str): str
-v をURIとしてエスケープシーケンスをデコードした文字列を返します。
-ただし`Str:encode_uri`でエンコードされないエスケープシーケンスはデコードされません。
+### @Str:decode_uri(encoded_uri: str): str
+encoded_uri をエンコードされたURIとしてデコードした文字列を返します。
+`Str:encode_uri`でエンコードされないエスケープシーケンスはデコードされません。
-### @Str:decode_uri_component(v: str): str
-v をURIとしてエスケープシーケンスをデコードした文字列を返します。
+### @Str:decode_uri_component(encoded_text: str): str
+encoded_text をエンコードされたURI構成要素としてデコードした文字列を返します。
## :: Arr
### @Arr:create(_length_: num, _initial_?: value): arr
From ab686d4a472341ef4398593c79b97d1aa99a34f3 Mon Sep 17 00:00:00 2001
From: salano_ym <53254905+salano-ym@users.noreply.github.com>
Date: Sun, 31 Mar 2024 10:48:02 +0000
Subject: [PATCH 08/47] =?UTF-8?q?encode=E7=B3=BB=E9=96=A2=E6=95=B0?=
=?UTF-8?q?=E3=81=AE=E5=90=8D=E5=89=8D=E7=A9=BA=E9=96=93=E3=82=92Str:?=
=?UTF-8?q?=E3=81=8B=E3=82=89Uri:=E3=81=AB=E7=A7=BB=E5=8B=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
CHANGELOG.md | 2 +-
docs/std.md | 11 ++++++-----
src/interpreter/lib/std.ts | 12 +++++++-----
test/index.ts | 10 ++++++----
4 files changed, 20 insertions(+), 15 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3987e087..fce03652 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,7 +7,7 @@
- `arr.incl`の引数の型制限を廃止
- `Date:millisecond`を追加
- `arr.fill`, `arr.repeat`, `Arr:create`を追加
-- `Str:encode_uri`, `Str:encode_uri_component`, `Str:decode_uri`, `Str:decode_uri_component`を追加
+- `Uri:encode_uri`, `Uri:encode_uri_component`, `Uri:decode_uri`, `Uri:decode_uri_component`を追加
# 0.17.0
- `package.json`を修正
diff --git a/docs/std.md b/docs/std.md
index 759ed24d..88cb72c8 100644
--- a/docs/std.md
+++ b/docs/std.md
@@ -131,19 +131,20 @@ _codePoints_の各要素は 0 以上、10FFFF16 以下である必要
UTF-8のバイト列を表す数値の配列から文字を生成します。
_bytes_の各要素は 0 以上、255 以下である必要があります。
-### @Str:encode_uri(uri: str): str
+## :: Uri
+### @Uri:encode_uri(uri: str): str
uri をURIとしてエンコードした文字列を返します。以下の文字はエンコードされません。
`A-Z a-z 0-9 - _ . ! ~ * ' ( ) ; , / ? : @ & = + $ #`
-### @Str:encode_uri_component(text: str): str
+### @Uri:encode_uri_component(text: str): str
text をURI構成要素としてエンコードした文字列を返します。以下の文字はエンコードされません。
`A-Z a-z 0-9 - _ . ! ~ * ' ( )`
-### @Str:decode_uri(encoded_uri: str): str
+### @Uri:decode_uri(encoded_uri: str): str
encoded_uri をエンコードされたURIとしてデコードした文字列を返します。
-`Str:encode_uri`でエンコードされないエスケープシーケンスはデコードされません。
+`Uri:encode_uri`でエンコードされないエスケープシーケンスはデコードされません。
-### @Str:decode_uri_component(encoded_text: str): str
+### @Uri:decode_uri_component(encoded_text: str): str
encoded_text をエンコードされたURI構成要素としてデコードした文字列を返します。
## :: Arr
diff --git a/src/interpreter/lib/std.ts b/src/interpreter/lib/std.ts
index e7d530cd..df46d6f5 100644
--- a/src/interpreter/lib/std.ts
+++ b/src/interpreter/lib/std.ts
@@ -498,23 +498,25 @@ export const std: Record = {
return a.value;
}))));
}),
-
- 'Str:encode_uri': FN_NATIVE(([v]) => {
+ //#endregion
+
+ //#region Uri
+ 'Uri:encode_uri': FN_NATIVE(([v]) => {
assertString(v);
return STR(encodeURI(v.value));
}),
- 'Str:encode_uri_component': FN_NATIVE(([v]) => {
+ 'Uri:encode_uri_component': FN_NATIVE(([v]) => {
assertString(v);
return STR(encodeURIComponent(v.value));
}),
- 'Str:decode_uri': FN_NATIVE(([v]) => {
+ 'Uri:decode_uri': FN_NATIVE(([v]) => {
assertString(v);
return STR(decodeURI(v.value));
}),
- 'Str:decode_uri_component': FN_NATIVE(([v]) => {
+ 'Uri:decode_uri_component': FN_NATIVE(([v]) => {
assertString(v);
return STR(decodeURIComponent(v.value));
}),
diff --git a/test/index.ts b/test/index.ts
index fc1b5805..a6fb2888 100644
--- a/test/index.ts
+++ b/test/index.ts
@@ -3057,31 +3057,33 @@ describe('std', () => {
`);
eq(res, NULL);
});
+ });
+ describe('Uri', () => {
test.concurrent('encode_uri', async () => {
const res = await exe(`
- <: Str:encode_uri("https://example.com/?q=あいちゃん")
+ <: Uri:encode_uri("https://example.com/?q=あいちゃん")
`);
eq(res, STR('https://example.com/?q=%E3%81%82%E3%81%84%E3%81%A1%E3%82%83%E3%82%93'));
});
test.concurrent('encode_uri_component', async () => {
const res = await exe(`
- <: Str:encode_uri_component("https://example.com/?q=あいちゃん")
+ <: Uri:encode_uri_component("https://example.com/?q=あいちゃん")
`);
eq(res, STR('https%3A%2F%2Fexample.com%2F%3Fq%3D%E3%81%82%E3%81%84%E3%81%A1%E3%82%83%E3%82%93'));
});
test.concurrent('decode_uri', async () => {
const res = await exe(`
- <: Str:decode_uri("https%3A%2F%2Fexample.com%2F%3Fq%3D%E3%81%82%E3%81%84%E3%81%A1%E3%82%83%E3%82%93")
+ <: Uri:decode_uri("https%3A%2F%2Fexample.com%2F%3Fq%3D%E3%81%82%E3%81%84%E3%81%A1%E3%82%83%E3%82%93")
`);
eq(res, STR('https%3A%2F%2Fexample.com%2F%3Fq%3Dあいちゃん'));
});
test.concurrent('decode_uri_component', async () => {
const res = await exe(`
- <: Str:decode_uri_component("https%3A%2F%2Fexample.com%2F%3Fq%3D%E3%81%82%E3%81%84%E3%81%A1%E3%82%83%E3%82%93")
+ <: Uri:decode_uri_component("https%3A%2F%2Fexample.com%2F%3Fq%3D%E3%81%82%E3%81%84%E3%81%A1%E3%82%83%E3%82%93")
`);
eq(res, STR('https://example.com/?q=あいちゃん'));
});
From 3deebcf6a2dfd9fd916ea642595a3d77ea10216d Mon Sep 17 00:00:00 2001
From: salano_ym <53254905+salano-ym@users.noreply.github.com>
Date: Sun, 31 Mar 2024 15:39:02 +0000
Subject: [PATCH 09/47] =?UTF-8?q?Uri:encode=E7=B3=BB=E3=81=AE=E9=96=A2?=
=?UTF-8?q?=E6=95=B0=E5=90=8D=E3=82=92=E5=A4=89=E6=9B=B4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
CHANGELOG.md | 2 +-
docs/std.md | 10 +++++-----
src/interpreter/lib/std.ts | 8 ++++----
test/index.ts | 16 ++++++++--------
4 files changed, 18 insertions(+), 18 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fce03652..6b8a2571 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,7 +7,7 @@
- `arr.incl`の引数の型制限を廃止
- `Date:millisecond`を追加
- `arr.fill`, `arr.repeat`, `Arr:create`を追加
-- `Uri:encode_uri`, `Uri:encode_uri_component`, `Uri:decode_uri`, `Uri:decode_uri_component`を追加
+- `Uri:encode_full`, `Uri:encode_component`, `Uri:decode_full`, `Uri:decode_component`を追加
# 0.17.0
- `package.json`を修正
diff --git a/docs/std.md b/docs/std.md
index 88cb72c8..efad9a3a 100644
--- a/docs/std.md
+++ b/docs/std.md
@@ -132,19 +132,19 @@ UTF-8のバイト列を表す数値の配列から文字を生成します。
_bytes_の各要素は 0 以上、255 以下である必要があります。
## :: Uri
-### @Uri:encode_uri(uri: str): str
+### @Uri:encode_full(uri: str): str
uri をURIとしてエンコードした文字列を返します。以下の文字はエンコードされません。
`A-Z a-z 0-9 - _ . ! ~ * ' ( ) ; , / ? : @ & = + $ #`
-### @Uri:encode_uri_component(text: str): str
+### @Uri:encode_component(text: str): str
text をURI構成要素としてエンコードした文字列を返します。以下の文字はエンコードされません。
`A-Z a-z 0-9 - _ . ! ~ * ' ( )`
-### @Uri:decode_uri(encoded_uri: str): str
+### @Uri:decode_full(encoded_uri: str): str
encoded_uri をエンコードされたURIとしてデコードした文字列を返します。
-`Uri:encode_uri`でエンコードされないエスケープシーケンスはデコードされません。
+`Uri:encode_full`でエンコードされないエスケープシーケンスはデコードされません。
-### @Uri:decode_uri_component(encoded_text: str): str
+### @Uri:decode_component(encoded_text: str): str
encoded_text をエンコードされたURI構成要素としてデコードした文字列を返します。
## :: Arr
diff --git a/src/interpreter/lib/std.ts b/src/interpreter/lib/std.ts
index df46d6f5..81d72d42 100644
--- a/src/interpreter/lib/std.ts
+++ b/src/interpreter/lib/std.ts
@@ -501,22 +501,22 @@ export const std: Record = {
//#endregion
//#region Uri
- 'Uri:encode_uri': FN_NATIVE(([v]) => {
+ 'Uri:encode_full': FN_NATIVE(([v]) => {
assertString(v);
return STR(encodeURI(v.value));
}),
- 'Uri:encode_uri_component': FN_NATIVE(([v]) => {
+ 'Uri:encode_component': FN_NATIVE(([v]) => {
assertString(v);
return STR(encodeURIComponent(v.value));
}),
- 'Uri:decode_uri': FN_NATIVE(([v]) => {
+ 'Uri:decode_full': FN_NATIVE(([v]) => {
assertString(v);
return STR(decodeURI(v.value));
}),
- 'Uri:decode_uri_component': FN_NATIVE(([v]) => {
+ 'Uri:decode_component': FN_NATIVE(([v]) => {
assertString(v);
return STR(decodeURIComponent(v.value));
}),
diff --git a/test/index.ts b/test/index.ts
index a6fb2888..3a1befeb 100644
--- a/test/index.ts
+++ b/test/index.ts
@@ -3060,30 +3060,30 @@ describe('std', () => {
});
describe('Uri', () => {
- test.concurrent('encode_uri', async () => {
+ test.concurrent('encode_full', async () => {
const res = await exe(`
- <: Uri:encode_uri("https://example.com/?q=あいちゃん")
+ <: Uri:encode_full("https://example.com/?q=あいちゃん")
`);
eq(res, STR('https://example.com/?q=%E3%81%82%E3%81%84%E3%81%A1%E3%82%83%E3%82%93'));
});
- test.concurrent('encode_uri_component', async () => {
+ test.concurrent('encode_component', async () => {
const res = await exe(`
- <: Uri:encode_uri_component("https://example.com/?q=あいちゃん")
+ <: Uri:encode_component("https://example.com/?q=あいちゃん")
`);
eq(res, STR('https%3A%2F%2Fexample.com%2F%3Fq%3D%E3%81%82%E3%81%84%E3%81%A1%E3%82%83%E3%82%93'));
});
- test.concurrent('decode_uri', async () => {
+ test.concurrent('decode_full', async () => {
const res = await exe(`
- <: Uri:decode_uri("https%3A%2F%2Fexample.com%2F%3Fq%3D%E3%81%82%E3%81%84%E3%81%A1%E3%82%83%E3%82%93")
+ <: Uri:decode_full("https%3A%2F%2Fexample.com%2F%3Fq%3D%E3%81%82%E3%81%84%E3%81%A1%E3%82%83%E3%82%93")
`);
eq(res, STR('https%3A%2F%2Fexample.com%2F%3Fq%3Dあいちゃん'));
});
- test.concurrent('decode_uri_component', async () => {
+ test.concurrent('decode_component', async () => {
const res = await exe(`
- <: Uri:decode_uri_component("https%3A%2F%2Fexample.com%2F%3Fq%3D%E3%81%82%E3%81%84%E3%81%A1%E3%82%83%E3%82%93")
+ <: Uri:decode_component("https%3A%2F%2Fexample.com%2F%3Fq%3D%E3%81%82%E3%81%84%E3%81%A1%E3%82%83%E3%82%93")
`);
eq(res, STR('https://example.com/?q=あいちゃん'));
});
From f7face7911baad21e7391f95e50d8e40f9071359 Mon Sep 17 00:00:00 2001
From: salano_ym <53254905+salano-ym@users.noreply.github.com>
Date: Sun, 31 Mar 2024 15:41:45 +0000
Subject: [PATCH 10/47] =?UTF-8?q?doc=E3=82=92=E4=BF=AE=E6=AD=A3(Uri:decode?=
=?UTF-8?q?=5Ffull)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
docs/std.md | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/docs/std.md b/docs/std.md
index efad9a3a..536e3112 100644
--- a/docs/std.md
+++ b/docs/std.md
@@ -142,7 +142,8 @@ text をURI構成要素としてエンコードした文字列を返します。
### @Uri:decode_full(encoded_uri: str): str
encoded_uri をエンコードされたURIとしてデコードした文字列を返します。
-`Uri:encode_full`でエンコードされないエスケープシーケンスはデコードされません。
+以下の文字に対応するエスケープシーケンスはデコードされません。
+`; , / ? : @ & = + $ #`
### @Uri:decode_component(encoded_text: str): str
encoded_text をエンコードされたURI構成要素としてデコードした文字列を返します。
From 67f393e1e0a6d25a3c8612e2163af6224d61895d Mon Sep 17 00:00:00 2001
From: salano_ym <53254905+salano-ym@users.noreply.github.com>
Date: Thu, 11 Apr 2024 09:02:07 +0000
Subject: [PATCH 11/47] arr.splice
---
CHANGELOG.md | 1 +
docs/primitive-props.md | 8 +++++
src/interpreter/primitive-props.ts | 16 ++++++++++
test/index.ts | 48 ++++++++++++++++++++++++++++++
4 files changed, 73 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 89464f88..5df721e9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,7 @@
- `Date:millisecond`を追加
- `arr.fill`, `arr.repeat`, `Arr:create`を追加
- JavaScriptのように分割代入ができるように(現段階では機能は最小限)
+- `arr.splice`を追加
# 0.17.0
- `package.json`を修正
diff --git a/docs/primitive-props.md b/docs/primitive-props.md
index 0c9c2919..b0c98249 100644
--- a/docs/primitive-props.md
+++ b/docs/primitive-props.md
@@ -184,6 +184,14 @@ _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_: error).name
型: `str`
diff --git a/src/interpreter/primitive-props.ts b/src/interpreter/primitive-props.ts
index 911313ac..5d05794d 100644
--- a/src/interpreter/primitive-props.ts
+++ b/src/interpreter/primitive-props.ts
@@ -279,6 +279,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);
+ }),
},
error: {
diff --git a/test/index.ts b/test/index.ts
index 5d4634e9..a2cdf9fa 100644
--- a/test/index.ts
+++ b/test/index.ts
@@ -2849,6 +2849,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)]),
+ ]));
+ });
});
});
From 3761bf1c895ca6fff7a98246991b0517ff12e383 Mon Sep 17 00:00:00 2001
From: salano_ym <53254905+salano-ym@users.noreply.github.com>
Date: Thu, 11 Apr 2024 09:07:16 +0000
Subject: [PATCH 12/47] =?UTF-8?q?doc=E4=BF=AE=E6=AD=A3(arr.splice)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
docs/primitive-props.md | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/docs/primitive-props.md b/docs/primitive-props.md
index b0c98249..f6c54bdb 100644
--- a/docs/primitive-props.md
+++ b/docs/primitive-props.md
@@ -186,9 +186,9 @@ _times_ には0以上の整数値を指定します。それ以外ではエラ
### @(_v_: arr).splice(_index_: num, _remove_count_: num, _items_: arr\): arr\
**【この操作は配列を書き換えます】**
-配列の _index_ から _remove_count_ 個の要素を取り除き、_items_ の要素を挿入します。
-返り値は取り除いた要素の配列を返します。\
-_index_ が負の場合、末尾から数えます。_index_ が最後の要素より後の場合、要素を取り除きません。\
+配列の _index_ から _remove_count_ 個の要素を取り除き、その位置に _items_ の要素を挿入します。
+返り値として、取り除いた要素の配列を返します。\
+_index_ が負の場合は末尾から数えます。_index_ が最後の要素より後の場合は要素を取り除きません。\
_remove_count_ を省略した場合、末尾まで取り除きます。\
_items_ を省略した場合、何も挿入しません。
From 3bd6c25a2f508cfb082bb7916b339f43d6c6124e Mon Sep 17 00:00:00 2001
From: salano_ym <53254905+salano-ym@users.noreply.github.com>
Date: Thu, 11 Apr 2024 09:16:59 +0000
Subject: [PATCH 13/47] =?UTF-8?q?doc=E4=BF=AE=E6=AD=A3=20(arr.splice)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
docs/primitive-props.md | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/docs/primitive-props.md b/docs/primitive-props.md
index f6c54bdb..345d2296 100644
--- a/docs/primitive-props.md
+++ b/docs/primitive-props.md
@@ -188,7 +188,8 @@ _times_ には0以上の整数値を指定します。それ以外ではエラ
**【この操作は配列を書き換えます】**
配列の _index_ から _remove_count_ 個の要素を取り除き、その位置に _items_ の要素を挿入します。
返り値として、取り除いた要素の配列を返します。\
-_index_ が負の場合は末尾から数えます。_index_ が最後の要素より後の場合は要素を取り除きません。\
+_index_ が負の場合は末尾から数えます。\
+_index_ が最後の要素より後の場合は要素を取り除かず、挿入は末尾に追加します。\
_remove_count_ を省略した場合、末尾まで取り除きます。\
_items_ を省略した場合、何も挿入しません。
From a1e98cff0b7c0ef5d6ba536fd411103b46698fc0 Mon Sep 17 00:00:00 2001
From: salano_ym <53254905+salano-ym@users.noreply.github.com>
Date: Thu, 11 Apr 2024 09:23:23 +0000
Subject: [PATCH 14/47] fix lint
---
src/interpreter/primitive-props.ts | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/interpreter/primitive-props.ts b/src/interpreter/primitive-props.ts
index 5d05794d..c8af6182 100644
--- a/src/interpreter/primitive-props.ts
+++ b/src/interpreter/primitive-props.ts
@@ -281,9 +281,9 @@ const PRIMITIVE_PROPS: {
}),
splice: (target: VArr): VFn => FN_NATIVE(async ([idx, rc, vs], opts) => {
- assertNumber(idx)
+ assertNumber(idx);
const index = (idx.value < -target.value.length) ? 0
- : (idx.value < 0) ? target.value.length + idx.value
+ : (idx.value < 0) ? target.value.length + idx.value
: (idx.value >= target.value.length) ? target.value.length
: idx.value;
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 15/47] 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 16/47] =?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 de79a9540adc87d27123057337333a32d96ee205 Mon Sep 17 00:00:00 2001
From: salano_ym <53254905+salano-ym@users.noreply.github.com>
Date: Thu, 11 Apr 2024 18:18:11 +0000
Subject: [PATCH 17/47] =?UTF-8?q?doc=E4=BF=AE=E6=AD=A3(arr.splice)?=
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 345d2296..a5a20b8d 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).splice(_index_: num, _remove_count_: num, _items_: arr\): arr\
+### @(_v_: arr).splice(_index_: num, _remove_count_?: num, _items_?: arr\): arr\
**【この操作は配列を書き換えます】**
配列の _index_ から _remove_count_ 個の要素を取り除き、その位置に _items_ の要素を挿入します。
返り値として、取り除いた要素の配列を返します。\
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 18/47] =?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 491de8bfa7c0f97b464aa908018d04b0185845ab Mon Sep 17 00:00:00 2001
From: salano_ym <53254905+salano-ym@users.noreply.github.com>
Date: Tue, 23 Apr 2024 10:38:51 +0000
Subject: [PATCH 19/47] =?UTF-8?q?arr.sort=E3=81=A7=E8=A1=8C=E3=82=8F?=
=?UTF-8?q?=E3=82=8C=E3=82=8B=E5=88=86=E5=89=B2=E3=81=95=E3=82=8C=E3=81=9F?=
=?UTF-8?q?=E5=90=84=E3=82=BD=E3=83=BC=E3=83=88=E3=82=92=E9=9D=9E=E5=90=8C?=
=?UTF-8?q?=E6=9C=9F=E5=87=A6=E7=90=86=E3=81=AB=E5=A4=89=E6=9B=B4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/interpreter/primitive-props.ts | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/interpreter/primitive-props.ts b/src/interpreter/primitive-props.ts
index 911313ac..9bc03ee5 100644
--- a/src/interpreter/primitive-props.ts
+++ b/src/interpreter/primitive-props.ts
@@ -231,8 +231,9 @@ const PRIMITIVE_PROPS: {
const mergeSort = async (arr: Value[], comp: VFn): Promise => {
if (arr.length <= 1) return arr;
const mid = Math.floor(arr.length / 2);
- const left = await mergeSort(arr.slice(0, mid), comp);
- const right = await mergeSort(arr.slice(mid), comp);
+ const left_promise = mergeSort(arr.slice(0, mid), comp);
+ const right_promise = mergeSort(arr.slice(mid), comp);
+ const [left, right] = await Promise.all([left_promise, right_promise]);
return merge(left, right, comp);
};
const merge = async (left: Value[], right: Value[], comp: VFn): Promise => {
From 2b1fd0ca9ed5c212ff0d2356e77bcfc27b9d9d4b Mon Sep 17 00:00:00 2001
From: salano_ym <53254905+salano-ym@users.noreply.github.com>
Date: Tue, 23 Apr 2024 10:39:15 +0000
Subject: [PATCH 20/47] update CHANGELOG
---
CHANGELOG.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 89464f88..a99d0f5e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,7 @@
- `Date:millisecond`を追加
- `arr.fill`, `arr.repeat`, `Arr:create`を追加
- JavaScriptのように分割代入ができるように(現段階では機能は最小限)
+- `arr.sort`の処理を非同期的にして高速化
# 0.17.0
- `package.json`を修正
From 32a8d66505553282089a8fbfe48c79cdd7ca04fb Mon Sep 17 00:00:00 2001
From: salano_ym <53254905+salano-ym@users.noreply.github.com>
Date: Thu, 25 Apr 2024 16:43:26 +0000
Subject: [PATCH 21/47] fix CHANGELOG.md
---
CHANGELOG.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d04db96d..6bd27575 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,7 @@
[Read translated version (en)](./translations/en/CHANGELOG.md)
# 未リリース分
+- `arr.sort`の処理を非同期的にして高速化
# 0.18.0
- `Core:abort`でプログラムを緊急停止できるように
@@ -14,7 +15,6 @@
- ネストされた名前空間下の変数を参照できるように
- `arr.every`, `arr.some`を追加
- `Date:to_iso_str`を追加
-- `arr.sort`の処理を非同期的にして高速化
# 0.17.0
- `package.json`を修正
From c7a5a046b66a58169b4626e9850ea09061e53e25 Mon Sep 17 00:00:00 2001
From: salano_ym <53254905+salano-ym@users.noreply.github.com>
Date: Thu, 25 Apr 2024 16:50:00 +0000
Subject: [PATCH 22/47] fix indent
---
src/interpreter/primitive-props.ts | 2 +-
test/index.ts | 6 +++---
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/interpreter/primitive-props.ts b/src/interpreter/primitive-props.ts
index 5f3a38d6..524eb2ac 100644
--- a/src/interpreter/primitive-props.ts
+++ b/src/interpreter/primitive-props.ts
@@ -294,7 +294,7 @@ const PRIMITIVE_PROPS: {
const result = target.value.splice(index, remove_count, ...items);
return ARR(result);
- }),
+ }),
every: (target: VArr): VFn => FN_NATIVE(async ([fn], opts) => {
assertFunction(fn);
diff --git a/test/index.ts b/test/index.ts
index db7f3cd6..eb9e3310 100644
--- a/test/index.ts
+++ b/test/index.ts
@@ -2922,10 +2922,10 @@ describe('primitive props', () => {
eq(res, ARR([
ARR([NUM(0)]),
ARR([NUM(1), NUM(2), NUM(3)]),
- ]));
- });
+ ]));
+ });
- test.concurrent('every', async () => {
+ test.concurrent('every', async () => {
const res = await exe(`
let arr1 = [0, 1, 2, 3]
let res1 = arr1.every(@(v,i){v==0 || i > 0})
From 492f6b81695d6391b244c11677e0d8fedffda49a Mon Sep 17 00:00:00 2001
From: salano_ym <53254905+salano-ym@users.noreply.github.com>
Date: Thu, 25 Apr 2024 16:52:00 +0000
Subject: [PATCH 23/47] fix indent
---
test/index.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/index.ts b/test/index.ts
index eb9e3310..d951dfae 100644
--- a/test/index.ts
+++ b/test/index.ts
@@ -2925,7 +2925,7 @@ describe('primitive props', () => {
]));
});
- test.concurrent('every', async () => {
+ test.concurrent('every', async () => {
const res = await exe(`
let arr1 = [0, 1, 2, 3]
let res1 = arr1.every(@(v,i){v==0 || i > 0})
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 24/47] 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`を修正
From c48c3ed27daf9d362420b5e714dad72a84354266 Mon Sep 17 00:00:00 2001
From: salano_ym <53254905+salano-ym@users.noreply.github.com>
Date: Thu, 25 Apr 2024 16:59:24 +0000
Subject: [PATCH 25/47] fix CHANGELOG.md
---
CHANGELOG.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a654335e..b52626fb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,7 @@
[Read translated version (en)](./translations/en/CHANGELOG.md)
# 未リリース分
+- `arr.splice`を追加
# 0.18.0
- `Core:abort`でプログラムを緊急停止できるように
@@ -14,7 +15,6 @@
- ネストされた名前空間下の変数を参照できるように
- `arr.every`, `arr.some`を追加
- `Date:to_iso_str`を追加
-- `arr.splice`を追加
# 0.17.0
- `package.json`を修正
From c982c39aacb0e359bb581ee4286fa43eb3648b68 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 25 Apr 2024 19:13:03 +0000
Subject: [PATCH 26/47] Bump actions/checkout from 4.1.3 to 4.1.4 in the
gh-actions group
Bumps the gh-actions group with 1 update: [actions/checkout](https://github.com/actions/checkout).
Updates `actions/checkout` from 4.1.3 to 4.1.4
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4.1.3...v4.1.4)
---
updated-dependencies:
- dependency-name: actions/checkout
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: gh-actions
...
Signed-off-by: dependabot[bot]
---
.github/workflows/api.yml | 2 +-
.github/workflows/gh-pages.yml | 2 +-
.github/workflows/lint.yml | 2 +-
.github/workflows/publish-nightly-dev.yml | 2 +-
.github/workflows/publish-nightly-next.yml | 2 +-
.github/workflows/test.yml | 2 +-
6 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/.github/workflows/api.yml b/.github/workflows/api.yml
index e2e714e0..338ccf10 100644
--- a/.github/workflows/api.yml
+++ b/.github/workflows/api.yml
@@ -14,7 +14,7 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v4.1.3
+ uses: actions/checkout@v4.1.4
- name: Setup Node.js
uses: actions/setup-node@v4.0.2
diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml
index 00064d0f..622154b9 100644
--- a/.github/workflows/gh-pages.yml
+++ b/.github/workflows/gh-pages.yml
@@ -12,7 +12,7 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v4.1.3
+ uses: actions/checkout@v4.1.4
- name: Setup Node.js
uses: actions/setup-node@v4.0.2
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index ea4397af..a659fbbf 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -14,7 +14,7 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v4.1.3
+ uses: actions/checkout@v4.1.4
- name: Setup Node.js
uses: actions/setup-node@v4.0.2
diff --git a/.github/workflows/publish-nightly-dev.yml b/.github/workflows/publish-nightly-dev.yml
index 7402073d..688a7485 100644
--- a/.github/workflows/publish-nightly-dev.yml
+++ b/.github/workflows/publish-nightly-dev.yml
@@ -15,7 +15,7 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v4.1.3
+ uses: actions/checkout@v4.1.4
with:
ref: ${{ env.BRANCH }}
diff --git a/.github/workflows/publish-nightly-next.yml b/.github/workflows/publish-nightly-next.yml
index 224fb9ae..f041b9e9 100644
--- a/.github/workflows/publish-nightly-next.yml
+++ b/.github/workflows/publish-nightly-next.yml
@@ -15,7 +15,7 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v4.1.3
+ uses: actions/checkout@v4.1.4
with:
ref: ${{ env.BRANCH }}
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index f4c95cc0..3f2eb121 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -18,7 +18,7 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v4.1.3
+ uses: actions/checkout@v4.1.4
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4.0.2
From ef711609ec283f5b20b2027787038445ed2ce541 Mon Sep 17 00:00:00 2001
From: salano_ym <53254905+salano-ym@users.noreply.github.com>
Date: Fri, 3 May 2024 07:40:18 +0000
Subject: [PATCH 27/47] add test Date: - Date:year - Date:month - Date:day -
Date:hour - Date:minute - Date:second - Date:millisecond
---
test/index.ts | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 49 insertions(+)
diff --git a/test/index.ts b/test/index.ts
index 290efa73..29873c4c 100644
--- a/test/index.ts
+++ b/test/index.ts
@@ -3187,6 +3187,55 @@ describe('std', () => {
});
describe('Date', () => {
+ test.concurrent('year', async () => {
+ const res = await exe(`
+ <: [Date:year(0), Date:year(1714946889010)]
+ `);
+ eq(res.value, [NUM(1970), NUM(2024)]);
+ });
+
+ test.concurrent('month', async () => {
+ const res = await exe(`
+ <: [Date:month(0), Date:month(1714946889010)]
+ `);
+ eq(res.value, [NUM(1), NUM(5)]);
+ });
+
+ test.concurrent('day', async () => {
+ const res = await exe(`
+ <: [Date:day(0), Date:day(1714946889010)]
+ `);
+ eq(res.value, [NUM(1), NUM(6)]);
+ });
+
+ test.concurrent('hour', async () => {
+ const res = await exe(`
+ <: [Date:hour(0), Date:hour(1714946889010)]
+ `);
+ eq(res.value, [NUM(0), NUM(7)]);
+ });
+
+ test.concurrent('minute', async () => {
+ const res = await exe(`
+ <: [Date:minute(0), Date:minute(1714946889010)]
+ `);
+ eq(res.value, [NUM(0), NUM(8)]);
+ });
+
+ test.concurrent('second', async () => {
+ const res = await exe(`
+ <: [Date:second(0), Date:second(1714946889010)]
+ `);
+ eq(res.value, [NUM(0), NUM(9)]);
+ });
+
+ test.concurrent('millisecond', async () => {
+ const res = await exe(`
+ <: [Date:millisecond(0), Date:millisecond(1714946889010)]
+ `);
+ eq(res.value, [NUM(0), NUM(10)]);
+ });
+
test.concurrent('to_iso_str', async () => {
const res = await exe(`
let d1 = Date:parse("2024-04-12T01:47:46.021+09:00")
From 769764a995e69d42b59bf24c89e2f316e741ad84 Mon Sep 17 00:00:00 2001
From: salano_ym <53254905+salano-ym@users.noreply.github.com>
Date: Fri, 3 May 2024 07:40:50 +0000
Subject: [PATCH 28/47] replace || -> ??
---
src/interpreter/lib/std.ts | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/src/interpreter/lib/std.ts b/src/interpreter/lib/std.ts
index 33daec7d..b3d5081d 100644
--- a/src/interpreter/lib/std.ts
+++ b/src/interpreter/lib/std.ts
@@ -183,37 +183,37 @@ export const std: Record = {
'Date:year': FN_NATIVE(([v]) => {
if (v) { assertNumber(v); }
- return NUM(new Date(v?.value || Date.now()).getFullYear());
+ return NUM(new Date(v?.value ?? Date.now()).getFullYear());
}),
'Date:month': FN_NATIVE(([v]) => {
if (v) { assertNumber(v); }
- return NUM(new Date(v?.value || Date.now()).getMonth() + 1);
+ return NUM(new Date(v?.value ?? Date.now()).getMonth() + 1);
}),
'Date:day': FN_NATIVE(([v]) => {
if (v) { assertNumber(v); }
- return NUM(new Date(v?.value || Date.now()).getDate());
+ return NUM(new Date(v?.value ?? Date.now()).getDate());
}),
'Date:hour': FN_NATIVE(([v]) => {
if (v) { assertNumber(v); }
- return NUM(new Date(v?.value || Date.now()).getHours());
+ return NUM(new Date(v?.value ?? Date.now()).getHours());
}),
'Date:minute': FN_NATIVE(([v]) => {
if (v) { assertNumber(v); }
- return NUM(new Date(v?.value || Date.now()).getMinutes());
+ return NUM(new Date(v?.value ?? Date.now()).getMinutes());
}),
'Date:second': FN_NATIVE(([v]) => {
if (v) { assertNumber(v); }
- return NUM(new Date(v?.value || Date.now()).getSeconds());
+ return NUM(new Date(v?.value ?? Date.now()).getSeconds());
}),
'Date:millisecond': FN_NATIVE(([v]) => {
if (v) { assertNumber(v); }
- return NUM(new Date(v?.value || Date.now()).getMilliseconds());
+ return NUM(new Date(v?.value ?? Date.now()).getMilliseconds());
}),
'Date:parse': FN_NATIVE(([v]) => {
From 19225bbd9a39b104f0b2fcdee5350d180bc9980f Mon Sep 17 00:00:00 2001
From: salano_ym <53254905+salano-ym@users.noreply.github.com>
Date: Fri, 3 May 2024 07:41:05 +0000
Subject: [PATCH 29/47] update CHAGELOG.md
---
CHANGELOG.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0fabbc0d..65c55b48 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,7 @@
[Read translated version (en)](./translations/en/CHANGELOG.md)
# 未リリース分
+- `Date:year`系の関数に0を渡すと現在時刻になる問題を修正
# 0.18.0
- `Core:abort`でプログラムを緊急停止できるように
From 5c885520aad753e93a7496187407998e5b5b2ab5 Mon Sep 17 00:00:00 2001
From: uzmoi
Date: Mon, 6 May 2024 18:16:21 +0900
Subject: [PATCH 30/47] =?UTF-8?q?fix:=20=E4=BD=8D=E7=BD=AE=E6=83=85?=
=?UTF-8?q?=E5=A0=B1=E3=82=92=E4=BF=AE=E6=AD=A3=20(#648)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* fix: 位置情報を修正
* changelog
* add test for location
---
CHANGELOG.md | 3 ++-
src/parser/parser.peggy | 5 ++---
test/index.ts | 14 ++++++++++++++
3 files changed, 18 insertions(+), 4 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 65c55b48..5ef6934a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,7 @@
# 未リリース分
- `Date:year`系の関数に0を渡すと現在時刻になる問題を修正
+- シンタックスエラーなどの位置情報を修正
# 0.18.0
- `Core:abort`でプログラムを緊急停止できるように
@@ -128,4 +129,4 @@
- 空の関数を定義できない問題を修正
- 空のスクリプトが許可されていない問題を修正
- ネームスペース付き変数のインクリメント、デクリメントを修正
-- ネームスペース付き変数への代入ができない問題を修正
+- ネームスペース付き変数への代入ができない問題を修正
diff --git a/src/parser/parser.peggy b/src/parser/parser.peggy
index 4aacdbeb..7a95e63e 100644
--- a/src/parser/parser.peggy
+++ b/src/parser/parser.peggy
@@ -28,9 +28,8 @@ PreprocessPart
/ .
Comment
- = "//" (!EOL .)* { return ''; }
- / "/*" (!"*/" .)* "*/" { return ''; }
-
+ = "//" (!EOL .)* { return ' '.repeat(text().length); }
+ / "/*" (!"*/" .)* "*/" { return text().replace(/[^\n]/g, ' '); }
//
// main parser
diff --git a/test/index.ts b/test/index.ts
index 29873c4c..fed26c01 100644
--- a/test/index.ts
+++ b/test/index.ts
@@ -2399,6 +2399,20 @@ describe('Location', () => {
if (!node.loc) assert.fail();
assert.deepEqual(node.loc, { start: 3, end: 13 });
});
+ test.concurrent('comment', async () => {
+ let node: Ast.Node;
+ const parser = new Parser();
+ const nodes = parser.parse(`
+ /*
+ */
+ // hoge
+ @f(a) { a }
+ `);
+ assert.equal(nodes.length, 1);
+ node = nodes[0];
+ if (!node.loc) assert.fail();
+ assert.deepEqual(node.loc, { start: 23, end: 33 });
+ });
});
describe('Variable declaration', () => {
From dc7bfa370d9748c40363d7e63c1d8bf952da0d9f Mon Sep 17 00:00:00 2001
From: uzmoi
Date: Mon, 6 May 2024 18:16:57 +0900
Subject: [PATCH 31/47] =?UTF-8?q?=E4=BA=8C=E9=A0=85=E6=BC=94=E7=AE=97?=
=?UTF-8?q?=E5=AD=90=E3=81=ABLoc=E3=82=92=E8=BF=BD=E5=8A=A0=20(#647)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* call, and, orノードにlocを追加
* InfixにoperatorLocsプロパティーを追加
* 糖衣構文の二項演算子のノードにlocを追加
* and, orノードにlocを追加
* refactor
* 型エイリアスを使用
---
etc/aiscript.api.md | 7 +++-
src/node.ts | 2 ++
src/parser/node.ts | 10 +++---
src/parser/parser.peggy | 11 +++++--
src/parser/plugins/infix-to-fncall.ts | 47 ++++++++++++++++++---------
5 files changed, 55 insertions(+), 22 deletions(-)
diff --git a/etc/aiscript.api.md b/etc/aiscript.api.md
index b35a710b..f94fdf10 100644
--- a/etc/aiscript.api.md
+++ b/etc/aiscript.api.md
@@ -72,6 +72,7 @@ type And = NodeBase & {
type: 'and';
left: Expression;
right: Expression;
+ operatorLoc: Loc;
};
// @public (undocumented)
@@ -79,6 +80,7 @@ type And_2 = NodeBase_2 & {
type: 'and';
left: Expression_2;
right: Expression_2;
+ operatorLoc: Loc;
};
// @public (undocumented)
@@ -556,6 +558,7 @@ type Infix = NodeBase_2 & {
type: 'infix';
operands: Expression_2[];
operators: InfixOperator[];
+ operatorLocs: Loc[];
};
// @public (undocumented)
@@ -706,7 +709,7 @@ type Namespace_2 = NodeBase_2 & {
// @public (undocumented)
type Node_2 = Namespace | Meta | Statement | Expression | TypeSource;
-// @public
+// @public (undocumented)
type Node_3 = Namespace_2 | Meta_2 | Statement_2 | Expression_2 | ChainMember | TypeSource_2;
// @public
@@ -778,6 +781,7 @@ type Or = NodeBase & {
type: 'or';
left: Expression;
right: Expression;
+ operatorLoc: Loc;
};
// @public (undocumented)
@@ -785,6 +789,7 @@ type Or_2 = NodeBase_2 & {
type: 'or';
left: Expression_2;
right: Expression_2;
+ operatorLoc: Loc;
};
// @public (undocumented)
diff --git a/src/node.ts b/src/node.ts
index 79153c10..aebff7de 100644
--- a/src/node.ts
+++ b/src/node.ts
@@ -153,12 +153,14 @@ export type And = NodeBase & {
type: 'and';
left: Expression;
right: Expression;
+ operatorLoc: Loc;
}
export type Or = NodeBase & {
type: 'or';
left: Expression;
right: Expression;
+ operatorLoc: Loc;
}
export type If = NodeBase & {
diff --git a/src/parser/node.ts b/src/parser/node.ts
index b9a2dd77..a165a08d 100644
--- a/src/parser/node.ts
+++ b/src/parser/node.ts
@@ -6,6 +6,8 @@
* この処理結果がプラグインによって処理されるとASTノードとなります。
*/
+import type { Loc } from '../node.js';
+
export type Node = Namespace | Meta | Statement | Expression | ChainMember | TypeSource;
export type Statement =
@@ -59,10 +61,7 @@ export function isExpression(x: Node): x is Expression {
type NodeBase = {
__AST_NODE: never; // phantom type
- loc?: {
- start: number;
- end: number;
- };
+ loc?: Loc;
};
export type Namespace = NodeBase & {
@@ -150,6 +149,7 @@ export type Infix = NodeBase & {
type: 'infix';
operands: Expression[];
operators: InfixOperator[];
+ operatorLocs: Loc[];
};
export type Not = NodeBase & {
@@ -161,12 +161,14 @@ export type And = NodeBase & {
type: 'and';
left: Expression;
right: Expression;
+ operatorLoc: Loc;
}
export type Or = NodeBase & {
type: 'or';
left: Expression;
right: Expression;
+ operatorLoc: Loc;
}
export type If = NodeBase & {
diff --git a/src/parser/parser.peggy b/src/parser/parser.peggy
index 7a95e63e..0a9b27b2 100644
--- a/src/parser/parser.peggy
+++ b/src/parser/parser.peggy
@@ -282,7 +282,8 @@ Infix
{
return createNode('infix', {
operands: [head, ...tail.map(i => i.term)],
- operators: tail.map(i => i.op)
+ operators: tail.map(i => i.op.value),
+ operatorLocs: tail.map(i => i.op.loc),
});
}
@@ -292,7 +293,13 @@ InfixSp
Op
= ("||" / "&&" / "==" / "!=" / "<=" / ">=" / "<" / ">" / "+" / "-" / "*" / "^" / "/" / "%")
-{ return text(); }
+{
+ const loc = location();
+ return {
+ value: text(),
+ loc: { start: loc.start.offset, end: loc.end.offset - 1 },
+ };
+}
Not
= "!" expr:Expr
diff --git a/src/parser/plugins/infix-to-fncall.ts b/src/parser/plugins/infix-to-fncall.ts
index 7d551320..d75dd4d2 100644
--- a/src/parser/plugins/infix-to-fncall.ts
+++ b/src/parser/plugins/infix-to-fncall.ts
@@ -1,6 +1,7 @@
import { visitNode } from '../visit.js';
import { AiScriptSyntaxError } from '../../error.js';
import type * as Cst from '../node.js';
+import type { Loc } from '../../node.js';
/**
* 中置演算子式を表す木
@@ -15,6 +16,7 @@ type InfixTree = {
left: InfixTree | Cst.Node;
right: InfixTree | Cst.Node;
info: {
+ opLoc: Loc;
priority: number; // 優先度(高いほど優先して計算される値)
} & ({
func: string; // 対応する関数名
@@ -76,15 +78,18 @@ function treeToNode(tree: InfixTree | Cst.Node): Cst.Node {
if (tree.info.mapFn) {
return tree.info.mapFn(tree);
} else {
+ const left = treeToNode(tree.left);
+ const right = treeToNode(tree.right);
return {
type: 'call',
- target: { type: 'identifier', name: tree.info.func },
- args: [treeToNode(tree.left), treeToNode(tree.right)],
+ target: { type: 'identifier', name: tree.info.func, loc: tree.info.opLoc },
+ args: [left, right],
+ loc: { start: left.loc!.start,end: right.loc!.end },
} as Cst.Call;
}
}
-const infoTable: Record = {
+const infoTable: Record> = {
'*': { func: 'Core:mul', priority: 7 },
'^': { func: 'Core:pow', priority: 7 },
'/': { func: 'Core:div', priority: 7 },
@@ -98,19 +103,31 @@ const infoTable: Record = {
'<=': { func: 'Core:lteq', priority: 4 },
'>=': { func: 'Core:gteq', priority: 4 },
'&&': {
- mapFn: infix => ({
- type: 'and',
- left: treeToNode(infix.left),
- right: treeToNode(infix.right),
- }) as Cst.And,
+ mapFn: infix => {
+ const left = treeToNode(infix.left);
+ const right = treeToNode(infix.right);
+ return {
+ type: 'and',
+ left,
+ right,
+ loc: { start: left.loc!.start, end: right.loc!.end },
+ operatorLoc: infix.info.opLoc,
+ } as Cst.And;
+ },
priority: 3,
},
'||': {
- mapFn: infix => ({
- type: 'or',
- left: treeToNode(infix.left),
- right: treeToNode(infix.right),
- }) as Cst.Or,
+ mapFn: infix => {
+ const left = treeToNode(infix.left);
+ const right = treeToNode(infix.right);
+ return {
+ type: 'or',
+ left,
+ right,
+ loc: { start: left.loc!.start, end: right.loc!.end },
+ operatorLoc: infix.info.opLoc,
+ } as Cst.Or;
+ },
priority: 3,
},
};
@@ -119,12 +136,12 @@ const infoTable: Record = {
* NInfix を関数呼び出し形式に変換する
*/
function transform(node: Cst.Infix): Cst.Node {
- const infos = node.operators.map(op => {
+ const infos = node.operators.map((op, i) => {
const info = infoTable[op];
if (info == null) {
throw new AiScriptSyntaxError(`No such operator: ${op}.`);
}
- return info;
+ return { ...info, opLoc: node.operatorLocs[i] } as InfixTree['info'];
});
let currTree = INFIX_TREE(node.operands[0]!, node.operands[1]!, infos[0]!);
for (let i = 0; i < infos.length - 1; i++) {
From 5e135c7985670ef4add47d832844cfeef56f2d2f Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 6 May 2024 19:38:17 +0000
Subject: [PATCH 32/47] Bump actions/checkout from 4.1.4 to 4.1.5 in the
gh-actions group
Bumps the gh-actions group with 1 update: [actions/checkout](https://github.com/actions/checkout).
Updates `actions/checkout` from 4.1.4 to 4.1.5
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4.1.4...v4.1.5)
---
updated-dependencies:
- dependency-name: actions/checkout
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: gh-actions
...
Signed-off-by: dependabot[bot]
---
.github/workflows/api.yml | 2 +-
.github/workflows/gh-pages.yml | 2 +-
.github/workflows/lint.yml | 2 +-
.github/workflows/publish-nightly-dev.yml | 2 +-
.github/workflows/publish-nightly-next.yml | 2 +-
.github/workflows/test.yml | 2 +-
6 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/.github/workflows/api.yml b/.github/workflows/api.yml
index 338ccf10..0a912e4f 100644
--- a/.github/workflows/api.yml
+++ b/.github/workflows/api.yml
@@ -14,7 +14,7 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v4.1.4
+ uses: actions/checkout@v4.1.5
- name: Setup Node.js
uses: actions/setup-node@v4.0.2
diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml
index 622154b9..d1b88410 100644
--- a/.github/workflows/gh-pages.yml
+++ b/.github/workflows/gh-pages.yml
@@ -12,7 +12,7 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v4.1.4
+ uses: actions/checkout@v4.1.5
- name: Setup Node.js
uses: actions/setup-node@v4.0.2
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index a659fbbf..a3eb5538 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -14,7 +14,7 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v4.1.4
+ uses: actions/checkout@v4.1.5
- name: Setup Node.js
uses: actions/setup-node@v4.0.2
diff --git a/.github/workflows/publish-nightly-dev.yml b/.github/workflows/publish-nightly-dev.yml
index 688a7485..caff8cd9 100644
--- a/.github/workflows/publish-nightly-dev.yml
+++ b/.github/workflows/publish-nightly-dev.yml
@@ -15,7 +15,7 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v4.1.4
+ uses: actions/checkout@v4.1.5
with:
ref: ${{ env.BRANCH }}
diff --git a/.github/workflows/publish-nightly-next.yml b/.github/workflows/publish-nightly-next.yml
index f041b9e9..62110872 100644
--- a/.github/workflows/publish-nightly-next.yml
+++ b/.github/workflows/publish-nightly-next.yml
@@ -15,7 +15,7 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v4.1.4
+ uses: actions/checkout@v4.1.5
with:
ref: ${{ env.BRANCH }}
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 3f2eb121..3e285926 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -18,7 +18,7 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v4.1.4
+ uses: actions/checkout@v4.1.5
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4.0.2
From 1e67f131e678e3a976034e06e6a0b16c7fac80ac Mon Sep 17 00:00:00 2001
From: salano_ym <53254905+salano-ym@users.noreply.github.com>
Date: Thu, 9 May 2024 07:40:22 +0000
Subject: [PATCH 33/47] =?UTF-8?q?str.starts=5Fwith=E3=82=92=E8=BF=BD?=
=?UTF-8?q?=E5=8A=A0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
CHANGELOG.md | 1 +
docs/primitive-props.md | 7 +++++
src/interpreter/primitive-props.ts | 15 +++++++++++
test/index.ts | 42 ++++++++++++++++++++++++++++++
4 files changed, 65 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5ef6934a..f004b87c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,7 @@
# 未リリース分
- `Date:year`系の関数に0を渡すと現在時刻になる問題を修正
- シンタックスエラーなどの位置情報を修正
+- `str.starts_with`を追加
# 0.18.0
- `Core:abort`でプログラムを緊急停止できるように
diff --git a/docs/primitive-props.md b/docs/primitive-props.md
index 609cc6ee..233b155c 100644
--- a/docs/primitive-props.md
+++ b/docs/primitive-props.md
@@ -62,6 +62,13 @@ Core:range(0,2).push(4) //[0,1,2,4]
### @(_v_: str).incl(_keyword_: str): bool
文字列中に _keyword_ が含まれていれば`true`、なければ`false`を返します。
+### @(_v_: str).starts_with(_prefix_: str, _start\_index_?: num): bool
+文字列が _prefix_ で始まっていれば`true`、そうでなければ`false`を返します。\
+_prefix_ が空文字列の場合は常に`true`を返します。\
+_start\_index_ が指定されている場合、そのインデックスから始めます。\
+_start\_index_ が`v_.len`より大きいか`-v.len`より小さい場合は`false`を返します。\
+_start\_index_ が負の場合は末尾から数えます。
+
### @(_v_: str).slice(_begin_: num, _end_: num): str
文字列の _begin_ 番目から _end_ 番目の直前までの部分を取得します。
diff --git a/src/interpreter/primitive-props.ts b/src/interpreter/primitive-props.ts
index c154c45a..2fa34826 100644
--- a/src/interpreter/primitive-props.ts
+++ b/src/interpreter/primitive-props.ts
@@ -119,6 +119,21 @@ const PRIMITIVE_PROPS: {
const res = target.value.codePointAt(i.value) ?? target.value.charCodeAt(i.value);
return Number.isNaN(res) ? NULL : NUM(res);
}),
+
+ starts_with: (target: VStr): VFn => FN_NATIVE(async ([prefix, start_index], _opts) => {
+ assertString(prefix);
+ if (!prefix.value) {
+ return TRUE;
+ }
+
+ if (start_index) assertNumber(start_index);
+ const raw_index = start_index?.value ?? 0;
+ if (raw_index < -target.value.length || raw_index > target.value.length) {
+ return FALSE;
+ }
+ const index = (raw_index >= 0) ? raw_index : target.value.length + raw_index;
+ return target.value.startsWith(prefix.value, index) ? TRUE : FALSE;
+ }),
},
arr: {
diff --git a/test/index.ts b/test/index.ts
index fed26c01..cb5f6250 100644
--- a/test/index.ts
+++ b/test/index.ts
@@ -2626,6 +2626,48 @@ describe('primitive props', () => {
ARR([NUM(97), NUM(98), NUM(99), NUM(240), NUM(169), NUM(184), NUM(189), NUM(240), NUM(159), NUM(145), NUM(137), NUM(240), NUM(159), NUM(143), NUM(191), NUM(240), NUM(159), NUM(145), NUM(168), NUM(226), NUM(128), NUM(141), NUM(240), NUM(159), NUM(145), NUM(166), NUM(100), NUM(101), NUM(102)])
);
});
+
+ test.concurrent('starts_with (no index)', async () => {
+ const res = await exe(`
+ let str = "hello"
+ let empty = ""
+ <: [
+ str.starts_with(""), str.starts_with("hello"),
+ str.starts_with("he"), str.starts_with("ell"),
+ empty.starts_with(""), empty.starts_with("he"),
+ ]
+ `);
+ eq(res, ARR([
+ TRUE, TRUE,
+ TRUE, FALSE,
+ TRUE, FALSE,
+ ]));
+ });
+
+ test.concurrent('starts_with (with index)', async () => {
+ const res = await exe(`
+ let str = "hello"
+ let empty = ""
+ <: [
+ str.starts_with("", 4), str.starts_with("he", 0),
+ str.starts_with("ll", 2), str.starts_with("lo", 3),
+ str.starts_with("lo", -2), str.starts_with("hel", -5),
+ str.starts_with("he", 2), str.starts_with("loa", 3),
+ str.starts_with("lo", -6), str.starts_with("", -7),
+ str.starts_with("lo", 6), str.starts_with("", 7),
+ empty.starts_with("", 2), empty.starts_with("ll", 2),
+ ]
+ `);
+ eq(res, ARR([
+ TRUE, TRUE,
+ TRUE, TRUE,
+ TRUE, TRUE,
+ FALSE, FALSE,
+ FALSE, TRUE,
+ FALSE, TRUE,
+ TRUE, FALSE,
+ ]));
+ });
});
describe('arr', () => {
From 32c6a4000d44539a45add9e1e5fbde5cac1f1239 Mon Sep 17 00:00:00 2001
From: salano_ym <53254905+salano-ym@users.noreply.github.com>
Date: Thu, 9 May 2024 07:40:53 +0000
Subject: [PATCH 34/47] =?UTF-8?q?str.ends=5Fwith=E3=82=92=E8=BF=BD?=
=?UTF-8?q?=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 | 7 +++++
src/interpreter/primitive-props.ts | 16 ++++++++++++
test/index.ts | 42 ++++++++++++++++++++++++++++++
4 files changed, 66 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f004b87c..bbdb8a1c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,7 +3,7 @@
# 未リリース分
- `Date:year`系の関数に0を渡すと現在時刻になる問題を修正
- シンタックスエラーなどの位置情報を修正
-- `str.starts_with`を追加
+- `str.starts_with`,`str.ends_with`を追加
# 0.18.0
- `Core:abort`でプログラムを緊急停止できるように
diff --git a/docs/primitive-props.md b/docs/primitive-props.md
index 233b155c..eaa27c63 100644
--- a/docs/primitive-props.md
+++ b/docs/primitive-props.md
@@ -69,6 +69,13 @@ _start\_index_ が指定されている場合、そのインデックスから
_start\_index_ が`v_.len`より大きいか`-v.len`より小さい場合は`false`を返します。\
_start\_index_ が負の場合は末尾から数えます。
+### @(_v_: str).ends_with(_suffix_: str, _end\_index_?: num): bool
+文字列が _suffix_ で終わっていれば`true`、そうでなければ`false`を返します。\
+_suffix_ が空文字列の場合は常に`true`を返します。\
+_end\_index_ が指定されている場合、そのインデックスの直前を末尾とします。\
+_end\_index_ が`v_.len`より大きいか`-v.len`より小さい場合は`false`を返します。\
+_end\_index_ が負の場合は末尾から数えます。
+
### @(_v_: str).slice(_begin_: num, _end_: num): str
文字列の _begin_ 番目から _end_ 番目の直前までの部分を取得します。
diff --git a/src/interpreter/primitive-props.ts b/src/interpreter/primitive-props.ts
index 2fa34826..a5881f14 100644
--- a/src/interpreter/primitive-props.ts
+++ b/src/interpreter/primitive-props.ts
@@ -134,6 +134,22 @@ const PRIMITIVE_PROPS: {
const index = (raw_index >= 0) ? raw_index : target.value.length + raw_index;
return target.value.startsWith(prefix.value, index) ? TRUE : FALSE;
}),
+
+ ends_with: (target: VStr): VFn => FN_NATIVE(async ([suffix, end_index], _opts) => {
+ assertString(suffix);
+ if (!suffix.value) {
+ return TRUE;
+ }
+
+ if (end_index) assertNumber(end_index);
+ const raw_index = end_index?.value ?? target.value.length;
+ if (raw_index < -target.value.length || raw_index > target.value.length) {
+ return FALSE;
+ }
+ const index = (raw_index >= 0) ? raw_index : target.value.length + raw_index;
+
+ return target.value.endsWith(suffix.value, index) ? TRUE : FALSE;
+ }),
},
arr: {
diff --git a/test/index.ts b/test/index.ts
index cb5f6250..7a21ee59 100644
--- a/test/index.ts
+++ b/test/index.ts
@@ -2668,6 +2668,48 @@ describe('primitive props', () => {
TRUE, FALSE,
]));
});
+
+ test.concurrent('ends_with (no index)', async () => {
+ const res = await exe(`
+ let str = "hello"
+ let empty = ""
+ <: [
+ str.ends_with(""), str.ends_with("hello"),
+ str.ends_with("lo"), str.ends_with("ell"),
+ empty.ends_with(""), empty.ends_with("he"),
+ ]
+ `);
+ eq(res, ARR([
+ TRUE, TRUE,
+ TRUE, FALSE,
+ TRUE, FALSE,
+ ]));
+ });
+
+ test.concurrent('ends_with (with index)', async () => {
+ const res = await exe(`
+ let str = "hello"
+ let empty = ""
+ <: [
+ str.ends_with("", 3), str.ends_with("lo", 5),
+ str.ends_with("ll", 4), str.ends_with("he", 2),
+ str.ends_with("ll", -1), str.ends_with("he", -3),
+ str.ends_with("he", 5), str.ends_with("lo", 3),
+ str.ends_with("lo", -6), str.ends_with("", -7),
+ str.ends_with("lo", 6), str.ends_with("", 7),
+ empty.ends_with("", 2), empty.ends_with("ll", 2),
+ ]
+ `);
+ eq(res, ARR([
+ TRUE, TRUE,
+ TRUE, TRUE,
+ TRUE, TRUE,
+ FALSE, FALSE,
+ FALSE, TRUE,
+ FALSE, TRUE,
+ TRUE, FALSE,
+ ]));
+ });
});
describe('arr', () => {
From 11e5f013104a2003b71ae8bc1eedc0d3f701780e Mon Sep 17 00:00:00 2001
From: salano_ym <53254905+salano-ym@users.noreply.github.com>
Date: Thu, 9 May 2024 13:07:05 +0000
Subject: [PATCH 35/47] fix docs/primitive-props.md - str.starts_with -
str.ends_with
---
docs/primitive-props.md | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/docs/primitive-props.md b/docs/primitive-props.md
index eaa27c63..2e797c79 100644
--- a/docs/primitive-props.md
+++ b/docs/primitive-props.md
@@ -66,14 +66,14 @@ Core:range(0,2).push(4) //[0,1,2,4]
文字列が _prefix_ で始まっていれば`true`、そうでなければ`false`を返します。\
_prefix_ が空文字列の場合は常に`true`を返します。\
_start\_index_ が指定されている場合、そのインデックスから始めます。\
-_start\_index_ が`v_.len`より大きいか`-v.len`より小さい場合は`false`を返します。\
+_start\_index_ が`v.len`より大きいか`-v.len`より小さい場合は`false`を返します。\
_start\_index_ が負の場合は末尾から数えます。
### @(_v_: str).ends_with(_suffix_: str, _end\_index_?: num): bool
文字列が _suffix_ で終わっていれば`true`、そうでなければ`false`を返します。\
_suffix_ が空文字列の場合は常に`true`を返します。\
-_end\_index_ が指定されている場合、そのインデックスの直前を末尾とします。\
-_end\_index_ が`v_.len`より大きいか`-v.len`より小さい場合は`false`を返します。\
+_end\_index_ が指定されている場合、そのインデックスの直前を末尾とします。(省略時は`v.len`)\
+_end\_index_ が`v.len`より大きいか`-v.len`より小さい場合は`false`を返します。\
_end\_index_ が負の場合は末尾から数えます。
### @(_v_: str).slice(_begin_: num, _end_: num): str
From 427a6d8453dcd4d28d1de9c120a4a90c54c6776e Mon Sep 17 00:00:00 2001
From: salano_ym <53254905+salano-ym@users.noreply.github.com>
Date: Thu, 9 May 2024 14:44:40 +0000
Subject: [PATCH 36/47] =?UTF-8?q?str.pad=5Fstart=E3=82=92=E8=BF=BD?=
=?UTF-8?q?=E5=8A=A0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
CHANGELOG.md | 1 +
docs/primitive-props.md | 5 +++++
src/interpreter/primitive-props.ts | 7 +++++++
test/index.ts | 16 ++++++++++++++++
4 files changed, 29 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5ef6934a..57e5b9db 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,7 @@
# 未リリース分
- `Date:year`系の関数に0を渡すと現在時刻になる問題を修正
- シンタックスエラーなどの位置情報を修正
+- `str.pad_start`を追加
# 0.18.0
- `Core:abort`でプログラムを緊急停止できるように
diff --git a/docs/primitive-props.md b/docs/primitive-props.md
index 609cc6ee..90e57528 100644
--- a/docs/primitive-props.md
+++ b/docs/primitive-props.md
@@ -78,6 +78,11 @@ _fromIndex_が指定されていれば、その位置から検索を開始しま
_fromIndex_が負値の時は末尾からの位置(文字列の長さ+_fromIndex_)が使用されます。
該当が無ければ-1を返します。
+### @(_v_: str).pad_start(_width_: num, _pad_?: str): str
+文字列の長さがが _width_ になるように、先頭を _pad_ の繰り返しで埋めた新しい文字列を返します。\
+_pad_ を省略した場合、空白`' '`で埋められます。\
+_pad_ が長すぎる場合、_pad_ の末尾が切り捨てられます。
+
### @(_v_: str).trim(): str
文字列の前後の空白を取り除いたものを返します。
diff --git a/src/interpreter/primitive-props.ts b/src/interpreter/primitive-props.ts
index c154c45a..2c68d8e9 100644
--- a/src/interpreter/primitive-props.ts
+++ b/src/interpreter/primitive-props.ts
@@ -119,6 +119,13 @@ const PRIMITIVE_PROPS: {
const res = target.value.codePointAt(i.value) ?? target.value.charCodeAt(i.value);
return Number.isNaN(res) ? NULL : NUM(res);
}),
+
+ pad_start: (target: VStr): VFn => FN_NATIVE(([width, pad], _) => {
+ assertNumber(width);
+ const s = (pad) ? (assertString(pad), pad.value) : ' ';
+
+ return STR(target.value.padStart(width.value, s));
+ }),
},
arr: {
diff --git a/test/index.ts b/test/index.ts
index fed26c01..b290296e 100644
--- a/test/index.ts
+++ b/test/index.ts
@@ -2626,6 +2626,22 @@ describe('primitive props', () => {
ARR([NUM(97), NUM(98), NUM(99), NUM(240), NUM(169), NUM(184), NUM(189), NUM(240), NUM(159), NUM(145), NUM(137), NUM(240), NUM(159), NUM(143), NUM(191), NUM(240), NUM(159), NUM(145), NUM(168), NUM(226), NUM(128), NUM(141), NUM(240), NUM(159), NUM(145), NUM(166), NUM(100), NUM(101), NUM(102)])
);
});
+
+ test.concurrent("pad_start", async () => {
+ const res = await exe(`
+ let str = "abc"
+ <: [
+ str.pad_start(0), str.pad_start(1), str.pad_start(2), str.pad_start(3), str.pad_start(4), str.pad_start(5),
+ str.pad_start(0, "0"), str.pad_start(1, "0"), str.pad_start(2, "0"), str.pad_start(3, "0"), str.pad_start(4, "0"), str.pad_start(5, "0"),
+ str.pad_start(0, "01"), str.pad_start(1, "01"), str.pad_start(2, "01"), str.pad_start(3, "01"), str.pad_start(4, "01"), str.pad_start(5, "01"),
+ ]
+ `);
+ eq(res, ARR([
+ STR("abc"), STR("abc"), STR("abc"), STR("abc"), STR(" abc"), STR(" abc"),
+ STR("abc"), STR("abc"), STR("abc"), STR("abc"), STR("0abc"), STR("00abc"),
+ STR("abc"), STR("abc"), STR("abc"), STR("abc"), STR("0abc"), STR("01abc"),
+ ]));
+ });
});
describe('arr', () => {
From e1b3a22aacb4cd71ca3b60f48935c0b331c4cf64 Mon Sep 17 00:00:00 2001
From: salano_ym <53254905+salano-ym@users.noreply.github.com>
Date: Thu, 9 May 2024 14:49:17 +0000
Subject: [PATCH 37/47] =?UTF-8?q?str.pad=5Fend=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 | 5 +++++
src/interpreter/primitive-props.ts | 7 +++++++
test/index.ts | 16 ++++++++++++++++
4 files changed, 29 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 57e5b9db..385bde1f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,7 +3,7 @@
# 未リリース分
- `Date:year`系の関数に0を渡すと現在時刻になる問題を修正
- シンタックスエラーなどの位置情報を修正
-- `str.pad_start`を追加
+- `str.pad_start`,`str.pad_end`を追加
# 0.18.0
- `Core:abort`でプログラムを緊急停止できるように
diff --git a/docs/primitive-props.md b/docs/primitive-props.md
index 90e57528..1c71f5e9 100644
--- a/docs/primitive-props.md
+++ b/docs/primitive-props.md
@@ -83,6 +83,11 @@ _fromIndex_が負値の時は末尾からの位置(文字列の長さ+_fromInd
_pad_ を省略した場合、空白`' '`で埋められます。\
_pad_ が長すぎる場合、_pad_ の末尾が切り捨てられます。
+### @(_v_: str).pad_end(_width_: num, _pad_?: str): str
+文字列の長さがが _width_ になるように、末尾を _pad_ の繰り返しで埋めた新しい文字列を返します。\
+_pad_ を省略した場合、空白`' '`で埋められます。\
+_pad_ が長すぎる場合、_pad_ の末尾が切り捨てられます。
+
### @(_v_: str).trim(): str
文字列の前後の空白を取り除いたものを返します。
diff --git a/src/interpreter/primitive-props.ts b/src/interpreter/primitive-props.ts
index 2c68d8e9..52a20104 100644
--- a/src/interpreter/primitive-props.ts
+++ b/src/interpreter/primitive-props.ts
@@ -126,6 +126,13 @@ const PRIMITIVE_PROPS: {
return STR(target.value.padStart(width.value, s));
}),
+
+ pad_end: (target: VStr): VFn => FN_NATIVE(([width, pad], _) => {
+ assertNumber(width);
+ const s = (pad) ? (assertString(pad), pad.value) : ' ';
+
+ return STR(target.value.padEnd(width.value, s));
+ }),
},
arr: {
diff --git a/test/index.ts b/test/index.ts
index b290296e..93a51b0c 100644
--- a/test/index.ts
+++ b/test/index.ts
@@ -2642,6 +2642,22 @@ describe('primitive props', () => {
STR("abc"), STR("abc"), STR("abc"), STR("abc"), STR("0abc"), STR("01abc"),
]));
});
+
+ test.concurrent("pad_end", async () => {
+ const res = await exe(`
+ let str = "abc"
+ <: [
+ str.pad_end(0), str.pad_end(1), str.pad_end(2), str.pad_end(3), str.pad_end(4), str.pad_end(5),
+ str.pad_end(0, "0"), str.pad_end(1, "0"), str.pad_end(2, "0"), str.pad_end(3, "0"), str.pad_end(4, "0"), str.pad_end(5, "0"),
+ str.pad_end(0, "01"), str.pad_end(1, "01"), str.pad_end(2, "01"), str.pad_end(3, "01"), str.pad_end(4, "01"), str.pad_end(5, "01"),
+ ]
+ `);
+ eq(res, ARR([
+ STR("abc"), STR("abc"), STR("abc"), STR("abc"), STR("abc "), STR("abc "),
+ STR("abc"), STR("abc"), STR("abc"), STR("abc"), STR("abc0"), STR("abc00"),
+ STR("abc"), STR("abc"), STR("abc"), STR("abc"), STR("abc0"), STR("abc01"),
+ ]));
+ });
});
describe('arr', () => {
From 4a18c33b18c0a5df9249529e5e3af0b25a8e89fe Mon Sep 17 00:00:00 2001
From: salano_ym <53254905+salano-ym@users.noreply.github.com>
Date: Thu, 9 May 2024 15:17:25 +0000
Subject: [PATCH 38/47] =?UTF-8?q?arr.insert=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 | 1 +
docs/primitive-props.md | 6 ++++++
src/interpreter/primitive-props.ts | 9 +++++++++
test/index.ts | 18 ++++++++++++++++++
4 files changed, 34 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5ef6934a..eb7dbe2a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,7 @@
# 未リリース分
- `Date:year`系の関数に0を渡すと現在時刻になる問題を修正
- シンタックスエラーなどの位置情報を修正
+- `arr.insert`を追加
# 0.18.0
- `Core:abort`でプログラムを緊急停止できるように
diff --git a/docs/primitive-props.md b/docs/primitive-props.md
index 609cc6ee..7f0df3f6 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).insert(_index_: num, _item_: value): null
+**【この操作は配列を書き換えます】**
+配列の _index_ の位置に _item_ を挿入します。\
+_index_ が負の場合は末尾から数えます。\
+_index_ が最後の要素より後の場合は末尾に追加します。
+
### @(_v_: arr).every(_func_: @(_item_: value, _index_: num) { bool }): bool
配列の全ての要素に対して _func_ が true を返す時のみ true 返します。空配列には常に true を返します。
diff --git a/src/interpreter/primitive-props.ts b/src/interpreter/primitive-props.ts
index c154c45a..db40623e 100644
--- a/src/interpreter/primitive-props.ts
+++ b/src/interpreter/primitive-props.ts
@@ -301,6 +301,15 @@ const PRIMITIVE_PROPS: {
}
return FALSE;
}),
+
+ insert: (target: VArr): VFn => FN_NATIVE(async ([index, item], opts) => {
+ assertNumber(index);
+ expectAny(item);
+
+ target.value.splice(index.value, 0, item);
+
+ return NULL;
+ }),
},
error: {
diff --git a/test/index.ts b/test/index.ts
index fed26c01..26571233 100644
--- a/test/index.ts
+++ b/test/index.ts
@@ -2920,6 +2920,24 @@ describe('primitive props', () => {
FALSE,
]));
});
+
+ test.concurrent('insert', async () => {
+ const res = await exe(`
+ let arr1 = [0, 1, 2]
+ let res = []
+ res.push(arr1.insert(3, 10)) // [0, 1, 2, 10]
+ res.push(arr1.insert(2, 20)) // [0, 1, 20, 2, 10]
+ res.push(arr1.insert(0, 30)) // [30, 0, 1, 20, 2, 10]
+ res.push(arr1.insert(-1, 40)) // [30, 0, 1, 20, 2, 40, 10]
+ res.push(arr1.insert(-4, 50)) // [30, 0, 1, 50, 20, 2, 40, 10]
+ res.push(arr1.insert(100, 60)) // [30, 0, 1, 50, 20, 2, 40, 10, 60]
+ <: [null,null,null,null,null,null,arr1]
+ `);
+ eq(res, ARR([
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ ARR([NUM(30), NUM(0), NUM(1), NUM(50), NUM(20), NUM(2), NUM(40), NUM(10), NUM(60)])
+ ]));
+ });
});
});
From 86fe815239c2b90cfb7067fcc3d5b405d8822335 Mon Sep 17 00:00:00 2001
From: salano_ym <53254905+salano-ym@users.noreply.github.com>
Date: Thu, 9 May 2024 15:24:58 +0000
Subject: [PATCH 39/47] fix test - arr.insert
---
test/index.ts | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/test/index.ts b/test/index.ts
index 26571233..6f34f61a 100644
--- a/test/index.ts
+++ b/test/index.ts
@@ -2931,7 +2931,8 @@ describe('primitive props', () => {
res.push(arr1.insert(-1, 40)) // [30, 0, 1, 20, 2, 40, 10]
res.push(arr1.insert(-4, 50)) // [30, 0, 1, 50, 20, 2, 40, 10]
res.push(arr1.insert(100, 60)) // [30, 0, 1, 50, 20, 2, 40, 10, 60]
- <: [null,null,null,null,null,null,arr1]
+ res.push(arr1)
+ <: res
`);
eq(res, ARR([
NULL, NULL, NULL, NULL, NULL, NULL,
From f6993b211524ae2c57c5de080481d4e789b43afd Mon Sep 17 00:00:00 2001
From: salano_ym <53254905+salano-ym@users.noreply.github.com>
Date: Thu, 9 May 2024 15:29:50 +0000
Subject: [PATCH 40/47] =?UTF-8?q?arr.remove=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 | 6 ++++++
src/interpreter/primitive-props.ts | 8 ++++++++
test/index.ts | 19 +++++++++++++++++++
4 files changed, 34 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index eb7dbe2a..c137df0d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,7 +3,7 @@
# 未リリース分
- `Date:year`系の関数に0を渡すと現在時刻になる問題を修正
- シンタックスエラーなどの位置情報を修正
-- `arr.insert`を追加
+- `arr.insert`,`arr.remove`を追加
# 0.18.0
- `Core:abort`でプログラムを緊急停止できるように
diff --git a/docs/primitive-props.md b/docs/primitive-props.md
index 7f0df3f6..2b76d495 100644
--- a/docs/primitive-props.md
+++ b/docs/primitive-props.md
@@ -190,6 +190,12 @@ _times_ には0以上の整数値を指定します。それ以外ではエラ
_index_ が負の場合は末尾から数えます。\
_index_ が最後の要素より後の場合は末尾に追加します。
+### @(_v_: arr).remove(_index_: num): value | null
+**【この操作は配列を書き換えます】**
+配列から _index_ の位置の要素を取り除き、その要素を返します。\
+_index_ が負の場合は末尾から数えます。\
+_index_ が最後の要素より後の場合は取り除かず、`null`を返します。
+
### @(_v_: arr).every(_func_: @(_item_: value, _index_: num) { bool }): bool
配列の全ての要素に対して _func_ が true を返す時のみ true 返します。空配列には常に true を返します。
diff --git a/src/interpreter/primitive-props.ts b/src/interpreter/primitive-props.ts
index db40623e..efda34b9 100644
--- a/src/interpreter/primitive-props.ts
+++ b/src/interpreter/primitive-props.ts
@@ -310,6 +310,14 @@ const PRIMITIVE_PROPS: {
return NULL;
}),
+
+ remove: (target: VArr): VFn => FN_NATIVE(async ([index], opts) => {
+ assertNumber(index);
+
+ const removed = target.value.splice(index.value, 1);
+
+ return removed[0] ?? NULL;
+ }),
},
error: {
diff --git a/test/index.ts b/test/index.ts
index 6f34f61a..04796634 100644
--- a/test/index.ts
+++ b/test/index.ts
@@ -2939,6 +2939,25 @@ describe('primitive props', () => {
ARR([NUM(30), NUM(0), NUM(1), NUM(50), NUM(20), NUM(2), NUM(40), NUM(10), NUM(60)])
]));
});
+
+ test.concurrent('remove', async () => {
+ const res = await exe(`
+ let arr1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
+ let res = []
+ res.push(arr1.remove(9)) // 9 [0, 1, 2, 3, 4, 5, 6, 7, 8]
+ res.push(arr1.remove(3)) // 3 [0, 1, 2, 4, 5, 6, 7, 8]
+ res.push(arr1.remove(0)) // 0 [1, 2, 4, 5, 6, 7, 8]
+ res.push(arr1.remove(-1)) // 8 [1, 2, 4, 5, 6, 7]
+ res.push(arr1.remove(-5)) // 2 [1, 4, 5, 6, 7]
+ res.push(arr1.remove(100)) // null [1, 4, 5, 6, 7]
+ res.push(arr1)
+ <: res
+ `);
+ eq(res, ARR([
+ NUM(9), NUM(3), NUM(0), NUM(8), NUM(2), NULL,
+ ARR([NUM(1), NUM(4), NUM(5), NUM(6), NUM(7)])
+ ]));
+ });
});
});
From 5c7f11f763ab4e9a19ebadb9afc9a0621ad107c3 Mon Sep 17 00:00:00 2001
From: FineArchs <133759614+FineArchs@users.noreply.github.com>
Date: Fri, 10 May 2024 22:26:51 +0900
Subject: [PATCH 41/47] =?UTF-8?q?=E7=A9=BA=E3=81=AE=E9=85=8D=E5=88=97?=
=?UTF-8?q?=E3=82=92=E5=88=9D=E6=9C=9F=E5=80=A4=E3=81=AA=E3=81=97=E3=81=A7?=
=?UTF-8?q?reduce=E3=81=99=E3=82=8B=E6=99=82=E3=82=A8=E3=83=A9=E3=83=BC?=
=?UTF-8?q?=E3=82=92=E5=87=BA=E3=81=99=E3=82=88=E3=81=86=E3=81=AB=20(#600)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* Update primitive-props.ts
* Update index.ts
* fix
* Update primitive-props.md
* Update CHANGELOG.md
---
CHANGELOG.md | 1 +
docs/primitive-props.md | 4 +++-
src/interpreter/primitive-props.ts | 1 +
test/index.ts | 8 ++++++++
4 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5ef6934a..17d265ab 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,7 @@
# 未リリース分
- `Date:year`系の関数に0を渡すと現在時刻になる問題を修正
- シンタックスエラーなどの位置情報を修正
+- `arr.reduce`が空配列に対して初期値なしで呼び出された時、正式にエラーを出すよう
# 0.18.0
- `Core:abort`でプログラムを緊急停止できるように
diff --git a/docs/primitive-props.md b/docs/primitive-props.md
index 609cc6ee..1356e1c3 100644
--- a/docs/primitive-props.md
+++ b/docs/primitive-props.md
@@ -140,11 +140,13 @@ _i_ 番目の文字が存在しない場合は null が返されます。
配列の要素のうち _func_ が true を返すようなもののみを抜き出して返します。
順序は維持されます。
-### @(_v_: arr).reduce(_func_: @(_acm_: value, _item_: value, _index_: num) { value }, _initial_: value): value
+### @(_v_: arr).reduce(_func_: Callback, _initial_: value): value
+`Callback`: @(_acm_: value, _item_: value, _index_: num): value
配列の各要素に対し _func_ を順番に呼び出します。
各呼び出しでは、前回の結果が第1引数 _acm_ として渡されます。
_initial_ が指定された場合は初回呼び出しの引数が(_initial_, _v_\[0], 0)、
指定されなかった場合は(_v_\[0], _v_\[1], 1)となります。
+配列が空配列であり、かつ _initial_ が指定されていない場合はエラーになります。従って基本的には _initial_ を指定しておくことが推奨されています。
### @(_v_: arr).find(_func_: @(_item_: value, _index_: num) { bool }): value
配列から _func_ が true を返すような要素を探し、その値を返します。
diff --git a/src/interpreter/primitive-props.ts b/src/interpreter/primitive-props.ts
index c154c45a..f158546c 100644
--- a/src/interpreter/primitive-props.ts
+++ b/src/interpreter/primitive-props.ts
@@ -183,6 +183,7 @@ const PRIMITIVE_PROPS: {
reduce: (target: VArr): VFn => FN_NATIVE(async ([fn, initialValue], opts) => {
assertFunction(fn);
const withInitialValue = initialValue != null;
+ if (!withInitialValue && (target.value.length === 0)) throw new AiScriptRuntimeError('Reduce of empty array without initial value');
let accumulator = withInitialValue ? initialValue : target.value[0]!;
for (let i = withInitialValue ? 0 : 1; i < target.value.length; i++) {
const item = target.value[i]!;
diff --git a/test/index.ts b/test/index.ts
index fed26c01..bfb716a4 100644
--- a/test/index.ts
+++ b/test/index.ts
@@ -4,6 +4,7 @@
*/
import * as assert from 'assert';
+import { expect, test } from '@jest/globals';
import { Parser, Interpreter, utils, errors, Ast } from '../src';
import { NUM, STR, NULL, ARR, OBJ, BOOL, TRUE, FALSE, ERROR ,FN_NATIVE } from '../src/interpreter/value';
let { AiScriptRuntimeError, AiScriptIndexOutOfRangeError } = errors;
@@ -2753,6 +2754,13 @@ describe('primitive props', () => {
eq(res, NUM(20));
});
+ test.concurrent('reduce of empty array without initial value', async () => {
+ await expect(exe(`
+ let arr = [1, 2, 3, 4]
+ <: [].reduce(@(){})
+ `)).rejects.toThrow('Reduce of empty array without initial value');
+ });
+
test.concurrent('find', async () => {
const res = await exe(`
let arr = ["abc", "def", "ghi"]
From 324fdddae2de004afe2bd52f597f7294b74fd758 Mon Sep 17 00:00:00 2001
From: salano_ym <53254905+salano-ym@users.noreply.github.com>
Date: Mon, 13 May 2024 01:06:52 +0900
Subject: [PATCH 42/47] remove spaces index.ts
---
test/index.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/index.ts b/test/index.ts
index bbadfa16..18e215b9 100644
--- a/test/index.ts
+++ b/test/index.ts
@@ -3105,7 +3105,7 @@ describe('primitive props', () => {
]),
]));
});
-
+
test.concurrent('every', async () => {
const res = await exe(`
let arr1 = [0, 1, 2, 3]
From 4cb7919f2593ee25625992341a0aa29577ed4645 Mon Sep 17 00:00:00 2001
From: salano_ym <53254905+salano-ym@users.noreply.github.com>
Date: Mon, 13 May 2024 02:31:03 +0000
Subject: [PATCH 43/47] improve test: Math:gen_rng
---
test/index.ts | 24 +++++++++++++++++-------
1 file changed, 17 insertions(+), 7 deletions(-)
diff --git a/test/index.ts b/test/index.ts
index 18e215b9..cb97391d 100644
--- a/test/index.ts
+++ b/test/index.ts
@@ -3302,17 +3302,27 @@ describe('std', () => {
test.concurrent('gen_rng', async () => {
const res = await exe(`
- @test(seed) {
- let random = Math:gen_rng(seed)
- return random(0 100)
+ @test(seed1, seed2) {
+ let n = 100
+ let max = 100000
+ let random1 = Math:gen_rng(seed1)
+ let random2 = Math:gen_rng(seed2)
+ var same = 0
+ for n {
+ if random1(1, max) == random2(1, max) {
+ same += 1
+ }
+ }
+ same / n
}
let seed1 = \`{Util:uuid()}\`
let seed2 = \`{Date:year()}\`
- let test1 = if (test(seed1) == test(seed1)) {true} else {false}
- let test2 = if (test(seed1) == test(seed2)) {true} else {false}
- <: [test1 test2]
+ let result = []
+ result.push(test(seed1, seed1) == 1)
+ result.push(test(seed1, seed2) < 0.05)
+ <: result
`)
- eq(res, ARR([BOOL(true), BOOL(false)]));
+ eq(res, ARR([BOOL(true), BOOL(true)]));
});
});
From e758cef712a6b00439fe1ac84109ae57e58407e3 Mon Sep 17 00:00:00 2001
From: salano_ym <53254905+salano-ym@users.noreply.github.com>
Date: Mon, 13 May 2024 13:05:20 +0900
Subject: [PATCH 44/47] =?UTF-8?q?Math:gen=5Frng=E3=81=AE=E3=83=86=E3=82=B9?=
=?UTF-8?q?=E3=83=88=E3=81=AB=E3=82=B3=E3=83=A1=E3=83=B3=E3=83=88=E3=82=92?=
=?UTF-8?q?=E8=BF=BD=E5=8A=A0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
test/index.ts | 1 +
1 file changed, 1 insertion(+)
diff --git a/test/index.ts b/test/index.ts
index cb97391d..30ec18ef 100644
--- a/test/index.ts
+++ b/test/index.ts
@@ -3301,6 +3301,7 @@ describe('std', () => {
});
test.concurrent('gen_rng', async () => {
+ // 2つのシード値から1~maxの乱数をn回生成して一致率を見る
const res = await exe(`
@test(seed1, seed2) {
let n = 100
From f4f860324e9c6df5f5db0f17096e688a59106da2 Mon Sep 17 00:00:00 2001
From: salano_ym <53254905+salano-ym@users.noreply.github.com>
Date: Mon, 13 May 2024 17:29:32 +0900
Subject: [PATCH 45/47] refactor index.ts
---
test/index.ts | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/test/index.ts b/test/index.ts
index 30ec18ef..fd235f22 100644
--- a/test/index.ts
+++ b/test/index.ts
@@ -3306,6 +3306,7 @@ describe('std', () => {
@test(seed1, seed2) {
let n = 100
let max = 100000
+ let threshold = 0.05
let random1 = Math:gen_rng(seed1)
let random2 = Math:gen_rng(seed2)
var same = 0
@@ -3314,14 +3315,16 @@ describe('std', () => {
same += 1
}
}
- same / n
+ let rate = same / n
+ if seed1 == seed2 { rate == 1 }
+ else { rate < threshold }
}
let seed1 = \`{Util:uuid()}\`
let seed2 = \`{Date:year()}\`
- let result = []
- result.push(test(seed1, seed1) == 1)
- result.push(test(seed1, seed2) < 0.05)
- <: result
+ <: [
+ test(seed1, seed1)
+ test(seed1, seed2)
+ ]
`)
eq(res, ARR([BOOL(true), BOOL(true)]));
});
From 38f36ef2cef10ecc7620db9f0f3d46c92d23abc6 Mon Sep 17 00:00:00 2001
From: FineArchs <133759614+FineArchs@users.noreply.github.com>
Date: Tue, 14 May 2024 20:14:37 +0900
Subject: [PATCH 46/47] =?UTF-8?q?=E9=96=A2=E6=95=B0=E3=81=AE=E7=9C=81?=
=?UTF-8?q?=E7=95=A5=E3=81=95=E3=82=8C=E3=81=9F=E5=BC=95=E6=95=B0=E3=81=AB?=
=?UTF-8?q?NULL=E3=82=92=E6=A0=BC=E7=B4=8D=E3=81=99=E3=82=8B=E3=82=88?=
=?UTF-8?q?=E3=81=86=E3=81=AB=20(#639)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* Update index.ts
* add test
* Update CHANGELOG.md
---
CHANGELOG.md | 2 ++
src/interpreter/index.ts | 2 +-
test/index.ts | 10 ++++++++++
3 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 65815163..8d1626a9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,8 @@
- `Uri:encode_full`, `Uri:encode_component`, `Uri:decode_full`, `Uri:decode_component`を追加
- `str.starts_with`,`str.ends_with`を追加
- `arr.splice`を追加
+- 関数の省略された引数にNULLを格納するように
+ - 一時的な措置であり、省略可能引数構文の実装と同時に廃止予定です。依存し過ぎないようにしてください
# 0.18.0
- `Core:abort`でプログラムを緊急停止できるように
diff --git a/src/interpreter/index.ts b/src/interpreter/index.ts
index 23df41ea..496e16ff 100644
--- a/src/interpreter/index.ts
+++ b/src/interpreter/index.ts
@@ -239,7 +239,7 @@ export class Interpreter {
for (let i = 0; i < (fn.args ?? []).length; i++) {
_args.set(fn.args![i]!, {
isMutable: true,
- value: args[i]!,
+ value: args[i] ?? NULL,
});
}
const fnScope = fn.scope!.createChildScope(_args);
diff --git a/test/index.ts b/test/index.ts
index 18e215b9..91492317 100644
--- a/test/index.ts
+++ b/test/index.ts
@@ -1297,6 +1297,16 @@ describe('Function call', () => {
}
assert.fail();
});
+
+ test.concurrent('omitted args', async () => {
+ const res = await exe(`
+ @f(x, y) {
+ [x, y]
+ }
+ <: f(1)
+ `);
+ eq(res, ARR([NUM(1), NULL]));
+ });
});
describe('Return', () => {
From f72da1b037ee5e9b03310ab4351d98491d70472d Mon Sep 17 00:00:00 2001
From: FineArchs <133759614+FineArchs@users.noreply.github.com>
Date: Fri, 17 May 2024 18:19:54 +0900
Subject: [PATCH 47/47] =?UTF-8?q?CHANGELOG=E3=81=AE=E6=9B=B4=E6=96=B0?=
=?UTF-8?q?=E3=82=92unreleased=E3=83=95=E3=82=A9=E3=83=AB=E3=83=80?=
=?UTF-8?q?=E5=86=85=E3=81=A7=E8=A1=8C=E3=81=86=E3=82=88=E3=81=86=E3=81=AB?=
=?UTF-8?q?=E3=81=99=E3=82=8B=20(#666)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* create pre-release workflow
* refactor
* fix
* time order
* 消し忘れ
---
.github/workflows/publish-nightly-next.yml | 56 ----------
...sh-nightly-dev.yml => publish-nightly.yml} | 28 +++--
CHANGELOG.md | 14 ---
package-lock.json | 75 ++++++++++---
package.json | 5 +-
scripts/check-release.mjs | 8 ++
scripts/gen-pkg-ts.mjs | 4 +-
scripts/pre-release.mjs | 101 ++++++++++++++++++
unreleased/.gitkeep | 0
unreleased/past.md | 10 ++
10 files changed, 202 insertions(+), 99 deletions(-)
delete mode 100644 .github/workflows/publish-nightly-next.yml
rename .github/workflows/{publish-nightly-dev.yml => publish-nightly.yml} (66%)
create mode 100644 scripts/check-release.mjs
create mode 100644 scripts/pre-release.mjs
create mode 100644 unreleased/.gitkeep
create mode 100644 unreleased/past.md
diff --git a/.github/workflows/publish-nightly-next.yml b/.github/workflows/publish-nightly-next.yml
deleted file mode 100644
index 62110872..00000000
--- a/.github/workflows/publish-nightly-next.yml
+++ /dev/null
@@ -1,56 +0,0 @@
-name: Publish nightly (next)
-
-on:
- schedule:
- - cron: '50 18 * * *'
- workflow_dispatch:
-
-jobs:
- publish:
- runs-on: ubuntu-latest
- env:
- NPM_SECRET: ${{ secrets.NPM_SECRET }}
- BRANCH: aiscript-next
- TAG: next
-
- steps:
- - name: Checkout
- uses: actions/checkout@v4.1.5
- with:
- ref: ${{ env.BRANCH }}
-
- - name: Setup Node.js
- uses: actions/setup-node@v4.0.2
- with:
- node-version: 20.x
-
- - name: Cache dependencies
- uses: actions/cache@v4
- with:
- path: ~/.npm
- key: npm-${{ hashFiles('package-lock.json') }}
- restore-keys: npm-
-
- - name: Install dependencies
- run: npm ci
-
- - name: Build
- run: npm run build
-
- - name: Set Version
- run: |
- TIME_STAMP=$( date +'%Y%m%d' )
- VERSION_SUFFIX=-$TAG.$TIME_STAMP
- vim package.json '+/"version"' '+s/:\s*".*\zs\ze"/'$VERSION_SUFFIX/ '+wq'
-
- - name: Check Commits
- run: |
- echo 'LAST_COMMITS='$( git log --since '24 hours ago' | wc -c ) >> $GITHUB_ENV
-
- - name: Publish
- uses: JS-DevTools/npm-publish@v3
- if: ${{ env.NPM_SECRET != '' && env.LAST_COMMITS != 0 }}
- with:
- token: ${{ env.NPM_SECRET }}
- tag: ${{ env.TAG }}
- access: public
diff --git a/.github/workflows/publish-nightly-dev.yml b/.github/workflows/publish-nightly.yml
similarity index 66%
rename from .github/workflows/publish-nightly-dev.yml
rename to .github/workflows/publish-nightly.yml
index caff8cd9..6669ba33 100644
--- a/.github/workflows/publish-nightly-dev.yml
+++ b/.github/workflows/publish-nightly.yml
@@ -1,4 +1,4 @@
-name: Publish nightly (dev)
+name: Publish nightly
on:
schedule:
@@ -8,16 +8,22 @@ on:
jobs:
publish:
runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ - branch: master
+ tag: dev
+ - branch: aiscript-next
+ tag: next
env:
NPM_SECRET: ${{ secrets.NPM_SECRET }}
- BRANCH: master
- TAG: dev
steps:
- - name: Checkout
+ - name: Checkout ${{ matrix.branch }}
uses: actions/checkout@v4.1.5
with:
- ref: ${{ env.BRANCH }}
+ ref: ${{ matrix.branch }}
- name: Setup Node.js
uses: actions/setup-node@v4.0.2
@@ -34,23 +40,23 @@ jobs:
- name: Install dependencies
run: npm ci
- - name: Build
- run: npm run build
-
- name: Set Version
run: |
+ CURRENT_VER=$(npm view 'file:.' version)
TIME_STAMP=$( date +'%Y%m%d' )
- VERSION_SUFFIX=-$TAG.$TIME_STAMP
- vim package.json '+/"version"' '+s/:\s*".*\zs\ze"/'$VERSION_SUFFIX/ '+wq'
+ echo 'NEWVERSION='$CURRENT_VER-${{ matrix.tag }}.$TIME_STAMP >> $GITHUB_ENV
- name: Check Commits
run: |
echo 'LAST_COMMITS='$( git log --since '24 hours ago' | wc -c ) >> $GITHUB_ENV
+ - name: Prepare Publish
+ run: npm run pre-release
+
- name: Publish
uses: JS-DevTools/npm-publish@v3
if: ${{ env.NPM_SECRET != '' && env.LAST_COMMITS != 0 }}
with:
token: ${{ env.NPM_SECRET }}
- tag: ${{ env.TAG }}
+ tag: ${{ matrix.tag }}
access: public
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8d1626a9..bc8ae5f0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,19 +1,5 @@
[Read translated version (en)](./translations/en/CHANGELOG.md)
-# 未リリース分
-- `Date:year`系の関数に0を渡すと現在時刻になる問題を修正
-- シンタックスエラーなどの位置情報を修正
-- `arr.reduce`が空配列に対して初期値なしで呼び出された時、正式にエラーを出すよう
-- `str.pad_start`,`str.pad_end`を追加
-- `arr.insert`,`arr.remove`を追加
-- `arr.sort`の処理を非同期的にして高速化
-- `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`を追加
-- 関数の省略された引数にNULLを格納するように
- - 一時的な措置であり、省略可能引数構文の実装と同時に廃止予定です。依存し過ぎないようにしてください
-
# 0.18.0
- `Core:abort`でプログラムを緊急停止できるように
- `index_of`の配列版を追加
diff --git a/package-lock.json b/package-lock.json
index 5d153106..15b55102 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@syuilo/aiscript",
- "version": "0.18.0",
+ "version": "0.19.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@syuilo/aiscript",
- "version": "0.18.0",
+ "version": "0.19.0",
"license": "MIT",
"dependencies": {
"seedrandom": "3.0.5",
@@ -27,6 +27,7 @@
"eslint-plugin-import": "2.29.1",
"jest": "29.7.0",
"peggy": "4.0.2",
+ "semver": "7.6.2",
"ts-jest": "29.1.2",
"ts-jest-resolver": "2.0.1",
"ts-node": "10.9.2",
@@ -1504,6 +1505,21 @@
"node": "*"
}
},
+ "node_modules/@microsoft/api-extractor/node_modules/semver": {
+ "version": "7.5.4",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
+ "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
+ "dev": true,
+ "dependencies": {
+ "lru-cache": "^6.0.0"
+ },
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/@microsoft/tsdoc": {
"version": "0.14.2",
"resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.14.2.tgz",
@@ -1619,6 +1635,21 @@
}
}
},
+ "node_modules/@rushstack/node-core-library/node_modules/semver": {
+ "version": "7.5.4",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
+ "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
+ "dev": true,
+ "dependencies": {
+ "lru-cache": "^6.0.0"
+ },
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/@rushstack/rig-package": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.5.2.tgz",
@@ -7178,13 +7209,10 @@
"license": "MIT"
},
"node_modules/semver": {
- "version": "7.5.4",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
- "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
+ "version": "7.6.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz",
+ "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==",
"dev": true,
- "dependencies": {
- "lru-cache": "^6.0.0"
- },
"bin": {
"semver": "bin/semver.js"
},
@@ -9360,6 +9388,15 @@
"requires": {
"brace-expansion": "^1.1.7"
}
+ },
+ "semver": {
+ "version": "7.5.4",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
+ "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
+ "dev": true,
+ "requires": {
+ "lru-cache": "^6.0.0"
+ }
}
}
},
@@ -9462,6 +9499,17 @@
"resolve": "~1.22.1",
"semver": "~7.5.4",
"z-schema": "~5.0.2"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "7.5.4",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
+ "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
+ "dev": true,
+ "requires": {
+ "lru-cache": "^6.0.0"
+ }
+ }
}
},
"@rushstack/rig-package": {
@@ -13540,13 +13588,10 @@
"version": "3.0.5"
},
"semver": {
- "version": "7.5.4",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
- "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
- "dev": true,
- "requires": {
- "lru-cache": "^6.0.0"
- }
+ "version": "7.6.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz",
+ "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==",
+ "dev": true
},
"shebang-command": {
"version": "2.0.0",
diff --git a/package.json b/package.json
index 273c1231..7e069506 100644
--- a/package.json
+++ b/package.json
@@ -33,7 +33,9 @@
"lint": "eslint . --ext .js,.jsx,.ts,.tsx",
"jest": "jest --coverage --detectOpenHandles",
"tsd": "tsd",
- "test": "npm run jest"
+ "test": "npm run jest",
+ "pre-release": "node scripts/pre-release.mjs && npm run build",
+ "prepublishOnly": "node scripts/check-release.mjs"
},
"devDependencies": {
"@microsoft/api-extractor": "7.42.3",
@@ -49,6 +51,7 @@
"eslint-plugin-import": "2.29.1",
"jest": "29.7.0",
"peggy": "4.0.2",
+ "semver": "7.6.2",
"ts-jest": "29.1.2",
"ts-jest-resolver": "2.0.1",
"ts-node": "10.9.2",
diff --git a/scripts/check-release.mjs b/scripts/check-release.mjs
new file mode 100644
index 00000000..4d218aeb
--- /dev/null
+++ b/scripts/check-release.mjs
@@ -0,0 +1,8 @@
+import { readdir } from 'node:fs/promises';
+
+await readdir('./unreleased')
+ .then(pathes => {
+ if (pathes.length > 1 || (pathes.length === 1 && pathes[0] !== '.gitkeep')) throw new Error('Run "npm run pre-release" before publish.')
+ }, err => {
+ if (err.code !== 'ENOENT') throw err;
+ });
diff --git a/scripts/gen-pkg-ts.mjs b/scripts/gen-pkg-ts.mjs
index f6d757a3..2e22d069 100644
--- a/scripts/gen-pkg-ts.mjs
+++ b/scripts/gen-pkg-ts.mjs
@@ -1,6 +1,6 @@
-import { writeFile } from 'node:fs/promises';
-import pkg from '../package.json' assert { type: 'json' };
+import { readFile, writeFile } from 'node:fs/promises';
+const pkg = JSON.parse((await readFile('./package.json', 'utf8')));
await writeFile('./src/pkg.ts',
`/*
This file is automatically generated by scripts/gen-pkg-ts.js.
diff --git a/scripts/pre-release.mjs b/scripts/pre-release.mjs
new file mode 100644
index 00000000..1dfd7dfb
--- /dev/null
+++ b/scripts/pre-release.mjs
@@ -0,0 +1,101 @@
+import { readFile, readdir, writeFile, mkdir, rm } from 'node:fs/promises';
+import { env } from 'node:process';
+import { promisify } from 'node:util';
+import child_process from 'node:child_process';
+import semverValid from 'semver/functions/valid.js';
+
+
+const exec = promisify(child_process.exec);
+const FILES = {
+ chlog: './CHANGELOG.md',
+ chlogs: './unreleased',
+ pkgjson: './package.json',
+};
+const enc = { encoding: env.ENCODING ?? 'utf8' };
+const pkgjson = JSON.parse(await readFile(FILES.pkgjson, enc));
+const newver = (() => {
+ const newverCandidates = [
+ [env.NEWVERSION, 'Environment variable NEWVERSION'],
+ [pkgjson.version, "Package.json's version field"],
+ ];
+ for (const [ver, name] of newverCandidates) {
+ if (ver) {
+ if (semverValid(ver)) return ver;
+ else throw new Error(`${name} is set to "${ver}"; it is not valid`);
+ }
+ }
+ throw new Error('No effective version setting detected.');
+})();
+const actions = {};
+
+/*
+ * Update package.json's version field
+ */
+actions.updatePackageJson = {
+ async read() {
+ return JSON.stringify(
+ { ...pkgjson, version: newver },
+ null, '\t'
+ );
+ },
+ async write(json) {
+ return writeFile(FILES.pkgjson, json);
+ },
+};
+
+/*
+ * Collect changelogs
+ */
+actions.collectChangeLogs = {
+ async read() {
+ const getNewLog = async () => {
+ const pathes = (await readdir(FILES.chlogs)).map(path => `${FILES.chlogs}/${path}`);
+ const pathesLastUpdate = await Promise.all(
+ pathes.map(async (path) => {
+ const gittime = Number((await exec(
+ `git log -1 --pretty="format:%ct" "${path}"`
+ )).stdout);
+ if (gittime) return { path, lastUpdate: gittime };
+ else {
+ console.log(`Warning: git timestamp of "${path}" was not detected`);
+ return { path, lastUpdate: Infinity }
+ }
+ })
+ );
+ pathesLastUpdate.sort((a, b) => a.lastUpdate - b.lastUpdate);
+ const logPromises = pathesLastUpdate.map(({ path }) => readFile(path, enc));
+ const logs = await Promise.all(logPromises);
+ return logs.map(v => v.trim()).join('\n');
+ };
+ const getOldLog = async () => {
+ const log = await readFile(FILES.chlog, enc);
+ const idx = log.indexOf('#');
+ return [
+ log.slice(0, idx),
+ log.slice(idx),
+ ];
+ };
+ const [newLog, [logHead, oldLog]] = await Promise.all([ getNewLog(), getOldLog() ]);
+ return `${logHead}# ${newver}\n${newLog}\n\n${oldLog}`;
+
+ },
+ async write(logs) {
+ return Promise.all([
+ writeFile(FILES.chlog, logs),
+ rm(FILES.chlogs, {
+ recursive: true,
+ force: true,
+ }).then(() =>
+ mkdir(FILES.chlogs)
+ ).then(() =>
+ writeFile(`${FILES.chlogs}/.gitkeep`, ''))
+ ]);
+ },
+};
+
+// read all before writing
+const reads = await Promise.all(Object.entries(actions).map(async ([name, { read }]) => [name, await read().catch(err => { throw new Error(`in actions.${name}.read: ${err}`) })]));
+
+// write after reading all
+await Promise.all(reads.map(([name, read]) => actions[name].write(read).catch(err => { throw new Error(`in actions.${name}.write: ${err}`) })));
+
diff --git a/unreleased/.gitkeep b/unreleased/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/unreleased/past.md b/unreleased/past.md
new file mode 100644
index 00000000..52191011
--- /dev/null
+++ b/unreleased/past.md
@@ -0,0 +1,10 @@
+- `Date:year`系の関数に0を渡すと現在時刻になる問題を修正
+- シンタックスエラーなどの位置情報を修正
+- `arr.reduce`が空配列に対して初期値なしで呼び出された時、正式にエラーを出すよう
+- `str.pad_start`,`str.pad_end`を追加
+- `arr.insert`,`arr.remove`を追加
+- `arr.sort`の処理を非同期的にして高速化
+- `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`を追加