標高+1m

Don't be rational.

Little Smallscript

物置を掃除してたらこんな本を見つけました。

Little Smalltalk入門 1989年6月21日 初版発行

父のものなんですが、持ち出してここ2,3日通勤中に読んでました。

Little SmalltalkってSmalltalk方言の一つで、Smalltalk(GUI環境付きのやつ)の雰囲気をキャラクタ端末で気軽に味わえるように、言語機能だけを抜き出したようなものらしいです。
要するにいわゆるスクリプト言語と立ち位置は同じ? ほとんどRubyです。(Rubyが後だけど)

本にのってるのはLittle Smalltalk version 1で、こんな感じに書きます。

"クラス定義"
Class Person :Animal
| myname answerStr |
[
  new: name
    myname <- name.
    answerStr <- 'hello' , myname
|
  name
    myname print.
    ^ myname
]

"メッセージ式"
(Person new: 'ympbyc') name

"レキシカルブロック"
#(1 2 3 4) inject: 0 into: [:a :b| (a , b) print. a + b]

"カスケード式"
"最初のメッセージ式の結果をレシーバとしてメッセージを送り続ける"
Person new: 'ympbyc'; name; name 

なんか書いてて楽しいし、javascript(飯の種)と比べて短くなりそうなのでLittle SmalltalkからJavascriptへのトランスレータを作ることにしました。CoffeeScriptのSmalltalk版みたいな感じね。
https://github.com/ympbyc/LittleSmallscript

金曜日の夜に初めて今月曜日の朝5時なんだけど、とりあえず式は大体変換できるようになった。
READMEにもあるけど、

  new LittleSmallscript("下のSmalltalkソース").expression();

[
  Person <- [ :name | 
    this at: 'name' put: name
  ]. 
  Person at: 'prototype'; at: 'answer' put: [this at: 'name'].
  p <- Person new: 'Yendor'. 
  p answer. 
  p
] value

(function () {
  Person =  function (name) {
    return  (this).atPut("name", name); 
  };
  (function () { 
    var _receiver = (Person).at("prototype");
    _receiver.atPut('answer', function () {
     return  (this).at("name"); 
    }); 
    return _receiver;  
  })(); 
  p =  (Person).new("Yendor");  
  (p).answer();  
  return  p; 
}).value()

になる。
javascriptだとコンストラクタ関数でオブジェクト作るから、あとは一時変数宣言できるようにすれば普通にOOPできちゃう。

で、ここまで作ってさあクラス定義のパーサ作るぞーと思ったところで、Little Smalltalkにバージョンがあることを知りました。
Little Smalltalk入門のはversion 1で、Web検索でよく出てくるのはversion 3、最新版はversion 5。
式はほとんど変わってないっぽいけど、クラスの作り方がバージョン間でかなり変わってる。
このリポジトリに全バージョンのテストコードとか例とかが入ってた。 https://github.com/crcx/littlesmalltalk
まとめた。 https://github.com/ympbyc/LittleSmallscript/blob/master/docs/versions.md

見た目的にはversion 1のが好きなんだけど完全に特殊形式で、version 4以降とかだと普通の式っぽくなってる。
varsion 4以降の、メソッド定義が1個1個バラバラにあるのがjavascriptコンストラクタ関数のprototypeにメソッド作ってくのに似てるので、これを実装しましょう。最新版だしね。

パーサはPEGっていうのを見よう見まねで実装したものを使って作ってます。PEGめっちゃ楽しい。
一部。ブロックの中の式をパースする部分。

    [:hoge| "このぶぶん"]
    BlockParser.prototype.blockStatement = function () {
      var _this = this;
      return this.cacheDo("blockStatement", function () {
        var ret ="";

        _this.skipSpace(); //スペース読み捨て
        //式がドットで繋がったのがmany(いくつか,またはゼロ個)ある
        ret += _this.many(function () {
          var a;
          a = _this.expression(); //式
          
          _this.skipSpace(); 
          _this.chr("."); //ドット
          _this.skipSpace();
          
          return a + "; ";
        });
        
        _this.optional(_this.explicitReturn); //ブロックの最後の式の前には^(explicitReturn)を付けられる(optional)
        ret += " return " + _this.expression() + ";"; //最後の式
        _this.skipSpace();

        return ret;
      });
    };


乞うご期待。