Repository: syuilo/aiscript
Pull request #323 (2023-09-05 13:29:14)

エラー型を追加
<!-- ℹ お読みください
PRありがとうございます！ PRを作成する前に、以下をご確認ください:
- 可能であればタイトルに、以下で示すようなPRの種類が分かるキーワードをプリフィクスしてください。
  - fix / refactor / feat / enhance / perf / chore
  - また、PRの粒度が適切であることを確認してください。ひとつのPRに複数の種類の変更や関心を含めることは避けてください。
- このPRによって解決されるIssueがある場合は、そのIssueへの参照を本文内に含めてください。
- CHANGELOG.mdに変更点を追記してください。リファクタリングなど、利用者に影響を与えない変更についてはこの限りではありません。
- この変更により新たに作成、もしくは更新すべきドキュメントがないか確認してください。
- 機能追加やバグ修正をした場合は、可能であればテストケースを追加してください。
- テスト、Lintが通っていることを予め確認してください。
  - `npm run test`、`npm run lint`でぞれぞれ実施可能です
- `npm run api`を実行してAPIレポートを更新し、差分がある場合はコミットしてください。
ご協力ありがとうございます🤗
-->
<!-- ℹ README
Thank you for your PR! Before creating a PR, please check the following:
- If possible, prefix the title with a keyword that identifies the type of this PR, as shown below.
  - fix / refactor / feat / enhance / perf / chore
  - Also, make sure that the granularity of this PR is appropriate. Please do not include more than one type of change or interest in a single PR.
- If there is an Issue which will be resolved by this PR, please include a reference to the Issue in the text.
- Please add the summary of the changes to CHANGELOG.md. However, this is not necessary for changes that do not affect the users, such as refactoring.
- Check if there are any documents that need to be created or updated due to this change.
- If you have added a feature or fixed a bug, please add a test case if possible.
- Please make sure that tests and Lint are passed in advance.
  - You can run it with `npm run test` and `npm run lint`.
- Run `npm run api` to update the API report and commit it if there are any diffs.
Thanks for your cooperation 🤗
-->

# What
<!-- このPRで何をしたのか？ どう変わるのか？ -->
<!-- What did you do with this PR? How will it change things? -->
新しくエラー型を追加し、試験的にJson:parseに導入します。
#304 を受けて、ひとまず`name`と`info`のprimitive-propsを持つだけのシンプルな型にしました。

# Why
<!-- なぜそうするのか？ どういう意図なのか？ 何が困っているのか？ -->
<!-- Why do you do it? What are your intentions? What is the problem? -->
AiScriptの実行を停止せずに関数の実行が失敗したことを知らせる手段を作るため。

# Additional info (optional)
<!-- テスト観点など -->
<!-- Test perspective, etc -->


codecov[bot]: ## [Codecov](https://app.codecov.io/gh/syuilo/aiscript/pull/323?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=syuilo) Report
Patch coverage: **`100.00%`** and project coverage change: **`+0.20%`** :tada:
> Comparison is base [(`63eb8fd`)](https://app.codecov.io/gh/syuilo/aiscript/commit/63eb8fd7a1ce8503c91aa66b6f5120bbe46701ec?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=syuilo) 87.84% compared to head [(`4e38c9a`)](https://app.codecov.io/gh/syuilo/aiscript/pull/323?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=syuilo) 88.05%.

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


```diff
@@            Coverage Diff             @@
##           master     #323      +/-   ##
==========================================
+ Coverage   87.84%   88.05%   +0.20%     
==========================================
  Files          20       20              
  Lines        3292     3314      +22     
  Branches      537      541       +4     
==========================================
+ Hits         2892     2918      +26     
+ Misses        389      385       -4     
  Partials       11       11              
```


| [Files Changed](https://app.codecov.io/gh/syuilo/aiscript/pull/323?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=syuilo) | Coverage Δ | |
|---|---|---|
| [src/interpreter/lib/std.ts](https://app.codecov.io/gh/syuilo/aiscript/pull/323?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=syuilo#diff-c3JjL2ludGVycHJldGVyL2xpYi9zdGQudHM=) | `75.17% <100.00%> (+0.17%)` | :arrow_up: |
| [src/interpreter/primitive-props.ts](https://app.codecov.io/gh/syuilo/aiscript/pull/323?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=syuilo#diff-c3JjL2ludGVycHJldGVyL3ByaW1pdGl2ZS1wcm9wcy50cw==) | `97.11% <100.00%> (+0.07%)` | :arrow_up: |
| [src/interpreter/value.ts](https://app.codecov.io/gh/syuilo/aiscript/pull/323?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=syuilo#diff-c3JjL2ludGVycHJldGVyL3ZhbHVlLnRz) | `100.00% <100.00%> (ø)` | |

... and [1 file with indirect coverage changes](https://app.codecov.io/gh/syuilo/aiscript/pull/323/indirect-changes?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=syuilo)


</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/syuilo/aiscript/pull/323?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).

FineArchs: コンフリクトの解決を行いました。

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c814152..0df3fc6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,8 @@
 - 指定時間待機する関数`Core:sleep`を追加
 - `exists 変数名` の構文で変数が存在するか判定できるように
 - オブジェクトを添字で参照できるように（`object['index']`のように）
+- 「エラー型（`error`）」を導入
+- `Json:parse`がパース失敗時にエラー型の値を返すように
 
 # 0.15.0
 - Mathを強化
diff --git a/docs/get-started.md b/docs/get-started.md
index bd70436..e20816d 100644
--- a/docs/get-started.md
+++ b/docs/get-started.md
@@ -51,6 +51,7 @@ this is a comment
 	<tr><td>オブジェクト</td><td><code>obj</code></td><td><code>{ foo: "bar"; a: 42; }</code></td></tr>
 	<tr><td>null</td><td><code>null</code></td><td><code>null</code></td></tr>
 	<tr><td>関数</td><td><code>fn</code></td><td><code>@(x) { x }</code></td></tr>
+	<tr><td>エラー</td><td><code>error</code></td><td><code>(TODO)</code></td></tr>
 </table>
 
 ## 変数
@@ -256,4 +257,15 @@ AiScriptファイルにメタデータを埋め込める機能です。
 	version: 42
 	keywords: ["foo" "bar" "baz"]
 }
-```
\ No newline at end of file
+```
+
+## エラー型
+一部の標準関数は実行失敗時にエラー型の値を返します。
+これによりエラー処理を行うことができます。
+```
+@validate(str){
+	let v=Json:parse(str)
+	if (Core:type(v)=='error') print(v.name)
+	else print('successful')
+}
+```
diff --git a/docs/std.md b/docs/std.md
index 7d4bfe1..ed87a68 100644
--- a/docs/std.md
+++ b/docs/std.md
@@ -33,10 +33,10 @@ AiScriptのバージョンです。
 JSONを生成します。  
 
 ### @Json:parse(_json_: str): value
-JSONをパースします。  
+JSONをパースします。 引数がJSONとしてパース可能性でない場合、エラー型の値（`name`=`'not_json'`）を返します。 
 
 ### @Json:parsable(_str_: str): bool
-文字列がJSONとしてパース可能であるかの判定を行います。 
+文字列がJSONとしてパース可能であるかの判定を行います。歴史的理由により存在しています 
 
 ## :: Date
 
@@ -236,6 +236,14 @@ _codepoint_ は 0 以上、10FFFF<sub>16</sub> 以下である必要がありま
 ### @Obj:copy(_v_: obj): obj
 オブジェクトのコピーを生成します。  
 
+## :: Error
+
+### @(_v_: error).name(): str
+エラーの識別子となる文字列を返します。
+
+### @(_v_: error).info(): value
+エラーに付加情報がある場合、それを返します。
+
 ## :: Async
 
 ### @Async:interval(_interval_: num, _callback_: fn, _immediate_?: bool): fn
diff --git a/etc/aiscript.api.md b/etc/aiscript.api.md
index 5cc949b..f5c4ff0 100644
--- a/etc/aiscript.api.md
+++ b/etc/aiscript.api.md
@@ -1,1036 +1,1048 @@
-## API Report File for "@syuilo/aiscript"
-
-> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
-
-```ts
-
-// Warning: (ae-forgotten-export) The symbol "NodeBase" needs to be exported by the entry point index.d.ts
-//
-// @public (undocumented)
-type AddAssign = NodeBase & {
-    type: 'addAssign';
-    dest: Expression;
-    expr: Expression;
-};
-
-// Warning: (ae-forgotten-export) The symbol "NodeBase_2" needs to be exported by the entry point index.d.ts
-//
-// @public (undocumented)
-type AddAssign_2 = NodeBase_2 & {
-    type: 'addAssign';
-    dest: Expression_2;
-    expr: Expression_2;
-};
-
-// @public (undocumented)
-abstract class AiScriptError extends Error {
-    constructor(message: string, info?: any);
-    // (undocumented)
-    info?: any;
-}
-
-// @public (undocumented)
-type And = NodeBase & {
-    type: 'and';
-    left: Expression;
-    right: Expression;
-};
-
-// @public (undocumented)
-type And_2 = NodeBase_2 & {
-    type: 'and';
-    left: Expression_2;
-    right: Expression_2;
-};
-
-// @public (undocumented)
-const ARR: (arr: VArr['value']) => VArr;
-
-// @public (undocumented)
-type Arr = NodeBase & {
-    type: 'arr';
-    value: Expression[];
-};
-
-// Warning: (ae-forgotten-export) The symbol "ChainProp" needs to be exported by the entry point index.d.ts
-//
-// @public (undocumented)
-type Arr_2 = NodeBase_2 & ChainProp & {
-    type: 'arr';
-    value: Expression_2[];
-};
-
-// @public (undocumented)
-function assertArray(val: Value | null | undefined): asserts val is VArr;
-
-// @public (undocumented)
-function assertBoolean(val: Value | null | undefined): asserts val is VBool;
-
-// @public (undocumented)
-function assertFunction(val: Value | null | undefined): asserts val is VFn;
-
-// @public (undocumented)
-function assertNumber(val: Value | null | undefined): asserts val is VNum;
-
-// @public (undocumented)
-function assertObject(val: Value | null | undefined): asserts val is VObj;
-
-// @public (undocumented)
-function assertString(val: Value | null | undefined): asserts val is VStr;
-
-// @public (undocumented)
-type Assign = NodeBase & {
-    type: 'assign';
-    dest: Expression;
-    expr: Expression;
-};
-
-// @public (undocumented)
-type Assign_2 = NodeBase_2 & {
-    type: 'assign';
-    dest: Expression_2;
-    expr: Expression_2;
-};
-
-declare namespace Ast {
-    export {
-        isStatement,
-        isExpression,
-        Loc,
-        Node_2 as Node,
-        Statement,
-        Expression,
-        Namespace,
-        Meta,
-        Definition,
-        Attribute,
-        Return,
-        Each,
-        For,
-        Loop,
-        Break,
-        Continue,
-        AddAssign,
-        SubAssign,
-        Assign,
-        Not,
-        And,
-        Or,
-        If,
-        Fn,
-        Match,
-        Block,
-        Exists,
-        Tmpl,
-        Str,
-        Num,
-        Bool,
-        Null,
-        Obj,
-        Arr,
-        Identifier,
-        Call,
-        Index,
-        Prop,
-        TypeSource,
-        NamedTypeSource,
-        FnTypeSource
-    }
-}
-export { Ast }
-
-// @public (undocumented)
-type Attr_2 = {
-    attr?: {
-        name: string;
-        value: Value;
-    }[];
-};
-
-// @public (undocumented)
-type Attribute = NodeBase & {
-    type: 'attr';
-    name: string;
-    value: Expression;
-};
-
-// @public (undocumented)
-type Attribute_2 = NodeBase_2 & {
-    type: 'attr';
-    name: string;
-    value: Expression_2;
-};
-
-// @public (undocumented)
-type Block = NodeBase & {
-    type: 'block';
-    statements: (Statement | Expression)[];
-};
-
-// @public (undocumented)
-type Block_2 = NodeBase_2 & ChainProp & {
-    type: 'block';
-    statements: (Statement_2 | Expression_2)[];
-};
-
-// @public (undocumented)
-const BOOL: (bool: VBool['value']) => VBool;
-
-// @public (undocumented)
-type Bool = NodeBase & {
-    type: 'bool';
-    value: boolean;
-};
-
-// @public (undocumented)
-type Bool_2 = NodeBase_2 & ChainProp & {
-    type: 'bool';
-    value: boolean;
-};
-
-// @public (undocumented)
-const BREAK: () => Value;
-
-// @public (undocumented)
-type Break = NodeBase & {
-    type: 'break';
-};
-
-// @public (undocumented)
-type Break_2 = NodeBase_2 & {
-    type: 'break';
-};
-
-// @public (undocumented)
-function CALL(target: Call_2['target'], args: Call_2['args'], loc?: {
-    start: number;
-    end: number;
-}): Call_2;
-
-// @public (undocumented)
-type Call = NodeBase & {
-    type: 'call';
-    target: Expression;
-    args: Expression[];
-};
-
-// @public (undocumented)
-type Call_2 = NodeBase_2 & {
-    type: 'call';
-    target: Expression_2;
-    args: Expression_2[];
-};
-
-// @public (undocumented)
-type CallChain = NodeBase_2 & {
-    type: 'callChain';
-    args: Expression_2[];
-};
-
-// @public (undocumented)
-type ChainMember = CallChain | IndexChain | PropChain;
-
-// @public (undocumented)
-const CONTINUE: () => Value;
-
-// @public (undocumented)
-type Continue = NodeBase & {
-    type: 'continue';
-};
-
-// @public (undocumented)
-type Continue_2 = NodeBase_2 & {
-    type: 'continue';
-};
-
-declare namespace Cst {
-    export {
-        isStatement_2 as isStatement,
-        isExpression_2 as isExpression,
-        hasChainProp,
-        CALL,
-        INDEX,
-        PROP,
-        Node_3 as Node,
-        Statement_2 as Statement,
-        Expression_2 as Expression,
-        Namespace_2 as Namespace,
-        Meta_2 as Meta,
-        Definition_2 as Definition,
-        Attribute_2 as Attribute,
-        Return_2 as Return,
-        Each_2 as Each,
-        For_2 as For,
-        Loop_2 as Loop,
-        Break_2 as Break,
-        Continue_2 as Continue,
-        AddAssign_2 as AddAssign,
-        SubAssign_2 as SubAssign,
-        Assign_2 as Assign,
-        InfixOperator,
-        Infix,
-        Not_2 as Not,
-        And_2 as And,
-        Or_2 as Or,
-        If_2 as If,
-        Fn_2 as Fn,
-        Match_2 as Match,
-        Block_2 as Block,
-        Exists_2 as Exists,
-        Tmpl_2 as Tmpl,
-        Str_2 as Str,
-        Num_2 as Num,
-        Bool_2 as Bool,
-        Null_2 as Null,
-        Obj_2 as Obj,
-        Arr_2 as Arr,
-        Identifier_2 as Identifier,
-        ChainMember,
-        CallChain,
-        IndexChain,
-        PropChain,
-        Call_2 as Call,
-        Index_2 as Index,
-        Prop_2 as Prop,
-        TypeSource_2 as TypeSource,
-        NamedTypeSource_2 as NamedTypeSource,
-        FnTypeSource_2 as FnTypeSource
-    }
-}
-export { Cst }
-
-// @public (undocumented)
-type Definition = NodeBase & {
-    type: 'def';
-    name: string;
-    varType?: TypeSource;
-    expr: Expression;
-    mut: boolean;
-    attr: Attribute[];
-};
-
-// @public (undocumented)
-type Definition_2 = NodeBase_2 & {
-    type: 'def';
-    name: string;
-    varType?: TypeSource_2;
-    expr: Expression_2;
-    mut: boolean;
-    attr?: Attribute_2[];
-};
-
-// @public (undocumented)
-type Each = NodeBase & {
-    type: 'each';
-    var: string;
-    items: Expression;
-    for: Statement | Expression;
-};
-
-// @public (undocumented)
-type Each_2 = NodeBase_2 & {
-    type: 'each';
-    var: string;
-    items: Expression_2;
-    for: Statement_2 | Expression_2;
-};
-
-// @public (undocumented)
-function eq(a: Value, b: Value): boolean;
-
-declare namespace errors {
-    export {
-        AiScriptError,
-        SyntaxError_2 as SyntaxError,
-        TypeError_2 as TypeError,
-        RuntimeError,
-        IndexOutOfRangeError
-    }
-}
-export { errors }
-
-// @public (undocumented)
-type Exists = NodeBase & {
-    type: 'exists';
-    identifier: Identifier;
-};
-
-// @public (undocumented)
-type Exists_2 = NodeBase_2 & ChainProp & {
-    type: 'exists';
-    identifier: Identifier_2;
-};
-
-// @public (undocumented)
-function expectAny(val: Value | null | undefined): asserts val is Value;
-
-// @public (undocumented)
-type Expression = If | Fn | Match | Block | Exists | Tmpl | Str | Num | Bool | Null | Obj | Arr | Not | And | Or | Identifier | Call | Index | Prop;
-
-// @public (undocumented)
-type Expression_2 = Infix | Not_2 | And_2 | Or_2 | If_2 | Fn_2 | Match_2 | Block_2 | Exists_2 | Tmpl_2 | Str_2 | Num_2 | Bool_2 | Null_2 | Obj_2 | Arr_2 | Identifier_2 | Call_2 | // IR
-Index_2 | // IR
-Prop_2;
-
-// @public (undocumented)
-const FALSE: {
-    type: "bool";
-    value: boolean;
-};
-
-// @public (undocumented)
-const FN: (args: VFn['args'], statements: VFn['statements'], scope: VFn['scope']) => VFn;
-
-// @public (undocumented)
-type Fn = NodeBase & {
-    type: 'fn';
-    args: {
-        name: string;
-        argType?: TypeSource;
-    }[];
-    retType?: TypeSource;
-    children: (Statement | Expression)[];
-};
-
-// @public (undocumented)
-type Fn_2 = NodeBase_2 & ChainProp & {
-    type: 'fn';
-    args: {
-        name: string;
-        argType?: TypeSource_2;
-    }[];
-    retType?: TypeSource_2;
-    children: (Statement_2 | Expression_2)[];
-};
-
-// @public (undocumented)
-const FN_NATIVE: (fn: VFn['native']) => VFn;
-
-// @public (undocumented)
-type FnTypeSource = NodeBase & {
-    type: 'fnTypeSource';
-    args: TypeSource[];
-    result: TypeSource;
-};
-
-// @public (undocumented)
-type FnTypeSource_2 = NodeBase_2 & {
-    type: 'fnTypeSource';
-    args: TypeSource_2[];
-    result: TypeSource_2;
-};
-
-// @public (undocumented)
-type For = NodeBase & {
-    type: 'for';
-    var?: string;
-    from?: Expression;
-    to?: Expression;
-    times?: Expression;
-    for: Statement | Expression;
-};
-
-// @public (undocumented)
-type For_2 = NodeBase_2 & {
-    type: 'for';
-    var?: string;
-    from?: Expression_2;
-    to?: Expression_2;
-    times?: Expression_2;
-    for: Statement_2 | Expression_2;
-};
-
-// @public (undocumented)
-function getLangVersion(input: string): string | null;
-
-// @public (undocumented)
-function hasChainProp<T extends Node_3>(x: T): x is T & ChainProp;
-
-// @public (undocumented)
-type Identifier = NodeBase & {
-    type: 'identifier';
-    name: string;
-};
-
-// @public (undocumented)
-type Identifier_2 = NodeBase_2 & ChainProp & {
-    type: 'identifier';
-    name: string;
-};
-
-// @public (undocumented)
-type If = NodeBase & {
-    type: 'if';
-    cond: Expression;
-    then: Statement | Expression;
-    elseif: {
-        cond: Expression;
-        then: Statement | Expression;
-    }[];
-    else?: Statement | Expression;
-};
-
-// @public (undocumented)
-type If_2 = NodeBase_2 & {
-    type: 'if';
-    cond: Expression_2;
-    then: Statement_2 | Expression_2;
-    elseif: {
-        cond: Expression_2;
-        then: Statement_2 | Expression_2;
-    }[];
-    else?: Statement_2 | Expression_2;
-};
-
-// @public (undocumented)
-function INDEX(target: Index_2['target'], index: Index_2['index'], loc?: {
-    start: number;
-    end: number;
-}): Index_2;
-
-// @public (undocumented)
-type Index = NodeBase & {
-    type: 'index';
-    target: Expression;
-    index: Expression;
-};
-
-// @public (undocumented)
-type Index_2 = NodeBase_2 & {
-    type: 'index';
-    target: Expression_2;
-    index: Expression_2;
-};
-
-// @public (undocumented)
-type IndexChain = NodeBase_2 & {
-    type: 'indexChain';
-    index: Expression_2;
-};
-
-// @public (undocumented)
-class IndexOutOfRangeError extends RuntimeError {
-    constructor(message: string, info?: any);
-}
-
-// @public (undocumented)
-type Infix = NodeBase_2 & {
-    type: 'infix';
-    operands: Expression_2[];
-    operators: InfixOperator[];
-};
-
-// @public (undocumented)
-type InfixOperator = '||' | '&&' | '==' | '!=' | '<=' | '>=' | '<' | '>' | '+' | '-' | '*' | '^' | '/' | '%';
-
-// @public (undocumented)
-export class Interpreter {
-    constructor(vars: Record<string, Value>, opts?: {
-        in?(q: string): Promise<string>;
-        out?(value: Value): void;
-        log?(type: string, params: Record<string, any>): void;
-        maxStep?: number;
-    });
-    // (undocumented)
-    abort(): void;
-    // (undocumented)
-    static collectMetadata(script?: Ast.Node[]): Map<any, any> | undefined;
-    // (undocumented)
-    exec(script?: Ast.Node[]): Promise<void>;
-    // (undocumented)
-    execFn(fn: VFn, args: Value[]): Promise<Value>;
-    // (undocumented)
-    registerAbortHandler(handler: () => void): void;
-    // (undocumented)
-    scope: Scope;
-    // (undocumented)
-    stepCount: number;
-    // (undocumented)
-    unregisterAbortHandler(handler: () => void): void;
-}
-
-// @public (undocumented)
-function isArray(val: Value): val is VArr;
-
-// @public (undocumented)
-function isBoolean(val: Value): val is VBool;
-
-// @public (undocumented)
-function isExpression(x: Node_2): x is Expression;
-
-// @public (undocumented)
-function isExpression_2(x: Node_3): x is Expression_2;
-
-// @public (undocumented)
-function isFunction(val: Value): val is VFn;
-
-// @public (undocumented)
-function isNumber(val: Value): val is VNum;
-
-// @public (undocumented)
-function isObject(val: Value): val is VObj;
-
-// @public (undocumented)
-function isStatement(x: Node_2): x is Statement;
-
-// @public (undocumented)
-function isStatement_2(x: Node_3): x is Statement_2;
-
-// @public (undocumented)
-function isString(val: Value): val is VStr;
-
-// @public (undocumented)
-function jsToVal(val: any): Value;
-
-// @public
-type Loc = {
-    start: number;
-    end: number;
-};
-
-// @public (undocumented)
-type Loop = NodeBase & {
-    type: 'loop';
-    statements: (Statement | Expression)[];
-};
-
-// @public (undocumented)
-type Loop_2 = NodeBase_2 & {
-    type: 'loop';
-    statements: (Statement_2 | Expression_2)[];
-};
-
-// @public (undocumented)
-type Match = NodeBase & {
-    type: 'match';
-    about: Expression;
-    qs: {
-        q: Expression;
-        a: Statement | Expression;
-    }[];
-    default?: Statement | Expression;
-};
-
-// @public (undocumented)
-type Match_2 = NodeBase_2 & ChainProp & {
-    type: 'match';
-    about: Expression_2;
-    qs: {
-        q: Expression_2;
-        a: Statement_2 | Expression_2;
-    }[];
-    default?: Statement_2 | Expression_2;
-};
-
-// @public (undocumented)
-type Meta = NodeBase & {
-    type: 'meta';
-    name: string | null;
-    value: Expression;
-};
-
-// @public (undocumented)
-type Meta_2 = NodeBase_2 & {
-    type: 'meta';
-    name: string | null;
-    value: Expression_2;
-};
-
-// @public (undocumented)
-type NamedTypeSource = NodeBase & {
-    type: 'namedTypeSource';
-    name: string;
-    inner?: TypeSource;
-};
-
-// @public (undocumented)
-type NamedTypeSource_2 = NodeBase_2 & {
-    type: 'namedTypeSource';
-    name: string;
-    inner?: TypeSource_2;
-};
-
-// @public (undocumented)
-type Namespace = NodeBase & {
-    type: 'ns';
-    name: string;
-    members: (Definition | Namespace)[];
-};
-
-// @public (undocumented)
-type Namespace_2 = NodeBase_2 & {
-    type: 'ns';
-    name: string;
-    members: (Definition_2 | Namespace_2)[];
-};
-
-// @public (undocumented)
-type Node_2 = Namespace | Meta | Statement | Expression | TypeSource;
-
-// @public
-type Node_3 = Namespace_2 | Meta_2 | Statement_2 | Expression_2 | ChainMember | TypeSource_2;
-
-// @public (undocumented)
-type Not = NodeBase & {
-    type: 'not';
-    expr: Expression;
-};
-
-// @public (undocumented)
-type Not_2 = NodeBase_2 & {
-    type: 'not';
-    expr: Expression_2;
-};
-
-// @public (undocumented)
-const NULL: {
-    type: "null";
-};
-
-// @public (undocumented)
-type Null = NodeBase & {
-    type: 'null';
-};
-
-// @public (undocumented)
-type Null_2 = NodeBase_2 & ChainProp & {
-    type: 'null';
-};
-
-// @public (undocumented)
-const NUM: (num: VNum['value']) => VNum;
-
-// @public (undocumented)
-type Num = NodeBase & {
-    type: 'num';
-    value: number;
-};
-
-// @public (undocumented)
-type Num_2 = NodeBase_2 & ChainProp & {
-    type: 'num';
-    value: number;
-};
-
-// @public (undocumented)
-const OBJ: (obj: VObj['value']) => VObj;
-
-// @public (undocumented)
-type Obj = NodeBase & {
-    type: 'obj';
-    value: Map<string, Expression>;
-};
-
-// @public (undocumented)
-type Obj_2 = NodeBase_2 & ChainProp & {
-    type: 'obj';
-    value: Map<string, Expression_2>;
-};
-
-// @public (undocumented)
-type Or = NodeBase & {
-    type: 'or';
-    left: Expression;
-    right: Expression;
-};
-
-// @public (undocumented)
-type Or_2 = NodeBase_2 & {
-    type: 'or';
-    left: Expression_2;
-    right: Expression_2;
-};
-
-// @public (undocumented)
-export class Parser {
-    constructor();
-    // (undocumented)
-    addPlugin(type: PluginType, plugin: ParserPlugin): void;
-    // (undocumented)
-    static parse(input: string): Ast.Node[];
-    // (undocumented)
-    parse(input: string): Ast.Node[];
-}
-
-// @public (undocumented)
-export type ParserPlugin = (nodes: Cst.Node[]) => Cst.Node[];
-
-// @public (undocumented)
-export type PluginType = 'validate' | 'transform';
-
-// @public (undocumented)
-function PROP(target: Prop_2['target'], name: Prop_2['name'], loc?: {
-    start: number;
-    end: number;
-}): Prop_2;
-
-// @public (undocumented)
-type Prop = NodeBase & {
-    type: 'prop';
-    target: Expression;
-    name: string;
-};
-
-// @public (undocumented)
-type Prop_2 = NodeBase_2 & {
-    type: 'prop';
-    target: Expression_2;
-    name: string;
-};
-
-// @public (undocumented)
-type PropChain = NodeBase_2 & {
-    type: 'propChain';
-    name: string;
-};
-
-// @public (undocumented)
-function reprValue(value: Value, literalLike?: boolean, processedObjects?: Set<object>): string;
-
-// @public (undocumented)
-const RETURN: (v: VReturn['value']) => Value;
-
-// @public (undocumented)
-type Return = NodeBase & {
-    type: 'return';
-    expr: Expression;
-};
-
-// @public (undocumented)
-type Return_2 = NodeBase_2 & {
-    type: 'return';
-    expr: Expression_2;
-};
-
-// @public (undocumented)
-class RuntimeError extends AiScriptError {
-    constructor(message: string, info?: any);
-}
-
-// @public (undocumented)
-export class Scope {
-    constructor(layerdStates?: Scope['layerdStates'], parent?: Scope, name?: Scope['name']);
-    add(name: string, val: Value): void;
-    assign(name: string, val: Value): void;
-    // (undocumented)
-    createChildScope(states?: Map<string, Value>, name?: Scope['name']): Scope;
-    exists(name: string): boolean;
-    get(name: string): Value;
-    getAll(): Map<string, Value>;
-    // (undocumented)
-    name: string;
-    // (undocumented)
-    opts: {
-        log?(type: string, params: Record<string, any>): void;
-        onUpdated?(name: string, value: Value): void;
-    };
-}
-
-// @public (undocumented)
-type Statement = Definition | Return | Each | For | Loop | Break | Continue | Assign | AddAssign | SubAssign;
-
-// @public (undocumented)
-type Statement_2 = Definition_2 | Return_2 | Attribute_2 | // AST
-Each_2 | For_2 | Loop_2 | Break_2 | Continue_2 | Assign_2 | AddAssign_2 | SubAssign_2;
-
-// @public (undocumented)
-const STR: (str: VStr['value']) => VStr;
-
-// @public (undocumented)
-type Str = NodeBase & {
-    type: 'str';
-    value: string;
-};
-
-// @public (undocumented)
-type Str_2 = NodeBase_2 & ChainProp & {
-    type: 'str';
-    value: string;
-};
-
-// @public (undocumented)
-type SubAssign = NodeBase & {
-    type: 'subAssign';
-    dest: Expression;
-    expr: Expression;
-};
-
-// @public (undocumented)
-type SubAssign_2 = NodeBase_2 & {
-    type: 'subAssign';
-    dest: Expression_2;
-    expr: Expression_2;
-};
-
-// @public (undocumented)
-class SyntaxError_2 extends AiScriptError {
-    constructor(message: string, info?: any);
-}
-
-// @public (undocumented)
-type Tmpl = NodeBase & {
-    type: 'tmpl';
-    tmpl: (string | Expression)[];
-};
-
-// @public (undocumented)
-type Tmpl_2 = NodeBase_2 & ChainProp & {
-    type: 'tmpl';
-    tmpl: (string | Expression_2)[];
-};
-
-// @public (undocumented)
-const TRUE: {
-    type: "bool";
-    value: boolean;
-};
-
-// @public (undocumented)
-class TypeError_2 extends AiScriptError {
-    constructor(message: string, info?: any);
-}
-
-// @public (undocumented)
-type TypeSource = NamedTypeSource | FnTypeSource;
-
-// @public (undocumented)
-type TypeSource_2 = NamedTypeSource_2 | FnTypeSource_2;
-
-// @public (undocumented)
-const unWrapRet: (v: Value) => Value;
-
-declare namespace utils {
-    export {
-        expectAny,
-        assertBoolean,
-        assertFunction,
-        assertString,
-        assertNumber,
-        assertObject,
-        assertArray,
-        isBoolean,
-        isFunction,
-        isString,
-        isNumber,
-        isObject,
-        isArray,
-        eq,
-        valToString,
-        valToJs,
-        jsToVal,
-        getLangVersion,
-        reprValue
-    }
-}
-export { utils }
-
-// @public (undocumented)
-function valToJs(val: Value): any;
-
-// @public (undocumented)
-function valToString(val: Value, simple?: boolean): string;
-
-// @public (undocumented)
-type Value = (VNull | VBool | VNum | VStr | VArr | VObj | VFn | VReturn | VBreak | VContinue) & Attr_2;
-
-declare namespace values {
-    export {
-        VNull,
-        VBool,
-        VNum,
-        VStr,
-        VArr,
-        VObj,
-        VFn,
-        VReturn,
-        VBreak,
-        VContinue,
-        Attr_2 as Attr,
-        Value,
-        NULL,
-        TRUE,
-        FALSE,
-        NUM,
-        STR,
-        BOOL,
-        OBJ,
-        ARR,
-        FN,
-        FN_NATIVE,
-        RETURN,
-        BREAK,
-        CONTINUE,
-        unWrapRet
-    }
-}
-export { values }
-
-// @public (undocumented)
-type VArr = {
-    type: 'arr';
-    value: Value[];
-};
-
-// @public (undocumented)
-type VBool = {
-    type: 'bool';
-    value: boolean;
-};
-
-// @public (undocumented)
-type VBreak = {
-    type: 'break';
-    value: null;
-};
-
-// @public (undocumented)
-type VContinue = {
-    type: 'continue';
-    value: null;
-};
-
-// @public (undocumented)
-type VFn = {
-    type: 'fn';
-    args?: string[];
-    statements?: Node_2[];
-    native?: (args: (Value | undefined)[], opts: {
-        call: (fn: VFn, args: Value[]) => Promise<Value>;
-        registerAbortHandler: (handler: () => void) => void;
-        unregisterAbortHandler: (handler: () => void) => void;
-    }) => Value | Promise<Value> | void;
-    scope?: Scope;
-};
-
-// @public (undocumented)
-type VNull = {
-    type: 'null';
-};
-
-// @public (undocumented)
-type VNum = {
-    type: 'num';
-    value: number;
-};
-
-// @public (undocumented)
-type VObj = {
-    type: 'obj';
-    value: Map<string, Value>;
-};
-
-// @public (undocumented)
-type VReturn = {
-    type: 'return';
-    value: Value;
-};
-
-// @public (undocumented)
-type VStr = {
-    type: 'str';
-    value: string;
-};
-
-// (No @packageDocumentation comment for this package)
-
-```
+## API Report File for "@syuilo/aiscript"
+
+> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
+
+```ts
+
+// Warning: (ae-forgotten-export) The symbol "NodeBase" needs to be exported by the entry point index.d.ts
+//
+// @public (undocumented)
+type AddAssign = NodeBase & {
+    type: 'addAssign';
+    dest: Expression;
+    expr: Expression;
+};
+
+// Warning: (ae-forgotten-export) The symbol "NodeBase_2" needs to be exported by the entry point index.d.ts
+//
+// @public (undocumented)
+type AddAssign_2 = NodeBase_2 & {
+    type: 'addAssign';
+    dest: Expression_2;
+    expr: Expression_2;
+};
+
+// @public (undocumented)
+abstract class AiScriptError extends Error {
+    constructor(message: string, info?: any);
+    // (undocumented)
+    info?: any;
+}
+
+// @public (undocumented)
+type And = NodeBase & {
+    type: 'and';
+    left: Expression;
+    right: Expression;
+};
+
+// @public (undocumented)
+type And_2 = NodeBase_2 & {
+    type: 'and';
+    left: Expression_2;
+    right: Expression_2;
+};
+
+// @public (undocumented)
+const ARR: (arr: VArr['value']) => VArr;
+
+// @public (undocumented)
+type Arr = NodeBase & {
+    type: 'arr';
+    value: Expression[];
+};
+
+// Warning: (ae-forgotten-export) The symbol "ChainProp" needs to be exported by the entry point index.d.ts
+//
+// @public (undocumented)
+type Arr_2 = NodeBase_2 & ChainProp & {
+    type: 'arr';
+    value: Expression_2[];
+};
+
+// @public (undocumented)
+function assertArray(val: Value | null | undefined): asserts val is VArr;
+
+// @public (undocumented)
+function assertBoolean(val: Value | null | undefined): asserts val is VBool;
+
+// @public (undocumented)
+function assertFunction(val: Value | null | undefined): asserts val is VFn;
+
+// @public (undocumented)
+function assertNumber(val: Value | null | undefined): asserts val is VNum;
+
+// @public (undocumented)
+function assertObject(val: Value | null | undefined): asserts val is VObj;
+
+// @public (undocumented)
+function assertString(val: Value | null | undefined): asserts val is VStr;
+
+// @public (undocumented)
+type Assign = NodeBase & {
+    type: 'assign';
+    dest: Expression;
+    expr: Expression;
+};
+
+// @public (undocumented)
+type Assign_2 = NodeBase_2 & {
+    type: 'assign';
+    dest: Expression_2;
+    expr: Expression_2;
+};
+
+declare namespace Ast {
+    export {
+        isStatement,
+        isExpression,
+        Loc,
+        Node_2 as Node,
+        Statement,
+        Expression,
+        Namespace,
+        Meta,
+        Definition,
+        Attribute,
+        Return,
+        Each,
+        For,
+        Loop,
+        Break,
+        Continue,
+        AddAssign,
+        SubAssign,
+        Assign,
+        Not,
+        And,
+        Or,
+        If,
+        Fn,
+        Match,
+        Block,
+        Exists,
+        Tmpl,
+        Str,
+        Num,
+        Bool,
+        Null,
+        Obj,
+        Arr,
+        Identifier,
+        Call,
+        Index,
+        Prop,
+        TypeSource,
+        NamedTypeSource,
+        FnTypeSource
+    }
+}
+export { Ast }
+
+// @public (undocumented)
+type Attr_2 = {
+    attr?: {
+        name: string;
+        value: Value;
+    }[];
+};
+
+// @public (undocumented)
+type Attribute = NodeBase & {
+    type: 'attr';
+    name: string;
+    value: Expression;
+};
+
+// @public (undocumented)
+type Attribute_2 = NodeBase_2 & {
+    type: 'attr';
+    name: string;
+    value: Expression_2;
+};
+
+// @public (undocumented)
+type Block = NodeBase & {
+    type: 'block';
+    statements: (Statement | Expression)[];
+};
+
+// @public (undocumented)
+type Block_2 = NodeBase_2 & ChainProp & {
+    type: 'block';
+    statements: (Statement_2 | Expression_2)[];
+};
+
+// @public (undocumented)
+const BOOL: (bool: VBool['value']) => VBool;
+
+// @public (undocumented)
+type Bool = NodeBase & {
+    type: 'bool';
+    value: boolean;
+};
+
+// @public (undocumented)
+type Bool_2 = NodeBase_2 & ChainProp & {
+    type: 'bool';
+    value: boolean;
+};
+
+// @public (undocumented)
+const BREAK: () => Value;
+
+// @public (undocumented)
+type Break = NodeBase & {
+    type: 'break';
+};
+
+// @public (undocumented)
+type Break_2 = NodeBase_2 & {
+    type: 'break';
+};
+
+// @public (undocumented)
+function CALL(target: Call_2['target'], args: Call_2['args'], loc?: {
+    start: number;
+    end: number;
+}): Call_2;
+
+// @public (undocumented)
+type Call = NodeBase & {
+    type: 'call';
+    target: Expression;
+    args: Expression[];
+};
+
+// @public (undocumented)
+type Call_2 = NodeBase_2 & {
+    type: 'call';
+    target: Expression_2;
+    args: Expression_2[];
+};
+
+// @public (undocumented)
+type CallChain = NodeBase_2 & {
+    type: 'callChain';
+    args: Expression_2[];
+};
+
+// @public (undocumented)
+type ChainMember = CallChain | IndexChain | PropChain;
+
+// @public (undocumented)
+const CONTINUE: () => Value;
+
+// @public (undocumented)
+type Continue = NodeBase & {
+    type: 'continue';
+};
+
+// @public (undocumented)
+type Continue_2 = NodeBase_2 & {
+    type: 'continue';
+};
+
+declare namespace Cst {
+    export {
+        isStatement_2 as isStatement,
+        isExpression_2 as isExpression,
+        hasChainProp,
+        CALL,
+        INDEX,
+        PROP,
+        Node_3 as Node,
+        Statement_2 as Statement,
+        Expression_2 as Expression,
+        Namespace_2 as Namespace,
+        Meta_2 as Meta,
+        Definition_2 as Definition,
+        Attribute_2 as Attribute,
+        Return_2 as Return,
+        Each_2 as Each,
+        For_2 as For,
+        Loop_2 as Loop,
+        Break_2 as Break,
+        Continue_2 as Continue,
+        AddAssign_2 as AddAssign,
+        SubAssign_2 as SubAssign,
+        Assign_2 as Assign,
+        InfixOperator,
+        Infix,
+        Not_2 as Not,
+        And_2 as And,
+        Or_2 as Or,
+        If_2 as If,
+        Fn_2 as Fn,
+        Match_2 as Match,
+        Block_2 as Block,
+        Exists_2 as Exists,
+        Tmpl_2 as Tmpl,
+        Str_2 as Str,
+        Num_2 as Num,
+        Bool_2 as Bool,
+        Null_2 as Null,
+        Obj_2 as Obj,
+        Arr_2 as Arr,
+        Identifier_2 as Identifier,
+        ChainMember,
+        CallChain,
+        IndexChain,
+        PropChain,
+        Call_2 as Call,
+        Index_2 as Index,
+        Prop_2 as Prop,
+        TypeSource_2 as TypeSource,
+        NamedTypeSource_2 as NamedTypeSource,
+        FnTypeSource_2 as FnTypeSource
+    }
+}
+export { Cst }
+
+// @public (undocumented)
+type Definition = NodeBase & {
+    type: 'def';
+    name: string;
+    varType?: TypeSource;
+    expr: Expression;
+    mut: boolean;
+    attr: Attribute[];
+};
+
+// @public (undocumented)
+type Definition_2 = NodeBase_2 & {
+    type: 'def';
+    name: string;
+    varType?: TypeSource_2;
+    expr: Expression_2;
+    mut: boolean;
+    attr?: Attribute_2[];
+};
+
+// @public (undocumented)
+type Each = NodeBase & {
+    type: 'each';
+    var: string;
+    items: Expression;
+    for: Statement | Expression;
+};
+
+// @public (undocumented)
+type Each_2 = NodeBase_2 & {
+    type: 'each';
+    var: string;
+    items: Expression_2;
+    for: Statement_2 | Expression_2;
+};
+
+// @public (undocumented)
+function eq(a: Value, b: Value): boolean;
+
+// @public (undocumented)
+const ERROR: (name: string, info?: Value) => Value;
+
+declare namespace errors {
+    export {
+        AiScriptError,
+        SyntaxError_2 as SyntaxError,
+        TypeError_2 as TypeError,
+        RuntimeError,
+        IndexOutOfRangeError
+    }
+}
+export { errors }
+
+// @public (undocumented)
+type Exists = NodeBase & {
+    type: 'exists';
+    identifier: Identifier;
+};
+
+// @public (undocumented)
+type Exists_2 = NodeBase_2 & ChainProp & {
+    type: 'exists';
+    identifier: Identifier_2;
+};
+
+// @public (undocumented)
+function expectAny(val: Value | null | undefined): asserts val is Value;
+
+// @public (undocumented)
+type Expression = If | Fn | Match | Block | Exists | Tmpl | Str | Num | Bool | Null | Obj | Arr | Not | And | Or | Identifier | Call | Index | Prop;
+
+// @public (undocumented)
+type Expression_2 = Infix | Not_2 | And_2 | Or_2 | If_2 | Fn_2 | Match_2 | Block_2 | Exists_2 | Tmpl_2 | Str_2 | Num_2 | Bool_2 | Null_2 | Obj_2 | Arr_2 | Identifier_2 | Call_2 | // IR
+Index_2 | // IR
+Prop_2;
+
+// @public (undocumented)
+const FALSE: {
+    type: "bool";
+    value: boolean;
+};
+
+// @public (undocumented)
+const FN: (args: VFn['args'], statements: VFn['statements'], scope: VFn['scope']) => VFn;
+
+// @public (undocumented)
+type Fn = NodeBase & {
+    type: 'fn';
+    args: {
+        name: string;
+        argType?: TypeSource;
+    }[];
+    retType?: TypeSource;
+    children: (Statement | Expression)[];
+};
+
+// @public (undocumented)
+type Fn_2 = NodeBase_2 & ChainProp & {
+    type: 'fn';
+    args: {
+        name: string;
+        argType?: TypeSource_2;
+    }[];
+    retType?: TypeSource_2;
+    children: (Statement_2 | Expression_2)[];
+};
+
+// @public (undocumented)
+const FN_NATIVE: (fn: VFn['native']) => VFn;
+
+// @public (undocumented)
+type FnTypeSource = NodeBase & {
+    type: 'fnTypeSource';
+    args: TypeSource[];
+    result: TypeSource;
+};
+
+// @public (undocumented)
+type FnTypeSource_2 = NodeBase_2 & {
+    type: 'fnTypeSource';
+    args: TypeSource_2[];
+    result: TypeSource_2;
+};
+
+// @public (undocumented)
+type For = NodeBase & {
+    type: 'for';
+    var?: string;
+    from?: Expression;
+    to?: Expression;
+    times?: Expression;
+    for: Statement | Expression;
+};
+
+// @public (undocumented)
+type For_2 = NodeBase_2 & {
+    type: 'for';
+    var?: string;
+    from?: Expression_2;
+    to?: Expression_2;
+    times?: Expression_2;
+    for: Statement_2 | Expression_2;
+};
+
+// @public (undocumented)
+function getLangVersion(input: string): string | null;
+
+// @public (undocumented)
+function hasChainProp<T extends Node_3>(x: T): x is T & ChainProp;
+
+// @public (undocumented)
+type Identifier = NodeBase & {
+    type: 'identifier';
+    name: string;
+};
+
+// @public (undocumented)
+type Identifier_2 = NodeBase_2 & ChainProp & {
+    type: 'identifier';
+    name: string;
+};
+
+// @public (undocumented)
+type If = NodeBase & {
+    type: 'if';
+    cond: Expression;
+    then: Statement | Expression;
+    elseif: {
+        cond: Expression;
+        then: Statement | Expression;
+    }[];
+    else?: Statement | Expression;
+};
+
+// @public (undocumented)
+type If_2 = NodeBase_2 & {
+    type: 'if';
+    cond: Expression_2;
+    then: Statement_2 | Expression_2;
+    elseif: {
+        cond: Expression_2;
+        then: Statement_2 | Expression_2;
+    }[];
+    else?: Statement_2 | Expression_2;
+};
+
+// @public (undocumented)
+function INDEX(target: Index_2['target'], index: Index_2['index'], loc?: {
+    start: number;
+    end: number;
+}): Index_2;
+
+// @public (undocumented)
+type Index = NodeBase & {
+    type: 'index';
+    target: Expression;
+    index: Expression;
+};
+
+// @public (undocumented)
+type Index_2 = NodeBase_2 & {
+    type: 'index';
+    target: Expression_2;
+    index: Expression_2;
+};
+
+// @public (undocumented)
+type IndexChain = NodeBase_2 & {
+    type: 'indexChain';
+    index: Expression_2;
+};
+
+// @public (undocumented)
+class IndexOutOfRangeError extends RuntimeError {
+    constructor(message: string, info?: any);
+}
+
+// @public (undocumented)
+type Infix = NodeBase_2 & {
+    type: 'infix';
+    operands: Expression_2[];
+    operators: InfixOperator[];
+};
+
+// @public (undocumented)
+type InfixOperator = '||' | '&&' | '==' | '!=' | '<=' | '>=' | '<' | '>' | '+' | '-' | '*' | '^' | '/' | '%';
+
+// @public (undocumented)
+export class Interpreter {
+    constructor(vars: Record<string, Value>, opts?: {
+        in?(q: string): Promise<string>;
+        out?(value: Value): void;
+        log?(type: string, params: Record<string, any>): void;
+        maxStep?: number;
+    });
+    // (undocumented)
+    abort(): void;
+    // (undocumented)
+    static collectMetadata(script?: Ast.Node[]): Map<any, any> | undefined;
+    // (undocumented)
+    exec(script?: Ast.Node[]): Promise<void>;
+    // (undocumented)
+    execFn(fn: VFn, args: Value[]): Promise<Value>;
+    // (undocumented)
+    registerAbortHandler(handler: () => void): void;
+    // (undocumented)
+    scope: Scope;
+    // (undocumented)
+    stepCount: number;
+    // (undocumented)
+    unregisterAbortHandler(handler: () => void): void;
+}
+
+// @public (undocumented)
+function isArray(val: Value): val is VArr;
+
+// @public (undocumented)
+function isBoolean(val: Value): val is VBool;
+
+// @public (undocumented)
+function isExpression(x: Node_2): x is Expression;
+
+// @public (undocumented)
+function isExpression_2(x: Node_3): x is Expression_2;
+
+// @public (undocumented)
+function isFunction(val: Value): val is VFn;
+
+// @public (undocumented)
+function isNumber(val: Value): val is VNum;
+
+// @public (undocumented)
+function isObject(val: Value): val is VObj;
+
+// @public (undocumented)
+function isStatement(x: Node_2): x is Statement;
+
+// @public (undocumented)
+function isStatement_2(x: Node_3): x is Statement_2;
+
+// @public (undocumented)
+function isString(val: Value): val is VStr;
+
+// @public (undocumented)
+function jsToVal(val: any): Value;
+
+// @public
+type Loc = {
+    start: number;
+    end: number;
+};
+
+// @public (undocumented)
+type Loop = NodeBase & {
+    type: 'loop';
+    statements: (Statement | Expression)[];
+};
+
+// @public (undocumented)
+type Loop_2 = NodeBase_2 & {
+    type: 'loop';
+    statements: (Statement_2 | Expression_2)[];
+};
+
+// @public (undocumented)
+type Match = NodeBase & {
+    type: 'match';
+    about: Expression;
+    qs: {
+        q: Expression;
+        a: Statement | Expression;
+    }[];
+    default?: Statement | Expression;
+};
+
+// @public (undocumented)
+type Match_2 = NodeBase_2 & ChainProp & {
+    type: 'match';
+    about: Expression_2;
+    qs: {
+        q: Expression_2;
+        a: Statement_2 | Expression_2;
+    }[];
+    default?: Statement_2 | Expression_2;
+};
+
+// @public (undocumented)
+type Meta = NodeBase & {
+    type: 'meta';
+    name: string | null;
+    value: Expression;
+};
+
+// @public (undocumented)
+type Meta_2 = NodeBase_2 & {
+    type: 'meta';
+    name: string | null;
+    value: Expression_2;
+};
+
+// @public (undocumented)
+type NamedTypeSource = NodeBase & {
+    type: 'namedTypeSource';
+    name: string;
+    inner?: TypeSource;
+};
+
+// @public (undocumented)
+type NamedTypeSource_2 = NodeBase_2 & {
+    type: 'namedTypeSource';
+    name: string;
+    inner?: TypeSource_2;
+};
+
+// @public (undocumented)
+type Namespace = NodeBase & {
+    type: 'ns';
+    name: string;
+    members: (Definition | Namespace)[];
+};
+
+// @public (undocumented)
+type Namespace_2 = NodeBase_2 & {
+    type: 'ns';
+    name: string;
+    members: (Definition_2 | Namespace_2)[];
+};
+
+// @public (undocumented)
+type Node_2 = Namespace | Meta | Statement | Expression | TypeSource;
+
+// @public
+type Node_3 = Namespace_2 | Meta_2 | Statement_2 | Expression_2 | ChainMember | TypeSource_2;
+
+// @public (undocumented)
+type Not = NodeBase & {
+    type: 'not';
+    expr: Expression;
+};
+
+// @public (undocumented)
+type Not_2 = NodeBase_2 & {
+    type: 'not';
+    expr: Expression_2;
+};
+
+// @public (undocumented)
+const NULL: {
+    type: "null";
+};
+
+// @public (undocumented)
+type Null = NodeBase & {
+    type: 'null';
+};
+
+// @public (undocumented)
+type Null_2 = NodeBase_2 & ChainProp & {
+    type: 'null';
+};
+
+// @public (undocumented)
+const NUM: (num: VNum['value']) => VNum;
+
+// @public (undocumented)
+type Num = NodeBase & {
+    type: 'num';
+    value: number;
+};
+
+// @public (undocumented)
+type Num_2 = NodeBase_2 & ChainProp & {
+    type: 'num';
+    value: number;
+};
+
+// @public (undocumented)
+const OBJ: (obj: VObj['value']) => VObj;
+
+// @public (undocumented)
+type Obj = NodeBase & {
+    type: 'obj';
+    value: Map<string, Expression>;
+};
+
+// @public (undocumented)
+type Obj_2 = NodeBase_2 & ChainProp & {
+    type: 'obj';
+    value: Map<string, Expression_2>;
+};
+
+// @public (undocumented)
+type Or = NodeBase & {
+    type: 'or';
+    left: Expression;
+    right: Expression;
+};
+
+// @public (undocumented)
+type Or_2 = NodeBase_2 & {
+    type: 'or';
+    left: Expression_2;
+    right: Expression_2;
+};
+
+// @public (undocumented)
+export class Parser {
+    constructor();
+    // (undocumented)
+    addPlugin(type: PluginType, plugin: ParserPlugin): void;
+    // (undocumented)
+    static parse(input: string): Ast.Node[];
+    // (undocumented)
+    parse(input: string): Ast.Node[];
+}
+
+// @public (undocumented)
+export type ParserPlugin = (nodes: Cst.Node[]) => Cst.Node[];
+
+// @public (undocumented)
+export type PluginType = 'validate' | 'transform';
+
+// @public (undocumented)
+function PROP(target: Prop_2['target'], name: Prop_2['name'], loc?: {
+    start: number;
+    end: number;
+}): Prop_2;
+
+// @public (undocumented)
+type Prop = NodeBase & {
+    type: 'prop';
+    target: Expression;
+    name: string;
+};
+
+// @public (undocumented)
+type Prop_2 = NodeBase_2 & {
+    type: 'prop';
+    target: Expression_2;
+    name: string;
+};
+
+// @public (undocumented)
+type PropChain = NodeBase_2 & {
+    type: 'propChain';
+    name: string;
+};
+
+// @public (undocumented)
+function reprValue(value: Value, literalLike?: boolean, processedObjects?: Set<object>): string;
+
+// @public (undocumented)
+const RETURN: (v: VReturn['value']) => Value;
+
+// @public (undocumented)
+type Return = NodeBase & {
+    type: 'return';
+    expr: Expression;
+};
+
+// @public (undocumented)
+type Return_2 = NodeBase_2 & {
+    type: 'return';
+    expr: Expression_2;
+};
+
+// @public (undocumented)
+class RuntimeError extends AiScriptError {
+    constructor(message: string, info?: any);
+}
+
+// @public (undocumented)
+export class Scope {
+    constructor(layerdStates?: Scope['layerdStates'], parent?: Scope, name?: Scope['name']);
+    add(name: string, val: Value): void;
+    assign(name: string, val: Value): void;
+    // (undocumented)
+    createChildScope(states?: Map<string, Value>, name?: Scope['name']): Scope;
+    exists(name: string): boolean;
+    get(name: string): Value;
+    getAll(): Map<string, Value>;
+    // (undocumented)
+    name: string;
+    // (undocumented)
+    opts: {
+        log?(type: string, params: Record<string, any>): void;
+        onUpdated?(name: string, value: Value): void;
+    };
+}
+
+// @public (undocumented)
+type Statement = Definition | Return | Each | For | Loop | Break | Continue | Assign | AddAssign | SubAssign;
+
+// @public (undocumented)
+type Statement_2 = Definition_2 | Return_2 | Attribute_2 | // AST
+Each_2 | For_2 | Loop_2 | Break_2 | Continue_2 | Assign_2 | AddAssign_2 | SubAssign_2;
+
+// @public (undocumented)
+const STR: (str: VStr['value']) => VStr;
+
+// @public (undocumented)
+type Str = NodeBase & {
+    type: 'str';
+    value: string;
+};
+
+// @public (undocumented)
+type Str_2 = NodeBase_2 & ChainProp & {
+    type: 'str';
+    value: string;
+};
+
+// @public (undocumented)
+type SubAssign = NodeBase & {
+    type: 'subAssign';
+    dest: Expression;
+    expr: Expression;
+};
+
+// @public (undocumented)
+type SubAssign_2 = NodeBase_2 & {
+    type: 'subAssign';
+    dest: Expression_2;
+    expr: Expression_2;
+};
+
+// @public (undocumented)
+class SyntaxError_2 extends AiScriptError {
+    constructor(message: string, info?: any);
+}
+
+// @public (undocumented)
+type Tmpl = NodeBase & {
+    type: 'tmpl';
+    tmpl: (string | Expression)[];
+};
+
+// @public (undocumented)
+type Tmpl_2 = NodeBase_2 & ChainProp & {
+    type: 'tmpl';
+    tmpl: (string | Expression_2)[];
+};
+
+// @public (undocumented)
+const TRUE: {
+    type: "bool";
+    value: boolean;
+};
+
+// @public (undocumented)
+class TypeError_2 extends AiScriptError {
+    constructor(message: string, info?: any);
+}
+
+// @public (undocumented)
+type TypeSource = NamedTypeSource | FnTypeSource;
+
+// @public (undocumented)
+type TypeSource_2 = NamedTypeSource_2 | FnTypeSource_2;
+
+// @public (undocumented)
+const unWrapRet: (v: Value) => Value;
+
+declare namespace utils {
+    export {
+        expectAny,
+        assertBoolean,
+        assertFunction,
+        assertString,
+        assertNumber,
+        assertObject,
+        assertArray,
+        isBoolean,
+        isFunction,
+        isString,
+        isNumber,
+        isObject,
+        isArray,
+        eq,
+        valToString,
+        valToJs,
+        jsToVal,
+        getLangVersion,
+        reprValue
+    }
+}
+export { utils }
+
+// @public (undocumented)
+function valToJs(val: Value): any;
+
+// @public (undocumented)
+function valToString(val: Value, simple?: boolean): string;
+
+// @public (undocumented)
+type Value = (VNull | VBool | VNum | VStr | VArr | VObj | VFn | VReturn | VBreak | VContinue | VError) & Attr_2;
+
+declare namespace values {
+    export {
+        VNull,
+        VBool,
+        VNum,
+        VStr,
+        VArr,
+        VObj,
+        VFn,
+        VReturn,
+        VBreak,
+        VContinue,
+        VError,
+        Attr_2 as Attr,
+        Value,
+        NULL,
+        TRUE,
+        FALSE,
+        NUM,
+        STR,
+        BOOL,
+        OBJ,
+        ARR,
+        FN,
+        FN_NATIVE,
+        RETURN,
+        BREAK,
+        CONTINUE,
+        unWrapRet,
+        ERROR
+    }
+}
+export { values }
+
+// @public (undocumented)
+type VArr = {
+    type: 'arr';
+    value: Value[];
+};
+
+// @public (undocumented)
+type VBool = {
+    type: 'bool';
+    value: boolean;
+};
+
+// @public (undocumented)
+type VBreak = {
+    type: 'break';
+    value: null;
+};
+
+// @public (undocumented)
+type VContinue = {
+    type: 'continue';
+    value: null;
+};
+
+// @public (undocumented)
+type VError = {
+    type: 'error';
+    value: string;
+    info?: Value;
+};
+
+// @public (undocumented)
+type VFn = {
+    type: 'fn';
+    args?: string[];
+    statements?: Node_2[];
+    native?: (args: (Value | undefined)[], opts: {
+        call: (fn: VFn, args: Value[]) => Promise<Value>;
+        registerAbortHandler: (handler: () => void) => void;
+        unregisterAbortHandler: (handler: () => void) => void;
+    }) => Value | Promise<Value> | void;
+    scope?: Scope;
+};
+
+// @public (undocumented)
+type VNull = {
+    type: 'null';
+};
+
+// @public (undocumented)
+type VNum = {
+    type: 'num';
+    value: number;
+};
+
+// @public (undocumented)
+type VObj = {
+    type: 'obj';
+    value: Map<string, Value>;
+};
+
+// @public (undocumented)
+type VReturn = {
+    type: 'return';
+    value: Value;
+};
+
+// @public (undocumented)
+type VStr = {
+    type: 'str';
+    value: string;
+};
+
+// (No @packageDocumentation comment for this package)
+
+```
diff --git a/package.json b/package.json
index 2846ed0..0f98405 100644
--- a/package.json
+++ b/package.json
@@ -25,7 +25,11 @@
 		"peg": "peggy --format es --cache -o src/parser/parser.js --allowed-start-rules Preprocess,Main src/parser/parser.peggy && npm run peg-copy",
 		"peg-debug": "peggy --trace --format es --cache -o src/parser/parser.js --allowed-start-rules Preprocess,Main src/parser/parser.peggy && npm run peg-copy",
 		"peg-copy": "copyfiles -f src/parser/parser.js built/parser/",
-		"build": "npm run peg && tsc --outDir built/esm && tsc --module commonjs --outDir built/cjs && tsc --outDir built/dts --declaration true --emitDeclarationOnly true --declarationMap true",
+		"ts": "npm run ts-esm && npm run ts-cjs && npm run ts-dts",
+		"ts-esm": "tsc --outDir built/esm",
+		"ts-cjs": "tsc --module commonjs --outDir built/cjs",
+		"ts-dts": "tsc --outDir built/dts --declaration true --emitDeclarationOnly true --declarationMap true",
+		"build": "npm run peg && npm run ts",
 		"build-debug": "npm run peg-debug && tsc",
 		"api": "npx api-extractor run --local --verbose",
 		"api-prod": "npx api-extractor run --verbose",
diff --git a/src/interpreter/lib/std.ts b/src/interpreter/lib/std.ts
index a7ffea5..f46e20b 100644
--- a/src/interpreter/lib/std.ts
+++ b/src/interpreter/lib/std.ts
@@ -1,7 +1,7 @@
 /* eslint-disable no-empty-pattern */
 import { v4 as uuid } from 'uuid';
 import seedrandom from 'seedrandom';
-import { NUM, STR, FN_NATIVE, FALSE, TRUE, ARR, NULL, BOOL, OBJ } from '../value.js';
+import { NUM, STR, FN_NATIVE, FALSE, TRUE, ARR, NULL, BOOL, OBJ, ERROR } from '../value.js';
 import { assertNumber, assertString, assertBoolean, valToJs, jsToVal, assertFunction, assertObject, eq, expectAny, assertArray, reprValue } from '../util.js';
 import { RuntimeError } from '../../error.js';
 import type { Value } from '../value.js';
@@ -152,7 +152,11 @@ export const std: Record<string, Value> = {
 
 	'Json:parse': FN_NATIVE(([json]) => {
 		assertString(json);
-		return jsToVal(JSON.parse(json.value));
+		try {
+			return jsToVal(JSON.parse(json.value));
+		} catch (e) {
+			return ERROR('not_json');
+		}
 	}),
 
 	'Json:parsable': FN_NATIVE(([str]) => {
diff --git a/src/interpreter/primitive-props.ts b/src/interpreter/primitive-props.ts
index fdd51b2..3784f8d 100644
--- a/src/interpreter/primitive-props.ts
+++ b/src/interpreter/primitive-props.ts
@@ -2,9 +2,9 @@ import { substring, length, indexOf, toArray } from 'stringz';
 import { RuntimeError } from '../error.js';
 import { assertArray, assertBoolean, assertFunction, assertNumber, assertString, expectAny } from './util.js';
 import { ARR, FALSE, FN_NATIVE, NULL, NUM, STR, TRUE } from './value.js';
-import type { Value, VArr, VFn, VNum, VStr } from './value.js';
+import type { Value, VArr, VFn, VNum, VStr, VError } from './value.js';
 
-type VWithPP = VNum|VStr|VArr;
+type VWithPP = VNum|VStr|VArr|VError;
 
 const PRIMITIVE_PROPS: {
 	[key in VWithPP['type']]: { [key: string]: (target: Value) => Value }
@@ -221,6 +221,12 @@ const PRIMITIVE_PROPS: {
 			return target;
 		}),
 	},
+
+	error: {
+		name: (target: VError): VStr => STR(target.value), 
+
+		info: (target: VError): Value => target.info ?? NULL,
+	},
 } as const;
 
 export function getPrimProp(target: Value, name: string): Value {
diff --git a/src/interpreter/value.ts b/src/interpreter/value.ts
index 44db6d5..420ccfb 100644
--- a/src/interpreter/value.ts
+++ b/src/interpreter/value.ts
@@ -57,6 +57,12 @@ export type VContinue = {
 	value: null;
 };
 
+export type VError = {
+	type: 'error';
+	value: string;
+	info?: Value;
+};
+
 export type Attr = {
 	attr?: {
 		name: string;
@@ -64,7 +70,7 @@ export type Attr = {
 	}[];
 };
 
-export type Value = (VNull | VBool | VNum | VStr | VArr | VObj | VFn | VReturn | VBreak | VContinue) & Attr;
+export type Value = (VNull | VBool | VNum | VStr | VArr | VObj | VFn | VReturn | VBreak | VContinue | VError) & Attr;
 
 export const NULL = {
 	type: 'null' as const,
@@ -134,3 +140,9 @@ export const CONTINUE = (): Value => ({
 });
 
 export const unWrapRet = (v: Value): Value => v.type === 'return' ? v.value : v;
+
+export const ERROR = (name: string, info?: Value): Value => ({
+	type: 'error' as const,
+	value: name,
+	info: info,
+});


Test patch:
diff --git a/test/index.ts b/test/index.ts
index 6e4c977..2da9812 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 } from '../src/interpreter/value';
+import { NUM, STR, NULL, ARR, OBJ, BOOL, TRUE, FALSE, ERROR } from '../src/interpreter/value';
 import { RuntimeError } from '../src/error';
 
 const exe = (program: string): Promise<any> => new Promise((ok, err) => {
@@ -2762,32 +2762,33 @@ describe('std', () => {
 
 		test.concurrent('parsable', async () => {
 			[
-				'',
 				'null',
-				'hoge',
 				'"hoge"',
-				'[',
 				'[]',
-				'{}'
+				'{}',
 			].forEach(async (str) => {
 				const res = await exe(`
-					<: Json:parsable('${str}')
+					<: [
+						Json:parsable('${str}')
+						Json:stringify(Json:parse('${str}'))
+					]
 				`);
-				assert.deepEqual(res.type, 'bool');
-				if (res.value) {
-					await exe(`
-						<: Json:parse('${str}')
-					`);
-				} else {
-					try {
-						await exe(`
-							<: Json:parse('${str}')
-						`);
-					} catch (e) {
-						if (e instanceof SyntaxError) return;
-					}
-					assert.fail()
-				}
+				eq(res, ARR([TRUE, STR(str)]));
+			});
+		});
+		test.concurrent('unparsable', async () => {
+			[
+				'',
+				'hoge',
+				'[',
+			].forEach(async (str) => {
+				const res = await exe(`
+					<: [
+						Json:parsable('${str}')
+						Json:parse('${str}')
+					]
+				`);
+				eq(res, ARR([FALSE, ERROR('not_json')]));
 			});
 		});
 	});