You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
lua is a lightweight, embeddable scripting language known for its simplicity and efficiency
widely used in game development, embedded systems, and as a configuration language like Neovim
Hello World
print("Hello World")
comments
single line comments
--single line comments
multi-line comments
--[[ multi-line comments]]
variables
declaration
globalVariable=12--default(avoid using globals)locallocalVariable=21--local, recommendedlocalx, y, z=1, 2, 3, 4--x = 1, y = 2, z = 3, and 4 is thrown awaylocalalpha, beta=1--alpha = 1, beta = nil
localarray= {1, 2, 3, 4, 5}
--insertionarray [6] =5--insert at index 6table.insert(array, 6)--append 6 to endtable.insert(array, 2, 7)--insert 7 at index 2--removaltable.remove(array)--remove last elementtable.remove(array, 1)--remove element at index 1--lengthprint(#array)--print length of array--concatenationlocalarray1= {"a", "b", "c"}
print(array.concat(array1, ", "))--array is {1, 7, 2, 3, 4, 5, 6, a, b, c}--interationforindex, valueinipairs(array) doprint("index: " ..index.."\tvalue: " ..tostring(value) ..'\n')
end--[[ output: index: 1 value: 1 index: 2 value: 7 index: 3 value: 2 index: 4 value: 3 index: 5 value: 4 index: 6 value: 5 index: 7 value: 6 index: 8 value: a index: 9 value: b index: 10 value: c]]--sortingtable.sort(array)--sort in ascending ordertable.sort(array, function(a, b) returna>bend)--sort in descending order
struct-like
localperson= {
firstName="Caesar",
age=19
}
--insertionperson.lastName="LEE"person [middleName] ="James"--removalperson.age=nil--remove by setting to nil(logical removal)--iterationforkey, valueinpairs(person) doprint("key: " ..key.."\tvalue: " ..tostring(value) ..'\n')
end--[[ output: key: firstName value: Caesar key: age value: nil key: lastName value: LEE key: middleName value: James]]person.sort--sort alphabetically
mixed tables
localmixedTable= {
1, 2, 3,--array partname="Caesar"
}
print(#mixedTable)--3, only support for array partprint(mixedTable [name])--Caesarprint(mixedTable [3])--3
localnum=3ifnum>0thenprint("positive")
elseifnum<0thenprint("negative")
elseprint("zero")
end
ternary
localfunctionparity (n)
iftype(n) =="number" thenreturn (n%2==0) and"even" or"odd"elsereturn"undefined type"endendlocalnum=2print(num.." is an " ..parity(num) .." number")
for
fori=1, 12do--range is [start, end], include both endsif(i==3ori==6ori==9)
--lua doesn't support continue--use if-else to simulate it--or use goto (lua 5.2+)elseprint("i is " ..i..'\n')--1, 2, 4, 5, 7, 8, 10, 11, 12endendlocalsum=0fori=5, 1, -1doif(i==3) thenbreakendifi==5thengotocontinue--use goto alternaitive for continueendsum=sum+iprint("sum is " ..sum)--4::continue::end
localfunctionigreet(name, greeting)--put default parameter at the endgreeting=greetingor"Hello"print(greeting..'' ..name)
endgreet("Caesar", "Fuck")--Fuck Caesargreet("CJL")--Hello CJL
anonymous functions(lua's lambda version)
return statements using ternaries (lambda version)
localfibonacci=function(n)
returnn<2and1orfibonaicci(n-2) +fibonacci(n-1)
end
sum of multiple values
print(
"sum is: " ..
(function(...)
localargs, sum= {...}, 0for_, valueinipairs(args) do--_ means indexsum=sum+valueendreturnsumend)(1, 2, 3)
)
metatables && metamethods
metatables allow you to change the behavior of tables
metatable is just a regular table with special keys(metamethods)
like a class where defines some special methods and operator overloads in C++
metamethod
meaning
C++ simular code
__index
called when accessing a non-existent key
operator[]
__newindex
called when assigning to a non-existent key
operator[], setter, etc
__call
allow calling the table as a function
operator()
__tostring
define string representation (used bytostring() and print())
operator<<, std::to_string()
__add
+ operator
operator+
__sub
- operator
operator-
__mul
* operator
operator*
__div
/ operator
operator/
__idiv
// operator(lua 5.3+)
operator/ for integer types
__mod
% operator
operator%
__pow
^ oprtator
operator^
__unm
unary - operator
unary operator-
__band
& bitwise AND operator(lua 5.3+)
operator&
__bor
| bitwise OR operator(lua 5.3+)
operator|
__bxor
~ bitwise XOR operator(lua 5.3+)
operoator^
__bnot
~ bitwise NOT operator(lua 5.3+)
operator~
__shl
<< shift left operaotor(lua 5.3+)
operator<< (bit shift)
__shr
>> shift right operator(lua 5.3+)
operator>> (bit shift)
__concat
.. operator
operator+ for std::string
__len
# operator
size() or length() methods
__eq
== and ~= operators
operaotor== and operaotor!=
__lt
< operator
operator<
__le
<=, >= operators
operator<= and operator>=
__ipairs
ipairs() function(lua 5.2+)
begin(), end() iterators
__pairs
pairs() function(lua 5.2+)
begin(), ned() iterators
__metatable
protect metatable, returned by getmetatable()
encapsulaition + access modifiers
__gc
garbage collection
destructor ~ClassName()
__mode
control weak tables(k, v, kv)
std::weak_ptr
example: complete 2D/3D vector implementation
--vector classlocalVector= {}--empty tableVector.__index=Vector--constructorfunctionVector.new(x, y, z)
iftype(x) ~="number" ortype(y) ~="number" thenprint("x and y must be numbers")
returnnilendifz~=nilandtype(z) ~="number" thenprint("z must be a number or nil")
returnnilendlocalself=setmetatable({}, Vector)--like thisself.x=xself.y=yself.z=zreturnselfend--dimensionsfunctionVector:is2D()
returnself.z==nilendfunctionVector:is3D()
returnself.z~=nilendfunctionVector:getDimension()
returnself.z==niland2or3end--additionfunctionVector.__add(a, b)
ifgetmetatable(a) ~=Vectororgetmetatable(b) ~=Vectorthenprint("cannot add with non-vector(s)")
returnnilendifa:getDimension() ~=b:getDimension() thenprint("cannot add with different dimension vector(s)")
returnnilendifa:is2D() thenreturnVector.new(a.x+b.x, a.y+b.y)
elsereturnVector.new(a.x+b.x, a.y+b.y, a.z+b.z)
endend--subtactionfunctionVector.__sub(a, b)
ifgetmetatable(a) ~=Vectororgetmetatable(b) ~=Vectorthenprint("cannot subtract with non-vector(s)")
returnnilendifa:getDimension() ~=b:getDimension() thenprint("cannot subtract with different dimension vectors")
returnnilendifa:is2D() thenreturnVector.new(a.x-b.x, a.y-b.y)
elsereturnVector.new(a.x-b.x, a.y-b.y, a.z-b.z)
endend--scalar multiplication or dot productfunctionVector.__mul(a, b)
--Vector * scalarifgetmetatable(a) ==Vectorandtype(b) =="number" thenifa:is2D() thenreturnVector.new(a.x*b, a.y*b)
elssreturnVector.new(a.x*b, a.y*b, a.z*b)
end--scalar * vectorelseiftype(a) =="number" andgetmetatable(b) ==Vectorthenifa:is2D() thenreturnVector.new(a*b.x, a*b.y)
elsereturnVector.new(a*b.x, a*b.y, a*b.z)
end--Vector * Vectorelseifgetmetatable(a) ==Vectorandgetmetatable(b) ==Vectorthenifa:getDimension() ~=b:getDimension() thenprint("cannot calculate dot product between different dimension vectors")
returnnilendifa:is2D() thenreturna.x*b.x+a.y*b.yelsereturna.x*b.x+a.y*b.y+a.z*b.zendelseprint("invalid parameter type")
returnnilendend--scalar divisionfunctionVector.__div(a, b)
ifgetmetatable(a) ~=Vectorandtype(b) ~="number" thenprint("invalid parameter type")
returnnilelseifb==0thenprint("cannot divided by zero")
returnnilelseifa:is2D() thenreturnVector.new(a.x/b, a.y/b)
elsereturnVector.new(a.x/b, a.y/b, a.z/b)
endendend--unary minusfunctionVector.__unm(v)
ifv:is2D() thenreturnVector.new(-v.x, -v.y)
elsereturnVector.new(-v.x, -v.y, -v.z)
endend--magnitudefunctionVector.__len(v)
ifv:is2D() thenreturnmath.sqrt(v.x^2+v.y^2)
elsereturnmath.sqrt(v.x^2+v.y^2+v.z^2)
endend--magnitude squaredfunctionVector:magnitudeSquared()
ifself:is2D() thenreturnself.x^2+self.y^2elsereturnself.x^2+self.y^2+self.z^2endend--equality comparisonfunctionVector.__eq(a, b)
ifgetmetatable(a) ~=Vectororgetmetatable(b) ~=Vectorthenreturnfalseendifa:getDimension() ~=b:getDimension() thenreturnfalseendifa:is2D() thenreturna.x==b.xanda.y==b.yelsereturna.x==b.xanda.y==b.yanda.z==b.zendend--less thanfunctionVector.__lt(a, b)
ifgetmetatable(a) ~=Vectororgetmetatable(b) ~=Vectorthenprint("cannot compare with non-vector(s)")
returnfalseendreturn#a<#bend--less than or equalfunctionVector.__le(a, b)
ifgetmetatable(a) ~=Vectororgetmetatable(b) ~=Vectorthenprint("cannot compare with non-vector(s)")
returnfalseendreturn#a<=#bend--string representationfunctionVector.__tostring(v)
ifv:is2D() thenstring.format("v = (%.3f, %.3f)", v.x, v.y)
elsestring.format("v = (%.3f, %.3f, %.3f)", v.x, v.y, v.z)
endend--normalize, convert to unit vectorfunctionVector:normalize()
ifself==Vector.ZEROprint("cannot normalize zero vector")
returnnilendifself:is2D() thenreturnVector.new(self.x/#self, self.y/#self)
elsereturnVector.new(self.x/#self, self.y/#self, self.z/#self)
endend--cross product (3D only)functionVector:cross(v)
ifgetmetatable(v) ~=Vectorthenprint("cannot calculate with non-vector")
returnnilelseifnotself:is3D() ornotv:is3D() thenprint("cannot calculate with non-3D vector(s)")
returnnilelsereturnVector.new(
self.y*v.z-self.z*v.y,
self.z*v.x-self.x*v.z,
self.x*v.y-self.y*v.x
)
endend--distancefunctionVector:distance(v)
ifgetmetatable(v) ~=Vectorthenprint("cannot calculate with non-vector")
returnnilelseifself:getDimension() ~=v:getDimension() thenprint("cannot calculate between different dimension vectors")
returnnilendreturn#(self-v)
end--angle between vectors in radiansfunctionVector:angle(v)
ifgetmetatable(v) ~=Vectorthenprint("cannot calculate with non-vector")
returnnilelseifself:getDimension() ~=v:getDimension() thenprint("cannot calculate between different dimension vectors")
returnnilelseifself==Vector.ZEROorv==Vector.ZEROthenprint("cannot calculate with zero vector")
returnnilelsereturnmath.acos((self*v) / (#self*#v))
endend--projectfunctionVector:project(v)
ifgetmetatable(v) ~=Vectorthenprint("cannot calculate with non-vector")
returnnilelseifself:getDimension() ~=v:getDimension() thenprint("cannot calculate between different dimension vectors")
returnnilelseifv==Vector.ZEROthenprint("cannot project onto zero vector")
returnnilelsereturnv* ((self*v) /v:magnitudeSquared())
endend--reflectfunctionVector:reflect(v)
ifgetmetatable(v) ~=Vectorthenprint("cannot calculate with non-vector")
returnnilelseifself:getDimension() ~=v:getDimension() thenprint("cannot calculate between different dimension vectors")
returnnilelsereturnself-v* (2* (self*v))
endend--linear interpolationfunctionVector:linearInterpolation(v, t)
ifgetmetatable(v) ~=Vectorthenprint("cannot calculate with non-vector")
returnnilelseifself:getDimension() ~=v:getDimension() thenprint("cannot calculate between different dimension vectors")
returnnilelsereturnself* (1-t) +v*tendend--clamp magnitudefunctionVector:clamp(maximumLength)
if#self>maximumLengththenreturnself:normalize() *maximumLengthendreturnVector.new(self.x, self.y, self.z)
end--static zero vectorVector.ZERO=Vector.ew(0, 0, 0)
string manipulation
function
description
#s or string.len(s)
length of str
string.upper(s)
convert to uppercase
string.lower(s)
convert to lowercase
string.sub(s, i, j)
substring from i to j(1-based, inclusive)
string.find(s, pattern, [start], [length])
return start and end positions of match
string.gsub(s, old, new, [n])
replace matches of old with new
string.format(format, ...)
formatted string, like printf in C
string.rep(s, n)
repeat sn times
string.reverse(s)
reversed string
string.char(n)
convert numbers to chars
string.byte(s, [i], [j])
return numeric code at index (support negative)
string.match(s, pattern, [start])
return captured substring(s)
string.gmatch(s, pattern)
return iterator for all matches
pattern characters
character
regular expression
description
.
.
any
%a
[A-Za-z]
letters
%c
[\x00-\x1F\x7F]
control characters
%d
\d or [0-9]
digits
%l
[a-z]
lowercases
%u
[A-Z]
uppercases
%w
\w or [A-Za-z0-9]
alphanumeric
%s
\s or [ \t\n\r]
space/writespace
%p
[!-/:-@[-`{-~]
punctutation
%x
[0-9A-Fa-f]
hexadecimal digits
%z
\0 or \x00
null character
+
+
$[1, \infty)$ repetitions
*
*
$[0, \infty)$ repetitions
-
*?
0/more repetitions
?
?
0/1 repetition
^
^
start of string
$
$
end of string
[set]
[set]
character set
[^set]
[^set]
complement of character set
()
()
capture group
%n(n = [0, 9])
\n(n = [0, 9])
captured string
%%
%
%
file I/O
read (default file operation)
read entire file
localfile=io.open("fileName", "r")--specify which file should be readiffilethen--if the file exists--read the whole contentlocalcontent=file:read("*all")--read all content of the file--*a is okprint(content)--print the contentfile:close()
end
read line by line
localfile=io.open("fileName", "r")
iffilethenforlineinfile:lines() doprint(line)
endfile:close()
end
read specific amounts
localfile=io.open("fileName", "r")
iffilethenlocalline=file:read("*line")--read one line--*l is oklocalnumber=file:read("*number")--read a number--*n is oklocalchars=file:read(12)--read 12 charactersfile:close()
end
use io.lines
forlineinio.lines("fileName") do--automatically close fileprint(line)
end
write
overwrite
localfile=io.open("fileName", "w")
iffilethenfile:write("content\n")
file:close()
end
append
localfile=io.open("fileName", "a")
iffilethenfile:write("content\n")
file:close()
end
file modes
mode
description
r
read(default)
w
write(create if needed)
a
append
r+
read and write(file must exist)
w+
read and write(create if needed)
a+
read and append
rb
read binary
wb
write binary
ab
append binary
date and time
functions
description
os.date([format], [time])
formatted date/time string, default is Fri Oct 10 08:59:30 2025
os.time([table])
timestamp in second since epoch (January 1, 2025 12:00:00 am)
os.difftime(laterTime, earlierTime)
difference between two timestamps in seconds
os.clock
CPU time used by program in seconds
format specifiers
specifier
description
%a
abbreviated weekday name
%A
full weekday name
%w
weekday as number([0 = Sunday, 6 = Saturday])
%b
abbreviated month name
%B
full month name
%m
month as number
%d
day of month
%j
day of year
%Y
year with century(4-digit)
%y
year without century(2-digit)
%x
date representation (10/13/25)
%H
hour in 24-hour format
%I
hour in 12-hour format
%M
minute
%S
second
%p
AM or PM
%X
time representation (18:21:12)
%c
date and time(10/13/25 18:21:12)
%Z
timezone name
%%
%
math
function
description
math.pi
$\pi$
math.huge
represent $\infty$
math.abs(n)
$\lvert n \rvert$
math.max(n, ...)
maximum value of all arguments
math.min(n, ...)
minimum value of all arguments
math.sqrt(n)
$\sqrt {n}$
math.sin(n)
$\sin(n)$
math.sinh(n)
$\sinh(n)$
math.asin(n)
$\arcsin(n)$
math.cos(n)
$\cos(n)$
math.cosh(n)
$\cosh(n)$
math.acos(n)
$\arccos(n)$
math.tan(n)
$\tan(n)$
math.tanh(n)
$\tanh(n)$
math.atan(n)
$\arctan(n)$
math.atan2(y, x)
$\arctan(\frac {y} {x})$
math.deg(n)
convert n radians to degree
math.rad(n)
convert n degree to radians
math.floor(n)
$\lfloor n \rfloor$
math.ceil(n)
$\lceil n \rceil$
math.pow(x, y)
${x} ^ {y}$
math.exp(n)
${e} ^ {n}$
math.fmod(x, y)
$x \mod y$
math.modf(n)
return integral part and fractional part of n
math.frexp(x)
$x = m \times {2} ^ {e}$, and return m and e, e.g. $12.5 = 0.781,25 \times {2} ^ {4}$
math.ldexp(m, e)
inverse of frexp
math.log(n)
$\log_{e}(n)$
math.log10(n)
$\log_{10}(n)$
math.random([m [,n]])
pseudo-random in $[0, 1)$ or $[1, m]$ or $[m, n]$
math.randomseed(n)
set seed for the pseudo-random generator
error throwing and handling
throw an error
localfunctionbiologicalGender(n)
ifnotnthenreturn"Male"elseifn==1thenreturn"Female"elseerror("invalid biological gender code (NOT MENTAL GENDER)")--throw an errorerror("invalid biological gender code: " ..n, 2)--add a code level: 2error({
type="InvalidParameter",
functionName="biologicalGender",
parameterName="n"message="invalid biological gender code"
})--throw an error object
handle an error
pcall protected call
localsuccess, result=pcall(throwErrorFunctionName, ...)--optional arguments--success is a boolean variable--result is a returned value or error messageifsuccessthenprint("Success:\t", result)--executed successfullyelseprint("Faild:\t", result)--caught an error message