2013-11-18 19:41:19 +00:00
|
|
|
# Lua API documentation
|
|
|
|
|
|
|
|
We the [Lua](http://www.lua.org) script language to customize and
|
|
|
|
extend [Lean](http://leanprover.net). This
|
|
|
|
[link](http://www.lua.org/docs.html) is a good starting point for
|
|
|
|
learning Lua. In this document, we focus on the Lean specific APIs.
|
|
|
|
Most of Lean components are exposed in the Lua API.
|
|
|
|
|
|
|
|
**Remark:** the script [md2lua.sh](md2lua.sh) extracts the Lua code
|
|
|
|
examples from the `*.md` documentation files in this directory.
|
|
|
|
|
|
|
|
## Hierarchical names
|
|
|
|
|
|
|
|
In Lean, we use _hierarchical names_ for identifying configuration
|
|
|
|
options, constants, and kernel objects. A hierarchical name is
|
|
|
|
essentially a list of strings and integers.
|
|
|
|
The following example demonstrates how to create and manipulate
|
|
|
|
hierarchical names using the Lua API.
|
|
|
|
|
|
|
|
```lua
|
|
|
|
local x = name("x") -- create a simple hierarchical name
|
|
|
|
local y = name("y")
|
|
|
|
-- In Lua, 'assert(p)' succeeds if 'p' does not evaluate to false (or nil)
|
|
|
|
assert(x == name("x")) -- test if 'x' is equal to 'name("x")'
|
|
|
|
assert(x ~= y) -- '~=' is the not equal operator in Lua
|
|
|
|
assert(x ~= "x")
|
|
|
|
|
|
|
|
assert(is_name(x)) -- test whether argument is a hierarchical name or not.
|
|
|
|
assert(not is_name("x"))
|
|
|
|
|
|
|
|
local x1 = name(x, 1) -- x1 is a name composed of the string "x" and number 1
|
|
|
|
assert(tostring(x1) == "x::1")
|
|
|
|
assert(x1 ~= name("x::1")) -- x1 is not equal to the string x::1
|
|
|
|
assert(x1 == name("x", 1))
|
|
|
|
|
|
|
|
local o = name("lean", "pp", "colors")
|
|
|
|
-- The previous construct is syntax sugar for the following expression
|
|
|
|
assert(o == name(name(name("lean"), "pp"), "colors"))
|
|
|
|
|
|
|
|
assert(x < y) -- '<' is a total order on hierarchical names
|
|
|
|
|
|
|
|
local h = x:hash() -- retrieve the hash code for 'x'
|
|
|
|
assert(h ~= y:hash())
|
|
|
|
```
|
2013-11-19 05:23:06 +00:00
|
|
|
|
|
|
|
## Lua tables
|
|
|
|
|
|
|
|
Tables are the only mutable, non-atomic type of data in Lua. Tables
|
|
|
|
are used to implement mappings, arrays, lists, objects, etc. Here is a
|
|
|
|
small examples demonstrating how to use Lua tables:
|
|
|
|
|
|
|
|
```lua
|
|
|
|
local t = {} -- create an empty table
|
|
|
|
t["x"] = 10 -- insert the entry "x" -> 10
|
|
|
|
t.x = 20 -- syntax-sugar for t["x"] = 20
|
|
|
|
t["y"] = 30 -- insert the entry "y" -> 30
|
|
|
|
assert(t["x"] == 20)
|
|
|
|
local p = { x = 10, y = 20 } -- create a table with two entries
|
|
|
|
assert(p.x == 10)
|
|
|
|
assert(p["x"] == 10)
|
|
|
|
assert(p.y == 20)
|
|
|
|
assert(p["y"] == 20)
|
|
|
|
```
|
|
|
|
|
|
|
|
Arrays are implemented by indexing tables with integers.
|
|
|
|
The arrays don't have a fixed size and grow dynamically.
|
|
|
|
The arrays in Lua usually start at index 1. The Lua libraries
|
|
|
|
use this convention. The following example initializes
|
|
|
|
an array with 100 elements.
|
|
|
|
|
|
|
|
```lua
|
|
|
|
local a = {} -- new array
|
|
|
|
for i=1, 100 do
|
|
|
|
a[i] = 0
|
|
|
|
end
|
|
|
|
local b = {2, 4, 6, 8, 10} -- create an array with 5 elements
|
|
|
|
assert(#b == 5) -- array has 5 elements
|
|
|
|
assert(b[1] == 2)
|
|
|
|
assert(b[2] == 4)
|
|
|
|
```
|
|
|
|
In Lua, we cannot provide custom hash and equality functions to tables.
|
|
|
|
So, we cannot effectively use Lua tables to implement mappings where
|
|
|
|
the keys are Lean hierarchical names, expressions, etc.
|
|
|
|
The following example demonstrates the issue.
|
|
|
|
|
|
|
|
```lua
|
|
|
|
local m = {} -- create empty table
|
|
|
|
local a = name("a")
|
|
|
|
m[a] = 10 -- map the hierarchical name 'a' to 10
|
|
|
|
assert(m[a] == 10)
|
|
|
|
local a1 = name("a")
|
|
|
|
assert(a == a1) -- 'a' and 'a1' are the same hierarchical name
|
|
|
|
assert(m[a1] == nil) -- 'a1' is not a key in the mapping 'm'
|
|
|
|
assert(m[a] == 10)
|
|
|
|
-- 'a' and 'a1' are two instances of the same object
|
|
|
|
-- Lua tables assume that different instances are not equal
|
|
|
|
```
|
|
|
|
|
|
|
|
## Splay maps
|
|
|
|
|
|
|
|
In Lean, we provide splay maps for implementing mappings where the keys are
|
2013-11-19 05:29:48 +00:00
|
|
|
Lean objects such as hierarchical names. A splay map is implemented using
|
|
|
|
a [splay tree](http://en.wikipedia.org/wiki/Splay_tree), a self-adjusting binary
|
|
|
|
search tree. We can also use Lua atomic data types
|
2013-11-19 05:23:06 +00:00
|
|
|
as keys in splay maps. However, we should not mix different types in the
|
|
|
|
same splay map. The Lean splay map assumes that `<` is a total order on the
|
|
|
|
keys inserted in the map.
|
|
|
|
|
|
|
|
```lua
|
|
|
|
local m = splay_map() -- create an empty splay map
|
2013-11-19 21:31:35 +00:00
|
|
|
assert(is_splay_map(m))
|
2013-11-19 05:23:06 +00:00
|
|
|
assert(#m == 0)
|
|
|
|
local a = name("a", 1)
|
|
|
|
local a1 = name("a", 1)
|
|
|
|
m:insert(a, 10) -- add the entry 'a::1' -> 10
|
|
|
|
assert(m:find(a1) == 10)
|
|
|
|
m:insert(name("b"), 20)
|
|
|
|
assert(#m == 2)
|
|
|
|
m:erase(a) -- remove entry with key 'a::1'
|
|
|
|
assert(m:find(a) == nil)
|
|
|
|
assert(not m:contains(a))
|
|
|
|
assert(#m == 1)
|
|
|
|
m:insert(name("c"), 30)
|
|
|
|
m:for_each( -- traverse the entries in the splay map
|
|
|
|
function(k, v) -- executing the given function
|
|
|
|
print(k, v)
|
|
|
|
end
|
|
|
|
)
|
|
|
|
local m2 = m:copy() -- the splay maps are copied in constant time
|
|
|
|
assert(#m2 == #m)
|
|
|
|
m2:insert(name("b", 2), 40)
|
|
|
|
assert(#m2 == #m + 1)
|
|
|
|
```
|
2013-11-19 21:31:35 +00:00
|
|
|
|
|
|
|
## Multiple precision numerals
|
|
|
|
|
|
|
|
We expose [GMP](http://gmplib.org/) (GNU Multiple precision arithmetic
|
|
|
|
library) in Lua. Internally, Lean uses multiple precision numerals for
|
|
|
|
representing expressing containing numerals.
|
|
|
|
In Lua, we can create multiple precision integers (_mpz_) and multiple
|
|
|
|
precision rationals (_mpq_). The following example demonstrates how to
|
|
|
|
use `mpz` and `mpq` numerals.
|
|
|
|
|
|
|
|
```lua
|
|
|
|
local ten = mpz(10) -- create the mpz numeral 10.
|
|
|
|
assert(is_mpz(ten)) -- test whether 'ten' is a mpz numeral or not
|
|
|
|
assert(not is_mpz(10))
|
|
|
|
local big = mpz("100000000000000000000000") -- create a mpz numeral from a string
|
|
|
|
-- The operators +, -, *, /, ^, <, <=, >, >=, ==, ~=
|
|
|
|
-- The operators +, -, *, /, ^ accept mixed mpz and Lua native types
|
|
|
|
assert(ten + 1 == mpz(11))
|
|
|
|
-- In Lua, objects of different types are always different
|
|
|
|
-- So, the mpz number 10 is different from the native Lua numeral 10
|
|
|
|
assert(mpz(10) ~= 10)
|
|
|
|
assert(mpz(3) / 2 == mpz(1))
|
|
|
|
-- The second argument of ^ must be a non-negative Lua numeral
|
|
|
|
assert(mpz(10) ^ 100 > mpz("1000000000000000000000000"))
|
|
|
|
assert(mpz(3) * mpz("1000000000000000000000") == mpz("3000000000000000000000"))
|
|
|
|
assert(mpz(4) + "10" == mpz(14))
|
|
|
|
local q1 = mpq(10) -- create the mpq numeral 10
|
|
|
|
local q2 = q1 / 3 -- create the mpq numeral 10/3
|
|
|
|
assert(q2 == mpq("10/3"))
|
|
|
|
local q3 = mpq(0.25) -- create the mpq numeral 1/4
|
|
|
|
assert(q3 == mpq(1)/4)
|
|
|
|
assert(is_mpq(q3)) -- test whether 'q3' is a mpq numeral or not
|
|
|
|
assert(not is_mpq(mpz(10))) -- mpz numerals are not mpq
|
|
|
|
assert(ten == mpz(10))
|
|
|
|
local q4 = mpq(ten) -- convert the mpz numeral 'ten' into a mpq numeral
|
|
|
|
assert(is_mpq(q4))
|
|
|
|
assert(mpq(1)/3 + mpq(2)/3 == mpq(1))
|
|
|
|
assert(mpq(0.5)^5 == mpq("1/32"))
|
|
|
|
assert(mpq(1)/2 > mpq("1/3"))
|
|
|
|
```
|
|
|
|
|
|
|
|
|