スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

拡張された JavaScript を通常の JavaScript に変換する

今やっているのは、先週書いたJavaScript の(主にMozillaによる)独自拡張のまとめにあるような構文を、通常の構文に書き直す、トランスレータの製作。そのため、今年の初め(もう2ヶ月たったのか!)に書いたように、JavaScriptのパーサを作ってる。

作ってると書いたけど、実はパーサはほぼ完成した。ASTをJavaScriptのコードとして書き出す部分も書いたので、あとはASTを調理する部分を書けばいい。パース→ASTを変換→書き出し、という流れになる。

じゃあ先週書いた構文は具体的にどう変換すればいいのか?

定数

Safari、Chrome、Operaなどでも使えるので変換の必要なし。

条件付きcatch節

一度全てキャッチしてから分岐すればいい。

try {
  throw 123;
} catch (ex if ex == 123) {
  alert(ex); // 123
}
try {
  throw 123;
} catch (ex) {
  if (ex == 123) {
    alert(ex); // 123
  } else {
    throw ex;
  }
}
for each...in

for...inを利用して適当に実装すればいいと思う。

for each (var x in {a:1,b:2,c:3}) {
  alert(x); // 1 → 2 → 3
}
var _obj = {a:1,b:2,c:3};
for (var _key in _obj) {
  var x = _obj[_key];
  alert(x); // 1 → 2 → 3
}
Generators and iterators

ごめんなさい考えてません。でも需要ありそうな気がする。

function gen() {
  for (var i = 0; i < 3; ++i) {
    yield i;
  }
}
function gen() {
  return {
    next:function() { ... },
    send:function(value) { ... },
    "throw":function(e) { ... },
    close:function() { ... }
  };
}
Array comprehensions

適当に。

[i+i for (i in {a:1,b:2,c:3}) if (i == "a")] // ["aa"]
(function(){var _a=[];for (var i in {a:1,b:2,c:3}) if (i == "a") _a.push(i+i);return _a;}()) // ["aa"]
Block scope with let

functionを使う。一定の条件下では、他と被らない変数名に変えるだけでいいかもしれない。

// let式
var z=5;
alert(let(x=1,y=2,z=z+2) x+y*z); // 15
// let文
let(x=1,y=2,z=z+2) {
  alert(x+y*z); // 15
}
// let宣言
let x=1,y=2,z=z+2;
alert(x+y*z); // NaN
// let式
var z=5;
alert(function(x,y,z) { return x+y*z; }(1,2,z+2)); // 15
// let文
(function(x,y,z) {
  alert(x+y*z); // 15
}(1,2,z+2));
// let宣言
// 適当ですごめんなさい
(function(){
var x=1,y=2,z=z+2;
alert(x+y*z); // NaN
}());
Destructuring assignment

普通の代入に直す。右辺がリテラルなら効率化できるかもしれない。

var [a,,c] = [1,2,3];
var _a = [1,2,3],a=_a[0],c=_a[2];
識別子の扱い

文字列リテラルにする。

var o = {do: function () { alert("Hello"); }};
o.do();
var o = {"do": function () { alert("Hello"); }};
o["do"]();
Expression closures

そのまんまreturnを加えるだけ。

var f = function(x) Math.sqrt(x);
var f = function(x) { return Math.sqrt(x); };
Generator expressions

知らん!

var gen = (i+i for (i in {a:1,b:2,c:3}) if (i == "a"));
var gen = {/* ごめんなさい考えてません */};
オブジェクトリテラル中でのget/set

変換の必要なし。

var o = {get hoge() { return "hoge"; }};
alert(o.hoge); // hoge

現在書いているトランスレータはそのうちGitHubで公開するつもり。本当は今週中に公開しようかと思ったけど無理かもしれない。

ところで、拡張されたJavaScriptを通常のJavaScriptに変換する、というのはすでにいくつかある。参考までに貼っておく:

  • Objective-J
    JavaScriptにObjective-Cみたいなオブジェクト指向の機能を加える…のかな。
  • Mascara
    ECMAScript 6 (って呼んでいいのか?)をコンパイルして普通のJavaScriptにするみたい。Pythonで記述されているとのこと。
  • Narrative JavaScript
    非同期処理を同期っぽく書けるようにするらしい。JavaScriptによるJavaScript実装であるNarcissusをベースとしている。

おまけ: パーサを書いてみてわかった、JavaScriptの三大凶悪文法(事項)

  • 単純に字句解析できない
    スラッシュが来ても除算か正規表現リテラルか区別がつかない。文脈から判断しないといけない。
  • Automatic Semicolon Insertion
    と思ったけど最初の字句解析の問題と比べたら大したことない気がしてきた。でもややこしい。
  • for文
    for文のためだけにExpressionNoInやその仲間たちが定義されてるんだぜ?

2010/03/28:誤記修正

スポンサーサイト

テーマ : プログラミング | ジャンル : コンピュータ

コメントの投稿

非公開コメント

プロフィール

minoki

Author:minoki
好きなプログラミング言語:
Haskell,Lua
GitHubアカウント
Twitter

最新記事
月別アーカイブ
カテゴリ
検索フォーム
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。