Contextオブジェクトとスコープとその継承(ver.0.6対応)

Contextオブジェクトという全てのインターフェイスになるオブジェクトがあり、メソッドコールに伴い生成されます。(サンプルスクリプトの実行には、スクリプトをコピー後、Giraffe+に"get-cb.eval"と入力し、F1を押すのが楽です。)

ローカル変数や関数はカレントContextのメンバとなります。


m: `[ //カレントContextに'm'をdef
n: 0x10 //この関数のContextに'n'をdef
n.flush //16が出力
]
m //カレントContextの'm'の呼び出し
n.flush //nなんて持ってないよ、とエラー
Context.callerは、呼ばれたContextを返します。(0.5以前はparentで得られましたが、ver.0.6以降はメソッドコールのContextは継承されません。)

m: `[
caller.n: 0x100 //このメソッドの呼び出し元に、'n'をdef
]
m
n.flush //256が出力
Context.selfはそのメソッドの呼ばれたオブジェクトを返します。(本当の持ち主はownerで得る。)

m: `[
self.identical?(caller).flush //1かtrueが出力
]
m
Context.return(x)はそのContextの戻り値をxに決定し、そのContextの呼び出し元に戻ります。Object.returnはx.return(Context)です。

m: `[
self.m2 //ver.0.6以降はContextが継承されない
'after m2' //ここには届かない
]
m2: `[
caller.return(10) //呼び出し元のreturnを実行
]
m.flush //10が出力
ver.0.6以降、メソッドコール時にContextの継承はなくなり、ダイナミックスコープではなくなりました。

s: 'abc'
m: `[
s //ver.0.6: sにアクセス不能でエラー
]
m.flush //ver.0.5: abcが出力
ver.0.6以降、メソッドコール時にContextの親は常にContextオブジェクトそのもの(global)です。

m: `[
m1: `[
parent.=== global
]
m1
]
m.flush //ver.0.5: 0; ver.0.6: 1
名前ではなく、直接メソッドオブジェクトを実行した場合(Method.invoke, Container.each等)は継承されます。

s: 'abc'
m: `[
s
]
m$.invoke.flush //ver.0.6以降もabcが出力
Context.argでそのメソッドの引数にアクセスできます。

m: `*[ //'*'は「なんでもあり」
arg.size //argは引数のbeginとendで構成されるrange
]
m(1 2).out //2
\/.out
m(1 2 3).flush //2/3が出力
Context.calleeで、実行中のそのメソッドオブジェクトそのものを得られます。C/C++のstaticローカル変数のようなものを扱うことが可能です。(ファンクタのメンバ変数のほうが感覚は近い)

m:: `[ //const外しのためのdef_copy。リテラルそのままだとconstのためdefができない。
callee.v.++
]
m$.v:: 0.copy //const外しのためのdef_copy。defはそのまま参照を持つので++するのに必要。
m //++
m //++ 2回目
m //++ 3回目
m$.v.flush //3が出力 //m$はget(:m)の略
Context.message_idで、実行中のそのメソッドコールの名前を得られます。メソッド実行(invocation)の場合は$undefined$になります。

m: `[
message_id
]
m.out
\/.out
m$.invoke.flush //m/$undefined$が出力
メソッド実行時、selfとownerは利便性から親と同じになっています。calleeは自分、callerは呼び出し元(parent)、message_idは$undefined$です。

m: `[
`[
self.=== (parent.self)
].invoke
]
m.flush //1