Warning: this is an htmlized version!
The original is here, and
the conversion rules are here.
#######
#
# E-scripts on material for a mini-course on Lua and related stuff.
#
# Note 1: use the eev command (defined in eev.el) and the
# ee alias (in my .zshrc) to execute parts of this file.
# Executing this file as a whole makes no sense.
# An introduction to eev can be found here:
#
#   (find-eev-quick-intro)
#   http://angg.twu.net/eev-intros/find-eev-quick-intro.html
#
# Note 2: be VERY careful and make sure you understand what
# you're doing.
#
# Note 3: If you use a shell other than zsh things like |&
# and the for loops may not work.
#
# Note 4: I always run as root.
#
# Note 5: some parts are too old and don't work anymore. Some
# never worked.
#
# Note 6: the definitions for the find-xxxfile commands are on my
# .emacs.
#
# Note 7: if you see a strange command check my .zshrc -- it may
# be defined there as a function or an alias.
#
# Note 8: the sections without dates are always older than the
# sections with dates.
#
# This file is at <http://angg.twu.net/e/lua5.e>
#           or at <http://angg.twu.net/e/lua5.e.html>.
#        See also <http://angg.twu.net/emacs.html>,
#                 <http://angg.twu.net/.zshrc[.html]>,
#                 <http://angg.twu.net/escripts.html>,
#             and <http://angg.twu.net/>.
#
#######



# «.how-to-use»			(to "how-to-use")
# «.quick-presentation»		(to "quick-presentation")
#   «.intro:types»		(to "intro:types")
#   «.intro:LUA_INIT»		(to "intro:LUA_INIT")
#   «.intro:PP»			(to "intro:PP")
#   «.intro:functions»		(to "intro:functions")
#   «.intro:lists»		(to "intro:lists")
#   «.intro:coercion»		(to "intro:coercion")
#   «.intro:string-literals»	(to "intro:string-literals")
#   «.intro:table-constructors»	(to "intro:table-constructors")
#   «.intro:keys»		(to "intro:keys")
#   «.intro:length»		(to "intro:length")
#   «.intro:for»		(to "intro:for")
#   «.intro:global-vars»	(to "intro:global-vars")
#   «.intro:local-vars»		(to "intro:local-vars")
#   «.intro:eval»		(to "intro:eval")
#   «.intro:assert»		(to "intro:assert")
#   «.intro:closures»		(to "intro:closures")
#   «.intro:iterators»		(to "intro:iterators")
#   «.intro:__tostring»		(to "intro:__tostring")
#   «.intro:metamethods»	(to "intro:metamethods")
#   «.intro:io»			(to "intro:io")
#   «.intro:string.gsub»	(to "intro:string.gsub")
#   «.intro:string.format»	(to "intro:string.format")
# «.coroutines»		(to "coroutines")
# «.bytecode:captures»	(to "bytecode:captures")
# «.captures-data-structures»	(to "captures-data-structures")
# «.install-5.1.2»	(to "install-5.1.2")
# «.minimal_GCW_SUGAR»	(to "minimal_GCW_SUGAR")
# «.invoking-arrays»	(to "invoking-arrays")
# «.string.find»	(to "string.find")
# «.string.gfind»	(to "string.gfind")
# «.emptycaptures»	(to "emptycaptures")
# «.C-calls-lua»	(to "C-calls-lua")
# «.xpcall-traceback»	(to "xpcall-traceback")
# «.calling-Lua-from-C»	(to "calling-Lua-from-C")
# «.monitored_p_C»	(to "monitored_p_C")
# «.debug.debug»	(to "debug.debug")
# «.getoutput»		(to "getoutput")
# «.captured-variables»	(to "captured-variables")
# «.xpcall»		(to "xpcall")
# «.pil24.1»		(to "pil24.1")
# «.lpeg-quickref»	(to "lpeg-quickref")
# «.lpeg-basic»		(to "lpeg-basic")
# «.lpeg-export»	(to "lpeg-export")
# «.lpeg-P»		(to "lpeg-P")
# «.lpeg-re-quickref»	(to "lpeg-re-quickref")
# «.lpeg-re-1»		(to "lpeg-re-1")
# «.lpeg-re-infix-1»	(to "lpeg-re-infix-1")
# «.lpeg-re-infix-2»	(to "lpeg-re-infix-2")
# «.lua-mode.el»	(to "lua-mode.el")
# «.patrick»		(to "patrick")





#####
#
# How to use this
# 2021aug21
#
#####

# «how-to-use»  (to ".how-to-use")
# This hands-on tutorial uses lua5.1, that is the version of
# Lua that I use in most of my Lua scripts. My main reason
# for preferring Lua5.1 is the "=" trick in the REPL, that
# is explained here:
#
#   (find-angg "edrxrepl/edrxrepl.lua" "Repl")

* (eepitch-shell)
* (eepitch-kill)
* (eepitch-shell)
sudo apt-get install -y lua5.1 lua5.1-dev lua5.1-doc

* (eepitch-shell)
* (eepitch-kill)
* (eepitch-shell)
# See: http://angg.twu.net/LUA/lua50init.lua.html
mkdir ~/LUA/
cd    ~/LUA/
rm -v lua50init.lua
wget   http://angg.twu.net/LUA/lua50init.lua

* (getenv "LUA_INIT")
* (setenv "LUA_INIT" (format "@%s/LUA/lua50init.lua" (getenv "HOME")))
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
A = {22, "22"}
PP(A, nil)

-- (find-wgeta "http://angg.twu.net/e/lua-intro.e")
-- (find-wgeta "http://angg.twu.net/e/lua-intro.e" "intro:types")





#####
#
# Quick presentation (updated to lua51)
# 2004sep02
#
#####

# «quick-presentation»  (to ".quick-presentation")
# Also at: (find-eev "examples/lua.e" "quick-presentation")
# (find-pilw3m "index.html")
# (find-pil2page 8 "Contents")
# (find-pil2text 8 "Contents")
#*

(defun nxt () (interactive) (search-forward "***"))
(defun nxt1 () (interactive) (nxt) (eek "3*DEL # SPC <delete> < <end> >"))










  «intro:types»  (to ".intro:types")
Lua has just a few basic data types.
We will see later that file handlers are not basic data types.
(find-pil2page (+ 19 9) "eight basic types")
(find-pil2text (+ 19 9) "eight basic types")
(find-pilw3m     "2.html" "eight basic types")
(find-lua51manual  "#2.2" "eight basic types")
(find-lua51manual "#pdf-type")

* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)

print(1,     type(1))          --> 1       number
print(1.0,   type(1.0))        --> 1       number
print("abc", type("abc"))      --> abc     string
print(nil,   type(nil))        --> nil     nil
print(true,  type(true))       --> true    boolean
print(false, type(false))      --> false   boolean
print(print, type(print))      --> function: 0x804d218     function
print({2,3,5}, type({}))       --> table: 0x8053ab0        table




  «intro:LUA_INIT» (to ".intro:LUA_INIT")
This is a hack to make Lua interpreters started from Emacs - like the
ones that are run by (eepitch-lua51) - load my init file.

# (find-lua51manual "#6" "Lua Stand-alone" "LUA_INIT" "@filename")
# (find-angg "LUA/lua50init.lua")
# http://angg.twu.net/LUA/lua50init.lua
# http://angg.twu.net/LUA/lua50init.lua.html

* (eepitch-shell)
* (eepitch-kill)
* (eepitch-shell)
mkdir ~/LUA/
cd    ~/LUA/
wget -nc http://angg.twu.net/LUA/lua50init.lua
*
* (getenv "LUA_INIT")
* (setenv "LUA_INIT" (concat "@" (ee-expand "~/LUA/lua50init.lua")))





  «intro:PP»  (to ".intro:PP")
I will sometimes use the function "PP",
defined in my init file, instead of "print".
(find-angg "LUA/lua50init.lua" "PP")
(find-angg "LUA/lua50init.lua" nil "LUA_INIT")

* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)

print(22, "22", print) --> 22 22 function: 0x9f11388
PP   (22, "22", print) --> 22 "22" <function: 0x9f11388>
print({2, 3, 5})       --> table: 0x9f1df70
PP   ({2, 3, 5})       --> {1=2, 2=3, 3=5}






  «intro:functions»  (to ".intro:functions")
Functions are values,
and "function f(args) body end" is just syntactical sugar
for "f=function(args) body end".
(find-lua51manual "#2.5.9" "f = function () body end")
(find-lua51manual  "#2.5.9" "f = function () body end")
(find-pilw3m "6.html" "More about Functions")
(find-pil2page (+ 19 45) "More About Functions")
(find-pil2text (+ 19 45) "More About Functions")

* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)

function square(a)     return a*a  end
square = function (a)  return a*a  end
print(square, square(2))   --> function: 0xa067dc0   4






  «intro:lists»  (to ".intro:lists")
Expressions may return lists of results,
and there are two ways to truncate lists
to a single result.
Multiple assignments work similarly to
functions receiving multiple arguments.
(find-lua51manual "#2.4.3" "Assignment")
(find-lua51manual "#2.5"   "Expressions")
(find-pilw3m  "5.1.html" "Multiple Results")
(find-pil2page (+ 19 36) "Multiple Results")
(find-pil2text (+ 19 36) "Multiple Results")
Vlists:  http://lua-users.org/lists/lua-l/2011-02/msg01467.html
Dracula: http://lua-users.org/lists/lua-l/2011-02/msg01477.html

* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)

function foo()  return 1, 2, 3  end
print(1, 2, 3)                         --> 1   2  3
print(foo())                           --> 1   2  3
print(99, foo())                       --> 99  1  2   3
print(99, foo(), 200)                  --> 99  1  200
print(99, (foo()))                     --> 99  1
zero, one, two, three, four = 0, 1, 2, 3, nil
zero, one, two, three, four = 0, 1, 2, 3
zero, one, two, three, four = 0, foo()
print(zero, one, two, three, four)     --> 0   1  2   3  nil
f = function (zero, one, two, three, four)
        print(zero, one, two, three, four)
  end
f(0, foo())                            --> 0   1  2   3  nil






  «intro:coercion»  (to ".intro:coercion")
Numbers are automatically coerced to strings
(and vice-versa) in certain situations.
(find-lua51manual  "#2.2.1" "Coercion")
(find-lua51manual  "#2.5.4" "Concatenation" "..")
(find-pilw3m     "2.4.html" "coercions")
(find-pil2page (+ 19 13)    "coercions")
(find-pil2text (+ 19 13)    "coercions")

* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)

print(1+"2")                    --> 3
print("ab".."cd")               --> abcd
print("<".. 11 .. 22 ..">")     --> <1122>






  «intro:string-literals»  (to ".intro:string-literals")
String literals can be quoted with '', "", [[]],
and also with [=[...]=], [==[...]==], etc.
There's a similar syntax for multi-line comments.
(find-lua51manual "#2.1" "Literal strings")
(find-lua51manual "#2.1" "Literal strings can also be defined")
(find-lua51manual "#2.1" "opening long bracket of level n")

-- A multi-line comment delimited by long brackets of level 4:
--[====[
  (inside the comment)
--]====]

* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
= "foo\nbar"
= [[foo\nbar]]
= [==[foo[[plic ploc]]bar]==]





  «intro:table-constructors»  (to ".intro:table-constructors")
Table constructors
(find-lua51manual "#2.5.7" "Table Constructors")
(find-pilw3m     "2.5.html" "Tables")
(find-pil2page (+ 19 13) "2.5      Tables")
(find-pil2text (+ 19 13) "2.5      Tables")

* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)

a = {10, 20, 30}
print(a[2])                      --> 20
print(200, "some string", a)     --> 200  some string  table: 0x8e2eee0
PP   (200, "some string", a)     --> 200 "some string" {1=10, 2=20, 3=30}
b = {11, a, "foo", print}
PP(b)   --> {1=11, 2={1=10, 2=20, 3=30}, 3="foo", 4=<function: 0x8e1e020>}
function foo() return 30, 40, 50 end
c = {10, 20, foo()}              --> {1=10, 2=20, 3=30, 4=40, 5=50}
PP(c)





  «intro:keys»  (to ".intro:keys")
More on tables:
keys and values don't need to be numbers,
reading and changing key/value pairs,
the {..., [key]=val, ...} syntax.

* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)

c = {11, 22, 33}
c[2] = c[2]+c[3]  -- change c[2] to 55
c[5] = 55         -- change c[5] to 55 (note that there's no c[4])
c["foo"] = "FOO"  -- change c["foo"] to "FOO"
print(c)          --> table: 0x84ee130
PP(c)             --> {1=11, 2=55, 3=33, 5=55, "foo"="FOO"}
d = {11, 22, 33, [5]=555, ["bar"]="BAR", [c]="!"}
PP(d)             --> {1=11, 2=22, 3=33, 5=555, "bar"="BAR", {...}="!"}
d[2] = nil        -- delete d[2]
d[c] = nil        -- delete d[c]
PP(d, d[2])       --> {1=11, 3=33, 5=555, "bar"="BAR"}  <nil>
x = {10, 20}
y = {10, 20}
PP(x, y)          --> {1=10, 2=20} {1=10, 2=20}
print(x, y)       --> table: 0x84fc048   table: 0x84fb770
x[1] = 1000
PP(x, y)          --> {1=1000, 2=20} {1=10, 2=20}





  «intro:length»  (to ".intro:length")
The somewhow non-deterministic "#" operator
(find-lua51manual "#2.5.5" "The Length Operator")
The four "#"s: http://lua-users.org/lists/lua-l/2011-04/msg00013.html
"is"/"or":     http://lua-users.org/lists/lua-l/2011-04/msg00065.html

* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)

f = function (T) printf("#%s = %d\n", mytostring(T), #T) end
s = function (n) a[n] = n;   f(a) end
r = function (n) a[n] = nil; f(a) end
a = {1, 2, 3, 4, 5}
r(3)      --> #{1=1, 2=2, 4=4, 5=5} = 5
s(7)      --> #{1=1, 2=2, 4=4, 5=5,      7=7} = 5
s(6)      --> #{1=1, 2=2, 4=4, 5=5, 6=6, 7=7} = 7
r(2)      --> #{1=1,      4=4, 5=5, 6=6, 7=7} = 7
r(7)      --> #{1=1,      4=4, 5=5, 6=6} = 6
s(100)    --> #{1=1,      4=4, 5=5, 6=6, 100=100} = 1
f("Foo")  --> #"Foo" = 3






  «intro:for»  (to ".intro:for")
The "for" statement in its two forms.
 (find-es "lua5" "for")
 (find-lua51manual "#2.4.5" "For Statement")

* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)

-- Numeric for:
for i=1,4     do print(i) end   --> 1 2 3 4
for i=5,-2,-2 do print(i) end   --> 5 3 1 -1
for i=2,2     do print(i) end   --> 2
for i=2,0     do print(i) end   --> (nothing)

-- Introduction to the generic for:
a={4, 5, k="V"}
PP(a)                                           --> {1=4, 2=5, "k"="V"}
for i=1,#a               do print(i, a[i]) end  --> 1 4 / 2 5
for key,val in  pairs(a) do print(key, val) end --> 1 4 / 2 5 / k V
for key,val in ipairs(a) do print(key, val) end --> 1 4 / 2 5

-- pairs(T) and ipairs(T) return "iterators".
a={4,5,k="V"}
print(a)          -->                      table: 0x8237440
print(pairs(a))   --> function: 0x82279e8  table: 0x8237440  nil
print(ipairs(a))  --> function: 0x8228370  table: 0x8237440  0






  «intro:global-vars»  (to ".intro:global-vars")
Global variables are stored in a table (usually called _G).
The T.key syntax is syntactic sugar for T["key"].
(find-lua51manual "#2.3" "environments")
(find-lua51manual "#pdf-_G")
(find-pil2page (+ 19 129) "The Environment")
(find-pil2text (+ 19 129) "The Environment")

* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)

for key,val in pairs(_G) do
  print(key, val)
end

print(string)                        --> table: 0x9961910
print(string.format)                 --> function: 0x9963d68
print(string["format"])              --> function: 0x9963d68
print(string.format("1+2=%d", 1+2))  --> 1+2=3
for key,val in pairs(string) do
  print(key, val)
end

print(print)        --> function: 0x9961388
print(_G["print"])  --> function: 0x9961388
print(_G.print)	    --> function: 0x9961388
print(_G)	    --> table: 0x9960450
print(_G["_G"])	    --> table: 0x9960450
print(_G._G)	    --> table: 0x9960450






  «intro:local-vars»  (to ".intro:local-vars")
Each block can have local variables.
Local variables are created dynamically by "local".
  (find-lua51manual "#2.3")
  (find-pil2page (+ 19 28) "4.2    Local Variables and Blocks")
  (find-pil2text (+ 19 28) "4.2    Local Variables and Blocks")

* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)

a = 22
do print(a)        --> 22
   local a = 33    -- the local "a" shadows the previous "a"
   print(a)        --> 33
end                -- discard the local "a"
print(a)           --> 22





  «intro:eval»  (to ".intro:eval")
The interpreter reads code as a string, and executes that.
This is done in two steps, both acessible by the user:
  "f = loadstring(str)" converts str to a function, f, and
  "f()" executes that function.
(This is similar to Lisp's "read" and "eval", by the way).
Actually we should use
  "f, err = loadstring(str)".
See: (find-pil2page (+ 19 64) "loadstring")
     (find-pil2text (+ 19 64) "loadstring")

* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)

str = [[ print("hello") ]]
print(str)                  --> print("hello")
f, err = loadstring(str)
print(f, err)               --> function: 0x88ee6c8  nil
f()                         --> hello

str = [[ print("no closing quo ]]
print(str)                  --> print("no closing quo
f, err = loadstring(str)
print(f, err)               --> nil  ...: unfinished string near '<eof>'

=  loadstring "2+()"
=  loadstring                "return 2+3,4"
= (loadstring                "return 2+3,4")()
= (loadstring "local a,b=...; return a*b,a")(10,20)





  «intro:assert»  (to ".intro:assert")
See: (find-lua51manual "#pdf-assert")
     (find-pilw3m "8.3.html" "assert")
     (find-pil2page (+ 19 64) "assert(loadstring(s))()")
     (find-pil2text (+ 19 64) "assert(loadstring(s))()")
     (find-pil2page (+ 19 67) "8.3      Errors")
     (find-pil2text (+ 19 67) "8.3      Errors")
     (find-pil2text (+ 19 67) "8.3      Errors" "assert")
     (find-pil2page (+ 19 68)                   "assert")
     http://lua-users.org/wiki/FinalizedExceptions

* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
print(assert(10, 20, 30))           --> 10 20 30
print(assert(nil))                  --> assertion failed
print(assert(nil, "Error message")) --> error message
str = [[ print("no closing quo ]]
print (loadstring(str))
assert(loadstring(str))

str = "print('foo'); return 1+2"
print(assert(loadstring(str))())    --> foo / 3






  «intro:closures»  (to ".intro:closures")
Capture of local variables (a.k.a. "closures").
(find-pilw3m "6.1.html" "closures")
(find-pil2page (+ 19 47) "6.1      Closures")
(find-pil2text (+ 19 47) "6.1      Closures")
(find-es "lua5" "closure-reductions")

* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)

foo = function ()              -- foo returns two functions...
  local storage
  return
    function () return storage end,         -- a "getter",
    function (x) storage = x; return x end  -- and a "setter".
end

get1, set1 = foo()     -- get1 and set1 use a first "storage"
get2, set2 = foo()     -- get2 and set2 use a second, different "storage"
print(set1(22), get1())          --> 22 22
print(set2(33), get1(), get2())  --> 33 22 33






  «intro:iterators»  (to ".intro:iterators")
We can use closures to construct "iterators" for the generic for.
(find-pilw3m "7.1.html" "Iterators and Closures")
(find-pil2page (+ 19 55) "7.1    Iterators and Closures")
(find-pil2text (+ 19 55) "7.1    Iterators and Closures")

* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)

myiterator = function (n)
    return function ()
        n = n / 2
        if n >= 1 then return n end
      end
  end
for n in myiterator(1024) do
  print(n)
end        --> 512 256 128 64 32 16 8 4 2 1






  «intro:__tostring»  (to ".intro:__tostring")
Introduction to metatables: the "__tostring" metamethod
(find-lua51manual "#2.8" "__add")
(find-lua51manual "#pdf-tostring" "__tostring")
(find-pil2page (+ 19 122) "mt.__tostring")
(find-pil2text (+ 19 122) "mt.__tostring")

* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
mt = {}
A = { name = "A" }
B = { name = "B" }
setmetatable(A, mt)
setmetatable(B, mt)
print(A)                    --> table: 0x9622d50
mt.__tostring = function (a)
    return a.name
  end
print(A)                    --> A
print(B)                    --> B
PP(A)                       --> {"name"="A"}
PP(B)                       --> {"name"="B"}
PP({A, B})                  --> {1={"name"="A"}, 2={"name"="B"}}
= string.format("%s", A)    --  error






  «intro:metamethods»  (to ".intro:metamethods")
Metatables: other metamethods besides __add and __tostring
(find-lua51manual "#2.8" "__add")
(find-pil2page (+ 19 123) "The __index metamethod")
(find-pil2text (+ 19 123) "The __index metamethod")
See also: http://angg.twu.net/__mt.html
  (find-TH "__mt")

* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
mt = {}
mt.__tostring = function (a) return a.name end
A = setmetatable({name = "A"}, mt)
A = setmetatable({name = "B"}, mt)
testmt = function (methodname)
    mt[methodname] = function (a, b)
        return methodname.."("..tostring(a)..", "..tostring(b)..")"
      end
  end
testmt("__add"); print(A+1, 1+A)    --> __add(A, 1)  __add(1, A)
testmt("__sub"); print(A-2, 2-A)    --> __sub(A, 2)  __sub(2, A)
testmt("__mul"); print(A*3, 3*A)    --> __mul(A, 3)  __mul(3, A)
testmt("__div"); print(A/4, 4/A)    --> __div(A, 4)  __div(4, A)
testmt("__mod"); print(A%5, 5%A)    --> __mod(A, 5)  __mod(5, A)
testmt("__pow"); print(A^6, 6^A)    --> __pow(A, 6)  __pow(6, A)
testmt("__concat"); print(A..7)	    --> __concat(A, 7)
testmt("__index"); print(A[8])	    --> __index(A, 8)
testmt("__unm"); print(-A)	    --> __unm(A, A)
testmt("__call"); print(A(10))	    --> __call(A, A)


-- Or:
mt = {}
mt.__tostring = function (a) return a.name end
mt.__add      = function (a, b) return mab("__add", a, b) end
mab = function (m, a, b) return m.."("..tostring(a)..", "..tostring(b)..")" end

A = setmetatable({name = "A"}, mt)
B = setmetatable({name = "B"}, mt)
= A
= B
= A+B

testmt = function (m) mt[m] = function (a, b) return mab(m, a, b) end end
testmt("__add"); print(A+1, 1+A)    --> __add(A, 1)  __add(1, A)
testmt("__sub"); print(A-2, 2-A)    --> __sub(A, 2)  __sub(2, A)
testmt("__mul"); print(A*3, 3*A)    --> __mul(A, 3)  __mul(3, A)
testmt("__div"); print(A/4, 4/A)    --> __div(A, 4)  __div(4, A)
testmt("__mod"); print(A%5, 5%A)    --> __mod(A, 5)  __mod(5, A)
testmt("__pow"); print(A^6, 6^A)    --> __pow(A, 6)  __pow(6, A)
testmt("__concat"); print(A..7)	    --> __concat(A, 7)
testmt("__index"); print(A[8])	    --> __index(A, 8)
testmt("__unm"); print(-A)	    --> __unm(A, A)
testmt("__call"); print(A(10))	    --> __call(A, 10)
PP(getmetatable(A))

t = setmetatable({}, {__div = function() return 1, 2 end})
= t / t     --> 1




Missing:
(find-lua51manual "#2.8" "\"len\":")
(find-lua51manual "#2.8" "\"eq\":")
(find-lua51manual "#2.8" "\"eq\":" "getcomphandler")
(find-lua51manual "#2.8" "\"lt\":")
(find-lua51manual "#2.8" "\"le\":")
(find-lua51manual "#2.8" "\"newindex\":")




  «intro:io»  (to ".intro:io")
Files and IO
(find-lua51manual "#5.7" "Input and Output Facilities")
(find-pilw3m "21.1.html")
(find-pil2page (+ 19 193) "The I/O Library")
(find-pil2text (+ 19 193) "The I/O Library")

* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
print(io)
for key,val in pairs(io) do print(key) end
print(io.stdin)
print(getmetatable(io.stdin))
print(getmetatable(io.stdin).__index)
for key,val in pairs(getmetatable(io.stdin)) do print(key) end




  «intro:string.gsub»  (to ".intro:string.gsub")
Strings: string.gsub
(find-lua51manual "#pdf-string.gsub")
(find-lua51manual "#5.4.1" "Patterns")
(find-pilw3m "20.html" "The String Library")
(find-pil2page (+ 19 175) "The String Library")
(find-pil2text (+ 19 175) "The String Library")

* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
pg = function (...) print(string.gsub(...)) end
pg = function (...) PP((string.gsub(...))) end
pg = function (...) PP(string.gsub(...)) end

t   = {name="lua", ver="5.1.4"}
tv  = function (v) return t[v] end
run = function (s) return loadstring(s)() end
PP(tv("ver"))                     --> "5.1.4"
PP(run("return 22, 33"))          --> 22 33
PP(os.getenv("HOME"))             --> "/home/edrx"
PP(os.getenv("FOO"))              --> <nil>

pg("hel wo",       "(%w+)",         "%1 %1")     --> "hel hel wo wo"   2
pg("hel wo",       "(%w+)",         "%1 %1", 1)  --> "hel hel wo"      1
pg("hel wo fr Lu", "(%w+)%s*(%w+)", "%2 %1")     --> "wo hel Lu fr"    2

pg("ho=$HOME, u=$USER", "%$(%w+)",  os.getenv)   --> "ho=/home/edrx, u=edrx" 2
pg("ho=$HOME, u=$FOO",  "%$(%w+)",  os.getenv)   --> "ho=/home/edrx, u=$FOO" 2
pg("4+5=$return 4+5$",  "%$(.-)%$", run)         --> "4+5=9"           1
pg("$name_$ver.tar.gz", "%$(%w+)",  tv)          --> "lua_5.1.tar.gz"  2





  «intro:string.format» (to ".intro:string.format")
Strings: string.format
(find-lua51manual "#pdf-string.format")
(find-pil2page (+ 19 177) "string.format")
(find-pil2text (+ 19 177) "string.format")
(find-man "3 printf")
(find-node "(libc)Formatted Output")
(find-node "(libc)Floating-Point Conversions")







testmt("__len"); print(#A)
testmt("__lt"); print(A<B, B<A)

print(mytostring_table(string, ",\n "))

mttest = function (field)
      a.__mt[field] = function (...) PP(field, unpack(arg)) end
    end




#*
# (find-dn4file "dednat41.lua" "string-methods")
# Metatables
lua51 -e '
  a = {}  
  PP(getmetatable(a))
  f = io.open("/tmp/o", "w")
  P(getmetatable(f))
  for key,val = 
'
#*




#####
#
# coroutines
# 2007may23
#
#####

# «coroutines»  (to ".coroutines")
# (find-pilfile "")
# (find-pilw3m "index.html")
# (find-pilw3m "9.html"   "Coroutines)
# (find-pilw3m "9.1.html" "Coroutine Basics")
# (find-pilw3m "9.2.html" "Pipes and Filters")
# (find-pilw3m "9.3.html" "Coroutines as Iterators")
# (find-pilw3m "9.4.html" "Non-Preemptive Multithreading")

-- (find-pilw3m "9.1.html" "Coroutine Basics")
-- (find-lua51manual "#2.11")
-- (find-lua51manual "#pdf-coroutine.resume")
-- (find-lua51file "")
-- (find-lua51file "src/lbaselib.c" "** Coroutine library")
-- (find-lua51file "src/lbaselib.c" "static const luaL_Reg co_funcs[] =")

* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
co = coroutine.create(function () print("hi") end)
print(co)                     --> thread: 0x8071d98
print(coroutine.status(co))   --> suspended
coroutine.resume(co)          --> hi
print(coroutine.status(co))   --> dead

* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
co = coroutine.create(function ()
    for i=1,4 do
      print("co", i)
      coroutine.yield()
    end
  end)
coroutine.resume(co)        --> co   1
print(coroutine.status(co)) --> suspended
coroutine.resume(co)        --> co   2
coroutine.resume(co)        --> co   3
coroutine.resume(co)        --> co   4
print(coroutine.status(co)) --> suspended
coroutine.resume(co)        --> (nothing)
print(coroutine.status(co)) --> dead
coroutine.resume(co)        --> (nothing)

* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
co = coroutine.create(function (a, b)
    print(a, b)
    print(coroutine.yield("foo", "bar"))
    print(coroutine.yield("bletch"))
    return "plic", "ploc"
  end)
print(coroutine.resume(co, 22, 33)) --> 22 33 / true foo bar
print(coroutine.resume(co, 44, 55)) --> 44 55 / true bletch
print(coroutine.resume(co, 66, 77)) --> 66 77 / true plic ploc
print(coroutine.status(co))         --> dead
print(coroutine.resume(co, 88, 99)) --> false   cannot resume dead coroutine




#####
#
# Understanding the bytecode: closures and capture of local variables
# 2007jun10
#
#####

# «bytecode:captures»  (to ".bytecode:captures")
# A closure is roughly a "prototype" - that holds the bytecode -
# plus a vector of upvalues.

# In the example below we are naming the prototypes according to where
# they start and end; so, for example, Proto_1_6 is the prototype that
# corresponds to the "function () ... end" thing that extends from
# lines 1 to 6, and Proto_1_8 is the "main prototype" of the chunk.
#*
cat > /tmp/foo.lua <<'%%%'
foo = function ()                            --> Proto_1_6
  local storage
  return
    function () return storage end,          --> Proto_4_4
    function (x) storage = x; return x end   --> Proto_5_5
end
get1, set1 = foo()
get2, set2 = foo()
%%%
#*
# (find-lua51w3m "doc/luac.html")
# (find-sh "luac51 -p -l /tmp/foo.lua")
# (find-sh "luac51    -l /tmp/foo.lua")

# «captures-data-structures»  (to ".captures-data-structures")
# (find-lua51file "src/lobject.h" "typedef struct Proto ")
# (find-lua51file "src/lobject.h" "typedef struct LClosure ")
# (find-lua51file "src/lobject.h" "typedef struct LocVar ")
# (find-lua51file "src/lobject.h" "typedef struct UpVal ")
# (find-lua51file "src/lstate.h"  "typedef struct CallInfo ")
# http://www.lua.org/source/5.1/lobject.h.html#Proto
# http://www.lua.org/source/5.1/lobject.h.html#LClosure
# http://www.lua.org/source/5.1/lobject.h.html#LocVar
# http://www.lua.org/source/5.1/lobject.h.html#UpVal
# http://www.lua.org/source/5.1/lstate.h.html#CallInfo
# (find-lua51file "src/lvm.c" "case OP_CLOSURE:")
# (find-fline "~/LOGS/2007jun09.lua")

Proto_4_4 = {
  k = { [-5] = "set2", [-4] = "get2", [-3] = "set1", [-2] = "get1", [-1] = "foo" },
  p = { [0] = Proto_1_6 },
  code = {
    "1  [4] GETUPVAL  0  0",   -- R[0] = U[0]   -- storage
    "2  [4] RETURN    0  2",   -- return R[0]
    "3  [4] RETURN    0  1",   -- (unreachable code)
  }
}
Proto_5_5 = {
  upvalues = { [0] = "storage" },  -- ???
  locvars  = { [0] = "x" },        -- ??? - x is an argument
  code = {
    "1  [5] SETUPVAL  0  0",   -- U[0] = R[0]   -- storage = x
    "2  [5] RETURN    0  2",   -- return R[0]
    "3  [5] RETURN    0  1",   -- (unreachable code)
  }
}
Proto_1_6 = {
  k = { [-5] = "set2", [-4] = "get2", [-3] = "set1", [-2] = "get1", [-1] = "foo" },
  p = { [0] = Proto_4_4, [1] = Proto_5_5 },
  locvars = { [0] = "storage" }
  code = {
    "1  [4] CLOSURE   1  0",   -- R[1] = closure(p[0],    -- Proto_4_4,
    "2  [4] MOVE      0  0",   --                LOCAL_0) --   storage
    "3  [5] CLOSURE   2  1",   -- R[2] = closure(p[1],    -- Proto_5_5,
    "4  [5] MOVE      0  0",   --                LOCAL_0) --   storage
    "5  [5] RETURN    1  3",   -- return R[1], R[2]
    "6  [6] RETURN    0  1",   -- (unreachable code)
  }
}
Proto_1_8 = {
  k = { [-5] = "set2", [-4] = "get2", [-3] = "set1", [-2] = "get1", [-1] = "foo" },
  p = { [0] = Proto_1_6 },
  code = {
    "1  [6] CLOSURE   0  0",   -- R[0] = closure(p[0])    --       Proto_1_6
    "2  [6] SETGLOBAL 0 -1",   -- G[k[-1]] = R[0]         -- foo = ^
    "3  [7] GETGLOBAL 0 -1",   -- R[0] = G[k[-1]]         --              foo
    "4  [7] CALL      0  1 3", -- R[0], R[1] = R[0]()     --                 ()
    "5  [7] SETGLOBAL 1 -3",   -- G[k[-3]] = R[1]         --       set1 =   ^
    "6  [7] SETGLOBAL 0 -2",   -- G[k[-2]] = R[0]         -- get1       = ^
    "7  [8] GETGLOBAL 0 -1",   -- R[0] = G[k[0]]          --              foo
    "8  [8] CALL      0  1 3", -- R[0], R[1] = R[0]()     --                 ()
    "9  [8] SETGLOBAL 1 -5",   -- G[k[-5]] = R[1]         --       set2 =   ^
    "10 [8] SETGLOBAL 0 -4",   -- G[k[-4]] = R[0]         -- get2       = ^
    "11 [8] RETURN    0  1",   -- return
  }
}

# (find-luanofrillspage 1)
# (find-luanofrillspage 52 "Closures and Closing")
# (find-luanofrillspage 28 "CALL")
# (find-luanofrillstext "-28-" -15 "CALL")

# An important diagram (that needs more details):
# (find-luaimppage 9)






#####
#
# building lua-5.1.2
# 2007apr04
#
#####

# «install-5.1.2»  (to ".install-5.1.2")
# http://www.lua.org/ftp/lua-5.1.2.tar.gz
# (code-c-d "lua51" "~/usrc/lua-5.1.2/")
# (find-lua51file "")
# (find-lua51file "INSTALL")
# (find-lua51file "oml")
# (find-lua51file "src/Makefile")
# (find-node "(make)Phony Targets" "`.PHONY'")
#*
mkdir   ~/usrc/
rm -Rfv ~/usrc/lua-5.1.2/
mkdir   ~/usrc/lua-5.1.2/
tar  -C ~/usrc/ -xvzf $S/http/www.lua.org/ftp/lua-5.1.2.tar.gz
cd      ~/usrc/lua-5.1.2/

# (to "risclua")
# «minimal_GCW_SUGAR»  (to ".minimal_GCW_SUGAR")
# (find-lua51file "src/llex.c" "#ifdef GCW_SUGAR")
# (find-lua51file "src/llex.c.orig" "case '=':")
# (find-tkdiff (ee-lua51file "src/llex.c") (ee-lua51file "src/llex.c.orig"))
#
cp -iv src/llex.c src/llex.c.orig
patch -p0 src/llex.c <<'%%%'
370a371,376
> #ifdef GCW_SUGAR
>         switch(ls->current) {
>          case '=': next(ls); return TK_EQ; break;
>          case '>': next(ls); return TK_RETURN; break;
>          default: return '=';  } 
> #else
372a379
> #endif
373a381,386
> #ifdef GCW_SUGAR
>       case '\\': {
>         next(ls);
>         return TK_FUNCTION;
>         }
> #endif
%%%

# Pre-compile llex.c with GCW_SUGAR=1
# cd src; gcc -O2 -Wall -DLUA_USE_LINUX -DGCW_SUGAR -c -o llex.o llex.c; cd ..
# Instead:

# (find-lua51file "src/Makefile")
patch -p0 src/Makefile <<'%%%'
11c11
< CFLAGS= -O2 -Wall $(MYCFLAGS)
---
> CFLAGS= -O2 -Wall $(MYCFLAGS) -DGCW_SUGAR -g
%%%

find * -name '*.[ch]' | sort > .files.ch
etags $(<.files.ch)

make linux test |& tee oml

# Make a .so
# (find-lua50file "Makefile" "so:")
# (find-lua51file "src/Makefile" "CORE_O=")
cd src; ld -o liblua.so -shared $(ar t liblua.a); cd ..

# (find-lua51file "oml")
# (find-lua51file "oml2")

#*
cd ~/usrc/lua-5.1.2/src/
cp -iv lua  ~/bin/lua51
cp -iv luac ~/bin/luac51

#*
# Test dlopen on lpeg
# (to "lpeg")
cd ~/usrc/lpeg-0.5/
~/usrc/lua-5.1.1/src/lua test.lua
~/usrc/lua-5.1.2/src/lua test.lua

#*
# (find-lua51file "src/Makefile")
# (find-lua51file "src/Makefile" "linux:")
# (find-lua51file "Makefile")
# (find-lua51file "oml")


make MYCFLAGS=-DGCW_SUGAR linux test |& tee oml




#####
#
# argpatch
# 2007jun09
#
#####

# (find-es "lua5" "argpatch")
* (eepitch-shell)
lua51 -e 'PP(arg)'
echo "PP(arg)" > /tmp/foo.lua
lua51 /tmp/foo.lua




#####
#
# Invoking arrays
# 2003jan08
#
#####

# «invoking-arrays»  (to ".invoking-arrays")
# (find-lua50ref "__call")
# (find-lua50ref "setmetatable")
# (find-lua50ref "sec3.7")
#*
lua50 -e '
  arr = {}				-- (find-lua50ref "sec3.7")
  setmetatable(arr, arr)		-- (find-lua50ref "setmetatable")
  arr.__call = print			-- (find-lua50ref "__call")
  arr(20, 30, 40)			--> table:0xxxxxxxxx 20 30 40

  arr.name = "<arr>"
  arr.__call = function (arr, ...)
      print(arr.name, unpack(arg))
    end
  arr(20, 30, 40)			--> <arr> 20 30 40
'
#*
lua50 -e '
  a = {}
  mt = {}
  setmetatable(a, mt)
  mtset = function (mtfield)
      mt[mtfield] = function (...) P(mtfield, unpack(arg)) end
    end
  mtset("__add"); b = a + 1
  mtset("__sub"); b = a - 2
  mtset("__mul"); b = a * 3
  mtset("__div"); b = a / 4
  mtset("__pow"); b = a ^ 5
  mtset("__unm"); b =   - a
  mtset("__concat"); b = a .. 6
  mtset("__eq");  b = a == a
  mtset("__lt");  b = a <  9
  mtset("__le");  b = a <= 10
'
#*

  mtset("__concat"); b = a[20]
  mtset("__eq"); b = a[20]
  mtset("__lt"); b = a[20]
  mtset("__le"); b = a[20]
  mtset("__index"); b = a[20]
  mtset("__newindex"); b = a[20]
  b = a[20]



# (find-lua50file "src/")

# (find-lua50file "src/lapi.c" "lua_getmetatable")
# (find-lua50file "src/lobject.h" "typedef struct Table")
# (find-lua50file "src/ltests.c" "static int metatable")
# (find-lua50file "src/ltm.c")
# (find-lua50file "src/lvm.c")
# (find-lua50file "src/lvm.c" "case OP_CALL:")

# (find-lua50file "src/lobject.h" "#define hvalue(o)")



#####
#
# string.find
# 2003mar12
#
#####

# «string.find»  (to ".string.find")
# (find-lua50ref "String Manipulation" "string.find")
# string.find (s, pattern [, init [, plain]])
#   --> begpos endpos captstr1 captstr2 ...
#*
lua50e 'P(string.find("0123456789", "3(45)(67)", 4))	--> 4 8 "45" "67"'
lua50e 'P(string.find("0123456789", "3(45)(67)", 5))	-->'
#*
# «string.gfind»  (to ".string.gfind")
# (find-lua50ref "String Manipulation" "string.gfind")
lua50e 'for w,s in string.gfind("aa!b!!c", "([^!]*)(!?)") do P(w, s) end'
lua50e 'for w,s in string.gfind("aa!b!!c!", "([^!]*)(!?)") do P(w, s) end'
#*



#####
#
# empty captures in patterns
# 2004jan14
#
#####

# «emptycaptures»  (to ".emptycaptures")
# (find-lua50ref "String Manipulation" ". string.find")
# (find-lua50ref "Captures" "the empty capture ()")
# (to "split")
#*
lua50e '
  P(string.find("abbc", "()(b+)()", 1))   --> 2 3  2 "bb" 4
  P(string.find("abbc", "()(b+)()", 2))   --> 2 3  2 "bb" 4
  P(string.find("abbc", "()(b+)()", 3))   --> 3 3  3 "b" 4
  P(string.find("abbc", "()(b+)()", 4))   -->
'
#*
lua50e '
split = function (str)
    local arr, pos = {}, 1
    while 1 do
      local _, __, word, newpos = string.find(str, "^[%s]*([^%s]+)()", pos)
      if newpos then table.insert(arr, word); pos = newpos
      else return arr
      end
    end
  end
PP(split(" abc  de "))
'
#*




####
#
# C calling lua
# 2004feb25
#
####

# «C-calls-lua»  (to ".C-calls-lua")
# (find-es "lua5" "C-calls-lua")
# (find-es "lua5" "luastackPP")
# (find-es "lua5" "pil")
# (find-es "lua5" "getoutput")
# (find-angg "LUA/lua50init.lua" "getoutput")




#####
#
# xpcall
# 2006sep16
#
#####

# «xpcall»  (to ".xpcall")
# (to "ldb")
# (find-lua51manual "#pdf-xpcall")
# (find-lua51manual "#pdf-debug.traceback")

* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
err    = function () print("foo"); io.output():flush(); error("bar") end
inner  = function () return 1+err() end
middle = function () return 1+inner() end
outer  = function () return 1+middle() end
outer()        -- "foo", then traceback
pcall(outer)   -- "foo", no traceback
xpcall(outer, PP)
xpcall(outer, function() print(debug.traceback()) end)

printtraceback = function() print(debug.traceback()) end
xpcall(outer, printtraceback)
xpcall(outer, debug.debug)
cont

-- (find-lua51file "src/ldebug.c")
-- (find-lua51file "src/ldblib.c")
-- (find-lua51file "src/ldblib.c" "{\"traceback\", db_errorfb},")
-- (find-lua51tag "db_errorfb")





#####
#
# pil 24.1: calling Lua from C
# 2006oct21
#
#####

# «pil24.1»  (to ".pil24.1")
# (find-es "icon" "icon-lua")
# (find-lua51file "")
# (find-lua51file "oml" "liblua.a")
# (find-lua51file "src/lua.c")
# (find-lua51file "src/" "liblua.a")

#*
# (eev-bounded)
rm -Rv /tmp/pil24_1/
mkdir  /tmp/pil24_1/
cd     /tmp/pil24_1/

cat > pil24_1.c <<'---'
#include <stdio.h>
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#include <string.h>   // for strlen
int main (void) {
  char buff[256];
  int error;
  lua_State *L = luaL_newstate();   /* opens Lua */
  luaL_openlibs(L);             /* opens the standard libraries */
  while (fgets(buff, sizeof(buff), stdin) != NULL) {
    error = luaL_loadbuffer(L, buff, strlen(buff), "line") ||
            lua_pcall(L, 0, 0, 0);
    if (error) {
      fprintf(stderr, "%s", lua_tostring(L, -1));
      lua_pop(L, 1);  /* pop error message from the stack */
    }
  }
  lua_close(L);
  return 0;
}
---

export LUA51SRC=$HOME/usrc/lua-5.1.1
gcc -O2 -Wall -I$LUA51SRC/src -c -o pil24_1.o pil24_1.c
# (find-lua51file "oml" "liblua.a")
# (find-lua51file "oml" "gcc -o lua ")
# gcc -o lua  lua.o liblua.a -lm -Wl,-E -ldl -lreadline -lhistory -lncurses
# gcc -o pil24_1 pil24_1.o $LUA51SRC/src/liblua.a -lm -Wl,-E -ldl -lreadline -lhistory -lncurses
  gcc -o pil24_1 pil24_1.o $LUA51SRC/src/liblua.a -lm -Wl,-E -ldl

echo 'print(1+2, "hello")' | ./pil24_1

#*
# (find-node "(gcc)Invoking GCC")
# (find-node "(gcc)Link Options")




#####
#
# lpeg quickref
# 2007mar05
#
#####

# «lpeg-quickref»  (to ".lpeg-quickref")
# (find-es "lua5" "lpeg-quickref")
# http://www.inf.puc-rio.br/~roberto/lpeg.html
# (find-lpegfile "lpeg.c")
# (find-lpegfile "lpeg.c" "{\"match\", matchl},")

lpeg.P(str)    matches str
lpeg.P(0)      matches always
lpeg.P(1)      matches one char (".")
lpeg.P(2)      matches two chars ("..")
lpeg.P(-1)     matches if there isn't another char (end of string)
lpeg.P(-2)     matches if there aren't two more chars
lpeg.P(p)      return the pattern p unmodified
lpeg.P(f)      if f(subj, pos) returns a valid newpos then matches until it
lpeg.P(gra)    matches the first entry (gra[1]) in the grammar gra (a table)
lpeg.V(2)      matches the second entry (gra[2]) in the grammar above this
lpeg.R("az", "AZ") matches any char in ranges - like "[A-Za-z]"
lpeg.S("abd")  matches any char in set - like "[abd]"
#patt          like patt, but without consuming input
-patt          like #patt, but negating the result
p1 * p2        concatenation: "p1p2"
p1 + p2        bounded prioritized choice - roughly like "p1|p2"
p1 - p2        equivalent to -p2 * p1
1 - cset       a char not in cset
patt ^ 0       at least 0 occurrences of patt - like "patt*"
patt ^ 1       at least 1 occurrence  of patt - like "patt+"
patt ^ 2       at least 2 occurrences of patt
patt ^ -1      at most  1 occurrence  of patt - like "patt?"
patt ^ -2      at most  2 occurrences of patt

lpeg.C(patt)   the substring matched by patt (then patt's other captures)
lpeg.Ca(patt)  if patt captures a,f,g,h then h(g(f(a)))   <--- WRONG!
lpeg.Cc(v)     matches the empty string, captures the value v
lpeg.Cs(patt)  the substring matched by patt, after substitutions
lpeg.Ct(patt)  all captures made by patt as a table
patt / f       if patt captured a,b,c then f(a, b, c)
patt / "_%2_"  if patt captured "foo" and "bar" then "_bar_"
patt / tbl     if patt captured a and b then tbl[a]




#####
#
# Lpeg: basic demos (but with "test" and "export")
# 2014aug30
#
#####

# «lpeg-basic» (to ".lpeg-basic")
# «lpeg-export» (to ".lpeg-export")
# file:///usr/share/doc/lua-lpeg-dev/lpeg.html

* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
require "lpeg"
loadlpeg()
lpeg.test = function (pat, str, ...) PP(pat:C():match(str, ...)) end
lpeg.export = function (str)
    for name in str:gmatch"%w+" do _G[name] = lpeg[name] end
  end
lpeg.export "P R S C Cp Ct Cc"
sp     =  S" " ^1           -- space         (no captures)
w      = (R"az"^1):C()      -- word          (one capture)
m      =  sp * w            -- one more word (one capture)
ms     = (sp * w)^1         -- more words    (one capture for each)
num    = (R"09"^1):C()

nop    = function () end
id     = function (...) return ... end
pre0   = function (...) return 0, ... end
swap   = function (a, b) return b, a end
swap   = function (a, b) return "<", b, a, ">" end

( w * m              ):test "abc def ghi jkl"
( w * ms             ):test "abc def ghi jkl"
( w * ms             ):test "abc def ghi"
( w * ms             ):test "abc def"
( w * ms             ):test "abc"
( w * ms             ):test ""
( w *  m/"_%1_"                         ):test "abc def ghi jkl"
( w * (m/"_%1_")                        ):test "abc def ghi jkl"
( w * (m * m /"_%1_%2_")    * m         ):test "abc def ghi jkl"
( w * (m * m / swap)        * m         ):test "abc def ghi jkl"
( w * (m/"_%1_")            * (m/"<%1>")):test "abc def ghi jkl"
( w * (m/nop)               * (m/"<%1>")):test "abc def ghi jkl"
( w * (m/id)                * (m/"<%1>")):test "abc def ghi jkl"
( w * (m/pre0)              * (m/"<%1>")):test "abc def ghi jkl"
(  w * Cc(20, 30, 40)       * (m/"_%1_")):test "abc def ghi jkl"
( (w * Cc(20, 30, 40)):Ct() * (m/"_%1_")):test "abc def ghi jkl"
( (w * Cc(20, 30, 40)):Ct() * (m/"_%1_")):test "abc def ghi jkl"

-- (find-es "lua5" "lpeg-re")
require "re"
re_extras = " _ -> ' '* "
re_extras = ""
string.retest = function (r, str) re.compile(r..re_extras):test(str) end
(" 'a'* "):retest "aaabbb"



-- «lpeg-P» (to ".lpeg-P")
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
require "lpeg"
lpeg.test   = function (pat, str, ...) PP(pat:C():match(str, ...)) end
lpeg.export = function (str) for w in str:gmatch"%w+" do _G[w]=lpeg[w] end end
lpeg.export "P R S C Cp Ct Cc"

-- lpeg.P(f)   if f(subj, pos) returns a valid newpos then matches until it




#####
#
# lpeg-re-quickref
# 2021sep04
#
#####

# «lpeg-re-quickref»  (to ".lpeg-re-quickref")




#####
#
# lpeg-re
# 2014oct03
#
#####

# «lpeg-re-1» (to ".lpeg-re-1")
# (find-angg "LUA/lua50init.lua" "syntree")
# file:///usr/share/doc/lua-lpeg-dev/re.html#ex

* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
require "re"
ang    = function (s) return "<"..s..">" end
retest = function (p) return function (s) print(re.match(s, p)) end end
retest "[0-9]"      "123abc"                                      --> 2
retest "[0-9]+"     "123abc"                                      --> 4
retest "{[0-9]+}"   "123abc"                                      --> 123
retest "{ [0-9]+ }" "123abc"                                      --> 123
retest "da <- d a    d <- {[0-9]+}  a <- {[a-z]+}" "123abc456"  --> 123 abc
retest "da <- {d} {a}   d <- [0-9]+   a <- [a-z]+" "123abc456"  --> 123 abc
retest "da <- {d a}     d <- [0-9]+   a <- [a-z]+" "123abc456"  --> 123abc

retest "da <- {d a} -> ang    d <- [0-9]+   a <- [a-z]+" "123abc456"  --> 123abc



# «lpeg-re-infix-1» (to ".lpeg-re-infix-1")
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
require "re"
g = function (...) return "("..table.concat({...}, " ")..")" end
f = function (...) local A={...}; return #A==1 and A[1] or g(...) end
defs   = { f = f }
c      = function (pat) return re.compile(pat, defs) end
retest = function (p) return function (s) print(re.match(s, c(p))) end end
retest [[
  e <- e3
  e3 <- (e2 ({"+"} e2)*) -> f
  e2 <- (e1 ({"*"} e1)*) -> f
  e1 <- (e0 ({"^"} e0)*) -> f
  e0 <- "(" e3 ")" / {[0-9]+}
]] "1*2+3^4*5^6+7^8"

--> ((1 * 2) + ((3 ^ 4) * (5 ^ 6)) + (7 ^ 8))

g = syntreeg
retest [[
  e <- e3
  e3 <- (e2 ({"+"} e2)*) -> f
  e2 <- (e1 ({"*"} e1)*) -> f
  e1 <- (e0 ({"^"} e0)*) -> f
  e0 <- "(" e3 ")" / {[0-9]+}
]] "1*2+3^4*5^6+7^8"

--> +_____+___________.   
--  |     |           |   
--  *__.  *_____.     ^__.
--  |  |  |     |     |  |
--  1  2  ^__.  ^__.  7  8
--        |  |  |  |      
--        3  4  5  6      



# «lpeg-re-infix-2» (to ".lpeg-re-infix-2")
# (find-angg "LUA/lua50init.lua" "re_expand_INFIX")
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
require "re"
g = syntreeg
f = function (...) local A={...}; return #A==1 and A[1] or g(...) end
defs   = { f = f }
c      = function (pat) return re.compile(pat, defs) end
retest = function (p) return function (s) print(re.match(s, c(p))) end end

gram = re_expand_INFIX [=[
  e  <- e3
  e3 <- INFIX( e2 s  + -   ) -> f
  e2 <- INFIX( e1 s  * /   ) -> f
  e1 <- INFIX( e0 ss ^     ) -> f
  e0 <- {[0-9]+}
  s  <- ' '*
  ss <- ' '+
]=]
= gram
retest (gram) "1*2+3^4*5^6+7^8"





#####
#
# lua-mode.el
# 2007feb05
#
#####

# «lua-mode.el»  (to ".lua-mode.el")
# (find-es "lua5" "lua-mode.el")






#####
#
# Patrick
# 2017mai16
#
#####

# «patrick» (to ".patrick")
# (defun u () (interactive) (find-escript-upload-links "lua-intro" "patrick"))
# (defun e () (interactive) (find-es "lua-intro" "patrick"))
# http://angg.twu.net/e/lua-intro.e.html#patrick
# http://angg.twu.net/e/lua-intro.e.html
# (find-wget "http://angg.twu.net/e/lua-intro.e" "<patrick-1>")



# <patrick-1>
# Instructions:

* (eepitch-shell)
* (eepitch-kill)
* (eepitch-shell)
sudo apt-get install lua5.1 lua5.1-doc

# http://angg.twu.net/e/lua-intro.e
mkdir -p $S/http/angg.twu.net/e/
cd       $S/http/angg.twu.net/e/
rm -v    'http://angg.twu.net/e/lua-intro.e'
wget     'http://angg.twu.net/e/lua-intro.e'
echo     'http://angg.twu.net/e/lua-intro.e' >> ~/.psne.log

mkdir ~/LUA/
cd    ~/LUA/
rm -v                        lua50init.lua
wget http://angg.twu.net/LUA/lua50init.lua
export LUA_INIT=@$HOME/LUA/lua50init.lua

* (setenv "LUA_INIT" (concat "@" (ee-expand "~/LUA/lua50init.lua")))
* (defun eejump-3 () (find-fline "$S/http/angg.twu.net/e/lua-intro.e"))
* (defun eejump-33 () (find-anchor "$S/http/angg.twu.net/e/lua-intro.e" "patrick"))
* (defun eejump-33 () (find-fline  "$S/http/angg.twu.net/e/lua-intro.e" "<patrick-1>"))
* (defun eepitch-lua51  () (interactive) (eepitch-comint "lua5.1"  "lua5.1"))

* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)

(defun find-lua51manual (&optional anchor &rest rest)
  (brg (format "file:///usr/share/doc/lua5.1-doc/doc/manual.html%s" (or anchor ""))))

(defun find-lua51manual (&optional anchor &rest rest) (find-lua51manual anchor))

;; (find-lua51manual "#2.2" "eight basic types")
;; (find-lua51manual "#2.2" "eight basic types")
;; (find-lua51manual "#pdf-type")

# (find-man "mkdir")
# (find-man "rm")
# (find-man "wget")
# (find-man "echo")
# (find-man "bash" "    cd ")

mkdir ~/LUA/
cd    ~/LUA/
rm -v                        lua50init.lua
wget http://angg.twu.net/LUA/lua50init.lua
export LUA_INIT=@$HOME/LUA/lua50init.lua






# <patrick-gab>
# (find-wget "http://angg.twu.net/e/lua-intro.e" "<patrick-gab>")

* (eepitch-shell)
* (eepitch-kill)
* (eepitch-shell)
# http://angg.twu.net/gabp/
rm -Rv ~/gabp/
mkdir  ~/gabp/
cd     ~/gabp/
wget http://angg.twu.net/gabp/gab.lua
wget http://angg.twu.net/gabp/gab-tests.lua

# Copie isto para o seu .emacs:

(code-c-d "angg" "~/" :anchor)
;; (find-angg "LUA/")
;; (find-angg "LUA/lua50init.lua")

(code-c-d "gabp" "~/gabp/" :anchor)
;; (find-gabp "")
;; (find-gabp "gab.lua")
;; (find-gabp "gab-tests.lua")








#  Local Variables:
#  coding:               utf-8-unix
#  modes: (fundamental-mode lua-mode c-mode)
#  End: