3atv精品不卡视频,97人人超碰国产精品最新,中文字幕av一区二区三区人妻少妇,久久久精品波多野结衣,日韩一区二区三区精品

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【转贴】Lua 5.0 参考手册

發布時間:2025/3/19 编程问答 11 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【转贴】Lua 5.0 参考手册 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

作者: Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes

Copyright ? 2003 Tecgraf, PUC-Rio. All rights reserved.

譯者:ShiningRay Nicholas @ NirvanaStudio

給予支持

1 - 緒論

Lua是一種為支持有數據描述機制的一般過程式編程語言而設計的擴展編程語言。它同樣可以對面向對象語言、函數式程序設計(Functional Programming,如Lisp)以及數據驅動編程(data-driven programming)提供很好的支持。它的目標是被用作一種強大的、輕型的配置語言。Lua目前已經被實現為一個擴展庫,是用clean C (ANSI C/C++的一個通用子集)編寫的。

作為一個擴展語言,Lua沒有"Main"函數的概念:它僅僅是嵌入一個宿主程序進行工作,可以稱之為 嵌入式編程 或者簡單的說是 宿主編程。這個宿主程序可以調用函數來執行Lua的代碼片斷,可以設置和讀取Lua的變量,可以注冊C函數讓Lua代碼調用。Lua的能力可以擴展到更大范圍,在不同的領域內,這樣就在同樣的語法框架下創建了你自定義的編程語言。

Lua的發行版包括一個獨立的嵌入式程序,lua,他使用Lua的擴展庫來提供一個完全的Lua解釋器。

Lua是自由軟件,通常不提供任何擔保,如它的版權說明中敘述的那樣。 手冊中描述的實現在Lua的官方網站可以找到,www.lua.org。

如果需要知道Lua設計背后的一些決定和討論,可以參考以下論文,它們都可以在Lua的網站上找到。

  • R.?Ierusalimschy, L.?H.?de Figueiredo, and W.?Celes. Lua---an extensible extension language. Software: Practice & Experience26 #6 (1996) 635-652.
  • L.?H.?de Figueiredo, R.?Ierusalimschy, and W.?Celes. The design and implementation of a language for extending applications. Proceedings of XXI Brazilian Seminar on Software and Hardware (1994) 273-283.
  • L.?H.?de Figueiredo, R.?Ierusalimschy, and W.?Celes. Lua: an extensible embedded language. Dr. Dobb's Journal21 #12 (Dec 1996) 26-33.
  • R.?Ierusalimschy, L.?H.?de Figueiredo, and W.?Celes. The evolution of an extension language: a history of Lua, Proceedings of V Brazilian Symposium on Programming Languages (2001) B-14-B-28.

Lua在葡萄牙語中的意思是“月亮”,發音是 LOO-ah。

2 - 語言

這一章將描述Lua的詞法、語法和語義結構。換句話說,這一章會講什么標記是合法的,他們是如何組合的,以及他們的組合是什么含義。

語言結構會使用常用的擴展BNF范式來解釋,如{a}?表示0或多個a, [a]?表示a是可選的(0個或1個)。非終端字體(不能顯示的)用 斜體表示,關鍵字是粗體,其他終端符號用typewriter(等寬)字體,并用單引號引出。

2.1 - 詞法約定

Lua中的標識符(Identifiers)可以是任意的數字、字符和下劃線“_”,但不能以數字開頭。這條規則符合大多數編程語言中的標識符的定義。(字符的具體定義要根據系統的地區設置:任何區域設置可以認同的字母表中的字母都可以用在標識符中。)

下面的關鍵字(keywords)為保留關鍵字不可以作為標識符出現:

and break do else elseifend false for function ifin local nil not orrepeat return then true until while

Lua對大小寫敏感:and是一個保留字,但是 And 和 AND 是兩個不一樣的、但都合法的標識符。習慣上來說,以下劃線開始且后面跟著大寫字母的標識符 (例如 _VERSION) 是為Lua內部變量所保留的。

下面的字符(串)是其他的一些標記:

+ - * / ^ =~= <= >= < > ==( ) { } [ ]; : , . .. ...

字符串(Literal strings) 以單引號或者雙引號定界,同時可以包含以下C語言風格的轉義字符:

  • \a --- 鈴聲(bell)
  • \b --- 回退(backspace)
  • \f --- form feed
  • \n --- 新行(newline)
  • \r --- 回車(carriage return)
  • \t --- 水平制表符(horizontal tab)
  • \v --- 垂直制表符(vertical tab)
  • \\ --- 反斜杠(backslash)
  • \" --- 雙引號(quotation mark)
  • \' --- 單引號(apostrophe)
  • \[ --- 左方括號(left square bracket)
  • \] --- 右方括號(right square bracket)

另外,一個 `\newline′ (一個反斜杠加上一個真正的換行符)會導致字符串內的分行。字符串中的字符也可以使用轉義字符`\ddd′通過數字值來指定。ddd 是最多為3個十進制數字的序列。Lua中的字符串也可以包含8進制數字,包括嵌入零,它可以表示為 `\0′。

字符串也可以用雙方括號來定界[[ · · · ]]。這種括號方式的語法,字符串可以跨越多行,也可以包含嵌套的,同時不會轉義任何序列。方便起見,當開始的 `[[′ 后面緊跟著一個換行符的話,這個換行符不會包括在字符串內。舉個例子:在一個使用ASCII編碼(其中`a′ 的編碼是?97,換行符是?10,字符`1′ 是?49)的系統中,以下四種格式得到的都是同一個字符串:

(1) "alo\n123\""(2) '\97lo\10\04923"'(3) [[alo123"]](4) [[alo123"]]

數值常量(Numerical constants) 可以有一個可選的底數部分和一個可選的指數部分。以下是有效的數值常量:

3 3.0 3.1416 314.16e-2 0.31416E1

注釋(Comments) 可以在任何地方出現,必須在最前面加上雙減號 (--)。如果緊接著 -- 的文本不是 [[,那么會認為是一個 短注釋(short comment), 這一行往后到行尾都是注釋。否則,會認為是一個 常注釋(long comment),注釋直到相應的 ]]結束。長注釋可以跨越多行,同時可以包含嵌套的 [[ · · · ]] 括號對。

為了方便起見,文件的第一行如果是以#開始,這個機制允許Lua在Unix系統中用做一個腳本解釋器(見 6)。

2.2 - 值和類型

Lua是一種 動態類型語言(dynamically typed language)。這意味著變量是沒有類型的;只有值才有。語言中沒有類型定義。所有的值都包含他自身的類型。

Lua中有八種基本類型:nil, boolean, number, string, function, userdata, thread 和 table。 Nil 空類型只對應 nil值,他的屬性和其他任何值都有區別;通常它代表沒有有效的值。 Boolean 布爾類型有兩種不同的值 false and true。在Lua中, nil and false 代表成假條件;其他任何值都代表成真條件。 Number 數字類型表示實數(雙精度浮點數)。(構建Lua解釋器時也可以很容易地用其他內部的表示方式表示數字,如單精度浮點數或者長整型)。 String 字符串類型表示一個字符的序列。Lua 字符串可以包含8位字符,包括嵌入的 ('\0') (見 2.1)。

函數是Lua中的 第一類值(first-class values)。也就是說函數可以保存在變量中,當作參數傳遞給其他函數,或者被當作結果返回。Lua可以調用(和處理)Lua寫的函數和C寫的函數 (見 2.5.7)。

用戶數據類型(userdata) 提供了讓任意C數據儲存在Lua變量中的功能。這種類型直接對應著一塊內存,Lua中也沒有任何預先定義的操作,除了賦值和一致性比較。然而,通過使用 元表(metatables),程序員可以定義處理userdata的操作。(見 2.8)。 Userdata 值不能在Lua中建立或者修改,只能通過 C?API。這保證了宿主程序的數據完整性。

線程(thread) 類型代表了相互獨立的執行線程,用來實現同步程序。

表(table) 類型實現了聯合數組,也就是說,數組不僅可以使用數字,還能使用其他的值(除了 nil)。 而且,tables 可以是 互異的(heterogeneous),他們可以保存任何類型的值(除了 nil)。 Tables 是Lua中唯一的數據結構機制;他們可以用來表示一般數組,特征表,集合,記錄,圖,樹等等。如果要表示記錄,Lua使用字段名作為索引。語言支持 a.name 這種比較優美的表示方式,還有 a["name"]。在Lua中有幾種建立表的簡便方法 (見 2.5.6)。

就像索引一樣,表字段的值也可以是任何類型(除了 nil)。特別需要注意地是,由于函數是第一型的值,表字段也可以包含函數。這樣表也可以支持 方法(methods) (見 2.5.8)。

表,函數,和用戶數據類型的值都是 對象(objects):變量不會包含他們的實際值,只是一個他們的引用(references)。 賦值,參數傳遞和函數返回只是操作這些值的引用,這些操作不會暗含任何拷貝。

庫函數 type 返回一個字符串描述給出值所表示的類型 (見 5.1)。

2.2.1 - 類型轉換

Lua提供運行時的數字和字符串值得自動轉換。任何對字符串的算術操作都會現嘗試把字符串轉換成數字,使用一般規則轉換。反過來,當一個數值用在需要字符串的地方時,數字會自動轉換成字符串,遵循一種合理的格式。如果要指定數值如何轉換成字符串,請使用字符串庫中的 format 函數(見 5.3)。

2.3 - 變量

變量是儲存值的地方。Lua中有三種不同的變量:全局變量,局部變量和表字段。

一個名稱可以表示全局變量或局部變量(或者一個函數的正式參數,一種局部變量的特殊形式):

var ::= Name

Lua假設變量是全局變量,除非明確地用local進行聲明 (見 2.4.7)。局部變量有 詞義范圍(lexically scoped):局部變量可以被在它們范圍內的函數自由訪問 (見 2.6)。

在變量第一次賦值之前,它的值是 nil

方括號用于對表進行檢索:

var ::= prefixexp `[′ exp `]

第一個表達式 (prefixexp)結果必須是表;第二個表達式 (exp) 識別表中一個特定條目。給出表的表達式有一個限制語法;詳細見 2.5。

var.NAME 語法是 var["NAME"] 的較好形式:

var ::= prefixexp `.′ Name

訪問全局變量和表字段的實質可以通過元表進行改變。對索引變量 t[i] 的訪問等同于調用 gettable_event(t,i)。(關于 gettable_event 的完整描述見 2.8。這個函數并沒有在Lua中定義,也無法調用。我們在這里僅僅用來解釋原理)。

所有的全局變量存在一個普?ǖ腖ua表中,稱之為 環境變量表(environment tables) 或簡稱 環境(environments)。由C寫的并導入到Lua中的函數 (C 函數) 全部共享一個通用 全局環境(global environment)。Lua寫的每個函數 (a Lua 函數) 都有一個它自己的環境的引用,這樣這個函數中的所有的全局變量都會指向這個環境變量表。當新創建一個函數時,它會繼承創建它的函數的環境。要改變或者獲得Lua函數的環境表,可以調用 setfenv or getfenv (見 5.1)。

訪問全局變量 x 等同于 _env.x,又等同于

gettable_event(_env, "x")

_env 是運行的函數的環境。(_env 變量并沒有在Lua中定義。我們這里僅僅用來解釋原理)

2.4 - 語句

Lua支持一種很通俗的語句集,和Pascal或者C中的很相似。他包括賦值,控制結構,過程調用,表構造和變量聲明。

2.4.1 - 語句段

Lua執行的最小單元稱之為一個 段(chunk)。一段語句就是簡單的語句的序列,以順序執行。每一個語句后面都可以加上一個分號(可選):

chunk ::= {stat [`;′]}

Lua將語句段作為一個匿名函數 (見 2.5.8) 的本體進行處理。這樣,語句段可以定義局部變量或者返回值。

一段語句可以儲存在文件內或者宿主程序的一個字符串中。當語句段被執行時,他首先被預編譯成虛擬機使用的字節碼,然后虛擬機用一個解釋器執行被編譯的代碼。

語句段也可以被預編譯為二進制代碼;詳情參看 luac 程序。源代碼和編譯形態可以互相轉換;Lua自動監測文件類型然后作相應操作。

2.4.2 - 語句塊

一個語句塊是一系列語句;從語句構成上來看,語句塊等同于語句段:

block ::= chunk

一個語句塊可以明確定界來替換單個語句:

stat ::= do block end

顯式語句塊可以很好地控制變量的聲明范圍。顯示語句塊有時也常會在另一個語句塊的中間添加 returnbreak 語句 (見 2.4.4)。

2.4.3 - 賦值

Lua允許多重賦值。因此,賦值的語法定義為:等號左邊是一個變量表,右邊是一個表達式表。兩邊的表中的元素都用逗號分隔開來:

stat ::= varlist1 `=′ explist1varlist1 ::= var {`,′ var}explist1 ::= exp {`,′ exp}

我們將在 2.5 討論表達式。

在賦值之前,值的表長度會被 調整 為和變量的表一樣。如果值比需要的多,多出的值就會被扔掉。如果值的數量不夠,就會用足夠多的 nil 來填充表直到滿足數量要求。如果表達式表以一個函數調用結束,那么在賦值之前,函數返回的所有的值都會添加到值的表中(除非把函數調用放在括號里面;見 2.5)。

賦值語句首先計算出所有的表達式,然后才會執行賦值,所以代碼:

i = 3i, a[i] = i+1, 20

設置 a[3] 為 20,但不影響 a[4]。因為在 a[i] 中的 i 在賦值為4之前是等于3。同樣的,下面這行:

x, y = y, x

可以交換 x 和 y 的值。

對全局變量和表字段的賦值可以看作是通過元表進行的。對一個索引變量的賦值 t[i] = val 等同于 settable_event(t,i,val)。 (settable_event詳細介紹參看 2.8 ,Lua中并未定義該函數,他也無法直接調用。我們這里只是用它來進行解釋。)

對全局變量的賦值 x = val 等同于賦值語句 _env.x = val,像前面也等同于:

settable_event(_env, "x", val)

_env 是運行函數的環境。(_env 變量并未在Lua中定義。我們這里只是用來進行解釋。)

2.4.4 - 控制結構

控制結構 if, whilerepeat 具有通用的含義和類似的語法:

stat ::= while exp do block endstat ::= repeat block until expstat ::= if exp then block {elseif exp then block} [else block] end

Lua也有 for 語句,有兩種格式 (見 2.4.5)。

控制結構的條件表達式 exp 可以返回任意值。falsenil 都表示假。所有其他的值都認為是真(特別要說明的:數字0和空字符串也表示真)。

語句 return 用來從函數或者是語句段中返回一個值。函數和語句段都可以返回多個值,所以 return 語句的語法為:

stat ::= return [explist1]

break 語句可以用來終止while, repeat 或者 for 循環的執行,直接跳到循環后面的語句。

stat ::= break

break 結束最里面的一個循環。

由于語法的原因, returnbreak 語句只能作為語句塊的 最后一個 語句。如果確實需要在語句塊的中間使用 return 或者 break,需要使用一個顯示語句塊: `do return end′ 和 `do break end′,這樣現在 returnbreak 就成為他們(內部)語句塊中的最后一個語句了。實際上,這兩種用法一般只用在調試中。

2.4.5 - For 語句

for 語句有兩種形式:數值形式和一般形式。

數值形式的 for 循環根據一個控制變量用算術過程重復一語句塊。語法如下:

stat ::= for Name `=′ exp `,′ exp [`,′ exp] do block end

block 語句塊根據 name 以第一個 exp 的值開始,直到他以第三個 exp 為步長達到了第二個 exp。一個這樣的 for 語句:

for var = e1, e2, e3 do block end

等價于一下代碼:

dolocal var, _limit, _step = tonumber(e1), tonumber(e2), tonumber(e3)if not (var and _limit and _step) then error() endwhile (_step>0 and var<=_limit) or (_step<=0 and var>=_limit) doblockvar = var + _stependend

注意:

  • 三種控制表達式只會被計算一次,在循環開始之前。他們的結果必須是數值。
  • _limit 和 _step 是不可見的變量。這里只是為了進行解釋。
  • 如果你在程序塊內給 var 賦值,結果行為將會不確定。
  • 如果沒有給出第三個表達式(步長),那么默認為1。
  • 你可以使用 break 來退出 for 循環。
  • 循環變量 var 是局部變量;你不可以在 for 循環結束之后繼續使用。如果你需要使用這個值,請在退出循環之前把它們傳給其他變量。

for 的語句的一般形式是操作于函數之上的,稱之為迭代器(iterators)。每一個迭代過程,它調用迭代函數來產生新的值,直到新的值是 nil 。一般形式 for 循環有如下語法:

stat ::= for Name {`,′ Name} in explist1 do block end

一個這樣的 for 語句

for var_1, ..., var_n in explist do block end

等同于以下代碼:

dolocal _f, _s, var_1 = explistlocal var_2, ... , var_nwhile true dovar_1, ..., var_n = _f(_s, var_1)if var_1 == nil then break endblockendend

注意:

  • explist 只會計算一次。他的結果是一個 迭代 函數,一個 狀態,和給第一個 迭代變量的一個初始值。
  • _f 和 _s 是不可見的變量。這里只是用來進行解釋說明。
  • 如果你在語句塊中給 var_1 賦值,那么行為就會變得不確定。
  • 你可以使用 break 來退出 for 循環。
  • 循環變量 var_i 是局部變量;你不可以在 for 循環結束之后繼續使用。如果你需要使用這個值,請在退出循環之前把它們傳給其他變量。

2.4.6 - 語句式函數調用

如果要忽略可能的影響,函數調用可以按照語句執行:

stat ::= functioncall

I在這里,所有的返回值都會被忽略。函數調用將在 2.5.7 詳細解釋。

2.4.7 - 局部變量聲明

局部變量可以在語句塊中任何地方聲明。聲明時也可以添加一個初始賦值:

stat ::= local namelist [`=′ explist1]namelist ::= Name {`,′ Name}

如果出現初始賦值,他的語法和多重賦值語句一樣(見 2.4.3)。否則,所有的變量都會初始化為 nil

一個語句段也是一個語句塊(見 2.4.1),所以語句段之內的任何顯式語句塊之外也可以聲明局部變量。這種局部變量在語句段結束就會銷毀。

局部變量的可見規則會在 2.6解釋。

2.5 - 表達式

Lua中有以下幾種基本表達式:

exp ::= prefixexpexp ::= nil | false | trueexp ::= Numberexp ::= Literalexp ::= functionexp ::= tableconstructorprefixexp ::= var | functioncall | `(′ exp `)

數字和字符串已經在 2.1 中解釋;變量在 2.3 中解釋;函數定義在 2.5.8;函數調用在 2.5.7;表構造器在 2.5.6。

一個用括號括起的表達式只會返回一個值。這樣,(f(x,y,z)) 將只會返回單一的一個值,即使 f 可以返回多個值,((f(x,y,z)) 的值將是 f 返回的第一個值或者如果 f 沒有返回任何值就是 nil )。

表達式也可以使用各種算術運算符,關系運算符和邏輯運算符,下面幾節就會講到。

2.5.1 - 算術運算符

Lua支持常見的幾種運算符:二元 + (加), - (減), * (乘), / (除), 以及 ^ (指數運算); 一元 - (負號)。如果操作數是數字,或者是可以轉換成數字的字符串(見 2.2.1),那么所有的操作都和算術意義上的運算一致(除了指數)。指數運算其實是調用一個全局函數 __pow,否則一個合適的元方法將會被調用(見 2.8)。標準數學庫定義了函數 __pow,給出了指數運算的定義(見 5.5)。

2.5.2 - 關系運算符

Lua中的關系運算符有

== ~= < > <= >=

這些運算只會產生 falsetrue值。

等于 (==) 先比較操作數的類型。如果類型不一樣,結果便是 false。否則,再比較操作數的值。對象(表,用戶數據,線程,和函數)是按照引用進行比較:只有兩個對象是同一個對象的時候,才認為是相等。每次你創建一個新的對象(表,用戶數據,或者是函數)。這個新的對象將不同于前面存在的任何對象。

你可以用"eq"元方法改變Lua比較表的方式(見 2.8)。

2.2.1 的轉換規則 不適用 于相等比較。這樣," "0"==0 結果是 false ,同樣 t[0] 和 t["0"] 給出的是表中不同的字段。

而操作符 ~= 是等于 (==) 的相反的操作。

T操作符的執行順序如下。如果兩個參數都是數字,那么它們就直接進行比較。如果,兩個參數都是字符串,那么它們的值會根據當前的區域設置進行比較。否則,Lua嘗試調用"lt"或者 "le" 元方法(見 2.8)。

2.5.3 - 邏輯運算符

Lua中的邏輯運算符是:

and or not

和控制結構一樣(見 2.4.4),所有的邏輯操作符認為 falsenil 都?羌伲淥鬧刀際欽妗?

not 操作符總是返回 falsetrue

合取運算 and 如果第一個參數是 false 或者 nil 則返回第一個參數;否則 and 返回第二個參數。析取運算 or 如果第一個參數不是 nilfalse 則返回第一個參數,否則 or 返回第二個參數。 andor 都使用截取計算,也就是,只有有必要的情況下才計算第二個參數。例如:

10 or error() -> 10nil or "a" -> "a"nil and 10 -> nilfalse and error() -> falsefalse and nil -> falsefalse or nil -> nil10 and 20 -> 20

2.5.4 - 串聯接

在Lua中字符串連接操作符是兩個點 (`..′)。如果兩邊的操作數都是字符或者數字,他們就都會按照 2.2.1的規則被轉換成字符串。否則,將調用 "concat" 元方法(見 2.8)。

2.5.5 - 優先級

Lua中的操作符的優先級如下表所示,從低到高優先級:

orand< > <= >= ~= ==..+ -* /not - (unary)^

表達式中,你可以使用括號來改變優先順序。串聯接符 (`..′) 和指數符 (`^′) 都是右結合的。其他二元操作都是左結合的。

2.5.6 - 表構造器

表構造器是創建表的表達式。當計算構造器的時候,就會創建一個新的表。構造器可以用來創建空的表,或者創建表并初始化一些字段。一般的語法如下:

tableconstructor ::= `{′ [fieldlist] `}′fieldlist ::= field {fieldsep field} [fieldsep]field ::= `[′ exp `]′ `=′ exp | Name `=′ exp | expfieldsep ::= `,′ | `;

[exp1] = exp2 形式的每一個添加到新表中的字段條目以 exp1 為鍵并以 exp2 為值。name = exp 形式的字段,等同于 ["name"] = exp。最后,exp 形式的字段等同于 [i] = exp 其中 i 是連續的整數,從1開始。其它格式的字段不會影響它的計數。例如:

a = {[f(1)] = g; "x", "y"; x = 1, f(x), [30] = 23; 45}

等同于:

dolocal temp = {}temp[f(1)] = gtemp[1] = "x" -- 1st exptemp[2] = "y" -- 2nd exptemp.x = 1 -- temp["x"] = 1temp[3] = f(x) -- 3rd exptemp[30] = 23temp[4] = 45 -- 4th expa = tempend

如果列表中最后一個字段的形式是 exp 同時表達式又是一個函數調用,那么調用返回的所有值會依次進入列表(見 2.5.7)。如果要避免這種情況,在函數調用兩邊加上括號(見 2.5)。

字段列表可以有一個結尾的分隔符,這個對由機器生成的列表十分方便。

2.5.7 - 函數調用

Lua中的一個函數調用有如下語法:

functioncall ::= prefixexp args

在函數調用中,首先會計算 prefixexp 和 args 。如果 prefixexp 的值是 function 類型,那么那個函數就會被調用,同時使用給出的參數。否則,他的 "call" 元方法就會被調用,第一個參數是 prefixexp 的值,接下來是原來的調用參數(見 2.8)。

形式

functioncall ::= prefixexp `:′ Name args

可以用來調用“方法”("methods")。調用 v:name(...) 語法上比 v.name(v,...),要好一些,除非表達式 v 只計算一次。

參數可以有以下幾種語法:

args ::= `(′ [explist1] `)′args ::= tableconstructorargs ::= Literal

所有的參數表達式都會在實際調用之前進行計算。f{...} 的調用形式在語法上較 f({...}) 要好,是因為,參數列表示一個單獨的新表。 f'...' (或者 f"..." 或者 f[[...]]) 較 f('...') 要好,是因為參數列表是一個單獨的字符串。

因為函數可以返回任意個結果(見 2.4.4),結果的數量必須在使用它們前進行調整。如果函數按照語句進行調用(見 2.4.6),那么它的返回列表就會被調整為零個元素,這樣就舍棄了所有的返回值。如果調用函數時,他是一個表達式列表的最后一個元素,那么不會做調整(除非調用時加了括號)。

以下是一些例子:

f() -- 調整為0個結果g(f(), x) -- f() 被調整成1個結果g(x, f()) -- g 獲得 x 加上f()返回的所有值a,b,c = f(), x -- f() 被調整成1個結果(此時c獲得nil值)a,b,c = x, f() -- f() 被調整為兩個結果a,b,c = f() -- f() 被調整為3個結果return f() -- 返回所有 f() 返回的值return x,y,f() -- 建立一個表包含所有 f() 返回的值{f()} -- creates a list with all values returned by f(){f(), nil} -- f() 被調整為一個結果

如果你用括號括起調用的函數,那么它就會被調整為返回一個值。

return x,y,(f()) -- returns x, y, and the first value from f(){(f())} -- creates a table with exactly one element

作為Lua語法自由格式的一個例外,你不能在函數調用的 `(′ 前面加入一個換行。這個限制可以避免語言中的一些二義性。如果你寫:

a = f(g).x(a)

Lua會讀作 a = f(g).x(a)。這樣,如果你想執行為兩條語句,你必須在中間加分號。如果你實際上想調用 f,你就必須刪除 (g) 前面的換行。

return functioncall 的調用格式稱之為 尾部調用(tail call)。Lua實現了proper tail calls;在一個尾部調用中,被調用的函數將會重新使用調用程序的棧。因此,程序執行對嵌套尾部調用的次數沒有任何限制。然而,尾部調用會清楚調用函數的調試信息。注意尾部調用只有在特殊的語法中才能出現,也就是 return 只有一個函數調用作為參數,這種語法保證了調用函數確切返回被調用函數的返回值。所以,下面的例子都不是尾部調用:

return (f(x)) -- results adjusted to 1return 2 * f(x)return x, f(x) -- additional resultsf(x); return -- results discardedreturn x or f(x) -- results adjusted to 1

2.5.8 - 函數定義

函數定義的語法是:

function ::= function funcbodyfuncbody ::= `(′ [parlist1] `)′ block end

下面較好的語法簡化了函數定義:

stat ::= function funcname funcbodystat ::= localfunction Name funcbodyfuncname ::= Name {`.′ Name} [`:′ Name]

語句

function f () ... end

會被翻譯為

f = function () ... end

語句

function t.a.b.c.f () ... end

會被翻譯為

t.a.b.c.f = function () ... end

語句

local function f () ... end

會被翻譯為

local f; f = function () ... end

一個函數定義是一個可執行的表達式,他的類型為 函數(function) 。當Lua預編譯語句段的時候,他的函數體也會被預編譯。這樣,當Lua執行函數定義的時候,函數被 實例化 (封裝 closed)。這個函數實例(或閉包 closure)是表達式的最終結果。同一個函數的不同的實例可以引用不同的外部局部變量也可以有不同的環境表。

形式參數(代表參數的變量,簡稱形參)就像用實際參數值(簡稱實參)初始化的局部變量一樣。

parlist1 ::= namelist [`,′ `...′]parlist1 ::= `...

當調用一個函數時,實參表會調整為和形參一樣的長度,除非函數是 variadic 或者 變長參數函數(vararg function)。變長參數函數在其參數列表最后有三個點 (`...′)。 變長參數函數不會對參數列表進行調整;而是,它把所有的額外實參放到一個隱含的形參 arg中。 arg 的值是一個表,包含一個字段?`n′ 表示額外參數的個數,位置 1,?2,?...,?n是額外的參數。

請思考以下函數定義的例子:

function f(a, b) endfunction g(a, b, ...) endfunction r() return 1,2,3 end

然后,我們有以下實參到形參的對應關系:

CALL PARAMETERSf(3) a=3, b=nilf(3, 4) a=3, b=4f(3, 4, 5) a=3, b=4f(r(), 10) a=1, b=10f(r()) a=1, b=2g(3) a=3, b=nil, arg={n=0}g(3, 4) a=3, b=4, arg={n=0}g(3, 4, 5, 8) a=3, b=4, arg={5, 8; n=2}g(5, r()) a=5, b=1, arg={2, 3; n=2}

結果使用 return 語句返回(見 2.4.4)。如果控制到達了函數尾部而沒有遇到 return 語句,那么函數沒有返回值。

冒號(:) 語法是用來定義 methods 的,也就是,函數有一個隱含的額外參數 self. 。這樣,語句:

function t.a.b.c:f (...) ... end

相對以下是較好的形式:

t.a.b.c.f = function (self, ...) ... end

2.6 - 可見性規則

Lua是一個有詞法范圍的語言。變量的范圍從聲明語句后的第一個語句開始到包含聲明的最內部的語句塊為止。例如:

x = 10 -- global variabledo -- new blocklocal x = x -- new `x', with value 10print(x) --> 10x = x+1do -- another blocklocal x = x+1 -- another `x'print(x) --> 12endprint(x) --> 11endprint(x) --> 10 (the global one)

注意:在類似 local x = x,正在聲明的新的 x 尚未進入范圍,所以第二個 x 指代的是外面的變量。

由于詞法范圍的規則,在局部變量的范圍內定義的函數可以任意訪問這些變量。例如:

local counter = 0function inc (x)counter = counter + xreturn counterend

內部函數使用的局部變量在函數內部稱之為 上值(upvalue),或者 外局部變量(external local variable)。

注意每個 local 語句執行時會定義一個新的局部變量。看以下例子:

a = {}local x = 20for i=1,10 dolocal y = 0a[i] = function () y=y+1; return x+y endend

循環產生了十個閉包(也就是,十個匿名函數的實例)。每個閉包使用不同的 y 變量,但他們共享同一個 x 變量。

2.7 - 錯誤處理

因為Lua是一個擴展語言,所有的Lua動作都是從宿主程序中調用Lua庫中函數的C代碼開始的(見 3.15)。無論錯誤發生在Lua編譯過程時或執行時,控制返回C,然后可以做相應的處理(比如打印一個錯誤)。

Lua代碼可以通過調用error函數來產生一個錯誤(見 5.1)。如果你要在Lua中捕獲錯誤,你可以使用 pcall 函數(見 5.1)。

2.8 - 元表 (Metatables)

Lua中的每一個表和用戶數據都可以擁有一個 元表(metatable)。這個 元表 是一個普通的Lua表,定義了在特定操作下原始表和用戶數據的行為。你可以通過設置一個對象的元表中的特定字段來更改它某些方面的行為。例如,當一個對象是一個加法的操作數時,Lua檢查它的元表中的 "__add" 字段是不是一個函數。如果是,Lua調用它來執行加法。

我們稱元表中的鍵(字段名,key)為 事件(events) ,值為 元方法(metamethods)。在上一個例子中, "add" 是事件,執行加法的函數是元方法。

你可以通過 set/getmetatable 函數來查詢和更改一個對象的元表(見 5.1)。

元表可以控制對象在算術操作、比較、串連接、索引取值中如何運行。元表也可以定義一個函數當收集內存垃圾時調用。每一個操作這里Lua都用一個特定的鍵關聯,稱之為事件。當Lua對一個表或是一個用戶數據執行上面中的一個操作時,它先檢查元表控制的操作已經羅列在下面。每個操作有一個相應的名稱,代表了他的含義。他們在元表中的鍵是由名稱前加上兩條下劃線;如,操作 "add" 的鍵是 "__add"。這些操作的語義

這里給出的Lua代碼僅僅是說明性的;真正的行為是硬編碼在解釋器中的,比下面的的模擬的效率要高很多。描述中用到的函數 (rawget, tonumber, 等等) 在 5.1 中會對他們進行描述。特別地,要獲得一個給定對象的元方法,我們使用這個表達式:

metatable(obj)[event]

這個要讀作:

rawget(metatable(obj) or {}, event)

也就是,訪問元方法時不會調用其它元方法,同時調用沒有元表的對象不會出錯(它返回一個 nil值)。

  • "add": + 加法操作。

    下面的 getbinhandler 函數定義了Lua如何給一個二元操作選擇一個處理器。首先,Lua嘗試第一個操作數。如果它的類型沒有定義這個操作的處理器,那么然后Lua嘗試第二個操作數。

    function getbinhandler (op1, op2, event)return metatable(op1)[event] or metatable(op2)[event]end

    利用該函數,op1 + op2 的行為方式可看作是

    function add_event (op1, op2)local o1, o2 = tonumber(op1), tonumber(op2)if o1 and o2 then -- both operands are numeric?return o1 + o2 -- `+' here is the primitive `add'else -- at least one of the operands is not numericlocal h = getbinhandler(op1, op2, "__add")if h then-- call the handler with both operandsreturn h(op1, op2)else -- no handler available: default behaviorerror("...")endendend
  • "sub": - 操作。行為方式類似 "add" 操作。
  • "mul": * 操作。行為方式類似 "add" 操作。
  • "div": / 操作。行為方式類似 "add" 操作。
  • "pow": ^ (指數) 操作

    function pow_event (op1, op2)local o1, o2 = tonumber(op1), tonumber(op2)if o1 and o2 then -- both operands are numeric?return __pow(o1, o2) -- call global `__pow'else -- at least one of the operands is not numericlocal h = getbinhandler(op1, op2, "__pow")if h then-- call the handler with both operandsreturn h(op1, op2)else -- no handler available: default behaviorerror("...")endendend
  • "unm": 一元取負 - 操作。

    function unm_event (op)local o = tonumber(op)if o then -- operand is numeric?return -o -- `-' here is the primitive `unm'else -- the operand is not numeric.-- Try to get a handler from the operandlocal h = metatable(op).__unmif h then-- call the handler with the operand and nilreturn h(op, nil)else -- no handler available: default behaviorerror("...")endendend
  • "concat": .. (串連接)操作。

    function concat_event (op1, op2)if (type(op1) == "string" or type(op1) == "number") and(type(op2) == "string" or type(op2) == "number") thenreturn op1 .. op2 -- primitive string concatenationelselocal h = getbinhandler(op1, op2, "__concat")if h thenreturn h(op1, op2)elseerror("...")endendend
  • "eq": == 操作。函數 getcomphandler 定義了Lua是如何為比較操作選擇一個元方法的。只有當參與比較的兩個對象屬于同一類型而且需要的元方法一樣時,才會選擇這個元方法。

    function getcomphandler (op1, op2, event)if type(op1) ~= type(op2) then return nil endlocal mm1 = metatable(op1)[event]local mm2 = metatable(op2)[event]if mm1 == mm2 then return mm1 else return nil endend

    事件如下定義:

    function eq_event (op1, op2)if type(op1) ~= type(op2) then -- different types?return false -- different objectsendif op1 == op2 then -- primitive equal?return true -- objects are equalend-- try metamethodlocal h = getcomphandler(op1, op2, "__eq")if h thenreturn h(op1, op2)elsereturn falseendend

    a ~= b is equivalent to not (a == b).

  • "lt": < 操作。

    function lt_event (op1, op2)if type(op1) == "number" and type(op2) == "number" thenreturn op1 < op2 -- numeric comparisonelseif type(op1) == "string" and type(op2) == "string" thenreturn op1 < op2 -- lexicographic comparisonelselocal h = getcomphandler(op1, op2, "__lt")if h thenreturn h(op1, op2)elseerror("...");endendend

    a > b is equivalent to b < a.

  • "le": <= 操作。

    function le_event (op1, op2)if type(op1) == "number" and type(op2) == "number" thenreturn op1 <= op2 -- numeric comparisonelseif type(op1) == "string" and type(op2) == "string" thenreturn op1 <= op2 -- lexicographic comparisonelselocal h = getcomphandler(op1, op2, "__le")if h thenreturn h(op1, op2)elseh = getcomphandler(op1, op2, "__lt")if h thenreturn not h(op2, op1)elseerror("...");endendendend

    a >= b is equivalent to b <= a. Note that, in the absence of a "le" metamethod, Lua tries the "lt", assuming that a <= b is equivalent to not (b < a).

  • "index": 通過索引訪問 table[key]。

    function gettable_event (table, key)local hif type(table) == "table" thenlocal v = rawget(table, key)if v ~= nil then return v endh = metatable(table).__indexif h == nil then return nil endelseh = metatable(table).__indexif h == nil thenerror("...");endendif type(h) == "function" thenreturn h(table, key) -- call the handlerelse return h[key] -- or repeat operation on itend
  • "newindex": 給表的索引賦值 table[key] = value。

    function settable_event (table, key, value)local hif type(table) == "table" thenlocal v = rawget(table, key)if v ~= nil then rawset(table, key, value); return endh = metatable(table).__newindexif h == nil then rawset(table, key, value); return endelseh = metatable(table).__newindexif h == nil thenerror("...");endendif type(h) == "function" thenreturn h(table, key,value) -- call the handlerelse h[key] = value -- or repeat operation on itend
  • "call": 當Lua調用某個值時調用。

    function function_event (func, ...)if type(func) == "function" thenreturn func(unpack(arg)) -- primitive callelselocal h = metatable(func).__callif h thenreturn h(func, unpack(arg))elseerror("...")endendend

2.9 - 垃圾收集

Lua 會自動進行內存管理。這意味著你不需要擔心新對象的內存分配問題,也不需要釋放不用的對象。Lua 通過不斷地運行 垃圾收集器 收集 dead objects (也就是那些Lua中無法訪問的對象)來自動管理內存。Lua中所有的對象都是自動管理的目標:表,用戶數據,函數,線程,和字符串。Lua使用兩個數字控制垃圾收集循環。一個數字表示Lua使用的動態內存的字節數,另一個是閥值。當內存字節數到達閥值時,Lua就運行垃圾收集器,來釋放死對象的空間。一旦字節計數器被調整,那么閥值就會被設為字節計數器新值的兩倍。

通過C API,你可以查詢和更改閥值(見 3.7)。將閥值設為零時會強制立刻進行垃圾收集,同時把他設為足夠大就可以停止垃圾收集。僅使用Lua代碼中的 gcinfo 和 collectgarbage 函數 (見 5.1)可以獲得一定程度上對垃圾收集循環的控制。

2.9.1 - 垃圾收集元方法 (Garbage-Collection Metamethods)

使用 C?API,你可以對用戶數據設置一個垃圾收集元方法(見 2.8)。這些元方法也稱為 終結器(finalizers)。終結器允許你用外部的資源管理來調整Lua的垃圾收集(如關閉文件,網絡或數據庫連接,或者釋放你自己的內存。

用元表中包含 __gc 字段的自由用戶數據不會立即被垃圾收集器回收。而是,Lua把它們放在一個列表中。收集完畢之后,Lua會對這個列表中的用戶數據執行和以下函數相等的操作:

function gc_event (udata)local h = metatable(udata).__gcif h thenh(udata)endend

在每個垃圾收集過程最后,調用用戶數據的終結器的順序,將按照他們在收集過程中添加到列表中的相反順序進行。也就是,第一個被調用的終結器是和在程序中創建的最后一個用戶數據相關的那個終結器。

2.9.2 - 弱表

一個 弱表(weak table) 是一個包含的元素是 弱引用(weak references)的表。垃圾收集器會忽略弱引用。換句話說,如果指向一個對象的引用只有弱引用,那么這個對象還是要被垃圾收集器回收。

弱表可以包含弱的鍵,弱的值,或者兩者皆有。一個包含弱鍵的表允許它的鍵被回收,但值不可以。一個同時包含弱鍵和弱值的表允許鍵和值的回收。無論哪種情況,只要鍵或者值中的一個被回收了,那么這一對鍵值將會從表中刪除。這個表的弱屬性是由它的元表的 __mode 字段控制的。如果 __mode 字段是一個包含字符?`k′的字符串,那么表中的鍵是弱鍵。如果 __mode 字段是一個包含字符 `v′ 的字符串,那么表中的值是弱值。

在你將表用作元表之后,你不應該更改 __mode 字段的值。否則,這個元表控制的表的弱表行為將會不確定。

2.10 - 同步程序

Lua支持同步程序,也稱為 半同步程序(semi-coroutines) 或 協同多線程(collaborative multithreading)。Lua中的一個同步程序代表了一個獨立的執行線程。然而,不像在多線程系統中的線程那樣,一個同步程序只有在調用了一個yield(產生結果)函數才能掛起它的執行。

你可以調用 coroutine.create 來創建一個同步程序。它唯一的一個參數是一個函數,代表同步程序的主函數。create 函數僅僅建立一個新的同步程序然后返回一個它的句柄 (一個線程 thread 類型的對象);它不會啟動該同步程序。

當你第一次調用 coroutine.resume,將 coroutine.create 返回的線程對象作為第一個參數傳遞給它,然后同步程序就啟動了,從它的主函數的第一行開始。傳給 coroutine.resume 的額外的參數會作為同步程序主函數的參數傳遞過去。在同步程序開始執行之后,它一直運行到它結束或產生結果。

一個同步程序通過兩種方式結束它的運行:正常情況下,當它的主函數返回(顯式地或隱式的,在最后一個指令之后)時結束;異常地,如果有未保護的錯誤。第一各情況下,coroutine.resume 返回 true,加上同步程序主函數返回的其它值。在有錯誤的情況下,coroutine.resume 返回 false ,并附上錯誤信息。

一個同步程序通過調用 coroutine.yield 來產生結果。當一個同步程序產生結果,相應的 coroutine.resume 就立刻返回,即使操作發生在嵌套函數調用中(也就是,不在主函數中,而在被主函數直接或間接調用的函數中)。在這種情況下, coroutine.resume 也返回 true,以及傳給 coroutine.yield。的所有參數。下次你繼續同一個同步程序時,它會從它原來yield的地方繼續執行,而 coroutine.yield 將返回給主程序傳給 coroutine.resume 的額外參數。

coroutine.wrap 函數創建一個和 coroutine.create 一樣的同步程序,但它不返回同步程序本身,而是返回一個繼續同步程序的函數(當調用的時候)。傳遞給這個函數的參數作為繼續resume的額外參數。函數將返回resume返回的所有值,出除了第一個(布爾值的錯誤代碼)。不像 coroutine.resume,這個函數不捕獲錯誤;出現任何錯誤都傳回給調用者。

請考慮以下例子:

function foo1 (a)print("foo", a)return coroutine.yield(2*a) endco = coroutine.create(function (a,b)print("co-body", a, b)local r = foo1(a+1)print("co-body", r)local r, s = coroutine.yield(a+b, a-b)print("co-body", r, s)return b, "end" end)a, b = coroutine.resume(co, 1, 10) print("main", a, b) a, b, c = coroutine.resume(co, "r") print("main", a, b, c) a, b, c = coroutine.resume(co, "x", "y") print("main", a, b, c) a, b = coroutine.resume(co, "x", "y") print("main", a, b)

當你運行它的時候,它會產生以下輸出結果:

co-body 1 10 foo 2 main true 4 co-body r main true 11 -9 co-body x y main true 10 end main false cannot resume dead coroutine

3 - 應用程序接口

這一節描述Lua中的C API,這是對于宿主程序可用的C函數集合,用以和Lua通訊。所有的API函數及其相關類型和常量都聲明在頭文件lua.h中。

即便每次我都使用“函數”這個詞,任何設施在API里面都可能被一個宏所替代。所有這些宏(macro)都只使用一次它的參數(除了第一個參數、這個每次總是一個Lua狀態),所以不會產生隱藏的副作用。

3.1 - 狀態

Lua庫是可重入的(reentrant)的:它沒有全局變量。整個Lua解釋器的狀態(全局變量、棧、等等)儲存在一個動態分配的 lua_State 結構類型中。一個指向這個狀態的指針必須作為庫中每一個函數的第一個參數,除了 lua_open 這個函數。該函數從最開始創建一個Lua狀態。

在調用任何API函數之前,你必須通過調用 lua_open 創建一個狀態:

lua_State *lua_open (void);

調用 lua_close 去釋放這個由 lua_open 創建的狀態:

void lua_close (lua_State *L);

這個函數銷毀所有被給予Lua狀態的對象(調用相應的垃圾收集元方法)并且釋放那個狀態使用的所有動態內存。在個別的平臺上,你或許不需要調用這個函數,因為當宿主程序結束的時候會自然的釋放所有的資源。另一方面,長時間運行的程序,像一些守護進程或者Web服務器,可能需要立即釋放那些不需要的狀態資源,以避免占用太多內存。

3.2 - 堆棧和索引

Lua使用一個來自于C語言的 虛擬棧(virtual stack) 傳遞值。棧里面的每一個元素都代表一個Lua值 (nil, number, string, etc.)。

只要Lua調用C語言函數,這個所調用的函數將得到一個新的棧,這個棧將獨立于先前的棧以及那些仍然活躍的C函數的棧。這個棧最初包含了C函數的所有參數,并且這也會存放C函數的返回值(見 3.16)。

為了方便起見,大多數查詢操作的API不需要遵守一個嚴格的棧定義(注:即不需要遵循FILO)。他們可以使用 索引(index) 引用任何棧中元素:一個正數索引代表了棧中的絕對位置(從1開始);一個負數索引代表了從棧頂的偏移量。更特別的是,如果棧有 n 個元素,那么索引 1 代表第一個元素(這就是說,這個元素首先入棧)并且索引 n 代表了最后一個元素;索引 -1 也代表了最后一個元素(也就是棧頂)并且索引 -n 代表了第一個元素。我們說一個索引存在于 1 和棧頂之間是有效的,換句話說,如果 1 <= abs(index) <= top。

在任何時間里,你可以調用 lua_gettop 得到棧頂元素的索引:

int lua_gettop (lua_State *L);

因為索引從 1 開始,lua_gettop 的結果等于棧中的元素數量(如果是0就意味著棧為空)。

當你與Lua API交互的時候,你有責任控制堆棧以避免溢出。。這個函數

int lua_checkstack (lua_State *L, int extra);

使棧的大小增長為 top + extra 個元素;如果無法將棧增加到那個大小將返回false。這個函數從不對棧進行收縮;如果棧已經比新的大小更大,它將不產生任何作用那個。

只要Lua調用C 函數,它必須至少保證 LUA_MINSTACK 這個棧中的位置是可用的。LUA_MINSTACK 定義在 lua.h 中,它的值是 20,所以你不需要總擔心棧空間除非你的代碼通過循環將元素壓入棧。

大多數插敘函數接受指向有效棧空間的索引,那就是說,索引達到棧空間的最大值是你需要使用 lua_checkstack。這樣的索引稱為可接受索引(acceptable indices)。更正規的說法,我們給出一個嚴格的定義如下:

(index < 0 && abs(index) <= top) || (index > 0 && index <= stackspace)

注意,0永遠不是一個可接受索引。

除非另外說明,任何函數接受有效索引可以被稱為是 偽索引(pseudo-indices),這些索引代表一些Lua值可以被C 代碼訪問但是卻不存在于棧中。假索引通常用于訪問全局環境變量,注冊表,和一個C 函數的上值(見 3.17)。

3.3 - 堆棧操作

一下的API提供了基本的棧操作:

void lua_settop (lua_State *L, int index);void lua_pushvalue (lua_State *L, int index);void lua_remove (lua_State *L, int index);void lua_insert (lua_State *L, int index);void lua_replace (lua_State *L, int index);

lua_settop 接受任何可接受的索引,或者0,并且將該索引設置為棧頂。如果新的棧頂比舊的更大,那么新元素被填上 nil 值。如果索引為 0,那么所有棧元素會被清除。在 lua.h 里面定義了一個有用的宏

#define lua_pop(L,n) lua_settop(L, -(n)-1)

用以從棧中彈出 n 個元素。

lua_pushvalue 將一個索引指向的元素的拷貝壓入棧。 lua_remove 刪除指定位置的元素,將該元素上方的所有元素下移以填滿空缺。lua_insert 將棧頂元素移動到指定位置,將該位置以上的元素上移。lua_replace 將棧頂元素移動到指定位置而不移動其他任何其他元素(因此替代了給定位置的元素的值)。所有這些函數只接受有效的索引。(你不能使用偽索引調用 lua_remove 或 lua_insert,因為他們不代表棧中的位置。)

舉個例子,如果棧開始于 10 20 30 40 50*(自底向上;`*′ 標記了棧頂),那么:

lua_pushvalue(L, 3) --> 10 20 30 40 50 30*lua_pushvalue(L, -1) --> 10 20 30 40 50 30 30*lua_remove(L, -3) --> 10 20 30 40 30 30*lua_remove(L, 6) --> 10 20 30 40 30*lua_insert(L, 1) --> 30 10 20 30 40*lua_insert(L, -1) --> 30 10 20 30 40* (no effect)lua_replace(L, 2) --> 30 40 20 30*lua_settop(L, -3) --> 30 40*lua_settop(L, 6) --> 30 40 nil nil nil nil*

3.4 - 堆棧查詢

下面的函數可以用來檢測棧內元素的類型:

int lua_type (lua_State *L, int index);int lua_isnil (lua_State *L, int index);int lua_isboolean (lua_State *L, int index);int lua_isnumber (lua_State *L, int index);int lua_isstring (lua_State *L, int index);int lua_istable (lua_State *L, int index);int lua_isfunction (lua_State *L, int index);int lua_iscfunction (lua_State *L, int index);int lua_isuserdata (lua_State *L, int index);int lua_islightuserdata (lua_State *L, int index);

這些函數只能使用可接受的索引。

lua_type 返回棧中元素值的類型,如果所有索引無效則返回 LUA_TNONE(就是說如果棧為空)。這些lua_type 代表的返回值作為常量定義在 lua.h 中:LUA_TNIL, LUA_TNUMBER, LUA_TBOOLEAN, LUA_TSTRING, LUA_TTABLE, LUA_TFUNCTION, LUA_TUSERDATA, LUA_TTHREAD, LUA_TLIGHTUSERDATA。下面的函數將這些常量轉換成字符串:

const char *lua_typename (lua_State *L, int type);

lua_is* 函數返回 1 當對象與所給類型兼容的時候,其他情況返回 0。 lua_isboolean 是一個例外:它只針對布爾值時才會成功(否則將是無用的,因為任何值都是一個布爾值)。這些函數對于無效引用返回 0。 lua_isnumber 接受數字和用數字表示的字符串;lua_isstring 接受字符串和數字(見 2.2.1);lua_isfunction 接受Lua函數和C函數; lua_isuserdata 接受完整的和輕量的用戶數據。要區分C 函數和Lua 函數,你可以使用 lua_iscfunction。要區分用戶數據,你可以使用 lua_islightuserdata。要區分數字還是用數字表示的字符串,你可以使用 lua_type。

這些API還包含了用于比較棧中的兩個值的操作:

int lua_equal (lua_State *L, int index1, int index2);int lua_rawequal (lua_State *L, int index1, int index2);int lua_lessthan (lua_State *L, int index1, int index2);

lua_equal 和 lua_lessthan 在比較他們的副本的時候是等效的(見 2.5.2)。 lua_rawequal 用于比較基本類型但不包括元方法。如果有任何形式的無效索引,這些函數都返回 0(false)。

3.5 - 堆棧取值

為了將一個棧中的值轉變為指定的C語言類型,你需要使用以下的轉換函數:

int lua_toboolean (lua_State *L, int index);lua_Number lua_tonumber (lua_State *L, int index);const char *lua_tostring (lua_State *L, int index);size_t lua_strlen (lua_State *L, int index);lua_CFunction lua_tocfunction (lua_State *L, int index);void *lua_touserdata (lua_State *L, int index);lua_State *lua_tothread (lua_State *L, int index);void *lua_topointer (lua_State *L, int index);

這些函數由任何可接受索引作為參數進行調用。當遇到一個無效索引,函數表現為就好像接受了一個錯誤類型的值。

lua_toboolean 將索引指向的Lua值轉換為C語言類型的布爾值(0 或 1)。就像所有Lua中的測試一樣,任何不等于 false 或者 nil 的Lua值通過 lua_toboolean 都將返回 1;否則將返回 0。當然,如果是一個無效索引,也將返回 0。(如果你只想接受真實的布爾值,使用 lua_isboolean 去測試值的類型。)

lua_tonumber 將索引指向的Lua值轉換成一個數字(默認情況下,lua_Number 是 double類型)。Lua值必須是一個數字或者可轉化為數字的字符串(見 2.2.1);否則,lua_tonumber 返回 0。

lua_tostring 將索引指向的Lua值轉換成字符串(const char*)。Lua值必須是一個字符串或者數字;否則,函數返回 NULL。如果值是一個數字,lua_tostring 會將棧中的真實值變成一個字符串類型。(當 lua_tostring 應用于鍵時這個改變將引起 lua_next 的混亂。)lua_tostring 在Lua 狀態內部返回一個字符串的指針。這個字符串總是以 0('\0')結尾,就像C 語言里的一樣,但是也可能包含其他 0 在其中。如果你不知道一個字符串中是否存在 0 ,你可以使用 lua_strlen 得到它的實際長度。因為Lua具有垃圾收集機制,所以不能保證 lua_tostring 返回的指針仍然有效,當相應的值從棧中刪除之后。如果你在當前函數返回之后還需要這個字符串,你需要復制它并且將它存入注冊表(見 3.18)。

lua_tocfunction 將棧中的值轉換為C 函數。這個值必須是一個C 函數;否則,lua_tocfunction 返回 NULL。類型 lua_CFunction 在 3.16 中有詳細解釋。

lua_tothread 將棧中的值轉換為Lua線程(被描繪成 lua_State *)。這個值必須是一個線程;否則;lua_tothread 返回 NULL。

lua_topointer 將棧中?鬧底晃ㄓ玫腃 語言指針(void *)。這個值可能是一個用戶數據、表、線程、或者函數;否則,lua_topointer 返回 NULL。Lua保證同種類型的不同對象將返回不同指針。沒有直接的方法將指針轉換回原來的值。這個函數通常用于調試。

lua_touserdata 在 3.8 中有詳細解釋。

3.6 - 將值壓入堆棧

以下的API函數將C 語言值壓入棧:

void lua_pushboolean (lua_State *L, int b);void lua_pushnumber (lua_State *L, lua_Number n);void lua_pushlstring (lua_State *L, const char *s, size_t len);void lua_pushstring (lua_State *L, const char *s);void lua_pushnil (lua_State *L);void lua_pushcfunction (lua_State *L, lua_CFunction f);void lua_pushlightuserdata (lua_State *L, void *p);

這些函數接受一個C 語言值,將其轉換成相應的Lua 值,并且將結果壓入棧。需要特別注意的是,lua_pushlstring 和 lua_pushstring 將對所給的字符串做一個內部拷貝。lua_pushstring 只能壓入合適的C 語言字符串(也就是說,字符串要以 '\0' 結尾,并且不能包含內嵌的 0);否則,你需要使用更通用的 lua_pushlstring 函數,它可以接受一個指定的大小。

你可以壓入“格式化的”字符串:

const char *lua_pushfstring (lua_State *L, const char *fmt, ...);const char *lua_pushvfstring (lua_State *L, const char *fmt, va_list argp);

這些函數將格式化的字符串壓入棧并且返回這個字符串的指針。它們和 sprintf、vsprintf 類似,但是有一些重要的不同之處:

  • 你不需要為結果分配空間:結果是Lua字符串并且Lua會關心內存分配問題(和內存釋放問題,通過垃圾收集機制)。
  • 轉換受到限制。這里沒有標志、寬度或精度。轉換操作的修飾符可以是簡單的`%%′(在字符串中插入一個`%′),`%s′(插入一個沒有大小限制的以 0 結尾的字符串),`%f′(插入一個 lua_Number),`%d′(插入一個 int),`%c′(插入一個 int 作為一個字符)。

這個函數

void lua_concat (lua_State *L, int n);

連接棧頂的 n 個值,將它們彈出,并且將結果留在棧頂。如果 n 為 1,結果是單個字符串(也就是說,函數什么也不做);如果 n 是 0,結果是空字符串。連接的完成依據Lua的語義(見 2.5.4)。

3.7 - 控制垃圾收集

Lua使用兩個數字控制垃圾收集循環。一個數字表示Lua使用的動態內存的字節數,另一個是閥值。(見 2.9)。一個數字表示Lua使用的動態內存的字節數,另一個是閥值。當內存字節數到達閥值時,Lua就運行垃圾收集器,來釋放死對象的空間。一旦字節計數器被調整,那么閥值就會被設為字節計數器新值的兩倍。

你可以通過以下的函數得到這兩個量的當前值:

int lua_getgccount (lua_State *L);int lua_getgcthreshold (lua_State *L);

它們的返回值的單位都是千字節(K bytes)。你可以通過下面的函數改變閥值

void lua_setgcthreshold (lua_State *L, int newthreshold);

然后,新的閥值得單位也是千字節。當你調用這個函數,Lua設置閥新值并且和字節計數器作比較。如果新的閥值小于字節計數器,Lua將立刻運行垃圾收集器。特別是 lua_setgcthreshold(L,0) 強迫進行垃圾收集。在這之后,一個新值根據先前的規則被設置。

3.8 - 用戶數據類型 (Userdata)

用戶數據代表了Lua中使用的C語言值。Lua支持兩種用戶數據:完整用戶數據(full userdata) 和 輕量用戶數據(light userdata)。

一個完整用戶數據代表了一塊內存。它是一個對象(像一個表):你必須創建它,它有自己的元表,當它被回收的時候你可以檢測到。一個完整用戶數據只能與自己相等(基于原始的相等規則)。

一個輕量用戶數據代表一個指針。它是?桓鮒擔ㄏ褚桓鍪鄭耗悴⒚揮寫唇ㄋ裁揮性懟ⅲ荒鼙換厥眨ㄒ蛭游幢淮唇ǎG崍坑沒菹嗟鵲奶跫侵剛脛趕虻牡刂廢嗤?

在Lua 代碼里,沒辦法測試用戶數據類型是完整的還是輕量的;兩者都是 用戶數據類型。在C 代碼里,如果是完整用戶數據,lua_type 返回 LUA_TUSERDATA,反之,返回 LUA_TLIGHTUSERDATA。

你可以通過下面的函數創建完整用戶數據:

void *lua_newuserdata (lua_State *L, size_t size);

這個函數根據指定大小分配一個內存塊,將用戶數據的地址壓入棧并且返回這個地址。

要將輕量用戶數據壓入棧,你需要使用 lua_pushlightuserdata(見 3.6)。

lua_touserdata (見 3.5)用來取回用戶數據的值。當你用在完整用戶數據的時候,它返回這個塊的地址,當你用在輕量用戶數據的時候,它返回它的指針,當你用在非用數據的時候,返回 NULL。

當Lua回收一個完整用戶數據,它調用該用戶數據的 gc 元方法,然后釋放該用戶數據相應的內存。

3.9 - 元表 (Metatables)

下面的函數允許你操作對象的元表:

int lua_getmetatable (lua_State *L, int index);int lua_setmetatable (lua_State *L, int index);

lua_getmetatable 將所給對象的元表壓入棧。如果索引無效,或這個對象不含有元表,該函數返回 0 并且不對棧進行任何操作。

lua_setmetatable 從棧中彈出一張表并且為所給對象設置一個新的元表。當無法給所給對象設置元表的時候該函數返回 0(也就是說,這個對象既不是一個用戶數據也不是一張表);盡管那樣,它仍從棧中彈出這張表。

3.10 - 加載Lua語句段

你可以通過 lua_load 加載一個Lua塊:

typedef const char * (*lua_Chunkreader)(lua_State *L, void *data, size_t *size);int lua_load (lua_State *L, lua_Chunkreader reader, void *data,const char *chunkname);

lua_load 的返回值是:

  • 0 --- 沒有錯誤
  • LUA_ERRSYNTAX --- 預編譯時句法錯誤
  • LUA_ERRMEM --- 內存分配錯誤

如果沒有錯誤,lua_load 將編譯過的語句段作為Lua 函數壓入棧頂。否則,它將壓入一個錯誤信息。

lua_load 自動檢測語句段的類型是文本還是二進制數據,并且根據類型將其載入(見程序 luac)。

lua_load 使用一個用戶提供的 reader 函數讀取語句段的內容。當需要調用其它段時,lua_load 調用 reader,傳遞其 data 參數。必須返回指向語句段所在的新內存塊的指針,并將段大小設置為 0。為了標志塊尾,reader 必須返回 NULL。reader 函數可以返回任何大于零的值。

在當前的實現中,reader 函數不能調用任何Lua 函數;為了保證這一點,它總是會得到為 NULL 的Lua狀態。

語句段名(chunkname) 用于錯誤信息和調試信息(見 4)。

參考輔助庫 (lauxlib.c) 了解如何使用 lua_load 以及如何使用現成的函數從文件和字符串中加載語句段。

3.11 - 表操作

通過調用以下函數可以創建表:

void lua_newtable (lua_State *L);

這個函數創建一張新的空表,并將其壓入棧。

要從棧中的表里讀取值,使用:

void lua_gettable (lua_State *L, int index);

index 代表表的位置。lua_gettable 從棧中彈出一個鍵,并且返回該鍵對應的值,表仍然留在堆棧中。在Lua中,這個函數可能觸發一個針對 index 事件的元方法(見 2.8)。想要在不調用任何元方法的情況下得到表主鍵所對應的真實值,使用這個原始(raw)版本:

void lua_rawget (lua_State *L, int index);

要將一個值儲存到棧中的一張表中,你需要將鍵壓入棧,再將值壓入棧,調用:

void lua_settable (lua_State *L, int index);

index 代表表的位置。lua_settable 從棧中彈出主鍵和值。表仍然留在棧中。在Lua中,這個操作可能觸發針對 settable 或者 newindex 事件的元方法。想要不受這些元方法的影響并且為任意表設置值,使用這個原始(raw)版本:

void lua_rawset (lua_State *L, int index);

你可以通過這個函數遍歷一張表:

int lua_next (lua_State *L, int index);

index 指向需要被遍歷的表。這個函數從堆棧中彈出一個鍵,從表中取一對鍵-值壓入棧(所給鍵的下一對)。如果沒有更多的元素,lua_next 返回 0(對棧不進行操作)。使用一個 nil 鍵標示遍歷的開始。

一個典型的遍歷操作看起來像這樣:

/* table is in the stack at index `t' */lua_pushnil(L); /* first key */while (lua_next(L, t) != 0) {/* `key' is at index -2 and `value' at index -1 */printf("%s - %s\n",lua_typename(L, lua_type(L, -2)), lua_typename(L, lua_type(L, -1)));lua_pop(L, 1); /* removes `value'; keeps `key' for next iteration */}

當遍歷一張表的時候,不要在鍵上直接調用 lua_tostring,除非你知道這個鍵確實是一個字符串。再次調用 lua_tostring 改變了所給索引指向的值;這使 lua_next 的調用發生混亂。

3.12 - 環境變量操作 (Manipulating Environments)

所有的全局變量保存在普通的Lua 表中,叫做環境變量。初始的環境變量被稱作全局環境變量。這張表總是在 LUA_GLOBALSINDEX 這個偽索引處。

要訪問或改變全局變量的值,你可以對環境變量表使用常規的表操作。舉個例子,存取一個全局變量的值:

lua_pushstring(L, varname);lua_gettable(L, LUA_GLOBALSINDEX);

你可以改變一個Lua 線程的全局環境變量通過 lua_replace 函數。

以下的函數提供獲取、設置Lua函數的環境變量的功能:

void lua_getfenv (lua_State *L, int index);int lua_setfenv (lua_State *L, int index);

lua_getfenv 將堆棧中 index 索引指向的函數的環境變量表壓入棧。如果函數是一個C 函數,lua_getfenv 將全局環境變量壓入棧。lua_setfenv 從棧中彈出一張表并且將其設置為棧中 index 索引處的函數的新環境變量。如果給定索引處的對象不是一個Lua 函數,lua_setfenv 返回 0。

3.13 - 將表作為數組使用 Using Tables as Arrays

有一些 API 能夠幫助我們將Lua 表作為數組使用,也就是說,表只由數字作為索引:

void lua_rawgeti (lua_State *L, int index, int n);void lua_rawseti (lua_State *L, int index, int n);

lua_rawgeti 將表中的第 n 個元素放入堆棧中的指定位置 index。lua_rawseti 將堆棧中指定位置 index 處的表中的第 n 個元素的值設定為棧頂的值,并將原來的值從棧中刪除。

3.14 - 調用函數

定義在Lua 中的函數和C語言函數經過注冊就可以被宿主程序調用。這些調用必須遵循以下協議:首先,被調用的函數被壓入棧;然后,函數的參數必須順序(direct order)輸入,也就是說,第一個參數需要被第一個輸入。最后,函數通過下面的方法調用:

void lua_call (lua_State *L, int nargs, int nresults);

nargs 是你壓入棧的參數的數量。所有參數和函數值從堆棧中彈出,并且函數結果被壓入棧。返回值的數量被調整為 nresults,除非 nresults 是 LUA_MULTRET。在那種情況下,所有函數結果都被壓入棧。Lua 會檢測返回值是否適合棧空間。函數返回值按順序被壓入棧(第一個返回值首先入棧),所以調用結束后最后一個返回值在棧頂。

下面的例子展示宿主程序如何可以和這個Lua 代碼等效:

a = f("how", t.x, 14)

這里是C 語言里的做法:

lua_pushstring(L, "t");lua_gettable(L, LUA_GLOBALSINDEX); /* global `t' (for later use) */lua_pushstring(L, "a"); /* var name */lua_pushstring(L, "f"); /* function name */lua_gettable(L, LUA_GLOBALSINDEX); /* function to be called */lua_pushstring(L, "how"); /* 1st argument */lua_pushstring(L, "x"); /* push the string "x" */lua_gettable(L, -5); /* push result of t.x (2nd arg) */lua_pushnumber(L, 14); /* 3rd argument */lua_call(L, 3, 1); /* call function with 3 arguments and 1 result */lua_settable(L, LUA_GLOBALSINDEX); /* set global variable `a' */lua_pop(L, 1); /* remove `t' from the stack */

注意上面的代碼是“平衡的”:在它結束時,堆棧返回原來的配置。這個被認為是良好的編程實踐。

(為了展示細節,我們只用Lua 提供的原始 API 完成這個例子。通常程序員定義并使用幾個宏和輔助庫函數在Lua 中提供高級存取功能。請參考例子中標準庫函數的源代碼。)

3.15 - 受保護調用 Protected Calls

當你通過 lua_call 調用一個函數,所調用函數內部產生的錯誤將向上傳遞(通過一個 longjmp)。如果你需要處理錯誤,你應該使用 lua_pcall:

int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc);

nargs 和 nresults 在 lua_call 中有相同的意義。如果調用過程中沒有錯誤,lua_pcall 的行為非常像 lua_call 。然而,如果有錯誤,lua_call 會捕獲它,將一個單一值(錯誤信息)壓入棧,并且返回錯誤代碼。像 lua_call ,lua_pcall 總是從棧中刪除函數和它的參數。

如果 errfunc 是 0,所返回的錯誤信息就是原始的錯誤信息。另外,errfunc 給出一個指向錯誤處理函數(error handler function)的棧索引。(在當前的實現中,索引不能為偽索引。)假設運行時錯誤,函數將和錯誤信息一起被調用,并且他的返回值將是 lua_pcall 返回的信息。

錯誤處理函數被用來為錯誤信息增加更多的調試信息,例如棧的記錄。這樣的信息在 lua_pcall 調用返回后將不能被收集,因此棧已經被解開了。

如果 lua_pcall 函數調用成功返回 0,否則返回以下的一個錯誤代碼(定義在 lua.h):

  • LUA_ERRRUN --- 運行時錯誤
  • LUA_ERRMEM --- 內存分配錯誤。這樣的錯誤下,Lua 不調用錯誤處理函數
  • LUA_ERRERR --- 運行錯誤處理函數時發生的錯誤

3.16 - 定義C 函數

Lua可以通過C 語言寫的函數進行擴展,這些函數必須是 lua_CFunction 類型的,作為以下定義:

typedef int (*lua_CFunction) (lua_State *L);

一個C 函數接收一個Lua 狀態并且返回一個整數,數值需要返回給Lua。

為了正確的和Lua 通訊,C 函數必須遵循以下協議,它定義了參數和返回值傳遞的方法:一個C 函數在它的堆棧中從Lua獲取順序(第一個參數首先入棧)參數。所以,當函數開始時,第一個參數在索引位置 1。為了將返回值傳遞給Lua,一個C 函數將它們順序壓入棧,并且返回它們的數量。任何在堆棧中位于返回值以下的值都將被Lua 適當的解除。就像Lua 函數一樣,一個C 函數被Lua 調用也可以返回很多結果。

作為一個例子,下面的函數接收一個任意數量的數字參數并且返回它們的平均值和總合:

static int foo (lua_State *L) {int n = lua_gettop(L); /* number of arguments */lua_Number sum = 0;int i;for (i = 1; i <= n; i++) {if (!lua_isnumber(L, i)) {lua_pushstring(L, "incorrect argument to function `average'");lua_error(L);}sum += lua_tonumber(L, i);}lua_pushnumber(L, sum/n); /* first result */lua_pushnumber(L, sum); /* second result */return 2; /* number of results */}

下面是一些便利的宏用來在Lua中注冊一個C 函數:

#define lua_register(L,n,f) \(lua_pushstring(L, n), \lua_pushcfunction(L, f), \lua_settable(L, LUA_GLOBALSINDEX))/* lua_State *L; *//* const char *n; *//* lua_CFunction f; */

它接收Lua 中的函數名和一個指向函數的指針。這樣,上面的C 函數foo可以在Lua中被注冊為 average 并被調用。

lua_register(L, "average", foo);

3.17 - 定義C 函數關閉 Defining C Closures

當一個C 函數被創建后,它可以與一些值關聯,這樣創建了一個 C 閉包(C?closure);這些值可以被隨時被函數訪問。為了使值和C 函數關聯,首先這些值要被壓入棧(有多個值時,第一個值先入),然后這個函數

void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);

被用來將C 函數壓入棧,通過參數 n 告知應該有多少個值和該函數關聯(lua_pushcclosure 將這些值從堆棧中彈出);事實上,這個宏 lua_pushcfunction 被定義作為 lua_pushcfunction 將 n 設置為 0。

然后,無論何時C 函數被調用,那些值被定為于指定的偽索引處。那些偽索引有一個宏 lua_upvalueindex 產生。第一個和函數關聯的值在 lua_upvalueindex(1) 處,其他的以此類推。當 n 比當前函數的上值大時,lua_upvalueindex(n) 會產生一個可接受的索引(但是無效)。

C語言函數和關閉的例子,請參考Lua官方發行版中的標準庫(src/lib/*.c)。

3.18 - 注冊表 Registry

Lua提供了一個注冊表,一張可以被所有C 代碼用來儲存任何需要儲存的Lua值的預定義表,特別是如果C 代碼需要維護C 函數以外存活的Lua值。這張表總是位于 LUA_REGISTRYINDEX 這個為索引處。任何C 語言庫可以將數據儲存在這張表中,只要它選擇的鍵和其他庫不同。典型的做法是你應該使用字符串作為主鍵包含你的庫名或者在你的代碼中使用一個包含C 對象地址的輕量用戶數據。

在注冊表中的整數鍵被引用機制所使用,由輔助庫實現,因此不應該被用作其它用途。

3.19 - C 中的錯誤處理 Error Handling in C

總的來說,Lua使用C longjmp 機制來處理錯誤。當Lua面對任何錯誤(例如內存分配錯誤,類型錯誤,句法錯誤)它 升起(raises) 一個錯誤,也就是說,它做了一個長跳躍。一個受保護的環境使用 setjmp 設置一個恢復點;任何錯誤跳至最近最活躍的恢復點。

如果錯誤發生在任何受保護的環境,Lua調用 panic 函數 并且隨后調用exit(EXIT_FAILURE)。你可以將panic 函數變為以下內容。

lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf);

你的新panic 函數可以避免程序因為沒有返回(例如通過一個長跳躍)而退出。否則,相應的Lua 狀態將不一致;唯一安全的操作就是關閉它。

幾乎所有的API 函數都可能引起錯誤,例如導致一個內存分配錯誤。:lua_open, lua_close, lua_load 和 lua_pcall 這些的函數運行在保護模式下(也就是說,它們創建了一個受保護的環境并在其中運行),所以它們從不會引起錯誤。

有另外一個函數將所給的C 函數運行在保護模式下:

int lua_cpcall (lua_State *L, lua_CFunction func, void *ud);

lua_cpcall 在保護模式下調用 func。func 由一個包含 ud 的輕量用戶數據開始。在錯誤問題上,lua_cpcall 像 lua_pcall 一樣返回相同的錯誤代碼(見 3.15),加上在棧頂的一個錯誤對象;否則,返回 0,并且不對堆棧進行任何操作。任何由 func 返回的值都被丟棄。

C 代碼可以通過調用下面的函數產生一個Lua錯誤:

void lua_error (lua_State *L);

錯誤信息(實際上可以是任何類型的對象)必須在棧頂。這個函數進行一個長跳躍,因此從來不會返回。

3.20 - 線程

Lua 提供了操作線程的部分支?幀H綣閿卸嘞叱灘僮韉腃 語言庫,那么Lua能夠與其協作并且在Lua中實現相同的機制。同樣,Lua在線程之上實現自己的協同程序系統。以下函數用來在Lua中創建一個線程:

lua_State *lua_newthread (lua_State *L);

這個函數將線程壓入棧并且返回代表新線程的 lua_State 指針。這個返回的新狀態與所有全局對象(例如表)共享初始狀態,但是有一個獨立的運行時堆棧。

每個線程都有自己獨立的全局環境表。當你創建一個線程,這張表就和所給狀態一樣,但是你可以獨自更改它們。

沒有明確的函數可以關閉或者銷毀一個線程。線程和其他Lua對象一樣受垃圾收集程序的支配:

要像協同程序一樣操作線程,Lua提供了以下函數:

int lua_resume (lua_State *L, int narg);int lua_yield (lua_State *L, int nresults);

你需要創建一個線程以便啟動協同程序;然后你將函數體和事件參數壓入堆棧;然后調用 lua_resume,narg 的值代表參數的數量。當同步程序暫停或者結束執行,函數將返回。當它返回后,棧中包含的所有值傳遞給 lua_yield,或者有主體函數返回。如果同步程序運行無誤,lua_resume 返回 0,否則返回一個錯誤代碼(見 3.15)。對于錯誤,堆棧只包含錯誤信息。要重起同步程序,將作為結果傳遞給 yield 的值壓入堆棧,并且調用 lua_resume。

lua_yield 函數只能像C 函數的返回表達式一樣被調用,就像下面所展示的:

return lua_yield (L, nresults);

如果C 函數像這樣調用 lua_yield,正在運行的同步程序暫停它的執行,并且調用 lua_resume 開始讓這個協同程序返回。nresults 這個參數代表了在堆棧中作為結果傳遞給 lua_resume 的值的數量。

要在不同線程中交換值,你可以使用 lua_xmove:

void lua_xmove (lua_State *from, lua_State *to, int n);

它從堆棧 from 中彈出 n 個值,并將其壓入堆棧 to。

4 - 調試接口 The Debug Interface

Lua 沒有內置的調試設施。它使用一種特殊的接口,這種接口依賴函數和 鉤子(hooks)。該接口允許構造不同種類的調試器,分析器以及其他工具用以從解釋器得到所需的信息。

4.1 - 堆棧及函數信息 Stack and Function Information

得到解釋程序運行時堆棧信息的主要函數是:

int lua_getstack (lua_State *L, int level, lua_Debug *ar);

這個函數用一個指定等級的函數的 activation record 的標示符填充一個 lua_Debug 結構,等級 0 是當前運行函數,然而等級 n+1 是在等級 n 上調用的函數。當沒有錯誤發生時,lua_getstack 返回 1;當在比棧更深的等級上調用的時候,它返回 0;

lua_Debug 結構被用來攜帶一個處于活動狀態的函數的各種信息:

typedef struct lua_Debug {int event;const char *name; /* (n) */const char *namewhat; /* (n) `global', `local', `field', `method' */const char *what; /* (S) `Lua' function, `C' function, Lua `main' */const char *source; /* (S) */int currentline; /* (l) */int nups; /* (u) number of upvalues */int linedefined; /* (S) */char short_src[LUA_IDSIZE]; /* (S) *//* private part */...} lua_Debug;

lua_getstack 只填充結構的私有部分以備之后使用。要填充 lua_Debug 其他有用信息,調用

int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar);

這個函數發生錯誤是返回 0 (舉個例子,一個無效的 what 選項)。what 字符串中的每個字符選擇填充一些 ar 結構的字段,把上面在 lua_Debug 定義中用圓括號括起來的字母作為指示: `S′ 填充在 source, linedefined 和 what 字段中;`l′ 填充在 currentline 字段中,等等...。而且,`f′ 將正在運?性謁燃渡系暮谷攵顏弧?

想要從一個不處于活動狀態的函數那得到信息(就是不在棧上的函數),你需要將其壓入棧并且用 >′ 作為 what 字符串的開始。舉個例子,要知道函數 f 定義在第幾行,你需要這樣寫

lua_Debug ar;lua_pushstring(L, "f");lua_gettable(L, LUA_GLOBALSINDEX); /* get global `f' */lua_getinfo(L, ">S", &ar);printf("%d\n", ar.linedefined);

lua_Debug 的字段有如下的含義:

  • source 如果函數在一個字符串中定義,那么 source 就是那個字符串。如果函數定義在一個文件中,source 開始于一個 `@′ 后面跟隨文件名。
  • short_src 一個可打印版的 source,用于錯誤信息。
  • linedefined 函數定義起始的行號。
  • what 如果這是一個Lua函數,顯示 "Lua" 字符串, "C" 為C 函數,"main" 如果這是一個語句段的main部分,"tail" 如果這是一個做了尾部調用的函數。在后面的情況里,Lua 沒有其他關于這個函部的信息。
  • currentline 代表當前函數執行到的行數。如果沒有行信息可用,currentline 被設置為 -1。
  • name 一個所給函數合理的函數名。因為函數在Lua中屬于第一類值,它們沒有固定的名字:一些函數可能是多個全局變量的值,其他的可能只儲存在一個表字段里。lua_getinfo 函數檢測函數如何被調用或者是否為一個全局變量的值以尋找一個合適的名字。如果找不到合適的名字,name 被設置為 NULL。
  • namewhat name 字段的解釋。根據函數如何被調用,namewhat 的值可以是 "global", "local", "method", "field" 或者 "" (空字符串)。(當沒有其他可選項的時候Lua使用空字符串代替)
  • nups 函數上值的數量。

4.2 - 操作局部變量和上值 Manipulating Local Variables and Upvalues

為了更多的操作局部變量和上值,調試接口使用索引:第一個參數或者局部變量索引為 1,以此類推,直到最后一個活動的局部變量。整個函數中的活動的上值沒有特定的順序。

下面的函數允許操作一個所給激活記錄的局部變量:

const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n);const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n);

參數 ar 必須是一個被前一個 lua_getstack 調用填充的有效的激活記錄或者作為一個鉤子函數的參數(見 4.3)。lua_getlocal 獲得一個局部變量的索引 n,將變量的值壓入棧,并且返回變量名。lua_setlocal 從棧頂分配一個值給變量并且返回變量名。當索引超過活動的局部變量的數量時,兩個函數都返回 NULL。

以下的函部可以操作所給函數的上值(不像局部變量,函數的上值即使在函數不處于活動狀態的時候都可以被訪問):

const char *lua_getupvalue (lua_State *L, int funcindex, int n);const char *lua_setupvalue (lua_State *L, int funcindex, int n);

這些函數可以作為Lua 函數使用也可以作為C 函數使用。(作為Lua 函數,上值是函數外部使用的局部變量,因此它被包含在函數閉包中。)funcindex 指向棧中的一個函數。lua_getupvalue 得到一個上值的索引 n,將上值的值壓入棧,并返回其變量名。lua_setupvalue 從棧頂分配一個值給上值并返回變量名。當索引大于上值數量時,兩個函數都返回 NULL。對于C 函數來說,這些函數使用空字符串作為所有上值的變量名。

作為一個例子,下面的函數列舉了所給等級的棧中的函數的所有局部變量名和上值變量名:

int listvars (lua_State *L, int level) {lua_Debug ar;int i;const char *name;if (lua_getstack(L, level, &ar) == 0)return 0; /* failure: no such level in the stack */i = 1;while ((name = lua_getlocal(L, &ar, i++)) != NULL) {printf("local %d %s\n", i-1, name);lua_pop(L, 1); /* remove variable value */}lua_getinfo(L, "f", &ar); /* retrieves function */i = 1;while ((name = lua_getupvalue(L, -1, i++)) != NULL) {printf("upvalue %d %s\n", i-1, name);lua_pop(L, 1); /* remove upvalue value */}return 1;}

4.3 - 鉤子 Hooks

Lua offers a mechanism of hooks, which are user-defined C functions that are called during the program execution. A hook may be called in four different events: a call event, when Lua calls a function; a return event, when Lua returns from a function; a line event, when Lua starts executing a new line of code; and a count event, which happens every "count" instructions. Lua identifies these events with the following constants: LUA_HOOKCALL, LUA_HOOKRET (or LUA_HOOKTAILRET, see below), LUA_HOOKLINE, and LUA_HOOKCOUNT.

A hook has type lua_Hook, defined as follows:

typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);

You can set the hook with the following function:

int lua_sethook (lua_State *L, lua_Hook func, int mask, int count);

func is the hook. mask specifies on which events the hook will be called: It is formed by a disjunction of the constants LUA_MASKCALL, LUA_MASKRET, LUA_MASKLINE, and LUA_MASKCOUNT. The count argument is only meaningful when the mask includes LUA_MASKCOUNT. For each event, the hook is called as explained below:

  • The call hook is called when the interpreter calls a function. The hook is called just after Lua enters the new function.
  • The return hook is called when the interpreter returns from a function. The hook is called just before Lua leaves the function.
  • The line hook is called when the interpreter is about to start the execution of a new line of code, or when it jumps back in the code (even to the same line). (This event only happens while Lua is executing a Lua function.)
  • The count hook is called after the interpreter executes every count instructions. (This event only happens while Lua is executing a Lua function.)

A hook is disabled by setting mask to zero.

You can get the current hook, the current mask, and the current count with the following functions:

lua_Hook lua_gethook (lua_State *L);int lua_gethookmask (lua_State *L);int lua_gethookcount (lua_State *L);

Whenever a hook is called, its ar argument has its field event set to the specific event that triggered the hook. Moreover, for line events, the field currentline is also set. To get the value of any other field in ar, the hook must call lua_getinfo. For return events, event may be LUA_HOOKRET, the normal value, or LUA_HOOKTAILRET. In the latter case, Lua is simulating a return from a function that did a tail call; in this case, it is useless to call lua_getinfo.

While Lua is running a hook, it disables other calls to hooks. Therefore, if a hook calls back Lua to execute a function or a chunk, that execution occurs without any calls to hooks.

5 - 標準庫

The standard libraries provide useful functions that are implemented directly through the C API. Some of these functions provide essential services to the language (e.g., type and getmetatable); others provide access to "outside" services (e.g., I/O); and others could be implemented in Lua itself, but are quite useful or have critical performance to deserve an implementation in C (e.g., sort).

All libraries are implemented through the official C API and are provided as separate C?modules. Currently, Lua has the following standard libraries:

  • 基本庫 basic library;
  • 字符串操作 string manipulation;
  • 表操作 table manipulation;
  • 數學函數 (sin, log 等等)mathematical functions (sin, log, etc.);
  • 輸入輸出 input and output;
  • 操作系統機制 operating system facilities;
  • 調試機制 debug facilities.

Except for the basic library, each library provides all its functions as fields of a global table or as methods of its objects.

To have access to these libraries, the C?host program must first call the functions luaopen_base (for the basic library), luaopen_string (for the string library), luaopen_table (for the table library), luaopen_math (for the mathematical library), luaopen_io (for the I/O and the Operating System libraries), and luaopen_debug (for the debug library). These functions are declared in lualib.h.

5.1 - 基本函數 Basic Functions

The basic library provides some core functions to Lua. If you do not include this library in your application, you should check carefully whether you need to provide some alternative implementation for some of its facilities.

assert (v [, message])

Issues an error when the value of its argument v is nil or false; otherwise, returns this value. message is an error message; when absent, it defaults to "assertion failed!"

collectgarbage ([limit])

Sets the garbage-collection threshold to the given limit (in Kbytes) and checks it against the byte counter. If the new threshold is smaller than the byte counter, then Lua immediately runs the garbage collector (see 2.9). If limit is absent, it defaults to zero (thus forcing a garbage-collection cycle).

dofile (filename)

Opens the named file and executes its contents as a Lua chunk. When called without arguments, dofile executes the contents of the standard input (stdin). Returns any value returned by the chunk. In case of errors, dofile propagates the error to its caller (that is, it does not run in protected mode).

error (message [, level])

Terminates the last protected function called and returns message as the error message. Function error never returns.

The level argument specifies where the error message points the error. With level 1 (the default), the error position is where the error function was called. Level 2 points the error to where the function that called error was called; and so on.

_G

A global variable (not a function) that holds the global environment (that is, _G._G = _G). Lua itself does not use this variable; changing its value does not affect any environment. (Use setfenv to change environments.)

getfenv (f)

Returns the current environment in use by the function. f can be a Lua function or a number, which specifies the function at that stack level: Level 1 is the function calling getfenv. If the given function is not a Lua function, or if f is 0, getfenv returns the global environment. The default for f is 1.

If the environment has a "__fenv" field, returns the associated value, instead of the environment.

getmetatable (object)

If the object does not have a metatable, returns nil. Otherwise, if the object's metatable has a "__metatable" field, returns the associated value. Otherwise, returns the metatable of the given object.

gcinfo ()

Returns two results: the number of Kbytes of dynamic memory that Lua is using and the current garbage collector threshold (also in Kbytes).

ipairs (t)

Returns an iterator function, the table t, and 0, so that the construction

for i,v in ipairs(t) do ... end

will iterate over the pairs (1,t[1]), (2,t[2]), ..., up to the first integer key with a nil value in the table.

loadfile (filename)

Loads a file as a Lua chunk (without running it). If there are no errors, returns the compiled chunk as a function; otherwise, returns nil plus the error message. The environment of the returned function is the global environment.

loadlib (libname, funcname)

Links the program with the dynamic C library libname. Inside this library, looks for a function funcname and returns this function as a C function.

libname must be the complete file name of the C library, including any eventual path and extension.

This function is not supported by ANSI C. As such, it is only available on some platforms (Windows, Linux, Solaris, BSD, plus other Unix systems that support the dlfcn standard).

loadstring (string [, chunkname])

Loads a string as a Lua chunk (without running it). If there are no errors, returns the compiled chunk as a function; otherwise, returns nil plus the error message. The environment of the returned function is the global environment.

The optional parameter chunkname is the name to be used in error messages and debug information.

To load and run a given string, use the idiom

assert(loadstring(s))()

next (table [, index])

Allows a program to traverse all fields of a table. Its first argument is a table and its second argument is an index in this table. next returns the next index of the table and the value associated with the index. When called with nil as its second argument, next returns the first index of the table and its associated value. When called with the last index, or with nil in an empty table, next returns nil. If the second argument is absent, then it is interpreted as nil.

Lua has no declaration of fields; There is no difference between a field not present in a table or a field with value nil. Therefore, next only considers fields with non-nil values. The order in which the indices are enumerated is not specified, even for numeric indices. (To traverse a table in numeric order, use a numerical for or the ipairs function.)

The behavior of next is undefined if, during the traversal, you assign any value to a non-existent field in the table.

pairs (t)

Returns the next function and the table t (plus a nil), so that the construction

for k,v in pairs(t) do ... end

will iterate over all key-value pairs of table t.

pcall (f, arg1, arg2, ...)

Calls function f with the given arguments in protected mode. That means that any error inside?f is not propagated; instead, pcall catches the error and returns a status code. Its first result is the status code (a boolean), which is true if the call succeeds without errors. In such case, pcall also returns all results from the call, after this first result. In case of any error, pcall returns false plus the error message.

print (e1, e2, ...)

Receives any number of arguments, and prints their values in stdout, using the tostring function to convert them to strings. This function is not intended for formatted output, but only as a quick way to show a value, typically for debugging. For formatted output, use format (see 5.3).

rawequal (v1, v2)

Checks whether v1 is equal to v2, without invoking any metamethod. Returns a boolean.

rawget (table, index)

Gets the real value of table[index], without invoking any metamethod. table must be a table; index is any value different from nil.

rawset (table, index, value)

Sets the real value of table[index] to value, without invoking any metamethod. table must be a table, index is any value different from nil, and value is any Lua value.

require (packagename)

Loads the given package. The function starts by looking into the table _LOADED to determine whether packagename is already loaded. If it is, then require returns the value that the package returned when it was first loaded. Otherwise, it searches a path looking for a file to load.

If the global variable LUA_PATH is a string, this string is the path. Otherwise, require tries the environment variable LUA_PATH. As a last resort, it uses the predefined path "?;?.lua".

The path is a sequence of templates separated by semicolons. For each template, require will change each interrogation mark in the template to packagename, and then will try to load the resulting file name. So, for instance, if the path is

"./?.lua;./?.lc;/usr/local/?/?.lua;/lasttry"

a require "mod" will try to load the files ./mod.lua, ./mod.lc, /usr/local/mod/mod.lua, and /lasttry, in that order.

The function stops the search as soon as it can load a file, and then it runs the file. After that, it associates, in table _LOADED, the package name with the value that the package returned, and returns that value. If the package returns nil (or no value), require converts this value to true. If the package returns false, require also returns false. However, as the mark in table _LOADED is false, any new attempt to reload the file will happen as if the package was not loaded (that is, the package will be loaded again).

If there is any error loading or running the file, or if it cannot find any file in the path, then require signals an error.

While running a file, require defines the global variable _REQUIREDNAME with the package name. The package being loaded always runs within the global environment.

setfenv (f, table)

Sets the current environment to be used by the given function. f can be a Lua function or a number, which specifies the function at that stack level: Level 1 is the function calling setfenv.

As a special case, when f is 0 setfenv changes the global environment of the running thread.

If the original environment has a "__fenv" field, setfenv raises an error.

setmetatable (table, metatable)

Sets the metatable for the given table. (You cannot change the metatable of a userdata from Lua.) If metatable is nil, removes the metatable of the given table. If the original metatable has a "__metatable" field, raises an error.

tonumber (e [, base])

Tries to convert its argument to a number. If the argument is already a number or a string convertible to a number, then tonumber returns that number; otherwise, it returns nil.

An optional argument specifies the base to interpret the numeral. The base may be any integer between 2 and 36, inclusive. In bases above?10, the letter `A′ (in either upper or lower case) represents?10, `B′ represents?11, and so forth, with `Z′ representing 35. In base 10 (the default), the number may have a decimal part, as well as an optional exponent part (see 2.2.1). In other bases, only unsigned integers are accepted.

tostring (e)

Receives an argument of any type and converts it to a string in a reasonable format. For complete control of how numbers are converted, use format (see 5.3).

If the metatable of e has a "__tostring" field, tostring calls the corresponding value with e as argument, and uses the result of the call as its result.

type (v)

Returns the type of its only argument, coded as a string. The possible results of this function are "nil" (a string, not the value nil), "number", "string", "boolean, "table", "function", "thread", and "userdata".

unpack (list)

Returns all elements from the given list. This function is equivalent to

return list[1], list[2], ..., list[n]

except that the above code can be written only for a fixed n. The number n is the size of the list, as defined for the table.getn function.

_VERSION

A global variable (not a function) that holds a string containing the current interpreter version. The current content of this string is "Lua 5.0".

xpcall (f, err)

This function is similar to pcall, except that you can set a new error handler.

xpcall calls function f in protected mode, using err as the error handler. Any error inside f is not propagated; instead, xpcall catches the error, calls the err function with the original error object, and returns a status code. Its first result is the status code (a boolean), which is true if the call succeeds without errors. In such case, xpcall also returns all results from the call, after this first result. In case of any error, xpcall returns false plus the result from err.

5.2 - Coroutine Manipulation

The operations related to coroutines comprise a sub-library of the basic library and come inside the table coroutine. See 2.10 for a general description of coroutines.

coroutine.create (f)

Creates a new coroutine, with body f. f must be a Lua function. Returns this new coroutine, an object with type "thread".

coroutine.resume (co, val1, ...)

Starts or continues the execution of coroutine co. The first time you resume a coroutine, it starts running its body. The arguments val1, ... go as the arguments to the body function. If the coroutine has yielded, resume restarts it; the arguments val1, ... go as the results from the yield.

If the coroutine runs without any errors, resume returns true plus any values passed to yield (if the coroutine yields) or any values returned by the body function (if the coroutine terminates). If there is any error, resume returns false plus the error message.

coroutine.status (co)

Returns the status of coroutine co, as a string: "running", if the coroutine is running (that is, it called status); "suspended", if the coroutine is suspended in a call to yield, or if it has not started running yet; and "dead" if the coroutine has finished its body function, or if it has stopped with an error.

coroutine.wrap (f)

Creates a new coroutine, with body f. f must be a Lua function. Returns a function that resumes the coroutine each time it is called. Any arguments passed to the function behave as the extra arguments to resume. Returns the same values returned by resume, except the first boolean. In case of error, propagates the error.

coroutine.yield (val1, ...)

Suspends the execution of the calling coroutine. The coroutine cannot be running neither a C function, nor a metamethod, nor an iterator. Any arguments to yield go as extra results to resume.

5.3 - String Manipulation

This library provides generic functions for string manipulation, such as finding and extracting substrings, and pattern matching. When indexing a string in Lua, the first character is at position?1 (not at?0, as in C). Indices are allowed to be negative and are interpreted as indexing backwards, from the end of the string. Thus, the last character is at position -1, and so on.

The string library provides all its functions inside the table string.

string.byte (s [, i])

Returns the internal numerical code of the i-th character of s, or nil if the index is out of range. If i is absent, then it is assumed to be?1. i may be negative.

Note that numerical codes are not necessarily portable across platforms.

string.char (i1, i2, ...)

Receives 0 or more integers. Returns a string with length equal to the number of arguments, in which each character has the internal numerical code equal to its correspondent argument.

Note that numerical codes are not necessarily portable across platforms.

string.dump (function)

Returns a binary representation of the given function, so that a later loadstring on that string returns a copy of the function. function must be a Lua function without upvalues.

string.find (s, pattern [, init [, plain]])

Looks for the first match of pattern in the string s. If it finds one, then find returns the indices of?s where this occurrence starts and ends; otherwise, it returns nil. If the pattern specifies captures (see string.gsub below), the captured strings are returned as extra results. A third, optional numerical argument init specifies where to start the search; it may be negative and its default value is?1. A value of true as a fourth, optional argument plain turns off the pattern matching facilities, so the function does a plain "find substring" operation, with no characters in pattern being considered "magic". Note that if plain is given, then init must be given too.

string.len (s)

Receives a string and returns its length. The empty string "" has length 0. Embedded zeros are counted, so "a\000b\000c" has length 5.

string.lower (s)

Receives a string and returns a copy of that string with all uppercase letters changed to lowercase. All other characters are left unchanged. The definition of what is an uppercase letter depends on the current locale.

string.rep (s, n)

Returns a string that is the concatenation of n copies of the string s.

string.sub (s, i [, j])

Returns the substring of s that starts at i and continues until j; i and j may be negative. If j is absent, then it is assumed to be equal to -1 (which is the same as the string length). In particular, the call string.sub(s,1,j) returns a prefix of s with length j, and string.sub(s, -i) returns a suffix of s with length i.

string.upper (s)

Receives a string and returns a copy of that string with all lowercase letters changed to uppercase. All other characters are left unchanged. The definition of what is a lowercase letter depends on the current locale.

string.format (formatstring, e1, e2, ...)

Returns a formatted version of its variable number of arguments following the description given in its first argument (which must be a string). The format string follows the same rules as the printf family of standard C?functions. The only differences are that the options/modifiers *, l, L, n, p, and h are not supported, and there is an extra option, q. The q option formats a string in a form suitable to be safely read back by the Lua interpreter: The string is written between double quotes, and all double quotes, newlines, and backslashes in the string are correctly escaped when written. For instance, the call

string.format('%q', 'a string with "quotes" and \n new line')

will produce the string:

"a string with \"quotes\" and \new line"

The options c, d, E, e, f, g, G, i, o, u, X, and x all expect a number as argument, whereas q and s expect a string. The * modifier can be simulated by building the appropriate format string. For example, "%*g" can be simulated with "%"..width.."g".

String values to be formatted with %s cannot contain embedded zeros.

string.gfind (s, pat)

Returns an iterator function that, each time it is called, returns the next captures from pattern pat over string s.

If pat specifies no captures, then the whole match is produced in each call.

As an example, the following loop

s = "hello world from Lua"for w in string.gfind(s, "%a+") doprint(w)end

will iterate over all the words from string s, printing one per line. The next example collects all pairs key=value from the given string into a table:

t = {}s = "from=world, to=Lua"for k, v in string.gfind(s, "(%w+)=(%w+)") dot[k] = vend

string.gsub (s, pat, repl [, n])

Returns a copy of s in which all occurrences of the pattern pat have been replaced by a replacement string specified by repl. gsub also returns, as a second value, the total number of substitutions made.

If repl is a string, then its value is used for replacement. Any sequence in repl of the form %n, with n between 1 and 9, stands for the value of the n-th captured substring (see below).

If repl is a function, then this function is called every time a match occurs, with all captured substrings passed as arguments, in order; if the pattern specifies no captures, then the whole match is passed as a sole argument. If the value returned by this function is a string, then it is used as the replacement string; otherwise, the replacement string is the empty string.

The optional last parameter n limits the maximum number of substitutions to occur. For instance, when n is 1 only the first occurrence of pat is replaced.

Here are some examples:

x = string.gsub("hello world", "(%w+)", "%1 %1")--> x="hello hello world world"x = string.gsub("hello world", "(%w+)", "%1 %1", 1)--> x="hello hello world"x = string.gsub("hello world from Lua", "(%w+)%s*(%w+)", "%2 %1")--> x="world hello Lua from"x = string.gsub("home = $HOME, user = $USER", "%$(%w+)", os.getenv)--> x="home = /home/roberto, user = roberto"x = string.gsub("4+5 = $return 4+5$", "%$(.-)%$", function (s)return loadstring(s)()end)--> x="4+5 = 9"local t = {name="lua", version="5.0"}x = string.gsub("$name_$version.tar.gz", "%$(%w+)", function (v)return t[v]end)--> x="lua_5.0.tar.gz"

Patterns

A character class is used to represent a set of characters. The following combinations are allowed in describing a character class:

  • x (where x is not one of the magic characters ^$()%.[]*+-?) --- represents the character x itself.
  • . --- (a dot) represents all characters.
  • %a --- represents all letters.
  • %c --- represents all control characters.
  • %d --- represents all digits.
  • %l --- represents all lowercase letters.
  • %p --- represents all punctuation characters.
  • %s --- represents all space characters.
  • %u --- represents all uppercase letters.
  • %w --- represents all alphanumeric characters.
  • %x --- represents all hexadecimal digits.
  • %z --- represents the character with representation 0.
  • %x (where x is any non-alphanumeric character) --- represents the character x. This is the standard way to escape the magic characters. Any punctuation character (even the non magic) can be preceded by a `%′ when used to represent itself in a pattern.
  • [set] --- represents the class which is the union of all characters in set. A range of characters may be specified by separating the end characters of the range with a `-′. All classes %x described above may also be used as components in set. All other characters in set represent themselves. For example, [%w_] (or [_%w]) represents all alphanumeric characters plus the underscore, [0-7] represents the octal digits, and [0-7%l%-] represents the octal digits plus the lowercase letters plus the `-′ character.

    The interaction between ranges and classes is not defined. Therefore, patterns like [%a-z] or [a-%%] have no meaning.

  • [^set] --- represents the complement of set, where set is interpreted as above.

For all classes represented by single letters (%a, %c, etc.), the corresponding uppercase letter represents the complement of the class. For instance, %S represents all non-space characters.

The definitions of letter, space, and other character groups depend on the current locale. In particular, the class [a-z] may not be equivalent to %l. The second form should be preferred for portability.

A pattern item may be

  • a single character class, which matches any single character in the class;
  • a single character class followed by `*′, which matches 0 or more repetitions of characters in the class. These repetition items will always match the longest possible sequence;
  • a single character class followed by `+′, which matches 1 or more repetitions of characters in the class. These repetition items will always match the longest possible sequence;
  • a single character class followed by `-′, which also matches 0 or more repetitions of characters in the class. Unlike `*′, these repetition items will always match the shortest possible sequence;
  • a single character class followed by `?′, which matches 0 or 1 occurrence of a character in the class;
  • %n, for n between 1 and 9; such item matches a substring equal to the n-th captured string (see below);
  • %bxy, where x and y are two distinct characters; such item matches strings that start with?x, end with?y, and where the x and y are balanced. This means that, if one reads the string from left to right, counting +1 for an x and -1 for a y, the ending y is the first y where the count reaches 0. For instance, the item %b() matches expressions with balanced parentheses.

A pattern is a sequence of pattern items. A `^′ at the beginning of a pattern anchors the match at the beginning of the subject string. A `$′ at the end of a pattern anchors the match at the end of the subject string. At other positions, `^′ and `$′ have no special meaning and represent themselves.

A pattern may contain sub-patterns enclosed in parentheses; they describe captures. When a match succeeds, the substrings of the subject string that match captures are stored (captured) for future use. Captures are numbered according to their left parentheses. For instance, in the pattern "(a*(.)%w(%s*))", the part of the string matching "a*(.)%w(%s*)" is stored as the first capture (and therefore has number?1); the character matching . is captured with number?2, and the part matching %s* has number?3.

As a special case, the empty capture () captures the current string position (a number). For instance, if we apply the pattern "()aa()" on the string "flaaap", there will be two captures: 3 and 5.

A pattern cannot contain embedded zeros. Use %z instead.

5.4 - Table Manipulation

This library provides generic functions for table manipulation. It provides all its functions inside the table table.

Most functions in the table library assume that the table represents an array or a list. For those functions, an important concept is the size of the array. There are three ways to specify that size:

  • the field "n" --- When the table has a field "n" with a numerical value, that value is assumed as its size.
  • setn --- You can call the table.setn function to explicitly set the size of a table.
  • implicit size --- Otherwise, the size of the object is one less the first integer index with a nil value.

For more details, see the descriptions of the table.getn and table.setn functions.

table.concat (table [, sep [, i [, j]]])

Returns table[i]..sep..table[i+1] ... sep..table[j]. The default value for sep is the empty string, the default for i is 1, and the default for j is the size of the table. If i is greater than j, returns the empty string.

table.foreach (table, f)

Executes the given f over all elements of table. For each element, f is called with the index and respective value as arguments. If f returns a non-nil value, then the loop is broken, and this value is returned as the final value of foreach.

See the next function for extra information about table traversals.

table.foreachi (table, f)

Executes the given f over the numerical indices of table. For each index, f is called with the index and respective value as arguments. Indices are visited in sequential order, from?1 to n, where n is the size of the table (see 5.4). If f returns a non-nil value, then the loop is broken and this value is returned as the result of foreachi.

table.getn (table)

Returns the size of a table, when seen as a list. If the table has an n field with a numeric value, this value is the size of the table. Otherwise, if there was a previous call to table.setn over this table, the respective value is returned. Otherwise, the size is one less the first integer index with a nil value.

table.sort (table [, comp])

Sorts table elements in a given order, in-place, from table[1] to table[n], where n is the size of the table (see 5.4). If comp is given, then it must be a function that receives two table elements, and returns true when the first is less than the second (so that not comp(a[i+1],a[i]) will be true after the sort). If comp is not given, then the standard Lua operator < is used instead.

The sort algorithm is not stable, that is, elements considered equal by the given order may have their relative positions changed by the sort.

table.insert (table, [pos,] value)

Inserts element value at position pos in table, shifting up other elements to open space, if necessary. The default value for pos is n+1, where n is the size of the table (see 5.4), so that a call table.insert(t,x) inserts x at the end of table t. This function also updates the size of the table by calling table.setn(table, n+1).

table.remove (table [, pos])

Removes from table the element at position pos, shifting down other elements to close the space, if necessary. Returns the value of the removed element. The default value for pos is n, where n is the size of the table (see 5.4), so that a call table.remove(t) removes the last element of table t. This function also updates the size of the table by calling table.setn(table, n-1).

table.setn (table, n)

Updates the size of a table. If the table has a field "n" with a numerical value, that value is changed to the given n. Otherwise, it updates an internal state so that subsequent calls to table.getn(table) return n.

5.5 - Mathematical Functions

This library is an interface to most of the functions of the standard C?math library. (Some have slightly different names.) It provides all its functions inside the table math. In addition, it registers the global __pow for the binary exponentiation operator ^, so that x^y returns xy. The library provides the following functions:

math.abs math.acos math.asin math.atan math.atan2math.ceil math.cos math.deg math.exp math.floormath.log math.log10 math.max math.min math.modmath.pow math.rad math.sin math.sqrt math.tanmath.frexp math.ldexp math.random math.randomseed

plus a variable math.pi. Most of them are only interfaces to the corresponding functions in the C?library. All trigonometric functions work in radians (previous versions of Lua used degrees). The functions math.deg and math.rad convert between radians and degrees.

The function math.max returns the maximum value of its numeric arguments. Similarly, math.min computes the minimum. Both can be used with 1, 2, or more arguments.

The functions math.random and math.randomseed are interfaces to the simple random generator functions rand and srand that are provided by ANSI?C. (No guarantees can be given for their statistical properties.) When called without arguments, math.random returns a pseudo-random real number in the range [0,1). When called with a number n, math.random returns a pseudo-random integer in the range [1,n]. When called with two arguments, l and u, math.random returns a pseudo-random integer in the range [l,u]. The math.randomseed function sets a "seed" for the pseudo-random generator: Equal seeds produce equal sequences of numbers.

5.6 - Input and Output Facilities

The I/O library provides two different styles for file manipulation. The first one uses implicit file descriptors, that is, there are operations to set a default input file and a default output file, and all input/output operations are over those default files. The second style uses explicit file descriptors.

When using implicit file descriptors, all operations are supplied by table io. When using explicit file descriptors, the operation io.open returns a file descriptor and then all operations are supplied as methods by the file descriptor.

The table io also provides three predefined file descriptors with their usual meanings from C: io.stdin, io.stdout, and io.stderr.

A file handle is a userdata containing the file stream (FILE*), with a distinctive metatable created by the I/O library.

Unless otherwise stated, all I/O functions return nil on failure (plus an error message as a second result) and some value different from nil on success.

io.close ([file])

Equivalent to file:close. Without a file, closes the default output file.

io.flush ()

Equivalent to file:flush over the default output file.

io.input ([file])

When called with a file name, it opens the named file (in text mode), and sets its handle as the default input file. When called with a file handle, it simply sets that file handle as the default input file. When called without parameters, it returns the current default input file.

In case of errors this function raises the error, instead of returning an error code.

io.lines ([filename])

Opens the given file name in read mode and returns an iterator function that, each time it is called, returns a new line from the file. Therefore, the construction

for line in io.lines(filename) do ... end

will iterate over all lines of the file. When the iterator function detects the end of file, it returns nil (to finish the loop) and automatically closes the file.

The call io.lines() (without a file name) is equivalent to io.input():lines(), that is, it iterates over the lines of the default input file.

io.open (filename [, mode])

This function opens a file, in the mode specified in the string mode. It returns a new file handle, or, in case of errors, nil plus an error message.

The mode string can be any of the following:

  • "r" read mode (the default);
  • "w" write mode;
  • "a" append mode;
  • "r+" update mode, all previous data is preserved;
  • "w+" update mode, all previous data is erased;
  • "a+" append update mode, previous data is preserved, writing is only allowed at the end of file.

The mode string may also have a b at the end, which is needed in some systems to open the file in binary mode. This string is exactly what is used in the standard?C function fopen.

io.output ([file])

Similar to io.input, but operates over the default output file.

io.read (format1, ...)

Equivalent to io.input():read.

io.tmpfile ()

Returns a handle for a temporary file. This file is open in update mode and it is automatically removed when the program ends.

io.type (obj)

Checks whether obj is a valid file handle. Returns the string "file" if obj is an open file handle, "closed file" if obj is a closed file handle, and nil if obj is not a file handle.

io.write (value1, ...)

Equivalent to io.output():write.

file:close ()

Closes file.

file:flush ()

Saves any written data to file.

file:lines ()

Returns an iterator function that, each time it is called, returns a new line from the file. Therefore, the construction

for line in file:lines() do ... end

will iterate over all lines of the file. (Unlike io.lines, this function does not close the file when the loop ends.)

file:read (format1, ...)

Reads the file file, according to the given formats, which specify what to read. For each format, the function returns a string (or a number) with the characters read, or nil if it cannot read data with the specified format. When called without formats, it uses a default format that reads the entire next line (see below).

The available formats are

  • "*n" reads a number; this is the only format that returns a number instead of a string.
  • "*a" reads the whole file, starting at the current position. On end of file, it returns the empty string.
  • "*l" reads the next line (skipping the end of line), returning nil on end of file. This is the default format.
  • number reads a string with up to that number of characters, returning nil on end of file. If number is zero, it reads nothing and returns an empty string, or nil on end of file.

file:seek ([whence] [, offset])

Sets and gets the file position, measured from the beginning of the file, to the position given by offset plus a base specified by the string whence, as follows:

  • "set" base is position 0 (beginning of the file);
  • "cur" base is current position;
  • "end" base is end of file;

In case of success, function seek returns the final file position, measured in bytes from the beginning of the file. If this function fails, it returns nil, plus a string describing the error.

The default value for whence is "cur", and for offset is 0. Therefore, the call file:seek() returns the current file position, without changing it; the call file:seek("set") sets the position to the beginning of the file (and returns 0); and the call file:seek("end") sets the position to the end of the file, and returns its size.

file:write (value1, ...)

Writes the value of each of its arguments to the filehandle file. The arguments must be strings or numbers. To write other values, use tostring or string.format before write.

5.7 - Operating System Facilities

This library is implemented through table os.

os.clock ()

Returns an approximation of the amount of CPU time used by the program, in seconds.

os.date ([format [, time]])

Returns a string or a table containing date and time, formatted according to the given string format.

If the time argument is present, this is the time to be formatted (see the os.time function for a description of this value). Otherwise, date formats the current time.

If format starts with `!′, then the date is formatted in Coordinated Universal Time. After that optional character, if format is *t, then date returns a table with the following fields: year (four digits), month (1--12), day (1--31), hour (0--23), min (0--59), sec (0--61), wday (weekday, Sunday is?1), yday (day of the year), and isdst (daylight saving flag, a boolean).

If format is not *t, then date returns the date as a string, formatted according to the same rules as the C?function strftime.

When called without arguments, date returns a reasonable date and time representation that depends on the host system and on the current locale (that is, os.date() is equivalent to os.date("%c")).

os.difftime (t2, t1)

Returns the number of seconds from time t1 to time t2. In Posix, Windows, and some other systems, this value is exactly t2-t1.

os.execute (command)

This function is equivalent to the C?function system. It passes command to be executed by an operating system shell. It returns a status code, which is system-dependent.

os.exit ([code])

Calls the C?function exit, with an optional code, to terminate the host program. The default value for code is the success code.

os.getenv (varname)

Returns the value of the process environment variable varname, or nil if the variable is not defined.

os.remove (filename)

Deletes the file with the given name. If this function fails, it returns nil, plus a string describing the error.

os.rename (oldname, newname)

Renames file named oldname to newname. If this function fails, it returns nil, plus a string describing the error.

os.setlocale (locale [, category])

Sets the current locale of the program. locale is a string specifying a locale; category is an optional string describing which category to change: "all", "collate", "ctype", "monetary", "numeric", or "time"; the default category is "all". The function returns the name of the new locale, or nil if the request cannot be honored.

os.time ([table])

Returns the current time when called without arguments, or a time representing the date and time specified by the given table. This table must have fields year, month, and day, and may have fields hour, min, sec, and isdst (for a description of these fields, see the os.date function).

The returned value is a number, whose meaning depends on your system. In Posix, Windows, and some other systems, this number counts the number of seconds since some given start time (the "epoch"). In other systems, the meaning is not specified, and the number returned by time can be used only as an argument to date and difftime.

os.tmpname ()

Returns a string with a file name that can be used for a temporary file. The file must be explicitly opened before its use and removed when no longer needed.

This function is equivalent to the tmpnam C?function, and many people (and even some compilers!) advise against its use, because between the time you call this function and the time you open the file, it is possible for another process to create a file with the same name.

5.8 - The Reflexive Debug Interface

The debug library provides the functionality of the debug interface to Lua programs. You should exert care when using this library. The functions provided here should be used exclusively for debugging and similar tasks, such as profiling. Please resist the temptation to use them as a usual programming tool: They can be very slow. Moreover, setlocal and getlocal violate the privacy of local variables and therefore can compromise some otherwise secure code.

All functions in this library are provided inside a debug table.

debug.debug ()

Enters an interactive mode with the user, running each string that the user enters. Using simple commands and other debug facilities, the user can inspect global and local variables, change their values, evaluate expressions, and so on. A line containing only the word cont finishes this function, so that the caller continues its execution.

Note that commands for debug.debug are not lexically nested with any function, so they have no direct access to local variables.

debug.gethook ()

Returns the current hook settings, as three values: the current hook function, the current hook mask, and the current hook count (as set by the debug.sethook function).

debug.getinfo (function [, what])

This function returns a table with information about a function. You can give the function directly, or you can give a number as the value of function, which means the function running at level function of the call stack: Level 0 is the current function (getinfo itself); level 1 is the function that called getinfo; and so on. If function is a number larger than the number of active functions, then getinfo returns nil.

The returned table contains all the fields returned by lua_getinfo, with the string what describing which fields to fill in. The default for what is to get all information available. If present, the option `f′ adds a field named func with the function itself.

For instance, the expression debug.getinfo(1,"n").name returns the name of the current function, if a reasonable name can be found, and debug.getinfo(print) returns a table with all available information about the print function.

debug.getlocal (level, local)

This function returns the name and the value of the local variable with index local of the function at level level of the stack. (The first parameter or local variable has index?1, and so on, until the last active local variable.) The function returns nil if there is no local variable with the given index, and raises an error when called with a level out of range. (You can call debug.getinfo to check whether the level is valid.)

debug.getupvalue (func, up)

This function returns the name and the value of the upvalue with index up of the function func. The function returns nil if there is no upvalue with the given index.

debug.setlocal (level, local, value)

This function assigns the value value to the local variable with index local of the function at level level of the stack. The function returns nil if there is no local variable with the given index, and raises an error when called with a level out of range. (You can call getinfo to check whether the level is valid.)

debug.setupvalue (func, up, value)

This function assigns the value value to the upvalue with index up of the function func. The function returns nil if there is no upvalue with the given index.

debug.sethook (hook, mask [, count])

Sets the given function as a hook. The string mask and the number count describe when the hook will be called. The string mask may have the following characters, with the given meaning:

  • "c" The hook is called every time Lua calls a function;
  • "r" The hook is called every time Lua returns from a function;
  • "l" The hook is called every time Lua enters a new line of code.

With a count different from zero, the hook is called after every count instructions.

When called without arguments, the debug.sethook function turns off the hook.

When the hook is called, its first parameter is always a string describing the event that triggered its call: "call", "return" (or "tail return"), "line", and "count". Moreover, for line events, it also gets as its second parameter the new line number. Inside a hook, you can call getinfo with level 2 to get more information about the running function (level?0 is the getinfo function, and level?1 is the hook function), unless the event is "tail return". In this case, Lua is only simulating the return, and a call to getinfo will return invalid data.

debug.traceback ([message])

Returns a string with a traceback of the call stack. An optional message string is appended at the beginning of the traceback. This function is typically used with xpcall to produce better error messages.

6 - Lua 獨立程序 Lua Stand-alone

盡管Lua被設計為一種內嵌于C 語言宿主程序中的擴展語言,它還是經常被用作一個獨立程序語言。一個Lua的解釋程序將Lua作為一個獨立的語言,我們稱之為簡化的 lua,它提供了標準的發行版本。獨立的解釋器包含了所有標準庫加上反射性的調試接口。它的使用方式如下:

lua [options] [script [args]]

options 可以是以下內容:

  • - 將 標準輸入(stdin) 當作文件執行;
  • -e stat 執行字符串 stat;
  • -l file “需要”file 文件;
  • -i 在運行腳本后進入交互模式;
  • -v 打印版本信息;
  • -- 停止處理選項。

在停止處理選項后,lua 運行所給的腳本,傳遞所給參數 args。當無參數調用時,lua 就像 stdin 是程序的終結時 lua -v -i 所表現的一樣,而且還與 lua- 一樣。

Before running any argument, the interpreter checks for an environment variable LUA_INIT. If its format is @filename, then lua executes the file. Otherwise, lua executes the string itself.

All options are handled in order, except -i. For instance, an invocation like

$ lua -e'a=1' -e 'print(a)' script.lua

will first set a to 1, then print a, and finally run the file script.lua. (Here, $ is the shell prompt. Your prompt may be different.)

Before starting to run the script, lua collects all arguments in the command line in a global table called arg. The script name is stored in index 0, the first argument after the script name goes to index 1, and so on. The field n gets the number of arguments after the script name. Any arguments before the script name (that is, the interpreter name plus the options) go to negative indices. For instance, in the call

$ lua -la.lua b.lua t1 t2

the interpreter first runs the file a.lua, then creates a table

arg = { [-2] = "lua", [-1] = "-la.lua", [0] = "b.lua",[1] = "t1", [2] = "t2"; n = 2 }

and finally runs the file b.lua.

在交互模式中,如果你寫入了一個不完整的語句,解釋器將等待你的完成。

If the global variable _PROMPT is defined as a string, then its value is used as the prompt. Therefore, the prompt can be changed directly on the command line:

$ lua -e"_PROMPT='myprompt> '" -i

(the outer pair of quotes is for the shell, the inner is for Lua), or in any Lua programs by assigning to _PROMPT. Note the use of -i to enter interactive mode; otherwise, the program would end just after the assignment to _PROMPT.

在Unix系統中,Lua腳本可以用 chmod +x 將其變成可執行程序,并且通過 #! 形式,例如

#!/usr/local/bin/lua

(當然,Lua解釋器的位置可能有所不同,如果 lua 在你的 PATH 中,那么

#!/usr/bin/env lua

就是一個更通用的解決方案。)

致謝

The Lua team is grateful to Tecgraf for its continued support to Lua. We thank everyone at Tecgraf, specially the head of the group, Marcelo Gattass. At the risk of omitting several names, we also thank the following individuals for supporting, contributing to, and spreading the word about Lua: Alan Watson. André Clinio, André Costa, Antonio Scuri, Asko Kauppi, Bret Mogilefsky, Cameron Laird, Carlos Cassino, Carlos Henrique Levy, Claudio Terra, David Jeske, Ed Ferguson, Edgar Toernig, Erik Hougaard, Jim Mathies, John Belmonte, John Passaniti, John Roll, Jon Erickson, Jon Kleiser, Mark Ian Barlow, Nick Trout, Noemi Rodriguez, Norman Ramsey, Philippe Lhoste, Renata Ratton, Renato Borges, Renato Cerqueira, Reuben Thomas, Stephan Herrmann, Steve Dekorte, Thatcher Ulrich, Tomás Gorham, Vincent Penquerc'h. Thank you!


與以前版本的不兼容性 Incompatibilities with Previous Versions

Lua 5.0 是一個主版本,所有與 Lua 4.0 有一些地方不兼容。

與 v4.0 的不兼容性 Incompatibilities with version 4.0

語言上的變動

  • 整個標簽方法模式被元表所替代。The whole tag-method scheme was replaced by metatables.
  • Function calls written between parentheses result in exactly one value.
  • A function call as the last expression in a list constructor (like {a,b,f()}) has all its return values inserted in the list.
  • The precedence of or is smaller than the precedence of and.
  • in, false, and true are reserved words.
  • The old construction for k,v in t, where t is a table, is deprecated (although it is still supported). Use for k,v in pairs(t) instead.
  • When a literal string of the form [[...]] starts with a newline, this newline is ignored.
  • Upvalues in the form %var are obsolete; use external local variables instead.

庫的變更

  • Most library functions now are defined inside tables. There is a compatibility script (compat.lua) that redefines most of them as global names.
  • In the math library, angles are expressed in radians. With the compatibility script (compat.lua), functions still work in degrees.
  • The call function is deprecated. Use f(unpack(tab)) instead of call(f, tab) for unprotected calls, or the new pcall function for protected calls.
  • dofile does not handle errors, but simply propagates them.
  • dostring is deprecated. Use loadstring instead.
  • The read option *w is obsolete.
  • The format option %n$ is obsolete.

API 上的改動

  • lua_open 不再需要堆棧大小作為參數(堆棧是動態的)。
  • lua_pushuserdata 已經被廢除了。使用 lua_newuserdata 或 lua_pushlightuserdata 來代替它。

Lua 完整語法參考

chunk ::= {stat [`;′]} block ::= chunk stat ::= varlist1 `=′ explist1 | functioncall | do block end | while exp do block end | repeat block until exp | if exp then block {elseif exp then block} [else block] end | return [explist1] | break | for Name `=′ exp `,′ exp [`,′ exp] do block end | for Name {`,′ Name} in explist1 do block end | function funcname funcbody | localfunction Name funcbody | local namelist [init] funcname ::= Name {`.′ Name} [`:′ Name] varlist1 ::= var {`,′ var} var ::= Name | prefixexp `[′ exp `]′ | prefixexp `.′ Name namelist ::= Name {`,′ Name} init ::= `=′ explist1 explist1 ::= {exp `,′} exp exp ::= nil | false | true | Number | Literal | function | prefixexp | tableconstructor | exp binop exp | unop exp prefixexp ::= var | functioncall | `(′ exp `)′ functioncall ::= prefixexp args | prefixexp `:′ Name args args ::= `(′ [explist1] `)′ | tableconstructor | Literal function ::= function funcbody funcbody ::= `(′ [parlist1] `)′ block end parlist1 ::= Name {`,′ Name} [`,′ `...′] | `...′ tableconstructor ::= `{′ [fieldlist] `}′ fieldlist ::= field {fieldsep field} [fieldsep] field ::= `[′ exp `]′ `=′ exp | name `=′ exp | exp fieldsep ::= `,′ | `;′ binop ::= `+′ | `-′ | `*′ | `/′ | `^′ | `..′ | `<′ | `<=′ | `>′ | `>=′ | `==′ | `~=′ | and | or unop ::= `-′ | not

總結

以上是生活随笔為你收集整理的【转贴】Lua 5.0 参考手册的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

亚洲s码欧洲m码国产av | 奇米影视888欧美在线观看 | 亚洲人成人无码网www国产 | 偷窥日本少妇撒尿chinese | 一个人看的www免费视频在线观看 | 国产做国产爱免费视频 | 四虎永久在线精品免费网址 | 青草视频在线播放 | 日日摸夜夜摸狠狠摸婷婷 | 亚洲熟妇色xxxxx欧美老妇 | 成年女人永久免费看片 | 国内精品九九久久久精品 | 蜜桃av蜜臀av色欲av麻 999久久久国产精品消防器材 | 国产偷抇久久精品a片69 | 国产精品二区一区二区aⅴ污介绍 | 国产av人人夜夜澡人人爽麻豆 | 国产真实伦对白全集 | 大色综合色综合网站 | 久久99国产综合精品 | 性生交大片免费看l | 婷婷综合久久中文字幕蜜桃三电影 | 亚洲成a人片在线观看无码3d | 日韩精品乱码av一区二区 | 丰满人妻翻云覆雨呻吟视频 | 婷婷丁香五月天综合东京热 | 欧洲欧美人成视频在线 | 日韩欧美成人免费观看 | 色婷婷综合中文久久一本 | 无码一区二区三区在线 | 一本无码人妻在中文字幕免费 | 国产国语老龄妇女a片 | 日本又色又爽又黄的a片18禁 | 午夜福利一区二区三区在线观看 | www一区二区www免费 | 国产综合久久久久鬼色 | 国产又粗又硬又大爽黄老大爷视 | 捆绑白丝粉色jk震动捧喷白浆 | 欧美日韩色另类综合 | 国产9 9在线 | 中文 | 亚洲综合在线一区二区三区 | 97精品国产97久久久久久免费 | 亚洲精品午夜无码电影网 | 国产精品亚洲а∨无码播放麻豆 | 双乳奶水饱满少妇呻吟 | 无码成人精品区在线观看 | 久久这里只有精品视频9 | 久久天天躁狠狠躁夜夜免费观看 | 99久久久无码国产精品免费 | 久久久久久久久蜜桃 | 精品一二三区久久aaa片 | 大地资源中文第3页 | 精品无码av一区二区三区 | 高潮喷水的毛片 | 色一情一乱一伦 | 国产疯狂伦交大片 | 亚洲精品国偷拍自产在线麻豆 | 国产亚洲精品久久久久久国模美 | 国产精品久久久久久亚洲影视内衣 | 人妻少妇精品久久 | 国产97色在线 | 免 | 国产亚洲欧美日韩亚洲中文色 | 国产午夜亚洲精品不卡 | 亚洲日本va午夜在线电影 | 国内老熟妇对白xxxxhd | 精品乱码久久久久久久 | 一本色道久久综合狠狠躁 | 国产97在线 | 亚洲 | 蜜桃臀无码内射一区二区三区 | 亚洲精品无码国产 | 亚洲中文字幕无码一久久区 | 免费乱码人妻系列无码专区 | 国产激情精品一区二区三区 | 性生交大片免费看l | 国产精品多人p群无码 | 免费观看的无遮挡av | 牛和人交xxxx欧美 | 亚洲人亚洲人成电影网站色 | 亚洲中文字幕av在天堂 | 亚洲人亚洲人成电影网站色 | 亚洲区小说区激情区图片区 | 精品国产一区二区三区四区 | 日本熟妇乱子伦xxxx | 麻豆国产97在线 | 欧洲 | 狠狠综合久久久久综合网 | 理论片87福利理论电影 | 国产小呦泬泬99精品 | 88国产精品欧美一区二区三区 | 久久亚洲国产成人精品性色 | 久久久无码中文字幕久... | av在线亚洲欧洲日产一区二区 | 狠狠噜狠狠狠狠丁香五月 | 特黄特色大片免费播放器图片 | 国产欧美熟妇另类久久久 | 国产69精品久久久久app下载 | 又湿又紧又大又爽a视频国产 | 国产在线精品一区二区三区直播 | 国产精品久免费的黄网站 | 人妻少妇精品视频专区 | 九九在线中文字幕无码 | 欧美亚洲日韩国产人成在线播放 | 日日摸夜夜摸狠狠摸婷婷 | 中文字幕日韩精品一区二区三区 | 国产一区二区三区影院 | 97色伦图片97综合影院 | 久久人妻内射无码一区三区 | 免费观看的无遮挡av | 一二三四在线观看免费视频 | 四虎国产精品免费久久 | 樱花草在线播放免费中文 | 国产免费无码一区二区视频 | 一个人免费观看的www视频 | 在线精品国产一区二区三区 | 天堂亚洲免费视频 | 人人妻人人澡人人爽欧美一区 | 国产精品久免费的黄网站 | 成人亚洲精品久久久久软件 | 亚洲精品中文字幕乱码 | 成人av无码一区二区三区 | 天堂а√在线地址中文在线 | 久久久国产精品无码免费专区 | 精品国产av色一区二区深夜久久 | 大屁股大乳丰满人妻 | 精品无码一区二区三区的天堂 | 初尝人妻少妇中文字幕 | 亚洲啪av永久无码精品放毛片 | a在线亚洲男人的天堂 | 鲁大师影院在线观看 | 99国产欧美久久久精品 | 麻豆蜜桃av蜜臀av色欲av | 亚洲国产av精品一区二区蜜芽 | 精品乱码久久久久久久 | 又大又紧又粉嫩18p少妇 | 亚洲精品一区二区三区大桥未久 | 成年女人永久免费看片 | 日韩av无码中文无码电影 | 国产精华av午夜在线观看 | 高清国产亚洲精品自在久久 | 亲嘴扒胸摸屁股激烈网站 | 国产免费久久精品国产传媒 | 男女性色大片免费网站 | 东京热无码av男人的天堂 | 人妻少妇精品无码专区二区 | 欧美性生交xxxxx久久久 | 午夜精品一区二区三区在线观看 | 亚洲熟悉妇女xxx妇女av | 国产午夜无码精品免费看 | 丰满少妇熟乱xxxxx视频 | 国产乱码精品一品二品 | 亚洲爆乳精品无码一区二区三区 | 老太婆性杂交欧美肥老太 | 麻豆成人精品国产免费 | 日本www一道久久久免费榴莲 | 亚洲男人av天堂午夜在 | 丰满人妻一区二区三区免费视频 | 欧美人与善在线com | 无遮无挡爽爽免费视频 | 日本爽爽爽爽爽爽在线观看免 | 亚洲一区二区观看播放 | 亚洲人成网站色7799 | 久久午夜夜伦鲁鲁片无码免费 | 荫蒂添的好舒服视频囗交 | 国产人妻久久精品二区三区老狼 | 国产九九九九九九九a片 | 中文精品无码中文字幕无码专区 | 欧洲精品码一区二区三区免费看 | 亚洲精品国产精品乱码不卡 | 国产亚洲精品精品国产亚洲综合 | 乱人伦人妻中文字幕无码久久网 | 噜噜噜亚洲色成人网站 | 成人影院yy111111在线观看 | 蜜桃av抽搐高潮一区二区 | 亚洲乱码中文字幕在线 | 日日碰狠狠丁香久燥 | 精品国产一区av天美传媒 | 国内丰满熟女出轨videos | 欧美老妇交乱视频在线观看 | 国产精品二区一区二区aⅴ污介绍 | 欧美一区二区三区 | 欧美刺激性大交 | 高潮毛片无遮挡高清免费视频 | 国产人妻久久精品二区三区老狼 | 国产精品第一区揄拍无码 | 中文字幕乱码人妻二区三区 | 中文无码成人免费视频在线观看 | 天堂久久天堂av色综合 | 中文字幕av日韩精品一区二区 | 国产麻豆精品精东影业av网站 | 成人性做爰aaa片免费看 | 国产亚av手机在线观看 | 网友自拍区视频精品 | 日本大香伊一区二区三区 | 欧洲精品码一区二区三区免费看 | 午夜精品一区二区三区的区别 | 久久99精品国产麻豆蜜芽 | 日韩人妻无码中文字幕视频 | 波多野结衣乳巨码无在线观看 | 最近免费中文字幕中文高清百度 | 久久综合激激的五月天 | 2020久久超碰国产精品最新 | 国产人妻大战黑人第1集 | 99国产精品白浆在线观看免费 | 日韩人妻无码一区二区三区久久99 | 狠狠色噜噜狠狠狠7777奇米 | 日本高清一区免费中文视频 | 中文字幕色婷婷在线视频 | 成人影院yy111111在线观看 | 国产精品无码mv在线观看 | 亚洲成av人片在线观看无码不卡 | 99久久精品午夜一区二区 | 精品亚洲韩国一区二区三区 | 午夜熟女插插xx免费视频 | 亚洲一区二区三区含羞草 | 色五月丁香五月综合五月 | 亚洲人成网站在线播放942 | 天天爽夜夜爽夜夜爽 | 国产亚洲精品精品国产亚洲综合 | 美女毛片一区二区三区四区 | 少妇一晚三次一区二区三区 | 亚洲精品中文字幕乱码 | 在线精品亚洲一区二区 | 日本一卡2卡3卡4卡无卡免费网站 国产一区二区三区影院 | 99久久婷婷国产综合精品青草免费 | 丁香啪啪综合成人亚洲 | 水蜜桃亚洲一二三四在线 | 老太婆性杂交欧美肥老太 | 亚洲一区二区三区含羞草 | 国产欧美熟妇另类久久久 | 免费男性肉肉影院 | 无码人妻丰满熟妇区毛片18 | 国产麻豆精品精东影业av网站 | 人人澡人摸人人添 | 亚洲 另类 在线 欧美 制服 | 大肉大捧一进一出好爽视频 | 97色伦图片97综合影院 | 欧美丰满老熟妇xxxxx性 | 精品国产一区二区三区av 性色 | 未满小14洗澡无码视频网站 | 色婷婷久久一区二区三区麻豆 | 1000部夫妻午夜免费 | 欧美性生交xxxxx久久久 | 国产乱人偷精品人妻a片 | 粗大的内捧猛烈进出视频 | 国产av一区二区三区最新精品 | 亚洲高清偷拍一区二区三区 | 日日碰狠狠丁香久燥 | 成在人线av无码免费 | 两性色午夜免费视频 | 久青草影院在线观看国产 | 亚洲精品国偷拍自产在线麻豆 | 欧美激情综合亚洲一二区 | 精品国产一区二区三区av 性色 | 老熟妇乱子伦牲交视频 | 97se亚洲精品一区 | 久久午夜无码鲁丝片 | 亚洲综合久久一区二区 | 十八禁视频网站在线观看 | 国产黑色丝袜在线播放 | 亚洲欧美综合区丁香五月小说 | 中文无码精品a∨在线观看不卡 | 性欧美疯狂xxxxbbbb | 99精品视频在线观看免费 | 国产在线精品一区二区高清不卡 | 精品厕所偷拍各类美女tp嘘嘘 | 中文字幕人成乱码熟女app | 精品国产青草久久久久福利 | 综合网日日天干夜夜久久 | 国产精品嫩草久久久久 | 77777熟女视频在线观看 а天堂中文在线官网 | 亚洲 a v无 码免 费 成 人 a v | 国产高清av在线播放 | 国产精品va在线观看无码 | 久久午夜无码鲁丝片 | 亚洲a无码综合a国产av中文 | 亚洲中文字幕久久无码 | 亚洲国产一区二区三区在线观看 | 性生交大片免费看l | 国产人妻精品一区二区三区不卡 | 国产凸凹视频一区二区 | 波多野42部无码喷潮在线 | 国产精品a成v人在线播放 | 亚洲va欧美va天堂v国产综合 | 成人试看120秒体验区 | 中文字幕 人妻熟女 | 成人影院yy111111在线观看 | 欧美freesex黑人又粗又大 | 欧美性猛交内射兽交老熟妇 | 精品国精品国产自在久国产87 | 免费网站看v片在线18禁无码 | 国产亚洲日韩欧美另类第八页 | 国产一区二区三区日韩精品 | 在线看片无码永久免费视频 | 精品国产乱码久久久久乱码 | 国产区女主播在线观看 | 精品午夜福利在线观看 | 国产明星裸体无码xxxx视频 | 成人免费视频视频在线观看 免费 | 无遮无挡爽爽免费视频 | 国产人妻精品午夜福利免费 | 夜夜高潮次次欢爽av女 | 国产精品无码一区二区三区不卡 | 国产亚洲精品久久久久久久久动漫 | 18禁止看的免费污网站 | 久久天天躁夜夜躁狠狠 | 成人影院yy111111在线观看 | 亚洲精品综合五月久久小说 | 国产免费久久精品国产传媒 | 疯狂三人交性欧美 | 国产黄在线观看免费观看不卡 | 又色又爽又黄的美女裸体网站 | 日本熟妇人妻xxxxx人hd | 国产精品免费大片 | 永久黄网站色视频免费直播 | 又紧又大又爽精品一区二区 | 久久久久99精品成人片 | 福利一区二区三区视频在线观看 | 东京无码熟妇人妻av在线网址 | 一本色道久久综合亚洲精品不卡 | а√资源新版在线天堂 | 欧美黑人性暴力猛交喷水 | 天天摸天天透天天添 | 国产热a欧美热a在线视频 | 国产疯狂伦交大片 | 亚洲精品一区三区三区在线观看 | 精品久久久久香蕉网 | 青草青草久热国产精品 | 国产精品理论片在线观看 | 人妻有码中文字幕在线 | 国产精品第一国产精品 | 中文字幕无码免费久久9一区9 | 丰满少妇弄高潮了www | 亚洲日韩av一区二区三区中文 | 99精品无人区乱码1区2区3区 | 曰本女人与公拘交酡免费视频 | 色老头在线一区二区三区 | 极品尤物被啪到呻吟喷水 | 精品国产青草久久久久福利 | 男女性色大片免费网站 | 欧美亚洲日韩国产人成在线播放 | 露脸叫床粗话东北少妇 | 亚洲精品午夜无码电影网 | 国产特级毛片aaaaaaa高清 | 欧美丰满熟妇xxxx性ppx人交 | 欧美熟妇另类久久久久久不卡 | 澳门永久av免费网站 | 欧美性猛交内射兽交老熟妇 | 扒开双腿疯狂进出爽爽爽视频 | 亚洲乱码中文字幕在线 | 97夜夜澡人人双人人人喊 | 亚洲欧美国产精品专区久久 | 欧美三级不卡在线观看 | 国产精品人人妻人人爽 | 亚洲中文字幕无码中文字在线 | 日本又色又爽又黄的a片18禁 | 无码帝国www无码专区色综合 | 小泽玛莉亚一区二区视频在线 | 撕开奶罩揉吮奶头视频 | 天海翼激烈高潮到腰振不止 | 欧美怡红院免费全部视频 | 精品无码一区二区三区爱欲 | 国产精品18久久久久久麻辣 | 亚洲国产一区二区三区在线观看 | 伦伦影院午夜理论片 | 亚洲精品国产第一综合99久久 | 中文字幕中文有码在线 | 99久久精品无码一区二区毛片 | 国产亲子乱弄免费视频 | 在线观看国产一区二区三区 | 任你躁国产自任一区二区三区 | 狂野欧美性猛xxxx乱大交 | 99视频精品全部免费免费观看 | 色综合天天综合狠狠爱 | 亚洲最大成人网站 | 熟妇人妻中文av无码 | 亲嘴扒胸摸屁股激烈网站 | 婷婷综合久久中文字幕蜜桃三电影 | 日本一卡2卡3卡4卡无卡免费网站 国产一区二区三区影院 | 漂亮人妻洗澡被公强 日日躁 | 少妇的肉体aa片免费 | 精品国产aⅴ无码一区二区 | 亚洲国产午夜精品理论片 | 又粗又大又硬又长又爽 | 麻豆蜜桃av蜜臀av色欲av | 国产成人精品必看 | 人妻aⅴ无码一区二区三区 | 最新国产麻豆aⅴ精品无码 | 水蜜桃av无码 | 亚欧洲精品在线视频免费观看 | 国产偷国产偷精品高清尤物 | 人妻有码中文字幕在线 | 中文无码精品a∨在线观看不卡 | 国产性生大片免费观看性 | av无码电影一区二区三区 | 午夜无码人妻av大片色欲 | 亚洲色欲久久久综合网东京热 | 狠狠色噜噜狠狠狠狠7777米奇 | 男女作爱免费网站 | 高中生自慰www网站 | 亚洲熟熟妇xxxx | 久久婷婷五月综合色国产香蕉 | 高潮毛片无遮挡高清免费 | 色婷婷香蕉在线一区二区 | 国产精品久久久久7777 | 日本护士xxxxhd少妇 | 久久无码中文字幕免费影院蜜桃 | 好男人社区资源 | 亚无码乱人伦一区二区 | 亚洲成a人片在线观看日本 | 18禁黄网站男男禁片免费观看 | 2019nv天堂香蕉在线观看 | 国内精品一区二区三区不卡 | 精品 日韩 国产 欧美 视频 | 国产女主播喷水视频在线观看 | 无码乱肉视频免费大全合集 | 国产精品对白交换视频 | 波多野42部无码喷潮在线 | 波多野结衣一区二区三区av免费 | 国产色视频一区二区三区 | 精品无码国产一区二区三区av | 内射白嫩少妇超碰 | 2020久久香蕉国产线看观看 | 中文字幕人妻无码一夲道 | 亚无码乱人伦一区二区 | 欧美自拍另类欧美综合图片区 | 98国产精品综合一区二区三区 | 婷婷色婷婷开心五月四房播播 | 久久国产精品偷任你爽任你 | 国产内射老熟女aaaa | 日日躁夜夜躁狠狠躁 | 性色欲网站人妻丰满中文久久不卡 | а√资源新版在线天堂 | 久久久久久久人妻无码中文字幕爆 | 性生交大片免费看女人按摩摩 | 无码国模国产在线观看 | 国产成人综合色在线观看网站 | 美女扒开屁股让男人桶 | 2020久久超碰国产精品最新 | 亚洲人成无码网www | 自拍偷自拍亚洲精品10p | 亚洲色偷偷男人的天堂 | 熟妇女人妻丰满少妇中文字幕 | 亚洲中文字幕在线观看 | 偷窥村妇洗澡毛毛多 | 色一情一乱一伦一视频免费看 | 亚洲精品国偷拍自产在线观看蜜桃 | 一本大道伊人av久久综合 | 国产性猛交╳xxx乱大交 国产精品久久久久久无码 欧洲欧美人成视频在线 | 久久精品女人的天堂av | 色欲人妻aaaaaaa无码 | 免费男性肉肉影院 | 亚洲日本在线电影 | 色综合久久中文娱乐网 | 久9re热视频这里只有精品 | 亚洲中文字幕在线无码一区二区 | 55夜色66夜色国产精品视频 | 在线а√天堂中文官网 | 国内精品一区二区三区不卡 | 无码任你躁久久久久久久 | 久久99热只有频精品8 | 精品国产一区二区三区av 性色 | 国产suv精品一区二区五 | 久久天天躁狠狠躁夜夜免费观看 | 综合激情五月综合激情五月激情1 | 亚洲一区二区三区四区 | 国产成人精品一区二区在线小狼 | 亚洲 a v无 码免 费 成 人 a v | 激情爆乳一区二区三区 | 国产麻豆精品一区二区三区v视界 | 久久五月精品中文字幕 | 扒开双腿疯狂进出爽爽爽视频 | 欧美阿v高清资源不卡在线播放 | 亚洲人成网站免费播放 | 波多野结衣一区二区三区av免费 | 亚洲综合无码久久精品综合 | 图片区 小说区 区 亚洲五月 | 国产成人久久精品流白浆 | 女人色极品影院 | 亚洲日本va中文字幕 | 欧美一区二区三区视频在线观看 | 久久综合给久久狠狠97色 | 亚洲啪av永久无码精品放毛片 | 精品无码一区二区三区爱欲 | 国产后入清纯学生妹 | 国产精品久久国产三级国 | 18禁黄网站男男禁片免费观看 | 久久国产精品_国产精品 | 好男人社区资源 | 亚洲中文字幕无码中文字在线 | 内射白嫩少妇超碰 | 熟妇人妻无乱码中文字幕 | 日本又色又爽又黄的a片18禁 | 日韩成人一区二区三区在线观看 | 夫妻免费无码v看片 | 亚洲阿v天堂在线 | 国产精品办公室沙发 | 欧美色就是色 | 国产成人一区二区三区在线观看 | 亚洲va中文字幕无码久久不卡 | 日韩精品乱码av一区二区 | 人妻无码αv中文字幕久久琪琪布 | 精品一二三区久久aaa片 | 久久精品无码一区二区三区 | 狂野欧美激情性xxxx | 精品无码成人片一区二区98 | 人妻少妇精品无码专区二区 | 人妻少妇精品无码专区二区 | 亚洲精品综合五月久久小说 | 欧美第一黄网免费网站 | 精品无人国产偷自产在线 | 精品国产乱码久久久久乱码 | 亚洲综合色区中文字幕 | 无码av免费一区二区三区试看 | 中文字幕无码免费久久9一区9 | 亚拍精品一区二区三区探花 | 久久精品人妻少妇一区二区三区 | 狠狠cao日日穞夜夜穞av | 国产精品无码一区二区三区不卡 | 亚洲天堂2017无码中文 | 东京热男人av天堂 | 亚洲精品无码国产 | 四十如虎的丰满熟妇啪啪 | 中文亚洲成a人片在线观看 | 永久免费观看国产裸体美女 | 好男人社区资源 | 精品无人区无码乱码毛片国产 | 日韩精品一区二区av在线 | 亚洲狠狠婷婷综合久久 | www国产亚洲精品久久网站 | 日本一区二区三区免费高清 | 永久免费观看美女裸体的网站 | 国产一区二区三区精品视频 | 国产精品爱久久久久久久 | 欧美激情综合亚洲一二区 | 日韩欧美成人免费观看 | 国产在线一区二区三区四区五区 | 亚洲日本va午夜在线电影 | 日韩无套无码精品 | 婷婷综合久久中文字幕蜜桃三电影 | 97精品人妻一区二区三区香蕉 | 高清国产亚洲精品自在久久 | 久久国产精品二国产精品 | 日韩av无码一区二区三区 | 国产无av码在线观看 | 2019午夜福利不卡片在线 | 狂野欧美性猛交免费视频 | 波多野结衣乳巨码无在线观看 | 老头边吃奶边弄进去呻吟 | 午夜熟女插插xx免费视频 | 天天燥日日燥 | 少妇性俱乐部纵欲狂欢电影 | 日本www一道久久久免费榴莲 | 国产乱子伦视频在线播放 | 亚洲中文字幕无码中字 | 精品偷自拍另类在线观看 | 亚洲经典千人经典日产 | 中文字幕+乱码+中文字幕一区 | 国产人妖乱国产精品人妖 | 国内精品人妻无码久久久影院蜜桃 | 激情国产av做激情国产爱 | 亚洲狠狠婷婷综合久久 | 在线天堂新版最新版在线8 | 欧美丰满少妇xxxx性 | 成人免费无码大片a毛片 | 色妞www精品免费视频 | 亚洲国产精品无码一区二区三区 | 综合激情五月综合激情五月激情1 | 欧美放荡的少妇 | 麻豆md0077饥渴少妇 | 精品久久久无码中文字幕 | 亚洲一区二区三区偷拍女厕 | 欧美国产日韩久久mv | 久久国产精品_国产精品 | 亚洲人成影院在线观看 | 日韩精品一区二区av在线 | 日日麻批免费40分钟无码 | 免费无码av一区二区 | 国产成人av免费观看 | 久久亚洲a片com人成 | 麻豆人妻少妇精品无码专区 | 国产成人无码一二三区视频 | 国精产品一区二区三区 | 丰满少妇弄高潮了www | 久久亚洲中文字幕无码 | 扒开双腿吃奶呻吟做受视频 | 亚洲一区二区三区 | 少妇被粗大的猛进出69影院 | 高潮毛片无遮挡高清免费 | 麻豆国产丝袜白领秘书在线观看 | 国产麻豆精品一区二区三区v视界 | 午夜丰满少妇性开放视频 | 亚洲啪av永久无码精品放毛片 | 狠狠色欧美亚洲狠狠色www | 亚洲а∨天堂久久精品2021 | 国产一区二区三区四区五区加勒比 | 丰满肥臀大屁股熟妇激情视频 | 国产精品人人妻人人爽 | 国产综合在线观看 | 免费播放一区二区三区 | 国产精品丝袜黑色高跟鞋 | v一区无码内射国产 | 超碰97人人做人人爱少妇 | 精品久久久无码中文字幕 | 伊人久久婷婷五月综合97色 | 国产内射爽爽大片视频社区在线 | 亚洲精品综合一区二区三区在线 | 女人和拘做爰正片视频 | 久久亚洲a片com人成 | 精品国产福利一区二区 | 日日天日日夜日日摸 | 日韩精品无码免费一区二区三区 | 国产成人午夜福利在线播放 | 国产九九九九九九九a片 | 人妻尝试又大又粗久久 | 欧美国产日韩亚洲中文 | 欧美性猛交xxxx富婆 | 国产精品第一区揄拍无码 | 给我免费的视频在线观看 | 波多野结衣高清一区二区三区 | 国产午夜无码精品免费看 | 国产肉丝袜在线观看 | 国产成人综合色在线观看网站 | 亚洲中文字幕乱码av波多ji | 免费人成在线观看网站 | 全黄性性激高免费视频 | 中文字幕乱码中文乱码51精品 | 中文字幕 亚洲精品 第1页 | 色欲人妻aaaaaaa无码 | 少妇性l交大片欧洲热妇乱xxx | 国产成人精品一区二区在线小狼 | 欧美老妇与禽交 | 久久国产劲爆∧v内射 | 国产一区二区三区精品视频 | 美女黄网站人色视频免费国产 | 久久综合久久自在自线精品自 | 亚洲日韩乱码中文无码蜜桃臀网站 | 国产肉丝袜在线观看 | 天天躁日日躁狠狠躁免费麻豆 | 国产美女精品一区二区三区 | 国产麻豆精品精东影业av网站 | 黑人巨大精品欧美一区二区 | 亚洲精品成人av在线 | 67194成是人免费无码 | 激情国产av做激情国产爱 | 无码精品国产va在线观看dvd | 秋霞成人午夜鲁丝一区二区三区 | 国产人妻久久精品二区三区老狼 | 午夜福利一区二区三区在线观看 | 色欲av亚洲一区无码少妇 | 亚洲中文字幕无码一久久区 | 无套内射视频囯产 | 无码人妻少妇伦在线电影 | 98国产精品综合一区二区三区 | 在线成人www免费观看视频 | 日韩少妇内射免费播放 | 又大又紧又粉嫩18p少妇 | 少妇被黑人到高潮喷出白浆 | 自拍偷自拍亚洲精品10p | 日韩精品无码免费一区二区三区 | 亚洲成av人片在线观看无码不卡 | 曰韩少妇内射免费播放 | 狠狠亚洲超碰狼人久久 | 国产人妻久久精品二区三区老狼 | 国产av久久久久精东av | 麻豆人妻少妇精品无码专区 | 牲欲强的熟妇农村老妇女视频 | 中文字幕日产无线码一区 | 午夜无码区在线观看 | 亚洲一区二区三区含羞草 | 极品嫩模高潮叫床 | 日欧一片内射va在线影院 | 免费乱码人妻系列无码专区 | 日本精品少妇一区二区三区 | 亚欧洲精品在线视频免费观看 | 激情综合激情五月俺也去 | 伊人久久大香线蕉av一区二区 | 三级4级全黄60分钟 | 亚洲乱码中文字幕在线 | 国产亚洲精品精品国产亚洲综合 | 成人性做爰aaa片免费看不忠 | 亚洲理论电影在线观看 | 国产av一区二区精品久久凹凸 | 亚洲日本一区二区三区在线 | 久久综合给合久久狠狠狠97色 | 无码帝国www无码专区色综合 | 亚洲色偷偷偷综合网 | 亚洲日本一区二区三区在线 | 少妇高潮喷潮久久久影院 | 熟女俱乐部五十路六十路av | 狠狠色色综合网站 | 欧美人与禽zoz0性伦交 | 精品日本一区二区三区在线观看 | 国产人妻久久精品二区三区老狼 | 伊人色综合久久天天小片 | 激情综合激情五月俺也去 | 色婷婷香蕉在线一区二区 | 欧美35页视频在线观看 | 四虎国产精品免费久久 | 伊人久久大香线焦av综合影院 | 熟女体下毛毛黑森林 | 台湾无码一区二区 | 欧美 日韩 亚洲 在线 | 内射后入在线观看一区 | 国产精品手机免费 | 国内揄拍国内精品人妻 | 97夜夜澡人人爽人人喊中国片 | 国产精品99久久精品爆乳 | 国产乱人伦av在线无码 | 国产精品久免费的黄网站 | 国产成人av免费观看 | 久青草影院在线观看国产 | 纯爱无遮挡h肉动漫在线播放 | 国产精品高潮呻吟av久久 | 国产精品久久久久久亚洲毛片 | 真人与拘做受免费视频一 | 欧美自拍另类欧美综合图片区 | 国产在线精品一区二区三区直播 | 初尝人妻少妇中文字幕 | 久久久中文字幕日本无吗 | 国产精品毛片一区二区 | 老熟女重囗味hdxx69 | 99久久亚洲精品无码毛片 | 国产人妻精品一区二区三区 | 婷婷五月综合缴情在线视频 | 丰满人妻一区二区三区免费视频 | 亚洲中文字幕va福利 | 丝袜人妻一区二区三区 | 在线播放无码字幕亚洲 | 日日摸天天摸爽爽狠狠97 | 国产免费久久久久久无码 | 天堂а√在线中文在线 | 狠狠色噜噜狠狠狠7777奇米 | 日本高清一区免费中文视频 | 东京热一精品无码av | 日日摸天天摸爽爽狠狠97 | 成熟女人特级毛片www免费 | 一本色道婷婷久久欧美 | 国产精品久久久久无码av色戒 | 国产亚洲视频中文字幕97精品 | 日本欧美一区二区三区乱码 | 亚洲热妇无码av在线播放 | 四虎4hu永久免费 | 国产成人亚洲综合无码 | 欧美 日韩 人妻 高清 中文 | 国产亚洲日韩欧美另类第八页 | 日韩精品无码一区二区中文字幕 | 成人片黄网站色大片免费观看 | 亚洲欧美国产精品专区久久 | 亚洲精品久久久久久一区二区 | 精品国产一区二区三区四区 | 黑人巨大精品欧美黑寡妇 | 日日鲁鲁鲁夜夜爽爽狠狠 | 欧美阿v高清资源不卡在线播放 | 亚洲中文字幕在线观看 | 日本高清一区免费中文视频 | 日本又色又爽又黄的a片18禁 | 国产精品成人av在线观看 | 欧美野外疯狂做受xxxx高潮 | 欧美性色19p | 免费国产黄网站在线观看 | 久久精品人人做人人综合试看 | 午夜丰满少妇性开放视频 | 99国产欧美久久久精品 | 国产成人无码一二三区视频 | 无码人妻精品一区二区三区下载 | 国产深夜福利视频在线 | 国产绳艺sm调教室论坛 | 亚洲s码欧洲m码国产av | 亚洲日韩精品欧美一区二区 | 一区二区三区乱码在线 | 欧洲 | 亚洲熟妇色xxxxx欧美老妇y | 99久久精品无码一区二区毛片 | 欧洲美熟女乱又伦 | 欧美35页视频在线观看 | 熟女少妇人妻中文字幕 | 日韩成人一区二区三区在线观看 | 日日橹狠狠爱欧美视频 | 精品无码av一区二区三区 | 欧美精品一区二区精品久久 | 粉嫩少妇内射浓精videos | 丰满少妇熟乱xxxxx视频 | 99riav国产精品视频 | 无码吃奶揉捏奶头高潮视频 | 又大又硬又黄的免费视频 | 国产精品理论片在线观看 | 国产成人精品必看 | 国产人成高清在线视频99最全资源 | 欧美老妇与禽交 | 国产三级久久久精品麻豆三级 | 国产精品无码久久av | 露脸叫床粗话东北少妇 | 漂亮人妻洗澡被公强 日日躁 | 色噜噜亚洲男人的天堂 | 欧美喷潮久久久xxxxx | 精品久久综合1区2区3区激情 | 国产av无码专区亚洲awww | 国产凸凹视频一区二区 | 亚洲国产精品久久人人爱 | 国产乱人伦av在线无码 | 国产精品99爱免费视频 | 特大黑人娇小亚洲女 | 欧美老熟妇乱xxxxx | 久久亚洲精品中文字幕无男同 | 女人被男人躁得好爽免费视频 | 无码中文字幕色专区 | 久久久久久久久蜜桃 | 久久人妻内射无码一区三区 | 亚洲伊人久久精品影院 | 久久婷婷五月综合色国产香蕉 | 欧美变态另类xxxx | 天天燥日日燥 | 精品偷自拍另类在线观看 | 国产亚洲人成a在线v网站 | 波多野结衣av一区二区全免费观看 | 国产亚洲精品久久久ai换 | 欧美成人家庭影院 | 美女毛片一区二区三区四区 | 伊人色综合久久天天小片 | 日本熟妇浓毛 | 欧洲熟妇色 欧美 | 国产肉丝袜在线观看 | 国产精品久久久久久久影院 | 国产av一区二区精品久久凹凸 | 国产两女互慰高潮视频在线观看 | 国产免费久久精品国产传媒 | 亚洲色在线无码国产精品不卡 | 天天躁夜夜躁狠狠是什么心态 | 99久久99久久免费精品蜜桃 | 国产乱人伦偷精品视频 | 色综合久久久无码中文字幕 | 日本一卡2卡3卡4卡无卡免费网站 国产一区二区三区影院 | 动漫av一区二区在线观看 | 国产激情无码一区二区app | 国产亚洲精品久久久ai换 | 强伦人妻一区二区三区视频18 | 亚洲精品一区二区三区大桥未久 | 成人无码视频在线观看网站 | 欧美日韩亚洲国产精品 | 男人的天堂2018无码 | 中文字幕人妻丝袜二区 | 国产精品手机免费 | 成人精品天堂一区二区三区 | 牲欲强的熟妇农村老妇女 | 激情综合激情五月俺也去 | 中文无码伦av中文字幕 | 亚洲成av人在线观看网址 | 欧美老熟妇乱xxxxx | 狠狠色丁香久久婷婷综合五月 | 影音先锋中文字幕无码 | 久精品国产欧美亚洲色aⅴ大片 | 日韩无套无码精品 | 四虎永久在线精品免费网址 | 成人三级无码视频在线观看 | 成人免费视频视频在线观看 免费 | 色老头在线一区二区三区 | 天天摸天天碰天天添 | 99精品无人区乱码1区2区3区 | 又大又硬又爽免费视频 | 久精品国产欧美亚洲色aⅴ大片 | 天天燥日日燥 | 97无码免费人妻超级碰碰夜夜 | 亚洲国产午夜精品理论片 | 男女超爽视频免费播放 | 亚洲国产精品久久人人爱 | 国产又爽又猛又粗的视频a片 | 亚洲精品一区二区三区在线观看 | 日韩av无码一区二区三区不卡 | 双乳奶水饱满少妇呻吟 | 国产精品手机免费 | 成人精品视频一区二区 | 88国产精品欧美一区二区三区 | 色婷婷欧美在线播放内射 | 亚洲一区二区三区含羞草 | 国产精品高潮呻吟av久久 | 粉嫩少妇内射浓精videos | 色综合久久中文娱乐网 | 久久精品人妻少妇一区二区三区 | 国产午夜无码精品免费看 | 动漫av网站免费观看 | 婷婷六月久久综合丁香 | 久久久亚洲欧洲日产国码αv | 日韩人妻无码中文字幕视频 | 亚洲日韩一区二区三区 | 狠狠综合久久久久综合网 | 偷窥村妇洗澡毛毛多 | 久久综合狠狠综合久久综合88 | 国产亚洲精品精品国产亚洲综合 | 99久久人妻精品免费二区 | 国产热a欧美热a在线视频 | 中文字幕无码视频专区 | 欧美黑人乱大交 | 久久精品国产一区二区三区肥胖 | 影音先锋中文字幕无码 | 亚洲一区二区观看播放 | 在教室伦流澡到高潮hnp视频 | 久久久久久久久蜜桃 | 亚洲成a人片在线观看无码 | 国产特级毛片aaaaaa高潮流水 | 亚洲人亚洲人成电影网站色 | 国产精品亚洲а∨无码播放麻豆 | 亚洲色欲色欲天天天www | a片免费视频在线观看 | 麻豆人妻少妇精品无码专区 | 乱码午夜-极国产极内射 | 中文字幕人妻无码一区二区三区 | 国产成人无码av片在线观看不卡 | 天天躁日日躁狠狠躁免费麻豆 | 俺去俺来也www色官网 | 中文字幕无码乱人伦 | 国产乱码精品一品二品 | 野外少妇愉情中文字幕 | 成人试看120秒体验区 | 亚洲爆乳精品无码一区二区三区 | 日本一卡2卡3卡四卡精品网站 | 国产人妖乱国产精品人妖 | 国产成人一区二区三区在线观看 | 亚洲欧洲日本无在线码 | 日韩精品成人一区二区三区 | 精品厕所偷拍各类美女tp嘘嘘 | 亚洲中文字幕av在天堂 | 在线精品亚洲一区二区 | 久久久国产精品无码免费专区 | 内射欧美老妇wbb | 国产欧美亚洲精品a | 成人亚洲精品久久久久 | 最近的中文字幕在线看视频 | 黑人巨大精品欧美一区二区 | 国产 精品 自在自线 | 国产乱人偷精品人妻a片 | 无码免费一区二区三区 | 亚洲经典千人经典日产 | 激情爆乳一区二区三区 | 国产精品igao视频网 | 日韩亚洲欧美精品综合 | 精品久久久无码人妻字幂 | 色情久久久av熟女人妻网站 | 老太婆性杂交欧美肥老太 | 亚洲欧美综合区丁香五月小说 | 日韩人妻无码一区二区三区久久99 | 日本免费一区二区三区最新 | 免费观看激色视频网站 | а√资源新版在线天堂 | 国产亚洲视频中文字幕97精品 | 国产精品高潮呻吟av久久4虎 | 久久久久久国产精品无码下载 | 亚洲欧美精品aaaaaa片 | 成人片黄网站色大片免费观看 | 国产精华av午夜在线观看 | 狂野欧美激情性xxxx | 亚洲无人区午夜福利码高清完整版 | 波多野结衣 黑人 | 久久久久99精品成人片 | 熟女少妇在线视频播放 | 久久久久久久人妻无码中文字幕爆 | 熟女少妇人妻中文字幕 | 无码人妻丰满熟妇区毛片18 | 精品国偷自产在线 | 亚洲va中文字幕无码久久不卡 | 国产69精品久久久久app下载 | 色综合视频一区二区三区 | 久久久中文久久久无码 | 露脸叫床粗话东北少妇 | 自拍偷自拍亚洲精品10p | 免费视频欧美无人区码 | 中文字幕人妻无码一夲道 | 人人妻人人澡人人爽人人精品浪潮 | 永久免费观看国产裸体美女 | 国产内射老熟女aaaa | 亚洲人成影院在线无码按摩店 | 性生交片免费无码看人 | 色狠狠av一区二区三区 | 全黄性性激高免费视频 | 国产一区二区三区精品视频 | 成在人线av无码免观看麻豆 | 国产成人av免费观看 | 久久精品视频在线看15 | 天堂亚洲2017在线观看 | 欧美国产日韩亚洲中文 | 欧美亚洲日韩国产人成在线播放 | 三上悠亚人妻中文字幕在线 | 亚洲国产成人a精品不卡在线 | 美女黄网站人色视频免费国产 | www国产亚洲精品久久网站 | 天堂а√在线地址中文在线 | 高清国产亚洲精品自在久久 | 国产综合久久久久鬼色 | 永久免费观看国产裸体美女 | 女人高潮内射99精品 | 精品国产麻豆免费人成网站 | 大地资源中文第3页 | 国产成人无码午夜视频在线观看 | 精品水蜜桃久久久久久久 | 亚洲精品一区国产 | 夫妻免费无码v看片 | 亚洲熟妇色xxxxx欧美老妇 | 国产亚洲欧美日韩亚洲中文色 | 男人的天堂2018无码 | 蜜桃视频插满18在线观看 | 强开小婷嫩苞又嫩又紧视频 | 久久99国产综合精品 | 少妇高潮喷潮久久久影院 | 久久99国产综合精品 | 荫蒂被男人添的好舒服爽免费视频 | 亚洲中文字幕成人无码 | 在线精品亚洲一区二区 | 麻豆国产丝袜白领秘书在线观看 | 欧美日韩一区二区综合 | 伊在人天堂亚洲香蕉精品区 | 亚洲小说图区综合在线 | 久久久亚洲欧洲日产国码αv | av人摸人人人澡人人超碰下载 | 18禁止看的免费污网站 | 免费无码的av片在线观看 | 亚洲综合无码一区二区三区 | 亚洲国精产品一二二线 | 好男人www社区 | 日韩亚洲欧美中文高清在线 | 一个人免费观看的www视频 | 国产av人人夜夜澡人人爽麻豆 | 亚洲中文无码av永久不收费 | 沈阳熟女露脸对白视频 | 无套内谢的新婚少妇国语播放 | 双乳奶水饱满少妇呻吟 | 国产精品怡红院永久免费 | 久久99精品久久久久久动态图 | 日韩精品a片一区二区三区妖精 | 色一情一乱一伦一视频免费看 | 精品成在人线av无码免费看 | 男女猛烈xx00免费视频试看 | 天天做天天爱天天爽综合网 | 给我免费的视频在线观看 | 国产av无码专区亚洲awww | 国产性生大片免费观看性 | 午夜男女很黄的视频 | 亚洲一区二区三区 | 成年美女黄网站色大免费全看 | 精品乱码久久久久久久 | 男女作爱免费网站 | 中国女人内谢69xxxxxa片 | 男女超爽视频免费播放 | 青青青爽视频在线观看 | 日韩精品无码免费一区二区三区 | 成人三级无码视频在线观看 | 77777熟女视频在线观看 а天堂中文在线官网 | 亚洲小说图区综合在线 | 午夜丰满少妇性开放视频 | 亚洲国产成人av在线观看 | 黑人大群体交免费视频 | 午夜精品久久久久久久 | 一本无码人妻在中文字幕免费 | www一区二区www免费 | 亚洲自偷自拍另类第1页 | 人人妻人人澡人人爽欧美一区九九 | 国产小呦泬泬99精品 | 国产午夜福利100集发布 | 国产一区二区三区四区五区加勒比 | 午夜福利电影 | 亚洲人成影院在线观看 | 久久aⅴ免费观看 | 乌克兰少妇性做爰 | 性色欲网站人妻丰满中文久久不卡 | 亚洲一区二区三区偷拍女厕 | 1000部啪啪未满十八勿入下载 | 国产无av码在线观看 | 国内老熟妇对白xxxxhd | 婷婷五月综合激情中文字幕 | 无码人妻黑人中文字幕 | 精品欧洲av无码一区二区三区 | 日韩av无码一区二区三区不卡 | 99久久无码一区人妻 | 又粗又大又硬又长又爽 | 精品久久久久久人妻无码中文字幕 | 亚洲色大成网站www国产 | a国产一区二区免费入口 | 久久99精品久久久久久 | 2020最新国产自产精品 | 色综合久久久久综合一本到桃花网 | 国产精品亚洲lv粉色 | 国产成人人人97超碰超爽8 | 蜜臀aⅴ国产精品久久久国产老师 | 少妇性俱乐部纵欲狂欢电影 | 永久免费观看国产裸体美女 | 国产精品久久久午夜夜伦鲁鲁 | 亚洲精品久久久久久久久久久 | 国产内射爽爽大片视频社区在线 | 国产人妻人伦精品1国产丝袜 | 国产女主播喷水视频在线观看 | 日本www一道久久久免费榴莲 | 亚洲乱码日产精品bd | 国色天香社区在线视频 | 97人妻精品一区二区三区 | 大乳丰满人妻中文字幕日本 | 成熟女人特级毛片www免费 | 在线看片无码永久免费视频 | 亚洲国产欧美日韩精品一区二区三区 | 狠狠色丁香久久婷婷综合五月 | 日本免费一区二区三区最新 | 亚洲精品国产第一综合99久久 | 无码国产色欲xxxxx视频 | 小鲜肉自慰网站xnxx | 国产香蕉尹人视频在线 | 久精品国产欧美亚洲色aⅴ大片 | 成熟人妻av无码专区 | 东京热无码av男人的天堂 | 精品人妻中文字幕有码在线 | 久久精品国产一区二区三区 | 欧美日本日韩 | 激情亚洲一区国产精品 | 青草青草久热国产精品 | 国产精品人人爽人人做我的可爱 | 亚洲中文无码av永久不收费 | 亚洲人亚洲人成电影网站色 | 亚洲中文字幕乱码av波多ji | 国产精品爱久久久久久久 | 精品一区二区三区波多野结衣 | 99久久婷婷国产综合精品青草免费 | 国产激情一区二区三区 | 四虎永久在线精品免费网址 | 东京一本一道一二三区 | 精品无码国产一区二区三区av | 波多野结衣aⅴ在线 | 精品欧美一区二区三区久久久 | 欧美freesex黑人又粗又大 | 日韩av无码一区二区三区 | 蜜桃视频插满18在线观看 | 久热国产vs视频在线观看 | 日本大香伊一区二区三区 | 国产精品怡红院永久免费 | 日韩av激情在线观看 | 国产精品99爱免费视频 | 国产亚洲精品久久久久久久久动漫 | 国产精品久久久久久久9999 | 国产超碰人人爽人人做人人添 | 免费看男女做好爽好硬视频 | 老子影院午夜伦不卡 | 久久亚洲精品中文字幕无男同 | 2020久久香蕉国产线看观看 | 精品欧美一区二区三区久久久 | 无码精品国产va在线观看dvd | 无码人妻丰满熟妇区五十路百度 | 欧美三级a做爰在线观看 | 色综合视频一区二区三区 | 亚洲欧美国产精品专区久久 | 人妻中文无码久热丝袜 | 日本爽爽爽爽爽爽在线观看免 | 小泽玛莉亚一区二区视频在线 | 国产激情无码一区二区app | 欧美喷潮久久久xxxxx | 伊人久久大香线蕉亚洲 | www国产精品内射老师 | 国产农村妇女高潮大叫 | 午夜福利试看120秒体验区 | 99久久久无码国产精品免费 | 亚洲中文字幕乱码av波多ji | 熟女少妇人妻中文字幕 | 在线a亚洲视频播放在线观看 | 国产一区二区三区日韩精品 | 色欲综合久久中文字幕网 | 精品国产aⅴ无码一区二区 | 亚洲自偷自拍另类第1页 | 两性色午夜视频免费播放 | 无码人妻出轨黑人中文字幕 | 亚洲精品一区国产 | 国产情侣作爱视频免费观看 | 人人澡人人透人人爽 | 国产精品无码mv在线观看 | 一二三四社区在线中文视频 | 亚洲性无码av中文字幕 | 国产亚洲美女精品久久久2020 | 欧美肥老太牲交大战 | 国产午夜无码视频在线观看 | 午夜福利一区二区三区在线观看 | 鲁大师影院在线观看 | 亚洲精品一区二区三区四区五区 | 欧美午夜特黄aaaaaa片 | 国产精品无码成人午夜电影 | 黑人大群体交免费视频 | 国产精品a成v人在线播放 | 波多野结衣高清一区二区三区 | 亚洲精品一区二区三区婷婷月 | 国产真实伦对白全集 | 四虎国产精品免费久久 | 国产精品亚洲五月天高清 | 亚洲娇小与黑人巨大交 | 天堂无码人妻精品一区二区三区 | 国产精品成人av在线观看 | 国产国语老龄妇女a片 | 老熟妇乱子伦牲交视频 | 国产精品人人爽人人做我的可爱 | а√天堂www在线天堂小说 | 伊人久久大香线蕉午夜 | 亚洲国产精品久久人人爱 | 熟妇人妻激情偷爽文 | 国产精品亚洲专区无码不卡 | 欧美freesex黑人又粗又大 | 中文字幕人妻无码一夲道 | 久久精品女人天堂av免费观看 | 日日麻批免费40分钟无码 | 久久久久免费看成人影片 | 99久久精品午夜一区二区 | 国产av无码专区亚洲a∨毛片 | 激情内射日本一区二区三区 | 一个人看的视频www在线 | 久久综合色之久久综合 | 国产精品爱久久久久久久 | 久久综合香蕉国产蜜臀av | 亚洲小说图区综合在线 | 亚洲 激情 小说 另类 欧美 | 欧美zoozzooz性欧美 | 熟妇激情内射com | 暴力强奷在线播放无码 | 荫蒂添的好舒服视频囗交 | 国产成人精品视频ⅴa片软件竹菊 | 亚洲色欲久久久综合网东京热 | 国产精品久久久久无码av色戒 | 麻豆国产人妻欲求不满谁演的 | 日韩视频 中文字幕 视频一区 | 色一情一乱一伦一区二区三欧美 | 国产精品久久福利网站 | 成人免费视频一区二区 | 精品aⅴ一区二区三区 | 麻豆av传媒蜜桃天美传媒 | 色婷婷久久一区二区三区麻豆 | 久久国产劲爆∧v内射 | 亚洲精品久久久久久一区二区 | 无码人妻丰满熟妇区五十路百度 | 中文字幕乱码中文乱码51精品 | 日韩精品无码免费一区二区三区 | 4hu四虎永久在线观看 | 亚洲人成影院在线无码按摩店 | 性生交大片免费看l | 国产九九九九九九九a片 | 男女猛烈xx00免费视频试看 | 久久亚洲中文字幕无码 | 好男人社区资源 | 动漫av一区二区在线观看 | 成人av无码一区二区三区 | 国产精品久久久久久久9999 | 色五月丁香五月综合五月 | 国产精品igao视频网 | 中文字幕人妻无码一区二区三区 | 国产无遮挡又黄又爽免费视频 | 久久精品人妻少妇一区二区三区 | 欧美亚洲日韩国产人成在线播放 | 97资源共享在线视频 | 亚洲の无码国产の无码步美 | 露脸叫床粗话东北少妇 | 性做久久久久久久久 | 国产亚洲日韩欧美另类第八页 | 亚洲欧美精品aaaaaa片 | 西西人体www44rt大胆高清 | 图片区 小说区 区 亚洲五月 | 午夜福利试看120秒体验区 | 色欲av亚洲一区无码少妇 | 成年美女黄网站色大免费全看 | 欧美日韩综合一区二区三区 | 国产后入清纯学生妹 | 国产片av国语在线观看 | 少妇人妻偷人精品无码视频 | 久久久久成人精品免费播放动漫 | 精品久久8x国产免费观看 | 少妇厨房愉情理9仑片视频 | 亚洲日韩av一区二区三区四区 | 色诱久久久久综合网ywww | 国产绳艺sm调教室论坛 | 十八禁真人啪啪免费网站 | 国产明星裸体无码xxxx视频 | 蜜桃av蜜臀av色欲av麻 999久久久国产精品消防器材 | 人人超人人超碰超国产 | 亚洲 日韩 欧美 成人 在线观看 | 亚洲精品一区三区三区在线观看 | 波多野42部无码喷潮在线 | 国产亚洲人成a在线v网站 | 日日碰狠狠躁久久躁蜜桃 | 两性色午夜视频免费播放 | 日日鲁鲁鲁夜夜爽爽狠狠 | 日本欧美一区二区三区乱码 | 久久久国产精品无码免费专区 | 欧美日本日韩 | 老熟妇仑乱视频一区二区 | 99久久人妻精品免费二区 | 中文字幕无码av波多野吉衣 | 又色又爽又黄的美女裸体网站 | 欧美国产日韩久久mv | 国产亚洲精品久久久久久国模美 | 亚洲中文字幕久久无码 | 999久久久国产精品消防器材 | 亚洲精品午夜无码电影网 | 亚洲精品一区三区三区在线观看 | 成年美女黄网站色大免费全看 | 少妇太爽了在线观看 | 国产精品va在线观看无码 | 成人性做爰aaa片免费看不忠 | 午夜福利一区二区三区在线观看 | 青青久在线视频免费观看 | 色偷偷人人澡人人爽人人模 | 中文字幕无线码免费人妻 | 国产高清不卡无码视频 | 久久99精品久久久久久动态图 | aⅴ亚洲 日韩 色 图网站 播放 | 成人精品一区二区三区中文字幕 | 国产精品内射视频免费 | 国产精品人妻一区二区三区四 | 久久国产精品精品国产色婷婷 | 一个人看的www免费视频在线观看 | 国产乱人无码伦av在线a | 水蜜桃亚洲一二三四在线 | 欧美黑人性暴力猛交喷水 | 国产精品手机免费 | 国产办公室秘书无码精品99 | 亚洲经典千人经典日产 | 欧美自拍另类欧美综合图片区 | 色偷偷人人澡人人爽人人模 | 麻豆精品国产精华精华液好用吗 | 精品亚洲韩国一区二区三区 | 国产亚洲日韩欧美另类第八页 | 国产亚洲精品久久久ai换 | 日日噜噜噜噜夜夜爽亚洲精品 | 激情五月综合色婷婷一区二区 | 蜜桃视频插满18在线观看 | 一本一道久久综合久久 | 青草青草久热国产精品 | 爆乳一区二区三区无码 | 2020久久香蕉国产线看观看 | 久久五月精品中文字幕 | 无码人妻丰满熟妇区毛片18 | 国产午夜无码视频在线观看 | 无码人妻丰满熟妇区五十路百度 | 青草青草久热国产精品 | 天堂久久天堂av色综合 | 国产av一区二区三区最新精品 | 1000部夫妻午夜免费 | 国产婷婷色一区二区三区在线 | 亚洲毛片av日韩av无码 | 伊人久久大香线蕉av一区二区 | 粉嫩少妇内射浓精videos | 麻豆国产丝袜白领秘书在线观看 | 欧美日韩一区二区综合 | 国产乱人伦av在线无码 | 国产人妻人伦精品 | 亚洲欧美国产精品专区久久 | 99久久婷婷国产综合精品青草免费 | 亚洲日本va午夜在线电影 | 亚洲成在人网站无码天堂 | 欧美黑人乱大交 | 日韩精品无码一本二本三本色 | 玩弄人妻少妇500系列视频 | 天堂а√在线地址中文在线 | 九九综合va免费看 | 亚洲爆乳大丰满无码专区 | 亚洲精品午夜无码电影网 | 国产熟女一区二区三区四区五区 | 99久久婷婷国产综合精品青草免费 | 精品无码国产一区二区三区av | 人妻少妇精品无码专区动漫 | 国产亲子乱弄免费视频 | 久久综合给久久狠狠97色 | 久久国产自偷自偷免费一区调 | 97夜夜澡人人爽人人喊中国片 | 亚洲色欲色欲天天天www | 精品久久久久久人妻无码中文字幕 | 思思久久99热只有频精品66 | 水蜜桃色314在线观看 | 国产麻豆精品一区二区三区v视界 | 欧美熟妇另类久久久久久不卡 | 国产黄在线观看免费观看不卡 | 国产激情一区二区三区 | 日本精品久久久久中文字幕 | 欧美国产日产一区二区 | 狠狠综合久久久久综合网 | 最近免费中文字幕中文高清百度 | 少妇性l交大片欧洲热妇乱xxx | 亚洲精品美女久久久久久久 | 国产精品99爱免费视频 | 少妇被粗大的猛进出69影院 | 亚洲日韩中文字幕在线播放 | 亚洲人交乣女bbw | 四虎国产精品一区二区 | 精品无码一区二区三区爱欲 | 窝窝午夜理论片影院 | 精品久久久久久亚洲精品 | 亚洲gv猛男gv无码男同 | 日本又色又爽又黄的a片18禁 | 亚洲欧美综合区丁香五月小说 | 免费看少妇作爱视频 | 亚洲男人av天堂午夜在 | 国产精品久久久久无码av色戒 | 十八禁视频网站在线观看 | 成人无码影片精品久久久 | 日本乱人伦片中文三区 | 久久99久久99精品中文字幕 | 亚洲天堂2017无码 | 精品人人妻人人澡人人爽人人 | 中文无码精品a∨在线观看不卡 | 精品国偷自产在线 | 久久99久久99精品中文字幕 | 亚洲自偷自拍另类第1页 | 亚洲国产精华液网站w | 激情国产av做激情国产爱 | 人妻夜夜爽天天爽三区 | 久久久久久久久蜜桃 | 亚洲熟熟妇xxxx | 欧美 丝袜 自拍 制服 另类 | 国产成人无码av片在线观看不卡 | 日韩av无码中文无码电影 | 国产乱码精品一品二品 | 国产精品va在线播放 | 久久无码专区国产精品s | 亚洲综合伊人久久大杳蕉 | 亚洲国精产品一二二线 | 18无码粉嫩小泬无套在线观看 | 精品人人妻人人澡人人爽人人 | 欧美刺激性大交 | 久久综合香蕉国产蜜臀av | 久久久精品人妻久久影视 | ass日本丰满熟妇pics | 亚洲熟熟妇xxxx | 亚洲色欲久久久综合网东京热 | 久久综合给合久久狠狠狠97色 | 亚洲va中文字幕无码久久不卡 | 一区二区三区高清视频一 | 日本又色又爽又黄的a片18禁 | 激情内射亚州一区二区三区爱妻 | 熟妇人妻中文av无码 | 亚洲毛片av日韩av无码 | 成人无码精品1区2区3区免费看 | 国产亚洲精品久久久久久大师 | 亚洲一区二区三区偷拍女厕 | 欧美成人家庭影院 | 欧美 亚洲 国产 另类 | 欧美三级a做爰在线观看 | 又大又黄又粗又爽的免费视频 | 久久精品视频在线看15 | 欧美激情内射喷水高潮 | 玩弄少妇高潮ⅹxxxyw | 免费无码av一区二区 | 精品欧洲av无码一区二区三区 | 色一情一乱一伦一视频免费看 | 天海翼激烈高潮到腰振不止 | 99精品久久毛片a片 | 成人亚洲精品久久久久 | 亚洲国产成人a精品不卡在线 | 成年美女黄网站色大免费视频 | 亚洲一区二区三区含羞草 | 色 综合 欧美 亚洲 国产 | 在线 国产 欧美 亚洲 天堂 | 波多野结衣乳巨码无在线观看 | 色婷婷综合中文久久一本 | 综合网日日天干夜夜久久 | 扒开双腿吃奶呻吟做受视频 | 国产成人人人97超碰超爽8 | 国产成人无码专区 | 亚洲精品久久久久avwww潮水 | 中文字幕无码免费久久9一区9 | 岛国片人妻三上悠亚 | 内射后入在线观看一区 | 日本高清一区免费中文视频 | 人妻夜夜爽天天爽三区 | 成 人影片 免费观看 | 色综合久久88色综合天天 | 99久久人妻精品免费一区 | 亚洲色偷偷男人的天堂 | 图片区 小说区 区 亚洲五月 | 亚洲日韩一区二区三区 | 久久国产精品精品国产色婷婷 | а天堂中文在线官网 | 久久人妻内射无码一区三区 | 成年美女黄网站色大免费全看 | 99久久婷婷国产综合精品青草免费 | 国产一区二区不卡老阿姨 | 午夜免费福利小电影 | 综合人妻久久一区二区精品 | 中文字幕av伊人av无码av | 久久精品中文字幕一区 | 无码播放一区二区三区 | 性欧美牲交xxxxx视频 | 亚洲精品国产精品乱码不卡 | 久久亚洲国产成人精品性色 | 在线视频网站www色 | 欧美人与禽zoz0性伦交 | 精品无码国产自产拍在线观看蜜 | 永久免费精品精品永久-夜色 | 亚洲成a人片在线观看无码 | 久久亚洲中文字幕精品一区 | 玩弄少妇高潮ⅹxxxyw | 欧美性生交xxxxx久久久 | 最新国产麻豆aⅴ精品无码 | 内射欧美老妇wbb | 国产精品第一区揄拍无码 | 亚洲自偷自拍另类第1页 | 亚洲日韩乱码中文无码蜜桃臀网站 | 国产女主播喷水视频在线观看 | 四虎影视成人永久免费观看视频 | 老熟妇乱子伦牲交视频 | 欧美国产亚洲日韩在线二区 | 在线观看国产一区二区三区 | 在线欧美精品一区二区三区 | 国产亚洲日韩欧美另类第八页 | 色综合久久久无码网中文 | 亚洲欧美国产精品专区久久 | 丰满人妻翻云覆雨呻吟视频 | 最新国产乱人伦偷精品免费网站 | 国产亲子乱弄免费视频 | 国产精品久久久久久无码 | 精品午夜福利在线观看 | 午夜精品一区二区三区在线观看 | 精品久久综合1区2区3区激情 | 成熟妇人a片免费看网站 | 国产精品资源一区二区 | 四虎影视成人永久免费观看视频 | 黑人玩弄人妻中文在线 | 精品国产麻豆免费人成网站 | 久久久久国色av免费观看性色 | 久久久婷婷五月亚洲97号色 | 无码帝国www无码专区色综合 | 国产精华av午夜在线观看 | 亚洲啪av永久无码精品放毛片 | 日韩人妻无码中文字幕视频 | 国产精品无码永久免费888 | 国产在线精品一区二区三区直播 | 18禁黄网站男男禁片免费观看 | 国产色视频一区二区三区 | 高潮毛片无遮挡高清免费 | 美女扒开屁股让男人桶 | 久久久久亚洲精品中文字幕 | 国产亚av手机在线观看 | 国产精品-区区久久久狼 | 野外少妇愉情中文字幕 | 大地资源网第二页免费观看 | 国内揄拍国内精品人妻 | 日本乱人伦片中文三区 | 精品国精品国产自在久国产87 | 乱码午夜-极国产极内射 | 男女下面进入的视频免费午夜 | 免费无码av一区二区 | 清纯唯美经典一区二区 | 扒开双腿吃奶呻吟做受视频 | 国产偷抇久久精品a片69 | 亚洲一区二区三区在线观看网站 | 99精品国产综合久久久久五月天 | 一本久久a久久精品亚洲 | 色婷婷av一区二区三区之红樱桃 | 国产av一区二区三区最新精品 | 2019午夜福利不卡片在线 | 色窝窝无码一区二区三区色欲 | 日本一区二区三区免费播放 | 无码国产乱人伦偷精品视频 | 亚洲 激情 小说 另类 欧美 | 亚洲成a人一区二区三区 | 精品水蜜桃久久久久久久 | 激情国产av做激情国产爱 | 无套内谢老熟女 | 97久久精品无码一区二区 | 久久久中文字幕日本无吗 | 日本一区二区三区免费高清 | 无套内射视频囯产 | 无码毛片视频一区二区本码 | 狂野欧美性猛xxxx乱大交 | 少妇人妻偷人精品无码视频 | 国产偷自视频区视频 | 国产猛烈高潮尖叫视频免费 | 国产综合久久久久鬼色 | 亚洲日韩一区二区三区 | 亚洲熟妇色xxxxx欧美老妇y | аⅴ资源天堂资源库在线 | av无码不卡在线观看免费 | 国产在线精品一区二区高清不卡 | 国产成人精品优优av | 全球成人中文在线 | 欧美freesex黑人又粗又大 | 黑人粗大猛烈进出高潮视频 | 2019nv天堂香蕉在线观看 | 人妻少妇精品视频专区 | 亚洲综合无码一区二区三区 | 中文亚洲成a人片在线观看 | 牲欲强的熟妇农村老妇女 | 少妇被粗大的猛进出69影院 | 欧美丰满熟妇xxxx性ppx人交 | 国产精品va在线播放 | 亚洲の无码国产の无码影院 | 东北女人啪啪对白 | 亚洲综合另类小说色区 | 九九久久精品国产免费看小说 | 中文字幕乱妇无码av在线 | 国产精品高潮呻吟av久久 | 999久久久国产精品消防器材 | 久久zyz资源站无码中文动漫 | 国产色视频一区二区三区 | 野狼第一精品社区 | 国产又爽又黄又刺激的视频 | 日韩精品a片一区二区三区妖精 | 国产高潮视频在线观看 | 一个人看的www免费视频在线观看 | 亚洲自偷自拍另类第1页 | 久久这里只有精品视频9 | 亚洲区小说区激情区图片区 | 少妇一晚三次一区二区三区 | 国产激情一区二区三区 | 久久亚洲日韩精品一区二区三区 | 亚洲乱亚洲乱妇50p | 一本久道高清无码视频 | 国产精品久免费的黄网站 | 成熟人妻av无码专区 | 国产va免费精品观看 | 蜜臀av在线播放 久久综合激激的五月天 | 未满成年国产在线观看 | 日日天日日夜日日摸 | 国产电影无码午夜在线播放 | 国产美女极度色诱视频www | 少妇邻居内射在线 | 丰满少妇人妻久久久久久 | 亚洲第一无码av无码专区 | av无码电影一区二区三区 | 国产成人久久精品流白浆 | 中文无码精品a∨在线观看不卡 | 亚洲成a人片在线观看日本 | 人人澡人摸人人添 | 国产美女极度色诱视频www | 久久午夜夜伦鲁鲁片无码免费 | 国产精品久久久久久亚洲影视内衣 | 内射巨臀欧美在线视频 | 成人性做爰aaa片免费看 | 亚洲国产精品久久久久久 | 国产手机在线αⅴ片无码观看 | 97久久国产亚洲精品超碰热 | 亚洲精品国产a久久久久久 | 白嫩日本少妇做爰 | 领导边摸边吃奶边做爽在线观看 | 色一情一乱一伦一区二区三欧美 | 久久久成人毛片无码 | 亚洲无人区午夜福利码高清完整版 | 人人妻人人澡人人爽精品欧美 | 精品国产一区av天美传媒 | 国产手机在线αⅴ片无码观看 | 一本久久a久久精品vr综合 | 精品少妇爆乳无码av无码专区 | 中文字幕人成乱码熟女app | 性色欲网站人妻丰满中文久久不卡 | 国产黑色丝袜在线播放 | 精品国偷自产在线 | 黑人巨大精品欧美一区二区 | 宝宝好涨水快流出来免费视频 | 精品国产福利一区二区 | 我要看www免费看插插视频 | 精品乱码久久久久久久 | 中文字幕无码日韩专区 | 成人毛片一区二区 | 国产区女主播在线观看 | 草草网站影院白丝内射 | 亚洲一区二区三区 | 又黄又爽又色的视频 | 精品国产成人一区二区三区 | 无码国产乱人伦偷精品视频 | 国产成人无码区免费内射一片色欲 | 欧美激情一区二区三区成人 | 精品aⅴ一区二区三区 | 久久久婷婷五月亚洲97号色 | 99久久久无码国产精品免费 | 国产无av码在线观看 | 精品少妇爆乳无码av无码专区 | 特黄特色大片免费播放器图片 | 在线亚洲高清揄拍自拍一品区 | 一本精品99久久精品77 | 无码人中文字幕 | 少妇厨房愉情理9仑片视频 | 中文精品无码中文字幕无码专区 | 国产黑色丝袜在线播放 | 国产精品沙发午睡系列 | 亚洲熟妇色xxxxx欧美老妇y | 牲交欧美兽交欧美 | 久久国产精品萌白酱免费 | 一本无码人妻在中文字幕免费 | 精品人人妻人人澡人人爽人人 | 少女韩国电视剧在线观看完整 | 俄罗斯老熟妇色xxxx | 成人免费视频在线观看 | 亚洲七七久久桃花影院 | 精品无码一区二区三区爱欲 |