Subscribed unsubscribe Subscribe Subscribe

枕を欹てて聴く

香炉峰の雪は簾を撥げて看る

subsetじゃない悲しい話 (JSON編)

JSON編以外はありません.


このような記事が
JSON: The JavaScript subset that isn't — Timeless

つまり, LineTerminatorに\u2028 / \u2029が含まれない(JSON)ので, StringLiteralがうっかりJSONの方が許容範囲が広がってしまっているという話です.

eval('"\u2028"');  // SyntaxError
JSON.parse('"\u2028"');  // OK

自作ECMAScript Engine, lv5のJSON Lexer, "あうう, 多分そのままIsLineTerminatorとか使ってたかも... ><"と思ってみてみると案の定でしたので修正しました.
https://github.com/Constellation/iv/commit/91f4f549fc4f2425d40588e0e5a5fdc56d8dace9
で, これを見てあるsource codeを思い出してしまったので... 結論としては, JSONの仕様直して欲しいです.

JSONは微妙にECMAScriptと違う

JSONはそれとなくECMAScriptと違いまして, 例えばWhiteSpaceです.
ECMAScript

WhiteSpace ::




<#x0a>



LineTerminator ::





LineTerminatorSequence ::

 [lookahead ∉  ]


 

JSON

JSONWhiteSpace ::




LineTerminatorというくくりが消えて, WhiteSpaceと合同になっていたり.

  • 16進数は許していなかったり(これはよく知られている)
  • StringLiteralがdouble quoteだけだったり(これも)
  • objectのkeyをStringにしないといけなかったり(これも)
  • object / arrayの末尾のelliminationはない(JSONでSyntaxErrorになったら大概これ)
JSON.parse('[10, 20, ]');  // SyntaxError

後, 面白い特徴がNumericLiteralにはあります. 通常Programming言語ではNumericLiteralは数値のみにしておいて, 単項演算子として+/-を定義することでPrimaryExpressionとしてreduceするのですが, JSONには演算子がありません. しかし負数が表せないとなるとそれはそれでアレなので, -が演算子でなくNumericLiteral自体に入っていたりします. この結果例えば

JSON.parse('-.2');  // SyntaxError .から始まるfloatにはsignは許容されない
JSON.parse('.2e20');  // SyntaxError .から始まるfloatにはExponentPartは許容されない
JSON.parse('+20');  // SyntaxError +はない

と厳しくなります.

このように基本的にJSON ECMAScriptはJSONの方が厳しく, その結果subsetだと思われてきたのですが, ところが... という話です. この結果悲しいことになります...

subsetじゃないと悲しい話本題

subsetじゃないと実は悲しい話があります. それは, evalするときに仮にJSONとみなすことはできないということです.

SpiderMonkeyで以下のものを実行してみてください

eval('"\u2028"');  // SyntaxError
eval('("\u2028")');  // あれ?

気になる方は, 早速tracemonkeyのsrcを!

結論

bugを報告しました.
https://bugzilla.mozilla.org/show_bug.cgi?id=657367

というわけでこのままではevalの速度が下がって悲しみに包まれるので, Crockfordさんよろしくお願いします><

追記
JSON Parserにflagを付けるべきというcommentを見て「なるほど, もっともだなあ」と思ったので, lv5もevalでJSON shortcutしてみることにしました(with template parameter)
https://github.com/Constellation/iv/commit/b452c82f935c0a73ec64766aef5ceb7455a716d1
https://github.com/Constellation/iv/commit/f0aed4e565ac4f38aae2bea3e8a8480196e4e9fe
compile timeにわかってることなので, template炸裂ですね.

追記2
trunkにてfixされました.

http://hg.mozilla.org/tracemonkey/rev/ef4d79fc60c0

SpiderMonkeyの現行JSON Parser, 書いているのWhere's WaldenでおなじみのWaldenさんだったんですね.