互動式 Lua |
|
Lua 其中一項好的特點是能以互動的方式使用此程式,就猶如和直譯器進行對話一般。同樣地,對話是學習人類語言的最佳方式,透過互動方式實際嘗試想法是很有幫助的。(或者,你只是想要在電腦上使用更好的計算器而已 ;))如果沒有指定腳本,或指定了 -i
選項,獨立的 lua 直譯器將進入互動模式。
然而,標準互動式命令提示有一些限制;如果你想要評量表達式,則必須在前面加上 '='。直譯器會將其轉譯為「return 」,以便始終輸入有效的區塊的 Lua 程式碼。此外,表格不會列印出來,除非其元資料表中有明確的 __tostring
$ lua Lua 5.1.2 Copyright (C) 1994-2007 Lua.org, PUC-Rio > = 10+20 30 > t = {10,20,30} > = t table: 003DB790
這有點尷尬,而且可能不是使用其他互動式語言的使用者預期的。使用 ilua 時,表達式不需要使用「=」,並且會以最佳的方式將表格列印出來。最後一個表達式的值始終可在變數 '_' 中取得。
$ lua ilua.lua ILUA: Lua 5.1.2 Copyright (C) 1994-2007 Lua.org, PUC-Rio "quit" to end > 10+20 30 > t = {10,20,30} > t {10,20,30} > _ {10,20,30} > m = {alice=1,john=2,betty=3} > m {betty=3,john=2,alice=1} > x+1 [string "local"]:1: variable 'x' is not declared > quit
請注意,變數必須在使用前宣告;ilua
以嚴格模式進行操作。任何變數的指派(包括 nil)都將宣告該變數。
事實上,10+20
並不是有效的 Lua 陳述式。我使用的是實驗性編譯技術 - 最初假設使用者輸入表達式,如果失敗,則嘗試編譯為陳述式。這顯示基本邏輯
function eval_lua(line) -- is it an expression? local err,chunk = compile('_pretty_print('..line..')') if err then -- otherwise, a statement? err,chunk = compile(line) end -- if compiled ok, then evaluate the chunk if not err then err = evaluate(chunk) end -- if there was any error, print it out if err then print(err) end end
我們可以透過全域變數 _pretty_print
精確控制值如何列印出來;其最重要的工作是展開表格。有必要注意一些失控狀況。表格可能過於龐大,或層次過於深入;可能會包含循環參照。ilua
會指定預設長度和深度來處理此狀況;函式 ilua.table_options
可用於變更最大長度和深度(預設分別為 20 和 7)。例如,ilua.table_options {limit=100}
會允許你列印較長的表格。它會偵測任何先前已列印或目前正在列印的表格。這些表格目前會顯示為 '{<self>}'。例如,對定義完善函式庫呼叫 require
會傳回此類型的表格,其中包含循環參照 _M
。
> require 'utils' {hex=function: 00487548,_PACKAGE='',printf=function: 003DD3F0,choose=function: 04878D8,import=function: 00487888,quit=function: 00486678,dump=function: 004875 0,_NAME='utils',timer=function: 00487638,_M={<self>},fprintf=function: 00485310 readf=function: 004878F8}
預設情況下,ilua
會在列印表格時嘗試表現得很聰明。我使用一個簡單的方案來判斷表格是類清單還是類地圖;有時它會出錯,因為並非所有表格都能歸類為其中之一。你可以使用 table_options
關閉這種聰明判斷。
> s = {1,2,bonzo='dog',felix='cat'} > s {1,2} > ilua.table_options {clever = false} > s {[1]=1,[2]=2,felix='cat',bonzo='dog'}
在處理任何選項或檔名之前,ilua
會試圖使用 require
載入「ilua-defs.lua」,因此可以放在套件路徑的任何地方。這是放置每次載入任何 Lua 程式碼的有用位置。
ilua
有幾個命令列旗標。-l
與 Lua 的相同選項很像;它會預載入指定的函式庫。-L
載入函式庫並將所有函式帶入全域名稱空間。
$ lua ilua.lua -Lmath ILUA: Lua 5.1.2 Copyright (C) 1994-2007 Lua.org, PUC-Rio "quit" to end > sin(1.2) 0.93203908596723
-L
可能會讓你很困擾,因此會提出警告,說明找到任何衝突
$ lua ilua.lua -Lutils -Ltest ILUA: Lua 5.1.2 Copyright (C) 1994-2007 Lua.org, PUC-Rio "quit" to end warning: test.printf overwrites utils.printf warning: test.unpack overwrites global unpack
-t
選項會將你的工作階段記錄檔記錄到一個記錄檔中。如果沒有指定檔,它會使用『ilua.log』。由於此選項需要一個變數,因此它必須是行中的最後一個選項
$ lua ilua.lua -t saving transcript "ilua.log" ILUA: Lua 5.1.2 Copyright (C) 1994-2007 Lua.org, PUC-Rio "quit" to end > 2.3*math(1.2) [string "local"]:1: attempt to call global 'math' (a table value) > 2.3*math.sin(1.2) 2.1436898977246 > quit $ cat ilua.log ! ilua -t > 2.3*math(1.2) [string "local"]:1: attempt to call global 'math' (a table value) > 2.3*math.sin(1.2) 2.1436898977246
取得記錄檔的另一個方法是 -T
,它會自動產生名稱為 ilua_yyyy_mm_dd_HH_MM.log
的記錄檔。
將表格匯入全域名稱空間通常對於測試很有用,因此可以使用 ilua.import
。例如,ilua.import(require 'lfs')
會匯入 lfs
函式庫,並讓所有函式都變為全域函式。
有時控制浮點輸出的小數點位數會很有用。ilua.precision
讓你設定數字的寬度和精度(如果你不太在乎,可以使用寬度 0)。『整數』的處理方式稍有不同。要重設為一般表示法,請直接呼叫 ilua.precision
,不要提供任何引數。
> t = {sin(1),sin(1.5),sin(5.2)} > t {0.8414709848079,0.99749498660405,-0.88345465572015} > ilua.precision(0,2) > t {0.84,1.00,-0.88} > {10,20,30} {10,20,30} > ilua.precision() > t {0.8414709848079,0.99749498660405,-0.88345465572015}
有時改變 ilua
列印特定類型的資料方式會很有用。ilua.print_handler
可用來設定特定類型的處理程式
> ilua.print_handler('function',function(f) return 'fun' end) > math.sin fun > math {log=fun,max=fun,acos=fun,huge=1.#INF,ldexp=fun,pi=3.1415926535898,cos=fun,tanh=fun, pow=fun,deg=fun,tan=fun,cosh=fun,sinh=fun,random=fun,randomseed=fun,frexp=fun, ceil=fun,floor=fun,rad=fun,abs=fun,sqrt=fun ... }
如前所述,ilua
以嚴格模式執行。不過,你可以指定一個在找不到變數時會呼叫的處理程式。這個範例讓作業系統環境變數可用,就像它們是唯讀 Lua 變數一樣
> ilua.global_handler(function(s) return os.getenv(s) end) > COMSPEC 'C:\WINDOWS\system32\cmd.exe' > WINDIR 'C:\WINDOWS' > s [string "local"]:1: variable 's' is not declared
最後一個自訂功能可以讓你的程式碼看到使用者輸入的每一行。例如,你可以將它放到「ilua-defs.lua」檔案中
ilua.line_handler(function (line) if line:sub(1,1) == '.' then -- a shell command! os.execute(line:sub(2)) return nil else return line end end)
現在,如果你鍵入像「. ls」或「. dir」的行,它會將該行的其餘部分當成作業系統命令!如果你傳回字串,ilua
會繼續處理,所以你也有機會以某種方式濾掉該字串。
與一般的 lua
不同,你無法在 ilua
中輸入多行陳述式
> for i=1,5 do print(i) end 1 2 3 4 5 > for i=1,10 do [string "local"]:1: 'end' expected near '<eof>'
實務上這通常不是問題,因為你可以在任何階段使用 dofile(filename)
匯入程式碼。如果需要的話,要解決這個問題並不困難。
將 ilua
與 PlutoLibrary 整合起來,以實現真正的「工作空間」持續性,會很有趣。這是部份語言系統提供的一種非常有生產力的模式,你可以將工作階段狀態連同函式和資料儲存起來,稍後再重新載入。
ilua.lua
可在 檔案:wiki_insecure/users/steved/ilua.lua 取得。使用 LuaInterface 的 ilua (lconsole) 的互動式 GUI 版本可在這裡取得
它有一個有用的簡短程式碼窗格,您可以在其中定義多行功能,並自動儲存它們。