星期二, 9月 22, 2009

boo 的 macro(1)

boo 的 macro 跟 C/C++ 的 macro 很類似,都是在編譯時期就被替代為實際的代碼。不過 C/C++ 只做簡單的替換,boo 的 macro 則是會在編譯時期時進行編譯並且執行、進行替換。


#
# dontimes.boo
#
import System
import Boo.Lang.Compiler

macro DoNTimes:
n = DoNTimes.Arguments[0] as Ast.IntegerLiteralExpression
print n.GetType().ToString() # n is IntegerLiteralExpression
print DoNTimes.Body.GetType().ToString() # DoNTimes.Body is Block
blocks = Ast.Block() # create new block add DoNTimes.Body n times.
for i in range(Convert.ToInt32(n.ValueObject)):
blocks.Add( DoNTimes.Body )
return blocks

DoNTimes 3:
print "foo"

print "Press any key to continue . . . "
Console.ReadKey(true)


使用 booi 來執行,你會看到下面的訊息,foo 被印了三次:

Boo.Lang.Compiler.Ast.IntegerLiteralExpression
Boo.Lang.Compiler.Ast.Block
foo
foo
foo
Press any key to continue . . .

那這跟用 for 迴圈來跑有什麼不同?


首先用 booc 來編譯:booc -t:exe dontimes.boo,在編譯的時候,你會發現第9行跟第10行的訊息被印了出來:

Boo.Lang.Compiler.Ast.IntegerLiteralExpression
Boo.Lang.Compiler.Ast.Block

這證明了 boo compiler 會在編譯時,把 macro 的部份先拿出來編譯,然後在編譯的時後去執行 macro,對程式碼進行替換。然後你會發現執行 dontimes 的時候,只印了 foo 三次。

reflector 來看,可以看到:

private static void Main(string[] argv)
{
Console.WriteLine("foo");
Console.WriteLine("foo");
Console.WriteLine("foo");
Console.WriteLine("Press any key to continue . . . ");
Console.ReadKey(true);
}


代碼只有三行Console.WriteLine("foo");,這很清楚的說明了 booc 在編譯時,就把 macro 的內容替換進去了。

沒有留言: