Hatena::ブログ(Diary)

四角革命前夜

2012年09月06日(木)

JSXでnode.jsを使ったhttpサーバを書いてみたよ

JSXでnode.jsを使ったhttpサーバを書いてみたのです。

と言ってもまあ、大したことをしているわけでもない上にまともに出来てないのですけど。

環境:Ubuntu Server 12.04 LTS 32bit / node.js 0.8.8 / JSX 0.0.1 commit 43b29a509f6be2ea9aa1b2314e0b910cbfbc0e83


node.jsx
native class global {
    static function require(filename: string): Object;
}

http.jsx
import 'js.jsx';

native class http {
  function createServer(): Server;
  function createServer(requestListener: function(: ServerRequest, : ServerResponse): void): Server;
}

native class Server {
  function listen(port: int): void;
}

native class ServerRequest {
  var method: string;
  var url: string;
  function setEncoding(encoding: string): void;
}

native class ServerResponse {
  function writeHead(statusCode: int): void;
  function writeHead(statusCode: int, reasonPhrase: Map.<string>): void;
  //function writeHead(statusCode: int, reasonPhrase: Map.<variant>): void;
  function end(): void;
  function end(data: string): void;
  function end(data: string, encoding: string): void;
}

app.jsx
import 'node.jsx';
import 'http.jsx';

final class _Main {
  static function main(args: string[]): void {
    var _http: http = global.require('http') as http;

    _http.createServer((req: ServerRequest, res: ServerResponse): void -> {
      res.writeHead(200, {
        'content-type': 'text/plain; charset=utf-8'
        });
      res.end('Hello, World!');
    }).listen(3000);
  }
}

Makefile
.PHONY: all
all:
  $(HOME)/Repos/git/JSX/bin/jsx app.jsx --release --executable node > app.js

これらをコンパイルすると……


app.js
var JSX = {};
(function () {

/**
 * copies the implementations from source interface to target
 */
function $__jsx_merge_interface(target, source) {
  for (var k in source.prototype)
    if (source.prototype.hasOwnProperty(k))
      target.prototype[k] = source.prototype[k];
}

/**
 * defers the initialization of the property
 */
function $__jsx_lazy_init(obj, prop, func) {
  function reset(obj, prop, value) {
    delete obj[prop];
    obj[prop] = value;
    return value;
  }

  Object.defineProperty(obj, prop, {
    get: function () {
      return reset(obj, prop, func());
    },
    set: function (v) {
      reset(obj, prop, v);
    },
    enumerable: true,
    configurable: true
  });
}

/**
 * sideeffect().a /= b
 */
function $__jsx_div_assign(obj, prop, divisor) {
  return obj[prop] = (obj[prop] / divisor) | 0;
}

/*
 * global functions called by JSX
 * (enamed so that they do not conflict with local variable names)
 */
var $__jsx_parseInt = parseInt;
var $__jsx_parseFloat = parseFloat;
var $__jsx_isNaN = isNaN;
var $__jsx_isFinite = isFinite;

var $__jsx_encodeURIComponent = encodeURIComponent;
var $__jsx_decodeURIComponent = decodeURIComponent;
var $__jsx_encodeURI = encodeURI;
var $__jsx_decodeURI = decodeURI;

var $__jsx_ObjectToString = Object.prototype.toString;
var $__jsx_ObjectHasOwnProperty = Object.prototype.hasOwnProperty;

/*
 * profiler object, initialized afterwards
 */
function $__jsx_profiler() {
}

/*
 * public interface to JSX code
 */
JSX.require = function (path) {
  var m = $__jsx_classMap[path];
  return m !== undefined ? m : null;
};

JSX.profilerIsRunning = function () {
  return $__jsx_profiler.getResults != null;
};

JSX.getProfileResults = function () {
  return ($__jsx_profiler.getResults || function () { return {}; })();
};

JSX.postProfileResults = function (url) {
  if ($__jsx_profiler.postResults == null)
    throw new Error("profiler has not been turned on");
  return $__jsx_profiler.postResults(url);
};

JSX.resetProfileResults = function () {
  if ($__jsx_profiler.resetResults == null)
    throw new Error("profiler has not been turned on");
  return $__jsx_profiler.resetResults();
};
/**
 * class _Main extends Object
 * @constructor
 */
function _Main() {
}

_Main.prototype = new Object;
/**
 * @constructor
 */
function _Main$() {
};

_Main$.prototype = new _Main;

/**
 * @param {Array.<undefined|!string>} args
 */
_Main.main$AS = function (args) {
  /** @type {http} */
  var _http;
  _http = (function (o) { return o instanceof http ? o : null; })(global.require('http'));
  _http.createServer((function (req, res) {
    res.writeHead(200, { 'content-type': 'text/plain; charset=utf-8' });
    res.end('Hello, World!');
  })).listen(3000);
};

var _Main$main$AS = _Main.main$AS;

/**
 * class js extends Object
 * @constructor
 */
function js() {
}

js.prototype = new Object;
/**
 * @constructor
 */
function js$() {
};

js$.prototype = new js;

js.global = (function () { return this; })();

var $__jsx_classMap = {
  "app.jsx": {
    _Main: _Main,
    _Main$: _Main$
  },
  "system:lib/js/js.jsx": {
    js: js,
    js$: js$
  }
};


})();

な感じに。あとは一番うしろに

JSX.require('app.jsx')._Main.main$AS([]);

を付ければOK……じゃなかった。

- _http = (function (o) { return o instanceof http ? o : null; })(global.require('http'));
+ _http = require('http');

という風に直に書き換えるというアレなことをすると動くみたい。

$ node app.js

requireどうやって書くんだろう。てかこんなことしてる場合じゃない!

2012年07月04日(水)

jsdo.itで直にCoffeeScriptとJSXが書けるようになってたよ

CoffeeScript

jsdo.itでCoffeeScript - jsdo.it - share JavaScript, HTML5 and CSS


JSX

jsdo.itでJSX - jsdo.it - share JavaScript, HTML5 and CSS


JavaScriptタブのところにshebangを書いてあげればいいみたい。

#!coffeescript
//#!jsx

この状態でsaveとかすると、右下のあたりに

Code compiled as COFFEESCRIPT

とか

Code compiled as JSX

とか表示されます。


告知とか、shebang書くとできるとか、見かけてないんだけどどこかにあるのかなあ?


追記:

告知来た!JSX, CoffeeScript support! - jsdo.it - share JavaScript, HTML5, CSS - developers blog

2012年06月09日(土)

JSXのexampleに曲率さくら.jsxが取り込まれたよ

というわけで曲率さくら.jsxが取り込まれました。

no title

ってまあ私はJSXに翻訳しただけで、大本のコードを書いたのは@さんなのですけど……


なんかスイマセン……


toteteroさんのコードはすごいものばかりなので必見です!

2012年06月04日(月)

JSXのちょっとしたまとめ

jsdo.itで動作させるものをJSXで書くためのメモとか。


JSXをコンパイルできる環境を整える

JSXを動かすためにnode.jsが必要で、JSXをリポジトリからクローンするのにGitが必要。(Gitはまあ必須じゃないけど)


最初にGitのインストールから。

Windowsなら最近出たばかりのGitHub for Windows使うとか、msysgit使うとか。前者の方がいろいろ楽かな。

MacならGitHub for Mac使うとか、homebrewからインストールするとか、公式のインストーラでインストールするとか。

Ubuntuなら

$ sudo apt-get install -y git-core

かなー。最近だとgit-coreじゃなくてgitで良くなったんだっけ?


続いてnode.jsのインストールを。

Windowsはここから適当なバージョンのnode.exeここから適当なバージョンのnpmを落としてきて、パスを通してあげればOKなのです。

Perlは面倒だから入れない。


MacとUbuntuはnodebrewから。nodebrewのインストールは別エントリで。

nodebrewはPerl製でMacにもUbuntuにも最初から入ってるし、node.jsだけじゃなくnpmも一緒にいれてくれるのでラクチン。


JSXのインストールとセットアップをする

Gitとnode.jsが用意できたら

$ git clone git://github.com/jsx/JSX.git

でリポジトリをクローンする。


で、Windowsの場合はPerlを入れていないので

> cd .\JSX
> npm install

で依存モジュールをインストール。


MacやUbuntuの場合は

$ make setup

でセットアップ。Ubuntuは……build-essentialとか入れておかないとMake入ってないんだったかな?


ちゃんと使えるかどうか、試しに

$ bin/jsx --version

もしくは

> node bin\jsx --version

を実行してバージョン番号が表示されれば普通に動くんじゃないでしょうか。


コードを書く

以下はコードのメモ。自分はこう書いてる、的なもの。


ほぼ必ず書くことになるであろうimport文。

import "js/web.jsx";

これでHTMLの要素が扱えるようになる。HTMLCanvasElementとかCanvasRenderingContext2Dとか。


エントリポイントとして_Mainクラスを書く。

final class _Main {

  static function main(args: string[]): void {
    (new Stage()).tick();
  }

}

Javaっぽい。このmainが最初に実行される。

mainに書いたのはJSX - a faster, safer, easier JavaScriptにあったShootingのソースを真似たやつだったかな?


final class Stage {

  var canvas: HTMLCanvasElement;
  var context: CanvasRenderingContext2D;

  function constructor() {
    this.canvas = dom.createElement('canvas') as HTMLCanvasElement;
    this.context = this.canvas.getContext('2d') as CanvasRenderingContext2D;

    this.canvas.width = dom.window.innerWidth;
    this.canvas.height = dom.window.innerHeight;

    dom.window.document.body.appendChild(this.canvas);
  }

  function tick(): void {

    //
    // なにかコンテキストをいじる処理
    //

    // ループ
    dom.window.setTimeout(function (): void {
      this.tick();
    }, 1000 / 60);
  }

}

canvasを動的に生成してサイズをウィンドウのサイズに合わせ、documentに追加し、tickを呼び出し続けるコード。

コンストラクタはconstructorで、戻り値の型を書かない。

チュートリアルによると、オーバーロードできるみたい。


var a = []: Array.<number>;
a[0] = 1;
a[1] = 2;
a[3] = 3;

とか。<number>には当然、自作のクラスなども入れられる。

(number[]とArray.<number>の違いをまだわかっていない……)


var i: number = Math.random();
var j: int = i * 2;

でコンパイルすると

/** @type {!number} */
var i;
/** @type {!number} */
var j;
i = Math.random();
j = (i * 2 | 0);

となり、intは(| 0)で整数にされる。整数しか使わないのならintで宣言すると速いかも。


var sakura = []: Array.<Sakura>;

sakura.sort(function (a: MayBeUndefined.<Sakura>, b: MayBeUndefined.<Sakura>): int {
  return a.size - b.size;
});

sortで関数を渡すときはこう書くみたい。MayBeUndefinedってなんだろ?


困ったら

$ git grep '探したい文字列'

でなんとか探す!w

テストコードとか割といろいろ引っかかるので以外と参考になる。


とかとか。面倒になったからここまで。

まだまだわかんないところたくさん!

JSXでユニットテスト

てかまあ、lib/common/test-case.jsxの上の方に書いてあるんだけど。

// test.jsx

// TestCaseを継承する必要があるのでtest-case.jsxをインポート
import 'test-case.jsx';
import 'timer.jsx';

// _Testクラスという名前が重要
// TestCaseを継承する
final class _Test extends TestCase {

  // メソッド名はtestから始める
  function testAaa(): void {
    this.expect(1, '1 == 1').toBe(1);
    this.expect(1, '1 != 2').notToBe(2);
    this.expect(1, '1 < 2').toBeLT(2);
    this.expect(1, '1 <= 1').toBeLE(1);
    this.expect(2, '2 > 1').toBeGT(1);
    this.expect(2, '2 >= 2').toBeGE(2);
  }

  function testBbb(): void {

    // 非同期なメソッドなどの確認
    this.async(function (async: AsyncContext): void {
      Timer.setTimeout(function (): void {
        this.expect(1).toBe(1);
        async.done();
      }, 300);
    }, 1000);

  } 
}

あとは以下を実行すると結果が一緒にでてきます。色が付いてると良いんだけどなあ……

$ jsx --test test.jsx
1..2
        ok 1 - 1 == 1
        ok 2 - 1 != 2
        ok 3 - 1 < 2
        ok 4 - 1 <= 1
        ok 5 - 2 > 1
        ok 6 - 2 >= 2
        1..6
ok 1 - testAaa
        ok 1
        1..1
ok 2 - testBbb

2012年06月03日(日)

JSXのちょっとした不具合(修正済み)

まさか自分が不具合に遭遇するとは思ってもみなかったので記念(?)に。


発端


その後

no title


修正速い!約1時間で修正w


ちなみに、これを書いていた(JavaScriptからJSXに書き直していた)ときに見つけたのでした。

曲率さくら.jsx forked: 曲率さくら - jsdo.it - share JavaScript, HTML5 and CSS

2012年06月01日(金)

JavaScriptのコードをJSXにトランスレート(か?)してみたよ

儚く散りゆく桜.jsx forked: 儚く散りゆく桜 - jsdo.it - share JavaScript, HTML5 and CSS

出来あがったのはこれ!(JSXのコードはHTMLタブにあります)


ちょっと苦労しましたが、なんとか助けていただいて出来ました!

2012年05月31日(木)

JSXを使ってみたよ

朝起きたらJSX!JSX!なんてTwitterのTLに流れてるものだからなんだろうと思ったら、

静的型付けでOOPなJava風のコードを「速い」JavaScriptのコードに変換してくれるコンパイラみたい(あってるのかな?)

んで、さっそく試してみたのですよー。

環境:WindowsXP SP3 / node 0.6.17 / npm 1.1.21


リポジトリを持ってくる

gitで持ってくるですよー。

$ git clone http://github.com/jsx/JSX.git
$ cd JSX/
$ npm install

npm installでモジュールを入れているけど、本当はmake setupするところなのです……

でも中でperlを使っているようなので直にnpm installを叩いてます。


コードを書いてみる

// aaa.jsx
class _Main {
  static function main(args: string[]): void {
    log "Hello, World!";
  }
}

チュートリアルにあったコードをそのまま書いてみた。

型の書き方がPascal, Scalaぽい。括弧省けるならセミコロンも省けると良かったかな……

まだちゃんと調べてないから本当は省けるのかもしれないけど。


コンパイルする

shebangも書いてあるのだけど、Windowsなのでアレなので直にnode.jsから実行します。

$ node bin/jsx aaa.jsx

これで実行すると標準出力に表示されます。


出力されたコード

var JSX = {};

(function () {



/**

 * copies the implementations from source interface to target

 */

function $__jsx_merge_interface(target, source) {

	for (var k in source.prototype)

		if (source.prototype.hasOwnProperty(k))

			target.prototype[k] = source.prototype[k];

}



/**

 * defers the initialization of the property

 */

function $__jsx_lazy_init(obj, prop, func) {

	function reset(obj, prop, value) {

		Object.defineProperty(obj, prop, {

			value: value, 

			enumerable: true,

			writable: true,

			configurable: true

		});

		return value;

	}



	Object.defineProperty(obj, prop, {

		get: function () {

			return reset(obj, prop, func());

		},

		set: function (v) {

			reset(obj, prop, v);

		},

		enumerable: true,

		configurable: true

	});

}



/*

 * global functions called by JSX as Number.* (renamed so that they do not conflict with local variable names)

 */

var $__jsx_parseInt = parseInt;

var $__jsx_parseFloat = parseFloat;

var $__jsx_isNaN = isNaN;

var $__jsx_isFinite = isFinite;



var $__jsx_ObjectToString = Object.prototype.toString;

var $__jsx_ObjectHasOwnProperty = Object.prototype.hasOwnProperty;



/*

 * public interface to JSX code

 */

JSX.require = function (path) {

	var m = $__jsx_classMap[path];

	return m !== undefined ? m : null;

}

/**
 * class _Main extends Object
 * @constructor
 */
function _Main() {
}

_Main.prototype = new Object;
/**
 * @constructor
 */
function _Main$() {
};

_Main$.prototype = new _Main;

/**
 * @param {Array.<undefined|!string>} args
 */
_Main.main$AS = function (args) {
	console.log("Hello, World!");
};

_Main$main$AS = _Main.main$AS;

var $__jsx_classMap = {
	"..\aaa.jsx": {
		_Main: _Main,
		_Main$: _Main$
	}
};


}());

こんな感じ。みたい。

Windowsだからなのかな、LFのファイルなんだけどCRが最初の方にまじってる。


Vimな人はjsx.vimでシンタックスハイライト出来るみたい。

jsx-mode.elもどこかにあるみたいだけど……


デバッグも--enable-source-mapを指定するとChromeで出来るみたい。


多人数での開発はやっぱりこういう言語の方がいいのかなー。