Cyan
Cyan, Yet Another New language - takuto_hの日記
http://www.geocities.jp/takt0_h/cyan/index.html
ほうほう。
実行の流れとしては、Parser#ParseでコードをパースしてCyanオブジェクト作成→Evaluatorオブジェクトを引数にCyBase#Compileを呼ぶとEvaluatorに中間言語のコンパイル結果が格納される→Evaluator#Runで実行。という処理をLoaderクラス内でやってる。
エンジン部分はこのへん。命令文字列-引数のペアが格納されたリストから命令を拾ってきてリフレクションで同名メソッドを呼んでるわけか、なるほど。
//Evaluator#Run()より抜粋 while (instructions.Count > 0) { insn = instructions[0]; instructions.RemoveAt(0); GetType().GetMethod(insn.Key).Invoke(this, insn.Value); } return dataStack.Pop();
で、実際どんな命令が実行されるのか見てみる。
Evaluator#Run、PrintStateメソッド呼び出しのコメントをはずす。#if falseされてるメソッド本体も有効化しておく(最初気づかずに自分で書いてしまった)
変数の参照
cyan> Object SetInfo (stdin):2, Get Object, => #<Object>
まあ普通。SetInfoはソース内での位置を記録するための命令かな。
リスト
cyan> [12,3] SetInfo (stdin):2 Push 1 Push 2 Push 3 Push [] Cons Cons Cons => [1, 2, 3]
おー。リスプだ。[]はnilの文字列表現
変数の代入
cyan> a=10 SetInfo (stdin):2 Push a Send (=),&(10) Push #<cont 00f90be8> Push a Push 10 Push [] Cons MakeArguments Send (=),[] Push [] Cons MakeArguments Call [] => 10
代入は内部的にはメソッドの呼び出し。
MakeArgumentsでスタックトップを引数にするための処理してからSendで呼ぶ。
メッセージ送るとき、継続も一緒に渡してるようだ。
quasiquote
cyan> `hoge SetInfo (stdin):2 Push hoge => hoge
cyan> `?x SetInfo (stdin):2 Get x => 10
cyan> `[1,2,x] SetInfo (stdin):2 Push 1 Push 2 Push x Push [] Cons Cons Cons => [1, 2, x] cyan> `[1,2,?x] SetInfo (stdin):2 Push 1 Push 2 Get x Push [] Cons Cons Cons => [1, 2, 10]
コンパイルの段階で展開されてる。
CyBase#Compile/CyBase#QuoteCompile,CyQuasiQuote,CyUnquoteあたり。
実行環境、継続
Evaluatorの状態
private List<KeyValuePair<string, object[]>> instructions; private Stack<CyBase> dataStack; private Env environment; private SourceInfo sInfo;
CyContinuationでもこれらを保持してるみたいですよと。
詳しい説明があった→http://www.geocities.jp/takt0_h/cyan/doc/ref/about-continuation.html
call/ccしてみる
cyan> cont=callcc(^(cont){cont}) SetInfo (stdin):2 Push cont Send (=) &(callcc(^(cont){ cont })) Push #<cont 029bf0b7> Push cont SetInfo (stdin):2 Get callcc Call &(^(cont){ cont }) Push #<cont 01695035> Push ^(func){ func(return) } Push $(cont) Push { cont } SetEnv MakeFunction Push [] Cons MakeArguments Call [] Push func Send (:=) &('^(cont){ cont }) Push #<cont 0383196a> Push func Push ^(cont){ cont } Push [] Cons MakeArguments Send (:=) [] Push [] Cons MakeArguments Call [] Pop Push &(^(cont){ cont }) Pop Push #<cont 01695035> SetInfo ./init/primitive.cy:10 Get func Call &(return) Push #<cont 01695035> Push ^(cont){ cont } Get return Push [] Cons MakeArguments Call [] Push cont Send (:=) &('#<cont 01695035>) Push #<cont 020b77b0> Push cont Push #<cont 01695035> Push [] Cons MakeArguments Send (:=) [] Push [] Cons MakeArguments Call [] Pop Push &(#<cont 01695035>) Pop Push #<cont 01695035> SetInfo (stdin):1 Get cont Push [] Cons MakeArguments Call [] Push [] Cons MakeArguments Send (=) [] Push [] Cons MakeArguments Call [] => #<cont 01695035>
うおう!
呼んでみると、
cyan> cont("hage") SetInfo (stdin):2 SetInfo (stdin):2 Get cont Call &("hage") Push #<cont 02f88675> Push #<cont 02a8480e> Push "hage" Push [] Cons MakeArguments Call [] Push [] Cons MakeArguments Send (=) [] Push [] Cons MakeArguments Call [] => "hage" cyan> cont SetInfo (stdin):2 Get cont => "hage"
なるほど