Repository: syuilo/aiscript
Pull request #215 (2022-09-05 11:11:21)

refactor type declarations for nodes
<!-- ℹ お読みください
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? -->

### ノードのグループをCSTとASTの2種類に変更。
より一般的な名前に変更。
- Ast → Cst
- N → Ast
### 型宣言の機能: 関連ノードの宣言変更とCST/ASTノードへの統合。
今までTypeSourceはノードとは別物として扱っていたが、普通のノードと同様に扱うようにする。
- fnノード: プロパティ名 args[].type → args[].argType
- fnノード: プロパティ名 ret → retType
- TypeSourceのnamedノード: ノード名 named → namedTypeSource
- TypeSourceのfnノード: ノード名 fn → fnTypeSource

# Why
<!-- なぜそうするのか？ どういう意図なのか？ 何が困っているのか？ -->
<!-- Why do you do it? What are your intentions? What is the problem? -->
ノードの型宣言の改善のため。

# Additional info (optional)
<!-- テスト観点など -->
<!-- Test perspective, etc -->


codecov[bot]: # [Codecov](https://codecov.io/gh/syuilo/aiscript/pull/215?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=syuilo) Report
Base: **86.47**% // Head: **86.53**% // Increases project coverage by **`+0.05%`** :tada:
> Coverage data is based on head [(`a8355d1`)](https://codecov.io/gh/syuilo/aiscript/pull/215?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=syuilo) compared to base [(`ae197be`)](https://codecov.io/gh/syuilo/aiscript/commit/ae197be2169f64b4c0bb465dee6c430676ad0dad?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=syuilo).
> Patch coverage: 95.80% of modified lines in pull request are covered.

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


```diff
@@            Coverage Diff             @@
##           master     #215      +/-   ##
==========================================
+ Coverage   86.47%   86.53%   +0.05%     
==========================================
  Files          19       19              
  Lines        2758     2770      +12     
  Branches      430      430              
==========================================
+ Hits         2385     2397      +12     
  Misses        366      366              
  Partials        7        7              
```


| [Impacted Files](https://codecov.io/gh/syuilo/aiscript/pull/215?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=syuilo) | Coverage Δ | |
|---|---|---|
| [src/type.ts](https://codecov.io/gh/syuilo/aiscript/pull/215/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=syuilo#diff-c3JjL3R5cGUudHM=) | `52.25% <44.44%> (-4.97%)` | :arrow_down: |
| [src/interpreter/index.ts](https://codecov.io/gh/syuilo/aiscript/pull/215/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=syuilo#diff-c3JjL2ludGVycHJldGVyL2luZGV4LnRz) | `90.25% <88.88%> (ø)` | |
| [src/index.ts](https://codecov.io/gh/syuilo/aiscript/pull/215/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=syuilo#diff-c3JjL2luZGV4LnRz) | `100.00% <100.00%> (ø)` | |
| [src/node.ts](https://codecov.io/gh/syuilo/aiscript/pull/215/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=syuilo#diff-c3JjL25vZGUudHM=) | `97.67% <100.00%> (+0.13%)` | :arrow_up: |
| [src/parser/index.ts](https://codecov.io/gh/syuilo/aiscript/pull/215/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=syuilo#diff-c3JjL3BhcnNlci9pbmRleC50cw==) | `82.95% <100.00%> (ø)` | |
| [src/parser/node.ts](https://codecov.io/gh/syuilo/aiscript/pull/215/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=syuilo#diff-c3JjL3BhcnNlci9ub2RlLnRz) | `99.00% <100.00%> (+0.04%)` | :arrow_up: |
| [src/parser/plugins/infix-to-fncall.ts](https://codecov.io/gh/syuilo/aiscript/pull/215/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=syuilo#diff-c3JjL3BhcnNlci9wbHVnaW5zL2luZml4LXRvLWZuY2FsbC50cw==) | `98.34% <100.00%> (ø)` | |
| [src/parser/plugins/set-attribute.ts](https://codecov.io/gh/syuilo/aiscript/pull/215/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=syuilo#diff-c3JjL3BhcnNlci9wbHVnaW5zL3NldC1hdHRyaWJ1dGUudHM=) | `81.25% <100.00%> (ø)` | |
| [src/parser/plugins/transform-chain.ts](https://codecov.io/gh/syuilo/aiscript/pull/215/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=syuilo#diff-c3JjL3BhcnNlci9wbHVnaW5zL3RyYW5zZm9ybS1jaGFpbi50cw==) | `94.87% <100.00%> (ø)` | |
| [src/parser/plugins/validate-keyword.ts](https://codecov.io/gh/syuilo/aiscript/pull/215/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=syuilo#diff-c3JjL3BhcnNlci9wbHVnaW5zL3ZhbGlkYXRlLWtleXdvcmQudHM=) | `97.61% <100.00%> (ø)` | |
| ... and [2 more](https://codecov.io/gh/syuilo/aiscript/pull/215/diff?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=syuilo) | |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=syuilo). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=syuilo)

</details>

[:umbrella: View full report at Codecov](https://codecov.io/gh/syuilo/aiscript/pull/215?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=syuilo).   
:loudspeaker: Do you have feedback about the report comment? [Let us know in this issue](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/etc/aiscript.api.md b/etc/aiscript.api.md
index 1956e61..5f24e4e 100644
--- a/etc/aiscript.api.md
+++ b/etc/aiscript.api.md
@@ -81,6 +81,49 @@ type Assign_2 = NodeBase_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,
+        If,
+        Fn,
+        Match,
+        Block,
+        Tmpl,
+        Str,
+        Num,
+        Bool,
+        Null,
+        Obj,
+        Arr,
+        Identifier,
+        Call,
+        Index,
+        Prop,
+        TypeSource,
+        NamedTypeSource,
+        FnTypeSource
+    }
+}
+export { Ast }
+
 // @public (undocumented)
 type Attr_2 = {
     attr?: {
@@ -194,6 +237,58 @@ 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,
+        If_2 as If,
+        Fn_2 as Fn,
+        Match_2 as Match,
+        Block_2 as Block,
+        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';
@@ -208,7 +303,7 @@ type Definition = NodeBase & {
 type Definition_2 = NodeBase_2 & {
     type: 'def';
     name: string;
-    varType?: TypeSource;
+    varType?: TypeSource_2;
     expr: Expression_2;
     mut: boolean;
     attr?: Attribute_2[];
@@ -272,9 +367,9 @@ type Fn = NodeBase & {
     type: 'fn';
     args: {
         name: string;
-        type?: TypeSource;
+        argType?: TypeSource;
     }[];
-    ret?: TypeSource;
+    retType?: TypeSource;
     children: (Statement | Expression)[];
 };
 
@@ -283,9 +378,9 @@ type Fn_2 = NodeBase_2 & ChainProp & {
     type: 'fn';
     args: {
         name: string;
-        type?: TypeSource;
+        argType?: TypeSource_2;
     }[];
-    ret?: TypeSource;
+    retType?: TypeSource_2;
     children: (Statement_2 | Expression_2)[];
 };
 
@@ -299,6 +394,20 @@ const FN_NATIVE: (fn: VFn['native']) => {
     }) => Value | Promise<Value> | void) | undefined;
 };
 
+// @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';
@@ -403,9 +512,9 @@ export class Interpreter {
     // (undocumented)
     abort(): void;
     // (undocumented)
-    static collectMetadata(script?: N.Node[]): Map<any, any> | undefined;
+    static collectMetadata(script?: Ast.Node[]): Map<any, any> | undefined;
     // (undocumented)
-    exec(script?: N.Node[]): Promise<void>;
+    exec(script?: Ast.Node[]): Promise<void>;
     // (undocumented)
     execFn(fn: VFn, args: Value[]): Promise<Value>;
     // (undocumented)
@@ -451,7 +560,7 @@ function isString(val: Value): val is VStr;
 // @public (undocumented)
 function jsToVal(val: any): Value;
 
-// @public (undocumented)
+// @public
 type Loc = {
     start: number;
     end: number;
@@ -505,45 +614,19 @@ type Meta_2 = NodeBase_2 & {
     value: Expression_2;
 };
 
-declare namespace N {
-    export {
-        isStatement,
-        isExpression,
-        Loc,
-        Node_2 as Node,
-        Statement,
-        Expression,
-        Namespace,
-        Meta,
-        Definition,
-        Attribute,
-        Return,
-        Each,
-        For,
-        Loop,
-        Break,
-        Continue,
-        AddAssign,
-        SubAssign,
-        Assign,
-        If,
-        Fn,
-        Match,
-        Block,
-        Tmpl,
-        Str,
-        Num,
-        Bool,
-        Null,
-        Obj,
-        Arr,
-        Identifier,
-        Call,
-        Index,
-        Prop
-    }
-}
-export { N }
+// @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 & {
@@ -560,10 +643,10 @@ type Namespace_2 = NodeBase_2 & {
 };
 
 // @public (undocumented)
-type Node_2 = Namespace | Meta | Statement | Expression;
+type Node_2 = Namespace | Meta | Statement | Expression | TypeSource;
 
-// @public (undocumented)
-type Node_3 = Namespace_2 | Meta_2 | Statement_2 | Expression_2 | ChainMember;
+// @public
+type Node_3 = Namespace_2 | Meta_2 | Statement_2 | Expression_2 | ChainMember | TypeSource_2;
 
 // @public (undocumented)
 const NULL: {
@@ -622,15 +705,13 @@ export class Parser {
     // (undocumented)
     addPlugin(type: PluginType, plugin: ParserPlugin): void;
     // (undocumented)
-    static parse(input: string): N.Node[];
+    static parse(input: string): Ast.Node[];
     // (undocumented)
-    parse(input: string): N.Node[];
+    parse(input: string): Ast.Node[];
 }
 
-// Warning: (ae-forgotten-export) The symbol "Ast" needs to be exported by the entry point index.d.ts
-//
 // @public (undocumented)
-export type ParserPlugin = (nodes: Ast.Node[]) => Ast.Node[];
+export type ParserPlugin = (nodes: Cst.Node[]) => Cst.Node[];
 
 // @public (undocumented)
 export type PluginType = 'validate' | 'transform';
@@ -764,6 +845,12 @@ const TRUE: {
     value: boolean;
 };
 
+// @public (undocumented)
+type TypeSource = NamedTypeSource | FnTypeSource;
+
+// @public (undocumented)
+type TypeSource_2 = NamedTypeSource_2 | FnTypeSource_2;
+
 // @public (undocumented)
 const unWrapRet: (v: Value) => Value;
 
@@ -898,10 +985,6 @@ type VStr = {
     value: string;
 };
 
-// Warnings were encountered during analysis:
-//
-// src/node.ts:81:2 - (ae-forgotten-export) The symbol "TypeSource" needs to be exported by the entry point index.d.ts
-
 // (No @packageDocumentation comment for this package)
 
 ```
diff --git a/src/index.ts b/src/index.ts
index 292cc54..fb91a37 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -7,8 +7,9 @@ import { Scope } from './interpreter/scope';
 import * as utils from './interpreter/util';
 import * as values from './interpreter/value';
 import { Parser, ParserPlugin, PluginType } from './parser';
+import * as Cst from './parser/node';
 import * as errors from './error';
-import * as N from './node';
+import * as Ast from './node';
 export { Interpreter };
 export { Scope };
 export { utils };
@@ -16,5 +17,6 @@ export { values };
 export { Parser };
 export { ParserPlugin };
 export { PluginType };
+export { Cst };
 export { errors };
-export { N };
+export { Ast };
diff --git a/src/interpreter/index.ts b/src/interpreter/index.ts
index 87eff17..31b822a 100644
--- a/src/interpreter/index.ts
+++ b/src/interpreter/index.ts
@@ -3,7 +3,7 @@
  */
 
 import autobind from 'autobind-decorator';
-import * as N from '../node';
+import * as Ast from '../node';
 import { Scope } from './scope';
 import { RuntimeError } from '../error';
 import { std } from './lib/std';
@@ -55,7 +55,7 @@ export class Interpreter {
 	}
 
 	@autobind
-	public async exec(script?: N.Node[]) {
+	public async exec(script?: Ast.Node[]) {
 		if (script == null || script.length === 0) return;
 
 		await this.collectNs(script);
@@ -71,10 +71,10 @@ export class Interpreter {
 	}
 
 	@autobind
-	public static collectMetadata(script?: N.Node[]) {
+	public static collectMetadata(script?: Ast.Node[]) {
 		if (script == null || script.length === 0) return;
 
-		function nodeToJs(node: N.Node): any {
+		function nodeToJs(node: Ast.Node): any {
 			switch (node.type) {
 				case 'arr': return node.value.map(item => nodeToJs(item));
 				case 'bool': return node.value;
@@ -116,7 +116,7 @@ export class Interpreter {
 	}
 
 	@autobind
-	private async collectNs(script: N.Node[]): Promise<void> {
+	private async collectNs(script: Ast.Node[]): Promise<void> {
 		for (const node of script) {
 			switch (node.type) {
 				case 'ns': {
@@ -132,7 +132,7 @@ export class Interpreter {
 	}
 
 	@autobind
-	private async collectNsMember(ns: N.Namespace): Promise<void> {
+	private async collectNsMember(ns: Ast.Namespace): Promise<void> {
 		const scope = this.scope.createChildScope();
 
 		for (const node of ns.members) {
@@ -149,7 +149,7 @@ export class Interpreter {
 				}
 
 				default: {
-					throw new Error('invalid ns member type: ' + (node as N.Node).type);
+					throw new Error('invalid ns member type: ' + (node as Ast.Node).type);
 				}
 			}
 		}
@@ -175,7 +175,7 @@ export class Interpreter {
 	}
 
 	@autobind
-	private async _eval(node: N.Node, scope: Scope): Promise<Value> {
+	private async _eval(node: Ast.Node, scope: Scope): Promise<Value> {
 		if (this.stop) return NULL;
 		this.log('node', { node: node });
 		this.stepCount++;
@@ -457,7 +457,7 @@ export class Interpreter {
 	}
 
 	@autobind
-	private async _run(program: N.Node[], scope: Scope): Promise<Value> {
+	private async _run(program: Ast.Node[], scope: Scope): Promise<Value> {
 		this.log('block:enter', { scope: scope.name });
 
 		let v: Value = NULL;
diff --git a/src/node.ts b/src/node.ts
index 4f12c1b..dcb3135 100644
--- a/src/node.ts
+++ b/src/node.ts
@@ -1,17 +1,15 @@
 /**
- * IRノード
+ * ASTノード
  *
- * IRノードはASTノードをインタプリタ等から操作しやすい構造に変形したものです。
+ * ASTノードはCSTノードをインタプリタ等から操作しやすい構造に変形したものです。
 */
 
-import { TypeSource } from './type';
-
 export type Loc = {
 	start: number;
 	end: number;
 };
 
-export type Node = Namespace | Meta | Statement | Expression;
+export type Node = Namespace | Meta | Statement | Expression | TypeSource;
 
 export type Statement =
 	Definition |
@@ -157,9 +155,9 @@ export type Fn = NodeBase & {
 	type: 'fn'; // 関数
 	args: {
 		name: string; // 引数名
-		type?: TypeSource; // 引数の型
+		argType?: TypeSource; // 引数の型
 	}[];
-	ret?: TypeSource; // 戻り値の型
+	retType?: TypeSource; // 戻り値の型
 	children: (Statement | Expression)[]; // 本体処理
 };
 
@@ -242,3 +240,19 @@ export type Prop = NodeBase & {
 	target: Expression; // 対象
 	name: string; // プロパティ名
 };
+
+// Type source
+
+export type TypeSource = NamedTypeSource | FnTypeSource;
+
+export type NamedTypeSource = NodeBase & {
+	type: 'namedTypeSource'; // 名前付き型
+	name: string; // 型名
+	inner?: TypeSource; // 内側の型
+};
+
+export type FnTypeSource = NodeBase & {
+	type: 'fnTypeSource'; // 関数の型
+	args: TypeSource[]; // 引数の型
+	result: TypeSource; // 戻り値の型
+};
diff --git a/src/parser/index.ts b/src/parser/index.ts
index 580da65..3472442 100644
--- a/src/parser/index.ts
+++ b/src/parser/index.ts
@@ -1,5 +1,5 @@
-import * as N from '../node';
-import * as Ast from './node';
+import * as Ast from '../node';
+import * as Cst from './node';
 import { SyntaxError } from '../error';
 import * as parser from './parser.js';
 
@@ -9,7 +9,7 @@ import { setAttribute } from './plugins/set-attribute';
 import { transformChain } from './plugins/transform-chain';
 import { infixToFnCall } from './plugins/infix-to-fncall';
 
-export type ParserPlugin = (nodes: Ast.Node[]) => Ast.Node[];
+export type ParserPlugin = (nodes: Cst.Node[]) => Cst.Node[];
 export type PluginType = 'validate' | 'transform';
 
 export class Parser {
@@ -33,7 +33,7 @@ export class Parser {
 		};
 	}
 
-	public static parse(input: string): N.Node[] {
+	public static parse(input: string): Ast.Node[] {
 		if (Parser.instance == null) {
 			Parser.instance = new Parser();
 		}
@@ -53,8 +53,8 @@ export class Parser {
 		}
 	}
 
-	public parse(input: string): N.Node[] {
-		let nodes: Ast.Node[];
+	public parse(input: string): Ast.Node[] {
+		let nodes: Cst.Node[];
 
 		// generate a node tree
 		try {
@@ -83,6 +83,6 @@ export class Parser {
 			nodes = plugin(nodes);
 		}
 
-		return nodes as N.Node[];
+		return nodes as Ast.Node[];
 	}
 }
diff --git a/src/parser/node.ts b/src/parser/node.ts
index f43220b..c6c978a 100644
--- a/src/parser/node.ts
+++ b/src/parser/node.ts
@@ -1,14 +1,12 @@
 /**
- * ASTノード
+ * CSTノード
  *
  * パーサーが生成する直接的な処理結果です。
  * パーサーが生成しやすい形式になっているため、インタプリタ等では操作しにくい構造になっていることがあります。
- * この処理結果がプラグインによって処理されるとIRノードとなります。
+ * この処理結果がプラグインによって処理されるとASTノードとなります。
 */
 
-import { TypeSource } from '../type';
-
-export type Node = Namespace | Meta | Statement | Expression | ChainMember;
+export type Node = Namespace | Meta | Statement | Expression | ChainMember | TypeSource;
 
 export type Statement =
 	Definition |
@@ -165,9 +163,9 @@ export type Fn = NodeBase & ChainProp & {
 	type: 'fn';
 	args: {
 		name: string;
-		type?: TypeSource;
+		argType?: TypeSource;
 	}[];
-	ret?: TypeSource; 
+	retType?: TypeSource;
 	children: (Statement | Expression)[];
 };
 
@@ -287,3 +285,19 @@ export type Prop = NodeBase & {
 export function PROP(target: Prop['target'], name: Prop['name'], loc?: { start: number, end: number }): Prop {
 	return { type: 'prop', target, name, loc } as Prop;
 }
+
+// Type source
+
+export type TypeSource = NamedTypeSource | FnTypeSource;
+
+export type NamedTypeSource = NodeBase & {
+	type: 'namedTypeSource';
+	name: string;
+	inner?: TypeSource;
+};
+
+export type FnTypeSource = NodeBase & {
+	type: 'fnTypeSource';
+	args: TypeSource[];
+	result: TypeSource;
+};
diff --git a/src/parser/parser.peggy b/src/parser/parser.peggy
index 3a216bd..c689f81 100644
--- a/src/parser/parser.peggy
+++ b/src/parser/parser.peggy
@@ -492,7 +492,7 @@ Arr
 
 Arg
 	= name:NAME type:(_* ":" _* @Type)?
-{ return { name, type }; }
+{ return { name, argType: type }; }
 
 Args
 	= head:Arg tails:(SEP @Arg)*
@@ -508,7 +508,7 @@ FnDef
 	}
 	return createNode('def', {
 		name: name,
-		expr: createNode('fn', { args: args || [], ret: ret }, content || []),
+		expr: createNode('fn', { args: args || [], retType: ret }, content || []),
 		mut: false,
 		attr: []
 	});
@@ -517,7 +517,7 @@ FnDef
 // function expression
 
 Fn = "@(" _* args:Args? _* ")" ret:(_* ":" _* @Type)? _* "{" _* content:Statements? _* "}"
-{ return createNode('fn', { args: args || [], ret: ret }, content || []); }
+{ return createNode('fn', { args: args || [], retType: ret }, content || []); }
 
 
 
@@ -555,7 +555,7 @@ Type
 
 FnType
 	= "@(" _* args:ArgTypes? _* ")" _* "=>" _* result:Type
-{ return createNode('fn', { args: args || [], result }); }
+{ return createNode('fnTypeSource', { args: args || [], result }); }
 
 ArgTypes
 	= head:Type tails:(SEP @Type)*
@@ -563,9 +563,9 @@ ArgTypes
 
 NamedType
 	= name:NAME __* "<" __* inner:Type __* ">"
-{ return createNode('named', { name, inner }); }
+{ return createNode('namedTypeSource', { name, inner }); }
 	/ name:NAME
-{ return createNode('named', { name, inner: null }); }
+{ return createNode('namedTypeSource', { name, inner: null }); }
 
 
 
diff --git a/src/parser/plugins/infix-to-fncall.ts b/src/parser/plugins/infix-to-fncall.ts
index 8034f0f..3a6213c 100644
--- a/src/parser/plugins/infix-to-fncall.ts
+++ b/src/parser/plugins/infix-to-fncall.ts
@@ -1,4 +1,4 @@
-import * as Ast from '../node';
+import * as Cst from '../node';
 import { visitNode } from '../visit';
 import { SyntaxError } from '../../error';
 
@@ -12,15 +12,15 @@ import { SyntaxError } from '../../error';
  */
 type InfixTree = {
 	type: 'infixTree';
-	left: InfixTree | Ast.Node;
-	right: InfixTree | Ast.Node;
+	left: InfixTree | Cst.Node;
+	right: InfixTree | Cst.Node;
 	info: {
 		func: string; // 対応する関数名
 		priority: number; // 優先度（高いほど優先して計算される値）
 	};
 };
 
-function INFIX_TREE(left: InfixTree | Ast.Node, right: InfixTree | Ast.Node, info: InfixTree["info"]): InfixTree {
+function INFIX_TREE(left: InfixTree | Cst.Node, right: InfixTree | Cst.Node, info: InfixTree["info"]): InfixTree {
 	return { type: 'infixTree', left, right, info };
 }
 
@@ -47,7 +47,7 @@ function INFIX_TREE(left: InfixTree | Ast.Node, right: InfixTree | Ast.Node, inf
  * - NOTE: 右結合性の演算子としては代入演算子などが挙げられる
  * - NOTE: 比較の演算子などは非結合性とされる
  */
-function insertTree(currTree: InfixTree | Ast.Node, nextTree: InfixTree | Ast.Node, nextOpInfo: InfixTree["info"]): InfixTree {
+function insertTree(currTree: InfixTree | Cst.Node, nextTree: InfixTree | Cst.Node, nextOpInfo: InfixTree["info"]): InfixTree {
 	if (currTree.type !== 'infixTree') {
 		return INFIX_TREE(currTree, nextTree, nextOpInfo);
 	}
@@ -63,7 +63,7 @@ function insertTree(currTree: InfixTree | Ast.Node, nextTree: InfixTree | Ast.No
 /**
  * 中置演算子式を表す木を対応する関数呼び出しの構造体に変換する
  */
-function treeToNode(tree: InfixTree | Ast.Node): Ast.Node {
+function treeToNode(tree: InfixTree | Cst.Node): Cst.Node {
 	if (tree.type !== 'infixTree') {
 		return tree;
 	}
@@ -71,7 +71,7 @@ function treeToNode(tree: InfixTree | Ast.Node): Ast.Node {
 		type: 'call',
 		target: { type: 'identifier', name: tree.info.func },
 		args: [treeToNode(tree.left), treeToNode(tree.right)],
-	} as Ast.Call;
+	} as Cst.Call;
 }
 
 const infoTable: Record<string, InfixTree["info"]> = {
@@ -93,7 +93,7 @@ const infoTable: Record<string, InfixTree["info"]> = {
 /**
  * NInfix を関数呼び出し形式に変換する
  */
-function transform(node: Ast.Infix): Ast.Node {
+function transform(node: Cst.Infix): Cst.Node {
 	const infos = node.operators.map(op => {
 		const info = infoTable[op];
 		if (info == null) {
@@ -108,7 +108,7 @@ function transform(node: Ast.Infix): Ast.Node {
 	return treeToNode(currTree);
 }
 
-export function infixToFnCall(nodes: Ast.Node[]): Ast.Node[] {
+export function infixToFnCall(nodes: Cst.Node[]): Cst.Node[] {
 	for (let i = 0; i < nodes.length; i++) {
 		nodes[i] = visitNode(nodes[i], (node) => {
 			if (node.type === 'infix') {
diff --git a/src/parser/plugins/set-attribute.ts b/src/parser/plugins/set-attribute.ts
index 4680a6d..f9b36c7 100644
--- a/src/parser/plugins/set-attribute.ts
+++ b/src/parser/plugins/set-attribute.ts
@@ -1,13 +1,13 @@
 import { SyntaxError } from '../../error';
-import * as Ast from '../node';
+import * as Cst from '../node';
 
-export function setAttribute(node: Ast.Expression[]): Ast.Expression[]
-export function setAttribute(node: Ast.Statement[]): Ast.Statement[]
-export function setAttribute(node: (Ast.Statement | Ast.Expression)[]): (Ast.Statement | Ast.Expression)[]
-export function setAttribute(node: Ast.Node[]): Ast.Node[]
-export function setAttribute(nodes: Ast.Node[]): Ast.Node[] {
-	const result: Ast.Node[] = [];
-	const stockedAttrs: Ast.Attribute[] = [];
+export function setAttribute(node: Cst.Expression[]): Cst.Expression[]
+export function setAttribute(node: Cst.Statement[]): Cst.Statement[]
+export function setAttribute(node: (Cst.Statement | Cst.Expression)[]): (Cst.Statement | Cst.Expression)[]
+export function setAttribute(node: Cst.Node[]): Cst.Node[]
+export function setAttribute(nodes: Cst.Node[]): Cst.Node[] {
+	const result: Cst.Node[] = [];
+	const stockedAttrs: Cst.Attribute[] = [];
 
 	for (const node of nodes) {
 		if (node.type === 'attr') {
diff --git a/src/parser/plugins/transform-chain.ts b/src/parser/plugins/transform-chain.ts
index 4cfb5c9..08c0a9e 100644
--- a/src/parser/plugins/transform-chain.ts
+++ b/src/parser/plugins/transform-chain.ts
@@ -1,23 +1,23 @@
-import * as Ast from '../node';
+import * as Cst from '../node';
 import { visitNode } from '../visit';
 
-function transformNode(node: Ast.Node): Ast.Node {
+function transformNode(node: Cst.Node): Cst.Node {
 	// chain
-	if (Ast.isExpression(node) && Ast.hasChainProp(node) && node.chain != null) {
+	if (Cst.isExpression(node) && Cst.hasChainProp(node) && node.chain != null) {
 		const { chain, ...hostNode } = node;
-		let parent: Ast.Expression = hostNode;
+		let parent: Cst.Expression = hostNode;
 		for (const item of chain) {
 			switch (item.type) {
 				case 'callChain': {
-					parent = Ast.CALL(parent, item.args, item.loc);
+					parent = Cst.CALL(parent, item.args, item.loc);
 					break;
 				}
 				case 'indexChain': {
-					parent = Ast.INDEX(parent, item.index, item.loc);
+					parent = Cst.INDEX(parent, item.index, item.loc);
 					break;
 				}
 				case 'propChain': {
-					parent = Ast.PROP(parent, item.name, item.loc);
+					parent = Cst.PROP(parent, item.name, item.loc);
 					break;
 				}
 				default: {
@@ -31,7 +31,7 @@ function transformNode(node: Ast.Node): Ast.Node {
 	return node;
 }
 
-export function transformChain(nodes: Ast.Node[]): Ast.Node[] {
+export function transformChain(nodes: Cst.Node[]): Cst.Node[] {
 	for (let i = 0; i < nodes.length; i++) {
 		nodes[i] = visitNode(nodes[i], transformNode);
 	}
diff --git a/src/parser/plugins/validate-keyword.ts b/src/parser/plugins/validate-keyword.ts
index 493a3f4..7bed8b3 100644
--- a/src/parser/plugins/validate-keyword.ts
+++ b/src/parser/plugins/validate-keyword.ts
@@ -1,5 +1,5 @@
 import { SyntaxError } from '../../error';
-import * as Ast from '../node';
+import * as Cst from '../node';
 import { visitNode } from '../visit';
 
 const reservedWord = [
@@ -45,7 +45,7 @@ function throwReservedWordError(name: string) {
 	throw new SyntaxError(`Reserved word "${name}" cannot be used as variable name.`);
 }
 
-function validateNode(node: Ast.Node): Ast.Node {
+function validateNode(node: Cst.Node): Cst.Node {
 	switch (node.type) {
 		case 'def':
 		case 'attr':
@@ -76,7 +76,7 @@ function validateNode(node: Ast.Node): Ast.Node {
 	return node;
 }
 
-export function validateKeyword(nodes: Ast.Node[]): Ast.Node[] {
+export function validateKeyword(nodes: Cst.Node[]): Cst.Node[] {
 	for (const inner of nodes) {
 		visitNode(inner, validateNode);
 	}
diff --git a/src/parser/plugins/validate-type.ts b/src/parser/plugins/validate-type.ts
index 99a9845..67308cd 100644
--- a/src/parser/plugins/validate-type.ts
+++ b/src/parser/plugins/validate-type.ts
@@ -1,8 +1,8 @@
-import * as Ast from '../node';
+import * as Cst from '../node';
 import { getTypeBySource } from '../../type';
 import { visitNode } from '../visit';
 
-function validateNode(node: Ast.Node): Ast.Node {
+function validateNode(node: Cst.Node): Cst.Node {
 	switch (node.type) {
 		case 'def': {
 			if (node.varType != null) {
@@ -12,12 +12,12 @@ function validateNode(node: Ast.Node): Ast.Node {
 		}
 		case 'fn': {
 			for (const arg of node.args) {
-				if (arg.type != null) {
-					getTypeBySource(arg.type);
+				if (arg.argType != null) {
+					getTypeBySource(arg.argType);
 				}
 			}
-			if (node.ret != null) {
-				getTypeBySource(node.ret);
+			if (node.retType != null) {
+				getTypeBySource(node.retType);
 			}
 			break;
 		}
@@ -26,7 +26,7 @@ function validateNode(node: Ast.Node): Ast.Node {
 	return node;
 }
 
-export function validateType(nodes: Ast.Node[]): Ast.Node[] {
+export function validateType(nodes: Cst.Node[]): Cst.Node[] {
 	for (const node of nodes) {
 		visitNode(node, validateNode);
 	}
diff --git a/src/parser/visit.ts b/src/parser/visit.ts
index de5e4c3..f3d3b45 100644
--- a/src/parser/visit.ts
+++ b/src/parser/visit.ts
@@ -1,87 +1,87 @@
-import * as Ast from './node';
+import * as Cst from './node';
 
-export function visitNode(node: Ast.Node, fn: (node: Ast.Node) => Ast.Node): Ast.Node {
+export function visitNode(node: Cst.Node, fn: (node: Cst.Node) => Cst.Node): Cst.Node {
 	const result = fn(node);
 
 	// nested nodes
 	switch (result.type) {
 		case 'def': {
-			result.expr = visitNode(result.expr, fn) as Ast.Definition['expr'];
+			result.expr = visitNode(result.expr, fn) as Cst.Definition['expr'];
 			break;
 		}
 		case 'return': {
-			result.expr = visitNode(result.expr, fn) as Ast.Return['expr'];
+			result.expr = visitNode(result.expr, fn) as Cst.Return['expr'];
 			break;
 		}
 		case 'each': {
-			result.items = visitNode(result.items, fn) as Ast.Each['items'];
-			result.for = visitNode(result.for, fn) as Ast.Each['for'];
+			result.items = visitNode(result.items, fn) as Cst.Each['items'];
+			result.for = visitNode(result.for, fn) as Cst.Each['for'];
 			break;
 		}
 		case 'for': {
 			if (result.from != null) {
-				result.from = visitNode(result.from, fn) as Ast.For['from'];
+				result.from = visitNode(result.from, fn) as Cst.For['from'];
 			}
 			if (result.to != null) {
-				result.to = visitNode(result.to, fn) as Ast.For['to'];
+				result.to = visitNode(result.to, fn) as Cst.For['to'];
 			}
 			if (result.times != null) {
-				result.times = visitNode(result.times, fn) as Ast.For['times'];
+				result.times = visitNode(result.times, fn) as Cst.For['times'];
 			}
-			result.for = visitNode(result.for, fn) as Ast.For['for'];
+			result.for = visitNode(result.for, fn) as Cst.For['for'];
 			break;
 		}
 		case 'loop': {
 			for (let i = 0; i < result.statements.length; i++) {
-				result.statements[i] = visitNode(result.statements[i], fn) as Ast.Loop['statements'][number];
+				result.statements[i] = visitNode(result.statements[i], fn) as Cst.Loop['statements'][number];
 			}
 			break;
 		}
 		case 'addAssign':
 		case 'subAssign':
 		case 'assign': {
-			result.expr = visitNode(result.expr, fn) as Ast.Assign['expr'];
-			result.dest = visitNode(result.dest, fn) as Ast.Assign['dest'];
+			result.expr = visitNode(result.expr, fn) as Cst.Assign['expr'];
+			result.dest = visitNode(result.dest, fn) as Cst.Assign['dest'];
 			break;
 		}
 		case 'infix': {
 			for (let i = 0; i < result.operands.length; i++) {
-				result.operands[i] = visitNode(result.operands[i], fn) as Ast.Infix['operands'][number];
+				result.operands[i] = visitNode(result.operands[i], fn) as Cst.Infix['operands'][number];
 			}
 			break;
 		}
 		case 'if': {
-			result.cond = visitNode(result.cond, fn) as Ast.If['cond'];
-			result.then = visitNode(result.then, fn) as Ast.If['then'];
+			result.cond = visitNode(result.cond, fn) as Cst.If['cond'];
+			result.then = visitNode(result.then, fn) as Cst.If['then'];
 			for (const prop of result.elseif) {
-				prop.cond = visitNode(prop.cond, fn) as Ast.If['elseif'][number]['cond'];
-				prop.then = visitNode(prop.then, fn) as Ast.If['elseif'][number]['then'];
+				prop.cond = visitNode(prop.cond, fn) as Cst.If['elseif'][number]['cond'];
+				prop.then = visitNode(prop.then, fn) as Cst.If['elseif'][number]['then'];
 			}
 			if (result.else != null) {
-				result.else = visitNode(result.else, fn) as Ast.If['else'];
+				result.else = visitNode(result.else, fn) as Cst.If['else'];
 			}
 			break;
 		}
 		case 'fn': {
 			for (let i = 0; i < result.children.length; i++) {
-				result.children[i] = visitNode(result.children[i], fn) as Ast.Fn['children'][number];
+				result.children[i] = visitNode(result.children[i], fn) as Cst.Fn['children'][number];
 			}
 			break;
 		}
 		case 'match': {
-			result.about = visitNode(result.about, fn) as Ast.Match['about'];
+			result.about = visitNode(result.about, fn) as Cst.Match['about'];
 			for (const prop of result.qs) {
-				prop.q = visitNode(prop.q, fn) as Ast.Match['qs'][number]['q'];
-				prop.a = visitNode(prop.a, fn) as Ast.Match['qs'][number]['a'];
+				prop.q = visitNode(prop.q, fn) as Cst.Match['qs'][number]['q'];
+				prop.a = visitNode(prop.a, fn) as Cst.Match['qs'][number]['a'];
 			}
 			if (result.default != null) {
-				result.default = visitNode(result.default, fn) as Ast.Match['default'];
+				result.default = visitNode(result.default, fn) as Cst.Match['default'];
 			}
 			break;
 		}
 		case 'block': {
 			for (let i = 0; i < result.statements.length; i++) {
-				result.statements[i] = visitNode(result.statements[i], fn) as Ast.Block['statements'][number];
+				result.statements[i] = visitNode(result.statements[i], fn) as Cst.Block['statements'][number];
 			}
 			break;
 		}
@@ -89,55 +89,55 @@ export function visitNode(node: Ast.Node, fn: (node: Ast.Node) => Ast.Node): Ast
 			for (let i = 0; i < result.tmpl.length; i++) {
 				const item = result.tmpl[i];
 				if (typeof item !== 'string') {
-					result.tmpl[i] = visitNode(item, fn) as Ast.Tmpl['tmpl'][number];
+					result.tmpl[i] = visitNode(item, fn) as Cst.Tmpl['tmpl'][number];
 				}
 			}
 			break;
 		}
 		case 'obj': {
 			for (const item of result.value) {
-				result.value.set(item[0], visitNode(item[1], fn) as Ast.Expression);
+				result.value.set(item[0], visitNode(item[1], fn) as Cst.Expression);
 			}
 			break;
 		}
 		case 'arr': {
 			for (let i = 0; i < result.value.length; i++) {
-				result.value[i] = visitNode(result.value[i], fn) as Ast.Arr['value'][number];
+				result.value[i] = visitNode(result.value[i], fn) as Cst.Arr['value'][number];
 			}
 			break;
 		}
 		case 'callChain': {
 			for (let i = 0; i < result.args.length; i++) {
-				result.args[i] = visitNode(result.args[i], fn) as Ast.Call['args'][number];
+				result.args[i] = visitNode(result.args[i], fn) as Cst.Call['args'][number];
 			}
 			break;
 		}
 		case 'indexChain': {
-			result.index = visitNode(result.index, fn) as Ast.Index['index'];
+			result.index = visitNode(result.index, fn) as Cst.Index['index'];
 			break;
 		}
 		case 'call': {
-			result.target = visitNode(result.target, fn) as Ast.Call['target'];
+			result.target = visitNode(result.target, fn) as Cst.Call['target'];
 			for (let i = 0; i < result.args.length; i++) {
-				result.args[i] = visitNode(result.args[i], fn) as Ast.Call['args'][number];
+				result.args[i] = visitNode(result.args[i], fn) as Cst.Call['args'][number];
 			}
 			break;
 		}
 		case 'index': {
-			result.target = visitNode(result.target, fn) as Ast.Index['target'];
-			result.index = visitNode(result.index, fn) as Ast.Index['index'];
+			result.target = visitNode(result.target, fn) as Cst.Index['target'];
+			result.index = visitNode(result.index, fn) as Cst.Index['index'];
 			break;
 		}
 		case 'prop': {
-			result.target = visitNode(result.target, fn) as Ast.Prop['target'];
+			result.target = visitNode(result.target, fn) as Cst.Prop['target'];
 			break;
 		}
 	}
 
-	if (Ast.hasChainProp(result)) {
+	if (Cst.hasChainProp(result)) {
 		if (result.chain != null) {
 			for (let i = 0; i < result.chain.length; i++) {
-				result.chain[i] = visitNode(result.chain[i], fn) as Ast.ChainMember;
+				result.chain[i] = visitNode(result.chain[i], fn) as Cst.ChainMember;
 			}
 		}
 	}
diff --git a/src/type.ts b/src/type.ts
index 42ce343..f001cd3 100644
--- a/src/type.ts
+++ b/src/type.ts
@@ -1,25 +1,7 @@
+import * as Ast from './node';
 import { SyntaxError } from './error';
-import { Loc } from './node';
 
-// Type source (AST)
-
-export type NamedTypeSource = {
-	type: 'named'; // 名前付き型
-	loc?: Loc; // コード位置
-	name: string; // 型名
-	inner?: TypeSource; // 内側の型
-};
-
-export type FnTypeSource = {
-	type: 'fn' // 関数の型
-	loc?: Loc; // コード位置
-	args: TypeSource[]; // 引数の型
-	result: TypeSource; // 戻り値の型
-};
-
-export type TypeSource = NamedTypeSource | FnTypeSource;
-
-// Type (IR)
+// Type (Semantic analyzed)
 
 export type TSimple<N extends string = string> = {
 	type: 'simple';
@@ -115,14 +97,14 @@ export function getTypeName(type: Type): string {
 			return `${ type.name }<${ type.inners.map(inner => getTypeName(inner)).join(', ') }>`;
 		}
 		case 'fn': {
-			return `@(${ type.args.map(arg => getTypeName(arg)).join(', ') }) => ${ getTypeName(type.result) }`;
+			return `@(${ type.args.map(arg => getTypeName(arg)).join(', ') }) { ${ getTypeName(type.result) } }`;
 		}
 	}
 }
 
-export function getTypeNameBySource(typeSource: TypeSource): string {
+export function getTypeNameBySource(typeSource: Ast.TypeSource): string {
 	switch (typeSource.type) {
-		case 'named': {
+		case 'namedTypeSource': {
 			if (typeSource.inner) {
 				const inner = getTypeNameBySource(typeSource.inner);
 				return `${ typeSource.name }<${ inner }>`;
@@ -130,16 +112,16 @@ export function getTypeNameBySource(typeSource: TypeSource): string {
 				return typeSource.name;
 			}
 		}
-		case 'fn': {
+		case 'fnTypeSource': {
 			const args = typeSource.args.map(arg => getTypeNameBySource(arg)).join(', ');
 			const result = getTypeNameBySource(typeSource.result);
-			return `@(${ args }) => ${ result }`;
+			return `@(${ args }) { ${ result } }`;
 		}
 	}
 }
 
-export function getTypeBySource(typeSource: TypeSource): Type {
-	if (typeSource.type === 'named') {
+export function getTypeBySource(typeSource: Ast.TypeSource): Type {
+	if (typeSource.type === 'namedTypeSource') {
 		switch (typeSource.name) {
 			// simple types
 			case 'null':


Test patch:
diff --git a/test/index.ts b/test/index.ts
index c9f02da..6cb4677 100644
--- a/test/index.ts
+++ b/test/index.ts
@@ -4,7 +4,7 @@
  */
 
 import * as assert from 'assert';
-import { Parser, Interpreter, utils, errors, N } from '../src';
+import { Parser, Interpreter, utils, errors, Ast } from '../src';
 import { NUM, STR, NULL, ARR, OBJ, BOOL, TRUE, FALSE } from '../src/interpreter/value';
 
 const exe = (program: string): Promise<any> => new Promise((ok, err) => {
@@ -1805,8 +1805,8 @@ describe('lang version', () => {
 
 describe('Attribute', () => {
 	it('single attribute with function (str)', async () => {
-		let node: N.Node;
-		let attr: N.Attribute;
+		let node: Ast.Node;
+		let attr: Ast.Attribute;
 		const parser = new Parser();
 		const nodes = parser.parse(`
 		#[Event "Recieved"]
@@ -1828,8 +1828,8 @@ describe('Attribute', () => {
 	});
 
 	it('multiple attributes with function (obj, str, bool)', async () => {
-		let node: N.Node;
-		let attr: N.Attribute;
+		let node: Ast.Node;
+		let attr: Ast.Attribute;
 		const parser = new Parser();
 		const nodes = parser.parse(`
 		#[Endpoint { path: "/notes/create"; }]
@@ -1877,8 +1877,8 @@ describe('Attribute', () => {
 	// TODO: attribute target does not exist
 
 	it('single attribute (no value)', async () => {
-		let node: N.Node;
-		let attr: N.Attribute;
+		let node: Ast.Node;
+		let attr: Ast.Attribute;
 		const parser = new Parser();
 		const nodes = parser.parse(`
 		#[serializable]
@@ -1900,7 +1900,7 @@ describe('Attribute', () => {
 
 describe('Location', () => {
 	it('function', async () => {
-		let node: N.Node;
+		let node: Ast.Node;
 		const parser = new Parser();
 		const nodes = parser.parse(`
 		@f(a) { a }