制御フロー

パステルステッチのプログラムを実行すると、まず「イニシャライズ実行」が行われ、それが終わると「本体実行」が行われます。イニシャライズ実行については後述します。本体実行では、パステルステッチのプログラムに書かれている文を前方から後方に向けて順に実行します。

パステルステッチの文は読み出し演算と同じように実行されます。ただし、パステルステッチの文のうち、疑似命令、ブロック開始文、制御構文は、読み出し演算としてではなく、それぞれに固有の方法で実行されます。

疑似命令には以下のものがあります。

制御構文には以下のものがあります。

これらの制御構文の姓はいずれも main です。これらの名前が有名ベクトルとして文の述語部に記述されたとき、制御構文として認識されます。述語の値がこれらの有名ベクトルと等しいというだけでは制御構文として認識されません。たとえば、述語部を null + break のような式にしてしまえば、制御構文ではなく読み出し演算として実行されます。

文が疑似命令、ブロック開始文、制御構文のいずれでもないならば、読み出し演算として実行されます。ただし、文は式の一部ではないので、読み出し演算の戻り値は捨てられます。

読み出し演算

読み出し演算は以下のように実行されます。

まず、述語部に有名ベクトル control flow andmain または control flow ormain が記述されているならば、制御構文として認識されます。意味はそれぞれ論理積または論理和です。述語の値がこれらの有名ベクトルと等しいというだけでは制御構文にはなりません。たとえば、述語部を null + control flow and のような式にしてしまえば、通常の読み出し演算として処理されます。引数 left が左辺を、引数 right が右辺を表します。これらの制御構文では、まず引数 left (左辺) の値を計算します。その結果、論理積で左辺が偽である場合、または、論理和で左辺が真である場合には、右辺を計算しません。そうでなければ、右辺を計算します。

読み出し演算が制御構文ではない場合には、まず、述語と、すべての引数が計算されます。続いて、述語の値の種類に応じて、以下のように処理されます。

引数解決の方法は後述します。

サブルーチン

サブルーチンを定義するには procedure ブロックを使用します。procedure ブロックのブロック開始文は単独形式の引数部を持ちます。この引数にはベクトルを指定する必要があります。procedure ブロックはサブルーチンとベクトルを結びつけます (これを「サブルーチンの登録」と言います。)。procedure ブロックの内部にさらに procedure ブロックを記述することができますが、外側と内側の procedure ブロックには特に関係性は発生しません。サブルーチンの登録はイニシャライズ実行で行われます。本体実行では procedure ブロックは単に読み飛ばされます。

サブルーチンを実行するには、読み出し演算の述語に、そのサブルーチンに対応するベクトルを与えます。引数解決の過程で、サブルーチンの実行よりも優先度の高い要因が存在しなければ、サブルーチンが実行されます。その読み出し演算の引数は、サブルーチンに対する引数として利用されます。

サブルーチンの実行中はコンテキスト変数の値を参照することができます。コンテキスト変数 #offset と #verb は特殊なコンテキスト変数です。それらの意味は次の段落で説明します。これらの特殊なコンテキスト変数を除いて、コンテキスト変数の値は、サブルーチンを呼び出した読み出し演算の引数の値です。これらのいずれにも当てはまらないコンテキスト変数の値は論理型の false になります。

コンテキスト変数 #offset は「サブルーチン固有ベクトル」を意味します。これは、サブルーチンを実行するごとに作られる (正確には、引数解決を開始した時点で作成される) 一意な無名ベクトルです。同一のサブルーチンであっても、そのサブルーチンを複数回実行した場合には、それぞれ異なるサブルーチン固有ベクトルが作られます。コンテキスト変数 #verb はサブルーチンを呼び出した読み出し演算の述語の値を意味します。この述語の値とは、引数変換 (後述) が行われた後のものです。また、コンテキスト変数 #verb は現在実行中のサブルーチンと結びつけられているベクトルと等しくなります。

メインルーチンでは、#offset はメインルーチンに固有の無名ベクトルです。他のコンテキスト変数の値は論理型の false です。

プリミティブ演算 return はサブルーチンの戻り値を指定します。他のプログラミング言語と違って、パステルステッチの return はサブルーチンを終了しません。単に戻り値を指定するだけです。プリミティブ演算 return を複数回実行した場合は、最後に実行したときの引数の値がサブルーチンの戻り値になります。また、プリミティブ演算 return を実行せずにサブルーチンを終了した場合は、戻り値は論理型の false になります。

制御構文 escape はサブルーチンを終了します。実行位置がサブルーチンの終端に達した場合にも、同様にサブルーチンを終了します。

サブルーチンを定義すると同時に実行するには mulde ブロックを使用します。mulde ブロックはサブルーチンの登録を行いません。本体実行の過程で、その場でサブルーチンを実行します。mulde ブロックのブロック開始文の引数は、サブルーチンの引数として、コンテキスト変数で参照できます。

サブルーチンを取り扱うために、以下のようなプリミティブ演算があります。

条件分岐

条件分岐には if ブロックを使用します。if ブロックのブロック開始文の引数が、論理型の true であるか、または論理型でない場合には、if ブロックの内部が実行されます。if ブロックのブロック開始文の引数が論理型の false である場合は、if ブロックの終端まで実行が飛ばされます。

ループ

ループには loop ブロックを使用します。loop ブロックの終端まで実行すると、loop ブロックの最初まで戻ります。loop ブロックのブロック開始文は引数をとりません。

ループを抜けるには制御構文 break を使用します。制御構文 break の引数が省略されたとき、または、引数の値が論理型の false であるときは、ループを抜けます。制御構文 break の引数の値が論理型の true であるか、または論理型でない場合には、そのまま次の文に進みます。

インタープリターの終了

パステルステッチのインタープリターを終了するには制御構文 halt を使用します。また、本体実行の過程でプログラムの終端に達したときも、同じようにインタープリターを終了します。コンティニュエーションを保存していれば、インタープリターを終了しても、外部からコンティニュエーションを起動することでプログラムの実行を再開することができます。

イニシャライズ実行

イニシャライズ実行では以下の処理が行われます。

これらの処理がプログラムの前方から後方に向けて順に実行されます。イニシャライズ実行の過程では、すでに登録されているサブルーチンを実行することが可能です。また、イニシャライズ実行の過程では、読み出し演算のメモ化と非局所制御フロー構文は無効です。