├── 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 | cover 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 | --------------------------------------------------------------------------------