JavaScript のパーサコンビネータに TypeScript で型を付けた

こんにちは, 口の中パッサパサです.


さてパッサパサといえばパーサコンビネータの話をしましょう.

以前作った JavaScript 用パーサコンビネータライブラリ の TypeScript 向けインターフェースをつくりました.

github.com

こんな感じで使えます. どーしてくれんだマリコちゃん.

import { string, StringParser } from "typed-loquat";

const p = string();
type P<T> = StringParser<T>;

const parser: P<string> = p.string("口の中").and(
    p.anyChar.manyTill(p.string("だよ").try()).map(cs => cs.join("")).bind(term =>
        p.string(term).and(p.eof).return(term)
    )
);

const result = parser.parse("", "口の中パッサパサだよパッサパサ");
if (result.success) {
    console.log(result.value); // → パッサパサ
}

まあこれは冗談として, サンプルいくつか用意してるのでこちらを見てください.

まだ型付けてみたって感じの alpha 版なので, なんか型付けミスってるとか使いにくいとかあればフィードバックください.

特徴

なんで @types/loquat とかでないのか

元の JS のライブラリの方を見てもらえるとわかると思うのですが, インターフェースが型を付けるのに恐ろしく適していないです. 大体全部 bind operator とか pipeline operator みたいなのが無いために prototype 拡張で凌いでいるのが悪い. これは当初から認識していて, まあいざ型提供したくなったら適当に固めたパッケージ作って提供してやればよかろうと思っていて, 今回のがそれです.

TypeScript について

だいたい Flow は触るたびにげんなりして帰ってくる*1って感じだけど, TypeScript はあんまりそういうことはなくて良いです.

*1:existential quantification すると壊れるとか (修正済み), interface の型引数に variance つけると壊れるとか (たぶんまだ修正されていない), existential types とか module types とかの命名に色々なものへのリスペクトを感じられないところとか

キーワードの組をハイライトする Atom 拡張を作りました

こんにちは, 自分のことをピカチュウだと思いこんでいる一般人です.


作りました. 標準の bracket-matcher のキーワード版ですね.

atom.io

こんな感じにカーソル位置のキーワード (struct) と対応するキーワード (end) がハイライトされるです. ハイライト以外にも対応するキーワードへのジャンプとかもできます.

f:id:susisu:20180923160123p:plain

特定の言語用には作っていないので, 各言語ごとに config.cson を編集してキーワードを設定する必要があります.

例えばシェルスクリプト用:

".shell.source":
  "keyword-pair-matcher":
    keywordPairs: [
      "if..fi"
      "case..esac"
      "for..done"
      "while..done"
      "until..done"
      "select..done"
    ]

OCaml 用はこんな感じ:

".ocaml.source":
  "keyword-pair-matcher":
    keywordPairs: [
      "begin..end"
      "for..done"
      "while..done"
      "struct..end"
      "sig..end"
      "object..end"
    ]

Ruby とかにも使えるかもしれませんが, 後置 if に対応していないので if..end とか追加すると破滅すると思います. 使う場合はよしなにやってください.