このブログは、旧・はてなダイアリー「檜山正幸のキマイラ飼育記 メモ編」(http://d.hatena.ne.jp/m-hiyama-memo/)のデータを移行・保存したものであり、今後(2019年1月以降)更新の予定はありません。

今後の更新は、新しいブログ http://m-hiyama-memo.hatenablog.com/ で行います。

Catyのコマンドと変数

http://d.hatena.ne.jp/m-hiyama-memo/20120104/1325638861 :

いずれ説明する。

今日説明する。絵に基づいて説明する。


原寸大

これがコマンドなわけだが:

  1. command body とはPythonコード、またはCatyScriptコードで、コマンドの本体となる定義体(definition body)のこと。
  2. パラメータの一部のArg0はシステムが準備する。今はWebリクエストのURLくらいで、大した用途はないが、いずれヘビーに使う予定だ。
  3. オプションパラメータOptsはコマンドライン(コマンド起動構文)、またはクエリー文字列から渡される。
  4. 引数パラメータArgsはコマンドラインから渡される。アクションのときは、自動的に%0と%1が同じ値にセットされる(これはアクション特有の仕様)。
  5. Arg0 + Args は、Argvとしてアクセスできる。(実際の変数名は _ARGV)
  6. パラメータの情報は、すべて変数としてアクセスできる(書き換えはできない)。command bodyの実行が始まるときには、パラメータ変数の値はすべて確定している。
  7. パラメータ変数以外に、(大域)環境変数がcommand bodyから見える。環境変数とパラメータ変数は、実行前にセットアップされるので、準備済み変数(prepared variables)と呼ぶ。
  8. 準備済み変数のセットアップ手順やスコーピングはけっこう複雑だが今は触れない。
  9. command bodyに制御が渡るときは、準備済み変数と共に標準入力も必ず存在している。標準入出力のデータが制御を運ぶ役割もしている。
  10. 準備済み変数と標準入力以外のデータが欲しいときは、readableファシリティを使う。ファシリティを経由しないIOはほぼ犯罪行為である。多くの場合、犯罪には天罰が下る。
  11. command bodyが正常に終了すれば標準出力にデータを書く。
  12. 例外とシグナルは標準出力以外の出力チャンネルとなる。どちらも「投げて」「キャッチされる」もの。実装は規定しないが、たぶん両者は同じ実装方式だろう。例外はエラーメッセージを出したりロギングしたりする都合から投げるデータ形式決まっている。シグナルは特に制限がない(勝手にやってくれ)。
  13. フォーワード制御は大域ジャンプで、例外/シグナルとは違い行き先が決まっている。ポートを使うと、行き先の決定を遅らせることができるが、実行時には特定のコマンドに飛ぶことになる。
  14. 出力チャンネルの選択は排他的で、どれか1つのチャンネルだけが選ばれる。他のチャンネルには何も出力されない。特定のチャンネルを使用禁止にするには、その型をneverと宣言すればよい。例外なら、throws only [] で例外チャンネルを使用しないこと、つまり絶対に例外を出さないことを宣言できる。
  15. Webの場合は特殊事情で、リダイレクトチャンネルを設ける。これは、シグナルで実装されることが多いだろうが、単に便宜上の都合から独立な出力チャンネルとして扱う。
  16. リダイレクトチャンネルのように、応用で必要ならチャンネルを増やしてもよい。ただし、コマンドの宣言構文が変わるので、ユーザー拡張はできない。



これは局所変数の説明の絵。局所変数(local variable)は、スクリプトコードの実行時に生成され利用(参照)される。Catyでは、変数参照(%foo)も一種のコマンド(射)のように扱う。変数参照(%foo)に制御が渡るときには、変数はセットされてなくてはならない。制御フローを解析すれば、未定義変数の参照は検出できる。

変数参照が点線で描かれたvoid標準入力を持つのは、コマンド扱いだからである。破線で描かれた変数伝搬ワイヤーは、readableファシリティからの入力と同じようなものだ。つまり、%foo は、local-variableファシリティを使う var-ref foo のようなコマンドだと思えばよい。'>' が、local-variableファシリティへの単一書き込みをする演算子となる。

変数参照は、値を変数ポイント(黒丸)から変数伝搬辺(破線)を通してもらうが、自分で値を作り出せばリテラル射となる。変数参照とリテラルはけっこう近い存在だ。



変数セット(variable set)の絵。変数セットとは、文字通り変数の集合体。大域環境変数やパラメータ変数達が変数セットをなす。実装上はシンボルテーブルにするかな。局所変数もスコープを作る(eachブロックとbeginブロック)ので、スコープ内の束縛=変数セットとみなすことができる。

図の変数bazのように、存在しても参照されない変数は描かなくてもよい。あってもなくても同じだから。変数の特徴は、一度値がセットされれば、それより後に何度でも参照できること。図の変数fooは二箇所で参照されている。



絵のソース

念のため、絵のソースを貼っておく。gvモジュールを使っている。万が一、画像ファイルをなくしても、これを実行すればすぐに作れる。手直してもすぐだ。SVGやプレーンDOT形式にも出せるよ。


// -*- coding: utf-8 -*-
// command

[
gv:node --shapa=point --style=invis cin,
gv:node --shapa=point --style=invis ain,
gv:node --shape=point --style=invis pin1,
gv:node --shape=point --style=invis pin2,
gv:node --label="* " --shape=diamond --style=filled --fillcolor=brown param,

gv:edge --label=StdIn cin cmd,
gv:edge --label=Opts pin1 param,
gv:edge --label=Arg0 ain param,
gv:edge --label=Args pin2 param,
gv:edge --label="ParamVars" --arrowhead=diamond param cmd,

gv:node --label="command\nbody" --style=filled --fillcolor=darkseagreen cmd,

gv:node --shapa=point --style=invis cout,
gv:node --label=" " --shape=diamond --style=filled --fillcolor=white th,
gv:node --shapa=point --style=invis cerr,
gv:node --shape=point --style=invis sout,
gv:node --label=target --style="dotted, filled" --fillcolor=yellowgreen port_h,

gv:edge --label=StdOut cmd cout,
gv:edge --label=Throwable cmd th,
gv:edge --label=Exception --color=red --fontcolor=red th cerr,
gv:edge --label="Signal" --color=blue --fontcolor=blue th sout,
gv:edge --color=seagreen --fontcolor=seagreen --label="Forward" cmd port_h,

] | gv:graph --label="command" --rankdir=LR --bgcolor=gainsboro


// -*- coding: utf-8 -*-
// variables

[
gv:node --shapa=point --style=invis vin,
gv:node --shapa=point --style=invis vout,
gv:node --shape=point --width=0.1 --style=filled --fillcolor=black var,

gv:edge --label=A --arrowhead=none --headlabel=foo vin var,
gv:edge var vout,

// ref

gv:node --shapa=point --style=invis rin,
gv:node --shapa=point --style=invis rout,
gv:node --label="%foo" --style=filled --fillcolor=moccasin ref,

gv:edge --arrowhead=none --style=dotted rin ref,
gv:edge --label=A ref rout,
gv:edge --style=dashed --arrowhead=diamond var ref,

] | gv:graph --label="local variable" --rankdir=LR --bgcolor=gainsboro


// -*- coding: utf-8 -*-
// variable set

[
[
gv:node --shape=point --style=invis v1in,
gv:node --shape=point --width=0.1 --style=filled --fillcolor=black var1,
gv:edge --label="foo::A" --style=dashed --arrowhead=none /*--headlabel=foo*/ v1in var1,

gv:node --shape=point --style=invis v2in,
gv:node --shape=point --width=0.1 --style=filled --fillcolor=black var2,
gv:edge --label="bar::B" --style=dashed --arrowhead=none /*--headlabel=bar*/ v2in var2,

gv:node --shape=point --style=invis v3in,
gv:node --shape=point --width=0.1 --style=filled --fillcolor=black var3,
gv:edge --label="baz::C" --style=dashed --arrowhead=none v3in var3,


] | gv:cluster --style="filled, rounded" --fillcolor=moccasin varset,

// ref1

gv:node --shape=point --style=invis r1in,
gv:node --shape=point --style=invis r1out,
gv:node --label="%foo" --style=filled --fillcolor=moccasin ref1,

gv:edge --arrowhead=none --style=dotted r1in ref1,
gv:edge --label=A ref1 r1out,
gv:edge --style=dashed --arrowhead=diamond var1 ref1,

// ref2

gv:node --shape=point --style=invis r2in,
gv:node --shape=point --style=invis r2out,
gv:node --label="%foo" --style=filled --fillcolor=moccasin ref2,

gv:edge --arrowhead=none --style=dotted r2in ref2,
gv:edge --label=A ref2 r2out,
gv:edge --style=dashed --arrowhead=diamond var1 ref2,

// ref3

gv:node --shape=point --style=invis r3in,
gv:node --shape=point --style=invis r3out,
gv:node --label="%bar" --style=filled --fillcolor=moccasin ref3,

gv:edge --arrowhead=none --style=dotted r3in ref3,
gv:edge --label=B ref3 r3out,
gv:edge --style=dashed --arrowhead=diamond var2 ref3,

] | gv:graph --label="variable set" --rankdir=LR --bgcolor=gainsboro