Lua

Lua（icon，词源葡萄牙语“月亮”）是一个简洁、轻量、可扩展的脚本语言。Lua有着相对简单的C语言API而很容易嵌入应用中。很多应用程序使用Lua作为自己的嵌入式脚本语言，以此来实现可配置性、可扩展性。

## 历史

Lua是在1993年由罗伯托·耶鲁萨林斯希、Luiz Henrique de Figueiredo和Waldemar Celes创建的，他们当时是巴西的里约热内卢天主教大学的计算机图形技术组（Tecgraf）成员。Lua的先驱是数据描述/配置语言“SOL”（简单对象语言）和“DEL”（数据录入语言）。他们于1992年–1993年在Tecgraf独立开发了需要增加灵活性的两个不同项目（都是用于工程应用的交互式图形程序）。在SOL和DEL中缺乏很多控制流结构，需要向它们增加完全的编程能力。

在《The Evolution of Lua》中，这门语言的作者写道：

Lua主要受到了下列前辈语言的影响：

- Modula-2：从中引入了大部分控制结构语法 (编程语言)，`if`、`while`、`repeat`/`until`。
- CLU：多赋值和从函数调用的多个返回值，这是对引用参数或显式指针的更简单的替代。
- C++：“允许局部变量只在需要的地方声明的灵巧想法”。
- SNOBOL和AWK：关联数组。
- LISP和Scheme：在发表于《Dr. Dobb's Journal》的文章中，Lua的创立者还声称，有着单一且无所不在的数据结构机制（列表）的LISP和Scheme，对他们决定将表格开发为Lua的主要数据结构起到了主要影响。Lua的语义久而久之日趋受到Scheme的影响，特别是介入了匿名函数和完全的词法作用域。

Lua在版本5.0之前在类似BSD许可证之下发行。自从版本5.0以来，Lua采用了MIT许可证。

## 特性

Lua是一种轻量语言，它的官方版本只包括一个精简的核心和最基本的库。这使得Lua体积小、启动速度快。它用ANSI C语言编写，并以源代码形式开放，编译后的完整参考解释器只有大约247kB，到5.4.3版本，该体积变成283kB（Linux,amd64），依然非常小巧，可以很方便的嵌入别的程式里。和许多“大而全”的语言不一样，网络通讯、图形界面等都没有预设提供。但是Lua可以很容易地被扩展：由宿主语言（通常是C或C++）提供这些功能，Lua可以使用它们，就像是本来就内置的功能一样。事实上，现在已经有很多成熟的扩展模块可供选用。

Lua是一个动态类型语言，支援增量式垃圾收集策略。有内建的，与操作系统无关的协作式多线程支援。Lua原生支援的数据类型很少，只提供了数值（默认是双精度浮点数，可配置）、布尔量、字符串、表格、函数、线程以及用户自定义数据这几种。但是其处理表和字符串的效率非常之高，加上元表的支援，开发者可以高效的模拟出需要的复杂数据类型（比如集合、数组等）。

## 语法和语义

Lua是一种多重编程范型的程式设计语言：它只提供了很小的一个特性集合来满足不同编程范型的需要，而不是为某种特定的编程范型提供繁杂的特性支援。例如，Lua并不提供继承这个特性，但是你可以用元表格来模拟它。诸如命名空间、类这些概念都没有在语言基本特性中实现，但是我们可以用表格结构（Lua唯一提供的复杂数据结构）轻易模拟。正是提供了这些基本的元特性，我们可以任意的对语言进行自需的改造。

Lua实现了少量的高级特征比如头等函数、垃圾回收、闭包、正当尾调用、类型转换（于运行时间在字符串和数值之间自动转换）、协程（协作多任务）和动态模块装载。

### 词法

经典的Hello World!程序可以写为如下：

```lua
print("Hello World!")
```

或者如下：

```lua
print 'Hello World' 
print [[Hello World]]
```

在Lua中注释可以于双连字符并行至此行的结束，类似于Ada、Eiffel、Haskell、SQL和VHDL。多行字符串和注释用双方括号来装饰。

下例中实现了一个阶乘函数：

```lua
local function factorial(nbr) -- 输入参数 nbr 为整数
    local res = 1 -- 将局部结果初始化为 1
    for idx = 2, nbr do -- 从 2 到 nbr 的循环
        res = res * idx
    end
    return res -- 返回 nbr 的阶乘
end
print(factorial(5))
```

```lua
120
```

### 控制流

Lua有一种类型的条件测试：

```lua
if then end
```

它具有可选的

```lua
else
```

和

```lua
elseif then
```

执行控制构造。

通用的

```lua
if then end
```

语句需要三个关键字:

```lua
if condition then
	--当 condition 为 true 时执行的语句体
end
```

可以增加

```lua
else
```

关键字来控制执行，它随同着在

```lua
if
```

条件求值为

```lua
false
```

之时执行的语句块：

```lua
if condition then
	--当 condition 为 true 时执行的语句体
else
	--当上述条件都为 false 时执行的可选默认语句体
end
```

还可以使用

```lua
elseif then
```

关键字依据多个条件来控制执行：

```lua
if condition1 then
	-- 当 condition1 为 true 时执行的语句体
elseif condition2 then
	-- 当 condition1 为 false 且 condition2 为 true 时执行的语句体
else -- 可选
	-- 当上述条件都为 false 时执行的可选默认语句体
end
```

Lua有四种类型的循环：

```lua
while
```

循环。

```lua
repeat
```

循环（类似于

```lua
do while
```

循环）、数值

```lua
for
```

循环和通用

```lua
for
```

循环。

while

```lua
condition = true -- 进入 while 循环的条件

while condition do
  -- 在这里修改 condition 为 false，以避免无限循环
end
```

```lua
--[[注意：如果循环无响应，请关闭模块：Example 或关闭浏览器]]--
local idx = 1     -- 初始计数器值
-- 将 condition 变量设为 false 的语句以避免无限循环
while idx <= 5 do -- 当 idx 小于或等于 5 时循环（为避免无限循环）
  print(idx)      -- 在调试控制台输出当前计数器值
  idx = idx + 1   -- 在每次迭代中增加计数器，以确保循环结束
end               -- 循环结束时 idx 的值将为 6。
print("while 循环之外、idx = " .. idx)
```

```lua
1
2
3
4
5
while 循环之外、idx = 6
```

repeat

```lua
condition = false -- 在 repeat 循环中至少循环一次的条件
repeat
  -- 在这里将 condition 修改为 true，以避免无限循环
until condition
```

```lua
local idx = 1     -- 初始计数器值
repeat
  print(idx)      -- 在调试控制台输出当前计数器值
  idx = idx + 1   -- 在每次迭代中增加计数器，以确保循环结束
  -- 将 condition 变量设为 true 的语句以避免无限循环
until idx > 5     -- 循环结束时 idx 的值将为 6。
print("repeat 循环之外、idx = " .. idx)
```

```lua
1
2
3
4
5
repeat 循环之外、idx = 6
```

for

```lua
for idx = first, last, delta do  --delta可以是负数，允许计数增加或减少的循环
  -- 使用 idx 的语句
  -- 例如：print(idx)
end
```

```lua
for idx = 1, 5 do -- for idx = 从, 到
    print(idx)
end
-- 变量 idx 在 for 循环外不可见
```

```lua
1
2
3
4
5
```

通用

```lua
for
```

循环：

```lua
for key, value in pairs(_G) do
  print("键: " .. key .. "、值: " .. tostring(value))
end
```

```lua
键: string、值: table
键: xpcall、值: function
键: package、值: table
键: rawset、值: function
键: _VERSION、值: Lua 5.1
键: error、值: function
键: pcall、值: function
键: os、值: table
键: unpack、值: function
键: math、值: table
键: ipairs、值: function
键: require、值: function
键: rawget、值: function
键: type、值: function
键: setmetatable、值: function
键: next、值: function
键: select、值: function
键: assert、值: function
键: pairs、值: function
键: tonumber、值: function
键: _G、值: table
键: table、值: table
键: rawequal、值: function
键: debug、值: table
键: mw、值: table
键: getmetatable、值: function
键: tostring、值: function
```

将在表格`_G`上使用标准迭代器函数`pairs`进行迭代，直到它返回`nil`。

可以有嵌套的循环，就是在其他循环中的循环。

```lua
local grid = {
  { 11, 12, 13 },
  { 21, 22, 23 },
  { 31, 32, 33 }
}

for indRow, row in ipairs(grid) do
  for indCol, value in ipairs(row) do
    print(" 行: " .. indRow .. "、列: " .. indCol .. " 值: " .. grid[indRow][indCol])
  end
end
```

```lua
行: 1、列: 1 值: 11
行: 1、列: 2 值: 12
行: 1、列: 3 值: 13
行: 2、列: 1 值: 21
行: 2、列: 2 值: 22
行: 2、列: 3 值: 23
行: 3、列: 1 值: 31
行: 3、列: 2 值: 32
行: 3、列: 3 值: 33
```

### 函数

Lua将函数处理为头等值，在下例子中用`print`函数的表现可以修改来展示：

```lua
do
  local oldprint = print
  -- 存储当前的print函数为oldprint
  function print(s)
    --[[重新定义print函数。新函数只有一个实际参数。
    平常的print函数仍可以通过oldprint使用。]]
    oldprint(s == "foo" and "bar" or s)
  end
end
```

任何对`print`的进一步调用都要经由新函数，并且由于Lua的词法作用域，这个旧的`print`函数将只能被这个新的修改了的`print`访问到。

Lua还支持闭包，展示如下：

```lua
function addto(x)
  -- 返回一个把实际参数加到x上
  return function(y)
    --[=[ 在我们引用变量x的时候，它在当前作用域的外部。
    它的生命期会比这个匿名函数短，Lua建立一个闭包。]=]
    return x + y
  end
end
fourplus = addto(4)
print(fourplus(3))  -- 打印7

print(addto(4)(3))
--[[这是因为这直接用视件参数3调用了从addto(4)返回的函数。
    如果经常这么调用的话会减少数据消耗并提升性能。]]
```

每次调用的时候为变量`x`建立新的闭包，所以返回的每个新匿名函数都访问它自己的`x`参数。闭包由Lua的垃圾收集器来管理，如同任何其他对象一样。

```Lua
function create_a_counter()
  local count = 0
  return function()
    count = count + 1
    return count
  end
end
```

`create_a_counter()`会返回一个匿名函数，这个匿名函数会把`count`加`1`后再回传。在匿名函数中的变数`count`的值会一直被保存在匿名函数中。因此调用`create_a_counter()`时产生一个记数器函数，每次调用记数器函数，都会得到一个比上次大`1`的值。

### 变量类型

Lua是一种动态类型语言，因此语言中没有类型的定义，不需要声明变量类型，每个变量自己保存了类型。

有8种基本类型：nil、布尔值（boolean）、数字型（number）、字符串型（string）、用户自定义类型（userdata）、函数（function）、线程（thread）和表（table）。

```Lua
print(type(nil))                    -- 输出 nil
print(type(99.7+12*9))              -- 输出 number
print(type(true))                   -- 输出 boolean
print(type("Hello Wikipedia"))      -- 输出 string
print(type(print))                  -- 输出 function
print(type({1, 2, test = "test"}))  -- 输出 table
```

### 表格

表格（table）是Lua中最重要的数据结构（并且是设计中唯一内建的复合数据类型），并且是所有用户创建类型的基础。它们是增加了自动数值键和特殊语法的关联数组。

表格是键和数据的有序对的搜集，其中的数据用键来引用；换句话说，它是散列异构关联数组。

表格使用`{}`构造器语法来创建。

```lua
a_table = {} -- 建立一个新的空表格
```

表格总是用引用来传递的（参见传共享调用）。

键（索引）可以是除了`nil`和NaN的任何值，包括函数。

```lua
a_table = {x = 10}  -- 建立一个新表格，具有映射"x"到数10的一个表项。
print(a_table["x"]) -- 打印于这个字符串关联的值，这里是10。
b_table = a_table
b_table["x"] = 20   -- 在表格中的值变更为20。
print(b_table["x"]) -- 打印20。
print(a_table["x"]) -- 还是打印20，因为a_table和b_table都引用相同的表格。
```

通过使用字符串作为键，表格经常用作对象复合（或记录）。由于这种用法太常见，Lua为访问这种字段提供了特殊语法。

```lua
point = { x = 10, y = 20 }   -- 建立一个新表格
print(point["x"])            -- 打印10
print(point.x)               -- 同上一行完全相同含义。易读的点只是语法糖。
```

通过使用表格来存储有关函数，它可以充当名字空间。

```lua
Point = {}

Point.new = function(x, y)
  return {x = x, y = y}  --  return {["x"] = x, ["y"] = y}
end

Point.set_x = function(point, x)
  point.x = x  --  point["x"] = x;
end
```

表格被自动的赋予了数值键，使得它们可以被用作数组数据类型。第一个自动索引是`1`而非`0`，因为很多其他编程语言都这样（尽管显式的索引`0`是允许的）。

数值键`1`不同于字符串键`"1"`。

```lua
array = { "a", "b", "c", "d" }   -- 索引被自动赋予。
print(array[2])                  -- 打印"b"。在Lua中自动索引开始于1。
print(#array)                    -- 打印4。#是表格和字符串的长度算符。
array[0] = "z"                   -- 0是合法索引。
print(#array)                    -- 仍打印4，因为Lua数组是基于1的。
```

表格`t`的长度被定义为任何整数索引`n`，使得`t[n]`不是`nil`而`t[n+1]`是`nil`；而且如果`t[1]`是`nil`， `n`可以是`0`。对于一个正规表格，具有非`nil`值从`1`到给定`n`，它的长度就精确的是`n`，它的最后的值的索引。如果这个数组有“洞”（就是说在其他非`nil`值之间的`nil`值），则`#t`可以是直接前导于`nil`值的任何一个索引（就是说可以把任何这种`nil`值当作数组的结束）。

```lua
ExampleTable =
{
  {1, 2, 3, 4},
  {5, 6, 7, 8}
}
print(ExampleTable[1][3]) -- 打印"3"
print(ExampleTable[2][4]) -- 打印"8"
```

表格可以是对象的数组。

```lua
function Point(x, y)        -- "Point"对象构造器
  return { x = x, y = y }   -- 建立并返回新对象（表格）
end
array = { Point(10, 20), Point(30, 40), Point(50, 60) }   -- 建立point的数组
                        -- array = { { x = 10, y = 20 }, { x = 30, y = 40 }, { x = 50, y = 60 } };
print(array[2].y)                                         -- 打印40
```

使用散列映射来模拟数组通常比使用真正数组要慢；但Lua表格为用作数组而做了优化来避免这个问题。

### 元表格

可扩展的语义是Lua的关键特征，而“元表格”概念允许以强力方式来定制Lua的表格。下列例子展示了一个“无限”表格。对于任何`n`，`fibs[n]`会给出第`n`个斐波那契数，使用了动态规划和记忆化。

```lua
fibs = { 1, 1 }                                -- 给fibs[1]和fibs[2]初始值。
setmetatable(fibs, {
  __index = function(values, n)                --[[__index是Lua预定义的函数， 
                                                   如果"n"不存在则调用它。]]
    values[n] = values[n - 1] + values[n - 2]  -- 计算并记忆化fibs[n]。
    return values[n]
  end
})
local res = '斐波那契数: '; for idx = 1, 18 do res = res .. fibs[idx] .. '、 ' end; print(res)
```

```lua
斐波那契数: 1、 1、 2、 3、 5、 8、 13、 21、 34、 55、 89、 144、 233、 377、 610、 987、 1597、 2584、 
```

## 面向对象编程

尽管Lua没有内建的类的概念，可以用过两个语言特征实现面向对象编程：头等函数和表格。通过放置函数和有关数据入表格，形成一个对象。继承（单继承和多重继承二者）可以通过使用元表格机制来实现，告诉这个对象在哪些父对象中查找不存在的方法。

对于这些技术不采用“类”的概念，而是采用原型，类似于Self或JavaScript。建立新对象要么通过工厂方法（从头构造一个新对象），要么通过复制现存的对象。

建立一个基本的向量对象：

```lua
local Vector = {}
Vector.__index = Vector

function Vector:new(x, y, z)    -- 构造器
  return setmetatable({x = x, y = y, z = z}, Vector)
end

function Vector:magnitude()     -- 另一个方法
  -- 使用self引用隐蔽的对象
  return math.sqrt(self.x^2 + self.y^2 + self.z^2)
end

local vec = Vector:new(0, 1, 0) -- 建立一个向量
print(vec:magnitude())          -- 调用一个方法 (输出: 1)
print(vec.x)                    -- 访问一个成员变量 (输出: 0)
```

Lua为便利对象定向提供了一些语法糖。要声明在原型表格内的成员函数，可以使用function table:func(args)，它等价于function table.func(self, args)。调用类方法也使用冒号，object:func(args)等价于object.func(object, args)。

下面是使用语法糖的对应的类：

```lua
local Vector = {}
Vector.__index = Vector

function Vector:new(x, y, z)    -- 构造子
  -- 因为函数定义使用冒号， 
  -- 其第一个实际参数是"self"
  -- 它引用到"Vector"
  return setmetatable({x = x, y = y, z = z}, self)
end

function Vector:magnitude()     -- 另一个方法
  -- 使用self引用隐含的对象
  return math.sqrt(self.x^2 + self.y^2 + self.z^2)
end

local vec = Vector:new(0, 1, 0) -- 建立一个向量
print(vec:magnitude())          -- 调用方法（输出：1）
print(vec.x)                    -- 访问成员变量（输出：0）
```

### 继承

Lua支持使用元表格来使得Lua具有类继承。在这个例子中，我们允许向量在派生的类中将它们的值乘以一个常量：

```lua
local Vector = {}
Vector.__index = Vector

function Vector:new(x, y, z)    -- 构造子
  -- 这里的self引用到我们调用"new"方法的任何类
  -- 在派生的类中，self将是派生的类。
  -- 在Vector类中，self将是Vector。
  return setmetatable({x = x, y = y, z = z}, self)
end

function Vector:magnitude()     -- 另一个方法
  -- 使用self引用隐含的对象
  return math.sqrt(self.x^2 + self.y^2 + self.z^2)
end

-- 类继承的例子
local VectorMult = {}
VectorMult.__index = VectorMult
setmetatable(VectorMult, Vector) -- 使得VectorMult成为Vector的孩子

function VectorMult:multiply(value) 
  self.x = self.x * value
  self.y = self.y * value
  self.z = self.z * value
  return self
end

local vec = VectorMult:new(0, 1, 0) -- 建立一个向量
print(vec:magnitude())          -- 调用一个方法（输出：1）
print(vec.y)                    -- 访问一个成员变量（输出：1）
vec:multiply(2)                 -- 将向量的所有分量乘以2
print(vec.y)                    -- 再次访问成员变量（输出：2）
```

Lua还支持多重继承，__index可以要么是一个函数要么是一个表格。也支持运算符重载，Lua元表格通过设置元素比如__add、__sub等来重写表的操作符操作行为。

## 实现

Lua程序不是从文本式的Lua文件直接解释的，而是编译成字节码，接着把它运行在Lua虚拟机上。编译过程典型的对于用户是不可见并且是在运行时间进行的，但是它可以离线完成用来增加装载性能或通过排除编译器来减少对宿主环境的内存占用。Lua字节码还可以在Lua之内产生和执行，使用来自字符串库的`dump`函数和`load/loadstring/loadfile`函数。Lua版本5.3.4是用大约24,000行C代码实现的。

像大多数CPU，而不像多数虚拟机（它们是基于堆栈的），Lua VM是基于寄存器的，因此更加类似真实的硬件设计。寄存器架构既避免了过多的值复制又减少了每函数的指令的总数。Lua 5的虚拟机是第一个广泛使用的基于寄存器的纯VM。Parrot和Android的Dalvik是另外两个周知的基于寄存器的VM。PCScheme的VM也是基于寄存器的。

下面的例子列出上面定义的阶乘函数的字节码（通过`luac` 5.1编译器来展示）：

```
function <factorial.lua:1,7> (9 instructions, 36 bytes at 0x8063c60)
1 param, 6 slots, 0 upvalues, 6 locals, 2 constants, 0 functions
	1	[2]	LOADK    	1 -1	; 1
	2	[3]	LOADK    	2 -2	; 2
	3	[3]	MOVE     	3 0
	4	[3]	LOADK    	4 -1	; 1
	5	[3]	FORPREP  	2 1	; to 7
	6	[4]	MUL      	1 1 5
	7	[3]	FORLOOP  	2 -2	; to 6
	8	[6]	RETURN   	1 2
	9	[7]	RETURN   	0 1
```

## C API

Lua意图被嵌入到其他应用之中，为了这个目的而提供了C API。API被分成两部分：Lua核心库和辅助库。Lua API的设计消除了对用C代码的手动引用管理的需要，不同于Python的API。API就像语言本身一样是极简主义的。高级功能通过辅助库来提供，它们很大程度上构成自预处理器宏，用以帮助做复杂的表格操作。

Lua C API是基于堆栈的。Lua提供压入和弹出最简单C数据类型（整数、浮点数等）进入和离开堆栈的函数，还有通过堆栈操作表格的函数。Lua堆栈稍微不同于传统堆栈，例如堆栈可以直接的被索引。负数索引指示从栈顶开始往下的偏移量。例如−1是在顶部的（最新进压入的值），而整数索引指示从底部（最旧的值）往上的偏移量。在C和Lua函数之间集结数据也使用堆栈完成。要调用一个Lua函数，把实际参数压入堆栈，并接着使用`lua_call`来调用实际的函数。在写从Lua直接调用的C函数的时候，实际参数读取自堆栈。

下面是从C调用Lua函数的例子:

```c
#include <stdio.h>
#include <lua.h> // Lua主要库 (lua_*)
#include <lauxlib.h> // Lua辅助库 (luaL_*)

int main(void)
{
    // 建立一个Lua状态
    lua_State *L = luaL_newstate();

    // 装载并执行一个字符串
    if (luaL_dostring(L, "function foo (x,y) return x+y end")) {
        lua_close(L);
        return -1;
    }

    // 压入全局"foo"（上面定义的函数）的值
    // 到堆栈，跟随着整数5和3
    lua_getglobal(L, "foo");
    lua_pushinteger(L, 5);
    lua_pushinteger(L, 3);
    lua_call(L, 2, 1); // 调用有二个实际参数和一个返回值的函数
    printf("Result: %d\n", lua_tointeger(L, -1)); // 打印在栈顶的项目的整数值
    lua_pop(L, 1); // 返回堆栈至最初状态
    lua_close(L); // 关闭Lua状态
    return 0;
}
```

如下这样运行这个例子：

```console
$ cc -o example example.c -llua
$ ./example
Result: 8
```

C API还提供一些特殊表格，位于各种Lua堆栈中的“伪索引”之上。Lua 5.2之前，在`LUA_GLOBALSINDEX`之上是全局表格；`_G`来自Lua内部，它是主名字空间。还有一个注册表位于`LUA_REGISTRYINDEX`，在这里C程序可以存储Lua值用于以后检索。

还可以使用Lua API写扩展模块。扩展模块是通过向Lua脚本提供本地设施，用来扩展解释器的功能的共享对象。从Lua方面看来，这种模块出现为一个名字空间表格，它持有自己的函数和变量。Lua脚本可以使用`require`装载扩展模块，就像用Lua自身写的模块一样。一组仍在增长中的叫做“rock”的模块可以通过叫做LuaRocks的软件包管理器获取到，类似于CPAN、RubyGems和Setuptools。对大多数流行的编程语言包括其他脚本语言，都存在预先写好的Lua绑定。对于C++，有许多基于模板的方式和一些自动绑定生成器。

## 应用

在视频游戏开发中，Lua被程序员广泛的用作脚本语言，主要由于它的可感知到的易于嵌入、快速执行，和短学习曲线。

在2003年，GameDev.net组织的一次投票，说明了Lua是游戏编程的最流行脚本语言。在2012年1月12日，Lua被《游戏开发者 (期刊)》宣布为编程工具范畴的Front Line奖2011年度获奖者。

大量非游戏应用也出于可扩展性而使用Lua，比如TeX排版设置语言实现LuaTeX、键-值数据库Redis、文本编辑器Neovim和web服务器Nginx。

通过Scribunto扩展，Lua可获得为MediaWiki软件中的服务器端脚本语言，Wikipedia和其他wiki都基于了它。它的应用包括允许从Wikidata集成数据到文章中，和助力于自动生物分类框系统。

Lua可以用于嵌入式硬件，不仅可以嵌入其他编程语言，而且可以嵌入微处理器中，例如NodeMCU开源硬件项目将Lua嵌入到Wi-Fi SoC中，另外，游戏平台Roblox所有游戏都是利用Lua进行编程的。另外, 还有中国大陆发起的开源LuatOS项目，也是将Lua应用到嵌入式领域，但不仅限于Wifi，它包含2G/4G/NBIOT等通信模块，也包含stm32/w800等嵌入式mcu，同时也支持在windows/linux平台上执行的模拟器。

## 派生语言

### 编译成Lua的语言

以Lua作为编译目标输出的编程语言：

- Moonscript，是动态、空白敏感的脚本语言，它受到CoffeeScript的启发，编译成Lua。
- Haxe，支持编译成Lua目标，支持Lua 5.1-5.3还有LuaJIT 2.0和2.1。
- Fennel，目标为Lua的Lisp方言。
- Urn，建造在Lua之上的Lisp方言。
- Amulet，类ML的函数式语言，其编译器输出Lua文件。
- LunarML，产生Lua/JavaScript代码的Standard ML编译器。

### 方言

- LuaJIT，Lua 5.1的即时编译器。
- Luau (程式语言)，由Roblox Corporation开发，并运用于Roblox平台，派生自Lua 5.1，具有渐进类型，补充特征并关注于性能。
- Ravi，启用了JIT的Lua 5.3语言并具有可选的静态类型。JIT由类型信息来指导。
- Shine，既有很多扩展的LuaJIT分叉，包括了模块系统和宏系统。
- Glua，嵌入到游戏盖瑞模组中作为其脚本语言的一个Lua修改版本。
- Teal，用Lua编写的静态类型的Lua方言。

此外，Lua用户社区在参考C语言实现之上提供了一些“能力补丁”。

## 延伸阅读

- (The 1st ed. is available online .)
- Chapters 6 and 7 are dedicated to Lua, while others look at software in Brazil more broadly.
- Interview with Roberto Ierusalimschy.
- How the embeddability of Lua impacted its design.
- Lua papers and theses

## 基本资料

- 编程范型：多范型：脚本，指令式（过程式，基于原型，面向对象），函数式
- 发行时间：1993年
- 设计者：Roberto Ierusalimschy、Waldemar Celes、Luiz Henrique de Figueiredo
- 软件版本周期：Q207316
- 类型系统：动态、强类型、鸭子
- 软件实现：//www.lua.org/download.html Lua, LuaJIT, //eliasdaler.github.io/luavela/ LuaVela, MoonSharp, //luvit.io Luvit, //www.luart.org LuaRT
- 实作语言：ANSI C
- dialects： Metalua, Idle, GSL Shell, Luau
- 受影响于：Scheme、SNOBOL、Modula-2、CLU、C++
- 施影响于：GameMonkey Script, Io, JavaScript, Julia, MiniD, Red (编程语言), Ring, Ruby, Squirrel (编程语言), MoonScript, C--
- 操作系统：跨平台
- 许可证：MIT许可证
- 文件扩展名：.lua