Repository: syuilo/aiscript
Pull request #355 (2023-09-16 01:00:56)

Bump the all group with 4 updates
Bumps the all group with 4 updates: [@microsoft/api-extractor](https://github.com/microsoft/rushstack/tree/HEAD/apps/api-extractor), [@types/jest](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/jest), [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) and [@types/uuid](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/uuid).

Updates `@microsoft/api-extractor` from 7.36.4 to 7.37.0
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a href="https://github.com/microsoft/rushstack/blob/main/apps/api-extractor/CHANGELOG.md"><code>@​microsoft/api-extractor</code>'s changelog</a>.</em></p>
<blockquote>
<h2>7.37.0</h2>
<p>Fri, 15 Sep 2023 00:36:58 GMT</p>
<h3>Minor changes</h3>
<ul>
<li>Update <code>@​types/node</code> from 14 to 18</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/microsoft/rushstack/commit/4775ea731cd4fe9da2ffc4f1d1acdbbc4428d967"><code>4775ea7</code></a> Bump versions [skip ci]</li>
<li><a href="https://github.com/microsoft/rushstack/commit/574cff6884706417d95c9acc199db4e5b1a9c340"><code>574cff6</code></a> Update changelogs [skip ci]</li>
<li><a href="https://github.com/microsoft/rushstack/commit/3ab024cb06f218f4c885f994b22bcd4a29ea0020"><code>3ab024c</code></a> [repo-wide] Update <code>@​types/node</code> from 14 to 18 (<a href="https://github.com/microsoft/rushstack/tree/HEAD/apps/api-extractor/issues/4324">#4324</a>)</li>
<li>See full diff in <a href="https://github.com/microsoft/rushstack/commits/@microsoft/api-extractor_v7.37.0/apps/api-extractor">compare view</a></li>
</ul>
</details>
<br />

Updates `@types/jest` from 29.5.4 to 29.5.5
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/jest">compare view</a></li>
</ul>
</details>
<br />

Updates `@types/node` from 20.6.0 to 20.6.1
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node">compare view</a></li>
</ul>
</details>
<br />

Updates `@types/uuid` from 9.0.3 to 9.0.4
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/uuid">compare view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will remove the ignore condition of the specified dependency and ignore conditions


</details>

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/syuilo/aiscript/pull/355?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=syuilo) Report
Patch and project coverage have no change.
> Comparison is base [(`09cd89f`)](https://app.codecov.io/gh/syuilo/aiscript/commit/09cd89f3e693e562ffe42129d62492e31ce92ee5?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=syuilo) 88.12% compared to head [(`35eb92a`)](https://app.codecov.io/gh/syuilo/aiscript/pull/355?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=syuilo) 88.12%.

<details><summary>Additional details and impacted files</summary>


```diff
@@           Coverage Diff           @@
##           master     #355   +/-   ##
=======================================
  Coverage   88.12%   88.12%           
=======================================
  Files          21       21           
  Lines        3369     3369           
  Branches      547      547           
=======================================
  Hits         2969     2969           
  Misses        389      389           
  Partials       11       11           
```




</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/syuilo/aiscript/pull/355?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=syuilo).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=syuilo).


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5222b43..5f9edf3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,8 @@
 - 「エラー型（`error`）」を導入
 - `Json:parse`がパース失敗時にエラー型の値を返すように
 - `let` で定義した変数が上書きできてしまうのを修正
+- For Host: Interpreterのコンストラクタの第２引数の要素に`err`（エラーコールバック）を設定できる。これは`Interpreter.exec`が失敗した時に加えて、**`Async:interval`や`Async:timeout`が失敗した場合にも呼び出される。** なお、これを設定した場合は例外throwは発生しなくなる。
+- For Host: ネイティブ関数は`opts.call`の代わりに`opts.topCall`を用いることで上記２つのようにエラーコールバックが呼び出されるように。**必要な場合にのみ使うこと。従来エラーキャッチ出来ていたケースでは引き続き`opts.call`を使う。**
 
 # 0.15.0
 - Mathを強化
diff --git a/etc/aiscript.api.md b/etc/aiscript.api.md
index 8078211..f6b0326 100644
--- a/etc/aiscript.api.md
+++ b/etc/aiscript.api.md
@@ -344,6 +344,7 @@ const ERROR: (name: string, info?: Value) => Value;
 declare namespace errors {
     export {
         AiScriptError,
+        NonAiScriptError,
         SyntaxError_2 as SyntaxError,
         TypeError_2 as TypeError,
         RuntimeError,
@@ -531,6 +532,7 @@ export class Interpreter {
     constructor(consts: Record<string, Value>, opts?: {
         in?(q: string): Promise<string>;
         out?(value: Value): void;
+        err?(e: AiScriptError): void;
         log?(type: string, params: Record<string, any>): void;
         maxStep?: number;
     });
@@ -540,8 +542,8 @@ export class Interpreter {
     static collectMetadata(script?: Ast.Node[]): Map<any, any> | undefined;
     // (undocumented)
     exec(script?: Ast.Node[]): Promise<void>;
-    // (undocumented)
     execFn(fn: VFn, args: Value[]): Promise<Value>;
+    execFnSimple(fn: VFn, args: Value[]): Promise<Value>;
     // (undocumented)
     registerAbortHandler(handler: () => void): void;
     // (undocumented)
@@ -673,6 +675,11 @@ type Node_2 = Namespace | Meta | Statement | Expression | TypeSource;
 // @public
 type Node_3 = Namespace_2 | Meta_2 | Statement_2 | Expression_2 | ChainMember | TypeSource_2;
 
+// @public
+class NonAiScriptError extends AiScriptError {
+    constructor(error: any);
+}
+
 // @public (undocumented)
 type Not = NodeBase & {
     type: 'not';
@@ -1003,13 +1010,14 @@ type VError = {
     info?: Value;
 };
 
-// @public (undocumented)
+// @public
 type VFn = {
     type: 'fn';
     args?: string[];
     statements?: Node_2[];
     native?: (args: (Value | undefined)[], opts: {
         call: (fn: VFn, args: Value[]) => Promise<Value>;
+        topCall: (fn: VFn, args: Value[]) => Promise<Value>;
         registerAbortHandler: (handler: () => void) => void;
         unregisterAbortHandler: (handler: () => void) => void;
     }) => Value | Promise<Value> | void;
diff --git a/package-lock.json b/package-lock.json
index 7999d38..68d2568 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -14,11 +14,11 @@
 				"uuid": "9.0.1"
 			},
 			"devDependencies": {
-				"@microsoft/api-extractor": "7.36.4",
-				"@types/jest": "29.5.4",
-				"@types/node": "20.6.0",
+				"@microsoft/api-extractor": "7.37.0",
+				"@types/jest": "29.5.5",
+				"@types/node": "20.6.1",
 				"@types/seedrandom": "3.0.5",
-				"@types/uuid": "9.0.3",
+				"@types/uuid": "9.0.4",
 				"@typescript-eslint/eslint-plugin": "6.7.0",
 				"@typescript-eslint/parser": "6.7.0",
 				"chalk": "5.3.0",
@@ -1400,17 +1400,17 @@
 			}
 		},
 		"node_modules/@microsoft/api-extractor": {
-			"version": "7.36.4",
-			"resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.36.4.tgz",
-			"integrity": "sha512-21UECq8C/8CpHT23yiqTBQ10egKUacIpxkPyYR7hdswo/M5yTWdBvbq+77YC9uPKQJOUfOD1FImBQ1DzpsdeQQ==",
+			"version": "7.37.0",
+			"resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.37.0.tgz",
+			"integrity": "sha512-df/wffWpDhYRw7kzdxeHGsCpim+dC8aFiZlsJb4uFvVPWhBZpDzOhQxSUTFx3Df1ORY+/JjuPR3fDE9Hq+PHzQ==",
 			"dev": true,
 			"dependencies": {
-				"@microsoft/api-extractor-model": "7.27.6",
+				"@microsoft/api-extractor-model": "7.28.0",
 				"@microsoft/tsdoc": "0.14.2",
 				"@microsoft/tsdoc-config": "~0.16.1",
-				"@rushstack/node-core-library": "3.59.7",
-				"@rushstack/rig-package": "0.4.1",
-				"@rushstack/ts-command-line": "4.15.2",
+				"@rushstack/node-core-library": "3.60.0",
+				"@rushstack/rig-package": "0.5.0",
+				"@rushstack/ts-command-line": "4.16.0",
 				"colors": "~1.2.1",
 				"lodash": "~4.17.15",
 				"resolve": "~1.22.1",
@@ -1423,14 +1423,14 @@
 			}
 		},
 		"node_modules/@microsoft/api-extractor-model": {
-			"version": "7.27.6",
-			"resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.27.6.tgz",
-			"integrity": "sha512-eiCnlayyum1f7fS2nA9pfIod5VCNR1G+Tq84V/ijDrKrOFVa598BLw145nCsGDMoFenV6ajNi2PR5WCwpAxW6Q==",
+			"version": "7.28.0",
+			"resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.28.0.tgz",
+			"integrity": "sha512-QIMtUVm1tqiKG+M6ciFgRShcDoovyltaeg+CbyOnyr7SMrp6gg0ojK5/nToMqR9kAvsTS4QVgW4Twl50EoAjcw==",
 			"dev": true,
 			"dependencies": {
 				"@microsoft/tsdoc": "0.14.2",
 				"@microsoft/tsdoc-config": "~0.16.1",
-				"@rushstack/node-core-library": "3.59.7"
+				"@rushstack/node-core-library": "3.60.0"
 			}
 		},
 		"node_modules/@microsoft/api-extractor/node_modules/typescript": {
@@ -1513,9 +1513,9 @@
 			}
 		},
 		"node_modules/@rushstack/node-core-library": {
-			"version": "3.59.7",
-			"resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.59.7.tgz",
-			"integrity": "sha512-ln1Drq0h+Hwa1JVA65x5mlSgUrBa1uHL+V89FqVWQgXd1vVIMhrtqtWGQrhTnFHxru5ppX+FY39VWELF/FjQCw==",
+			"version": "3.60.0",
+			"resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.60.0.tgz",
+			"integrity": "sha512-PcyrqhILvzU+65wMFybQ2VeGNnU5JzhDq2OvUi3j6jPUxyllM7b2hrRUwCuVaYboewYzIbpzXFzgxe2K7ii1nw==",
 			"dev": true,
 			"dependencies": {
 				"colors": "~1.2.1",
@@ -1536,9 +1536,9 @@
 			}
 		},
 		"node_modules/@rushstack/rig-package": {
-			"version": "0.4.1",
-			"resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.4.1.tgz",
-			"integrity": "sha512-AGRwpqlXNSp9LhUSz4HKI9xCluqQDt/obsQFdv/NYIekF3pTTPzc+HbQsIsjVjYnJ3DcmxOREVMhvrMEjpiq6g==",
+			"version": "0.5.0",
+			"resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.5.0.tgz",
+			"integrity": "sha512-bGnOW4DWHOePDiABKy6qyqYJl9i7fKn4bRucExRVt5QzyPxuVHMl8CMmCabtoNSpXzgG3qymWOrMoa/W2PpJrw==",
 			"dev": true,
 			"dependencies": {
 				"resolve": "~1.22.1",
@@ -1546,9 +1546,9 @@
 			}
 		},
 		"node_modules/@rushstack/ts-command-line": {
-			"version": "4.15.2",
-			"resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.15.2.tgz",
-			"integrity": "sha512-5+C2uoJY8b+odcZD6coEe2XNC4ZjGB4vCMESbqW/8DHRWC/qIHfANdmN9F1wz/lAgxz72i7xRoVtPY2j7e4gpQ==",
+			"version": "4.16.0",
+			"resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.16.0.tgz",
+			"integrity": "sha512-WJKhdR9ThK9Iy7t78O3at7I3X4Ssp5RRZay/IQa8NywqkFy/DQbT3iLouodMMdUwLZD9n8n++xLubVd3dkmpkg==",
 			"dev": true,
 			"dependencies": {
 				"@types/argparse": "1.0.38",
@@ -1711,9 +1711,9 @@
 			}
 		},
 		"node_modules/@types/jest": {
-			"version": "29.5.4",
-			"resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.4.tgz",
-			"integrity": "sha512-PhglGmhWeD46FYOVLt3X7TiWjzwuVGW9wG/4qocPevXMjCmrIc5b6db9WjeGE4QYVpUAWMDv3v0IiBwObY289A==",
+			"version": "29.5.5",
+			"resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.5.tgz",
+			"integrity": "sha512-ebylz2hnsWR9mYvmBFbXJXr+33UPc4+ZdxyDXh5w0FlPBTfCVN3wPL+kuOiQt3xvrK419v7XWeAs+AeOksafXg==",
 			"dev": true,
 			"dependencies": {
 				"expect": "^29.0.0",
@@ -1739,9 +1739,9 @@
 			"dev": true
 		},
 		"node_modules/@types/node": {
-			"version": "20.6.0",
-			"resolved": "https://registry.npmjs.org/@types/node/-/node-20.6.0.tgz",
-			"integrity": "sha512-najjVq5KN2vsH2U/xyh2opaSEz6cZMR2SetLIlxlj08nOcmPOemJmUK2o4kUzfLqfrWE0PIrNeE16XhYDd3nqg==",
+			"version": "20.6.1",
+			"resolved": "https://registry.npmjs.org/@types/node/-/node-20.6.1.tgz",
+			"integrity": "sha512-4LcJvuXQlv4lTHnxwyHQZ3uR9Zw2j7m1C9DfuwoTFQQP4Pmu04O6IfLYgMmHoOCt0nosItLLZAH+sOrRE0Bo8g==",
 			"dev": true
 		},
 		"node_modules/@types/normalize-package-data": {
@@ -1769,9 +1769,9 @@
 			"dev": true
 		},
 		"node_modules/@types/uuid": {
-			"version": "9.0.3",
-			"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.3.tgz",
-			"integrity": "sha512-taHQQH/3ZyI3zP8M/puluDEIEvtQHVYcC6y3N8ijFtAd28+Ey/G4sg1u2gB01S8MwybLOKAp9/yCMu/uR5l3Ug==",
+			"version": "9.0.4",
+			"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.4.tgz",
+			"integrity": "sha512-zAuJWQflfx6dYJM62vna+Sn5aeSWhh3OB+wfUEACNcqUSc0AGc5JKl+ycL1vrH7frGTXhJchYjE1Hak8L819dA==",
 			"dev": true
 		},
 		"node_modules/@types/yargs": {
@@ -9121,17 +9121,17 @@
 			}
 		},
 		"@microsoft/api-extractor": {
-			"version": "7.36.4",
-			"resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.36.4.tgz",
-			"integrity": "sha512-21UECq8C/8CpHT23yiqTBQ10egKUacIpxkPyYR7hdswo/M5yTWdBvbq+77YC9uPKQJOUfOD1FImBQ1DzpsdeQQ==",
+			"version": "7.37.0",
+			"resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.37.0.tgz",
+			"integrity": "sha512-df/wffWpDhYRw7kzdxeHGsCpim+dC8aFiZlsJb4uFvVPWhBZpDzOhQxSUTFx3Df1ORY+/JjuPR3fDE9Hq+PHzQ==",
 			"dev": true,
 			"requires": {
-				"@microsoft/api-extractor-model": "7.27.6",
+				"@microsoft/api-extractor-model": "7.28.0",
 				"@microsoft/tsdoc": "0.14.2",
 				"@microsoft/tsdoc-config": "~0.16.1",
-				"@rushstack/node-core-library": "3.59.7",
-				"@rushstack/rig-package": "0.4.1",
-				"@rushstack/ts-command-line": "4.15.2",
+				"@rushstack/node-core-library": "3.60.0",
+				"@rushstack/rig-package": "0.5.0",
+				"@rushstack/ts-command-line": "4.16.0",
 				"colors": "~1.2.1",
 				"lodash": "~4.17.15",
 				"resolve": "~1.22.1",
@@ -9149,14 +9149,14 @@
 			}
 		},
 		"@microsoft/api-extractor-model": {
-			"version": "7.27.6",
-			"resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.27.6.tgz",
-			"integrity": "sha512-eiCnlayyum1f7fS2nA9pfIod5VCNR1G+Tq84V/ijDrKrOFVa598BLw145nCsGDMoFenV6ajNi2PR5WCwpAxW6Q==",
+			"version": "7.28.0",
+			"resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.28.0.tgz",
+			"integrity": "sha512-QIMtUVm1tqiKG+M6ciFgRShcDoovyltaeg+CbyOnyr7SMrp6gg0ojK5/nToMqR9kAvsTS4QVgW4Twl50EoAjcw==",
 			"dev": true,
 			"requires": {
 				"@microsoft/tsdoc": "0.14.2",
 				"@microsoft/tsdoc-config": "~0.16.1",
-				"@rushstack/node-core-library": "3.59.7"
+				"@rushstack/node-core-library": "3.60.0"
 			}
 		},
 		"@microsoft/tsdoc": {
@@ -9216,9 +9216,9 @@
 			}
 		},
 		"@rushstack/node-core-library": {
-			"version": "3.59.7",
-			"resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.59.7.tgz",
-			"integrity": "sha512-ln1Drq0h+Hwa1JVA65x5mlSgUrBa1uHL+V89FqVWQgXd1vVIMhrtqtWGQrhTnFHxru5ppX+FY39VWELF/FjQCw==",
+			"version": "3.60.0",
+			"resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.60.0.tgz",
+			"integrity": "sha512-PcyrqhILvzU+65wMFybQ2VeGNnU5JzhDq2OvUi3j6jPUxyllM7b2hrRUwCuVaYboewYzIbpzXFzgxe2K7ii1nw==",
 			"dev": true,
 			"requires": {
 				"colors": "~1.2.1",
@@ -9231,9 +9231,9 @@
 			}
 		},
 		"@rushstack/rig-package": {
-			"version": "0.4.1",
-			"resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.4.1.tgz",
-			"integrity": "sha512-AGRwpqlXNSp9LhUSz4HKI9xCluqQDt/obsQFdv/NYIekF3pTTPzc+HbQsIsjVjYnJ3DcmxOREVMhvrMEjpiq6g==",
+			"version": "0.5.0",
+			"resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.5.0.tgz",
+			"integrity": "sha512-bGnOW4DWHOePDiABKy6qyqYJl9i7fKn4bRucExRVt5QzyPxuVHMl8CMmCabtoNSpXzgG3qymWOrMoa/W2PpJrw==",
 			"dev": true,
 			"requires": {
 				"resolve": "~1.22.1",
@@ -9241,9 +9241,9 @@
 			}
 		},
 		"@rushstack/ts-command-line": {
-			"version": "4.15.2",
-			"resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.15.2.tgz",
-			"integrity": "sha512-5+C2uoJY8b+odcZD6coEe2XNC4ZjGB4vCMESbqW/8DHRWC/qIHfANdmN9F1wz/lAgxz72i7xRoVtPY2j7e4gpQ==",
+			"version": "4.16.0",
+			"resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.16.0.tgz",
+			"integrity": "sha512-WJKhdR9ThK9Iy7t78O3at7I3X4Ssp5RRZay/IQa8NywqkFy/DQbT3iLouodMMdUwLZD9n8n++xLubVd3dkmpkg==",
 			"dev": true,
 			"requires": {
 				"@types/argparse": "1.0.38",
@@ -9403,9 +9403,9 @@
 			}
 		},
 		"@types/jest": {
-			"version": "29.5.4",
-			"resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.4.tgz",
-			"integrity": "sha512-PhglGmhWeD46FYOVLt3X7TiWjzwuVGW9wG/4qocPevXMjCmrIc5b6db9WjeGE4QYVpUAWMDv3v0IiBwObY289A==",
+			"version": "29.5.5",
+			"resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.5.tgz",
+			"integrity": "sha512-ebylz2hnsWR9mYvmBFbXJXr+33UPc4+ZdxyDXh5w0FlPBTfCVN3wPL+kuOiQt3xvrK419v7XWeAs+AeOksafXg==",
 			"dev": true,
 			"requires": {
 				"expect": "^29.0.0",
@@ -9431,9 +9431,9 @@
 			"dev": true
 		},
 		"@types/node": {
-			"version": "20.6.0",
-			"resolved": "https://registry.npmjs.org/@types/node/-/node-20.6.0.tgz",
-			"integrity": "sha512-najjVq5KN2vsH2U/xyh2opaSEz6cZMR2SetLIlxlj08nOcmPOemJmUK2o4kUzfLqfrWE0PIrNeE16XhYDd3nqg==",
+			"version": "20.6.1",
+			"resolved": "https://registry.npmjs.org/@types/node/-/node-20.6.1.tgz",
+			"integrity": "sha512-4LcJvuXQlv4lTHnxwyHQZ3uR9Zw2j7m1C9DfuwoTFQQP4Pmu04O6IfLYgMmHoOCt0nosItLLZAH+sOrRE0Bo8g==",
 			"dev": true
 		},
 		"@types/normalize-package-data": {
@@ -9461,9 +9461,9 @@
 			"dev": true
 		},
 		"@types/uuid": {
-			"version": "9.0.3",
-			"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.3.tgz",
-			"integrity": "sha512-taHQQH/3ZyI3zP8M/puluDEIEvtQHVYcC6y3N8ijFtAd28+Ey/G4sg1u2gB01S8MwybLOKAp9/yCMu/uR5l3Ug==",
+			"version": "9.0.4",
+			"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.4.tgz",
+			"integrity": "sha512-zAuJWQflfx6dYJM62vna+Sn5aeSWhh3OB+wfUEACNcqUSc0AGc5JKl+ycL1vrH7frGTXhJchYjE1Hak8L819dA==",
 			"dev": true
 		},
 		"@types/yargs": {
diff --git a/package.json b/package.json
index d2c99f2..db5f4fa 100644
--- a/package.json
+++ b/package.json
@@ -36,11 +36,11 @@
 		"test": "npm run jest"
 	},
 	"devDependencies": {
-		"@microsoft/api-extractor": "7.36.4",
-		"@types/jest": "29.5.4",
-		"@types/node": "20.6.0",
+		"@microsoft/api-extractor": "7.37.0",
+		"@types/jest": "29.5.5",
+		"@types/node": "20.6.1",
 		"@types/seedrandom": "3.0.5",
-		"@types/uuid": "9.0.3",
+		"@types/uuid": "9.0.4",
 		"@typescript-eslint/eslint-plugin": "6.7.0",
 		"@typescript-eslint/parser": "6.7.0",
 		"chalk": "5.3.0",
diff --git a/playground/src/App.vue b/playground/src/App.vue
index ba01b99..fa2249f 100644
--- a/playground/src/App.vue
+++ b/playground/src/App.vue
@@ -99,6 +99,9 @@ const run = async () => {
 				print: true
 			});
 		},
+		err: (e) => {
+			window.alert('Error: ' + e.message);
+		},
 		log: (type, params) => {
 			switch (type) {
 				case 'end': logs.value.push({
@@ -115,7 +118,7 @@ const run = async () => {
 		await interpreter.exec(ast.value);
 	} catch (e) {
 		console.error(e);
-		window.alert('Error: ' + e);
+		window.alert('Internal Error: ' + e);
 	}
 }
 
diff --git a/run.js b/run.js
index f832fb6..8777f5c 100644
--- a/run.js
+++ b/run.js
@@ -1,8 +1,9 @@
 import fs from 'fs';
 import * as readline from 'readline';
 import chalk from 'chalk';
-import { Parser, Interpreter, utils } from '@syuilo/aiscript';
-const { valToString } = utils
+import { Parser, Interpreter, errors, utils } from '@syuilo/aiscript';
+const { AiScriptError } = errors;
+const { valToString } = utils;
 
 const i = readline.createInterface({
 	input: process.stdin,
@@ -18,6 +19,9 @@ const interpreter = new Interpreter({}, {
 	out(value) {
 		console.log(chalk.magenta(valToString(value, true)));
 	},
+	err(e) {
+		console.log(chalk.red(`${e}`));
+	},
 	log(type, params) {
 		/*
 		switch (type) {
@@ -36,6 +40,14 @@ const interpreter = new Interpreter({}, {
 });
 
 const script = fs.readFileSync('./test.is', 'utf8');
-const ast = Parser.parse(script);
-
-interpreter.exec(ast);
+try {
+	const ast = Parser.parse(script);
+	await interpreter.exec(ast);
+} catch (e) {
+	if (e instanceof AiScriptError) {
+		console.log(chalk.red(`${e}`));
+	} else {
+		throw e
+	}
+}
+i.close();
diff --git a/src/error.ts b/src/error.ts
index 73340ad..8c6be6d 100644
--- a/src/error.ts
+++ b/src/error.ts
@@ -13,6 +13,15 @@ export abstract class AiScriptError extends Error {
 	}
 }
 
+/**
+ * Wrapper for non-AiScript errors.
+ */
+export class NonAiScriptError extends AiScriptError {
+	constructor(error: any) {
+		super(`Internal Error. ${error}`, error);
+	}
+}
+
 export class SyntaxError extends AiScriptError {
 	constructor(message: string, info?: any) {
 		super(message, info);
diff --git a/src/interpreter/index.ts b/src/interpreter/index.ts
index 79395c5..89e2e5b 100644
--- a/src/interpreter/index.ts
+++ b/src/interpreter/index.ts
@@ -3,11 +3,11 @@
  */
 
 import { autobind } from '../utils/mini-autobind.js';
-import { IndexOutOfRangeError, RuntimeError } from '../error.js';
+import { AiScriptError, NonAiScriptError, IndexOutOfRangeError, RuntimeError } from '../error.js';
 import { Scope } from './scope.js';
 import { std } from './lib/std.js';
 import { assertNumber, assertString, assertFunction, assertBoolean, assertObject, assertArray, eq, isObject, isArray, expectAny, reprValue } from './util.js';
-import { NULL, RETURN, unWrapRet, FN_NATIVE, BOOL, NUM, STR, ARR, OBJ, FN, BREAK, CONTINUE } from './value.js';
+import { NULL, RETURN, unWrapRet, FN_NATIVE, BOOL, NUM, STR, ARR, OBJ, FN, BREAK, CONTINUE, ERROR } from './value.js';
 import { getPrimProp } from './primitive-props.js';
 import { Variable } from './variable.js';
 import type { Value, VFn } from './value.js';
@@ -28,6 +28,7 @@ export class Interpreter {
 		private opts: {
 			in?(q: string): Promise<string>;
 			out?(value: Value): void;
+			err?(e: AiScriptError): void;
 			log?(type: string, params: Record<string, any>): void;
 			maxStep?: number;
 		} = {},
@@ -66,16 +67,47 @@ export class Interpreter {
 	@autobind
 	public async exec(script?: Ast.Node[]): Promise<void> {
 		if (script == null || script.length === 0) return;
-
-		await this.collectNs(script);
-
-		const result = await this._run(script, this.scope);
-
-		this.log('end', { val: result });
+		try {
+			await this.collectNs(script);
+			const result = await this._run(script, this.scope);
+			this.log('end', { val: result });
+		} catch (e) {
+			this.handleError(e);
+		}
 	}
 
+	/**
+	 * Executes AiScript Function.
+	 * When it fails,
+	 * (i)If error callback is registered via constructor, this.abort is called and the callback executed, then returns ERROR('func_failed').
+	 * (ii)Otherwise, just throws a error.
+	 *
+	 * @remarks This is the same function as that passed to AiScript NATIVE functions as opts.topCall.
+	 *
+	 * @param fn - the function
+	 * @param args - arguments for the function
+	 * @returns Return value of the function, or ERROR('func_failed') when the (i) condition above is fulfilled.
+	 */
 	@autobind
 	public async execFn(fn: VFn, args: Value[]): Promise<Value> {
+		return await this._fn(fn, args)
+			.catch(e => {
+				this.handleError(e);
+				return ERROR('func_failed');
+			});
+	}
+	/**
+	 * Executes AiScript Function.
+	 * Almost same as execFn but when error occurs this always throws and never calls callback.
+	 *
+	 * @remarks This is the same function as that passed to AiScript NATIVE functions as opts.call.
+	 *
+	 * @param fn - the function
+	 * @param args - arguments for the function
+	 * @returns Return value of the function.
+	 */
+	@autobind
+	public execFnSimple(fn: VFn, args: Value[]): Promise<Value> {
 		return this._fn(fn, args);
 	}
 
@@ -120,6 +152,23 @@ export class Interpreter {
 		return meta;
 	}
 
+	@autobind
+	// eslint-disable-next-line @typescript-eslint/no-explicit-any
+	private handleError(e: any): void {
+		if (this.opts.err) {
+			if (!this.stop) {
+				this.abort();
+				if (e instanceof AiScriptError) {
+					this.opts.err(e);
+				} else {
+					this.opts.err(new NonAiScriptError(e));
+				}
+			}
+		} else {
+			throw e;
+		}
+	}
+
 	@autobind
 	private log(type: string, params: Record<string, unknown>): void {
 		if (this.opts.log) this.opts.log(type, params);
@@ -173,7 +222,8 @@ export class Interpreter {
 	private async _fn(fn: VFn, args: Value[]): Promise<Value> {
 		if (fn.native) {
 			const result = fn.native(args, {
-				call: this._fn,
+				call: this.execFnSimple,
+				topCall: this.execFn,
 				registerAbortHandler: this.registerAbortHandler,
 				unregisterAbortHandler: this.unregisterAbortHandler,
 			});
diff --git a/src/interpreter/lib/std.ts b/src/interpreter/lib/std.ts
index f46e20b..91b69ae 100644
--- a/src/interpreter/lib/std.ts
+++ b/src/interpreter/lib/std.ts
@@ -536,7 +536,7 @@ export const std: Record<string, Value> = {
 		}
 
 		const id = setInterval(() => {
-			opts.call(callback, []);
+			opts.topCall(callback, []);
 		}, interval.value);
 
 		const abortHandler = (): void => {
@@ -557,7 +557,7 @@ export const std: Record<string, Value> = {
 		assertFunction(callback);
 
 		const id = setTimeout(() => {
-			opts.call(callback, []);
+			opts.topCall(callback, []);
 		}, delay.value);
 
 		const abortHandler = (): void => {
diff --git a/src/interpreter/value.ts b/src/interpreter/value.ts
index 420ccfb..0933bc1 100644
--- a/src/interpreter/value.ts
+++ b/src/interpreter/value.ts
@@ -30,12 +30,16 @@ export type VObj = {
 	value: Map<string, Value>;
 };
 
+/**
+ * When your AiScript NATIVE function passes VFn.call to other caller(s) whose error thrown outside the scope, use VFn.topCall instead to keep it under AiScript error control system.
+ */
 export type VFn = {
 	type: 'fn';
 	args?: string[];
 	statements?: Node[];
 	native?: (args: (Value | undefined)[], opts: {
 		call: (fn: VFn, args: Value[]) => Promise<Value>;
+		topCall: (fn: VFn, args: Value[]) => Promise<Value>;
 		registerAbortHandler: (handler: () => void) => void;
 		unregisterAbortHandler: (handler: () => void) => void;
 	}) => Value | Promise<Value> | void;


Test patch:
diff --git a/test/index.ts b/test/index.ts
index 2e23691..cd7db13 100644
--- a/test/index.ts
+++ b/test/index.ts
@@ -5,7 +5,7 @@
 
 import * as assert from 'assert';
 import { Parser, Interpreter, utils, errors, Ast } from '../src';
-import { NUM, STR, NULL, ARR, OBJ, BOOL, TRUE, FALSE, ERROR } from '../src/interpreter/value';
+import { NUM, STR, NULL, ARR, OBJ, BOOL, TRUE, FALSE, ERROR ,FN_NATIVE } from '../src/interpreter/value';
 import { RuntimeError } from '../src/error';
 
 const exe = (program: string): Promise<any> => new Promise((ok, err) => {
@@ -71,6 +71,41 @@ describe('Interpreter', () => {
 	});
 });
 
+describe('error handler', () => {
+	test.concurrent('error from outside caller', async () => {
+		let outsideCaller: () => Promise<null> = async () => {};
+		let errCount: number = 0;
+		const aiscript = new Interpreter({
+			emitError: FN_NATIVE((_args, _opts) => {
+				throw Error('emitError');
+			}),
+			genOutsideCaller: FN_NATIVE(([fn], opts) => {
+				utils.assertFunction(fn);
+				outsideCaller = async () => {
+					opts.topCall(fn);
+				};
+			}),
+		}, {
+			err(e){ errCount+=1 },
+		});
+		await aiscript.exec(Parser.parse(`
+		genOutsideCaller(emitError)
+		`));
+		assert.strictEqual(errCount, 0);
+		await outsideCaller();
+		assert.strictEqual(errCount, 1);
+	});
+	test.concurrent('array.map calls the handler just once', async () => {
+		let errCount: number = 0;
+		const aiscript = new Interpreter({}, {
+			err(e){ errCount+=1 },
+		});
+		await aiscript.exec(Parser.parse(`
+		Core:range(1,5).map(@(){ hoge })
+		`));
+		assert.strictEqual(errCount, 1);
+});
+
 describe('ops', () => {
 	test.concurrent('==', async () => {
 		eq(await exe('<: (1 == 1)'), BOOL(true));