showtype演算子
showtype演算子とは、コンパイル時にオペランドの型名をに文字列に変換する演算子です。Haxeにも**$type**という似たような関数があるので、そちらを真似して作ってみました。ただし、$type関数は型名をエラー出力するのに対し、showtype演算子は単に文字列化するだけです。
showtype.ts
console.log(showtype (n => n*2));
showtype.js
console.log("(n: any) => number");
演算子の優先順位はtypeofやdeleteと同じとします。
パーサーとレキサーを変更する
DeleteKeyword
の下にShowtypeKeyword
を追加します。
diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts
index d3e40a2..cf30c7a 100644
--- a/src/compiler/parser.ts
+++ b/src/compiler/parser.ts
@@ -1467,6 +1467,7 @@ module ts {
case SyntaxKind.TildeToken:
case SyntaxKind.ExclamationToken:
case SyntaxKind.DeleteKeyword:
+ case SyntaxKind.ShowtypeKeyword:
case SyntaxKind.TypeOfKeyword:
case SyntaxKind.VoidKeyword:
case SyntaxKind.PlusPlusToken:
@@ -1876,6 +1877,7 @@ module ts {
case SyntaxKind.TildeToken:
case SyntaxKind.ExclamationToken:
case SyntaxKind.DeleteKeyword:
+ case SyntaxKind.ShowtypeKeyword:
case SyntaxKind.TypeOfKeyword:
case SyntaxKind.VoidKeyword:
case SyntaxKind.PlusPlusToken:
diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts
index 2ff3217..18e5aae 100644
--- a/src/compiler/scanner.ts
+++ b/src/compiler/scanner.ts
@@ -72,6 +72,7 @@ module ts {
"require": SyntaxKind.RequireKeyword,
"return": SyntaxKind.ReturnKeyword,
"set": SyntaxKind.SetKeyword,
+ "showtype": SyntaxKind.ShowtypeKeyword,
"static": SyntaxKind.StaticKeyword,
"string": SyntaxKind.StringKeyword,
"super": SyntaxKind.SuperKeyword,
diff --git a/src/compiler/types.ts b/src/compiler/types.ts
index 6b84676..dd5eccd 100644
--- a/src/compiler/types.ts
+++ b/src/compiler/types.ts
@@ -80,6 +80,7 @@ module ts {
DebuggerKeyword,
DefaultKeyword,
DeleteKeyword,
+ ShowtypeKeyword,
DoKeyword,
ElseKeyword,
EnumKeyword,
これで、あたかもshowtype演算子が存在するかのようにコンパイルされるようになります。
$ jake
$ node built/local/tc.js showtype.ts
$ cat showtype.js
showtype.js
console.log(showtype (function (n) { return n * 2; }));
showtypeの結果を文字列型にする
showtype演算子の結果の型は未定義なので、内部ではunknown型として扱われ、最終的にはany型になります。これを文字列型として扱われるように変更します。
diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts
index 004a4f3..4814361 100644
--- a/src/compiler/checker.ts
+++ b/src/compiler/checker.ts
@@ -4228,6 +4228,7 @@ module ts {
case SyntaxKind.DeleteKeyword:
return booleanType;
case SyntaxKind.TypeOfKeyword:
+ case SyntaxKind.ShowtypeKeyword:
return stringType;
case SyntaxKind.VoidKeyword:
return undefinedType;
showtype.ts
var type = showtype 123;
type = 456;
ソースを書き換えたら再びビルドしてテスト。
$ jake
$ node built/local/tc.js showtype.ts
showtype.ts(2,1): Type 'number' is not assignable to type 'string'.
想定通りエラーが出るようになりました。
ジェネレーターを変更する
いよいよJSを生成する部分を変更します。ジェネレーターからは型チェックのAPIが見えないので、ノードに直接文字列を持たせることにしました。
diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts
index 4814361..8deb69d 100644
--- a/src/compiler/checker.ts
+++ b/src/compiler/checker.ts
@@ -4219,6 +4219,10 @@ module ts {
function checkPrefixExpression(node: UnaryExpression): Type {
var operandType = checkExpression(node.operand);
+ if (node.operator === SyntaxKind.ShowtypeKeyword) {
+ (<any>node).typeName = typeToString(operandType);
+ }
+
switch (node.operator) {
case SyntaxKind.PlusToken:
case SyntaxKind.MinusToken:
diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts
index d1e2367..91eb2e3 100644
--- a/src/compiler/emitter.ts
+++ b/src/compiler/emitter.ts
@@ -781,6 +781,11 @@ module ts {
}
function emitUnaryExpression(node: UnaryExpression) {
+ if (node.operator === SyntaxKind.ShowtypeKeyword) {
+ write(JSON.stringify((<any>node).typeName));
+ return;
+ }
+
if (node.kind === SyntaxKind.PrefixOperator) {
write(tokenToString(node.operator));
}
ビルドしてテスト。
ちゃんと動いているようです。
$ jake
$ node built/local/tc.js showtype.ts
showtype.ts
console.log(showtype (n => n * 2));
console.log(showtype { key: ["value"], id: 1 });
console.log(showtype null);
console.log(showtype <any>null);
showtype.js
console.log("(n: any) => number");
console.log("{ key: string[]; id: number; }");
console.log("null");
console.log("any");
まとめ
新しいコンパイラはシンプルになっていいですね!安定版が待ち遠しいです。
フォークしたリポジトリ