というのを昔作ってたんだけど、最近また作り始めた。
npmにはまだ登録してない。npm install -g mizchi/tcs で入る。typescriptのtscと紛らわしいので、たぶんそのうち名前変える。
今動いてるコード。
# this is comment
# expr
1
a.b
(a()).b
1 > 2
{}
{a: 1, b: 2}
{
c: 1
d: 2
}
# assignment with type annotation
var x1 = 3
var x2: number = 3
# Can declare let and const but flowtype can't parse them yet
let y = 2
# function
myFunc(a: number, b: number): number
# return last expression
a + b
() => 1
setTimeout(() =>
myFunc(1, 2)
, 1000)
# class
class X<T>
n: number
_x: T
static staticFunc() {}
foo<U>()
a
get prop() {this._x}
set prop(_x:number)
@._x = x
class Y extends X<number>
constructor()
super()
var y = new Y()
# interface
interface Point
x: number
y: number
interface Point3d extends Point
z: number
# if
if true
a
else if false
b
else if false
c
else
d
# switch
switch e
when 1
a
when 2
a
else
a
# for
for var i in items
print(i)
# for of is same with es6, not coffee
for i of items
print(i)
# module
import x from './x'
export default {}
ES2015時代のcoffeescript、というコンセプトで設計した。
使い方
$ tcs -s src -o _tcs -t flow
$ flow init
$ flow
$ tcs -s src -o lib -t es5
flowのコード、もしくはes5へコンパイルできる。
TypedCoffeeScript v1の反省
昔作った版でやっていたこと
- 既存のCoffeeScriptコンパイラへの大規模な介入
- 型システムの自作
要約: 頑張りすぎた。勉強にはなったが、設計ミスに気づき作業量を見積もった段階で、個人で手を付けられるものではなくなり、放置してしまった。
その反省を活かして、今回は次のようになっている
- flowtypeのコードを生成する(型システムを実装しない)
- パーサのみの実装(直接flowtypeのASTを構築し、複雑な後処理をしない)
設計
- pegjs/pegcoffee
- recast
- babel
recastはreact-toolsの中で使われているパーサで、flowtypeの型アノテーション付きコードを生成できる唯一の実装。ParserAPI + 型アノテーションの独自ASTで、これをターゲットにしてpegjsでパースしながらASTを直接組み立てる。
ここは仕様化されてないので、今後パーサを書き直すことも想定している。
で、この言語使えるの?
es5がターゲットのcoffeescript風言語として扱うだけならとくに問題ない。とはいえエラーメッセージが不親切だったり、分割代入や、自分があんまり使わないwhileの実装が実は抜けてたりする。これは単純に完成度の問題なので、時間をかければどうとでもなる。
というのと別に、flowtypeの型チェック機能、ファイル単体なら使えるんだけど、複数ファイルに分割した時のimport/export の挙動がかなり怪しい。これはfacebook/flowに実装依存になるので、なんとも言いがたい。とりあえずコード生成まではできる。
この言語が使えない、というよりは、flowtypeの挙動がよくわからんってのがある。nuclidの公開のタイミングでアップデートしてくると思うので、そのタイミングでまた考える。
CoffeeScriptからの変更点
- そもそもスーパーセットを目指さない(頑張り過ぎない)
- CoffeeScript主要な機能はES2015に取り込まれたので、できるだけES2015に近づける
- 議論が多い変数の自動宣言は削除。letやconstを使いたいのもある。
reiny への適用
reinyっていうテンプレートエンジンを作っていたのだけど、テンプレートエンジン上で、テンプレートエンジン内のロジックとして if 2 > 1
みたいなコードを書けるようにしようとしたとき、ここで 2 > 1 をパース出来るexpressionノードのパーサが必要になる。これを実装するとなるとほぼプログラミング言語に近くなる。
だたら先に前々から作りたかったtyped coffee script v2 実装して、その後バックポートすりゃいいじゃん、と作り始めた。実はそんなに時間はかけてなくて、およそ3日分ぐらいの作業量。
今後
隙をみてちゃんと作っていく。頑張り過ぎず長期的に開発するのが目標。実装は単なるpegjs(pegcoffee) のパーサジェネレータがあるだけなので、興味ある人は読んでみるといいと思います。
ちょっとコード汚いけど… https://github.com/mizchi/tcs/tree/master/grammars
flowtypeのコード生成についてはflowの成り行きを見届ける感じで。