顯示具有 boo 標籤的文章。 顯示所有文章
顯示具有 boo 標籤的文章。 顯示所有文章

星期三, 9月 23, 2009

boo 的 macro(2)

boo 應該是在 0.8 以後吧,就提供了 macro 這個新的關鍵字,用來寫 macro,之前的寫法相當麻煩,需要先繼承 AbstractAstMacro,然後overwrite Expand 這個方法。
新的 macro 關鍵字簡化了一些功夫,macro 之後接的是名稱,下面的 block 就是描述要怎麼去替代,block 的最後再傳回 Ast.Block 即可。

大致的寫法就像這樣子:

macro Msg:
args=Msg.Arguments # macro 名稱其後加上 .Arguments,表示取得 macro 後面的參數
# [| |] 是相對簡便的語法,表示這裡面是個 Ast.Block,也就是程式區塊,而 .Body 則表示是 macro 下面的 block
# 注意:[| 後與 |] 前一定要分行,否則會有錯誤
return [|
$(Msg.Body)
|]


寫法相當簡潔,不過在寫的時候,卻很容易讓人碰壁。最大的原因是用法誨澀,以上面的 Msg macro 來說,當 Msg 123 的時候,Msg.Arguments[0] 的型態照理應該是 Int32 才對,但實際上卻是 Ast.IntegerLiteralExpression,型態已經全然是 Compiler AST tree 裡的型態,macro 裡要取用變數、或產生 block也很容易造成困擾,這對於不玩 compiler 的人來說,是相當高的門檻。再者,文件的缺少也是很重要的因素,官方對於這方面的文件非常缺少(比較少人玩 Boo 也是一個主因)。
但是,這對於創造新的語法來說,卻是相當的便利,這也就是一般常說的 DSL,你可以針對某個特定領域來創造適合的語法。網路上能找到的例子,也多半如此。

星期二, 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 的內容替換進去了。

星期三, 7月 08, 2009

Boo Generator expression

從這串討論:Array Type Question - Boo Programming Language裡的例子,最能看出其威力。

objectArray 是一個型別為 object 的陣列,但裡面的 object 其實都是 string。
下面這樣一行,就把型別為 object 的陣列轉為字串的陣列了...


strings = array(o as string for o in objectArray)


其他更詳細的說明可以參考:維基教科書 的 BOO/Generators

星期二, 9月 02, 2008

[Boo]booish 與 booc 編譯後的執行結果不同?

Boo Programming Language網上論壇發現了這個討論串:Problems with BooPrimer
發問者表示同樣的程式在 booish 執行與用 booc 編譯後的執行結果不同,我大吃一驚,趕緊試試,發現真的是跟發問者講的一樣,心想完蛋,怎麼會這樣...


i = 0
while i < 5:
print i
i += 1


隔了一天,有人(Stoo)回覆了,說 booish 在執行結束後,會再次印出 i 的值,並建議改成這樣,可以更能看出問題所在:

i = 0
while i < 5:
print "i=${i}"
i += 1


果然,執行結果就如同他回覆所說的一樣:

i = 0
i = 1
i = 2
i = 3
i = 4
5

星期三, 8月 20, 2008

[Boo]在 ASP.Net 裡使用 Boo

方法很簡單,只要修改 web.config,然後把 Boo 相關的 assembly 放到 bin 目錄下即可:

<configuration>
<system.web>
<compilation debug="true">
<assemblies>
<add assembly="Boo.Lang.CodeDom" />
</assemblies>
<compilers>
<compiler language="Boo" extension=".boo" type="Boo.Lang.CodeDom.BooCodeProvider, Boo.Lang.CodeDom" compilerOptions="-ducky -utf8"/>
</compilers>
</compilation>
<customErrors mode="Off"/>
</system.web>
</configuration>


要注意的是,如果你的應用程式不是 code behind 而且 Hosting 是 IIS 或是 .NET framework 內建的小 web server 時,會有問題。問題出在 Indent,Boo 對於 Indent 很敏感,不知道為甚麼,在 Microsoft.NET 下,Indent 就是會錯。使用Mono XSP的話,則沒有問題。
是故,你可以改使用 code behind 的方式繞過這問題。

會發現這問題,是因為有人在 boolang 討論群組裡問了這問題:boo on asp.net,我去試才知道的。最後提問者改用 xsp...

星期二, 7月 22, 2008

[Boo]Play automatically after Banshee launched - part 2

每次都從第一首播放,實在太沒意思,所以在播放前切換為 Shuffle 模式,播放時,就會隨機挑選一首開始播放,然後再關閉 Shuffle 模式。


import System
import System.IO
import Banshee.ServiceStack
import Banshee.PlaybackController

def AutoPlay() as bool:
ServiceManager.PlaybackController.ShuffleMode = PlaybackShuffleMode.Song
ServiceManager.PlayerEngine.Play()
ServiceManager.PlaybackController.ShuffleMode = PlaybackShuffleMode.Linear

def OnClientStarted( client as Client ):
Hyena.Log.Information( "engine is playing now..." )
GLib.Timeout.Add(1500, AutoPlay)
Banshee.ServiceStack.Application.ClientStarted -= OnClientStarted

Hyena.Log.Information( "autoplay script is loaded." )

Banshee.ServiceStack.Application.ClientStarted += OnClientStarted


p.s. 上次有提到要作自動記錄播放與自動播放記錄曲目的功能,我的確是做了,只是在播放完指定曲目後,又跳回第一首,這表示我還得繼續研究原始碼才行,所以暫時不釋出。

星期二, 7月 15, 2008

[Boo]用 Boo 寫 Web Service

必須先將以 Boo 寫的 Web Service 編譯為 Assembly,然後再製作一個以 c# 或 vb.net 寫的 asmx 繼承該 Web Service 類別才行。
否則會遇到 "The invoked member is not supported in a dynamic module." 的錯誤。

我是在遇到錯誤的時候,去參考 boo 源碼 examples/asp.net 下的 Math.asmx 與 Math.asmx.boo 才知道這件事情的。
本來我還在納悶,為甚麼 examples/asp.net 下會有一個用 c# 寫的 asmx,還以為是搞錯了呢~


// Math.asmx.boo
// 要先編譯好,放在 bin 目錄下:booc -t:library -out:bin/Math.dll Math.asmx.boo
import System.Web.Services

[WebService]
class Math:
[WebMethod]
def Add(a as int, b as int):
return a+b

[WebMethod]
def Multiply(a as int, b as int):
return a*b



<%@WebService Class="MathService" Language="C#" %>
// Math.asmx
public class MathService : Math // 繼承用 Boo 寫的 Math 類別
{
}

星期五, 7月 04, 2008

[Boo]Play automatically after Banshee launched

I use the BooScript extension which was introduced in previous post to make Banshee play automatically.
When BooScript extension is loaded, the extension will check the scripts. If there are scripts, it will compile them and execute. At this moment, lots of things are not initialized yet, so we have to add code to Application.ClientStarted. And application will execute our code after everything is initialized.


import System
import System.IO
import Banshee.ServiceStack

def OnClientStarted( client as Client ):
Hyena.Log.Information( "engine is playing now..." )
ServiceManager.PlayerEngine.Play()

Hyena.Log.Information( "autoplay script is loaded." )

Banshee.ServiceStack.Application.ClientStarted += OnClientStarted


The script is very simple, I will add the functions to save the current track and to play the saved track automatically.

星期四, 7月 03, 2008

[Linux]Using BooScript in Banshee 1.0

There are 2 ways to run the script:
  1. Run banshee with parameter: --run-scripts your_boo_scripts.boo
  2. Place the scripts in ~/.config/banshee-1/boo-scripts/


If you are familar with boo, it is not hard to add more functions for Banshee.
Of course, you have to understand the source code of Banshee. Beside the source code, you can refer to the official extension provided by Banshee.

星期五, 6月 27, 2008

[Boo]Boo(20)-Generator 函式

Generator 函式其實就跟 C# 的 Iterator 一樣,利用 yield 關鍵字先把值傳回讓呼叫者使用。
使用 Generator/Iterator 最大的好處是可以讓函式只做必要的邏輯,而不需要把一些事情綁在迴圈裡面。
下面就是一個很標準的尋訪目錄樹的範例,尋訪的工作交給 walk,主程式則負責依據傳回的值作處理。


import System
import System.IO

def walk( path as string ):
di = DirectoryInfo( path )
for d in di.GetDirectories():
yield d as FileSystemInfo
for f in di.GetFiles():
yield f as FileSystemInfo

for node in walk( "." ):
if node isa DirectoryInfo:
print "[${node.Name}]"
elif node isa FileInfo:
print node.Name


參考自:Generators

p.s. 這系列文章一定會持續寫到 macro 出現為止。

星期五, 6月 20, 2008

[Boo]Boo 的 currying

拜讀了Jserv大的"以 C 語言實做 Functional Language 的 Currying"Thinker大的"真 C 語言實做 Functional Language 的 Currying"以後,決定也來挖掘一下 Boo 的 currying 寫法,根據這篇文章:Boo Programming Language Languages Currying Def Return World,程式碼出乎意料的簡單:

//Currying:
plusX = { a as int | return { b as int | return a + b }}

print plusX(3)(4)

就這樣。老實說,大概懂了,可是又不是很懂,也沒想到用途。

所以,就跟沒懂是一樣的。

星期一, 6月 16, 2008

[Boo]Boo(19)-例外處理

例外處理的語法與 Python 相近,差別在於 Boo 使用 ensure,而 Python 使用 finally。
除此之外,Boo 統一使用 except 處理各種例外,而 Python 使用 else 處理無法處理的例外型態。


import System

class MyException(Exception):
_msg as string
def constructor( s as string ):
_msg = s
override def ToString() as string:
return "MyException::${_msg}"

// 試著調整這兩個變數試試看
isExceptionHappen = false
isMyExceptionHappen = true

try:
// .. do something ...
if isExceptionHappen:
raise Exception("Something wrong.") // 提出例外情況
// ...
if isMyExceptionHappen:
raise MyException("Hey!!")
except e as MyException:
print e.ToString()
except e as Exception:
print e.Message
ensure:
print "不管有沒有錯誤,這裡都會被執行。"


參考:Boo Primer - 例外Python tutorial - 8. Errors and Exceptions

星期五, 6月 13, 2008

[Boo]Boo(18)-命名空間

.NET上的語言幾乎都導入命名空間了,Boo 無法置身事外...

命名的方式,則是在原始檔第一行加上: namespace 命名空間名稱
撇開註解不算,命名空間的宣告,無論如何都要是程式碼的第一行,否則會有錯誤發生。

引用時,則是使用 import 關鍵字,例如:

import System

Console.WriteLine( "Hello world!" )

// 為甚麼要引用命名空間?因為這樣寫很累...
System.Console.WriteLine( "Hello again." )


你也可以指明組件(Assembly)的名稱,所以這幾種寫法也行:

import System.Data from System.Data
import Gtk from "gtk-sharp"


對了,組件不需要特別加上 ".dll"

星期五, 6月 06, 2008

[Boo]Boo(17)-結構與列舉

結構(struct)跟類別很類似,最明顯的差別在於 class 被換成 struct 了,類別的一些特性也可以在結構上使用。
其他的差別:無法繼承類別、結構,只能實作 Interface﹔結構是值型別,在複製實體時,是整個克隆(Clone)而不是像類別一樣,只做參考。

struct Dog:
def constructor( name ):
_name=name
[property(Name)]
_name as string
emptydog=Dog()
print "emptydog.Name=${emptydog.Name}" // 什麼都沒印出
lucky=Dog("Lucky")
print "lucky.Name=${lucky.Name}" // 印出 Lucky


列舉(enum),如果你有用過 C/C++/C# 的話,應該不陌生:

// 宣告列舉
enum Day:
Sunday
Monday
Tuesday
Wednesday
Thursday
Friday
Sunday
// 也可以指定數值
enum Task:
TODO=100
FIXME=101
// 列印
print Day.Sunday
// 尋訪列舉型別裡所有元素
for s in Enum.GetNames(Day):
print s
// 另一種
for n,v in array( zip( Enum.GetNames(Task), Enum.GetValues(Task)) ):
print "${n}=${v}"

星期一, 6月 02, 2008

[Boo]Boo(16)-Class

Boo 的類別(Class),跟 Python 很像,基本上不複雜。

class Animal:
pass

class Dog(Animal):
def constructor():
pass
def constructor( name ):
_name=name
def destructor():
pass
def Bark():
print "${_name} is barking..."
[property(Name)]
_name = "Anonymous"
spot=Dog( "spot" )
whity=Dog( Name:"whity" )
print spot.Name
whity.Bark()


class 跟 C# 一樣,可以加上 public、protected、internal、protected internal、private、abstract、final 等修飾詞,預設是 public。
繼承的話,就是在類別名稱後面加上小括號,並在括號內放置欲繼承的類別。
建構子與解構子分別是 constructor 與 destructor,可寫可不寫。
方法的宣告其實跟前面提到的函數很像,都是使用 def ,def 的前面還可以加上 abstract、static、virtual、override 等修飾詞。
最後是欄位,通常就跟寫運算式一樣,給定一個值就行了,像這樣:_name="",前面的 [property()] 是 attribute,是一個偷懶的寫法,實際上是 get/set 的組合體:

class Cat(Animal):
def constructor():
pass
def constructor( name ):
_name=name
def destructor():
pass
def Meow():
print "${_name} is meowing..."
Name as string:
get:
return _name
set:
_name=value
_name = "Anonymous"


看到這裡,你有發現到這行嗎?whity=Dog( Name:"whity" )。咦,莫非在建構時可以直接指定屬性的值,沒錯,這寫起程式來方便很多啊~

參考資料:

星期四, 5月 29, 2008

[Boo]Boo(15)-內建函數:容器操作

join()、map()、array()、matrix()、iterator()、enumerate()、range()、reversed()、zip()、cat()

這一類的函式還...蠻多的,大多都與 python 相容。

join(),把 Enumerator 裡面每個元素轉成字串,最後串成一個字串傳回。你也可以加上第二個引數,他會自動幫你加上,例如:join( [1,2,3,4,5], ":" ) 會得到 "1:2:3:4:5" 的字串。
map(),對 Enumerator 裡面每個元素施行指定的函式。
array(),傳入一個 Enumerator 回傳一個陣列。
matrix(),建立多維陣列。
iterator(),取得物件的 IEnumerable 介面,如果物件沒有 IEnumerable 介面,但有繼承 TextReader 的話,則改用 TextReaderEnumerator.lines() 取得 IEnumerable。這個函數在內部非常頻繁地被這裡提到的其他函數使用到。
enumerate(),先取得物件的 IEnumerable 介面,然後傳回類似 (index, value ) 的 Enumerator,舉例來說,List( enumerate( [ "a", "b", "c", "d" ] ) ) 的結果會是:[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd')]。
range() 很容易理解,傳入數值,會回傳有循序數值的 Enumerator,你也可以傳入起始與結束的數值或是傳入起始、結束與遞增數。
reversed(),將 Enumerator 裡面的元素以相反順序擺放,內部是使用 ReversedListEnumerator 類別來完成這件事情。
zip(),傳入多個 Enumerator,它會把每個 Enumerator 的第 0 個元素放到一起、第 1 個元素放到一起...以此類推,最後再傳回一個 Enumerator。這個函數看例子會比較容易了解,array(zip(['a','b','c'],[4,5,6],['aa','bb','cc'])) 的結果會是 (('a', 4, 'aa'), ('b', 5, 'bb'), ('c', 6, 'cc'))。老實說,我還沒想到要怎麼用...
cat(),跟 join 有點像,不過不會傳回字串,而是把傳入的 Enumerator 串接起來成一個 Enumerator 再傳回。

這裡有的函數我沒舉例,要看例子的話,可以參考Boo Primer中文版對內建函數的說明

星期五, 5月 23, 2008

[Boo]Boo(14)-內建函數:輸入與輸入

print、gets、prompt

print 就是調用 Console.WriteLine() 而已,官方建議使用 print macro,而不要使用這個函數。
gets 從標準輸入取得一個字串,實際上就是調用 Console.ReadLine()。
prompt 是 Console.ReadLine() + Console.Write() 的組合技,在印出你給的提示訊息之後,會接著從標準輸入取得字串。

從標準輸入取得字串的意思就是,畫面會停住,等你輸入字元,直到你按下 Enter 之後,才把你輸入的字元放到字串裡傳回。


print("Hello")
s = gets()
print s
s = prompt("Please input something:")
print s


當然,除了這些函數以外,你還是可以直接使用 .NET Framework 裡的 System.IO 來處理。

星期三, 5月 21, 2008

[Boo]Boo(13)-內建函數:shell 類

shell()、shellp()、shellm()
顧名思義,就是執行外部的程式。

shell() 會等待外部程式執行完成以後,回傳一個字串,字串裡是執行的結果。
shellp() 不會等待外部程式執行完成,會直接回傳 Process 物件,事實上,shell() 也呼叫了這個函數,只是 shell() 拿到 Process 物件以後,利用 Process.StandardOutput() 去讀取執行結果,並使用 Process.WaitForExit() 等待程序執行完成。
shellm() 也是執行外部程式,但這個外部程式必須是 Managed,也就是 .NET 應用程式。老實說,看了 boo 源碼以後,我不是很懂。源碼裡面是建立一個新的 AppDomain,載入指定的程式,然後找到 EntryPoint 並執行。我猜想,這樣的作法主要用來避免再次建立新程序、啟動 CLR,在 CPU、記憶體使用上會比較有效率。如果你的外部程式正好也是 .NET 應用程式的話,就用 shellm(),我想會比較好。


input = shell( "booc.exe", "" )

星期一, 5月 19, 2008

[Boo]booc 的 49 道工法

從 Visual Studio debugger 裡面截出來的...想不到編譯需要這麼多步驟...

- _items {維度:[64]} object[]
+ [0] {Boo.Lang.Parser.BooParsingStep} object {Boo.Lang.Parser.BooParsingStep}
+ [1] {Boo.Lang.Compiler.Steps.InitializeTypeSystemServices} object {Boo.Lang.Compiler.Steps.InitializeTypeSystemServices}
+ [2] {Boo.Lang.Compiler.Steps.PreErrorChecking} object {Boo.Lang.Compiler.Steps.PreErrorChecking}
+ [3] {Boo.Lang.Compiler.Steps.ExpandAstLiterals} object {Boo.Lang.Compiler.Steps.ExpandAstLiterals}
+ [4] {Boo.Lang.Compiler.Steps.MergePartialClasses} object {Boo.Lang.Compiler.Steps.MergePartialClasses}
+ [5] {Boo.Lang.Compiler.Steps.InitializeNameResolutionService} object {Boo.Lang.Compiler.Steps.InitializeNameResolutionService}
+ [6] {Boo.Lang.Compiler.Steps.IntroduceGlobalNamespaces} object {Boo.Lang.Compiler.Steps.IntroduceGlobalNamespaces}
+ [7] {Boo.Lang.Compiler.Steps.TransformCallableDefinitions} object {Boo.Lang.Compiler.Steps.TransformCallableDefinitions}
+ [8] {Boo.Lang.Compiler.Steps.BindTypeDefinitions} object {Boo.Lang.Compiler.Steps.BindTypeDefinitions}
+ [9] {Boo.Lang.Compiler.Steps.BindGenericParameters} object {Boo.Lang.Compiler.Steps.BindGenericParameters}
+ [10] {Boo.Lang.Compiler.Steps.BindNamespaces} object {Boo.Lang.Compiler.Steps.BindNamespaces}
+ [11] {Boo.Lang.Compiler.Steps.BindBaseTypes} object {Boo.Lang.Compiler.Steps.BindBaseTypes}
+ [12] {Boo.Lang.Compiler.Steps.BindAndApplyAttributes} object {Boo.Lang.Compiler.Steps.BindAndApplyAttributes}
+ [13] {Boo.Lang.Compiler.Steps.ExpandMacros} object {Boo.Lang.Compiler.Steps.ExpandMacros}
+ [14] {Boo.Lang.Compiler.Steps.IntroduceModuleClasses} object {Boo.Lang.Compiler.Steps.IntroduceModuleClasses}
+ [15] {Boo.Lang.Compiler.Steps.NormalizeStatementModifiers} object {Boo.Lang.Compiler.Steps.NormalizeStatementModifiers}
+ [16] {Boo.Lang.Compiler.Steps.NormalizeTypeAndMemberDefinitions} object {Boo.Lang.Compiler.Steps.NormalizeTypeAndMemberDefinitions}
+ [17] {Boo.Lang.Compiler.Steps.BindTypeDefinitions} object {Boo.Lang.Compiler.Steps.BindTypeDefinitions}
+ [18] {Boo.Lang.Compiler.Steps.BindGenericParameters} object {Boo.Lang.Compiler.Steps.BindGenericParameters}
+ [19] {Boo.Lang.Compiler.Steps.BindEnumMembers} object {Boo.Lang.Compiler.Steps.BindEnumMembers}
+ [20] {Boo.Lang.Compiler.Steps.BindBaseTypes} object {Boo.Lang.Compiler.Steps.BindBaseTypes}
+ [21] {Boo.Lang.Compiler.Steps.BindMethods} object {Boo.Lang.Compiler.Steps.BindMethods}
+ [22] {Boo.Lang.Compiler.Steps.ResolveTypeReferences} object {Boo.Lang.Compiler.Steps.ResolveTypeReferences}
+ [23] {Boo.Lang.Compiler.Steps.BindTypeMembers} object {Boo.Lang.Compiler.Steps.BindTypeMembers}
+ [24] {Boo.Lang.Compiler.Steps.ProcessInheritedAbstractMembers} object {Boo.Lang.Compiler.Steps.ProcessInheritedAbstractMembers}
+ [25] {Boo.Lang.Compiler.Steps.CheckMemberNames} object {Boo.Lang.Compiler.Steps.CheckMemberNames}
+ [26] {Boo.Lang.Compiler.Steps.ProcessMethodBodiesWithDuckTyping} object {Boo.Lang.Compiler.Steps.ProcessMethodBodiesWithDuckTyping}
+ [27] {Boo.Lang.Compiler.Steps.PreProcessExtensionMethods} object {Boo.Lang.Compiler.Steps.PreProcessExtensionMethods}
+ [28] {Boo.Lang.Compiler.Steps.UnfoldConstants} object {Boo.Lang.Compiler.Steps.UnfoldConstants}
+ [29] {Boo.Lang.Compiler.Steps.OptimizeIterationStatements} object {Boo.Lang.Compiler.Steps.OptimizeIterationStatements}
+ [30] {Boo.Lang.Compiler.Steps.BranchChecking} object {Boo.Lang.Compiler.Steps.BranchChecking}
+ [31] {Boo.Lang.Compiler.Steps.CheckIdentifiers} object {Boo.Lang.Compiler.Steps.CheckIdentifiers}
+ [32] {Boo.Lang.Compiler.Steps.StricterErrorChecking} object {Boo.Lang.Compiler.Steps.StricterErrorChecking}
+ [33] {Boo.Lang.Compiler.Steps.CheckAttributesUsage} object {Boo.Lang.Compiler.Steps.CheckAttributesUsage}
+ [34] {Boo.Lang.Compiler.Steps.ExpandDuckTypedExpressions} object {Boo.Lang.Compiler.Steps.ExpandDuckTypedExpressions}
+ [35] {Boo.Lang.Compiler.Steps.ProcessAssignmentsToValueTypeMembers} object {Boo.Lang.Compiler.Steps.ProcessAssignmentsToValueTypeMembers}
+ [36] {Boo.Lang.Compiler.Steps.ExpandProperties} object {Boo.Lang.Compiler.Steps.ExpandProperties}
+ [37] {Boo.Lang.Compiler.Steps.RemoveDeadCode} object {Boo.Lang.Compiler.Steps.RemoveDeadCode}
+ [38] {Boo.Lang.Compiler.Steps.CheckMembersProtectionLevel} object {Boo.Lang.Compiler.Steps.CheckMembersProtectionLevel}
+ [39] {Boo.Lang.Compiler.Steps.NormalizeIterationStatements} object {Boo.Lang.Compiler.Steps.NormalizeIterationStatements}
+ [40] {Boo.Lang.Compiler.Steps.ProcessSharedLocals} object {Boo.Lang.Compiler.Steps.ProcessSharedLocals}
+ [41] {Boo.Lang.Compiler.Steps.ProcessClosures} object {Boo.Lang.Compiler.Steps.ProcessClosures}
+ [42] {Boo.Lang.Compiler.Steps.ProcessGenerators} object {Boo.Lang.Compiler.Steps.ProcessGenerators}
+ [43] {Boo.Lang.Compiler.Steps.ExpandVarArgsMethodInvocations} object {Boo.Lang.Compiler.Steps.ExpandVarArgsMethodInvocations}
+ [44] {Boo.Lang.Compiler.Steps.InjectCallableConversions} object {Boo.Lang.Compiler.Steps.InjectCallableConversions}
+ [45] {Boo.Lang.Compiler.Steps.ImplementICallableOnCallableDefinitions} object {Boo.Lang.Compiler.Steps.ImplementICallableOnCallableDefinitions}
+ [46] {Boo.Lang.Compiler.Steps.CheckNeverUsedMembers} object {Boo.Lang.Compiler.Steps.CheckNeverUsedMembers}
+ [47] {Boo.Lang.Compiler.Steps.EmitAssembly} object {Boo.Lang.Compiler.Steps.EmitAssembly}
+ [48] {Boo.Lang.Compiler.Steps.SaveAssembly} object {Boo.Lang.Compiler.Steps.SaveAssembly}


第 0 步由 Boo.Lang.Compiler.Pipelines.Parse (src\Boo.Lang.Compiler\Pipelines\Parse.cs) 加入。
第 1~27 步由 Boo.Lang.Compiler.Pipelines.ResolveExpressions (src\Boo.Lang.Compiler\Pipelines\ResolveExpressions.cs) 加入。
第 28~46 步由 Boo.Lang.Compiler.Pipelines.Compile (src\Boo.Lang.Compiler\Pipelines\Compile.cs)加入。
第 47 步由 Boo.Lang.Compiler.Pipelines.CompileToMemory (src\Boo.Lang.Compiler\Pipelines\CompileToMemory.cs) 加入。
第 48 步由 Boo.Lang.Compiler.Pipelines.CompileToFile (src\Boo.Lang.Compiler\Pipelines\CompileToFile.cs)加入。

這些步驟都是利用繼承的關係建立起來的:CompileToFile -> CompileToMemory -> Compile -> ResolveExpressions -> Parse
只應用了繼承的威力...

星期五, 5月 16, 2008

[Boo]Boo(12)-函數

函數定義方法很簡單,比較特別的就是不定個數變數。


// Say
def Say( s as string):
print s

// 也是 Say
def Say( i as int):
print i

// 不定個數
def Say(*args as (object)):
print "len(args)=${len(args)}"
for arg in args:
print arg

// 求平方
def pow( i as int ) as int:
return i*i

Say( "Hello world!" )
Say( 20 )
Say( pow( 2 ) )
Say( 1, "s", join(range(10)) )

a = (5, 8, 1, "end")
Say(*a)


as string、as int...等,其實都可以省略不寫,別忘了 Boo 會自動判定。
然後有看到 Say() 定義了三次嗎?是的,Boo 支援多載(overloading)。
不定個數變數,定義的方法比較特別,要加上 *,然後用法就當作是 enumerator 來用就行了。