Squeakをかじる その3

Squeakをかじる その2の続き。

トレイトを試すコード

sumimさんのアドバイスのお陰で、ようやく「全部コードで表現」ができました。

Trait named: #MyTrait
    uses: {}
    category: #MyCategory.

MyTrait compile: '
hoge
    ^''T#hoge''
'.

Object subclass: #MyClass
    uses: T
    instanceVariableNames: ''
    classVariableNames: ''
    poolDictionaries: ''
    category: 'MyCategory'.

MyClass new hoge  "=> 'T#hoge'".

しかしこれを試すためには、まだ「1〜3個目の文をそれぞれ選択してDo-itして、最後の文をPrint-itせよ」などという説明が必要になってしまう。

自動化へ

試す過程で人間の操作をなるべく減らしたい。Squeakでどうやったらいいだろうか。

今回、諸般の事情で他のプロセスから制御したい。そこでまずは出力をTranscriptではなく標準出力に出すようにしたい。OSProcess のsarをダウンロードし、ドラッグドロップで入れる。そうすると以下のコードで標準出力にhello worldと書ける。

OSProcess thisOSProcess stdOut
    nextPutAll: 'hello world';
    nextPut: Character lf;
    flush.

Squeakコマンドラインから起動

今回僕は Squeak-4.3-All-in-One でインストールしたので、実行バイナリがどこにあるのかよくわからない。探しまわってみたら
/Applications/Squeak-4.3-All-in-One.app/Contents/MacOS/Squeak\ VM\ Opt がそれのようだ。

次にこれを起動するとイメージファイルがないって言われる。

$ /Applications/Squeak-4.3-All-in-One.app/Contents/MacOS/Squeak\ VM\ Opt
This interpreter (vers. 6502) cannot read image file (vers. 1702195571).
Press CR to quit...

先ほどのOSProcessをインストールしたイメージを適当に名前を付けて保存しておく。WithOSProcessにした。これもまたどこに保存されたのかよくわからなくて探すはめになった。 /Applications/Squeak-4.3-All-in-One.app/Contents/Resources/WithOSProcess.image にあった。

Squeak起動時にコマンドライン引数でファイルへのフルパスを渡すとそれが実行される。-headlessをつけるとGUIを起動せずに実行するらしいので最初はそれをつけていたのだけども、それをやるとエラーが起きた時にエラーメッセージを見れない。というわけで当面は付けないでおく。

いちいち絶対パスで書くとかめんどくさいのでこんなPythonスクリプトをrun_squeak.pyって名前で作っておいた。

#!/usr/bin/env python
import subprocess
import sys
import os
scriptname = sys.argv[1]
subprocess.call(["/Applications/Squeak-4.3-All-in-One.app/Contents/MacOS/Squeak VM Opt",
                 "/Applications/Squeak-4.3-All-in-One.app/Contents/Resources/WithOSProcess.image",
                 os.path.abspath(scriptname)])

これでhello worldが出るようになった。しかし、出力した後終了しない。どうやって終了するのかがわからなかったので自分自身にSIGKILLを投げることにした。

squeak := OSProcess thisOSProcess.

squeak stdOut
    nextPutAll: 'hello world';
    nextPut: Character lf;
    flush.

squeak sigkill: squeak.

無事hello worldと出力して終了するようになった。

$ ./run_squeak.py helloworld.st
hello world
$

まとめ

とういうわけで、このようなコードを書くことで、トレイトの挙動を人間の操作なしで確認できるようになった。めでたしめでたし。

https://github.com/nishio/learn_language/blob/master/squeak/test_trait.st

$ ./run_squeak.py test_trait.st
T#hoge


もうちょっと手を加えたら、他の言語と一緒にこういう感じで挙動を確認することができるようになるはず: https://github.com/nishio/learn_language/blob/master/coderunner/test/zero_division.py

あ、ダメだ、現状ではSqueakで1/0するとGUIでエラーのダイアログが出てしまう。まずはこれを横取りして標準出力に流すとかしなければ…。Exception >> signal に self halt.仕込んだら無限ループになっちゃった。

追記

Signalに手を入れるより、トラップされずに一番上まで来た例外を捕まえればいいだけか。

[ 
  1 / 0
] 
  on: Exception 
  do: [:x| Transcript show: x; showln: x messageText.] 

できたできた: https://github.com/nishio/learn_language/blob/master/squeak/test_zerodivide.st