Operator
All of Lua’s binary and unary operators are available. Additionally != is as an alias for ~=, and either \ or :: can be used to write a chaining function call like tb\func! or tb::func!. And Yuescipt offers some other special operators to write more expressive codes.
tb\func! if tb ~= niltb::func! if tb != niltb\func! if tb ~= niltb::func! if tb != nilChaining Comparisons
Section titled “Chaining Comparisons”Comparisons can be arbitrarily chained:
print 1 < 2 <= 2 < 3 == 3 > 2 >= 1 == 1 < 3 != 5-- output: true
a = 5print 1 <= a <= 10-- output: trueprint 1 < 2 <= 2 < 3 == 3 > 2 >= 1 == 1 < 3 != 5-- output: true
a = 5print 1 <= a <= 10-- output: trueNote the evaluation behavior of chained comparisons:
v = (x) -> print x x
print v(1) < v(2) <= v(3)--[[ output: 2 1 3 true]]
print v(1) > v(2) <= v(3)--[[ output: 2 1 false]]v = (x) -> print x x
print v(1) < v(2) <= v(3)--[[ output: 2 1 3 true]]
print v(1) > v(2) <= v(3)--[[ output: 2 1 false]]The middle expression is only evaluated once, rather than twice as it would be if the expression were written as v(1) < v(2) and v(2) <= v(3). However, the order of evaluations in a chained comparison is undefined. It is strongly recommended not to use expressions with side effects (such as printing) in chained comparisons. If side effects are required, the short-circuit and operator should be used explicitly.
Table Appending
Section titled “Table Appending”The [] = operator is used to append values to tables.
tab = []tab[] = "Value"tab = []tab[] = "Value"You can also use the spread operator ... to append all elements from one list to another:
tbA = [1, 2, 3]tbB = [4, 5, 6]tbA[] = ...tbB-- tbA is now [1, 2, 3, 4, 5, 6]tbA = [1, 2, 3]tbB = [4, 5, 6]tbA[] = ...tbB-- tbA is now [1, 2, 3, 4, 5, 6]Table Spreading
Section titled “Table Spreading”You can concatenate array tables or hash tables using spread operator ... before expressions in table literals.
When spreading into a brace table literal (for example, {...other}), both the array part and hash part of the Lua table are copied.
parts = * "shoulders" * "knees"lyrics = * "head" * ...parts * "and" * "toes"
copy = {...other}
a = {1, 2, 3, x: 1}b = {4, 5, y: 1}merge = {...a, ...b}parts = * "shoulders" * "knees"lyrics = * "head" * ...parts * "and" * "toes"
copy = {...other}
a = {1, 2, 3, x: 1}b = {4, 5, y: 1}merge = {...a, ...b}List Table Spreading
Section titled “List Table Spreading”When spreading into a bracket table literal (for example, [...other,]), only the array part is copied.
source = {1, 2, 3, name: "Yue"}fullCopy = {...source}listCopy = [...source,]-- fullCopy => {1, 2, 3, name: "Yue"}-- listCopy => [1, 2, 3]source = {1, 2, 3, name: "Yue"}fullCopy = {...source}listCopy = [...source,]-- fullCopy => {1, 2, 3, name: "Yue"}-- listCopy => [1, 2, 3]Table Reversed Indexing
Section titled “Table Reversed Indexing”You can use the # operator to get the last elements of a table.
last = data.items[#]second_last = data.items[#-1]data.items[#] = 1last = data.items[#]second_last = data.items[#-1]data.items[#] = 1Metatable
Section titled “Metatable”The <> operator can be used as a shortcut for metatable manipulation.
Metatable Creation
Section titled “Metatable Creation”Create normal table with empty bracekets <> or metamethod key which is surrounded by <>.
mt = {}add = (right) => <>: mt, value: @value + right.valuemt.__add = add
a = <>: mt, value: 1 -- set field with variable of the same nameb = :<add>, value: 2c = <add>: mt.__add, value: 3
d = a + b + cprint d.value
close _ = <close>: -> print "out of scope"mt = {}add = (right) => <>: mt, value: @value + right.valuemt.__add = add
a = <>: mt, value: 1 -- set field with variable of the same nameb = :<add>, value: 2c = <add>: mt.__add, value: 3
d = a + b + cprint d.value
close _ = <close>: -> print "out of scope"Metatable Accessing
Section titled “Metatable Accessing”Accessing metatable with <> or metamethod name surrounded by <> or writing some expression in <>.
-- create with metatable containing field "value"tb = <"value">: 123tb.<index> = tb.<>print tb.value
tb.<> = __index: {item: "hello"}print tb.item-- create with metatable containing field "value"tb = <"value">: 123tb.<index> = tb.<>print tb.valuetb.<> = __index: {item: "hello"}print tb.itemMetatable Destructure
Section titled “Metatable Destructure”Destruct metatable with metamethod key surrounded by <>.
{item, :new, :<close>, <index>: getter} = tbprint item, new, close, getter{item, :new, :<close>, <index>: getter} = tbprint item, new, close, getterExistence
Section titled “Existence”The ? operator can be used in a variety of contexts to check for existence.
func?!print abc?["hello world"]?.xyz
x = tab?.valuelen = utf8?.len or string?.len or (o) -> #o
if print and x? print x
with? io.open "test.txt", "w" \write "hello" \close!func?!print abc?["hello world"]?.xyz
x = tab?.valuelen = utf8?.len or string?.len or (o) -> #o
if print and x? print x
with? io.open "test.txt", "w" \write "hello" \close!Piping
Section titled “Piping”Instead of a series of nested function calls, you can pipe values with operator |>.
"hello" |> print1 |> print 2 -- insert pipe item as the first argument2 |> print 1, _, 3 -- pipe with a placeholder
-- pipe expression in multilinereadFile "example.txt" |> extract language, {} |> parse language |> emit |> render |> print"hello" |> print1 |> print 2 -- insert pipe item as the first argument2 |> print 1, _, 3 -- pipe with a placeholder
-- pipe expression in multilinereadFile "example.txt" |> extract language, {} |> parse language |> emit |> render |> printNil Coalescing
Section titled “Nil Coalescing”The nil-coalescing operator ?? returns the value of its left-hand operand if it isn’t nil; otherwise, it evaluates the right-hand operand and returns its result. The ?? operator doesn’t evaluate its right-hand operand if the left-hand operand evaluates to non-nil.
local a, b, c, da = b ?? c ?? dfunc a ?? {}
a ??= falselocal a, b, c, da = b ?? c ?? dfunc a ?? {}a ??= falseImplicit Object
Section titled “Implicit Object”You can write a list of implicit structures that starts with the symbol * or - inside a table block. If you are creating implicit object, the fields of the object must be with the same indent.
-- assignment with implicit objectlist = * 1 * 2 * 3
-- function call with implicit objectfunc * 1 * 2 * 3
-- return with implicit objectf = -> return * 1 * 2 * 3
-- table with implicit objecttb = name: "abc"
values: - "a" - "b" - "c"
objects: - name: "a" value: 1 func: => @value + 1 tb: fieldA: 1
- name: "b" value: 2 func: => @value + 2 tb: { }-- assignment with implicit objectlist = * 1 * 2 * 3
-- function call with implicit objectfunc * 1 * 2 * 3
-- return with implicit objectf = -> return * 1 * 2 * 3
-- table with implicit objecttb = name: "abc"
values: - "a" - "b" - "c"
objects: - name: "a" value: 1 func: => @value + 1 tb: fieldA: 1
- name: "b" value: 2 func: => @value + 2 tb: { }