view paper/chapter/02-interface.tex @ 37:b8cb6fcd9342

...
author anatofuz <anatofuz@cr.ie.u-ryukyu.ac.jp>
date Sun, 31 Jan 2021 21:04:41 +0900
parents d9c29dddf64f
children ae00fdac2e99
line wrap: on
line source

\section{GearsOSのInterfaceの構文の改良}
GearsOSのInterfaceでは、 従来はDataGearとCodeGearを分離して記述していた。
CodeGearの入出力をDataGearとして列挙する必要があった。
CodeGearの入出力として\texttt{\_\_code()}の間に記述したDataGearの一覧と、Interface上部で記述したDataGearの集合が一致している必要がある。

従来の分離している記法の場合、 このDataGearの宣言が一致していないケースが多々発生した。
またInterfaceの入力としてのDataGearではなく、 フィールド変数としてDataGearを使うようなプログラミングスタイルを取ってしまうケースも見られた。
GearsOSでは、 DataGearやフィールド変数をオブジェクトに格納したい場合、 Interface側ではなくImpl側に変数を保存する必要がある。
Interface側に記述してしまう原因は複数考えられる。
GearsOSのプログラミングスタイルに慣れていないことも考えられるが、構文によるところも考えられる。
CodeGearとDataGearはInterfaceの場合は密接な関係性にあるが、 分離して記述してしまうと「DataGearの集合」と「CodeGearの集合」を別個で捉えてしまう。
あくまでInterfaceで定義するCodeGearとDataGearはInterfaceのAPIである。
これをユーザーに強く意識させる必要がある。

golangにもInterfaceの機能が実装されている。
golangの場合はInterfaceは関数の宣言部分のみを記述するルールになっている。
変数名は含まれていても含まなくても問題ない。

\begin{lstlisting}[frame=lrbt,label=src:golang_interface,caption={golangのinterface宣言}]
type geometry interface {
    area() float64
    perim() float64
}
\end{lstlisting}

\section{Implementの型をいれたことによる間違ったGearsプログラミング}
Implementの型を導入したが、 GearsOSのプログラミングをするにつれていくつかの間違ったパターンがあることがわかった。
自動生成されるStubCodeGearは、 goto metaから遷移するのが前提であるため、 引数をContextから取り出す必要がある。
Contextから取り出す場合は、 実装しているInterfaceに対応している置き場所からデータを取り出す。
この置き場所は\texttt{data}配列であり、 配列の添え字は\texttt{enum Data}と対応している。
また各CodeGearからgotoする際に、 遷移先のInterfaceに値を書き込みに行く。


Interfaceで定義したCodeGearと対応しているImplementのCodeGearの場合はこのデータの取り出し方で問題はない。
しかしImplementのCodeGearから内部でgotoするCodeGearの場合は事情が異なる。
内部でgotoするCodeGearは、 Javaなどのプライベートメソッドのように使うことを想定している。
このCodeGearのことをprivate CodeGearと呼ぶ。
privateCodeGearにgotoする場合、 goto元のCodeGearからは\texttt{goto meta}経由で遷移する。
goto metaが発行されるとStub Code Gearに遷移するが、現在のシステムではInterfaceから値をとってくることになってしまう。


\section{メタ計算部分の入れ替え}
GearsOSでは次のCodeGearに移行する前のMetaCodeGearとして、 デフォルトでは\texttt{\_\_code meta}が使われている。
\texttt{\_\_code meta}はcontextに含まれているCodeGearの関数ポインタを、 enumからディスパッチして次のStub CodeGearに継続するものである。

例えばモデル検査をGearsOSで実行する場合、 通常のStub CodeGearのほかに状態の保存などを行う必要がある。
この状態の保存に関する一連の処理は明らかにメタ計算であるので、 ノーマルレベルのCodeGearではない箇所で行いたい。
ノーマルレベル以外のCodeGearで実行する場合は、 通常のコード生成だとStubCodeGearの中で行うことになる。
StubCodeGearは自動生成されてしまうため、 値の取り出し以外のことを行う場合は自分で実装する必要がある。
しかしモデル検査に関する処理は様々なCodeGearの後に行う必要があるため、 すべてのCodeGearのStubを静的に実装するのは煩雑である。

ノーマルレベルのCodeGearの処理の後に、StubCodeGear以外のMeta Code Gearを実行したい。
Stub Code Gearに直ちに遷移してしまう\texttt{\_\_code meta}以外のMeta CodeGearに、 特定のCodeGearの計算が終わったら遷移したい。
このためには、特定のCodeGearの遷移先のMetaCodeGearをユーザーが定義できるAPIが必要となる。
このAPIを実装すると、ユーザーが柔軟にメタ計算を選択することが可能となる。

GearsOSのビルドシステムのAPIとして\texttt{meta.pm}を作製した。
これはPerlのモジュールファイルとして実装した。
meta.pmはPerlで実装されたGearsOSのトランスコンパイラであるgenerate\_stub.plから呼び出される。
meta.pmの中のサブルーチンである\texttt{replaceMeta}に変更対象のCodeGearと変更先のMetaCodeGearへのgotoを記述する。
ユーザーはmeta.pmのPerlファイルをAPIとしてGearsOSのトランスコンパイラにアクセスすることが可能となる。

具体的な使用例をコード\ref{src:metapm}に示す。
meta.pmはサブルーチン\texttt{replaceMeta}が返すリストの中に、特定のパターンで配列を設定する。
各配列の0番目には、goto metaを置換したいCodeGearの名前を示すPerl正規表現リテラルを入れる。
コード\ref{src:metapm}の例では、\texttt{PhilsImpl}が名前に含まれるCodeGearを指定している。
すべてのCodeGearのgotoの先を切り替える場合は\texttt{qr/.*\//}などの正規表現を指定する。

\lstinputlisting[label=src:metapm, caption=meta.pm]{src/meta.pm}

generate\_stub.plはGears CbCファイルの変換時に、 CbCファイルがあるディレクトリにmeta.pmがあるかを確認する。
meta.pmがある場合はモジュールロードを行う。
meta.pmがない場合はmeta Code Gearにgotoするものをデフォルト設定として使う。
各Gode Gearが\texttt{goto文}を呼び出したタイミングでreplaceMetaを呼び出し、 ルールにしたがってgoto文を書き換える。
変換するCodeGearがルールになかった場合は、 デフォルト設定が呼び出される。

\section{別Interfaceからの書き出しを取得する必要があるCodeGear}

従来のMetaCodeGearの生成では、 別のInterfaceからの入力を受け取るCodeGearのStubの生成に問題があった。
具体的なこの問題が発生する例題をソースコード\ref{src:insertTest1}に示す。
この例では\texttt{pop2Test}Code Gearから \texttt{stack->pop2}を呼び出し、 継続として\texttt{pop2Test1}を渡している。
\texttt{pop2Test}自体はStackTest Interfaceであり、 \texttt{stack->pop2}の\texttt{stack}はStack Interfaceである。

\lstinputlisting[label=src:insertTest1, caption=2つ以上の出力があるCodeGearからの遷移例]{src/pop2test.cbc}

当初Perlスクリプトが生成した\texttt{insertCase1}のstub CodeGearはソースコード\ref{src:pop2stub-origin}のものである。
\texttt{insertCase1}はtree, parent, grandparentの3引数必要であるが、生成されたコードの引数がそろっていないことがわかる。


\lstinputlisting[label=src:pop2stub-origin, caption=生成されたStub]{src/pop2stub-origin.cbc}