ECMAScript のスラッシュ判断

そのスラッシュは、 コメントか? 除算記号か? 正規表現リテラルか? それが問題だ。 ということで、 テキスト・エディタのシンタックス・ハイライト規則を覗いてみました。

GNU Emacs 24.3 の場合

⇒ /usr/share/emacs/24.3/lisp/progmodes/js.el.gz

= ( [ { , : ; のいずれかに続く /pattern/ 
(defun js-syntax-propertize (start end)
  (goto-char start)
  (js-syntax-propertize-regexp end)
  (funcall
   (syntax-propertize-rules
    ("\\(?:^\\|[=([{,:;]\\)\\(?:[ \t]\\)*\\(/\\)[^/*]"
     ; 省略
     ))
   (point) end))

Vim 7.4 の場合

⇒ /usr/share/vim/vim74/syntax/javascript.vim

/pattern/ の後ろが行末か、 ; . , ) ] } のいずれかが続く
syn region  javaScriptRegexpString
  start=+/[^/*]+me=e-1
  skip=+\\\\\|\\/+
  end=+/[gim]\{0,2\}\s*$+
  end=+/[gim]\{0,2\}\s*[;.,)\]}]+me=e-1
  contains=@htmlPreproc
  oneline

普段使っていて、シンタックス・ハイライトをする様子から予想していたとおり、 正規表現リテラルかどうかの判定方法は単純でした。

テキスト・エディタではないのですが、 私が見つけた中では、 字句解析の戻り読みで一番頑張っているのは、 Javascript の衛生的マクロ処理系 sweet.js です。 これは、丸括弧の直後が文か式か、 波括弧の直後が文か式かを調べ上げて、 文なら正規表現、 式なら除算記号であると厳密に判定しています。

https://github.com/sweet-js/sweet.js/wiki/design

もう一つ。 Chiffon のトークナイザは sweet.js から波括弧の判定を省いて、 丸括弧の判定を同じ方針でやっています。 return と throw の直後が式か文かの判定は自動セミコロン挿入規則 (ASI) を考慮しておらず、 やや甘くなっています。

https://github.com/polygonplanet/Chiffon

ただし、 波括弧の (空白とコメントをスキップした) 直後にスラッシュが現れる場合は構文上ではありえますが、 今の ECMAScript で意味があるのか疑問です。 ブロックの終わりの直後では、 正規表現リテラルで始まる式を書くということです。 そのような使い方をするときは正規表現オブジェクトへの副作用を見込んでおり、 オブジェクトに束縛した変数で始めるのがほとんどではないかと思われるからです。 式の終わりの直後では、 オブジェクト・リテラルか関数式を除算することになるので、 これも意味があるのか疑問です。 仮に、 演算子オーバーライドが実装されたとしても、 意味がある演算が思い浮かびません。 あるとすれば、 関係除算ぐらいでしょうけど、 オブジェクト・リテラルにしても関数式にしても被関係除算になることはないはずです。

そう考えると、sweet.js は頑張りすぎで、Chiffon の方針が落としどころでしょう。 ただし、ASI は考慮しておいた方が良いので、 return と throw のキーワードが同じ行に含まれているかどうかの判定が欲しいところです。