= デバッグ

スクリプティング言語は、
一般に「プログラミングしやすい」言語と考えられています。
しかし、どのようなソースコードにも必ずバグが存在し、
デバッグ作業が必要となりあす。

ここでは、Konoha のデバッグ支援の機構をみていきましょう。

== print 文 - print デバッグ専用のステートメント

どのようなソースコードにも必ずバグは存在します。
漫然とソースコードを眺めているより、実行時の状態をトレース(追跡)した方が、
効率よくバグの原因を見つけられます。

実行状態のトレースは、特別な解析ツールを利用しない限り、
プログラマ自身が経験と勘を頼りにしてプログラム中に埋め込むことになります。
これが通称、「print(f) デバッグ」と呼ばれる手法です。

次は、簡単なバグが含まれたコードの例です。

{{{
int fibo(int n) {
	if(n == 1) return 1;
	return fibo(n-1) + fibo(n-2);
}

}}}

あきらかに !StackOverflow なのですが、
そういうことは気にせずに、パラメータ n の値を調べてみましょう。

{{{
>>> int fibo(int n) {
...   print n;   // パラメータを表示してみる
...	  if(n == 1) return 1;
...   return fibo(n-1) + fibo(n-2);
... }
>>> fibo(1)
n=1
>>> fibo(2)
n=2
n=1
n=0
n=-1
n=-2
.... 

}}}

Konoha の print 文は、
デバッグ情報を表示するための専用のステートメントです。
そのため、変数名などは親切に表示してくれます。

=== デバッグモード -g オプション

print 文の便利なところは、
通常のスクリプトの実行では無視される点です。

{{{
cat print.k 
OUT << "begin of print" << EOL;
x, y = 1, 2;
print x, y;
OUT << "end of print" << EOL;

$ konoha print.k 
begin of print
end of print

}}}

何も表示されません。
konoha を実行するとき、-g オプションを付けると、
print 文が有効になります。

{{{
$ konoha -g print.k
begin of print
x=1, y=2
end of print

}}}

-g2 オプションを付けると、もう少し詳しい情報が得られます。

{{{
$ konoha -g2 print.k
begin of print
[print.k:3] x=1, y=2
end of print

}}}

Konoha の print 文の特徴は、
デバッグ表示を実行モードによって自由にかえられる点にあります。
一時的に、実行時の内部状態を知りたいときは、
print 文を使うようにしましょう。

=== デバッグモードの実行時切り替え 

デバッグモードは、実行コンテクスト(Context)単位で切り替えています。
Contextクラスを変更することで、実行時にモードを切り替えることもできます。

{{{
Context.setDebug(true);            // デバッグモードに変更
Context.setDebug(false);           // リリースモードに変更

}}}

「実行時のモード切り換え」を正しく使うためには、
Konoha のスクリプト実行の内側まで注意する必要があります。
スクリプトの実行は、厳密に言えば、コンパイル（コード生成）とコードの実行からなり、
-g オプションなしでコンパイルをしたコードは、
print文と（後述する）assert 文はコンパイルされません。

== assert文

アサーション(assertion)は、表明と訳されます。
プログラムが正しく動作するための条件を表明することで、
Konoha は常に表明された条件を満たしながら動作しているかチェックしてくれます。

これは、使い方を覚えると、非常に便利です。

また、fibonacci 関数で恐縮なのですが、次のように使います。

{{{
int fibo(int n) {
   assert(n > 0);     // n > 0 と表明する
   if(n == 1 || n == 2) return 1;
   return fibo(n-1) + fibo(n-2);
}

}}}

さて、動作は（正しく利用する限り）今までと変わりはありません。

{{{
>>> fibo(10)
55

}}}

ただし、アサーションの条件に違反すると、実行時例外をスローします。

{{{
>>> fibo(0)

[assert.k:2] Assertion!!
  at (assert.k:2):main.Script.fibo(n=0)
  at ((shell):4):main.Script

}}}

ここで何がうれしいのかといえば、
間違って fibo() 関数を呼び出している箇所を探すことができる点です。
つまり、fibo(0)を呼び出した方が明確にバグになります。

assert文を使えば、
もし0以下のパラメータで呼ばれたらどうしようと悩む必要もありません。

{{{
int fibo(int n) {   // 悩める fibo()
	if(n > 0) { 
		if(n == 1 || n == 2) return 1;
		return fibo(n-1) + fibo(n-2);
	}
	return 0; // いいのか?
}

}}}

assert文は、デバッグ作業を助けるステートメントです。
結局、プログラムの動作が!Assertion!! 例外で停止してしまうからです。
そのため、徹底的にソフトウェアテストを行うようにしましょう。
print 文と同様に、デバッグモード(-gオプション付き)でなければ無視されます。

=== assert文 と終了処理

Konohaは、Assertion!! をスローする直前にどういう状態であったか表示するため、
条件式に続けてステートメントを記述できるように拡張してあります。

{{{
assert(n > MAX) {
	print n, MAX;
}
}}}

{{{ comment

=== @Debug アノテーション

デバッグモード (-g オプション) は、
スクリプトのリリースとデバッグを繰り返すときに便利なのですが、
メソッド単位でデバッグモードを制御したいときもあります。

そのようなときは、@Debug アノテーションを付ければ、
常に print 文は有効になります。

@Debug
int fibo(int n) {
    print n; 
	if(n == 1) return 1;
	return fibo(n-1) + fibo(n-2);
}

}}}

== test文**

Konohaプロジェクトでは、
ユニットテストをサポートするための専用のステートメントを導入する計画です。

次は、提案されているtest文です。

{{{
test "finonacchi" {
  must fibo(10) == 55;
} 

}}}

[[include(KbookIndex)]]
[[include(KbookFooter)]]
