├── docs
├── cover.jpg
├── excerpt.pdf
├── LuaQuickReference2.pdf
├── _layouts
│ └── default.html
├── style.css
└── index.md
├── ex22.lua
├── ex07.lua
├── ex16.lua
├── ex04.lua
├── ex15.lua
├── ex20.lua
├── ex05.lua
├── ex10.lua
├── ex21.lua
├── ex06.lua
├── ex19.lua
├── ex03.lua
├── ex23.c
├── ex01.lua
├── ex02.lua
├── README
├── ex11.lua
├── ex25.c
├── Makefile
├── ex18.lua
├── ex24.c
├── ex12.lua
├── ex27.c
├── ex09.lua
├── ex14.lua
├── ex28.c
├── ex30.c
├── ex17.lua
├── ex32.c
├── ex08.lua
├── ex29.c
├── ex26.c
├── ex34.c
├── ex13.lua
├── ex33.c
└── ex31.c
/docs/cover.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbitalquark/lua-quick-reference/HEAD/docs/cover.jpg
--------------------------------------------------------------------------------
/docs/excerpt.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbitalquark/lua-quick-reference/HEAD/docs/excerpt.pdf
--------------------------------------------------------------------------------
/docs/LuaQuickReference2.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orbitalquark/lua-quick-reference/HEAD/docs/LuaQuickReference2.pdf
--------------------------------------------------------------------------------
/ex22.lua:
--------------------------------------------------------------------------------
1 | -- Example 22. Compute a date 90 days in the future
2 | local time = os.date("*t") -- e.g. 01 May 2017
3 | time.day = time.day + 90
4 | local future = os.time(time)
5 | os.date("%d %b %Y", future) -- e.g. 30 Jul 2017
6 |
7 | --8<----------------------------------------------------------------------------
8 | print(os.date("%d %b %Y", future))
9 | --8<----------------------------------------------------------------------------
10 |
--------------------------------------------------------------------------------
/ex07.lua:
--------------------------------------------------------------------------------
1 | -- Example 7. Create a read-only table
2 | local t = { --[[ read-only table contents ]] }
3 | t = setmetatable({}, {
4 | __index = t,
5 | __newindex = function() error("read-only table") end
6 | })
7 |
8 | --8<----------------------------------------------------------------------------
9 | rawset(t,'x', 1)
10 | rawset(t,'y', 2)
11 | print(t.x, t.y)
12 | t.z = 3
13 | --8<----------------------------------------------------------------------------
14 |
--------------------------------------------------------------------------------
/ex16.lua:
--------------------------------------------------------------------------------
1 | -- Example 16. Pretty print a table
2 |
3 | --8<----------------------------------------------------------------------------
4 | t = {a = 1, b = 2, c = 3}
5 | --8<----------------------------------------------------------------------------
6 |
7 | -- Print something like "{a = 1, b = 2, c = 3}".
8 | local items = {}
9 | for k, v in pairs(t) do
10 | items[#items + 1] = string.format("%s = %s", k, v)
11 | end
12 | table.sort(items)
13 | print(string.format("{%s}", table.concat(items, ", ")))
14 |
--------------------------------------------------------------------------------
/ex04.lua:
--------------------------------------------------------------------------------
1 | -- Example 4. Function that accepts variable arguments
2 | function handle_event(event_name, ...)
3 | local f = event_handlers[event_name]
4 | if f then
5 | -- Forward all event parameters to the event
6 | -- handler function.
7 | return f(...)
8 | end
9 | end
10 |
11 | --8<----------------------------------------------------------------------------
12 | event_handlers = {
13 | foo = function(...) print('handling foo', ...) end
14 | }
15 | handle_event('foo', 1, 2, 3)
16 | --8<----------------------------------------------------------------------------
17 |
--------------------------------------------------------------------------------
/ex15.lua:
--------------------------------------------------------------------------------
1 | -- Example 15. Iterate over a table in order by string keys
2 | -- Create the table to be iterated over.
3 | local t = {a = 1, b = 2, c = 3, z = 26}
4 | -- Create intermediate list of keys and sort it.
5 | local keys = {}
6 | for k, v in pairs(t) do
7 | keys[#keys + 1] = k
8 | end
9 | table.sort(keys)
10 | -- Now iterate in key order.
11 | for _, k in ipairs(keys) do
12 | local v = t[k]
13 | --[[ process v ]]
14 | --8<--------------------------------------------------------------------------
15 | print(k, v)
16 | --8<--------------------------------------------------------------------------
17 | end
18 |
--------------------------------------------------------------------------------
/ex20.lua:
--------------------------------------------------------------------------------
1 | -- Example 20. Obtain a file's size before processing it
2 |
3 | --8<----------------------------------------------------------------------------
4 | local filename = '/home/mitchell/code/textadept/init.lua'
5 | --8<----------------------------------------------------------------------------
6 |
7 | local f = io.open(filename, "r")
8 | local size = f:seek("end")
9 | f:seek("set") -- restore position to beginning of file
10 |
11 | --8<----------------------------------------------------------------------------
12 | print(size)
13 | --8<----------------------------------------------------------------------------
14 |
--------------------------------------------------------------------------------
/docs/_layouts/default.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{ page.title }}
5 |
6 |
7 |
8 |
9 |
10 |
13 |
14 | {{ content }}
15 |
16 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/ex05.lua:
--------------------------------------------------------------------------------
1 | -- Example 5. Overload concatenation for a list
2 | local t1, t2 = {1, 2, 3}, {4, 5, 6}
3 | local mt = {}
4 | function mt.__concat(a, b)
5 | local t = {}
6 | -- Add all elements of a to t.
7 | for i = 1, #a do t[#t + 1] = a[i] end
8 | -- Add all elements of b to t.
9 | for i = 1, #b do t[#t + 1] = b[i] end
10 | return t
11 | end
12 | setmetatable(t1, mt)
13 | local t3 = t1 .. t2 -- results in {1, 2, 3, 4, 5, 6}
14 |
15 | --8<----------------------------------------------------------------------------
16 | print(table.unpack(t3))
17 | --8<----------------------------------------------------------------------------
18 |
--------------------------------------------------------------------------------
/ex10.lua:
--------------------------------------------------------------------------------
1 | -- Example 10. Control global variable access and assignment
2 | setmetatable(_G, {
3 | __index = function(t, key)
4 | local errmsg = "Unknown global '%s'"
5 | error(string.format(errmsg, key))
6 | end,
7 | __newindex = function(t, key, value)
8 | local errmsg = "Attempt to create global '%s'. \z
9 | Use rawset() instead."
10 | error(string.format(errmsg, key))
11 | end
12 | })
13 |
14 | --8<----------------------------------------------------------------------------
15 | xpcall(function() print(x) end, print)
16 | xpcall(function() x = 1 end, print)
17 | --8<----------------------------------------------------------------------------
18 |
--------------------------------------------------------------------------------
/ex21.lua:
--------------------------------------------------------------------------------
1 | -- Example 21. Fetch the contents of a directory
2 |
3 | --8<----------------------------------------------------------------------------
4 | local dir = '/home/mitchell/code/textadept/'
5 | --8<----------------------------------------------------------------------------
6 |
7 | local filenames = {} -- or "dir /B "
8 | local p = io.popen("ls -1 " .. dir)
9 | for filename in p:lines() do
10 | filenames[#filenames + 1] = filename
11 | end
12 |
13 | --8<----------------------------------------------------------------------------
14 | for i = 1, #filenames do
15 | print(filenames[i])
16 | end
17 | --8<----------------------------------------------------------------------------
18 |
--------------------------------------------------------------------------------
/ex06.lua:
--------------------------------------------------------------------------------
1 | -- Example 6. Processing a file
2 | local filenames = { --[[ list of filenames... ]] }
3 | --8<----------------------------------------------------------------------------
4 | filenames = {'/usr/share/dict/words'}
5 | --8<----------------------------------------------------------------------------
6 | for i = 1, #filenames do
7 | local f = io.open(filenames[i])
8 | if f then
9 | --8<------------------------------------------------------------------------
10 | local n = select(2, f:read('a'):gsub('\n', '\n'))
11 | print(n .. ' words')
12 | --8<------------------------------------------------------------------------
13 | --[[ process file... ]]
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/ex19.lua:
--------------------------------------------------------------------------------
1 | -- Example 19. Echo lines matching a Lua pattern
2 |
3 | --8<----------------------------------------------------------------------------
4 | local lines = {
5 | 'foo\n',
6 | '2017/01/01\n',
7 | 'bar\n',
8 | '2017/02/01\n',
9 | 'baz\n'
10 | }
11 | local i = 0
12 | io.read = function()
13 | i = i + 1
14 | return lines[i]
15 | end
16 | --8<----------------------------------------------------------------------------
17 |
18 | local date_patt = "%d+/%d+/%d+"
19 | local line = io.read("*L")
20 | while line do
21 | if line:find(date_patt) then
22 | io.write(line)
23 | end
24 | line = io.read("*L")
25 | end
26 | -- Note: for line in io.lines(io.stdin, "*L") do … end
27 | -- is also valid.
28 |
--------------------------------------------------------------------------------
/ex03.lua:
--------------------------------------------------------------------------------
1 | -- Example 3. Numerical antiderivative (integral) function
2 | local function F(f, dx)
3 | dx = dx or 1e-4
4 | -- Trapezoidal numeric integration function that uses
5 | -- upvalues 'f' and 'dx'.
6 | return function(b)
7 | local sum, a = 0, 0
8 | for x = a, b, dx do
9 | sum = sum + (f(x) + f(x + dx)) / 2 * dx
10 | end
11 | return sum
12 | end
13 | end
14 | -- x2 = ∫ 2x dx
15 | local x2 = F(function(x) return 2 * x end)
16 | -- x2(0), x2(1), x2(2), x2(3) gives approx. 0, 1, 4, 9
17 |
18 | --8<----------------------------------------------------------------------------
19 | print(x2(0), x2(1), x2(2), x2(3))
20 | --8<----------------------------------------------------------------------------
21 |
--------------------------------------------------------------------------------
/ex23.c:
--------------------------------------------------------------------------------
1 | // Example 23. Simple stand-alone Lua interpreter
2 | #include "lua.h"
3 | #include "lauxlib.h"
4 | #include "lualib.h"
5 |
6 | int main(int argc, char **argv) {
7 | int status = 0;
8 | // Create a new embedded Lua interpreter.
9 | lua_State *L = luaL_newstate();
10 | // Load all of Lua's standard library modules.
11 | luaL_openlibs(L);
12 | // Execute the Lua script specified on the command
13 | // line. If there is an error, report it.
14 | if (argc > 1 && luaL_dofile(L, argv[1]) != LUA_OK) {
15 | const char *errmsg = lua_tostring(L, -1);
16 | fprintf(stderr, "Lua error: %s\n", errmsg);
17 | status = 1;
18 | }
19 | // Close the Lua interpreter.
20 | lua_close(L);
21 | return status;
22 | }
23 |
--------------------------------------------------------------------------------
/ex01.lua:
--------------------------------------------------------------------------------
1 | -- Example 1. Sieve of Eratosthenes
2 | function sieve(n)
3 | -- Construct initial {2..n} table.
4 | local is_prime = {}
5 | for i = 2, n do
6 | is_prime[i] = true
7 | end
8 | -- Strike out all existing multiples of primes.
9 | for i = 2, math.sqrt(n) do
10 | if is_prime[i] then
11 | for j = i^2, n, i do
12 | is_prime[j] = false
13 | end
14 | end
15 | end
16 | -- Construct the final primes list.
17 | local primes = {}
18 | for i = 2, n do
19 | if is_prime[i] then
20 | primes[#primes + 1] = i
21 | end
22 | end
23 | return primes
24 | end
25 |
26 | --8<----------------------------------------------------------------------------
27 | print(table.unpack(sieve(30)))
28 | --8<----------------------------------------------------------------------------
29 |
--------------------------------------------------------------------------------
/ex02.lua:
--------------------------------------------------------------------------------
1 | -- Example 2. Emulating "continue" with goto
2 | local function open_files(filenames)
3 | for i = 1, #filenames do
4 | local text = ""
5 | local f = io.open(filenames[i])
6 | if f then
7 | text = f:read("a")
8 | if not text then goto continue end -- cannot read
9 | f:close()
10 | --8<----------------------------------------------------------------------
11 | print('opened', filenames[i])
12 | --8<----------------------------------------------------------------------
13 | end
14 | --[[ process text ]]
15 | ::continue::
16 | end
17 | end
18 |
19 | --8<----------------------------------------------------------------------------
20 | open_files{'/etc/shadow','/etc/fstab'}
21 | --8<----------------------------------------------------------------------------
22 |
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
1 | These examples come from:
2 |
3 | Lua Quick Reference
4 | Second Edition
5 | Published: May 2020
6 | ISBN: 978-0-9912379-5-1
7 | Pages: 169
8 |
9 | https://orbitalquark.github.io/lua-quick-reference/
10 |
11 | The contents of these examples may also include test code and/or boilerplate
12 | code delimitted by "snipped" comments.
13 |
14 | In Lua, snipped comments look like:
15 |
16 | --8<---------------------------------------------------------------------------
17 | Test and/or boilerplate code not included in the book.
18 | --8<---------------------------------------------------------------------------
19 |
20 | In C, snippet comments look like:
21 |
22 | //8<---------------------------------------------------------------------------
23 | Test and/or boilerplate code not included in the book.
24 | //8<---------------------------------------------------------------------------
25 |
--------------------------------------------------------------------------------
/ex11.lua:
--------------------------------------------------------------------------------
1 | -- Example 11. Handle string encoding errors
2 |
3 | --8<----------------------------------------------------------------------------
4 | filename = '/home/mitchell/code/textadept/init.lua'
5 | toutf8 = function() error('conversion failed') end
6 | --toutf8 = function() return 'utf-8' end
7 | --8<----------------------------------------------------------------------------
8 |
9 | local encodings = {
10 | "UTF-8", "UTF-16", "UTF-32", "ASCII", "ISO-8859-1"
11 | }
12 | local f = io.open(filename, "r")
13 | local text = f:read("a")
14 | f:close()
15 | for i = 1, #encodings do
16 | -- Attempt to convert file contents to UTF-8.
17 | local ok, conv = pcall(toutf8, text, encodings[i])
18 | if ok then
19 | text = conv
20 | goto encoding_detected
21 | end
22 | end
23 | error("Could not detect file encoding.")
24 | ::encoding_detected::
25 | --[[ process UTF-8-encoded text ]]
26 |
--------------------------------------------------------------------------------
/ex25.c:
--------------------------------------------------------------------------------
1 | // Example 25. Push a lower-case copy of a string
2 |
3 | //8<----------------------------------------------------------------------------
4 | #include
5 | #include
6 | #include "lua.h"
7 | #include "lauxlib.h"
8 | #include "lualib.h"
9 |
10 | int main(int argc, char **argv) {
11 | lua_State *L = luaL_newstate();
12 | luaL_openlibs(L);
13 | const char *s = "TEST";
14 | //8<----------------------------------------------------------------------------
15 |
16 | luaL_Buffer b;
17 | size_t len = strlen(s);
18 | char *p = luaL_buffinitsize(L, &b, len);
19 | for (int i = 0; i < len; i++)
20 | p[i] = tolower((unsigned char)s[i]);
21 | luaL_pushresultsize(&b, len);
22 |
23 | //8<----------------------------------------------------------------------------
24 | printf("%s\n", lua_tostring(L, -1));
25 | if (lua_gettop(L) > 1) printf("stack size != 1\n");
26 | lua_close(L);
27 | return 0;
28 | }
29 | //8<----------------------------------------------------------------------------
30 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | LUA_PREFIX=/tmp/lua-5.4.0/install
2 | CC = gcc
3 | CFLAGS = -g -std=c99 -I $(LUA_PREFIX)/include
4 | LDFLAGS = $(LUA_PREFIX)/lib/liblua.a -lm -ldl
5 | #LDFLAGS = -llua -lm -ldl
6 |
7 | exes = ex23 ex24 ex25 ex26 ex27 ex28 ex29 ex30 ex31 ex32 ex33 ex34
8 | all: $(exes)
9 |
10 | ex23: ex23.c; $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)
11 | ex24: ex24.c; $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)
12 | ex25: ex25.c; $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)
13 | ex26: ex26.c; $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)
14 | ex27: ex27.c; $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)
15 | ex28: ex28.c; $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)
16 | ex29: ex29.c; $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)
17 | ex30: ex30.c; $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)
18 | ex31: ex31.c; $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)
19 | ex32: ex32.c; $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)
20 | ex33: ex33.c; $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)
21 | ex34: ex34.c; $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)
22 |
23 | clean:
24 | rm -f $(exes)
25 |
26 | run: $(exes)
27 | for exe in $(exes); do ./$$exe; done
28 | for lua in `ls *.lua`; do ./ex23 $$lua; done
29 |
--------------------------------------------------------------------------------
/ex18.lua:
--------------------------------------------------------------------------------
1 | -- Example 18. Generate list permutations
2 | -- Permutes a list by taking each element and
3 | -- recursively re-ordering the remaining elements.
4 | -- For instance, given {1, 2, 3}:
5 | -- Takes 1 and re-orders 2 and 3 (1, 2, 3 and 1, 3, 2).
6 | -- Takes 2 and re-orders 1 and 3 (2, 1, 3 and 2, 3, 1).
7 | -- Takes 3 and re-orders 1 and 2 (3, 1, 2 and 3, 2, 1).
8 | local function permute(list, i)
9 | i = i or 1
10 | if i > #list then
11 | coroutine.yield(list)
12 | else
13 | for j = i, #list do
14 | list[i], list[j] = list[j], list[i]
15 | permute(list, i + 1)
16 | list[i], list[j] = list[j], list[i]
17 | end
18 | end
19 | end
20 | -- Iterator.
21 | local function permutations(list)
22 | return coroutine.wrap(function() permute(list) end)
23 | end
24 | for permutation in permutations{1, 2, 3} do
25 | --[[ process permutation ]]
26 | --8<--------------------------------------------------------------------------
27 | print(table.unpack(permutation))
28 | --8<--------------------------------------------------------------------------
29 | end
30 |
--------------------------------------------------------------------------------
/ex24.c:
--------------------------------------------------------------------------------
1 | // Example 24. Push the entire contents of a file as a string
2 |
3 | //8<----------------------------------------------------------------------------
4 | #include
5 | #include
6 | #include "lua.h"
7 | #include "lauxlib.h"
8 | #include "lualib.h"
9 |
10 | int main(int argc, char **argv) {
11 | lua_State *L = luaL_newstate();
12 | luaL_openlibs(L);
13 | const char *filename = "/home/mitchell/code/textadept/src/textadept.c";
14 | //8<----------------------------------------------------------------------------
15 |
16 | FILE *f = fopen(filename, "r");
17 | luaL_Buffer b;
18 | luaL_buffinit(L, &b);
19 | char buf[BUFSIZ];
20 | while (fgets(buf, BUFSIZ, f) != NULL)
21 | luaL_addlstring(&b, buf, strlen(buf));
22 | luaL_pushresult(&b);
23 | fclose(f);
24 |
25 | //8<----------------------------------------------------------------------------
26 | printf("%s\n", lua_tostring(L, -1));
27 | if (lua_gettop(L) > 1) printf("stack size != 1\n");
28 | lua_close(L);
29 | return 0;
30 | }
31 | //8<----------------------------------------------------------------------------
32 |
--------------------------------------------------------------------------------
/ex12.lua:
--------------------------------------------------------------------------------
1 | -- Example 12. Safely load a configuration file
2 |
3 | --8<----------------------------------------------------------------------------
4 | local f = io.open('config.lua', 'w')
5 | f:write([[
6 | --8<----------------------------------------------------------------------------
7 |
8 | -- File "config.lua".
9 | width = 600
10 | height = 400
11 | home_path = "/home/mitchell"
12 |
13 | --8<----------------------------------------------------------------------------
14 | ]])
15 | f:close()
16 | --8<----------------------------------------------------------------------------
17 |
18 | -- Program code.
19 | local config = {}
20 | assert(loadfile("config.lua", "t", config))()
21 | for option, setting in pairs(config) do
22 | --[[ process option and setting ]]
23 | --8<--------------------------------------------------------------------------
24 | print(option, setting)
25 | --8<--------------------------------------------------------------------------
26 | end
27 |
28 | --8<----------------------------------------------------------------------------
29 | os.remove('config.lua')
30 | --8<----------------------------------------------------------------------------
31 |
--------------------------------------------------------------------------------
/ex27.c:
--------------------------------------------------------------------------------
1 | // Example 27. Delete all string keys from a table
2 |
3 | //8<----------------------------------------------------------------------------
4 | #include "lua.h"
5 | #include "lauxlib.h"
6 | #include "lualib.h"
7 |
8 | int main(int argc, char **argv) {
9 | lua_State *L = luaL_newstate();
10 | luaL_openlibs(L);
11 | luaL_dostring(L, "t={1,2,3,a=1,b=2,c=3}");
12 | lua_getglobal(L, "t");
13 | //8<----------------------------------------------------------------------------
14 |
15 | lua_pushnil(L);
16 | while (lua_next(L, -2) != 0) {
17 | if (lua_type(L, -2) == LUA_TSTRING) {
18 | // Delete values assigned to string keys (fields).
19 | const char *key = lua_tostring(L, -2);
20 | lua_pushnil(L);
21 | lua_setfield(L, -4, key);
22 | }
23 | lua_pop(L, 1); // value
24 | }
25 | lua_pop(L, 1); // table iterated over
26 |
27 | //8<----------------------------------------------------------------------------
28 | if (lua_gettop(L) > 0) printf("stack size != 0\n");
29 | luaL_dostring(L, "for k,v in pairs(t) do print(k,v) end");
30 | lua_close(L);
31 | return 0;
32 | }
33 | //8<----------------------------------------------------------------------------
34 |
--------------------------------------------------------------------------------
/ex09.lua:
--------------------------------------------------------------------------------
1 | -- Example 9. Define, load, and use a Lua module.
2 | -- File "trig.lua".
3 | local M = {}
4 | -- Radians mode.
5 | M.rad = {
6 | sin = math.sin,
7 | cos = math.cos,
8 | tan = math.tan,
9 | }
10 | -- Degrees mode.
11 | M.deg = {
12 | sin = function(x) return math.sin(math.rad(x)) end,
13 | cos = function(x) return math.cos(math.rad(x)) end,
14 | tan = function(x) return math.tan(math.rad(x)) end
15 | }
16 |
17 | --8<----------------------------------------------------------------------------
18 | if false then
19 | --8<----------------------------------------------------------------------------
20 | return M
21 | --8<----------------------------------------------------------------------------
22 | end
23 | package.loaded['trig'] = M
24 | --8<----------------------------------------------------------------------------
25 |
26 | -- Program code.
27 | local trig = require("trig").deg
28 | trig.sin(30) -- results in 0.5
29 | trig = require("trig").rad
30 | trig.sin(math.pi / 6) -- also results in 0.5
31 |
32 | --8<----------------------------------------------------------------------------
33 | print(require('trig').deg.sin(30))
34 | print(require('trig').rad.sin(math.pi / 6))
35 | --8<----------------------------------------------------------------------------
36 |
--------------------------------------------------------------------------------
/ex14.lua:
--------------------------------------------------------------------------------
1 | -- Example 14. Simple URL parser
2 | function urlparse(url)
3 | -- Decode escapes like "%5C" -> "\".
4 | url = url:gsub("%%(%x%x)", function(c)
5 | return string.char(tonumber(c, 16))
6 | end)
7 | -- Parse out URL parts.
8 | local patt = "^([^:]+)://([^/]+)(.*)$"
9 | local scheme, host_part, rest = url:match(patt)
10 | local host, port = host_part:match("^([^:]+):?(%d*)")
11 | local path, query = rest:match("^([^?]*)%??(.*)$")
12 | local parts = {}
13 | for part in query:gmatch("[^&]+") do
14 | local k, v = part:match("^([^=]+)=(.*)$")
15 | parts[k] = v
16 | end
17 | -- Return parsed parts in a table.
18 | return {
19 | scheme = scheme,
20 | host = host, port = tonumber(port) or 80,
21 | path = path, query = parts
22 | }
23 | end
24 | urlparse("http://www.example.com/path?key=value")
25 | -- results in:
26 | -- {scheme = "http", host = "www.example.com",
27 | -- port = 80, path = "/path", query = {key = "value"}}
28 |
29 | --8<----------------------------------------------------------------------------
30 | for k, v in pairs(urlparse("http://www.example.com/path?key=value")) do
31 | if type(v) ~= 'table' then
32 | print(k, v)
33 | else
34 | print(k)
35 | for k2, v2 in pairs(v) do print('', k2, v2) end
36 | end
37 | end
38 | --8<----------------------------------------------------------------------------
39 |
--------------------------------------------------------------------------------
/ex28.c:
--------------------------------------------------------------------------------
1 | // Example 28. Mathematical gamma function
2 |
3 | //8<----------------------------------------------------------------------------
4 | #include
5 | #include
6 |
7 | #include "lua.h"
8 | #include "lauxlib.h"
9 | #include "lualib.h"
10 |
11 | //8<----------------------------------------------------------------------------
12 | static int gamma(lua_State *L) {
13 | double z = luaL_checknumber(L, 1); // fetch argument
14 | lua_pushnumber(L, tgamma(z)); // push value to return
15 | return 1; // number of stack values to return
16 | }
17 |
18 | //8<----------------------------------------------------------------------------
19 | int main() {
20 | lua_State *L = luaL_newstate();
21 | luaL_openlibs(L);
22 | //8<----------------------------------------------------------------------------
23 |
24 | // Add gamma to Lua's math module.
25 | lua_getglobal(L, "math");
26 | lua_pushcfunction(L, gamma);
27 | lua_setfield(L, -2, "gamma");
28 | lua_pop(L, 1); // global "math"
29 |
30 | //8<----------------------------------------------------------------------------
31 | if (lua_gettop(L) > 0) printf("stack size != 0\n");
32 | luaL_dostring(L, "return math.gamma(3)");
33 | printf("%f\n", lua_tonumber(L, -1));
34 | lua_pop(L, 1);
35 | lua_close(L);
36 | return 0;
37 | }
38 | //8<----------------------------------------------------------------------------
39 |
--------------------------------------------------------------------------------
/ex30.c:
--------------------------------------------------------------------------------
1 | // Example 30. Call Lua's string.find
2 |
3 | //8<----------------------------------------------------------------------------
4 | #include
5 | #include
6 | #include
7 |
8 | #include "lua.h"
9 | #include "lauxlib.h"
10 | #include "lualib.h"
11 |
12 | int main() {
13 | lua_State *L = luaL_newstate();
14 | luaL_openlibs(L);
15 | const char *s = "foobar", *pattern = "b..";
16 | //8<----------------------------------------------------------------------------
17 |
18 | // Record initial stack size due to LUA_MULTRET.
19 | int n = lua_gettop(L);
20 | // Push the global function string.find().
21 | lua_getglobal(L, "string");
22 | lua_getfield(L, -1, "find");
23 | lua_replace(L, -2);
24 | // Push two arguments.
25 | lua_pushstring(L, s);
26 | lua_pushstring(L, pattern);
27 | // Call the function with those two arguments,
28 | // expecting a variable number of results.
29 | if (lua_pcall(L, 2, LUA_MULTRET, 0) == LUA_OK &&
30 | lua_gettop(L) > n) {
31 | int start = lua_tointeger(L, n + 1);
32 | int end = lua_tointeger(L, n + 2);
33 | /* process returned positions and any captures */
34 | //8<--------------------------------------------------------------------------
35 | printf("%i %i\n", start, end);
36 | //8<--------------------------------------------------------------------------
37 | lua_settop(L, n); // pop all returned values
38 | }
39 |
40 | //8<----------------------------------------------------------------------------
41 | if (lua_gettop(L) > 0) printf("stack size != 0\n");
42 | lua_close(L);
43 | return 0;
44 | }
45 | //8<----------------------------------------------------------------------------
46 |
--------------------------------------------------------------------------------
/ex17.lua:
--------------------------------------------------------------------------------
1 | -- Example 17. Emulate string.gsub() without captures
2 | -- Returns a thread that, for each instance of a
3 | -- pattern found, yields that match to main thread and
4 | -- substitutes it with the replacement received.
5 | local function gsub(str, patt, init)
6 | init = init or 1
7 | return coroutine.create(function()
8 | local buffer = {} -- for building resultant string
9 | local s, e = str:find(patt, init)
10 | while s do
11 | -- Add substring up to match to result buffer.
12 | buffer[#buffer + 1] = str:sub(init, s - 1)
13 | -- Yield match, receive replacement, and add to
14 | -- result buffer.
15 | local match = str:sub(s, e)
16 | local replacement = coroutine.yield(match)
17 | buffer[#buffer + 1] = replacement
18 | -- Continue the search.
19 | init = e + 1
20 | s, e = str:find(patt, init)
21 | end
22 | -- Build and return the final replacement string.
23 | return table.concat(buffer)
24 | end)
25 | end
26 | -- Replaces all instances of a pattern in a string by
27 | -- creating a thread that searches within that string
28 | -- and, for each match yielded, produces a suitable
29 | -- replacement.
30 | local function threaded_gsub(str, patt, repl)
31 | local thread = gsub(str, patt)
32 | local ok, match = coroutine.resume(thread)
33 | while coroutine.status(thread) == "suspended" do
34 | local replacement = --[[ produce from match ]]
35 | --8<------------------------------------------------------------------------
36 | match:upper()
37 | --8<------------------------------------------------------------------------
38 | ok, match = coroutine.resume(thread, replacement)
39 | end
40 | return match -- final resultant string
41 | end
42 |
43 | --8<----------------------------------------------------------------------------
44 | print(threaded_gsub('foo', '.'))
45 | --8<----------------------------------------------------------------------------
46 |
--------------------------------------------------------------------------------
/ex32.c:
--------------------------------------------------------------------------------
1 | // Example 32. Run user-defined Lua code in a sandbox
2 |
3 | //8<----------------------------------------------------------------------------
4 | #include
5 | #include "lua.h"
6 | #include "lauxlib.h"
7 | #include "lualib.h"
8 |
9 | int main(int argc, char **argv) {
10 | lua_State *L = luaL_newstate();
11 | luaL_openlibs(L);
12 | const char *user_script = "/tmp/foo.lua";
13 | //8<----------------------------------------------------------------------------
14 |
15 | // Define and store the sandbox for subsequent use.
16 | const char *safe[] = {
17 | "assert", "error", "ipairs", "math", "next", "pairs",
18 | "pcall", "select", "string", "table", "tonumber",
19 | "tostring", "type", "xpcall", NULL
20 | };
21 | lua_newtable(L); // the sandbox environment
22 | for (const char **p = safe; *p; p++)
23 | lua_getglobal(L, *p), lua_setfield(L, -2, *p);
24 | /* add other safe host functions to sandbox */
25 | int sandbox_ref = luaL_ref(L, LUA_REGISTRYINDEX);
26 |
27 | //8<----------------------------------------------------------------------------
28 | lua_rawgeti(L, LUA_REGISTRYINDEX, sandbox_ref), lua_setglobal(L, "sandbox");
29 | //8<----------------------------------------------------------------------------
30 |
31 | // Attempt to load the user-defined Lua script
32 | // (text-only) as an anonymous function.
33 | if (luaL_loadfilex(L, user_script, "t") == LUA_OK) {
34 | // Make the sandbox the function's environment.
35 | lua_rawgeti(L, LUA_REGISTRYINDEX, sandbox_ref);
36 | lua_setupvalue(L, -2, 1);
37 | // Execute the script.
38 | if (lua_pcall(L, 0, 0, 0) != LUA_OK) {
39 | /* process and pop error message at index -1 */
40 | }
41 | }
42 | /* ... */
43 | // Finished with the sandbox; delete it.
44 | luaL_unref(L, LUA_REGISTRYINDEX, sandbox_ref);
45 |
46 | //8<----------------------------------------------------------------------------
47 | luaL_dostring(L, "for k,v in pairs(sandbox) do print(k,v) end");
48 | lua_close(L);
49 | return 0;
50 | }
51 | //8<----------------------------------------------------------------------------
52 |
--------------------------------------------------------------------------------
/docs/style.css:
--------------------------------------------------------------------------------
1 | /* Copyright 2012-2020 Mitchell. */
2 |
3 | * {
4 | border: 0 solid #a6a6a6;
5 | margin: 0;
6 | padding: 0;
7 | }
8 |
9 | a {
10 | color: #1a66b3;
11 | text-decoration: none;
12 | }
13 | a:hover { text-decoration: underline; }
14 | a:visited { color: #661a66; }
15 |
16 | body {
17 | background-color: #f2f2f2;
18 | color: #333333;
19 | }
20 |
21 | code { font-size: 1.2em; }
22 |
23 | del { color: #994d4d; }
24 |
25 | h1 { margin: 0 0 1em 0; }
26 | h2, h3, h4, h5, h6 { margin: 1em 0 1em 0; }
27 | h1 { font-size: 1.3em; }
28 | h2 { font-size: 1.2em; }
29 | h3 { font-size: 1.1em; }
30 | h4 { font-size: 1.0em; }
31 | h5 { font-size: 0.9em; }
32 |
33 | hr {
34 | border: 1px solid #d9d9d9;
35 | border-width: 1px 0 0 0;
36 | margin: 1em 0 1em 0;
37 | }
38 |
39 | input, textarea {
40 | border-width: 1px;
41 | font-size: 1em;
42 | }
43 |
44 | ins { color: #4d994d; }
45 |
46 | li > code, p > code, em > code, td > code { color: #808080; }
47 |
48 | pre {
49 | color: #808080;
50 | margin: 0 2.5em 0 2.5em;
51 | white-space: pre-wrap;
52 | }
53 |
54 | table, th, td {
55 | border-width: 1px;
56 | border-collapse: collapse;
57 | margin-left: 1em;
58 | padding: 0.25em;
59 | }
60 |
61 | #content {
62 | border-width: 0 1px 0 1px;
63 | font-size: 1.2em;
64 | margin: 0 auto 0 auto;
65 | max-width: 1000px;
66 | }
67 |
68 | #header h1 {
69 | background-color: #d9d9d9;
70 | border-width: 0 0 1px 0;
71 | margin: 0;
72 | padding: 0.25em;
73 | }
74 | #header img { vertical-align: text-bottom; }
75 | #header ul, #header p {
76 | border-width: 0 0 1px 0;
77 | margin-bottom: 1.5em;
78 | padding: 0.25em;
79 | }
80 | #header ul { list-style: none; }
81 | #header li {
82 | color: #808080;
83 | display: inline;
84 | }
85 | #header li form { display: inline; }
86 |
87 | #main { margin-left: 1em; }
88 | #main dl, #main p { margin: 1em; }
89 | #main dd, #main ol, #main ul { margin-left: 2.5em; }
90 | #main ol p, #main ul p { margin-left: 0; }
91 |
92 | #footer {
93 | background-color: #d9d9d9;
94 | border-width: 1px 0 1px 0;
95 | clear: both;
96 | padding: 0.25em;
97 | margin-top: 1.5em;
98 | }
99 |
--------------------------------------------------------------------------------
/ex08.lua:
--------------------------------------------------------------------------------
1 | -- Example 8. A sample class for 2-D vector objects
2 | -- Create the vector class object.
3 | local vector = {}
4 | vector.__index = vector
5 | -- Create a new vector with the given components.
6 | function vector.new(x, y)
7 | local v = {x = x, y = y}
8 | return setmetatable(v, vector)
9 | end
10 | -- Overload length operator to compute magnitude.
11 | function vector.__len(v)
12 | return math.sqrt(v.x^2 + v.y^2)
13 | end
14 | -- Overload addition operator to add two vectors.
15 | function vector.__add(v1, v2)
16 | assert(getmetatable(v1) == getmetatable(v2),
17 | "vectors expected")
18 | return vector.new(v1.x + v2.x, v1.y + v2.y)
19 | end
20 | -- Overload subtraction operator to subtract vectors.
21 | function vector.__sub(v1, v2)
22 | assert(getmetatable(v1) == getmetatable(v2),
23 | "vectors expected")
24 | return vector.new(v1.x - v2.x, v1.y - v2.y)
25 | end
26 | -- Overload multiplication operator to compute vector
27 | -- dot product or scale a vector.
28 | function vector.__mul(v1, v2)
29 | if getmetatable(v1) == getmetatable(v2) then
30 | return v1.x * v2.x + v1.y * v2.y
31 | elseif tonumber(v1) or tonumber(v2) then
32 | local scalar = tonumber(v1) or v2
33 | local v = not tonumber(v1) and v1 or v2
34 | return vector.new(scalar * v.x, scalar * v.y)
35 | else
36 | error("vectors or scalar and vector expected")
37 | end
38 | end
39 | -- Normalize a vector in-place.
40 | function vector:normalize()
41 | local magnitude = #self
42 | self.x = self.x / magnitude
43 | self.y = self.y / magnitude
44 | end
45 | -- Overload exponentiation operator to compute angle
46 | -- between vectors.
47 | function vector.__pow(v1, v2)
48 | assert(getmetatable(v1) == getmetatable(v2),
49 | "vectors expected")
50 | return math.acos(v1 * v2 / (#v1 * #v2))
51 | end
52 | -- Return a vector's direction angle from x-axis.
53 | function vector:angle()
54 | return self ^ vector.new(1, 0)
55 | end
56 | -- Return a vector's string representation.
57 | function vector:__tostring()
58 | return string.format("<%.3f, %.3f>", self.x, self.y)
59 | end
60 |
61 | --8<----------------------------------------------------------------------------
62 | local v1 = vector.new(1, 2)
63 | local v2 = vector.new(-1, 1)
64 | print(v1, #v1)
65 | print(v2, #v2)
66 | print(v1 + v2, v1 - v2)
67 | print(v1 * v2)
68 | print(3 * v2)
69 | print((v1 + v2):angle())
70 | v2:normalize()
71 | print(v2)
72 | --8<----------------------------------------------------------------------------
73 |
--------------------------------------------------------------------------------
/ex29.c:
--------------------------------------------------------------------------------
1 | // Example 29. C function that translates string characters
2 |
3 | //8<----------------------------------------------------------------------------
4 | #include
5 | #include
6 | #include
7 |
8 | #include "lua.h"
9 | #include "lauxlib.h"
10 | #include "lualib.h"
11 |
12 | //8<----------------------------------------------------------------------------
13 |
14 | static int translate_chars(lua_State *L) {
15 | // Fetch arguments. The first should be a string. The
16 | // second should be a table, if given. Otherwise, use
17 | // a default table stored as an upvalue.
18 | const char *s = luaL_checkstring(L, 1);
19 | if (lua_gettop(L) > 1)
20 | luaL_checktype(L, 2, LUA_TTABLE);
21 | else
22 | lua_pushvalue(L, lua_upvalueindex(1));
23 | // Allocate and fill a copy of the string argument,
24 | // translate its characters according to the table
25 | // argument, and push the result.
26 | char *o = strcpy(malloc(strlen(s) + 1), s);
27 | for (char *p = o; *p; p++) {
28 | lua_pushlstring(L, p, 1); // table key
29 | lua_gettable(L, 2); // fetch value assigned to key
30 | if (lua_isstring(L, -1))
31 | *p = *lua_tostring(L, -1); // translate char
32 | lua_pop(L, 1); // table value
33 | }
34 | lua_pushstring(L, o); // push the value to return
35 | free(o);
36 | return 1; // the number of stack values to return
37 | }
38 |
39 | //8<----------------------------------------------------------------------------
40 |
41 | int main() {
42 | lua_State *L = luaL_newstate();
43 | luaL_openlibs(L);
44 | //8<----------------------------------------------------------------------------
45 |
46 | // Create the default translation table, assign it as
47 | // an upvalue to translate_chars, and register that
48 | // function as the global function "tr".
49 | lua_createtable(L, 0, 1);
50 | lua_pushliteral(L, "_");
51 | lua_setfield(L, -2, " "); // translate ' ' to '_'
52 | lua_pushcclosure(L, translate_chars, 1);
53 | lua_setglobal(L, "tr");
54 |
55 | //8<----------------------------------------------------------------------------
56 | if (lua_gettop(L) > 0) printf("stack size != 0\n");
57 | luaL_dostring(L, "return tr('hello world!')");
58 | printf("%s\n", lua_tostring(L, -1));
59 | lua_pop(L, 1);
60 | luaL_dostring(L, "return tr('hello!', {['!'] = '?'})");
61 | printf("%s\n", lua_tostring(L, -1));
62 | lua_pop(L, 1);
63 | lua_close(L);
64 | return 0;
65 | }
66 | //8<----------------------------------------------------------------------------
67 |
--------------------------------------------------------------------------------
/ex26.c:
--------------------------------------------------------------------------------
1 | // Example 26. Use a C structure as a Lua value
2 |
3 | //8<----------------------------------------------------------------------------
4 | #include
5 | #include "lua.h"
6 | #include "lauxlib.h"
7 | #include "lualib.h"
8 |
9 | //8<----------------------------------------------------------------------------
10 |
11 | // C struct for using FILE* as a Lua value.
12 | typedef struct {FILE *f;} File;
13 |
14 | // Metamethod for closing to-be-closed files.
15 | static int close_file(lua_State *L) {
16 | File *lf = (File *)luaL_checkudata(L, 1, "file_mt");
17 | lua_getiuservalue(L, 1, 1); // f closed?
18 | if (!lua_toboolean(L, -1)) {
19 | fclose(lf->f);
20 | lua_pushboolean(L, 1);
21 | lua_setiuservalue(L, 1, 1); // f closed now
22 | //8<------------------------------------------------------------------------
23 | printf("file closed\n");
24 | //8<------------------------------------------------------------------------
25 | }
26 | //8<--------------------------------------------------------------------------
27 | else printf("file already closed\n");
28 | //8<--------------------------------------------------------------------------
29 | return 0;
30 | }
31 |
32 | //8<----------------------------------------------------------------------------
33 | int main() {
34 | lua_State *L = luaL_newstate();
35 | luaL_openlibs(L);
36 | const char *filename = "/home/mitchell/code/textadept/init.lua";
37 | //8<----------------------------------------------------------------------------
38 |
39 | // Create a new file userdata, open and associate a
40 | // file with it, assign a metatable that helps
41 | // automatically close the file, and mark the userdata
42 | // as a to-be-closed variable.
43 | File *lf = lua_newuserdatauv(L, sizeof(FILE), 1);
44 | lf->f = fopen(filename, "r");
45 | lua_pushboolean(L, 0);
46 | lua_setiuservalue(L, -2, 1); // f not closed yet
47 | if (luaL_newmetatable(L, "file_mt")) {
48 | lua_pushcfunction(L, close_file);
49 | lua_setfield(L, -2, "__close");
50 | //8<----------------------------------------------------------------------------
51 | lua_pushcfunction(L, close_file);
52 | lua_setfield(L, -2, "__gc");
53 | //8<----------------------------------------------------------------------------
54 | }
55 | lua_setmetatable(L, -2);
56 | lua_toclose(L, -1);
57 | /* do something with the file */
58 | lua_pop(L, 1); // invokes __close()
59 |
60 | //8<----------------------------------------------------------------------------
61 | if (lua_gettop(L) > 0) printf("stack size != 0\n");
62 | lua_close(L);
63 | return 0;
64 | }
65 | //8<----------------------------------------------------------------------------
66 |
--------------------------------------------------------------------------------
/ex34.c:
--------------------------------------------------------------------------------
1 | // Example 34. Call a function for each table key-value pair
2 |
3 | //8<----------------------------------------------------------------------------
4 | #include "lua.h"
5 | #include "lauxlib.h"
6 | #include "lualib.h"
7 | //8<----------------------------------------------------------------------------
8 |
9 | // Thread body continuation function for iterating over
10 | // a table's key-value pairs and calling a function
11 | // with each pair as that function's arguments.
12 | static int iterator(lua_State *thread, int status,
13 | lua_KContext ctx) {
14 | if (status == LUA_OK)
15 | lua_pushnil(thread); // start iteration
16 | else
17 | lua_pop(thread, 1); // previous value
18 | while (lua_next(thread, 1) != 0) {
19 | lua_pushvalue(thread, lua_upvalueindex(1));
20 | lua_pushvalue(thread, -3); // key
21 | lua_pushvalue(thread, -3); // value
22 | lua_callk(thread, 2, 0, 0, iterator);
23 | lua_pop(thread, 1); // value
24 | }
25 | return 0;
26 | }
27 |
28 | // Initial thread body function.
29 | static int iterate(lua_State *thread) {
30 | return iterator(thread, LUA_OK, 0);
31 | }
32 |
33 | //8<----------------------------------------------------------------------------
34 | int main(int argc, char **argv) {
35 | lua_State *L = luaL_newstate();
36 | luaL_openlibs(L);
37 | //8<----------------------------------------------------------------------------
38 |
39 | lua_State *thread = lua_newthread(L);
40 | /* push function to be called each iteration */
41 | //8<--------------------------------------------------------------------------
42 | lua_getglobal(thread, "coroutine");
43 | lua_getfield(thread, -1, "yield");
44 | lua_replace(thread, -2);
45 | //8<--------------------------------------------------------------------------
46 | lua_pushcclosure(thread, iterate, 1);
47 | /* push table to be iterated over */
48 | //8<--------------------------------------------------------------------------
49 | lua_pushglobaltable(thread);
50 | //8<--------------------------------------------------------------------------
51 | int nresults;
52 | while (lua_resume(thread, L, 1, &nresults) == LUA_YIELD) {
53 | /* work to do in-between yields */
54 | //8<--------------------------------------------------------------------------
55 | printf("%s\t%s\n", lua_tostring(thread, -2), luaL_typename(thread, -1));
56 | //8<--------------------------------------------------------------------------
57 | lua_pop(thread, nresults);
58 | }
59 | lua_pop(L, 1); // dead thread
60 |
61 | //8<----------------------------------------------------------------------------
62 | if (lua_gettop(L) > 0) printf("stack size != 0\n");
63 | lua_close(L);
64 | return 0;
65 | }
66 | //8<----------------------------------------------------------------------------
67 |
--------------------------------------------------------------------------------
/ex13.lua:
--------------------------------------------------------------------------------
1 | -- Example 13. Save game data in a binary format
2 | -- Saved player data comprises a name, level (1-100),
3 | -- attribute stats (0-255), map xy-coordinate position,
4 | -- and inventory of items. Inventory items each have an
5 | -- id (0-65535) and count (0-255).
6 | local info_fmt = "zI1"
7 | local stats_fmt = "I1I1"
8 | local position_fmt = "ii"
9 | local inventory_item_fmt = "I2I1"
10 | function save_player_data(player)
11 | -- Generate static player save data.
12 | local data = {
13 | info_fmt:pack(player.name, player.level),
14 | stats_fmt:pack(player.strength, player.defense),
15 | position_fmt:pack(player.x, player.y),
16 | string.pack("I1", #player.inventory)
17 | }
18 | -- Generate dynamic player save data.
19 | for i = 1, #player.inventory do
20 | local item = player.inventory[i]
21 | data[#data + 1] = string.pack(inventory_item_fmt,
22 | item.id, item.count)
23 | end
24 | data = table.concat(data)
25 | --[[ save data ]]
26 | --8<--------------------------------------------------------------------------
27 | return data
28 | --8<--------------------------------------------------------------------------
29 | end
30 | function load_player_data(player--[[]],data--[[]])
31 | --[[ read data ]]
32 | local name, level, stats, x, y, inventory_size, pos
33 | -- Read static player save data.
34 | name, level, pos = info_fmt:unpack(data)
35 | stats = {stats_fmt:unpack(data, pos)}
36 | x, y, pos = position_fmt:unpack(data, stats[3])
37 | -- Read dynamic player save data.
38 | inventory_size, pos = string.unpack("I1", data, pos)
39 | local inventory = {}
40 | for i = 1, inventory_size do
41 | local id, ct
42 | id, ct, pos = inventory_item_fmt:unpack(data, pos)
43 | inventory[#inventory + 1] = {id = id, count = ct}
44 | end
45 | -- Load player data.
46 | player.name, player.level = name, level
47 | player.strength, player.defense = stats[1], stats[2]
48 | player.x, player.y = x, y
49 | player.inventory = inventory
50 | end
51 |
52 | --8<----------------------------------------------------------------------------
53 | local player = {
54 | name = 'm', level = 50, strength = 100, defense = 255, x = -1, y = -10,
55 | inventory = {
56 | {id = 1, count = 10, name = 'potion'},
57 | {id = 0, count = 1, name = 'elixir'},
58 | {id = 2, count = 5, name = 'phoenix down'}
59 | }
60 | }
61 | local loaded_player = {}
62 | load_player_data(loaded_player, save_player_data(player))
63 | for k, v in pairs(loaded_player) do
64 | if type(v) ~= 'table' then
65 | print(k, v)
66 | else
67 | print(k)
68 | for _, item in ipairs(v) do
69 | print('', item.id, item.count)
70 | end
71 | end
72 | end
73 | --8<----------------------------------------------------------------------------
74 |
--------------------------------------------------------------------------------
/ex33.c:
--------------------------------------------------------------------------------
1 | // Example 33. Monitor output from a set of files
2 |
3 | //8<----------------------------------------------------------------------------
4 | #include
5 | #include "lua.h"
6 | #include "lauxlib.h"
7 | #include "lualib.h"
8 | //8<----------------------------------------------------------------------------
9 |
10 | // Filenames to monitor.
11 | const char *filenames[32]; // will have NULL sentinel
12 |
13 | // Thread body continuation function for monitoring a
14 | // file.
15 | static int monitor(lua_State *thread, int status,
16 | lua_KContext ctx) {
17 | FILE *f = (FILE*)ctx;
18 | // Stop monitoring file if requested to.
19 | if (status == LUA_YIELD &&
20 | !lua_toboolean(thread, 1)) {
21 | fclose(f);
22 | return 0;
23 | }
24 | // Check for data to be read.
25 | int c = getc(f);
26 | if (c != EOF) {
27 | // Read and yield a line of data.
28 | ungetc(c, f);
29 | char buf[BUFSIZ];
30 | fgets(buf, BUFSIZ, f);
31 | lua_pushstring(thread, buf);
32 | return lua_yieldk(thread, 1, ctx, monitor);
33 | } else {
34 | // No data to read; yield nothing.
35 | return lua_yieldk(thread, 0, ctx, monitor);
36 | }
37 | }
38 |
39 | // Thread body function for monitoring a file.
40 | static int monitor_file(lua_State *thread) {
41 | const char *filename = luaL_checkstring(thread, 1);
42 | FILE *f = fopen(filename, "r");
43 | if (!f)
44 | return luaL_error(thread, "file '%s' not found",
45 | filename);
46 | lua_settop(thread, 0); // clear
47 | return monitor(thread, LUA_OK, (lua_KContext)f);
48 | }
49 |
50 | //8<----------------------------------------------------------------------------
51 | int main(int argc, char **argv) {
52 | lua_State *L = luaL_newstate();
53 | luaL_openlibs(L);
54 | filenames[0] = "/tmp/output"; filenames[1] = "/tmp/output2"; filenames[2] = NULL;
55 | //8<----------------------------------------------------------------------------
56 |
57 | // Create and start threads.
58 | lua_createtable(L, 32, 0); // active threads table
59 | for (int i = 0; i < 32; i++) {
60 | if (!filenames[i]) break;
61 | lua_State *thread = lua_newthread(L);
62 | lua_pushcfunction(thread, monitor_file);
63 | lua_pushstring(thread, filenames[i]);
64 | int nresults; // unused
65 | if (lua_resume(thread, L, 1, &nresults) == LUA_YIELD)
66 | // Store thread for monitoring.
67 | lua_rawseti(L, -2, lua_rawlen(L, -2) + 1);
68 | else {
69 | /* handle error starting thread */
70 | //8<------------------------------------------------------------------------
71 | printf("%s\n", lua_tostring(thread, -1));
72 | //8<------------------------------------------------------------------------
73 | lua_pop(L, 1);
74 | }
75 | }
76 | // Monitor active threads.
77 | int i = 1;
78 | while (lua_rawlen(L, -1) > 0) {
79 | lua_rawgeti(L, -1, i);
80 | lua_State *thread = lua_tothread(L, -1);
81 | if (lua_gettop(thread) > 0) {
82 | // Thread has output from its monitored file.
83 | const char *line = lua_tostring(thread, -1);
84 | /* process line and possibly stop monitoring */
85 | //8<------------------------------------------------------------------------
86 | printf("%s", line);
87 | int keep_monitoring = 0;
88 | //8<------------------------------------------------------------------------
89 | lua_pushboolean(thread, keep_monitoring);
90 | lua_replace(thread, 1);
91 | int nresults; // unused
92 | lua_resume(thread, L, 1, &nresults);
93 | if (!keep_monitoring) {
94 | // Stop monitoring the now-dead thread.
95 | lua_getglobal(L, "table");
96 | lua_getfield(L, -1, "remove");
97 | lua_replace(L, -2);
98 | lua_pushvalue(L, -3); // active threads table
99 | lua_pushnumber(L, i);
100 | lua_call(L, 2, 0); // table.remove(threads, i)
101 | lua_pop(L, 1); // dead thread
102 | continue; // monitor next thread
103 | }
104 | }
105 | lua_pop(L, 1); // thread
106 | if (++i > lua_rawlen(L, -1)) i = 1; // start again
107 | }
108 | lua_pop(L, 1); // active threads table
109 |
110 | //8<----------------------------------------------------------------------------
111 | if (lua_gettop(L) > 0) printf("stack size != 0\n");
112 | lua_close(L);
113 | return 0;
114 | }
115 | //8<----------------------------------------------------------------------------
116 |
--------------------------------------------------------------------------------
/ex31.c:
--------------------------------------------------------------------------------
1 | // Example 31. Complex number module
2 |
3 | //8<----------------------------------------------------------------------------
4 | #include "lualib.h"
5 | //8<----------------------------------------------------------------------------
6 |
7 | #include
8 | #include "lua.h"
9 | #include "lauxlib.h"
10 |
11 | typedef double complex Complex;
12 |
13 | // Pushes a complex number as userdata.
14 | static int pushcomplex(lua_State *L, Complex z) {
15 | Complex *p = lua_newuserdatauv(L, sizeof(Complex),
16 | 0);
17 | *p = z;
18 | luaL_setmetatable(L, "complex_mt");
19 | return 1;
20 | }
21 |
22 | // Creates and pushes a new complex number.
23 | static int complex_new(lua_State *L) {
24 | double x = luaL_optnumber(L, 1, 0);
25 | double y = luaL_optnumber(L, 2, 0);
26 | pushcomplex(L, x + y * I);
27 | return 1;
28 | }
29 |
30 | // Asserts and returns a complex number function
31 | // argument.
32 | static Complex checkcomplex(lua_State *L, int arg) {
33 | return lua_isuserdata(L, 1) ?
34 | *((Complex *)luaL_checkudata(L, arg, "complex_mt"))
35 | : luaL_checknumber(L, arg);
36 | }
37 |
38 | // Defines a binary complex number operation.
39 | #define binop(name, op) \
40 | static int complex_##name(lua_State *L) { \
41 | Complex z1 = checkcomplex(L, 1); \
42 | Complex z2 = checkcomplex(L, 2); \
43 | return pushcomplex(L, z1 op z2); \
44 | }
45 |
46 | // Defines a unary complex number operation.
47 | #define unop(name, op) \
48 | static int complex_##name(lua_State *L) { \
49 | Complex z = checkcomplex(L, 1); \
50 | return pushcomplex(L, op(z)); \
51 | }
52 |
53 | // Complex number operations.
54 | unop(abs, cabs)
55 | unop(real, creal)
56 | unop(imag, cimag)
57 | unop(arg, carg)
58 | unop(conj, conj)
59 | binop(add, +)
60 | binop(sub, -)
61 | binop(mul, *)
62 | binop(div, /)
63 | unop(unm, -)
64 | binop(eq, ==)
65 |
66 | // String representation of a complex number.
67 | static int complex_tostring(lua_State *L) {
68 | Complex z = checkcomplex(L, 1);
69 | double x = creal(z), y = cimag(z);
70 | if (x != 0 && y > 0)
71 | lua_pushfstring(L, "%f+%fi", x, y);
72 | else if (x != 0 && y < 0)
73 | lua_pushfstring(L, "%f%fi", x, y);
74 | else if (x == 0)
75 | lua_pushfstring(L, "%fi", y);
76 | else
77 | lua_pushfstring(L, "%f", x);
78 | return 1;
79 | }
80 |
81 | // Complex module functions.
82 | static const luaL_Reg complex_functions[] = {
83 | {"new", complex_new},
84 | {"abs", complex_abs},
85 | {"real", complex_real},
86 | {"imag", complex_imag},
87 | {"arg", complex_arg},
88 | {"conj", complex_conj},
89 | {NULL, NULL}
90 | };
91 |
92 | // Complex number metamethods.
93 | static const luaL_Reg complex_metamethods[] = {
94 | {"__add", complex_add},
95 | {"__sub", complex_sub},
96 | {"__mul", complex_mul},
97 | {"__div", complex_div},
98 | {"__unm", complex_unm},
99 | {"__eq", complex_eq},
100 | {"__tostring", complex_tostring},
101 | {NULL, NULL}
102 | };
103 |
104 | // Complex number module entry point.
105 | int luaopen_complex(lua_State *L) {
106 | // Create and push the module table.
107 | luaL_newlib(L, complex_functions);
108 | // Create the complex number metatable, fill it,
109 | // link it with the module table, then pop it.
110 | luaL_newmetatable(L, "complex_mt");
111 | luaL_setfuncs(L, complex_metamethods, 0);
112 | lua_pushvalue(L, -2); // the module table
113 | lua_setfield(L, -2, "__index");
114 | lua_pop(L, 1); // metatable
115 | return 1; // return the module table
116 | }
117 |
118 | //8<----------------------------------------------------------------------------
119 | int main() {
120 | lua_State *L = luaL_newstate();
121 | luaL_openlibs(L);
122 | luaL_requiref(L, "complex", luaopen_complex, 0);
123 | lua_pop(L, 1);
124 |
125 | // Lua code.
126 | luaL_dostring(L, "complex = require('complex')");
127 | luaL_dostring(L, "print(complex.new(3, 4))");
128 | luaL_dostring(L, "print(complex.new(-3, 4))");
129 | luaL_dostring(L, "print(complex.new(3, -4))");
130 | luaL_dostring(L, "print(complex.new(-3, -4))");
131 | luaL_dostring(L, "print(complex.new(3, 0))");
132 | luaL_dostring(L, "print(complex.new(0, 4))");
133 | luaL_dostring(L, "print(complex.new(-3, 0))");
134 | luaL_dostring(L, "print(complex.new(0, -4))");
135 | luaL_dostring(L, "print(complex.new(-1, 1):conj())");
136 |
137 | if (lua_gettop(L) > 0) printf("stack size != 0\n");
138 | lua_close(L);
139 | return 0;
140 | }
141 | //8<----------------------------------------------------------------------------
142 |
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 |
2 |

3 |
4 |
5 | *Lua Quick Reference*
6 | Second Edition
7 |
8 | Download the [e-book][] for free.
9 |
10 | Published: May 2020
11 | ISBN: 978-0-9912379-5-1
12 | Pages: 169
13 |
14 | Download the [source code examples][].
15 |
16 | Lua is a small, fast, powerful, and embeddable scripting language. It is
17 | well-suited for use in video games, application scripting, embedded devices, and
18 | nearly anywhere else a scripting language is needed. This quick reference
19 | contains a wealth of knowledge on how to program in and embed Lua, whether it is
20 | Lua 5.4, 5.3, 5.2, or 5.1. This book can even be used with LuaJIT, a
21 | Just-In-Time compiler for Lua based on Lua 5.1. *Lua Quick Reference* groups the
22 | language's features and C API in a convenient and easy-to-use manner, while
23 | clearly marking the differences between Lua versions.
24 |
25 | This book covers:
26 |
27 | * Lua syntax, expressions, and statements
28 | * Metatables and metamethods
29 | * Object-oriented programming with Lua
30 | * Creating and working with Lua and C Modules
31 | * Lua's standard library and its C API
32 | * Collaborative multi-threading in Lua and C
33 | * How to embed and use Lua within a host
34 | * And much more
35 |
36 | Mitchell commands over 15 years of experience programming in and embedding Lua
37 | in both the corporate and open-source realms.
38 |
39 | [e-book]: https://raw.githubusercontent.com/orbitalquark/lua-quick-reference/default/docs/LuaQuickReference2.pdf
40 | [source code examples]: https://github.com/orbitalquark/lua-quick-reference
41 |
42 | ## Table of Contents
43 |
44 | * Introduction
45 | + Download
46 | + Code Editors
47 | + Conventions
48 | + Terminology
49 | + Environment Variables
50 | * Command Line Options
51 |
52 | * Part I: The Lua Language
53 | + Fundamentals
54 | + Comments
55 | + Identifiers and Reserved Words
56 | + Variables and Scopes
57 | + Types
58 | - Nil
59 | - Booleans
60 | - Numbers
61 | - Strings
62 | - Functions
63 | - Tables
64 | - Threads
65 | - Userdata
66 | - Perform Basic Value Operations
67 | + Expressions and Operators
68 | - Arithmetic Operators
69 | - Relational Operators
70 | - Logical Operators
71 | - Bitwise Operators
72 | - Other Operators
73 | + Statements
74 | - Variable Assignment
75 | - Control Structures
76 | - Labels and Goto
77 | + Functions
78 | - Functions with Variable Arguments
79 | + Metatables and Metamethods
80 | - Assign and Retrieve Metatables
81 | - Arithmetic Metamethods
82 | - Relational Metamethods
83 | - Bitwise Metamethods
84 | - Closing Metamethod
85 | - Other Operator and Statement Metamethods
86 | - Function Metamethods
87 | - Bypass Metamethods
88 | + Object-Oriented Programming
89 | - Define a Class
90 | - Utilize a Class
91 | + Modules
92 | - Create a Lua Module
93 | + Environments
94 | + Error Handling and Warnings
95 | + Load and Run Dynamic Code
96 | + Numeric Facilities
97 | - Trigonometric Functions
98 | - Exponential and Logarithmic Functions
99 | - Generate Random Numbers
100 | - Work with Integers
101 | + String Facilities
102 | - Create a Compound String
103 | - Query and Transform Strings
104 | - Search and Replace Within a String
105 | - Work with UTF-8 Strings
106 | + Table and List Facilities
107 | - Iterate Over a Table
108 | - Manipulate Lists
109 | - Unpack Lists
110 | - Create Strings from Lists
111 | + Thread Facilities
112 | - Create a Thread
113 | - Start, Resume, and Yield a Thread
114 | - Query Thread Status
115 | + Input and Output Facilities
116 | - Simple Input and Output
117 | - Object-Oriented Input and Output
118 | - Manage Files
119 | - Start and Interact with a Process
120 | + Operating System Facilities
121 | - Dates and Times
122 | - Locale Settings
123 | + Memory Management
124 | + Miscellaneous
125 |
126 | * Part II: The Lua C API
127 | + C API Introduction
128 | - Compiling Lua Programs
129 | + The Stack
130 | - Increase Stack Size
131 | - Work with Stack Indices
132 | - Push Values
133 | - Pop Values
134 | - Query Values
135 | - Retrieve Values
136 | + Basic Stack Operations
137 | - Element Operations
138 | - Global Variable Operations
139 | - Arithmetic Operations
140 | - Relational Operations
141 | - Bitwise Operations
142 | - String Operations
143 | - Table Operations
144 | - Length Operations
145 | - Reference Operations
146 | + C Functions
147 | - Define a C Function
148 | - Register a C Function
149 | - Call a C Function
150 | + Metatables
151 | - Create or Fetch a Metatable
152 | - Assign a Metatable
153 | - Retrieve a Metatable
154 | - Metamethods and Metafields
155 | + C Modules
156 | + Error and Warning Handling
157 | - Retrieve Error Information
158 | + Load and Run Dynamic Code
159 | + Threading in C
160 | - Create a Thread
161 | - Start or Resume a Thread
162 | - Yield a Thread
163 | - Transfer Values Between Threads
164 | - Query a Thread’s Status
165 | - Call a Function that Yields
166 | + Memory Management
167 | + Miscellaneous
168 |
169 | * Lua API Index
170 | * Concept Index
171 |
172 | ## Errata
173 |
174 | None reported.
175 |
--------------------------------------------------------------------------------