The files with v3_ in front of it only work in 3.0, not in the LuaJIT 2.1 backport.
Last active
July 8, 2026 09:00
-
-
Save MikePall/a8372d92cb2e6380cf56e78f69ee70a4 to your computer and use it in GitHub Desktop.
LuaJIT 3.0 Syntax Extensions Test Cases
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| local function expect_err(code, expect) | |
| local f, err = loadstring(code, "=") | |
| if f ~= nil then | |
| error("unexpected success", 2) | |
| elseif not err:match(expect) then | |
| error('expected "'..expect..'", but got "'..err:gsub("^:1: ", "")..'"', 2) | |
| end | |
| end | |
| local N = setmetatable({}, { __index = function(_, x) return x end }) | |
| -- Bit operators: syntax. | |
| do | |
| assert(~ N[0b1010] == 0xfffffff5|0) | |
| assert(N[0xffffffff] | 0 == -1) | |
| assert(N[0b1010] & N[0b1100] == 0b1000) | |
| assert(N[0b1010] | N[0b1100] == 0b1110) | |
| assert(N[0b1010] ~ N[0b1100] == 0b0110) | |
| assert(N[0x55aa55aa] << N[4] == 0x5aa55aa0) | |
| assert(N[0x55aa55aa] >> N[4] == 0x055aa55a) | |
| assert(N[0x55aa55aa] ~>> N[4] == 0x055aa55a) | |
| assert(N[0xaa55aa55] >> N[4] == 0x0aa55aa5) | |
| assert(N[0xaa55aa55] ~>> N[4] == 0xfaa55aa5|0) | |
| end | |
| -- Bit operators: constant folding. | |
| do | |
| assert(~ 0b1010 == 0xfffffff5|0) | |
| assert(0xffffffff | 0 == -1) | |
| assert(0b1010 & 0b1100 == 0b1000) | |
| assert(0b1010 | 0b1100 == 0b1110) | |
| assert(0b1010 ~ 0b1100 == 0b0110) | |
| assert(0x55aa55aa << 4 == 0x5aa55aa0) | |
| assert(0x55aa55aa >> 4 == 0x055aa55a) | |
| assert(0x55aa55aa ~>> 4 == 0x055aa55a) | |
| assert(0xaa55aa55 >> 4 == 0x0aa55aa5) | |
| assert(0xaa55aa55 ~>> 4 == 0xfaa55aa5|0) | |
| end | |
| -- Bit operators: precedence. | |
| do | |
| assert(~ N[0b1010] & N[0b1100] == 0b0100) | |
| assert((~ N[0b1010]) & N[0b1100] == 0b0100) | |
| assert(~ (N[0b1010] & N[0b1100]) == -9) | |
| assert(~ N[0b1010] | N[0b1100] == -3) | |
| assert((~ N[0b1010]) | N[0b1100] == -3) | |
| assert(~ (N[0b1010] | N[0b1100]) == -15) | |
| assert(~ N[0b1010] ~ N[0b1100] == -7) | |
| assert((~ N[0b1010]) ~ N[0b1100] == -7) | |
| assert(~ (N[0b1010] ~ N[0b1100]) == -7) | |
| assert(~ N[0x55aa55aa] << N[4] == 0xa55aa550|0) | |
| assert((~ N[0x55aa55aa]) << N[4] == 0xa55aa550|0) | |
| assert(~ (N[0x55aa55aa] << N[4]) == 0xa55aa55f|0) | |
| assert(~ N[0x55aa55aa] >> N[4] == 0x0aa55aa5) | |
| assert((~ N[0x55aa55aa]) >> N[4] == 0x0aa55aa5) | |
| assert(~ (N[0x55aa55aa] >> N[4]) == 0xfaa55aa5|0) | |
| assert(~ N[0x55aa55aa] ~>> N[4] == 0xfaa55aa5|0) | |
| assert((~ N[0x55aa55aa]) ~>> N[4] == 0xfaa55aa5|0) | |
| assert(~ (N[0x55aa55aa] ~>> N[4]) == 0xfaa55aa5|0) | |
| assert(N[0b1010] & N[0b1100] ~ N[0b1101] == 0b0101) | |
| assert((N[0b1010] & N[0b1100]) ~ N[0b1101] == 0b0101) | |
| assert(N[0b1010] & (N[0b1100] ~ N[0b1101]) == 0b0000) | |
| assert(N[0b1010] | N[0b1100] & N[0b1101] == 0b1110) | |
| assert((N[0b1010] | N[0b1100]) & N[0b1101] == 0b1100) | |
| assert(N[0b1010] | (N[0b1100] & N[0b1101]) == 0b1110) | |
| assert(N[0b1010] | N[0b1100] ~ N[0b1101] == 0b1011) | |
| assert((N[0b1010] | N[0b1100]) ~ N[0b1101] == 0b0011) | |
| assert(N[0b1010] | (N[0b1100] ~ N[0b1101]) == 0b1011) | |
| assert(N[0x55aa55aa] >> N[3] & N[1] == 0x00000001) | |
| assert((N[0x55aa55aa] >> N[3]) & N[1] == 0x00000001) | |
| assert(N[0x55aa55aa] >> (N[3] & N[1]) == 0x2ad52ad5) | |
| assert(N[0b1010] | N[0b1100] + N[0b0101] == 0b11011) | |
| assert((N[0b1010] | N[0b1100]) + N[0b0101] == 0b10011) | |
| assert(N[0b1010] | (N[0b1100] + N[0b0101]) == 0b11011) | |
| end | |
| -- Bit operators: associativity. | |
| do | |
| assert(N[0x55aa55aa] << N[4] << N[2] == 0x6a956a80) | |
| assert((N[0x55aa55aa] << N[4]) << N[2] == 0x6a956a80) | |
| assert(N[0x55aa55aa] << (N[4] << N[2]) == 0x55aa0000) | |
| assert(N[0x55aa55aa] >> N[4] >> N[2] == 0x0156a956) | |
| assert((N[0x55aa55aa] >> N[4]) >> N[2] == 0x0156a956) | |
| assert(N[0x55aa55aa] >> (N[4] >> N[2]) == 0x2ad52ad5) | |
| assert(N[0xaa55aa55] ~>> N[4] ~>> N[2] == 0xfea956a9|0) | |
| assert((N[0xaa55aa55] ~>> N[4]) ~>> N[2] == 0xfea956a9|0) | |
| assert(N[0xaa55aa55] ~>> (N[4] ~>> N[2]) == 0xd52ad52a|0) | |
| end | |
| -- Bit operators: shift width masking. | |
| do | |
| assert(N[0x55aa55aa] << N[32] == 0x55aa55aa) | |
| assert(N[0x55aa55aa] >> N[32] == 0x55aa55aa) | |
| assert(N[0x55aa55aa] ~>> N[32] == 0x55aa55aa) | |
| assert(N[0xaa55aa55] ~>> N[32] == 0xaa55aa55|0) | |
| assert(N[0x55aa55aa] << N[36] == 0x5aa55aa0) | |
| assert(N[0x55aa55aa] >> N[36] == 0x055aa55a) | |
| assert(N[0x55aa55aa] ~>> N[36] == 0x055aa55a) | |
| assert(N[0xaa55aa55] ~>> N[36] == 0xfaa55aa5|0) | |
| assert(N[0xaa55aa55] << N[-1] == 0x80000000|0) | |
| assert(N[0xaa55aa55] >> N[-1] == 0x00000001) | |
| assert(N[0xaa55aa55] ~>> N[-1] == 0xffffffff|0) | |
| end | |
| -- Bit operators: metamethods. | |
| if jit and jit.version_num >= 30000 then -- NOT backported to v2.1. | |
| local mt = {} | |
| for _,name in ipairs({"bnot", "band", "bor", "bxor", "shl", "shr", "sar"}) do | |
| mt["__"..name] = function() return name end | |
| end | |
| local a = setmetatable({}, mt) | |
| local b = setmetatable({}, mt) | |
| assert(~ a == "bnot") | |
| assert(a & 1 == "band" and 1 & b == "band" and a & b == "band") | |
| assert(a | 1 == "bor" and 1 | b == "bor" and a | b == "bor") | |
| assert(a ~ 1 == "bxor" and 1 ~ b == "bxor" and a ~ b == "bxor") | |
| assert(a << 1 == "shl" and 1 << b == "shl" and a << b == "shl") | |
| assert(a >> 1 == "shr" and 1 >> b == "shr" and a >> b == "shr") | |
| assert(a ~>> 1 == "sar" and 1 ~>> b == "sar" and a ~>> b == "sar") | |
| end | |
| -- Bit operators: syntax errors. | |
| do | |
| expect_err("~", "near.*~") | |
| expect_err("~ a", "near.*~") | |
| expect_err("~ a = 1", "near.*~") | |
| expect_err("~ a += 1", "near.*~") | |
| expect_err("~ a()", "near.*~") | |
| expect_err("&", "near.*&") | |
| expect_err("a &", "near.*&") | |
| expect_err("a & b", "near.*&") | |
| expect_err("a & b = 1", "near.*&") | |
| expect_err("a & b += 1", "near.*&") | |
| expect_err("a() & b", "near.*&") | |
| expect_err("a & b()", "near.*&") | |
| expect_err("|", "near.*|") | |
| expect_err("a |", "near.*|") | |
| expect_err("a | b", "near.*|") | |
| expect_err("a | b = 1", "near.*|") | |
| expect_err("a | b += 1", "near.*|") | |
| expect_err("a() | b", "near.*|") | |
| expect_err("a | b()", "near.*|") | |
| expect_err("~", "near.*~") | |
| expect_err("a ~", "near.*~") | |
| expect_err("a ~ b", "near.*~") | |
| expect_err("a ~ b = 1", "near.*~") | |
| expect_err("a ~ b += 1", "near.*~") | |
| expect_err("a() ~ b", "near.*~") | |
| expect_err("a ~ b()", "near.*~") | |
| expect_err("<<", "near.*<<") | |
| expect_err("a <<", "near.*<<") | |
| expect_err("a << b", "near.*<<") | |
| expect_err("a << b = 1", "near.*<<") | |
| expect_err("a << b += 1", "near.*<<") | |
| expect_err("a() << b", "near.*<<") | |
| expect_err("a << b()", "near.*<<") | |
| expect_err(">>", "near.*>>") | |
| expect_err("a >>", "near.*>>") | |
| expect_err("a >> b", "near.*>>") | |
| expect_err("a >> b = 1", "near.*>>") | |
| expect_err("a >> b += 1", "near.*>>") | |
| expect_err("a() >> b", "near.*>>") | |
| expect_err("a >> b()", "near.*>>") | |
| expect_err("~>>", "near.*~>>") | |
| expect_err("a ~>>", "near.*~>>") | |
| expect_err("a ~>> b", "near.*~>>") | |
| expect_err("a ~>> b = 1", "near.*~>>") | |
| expect_err("a ~>> b += 1", "near.*~>>") | |
| expect_err("a() ~>> b", "near.*~>>") | |
| expect_err("a ~>> b()", "near.*~>>") | |
| end | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| -- Adapted from bit operations library tests. | |
| local xbit = { | |
| bnot = function(a) return ~a end, | |
| band = function(a, b) return a & b end, | |
| bor = function(a, b) return a | b end, | |
| bxor = function(a, b) return a ~ b end, | |
| lshift = function(a, b) return a << b end, | |
| rshift = function(a, b) return a >> b end, | |
| arshift = function(a, b) return a ~>> b end, | |
| } | |
| local vb = { | |
| 0, 1, -1, 2, -2, 0x12345678, 0x87654321, | |
| 0x33333333, 0x77777777, 0x55aa55aa, 0xaa55aa55, | |
| 0x7fffffff, 0x80000000, 0xffffffff | |
| } | |
| local function cksum(name, s, r) | |
| local z = 0 | |
| for i=1,#s do z = (z + string.byte(s, i)*i) % 2147483629 end | |
| if z ~= r then | |
| error("bit."..name.." test failed (got "..z..", expected "..r..")", 0) | |
| end | |
| end | |
| local function check_unop(name, r) | |
| local f = xbit[name] | |
| local s = "" | |
| if pcall(f) or pcall(f, "z") or pcall(f, true) then | |
| error("bit."..name.." fails to detect argument errors", 0) | |
| end | |
| for _,x in ipairs(vb) do s = s..","..tostring(f(x)) end | |
| cksum(name, s, r) | |
| end | |
| local function check_binop(name, r) | |
| local f = xbit[name] | |
| local s = "" | |
| if pcall(f) or pcall(f, "z") or pcall(f, true) then | |
| error("bit."..name.." fails to detect argument errors", 0) | |
| end | |
| for _,x in ipairs(vb) do | |
| for _,y in ipairs(vb) do s = s..","..tostring(f(x, y)) end | |
| end | |
| cksum(name, s, r) | |
| end | |
| local function check_binop_range(name, r, yb, ye) | |
| local f = xbit[name] | |
| local s = "" | |
| if pcall(f) or pcall(f, "z") or pcall(f, true) or pcall(f, 1, true) then | |
| error("bit."..name.." fails to detect argument errors", 0) | |
| end | |
| for _,x in ipairs(vb) do | |
| for y=yb,ye do s = s..","..tostring(f(x, y)) end | |
| end | |
| cksum(name, s, r) | |
| end | |
| local function check_shift(name, r) | |
| check_binop_range(name, r, 0, 31) | |
| end | |
| -- Bit operators: minimal sanity checks. | |
| do | |
| assert(0x7fffffff == 2147483647, "broken hex literals") | |
| assert(0xffffffff == -1 or 0xffffffff == 2^32-1, "broken hex literals") | |
| assert(tostring(-1) == "-1", "broken tostring()") | |
| assert(tostring(0xffffffff) == "-1" or tostring(0xffffffff) == "4294967295", "broken tostring()") | |
| end | |
| -- Bit operators: basic argument processing. | |
| do | |
| assert(xbit.bxor(1,2) == 3) | |
| end | |
| -- Bit operators: computed value. | |
| do | |
| check_unop("bnot", 287870) | |
| check_binop("band", 41206764) | |
| check_binop("bor", 51253663) | |
| check_binop("bxor", 79322427) | |
| check_shift("lshift", 325260344) | |
| check_shift("rshift", 139061800) | |
| check_shift("arshift", 111364720) | |
| end | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| local function expect_err(code, expect) | |
| local f, err = loadstring(code, "=") | |
| if f ~= nil then | |
| error("unexpected success", 2) | |
| elseif not err:match(expect) then | |
| error('expected "'..expect..'", but got "'..err:gsub("^:1: ", "")..'"', 2) | |
| end | |
| end | |
| local ok, ffi = pcall(require, "ffi") | |
| if ok then | |
| NULL = ffi.new("void *") | |
| else | |
| NULL = nil | |
| end | |
| NIL = nil | |
| FALSE = false | |
| TRUE = true | |
| NUMBER1 = 1 | |
| NUMBER2 = 2 | |
| collectgarbage() -- Prevent (simple) global store-to-load forwarding. | |
| -- nil-coalescing operator: syntax. | |
| do | |
| assert((NIL ?? NIL) == nil) | |
| assert((NIL ?? NUMBER1) == 1) | |
| assert((NULL ?? NUMBER1) == 1) | |
| assert((FALSE ?? NUMBER1) == false) | |
| assert((TRUE ?? NUMBER1) == true) | |
| assert((NUMBER1 ?? NUMBER2) == 1) | |
| assert((NIL == FALSE ?? NUMBER1) == false) | |
| assert((FALSE == FALSE ?? NUMBER1) == true) | |
| assert((NUMBER1 < NUMBER2 ?? NUMBER1) == true) | |
| assert((NUMBER1 > NUMBER2 ?? NUMBER1) == false) | |
| assert((NIL ?? NUMBER1 + NUMBER2) == 3) | |
| assert((NULL ?? NUMBER1 + NUMBER2) == 3) | |
| assert((FALSE ?? NUMBER1 + NUMBER2) == false) | |
| assert((TRUE ?? NUMBER1 + NUMBER2) == true) | |
| assert((NIL ?? NIL ?? NIL) == nil) | |
| assert((NIL ?? NIL ?? NUMBER1) == 1) | |
| assert((NIL ?? NULL ?? NUMBER1) == 1) | |
| assert((NULL ?? NULL ?? NUMBER1) == 1) | |
| assert((NIL ?? FALSE ?? NIL) == false) | |
| assert((NIL ?? FALSE ?? NUMBER2) == false) | |
| assert((NIL ?? NUMBER1 ?? NIL) == 1) | |
| assert((NIL ?? NUMBER1 ?? NUMBER2) == 1) | |
| end | |
| -- nil-coalescing operator: constant folding. | |
| do | |
| assert((nil ?? nil) == nil) | |
| assert((nil ?? 1) == 1) | |
| assert((false ?? 1) == false) | |
| assert((true ?? 1) == true) | |
| assert((1 ?? 2) == 1) | |
| assert((nil == false ?? 1) == false) | |
| assert((false == false ?? 1) == true) | |
| assert((1 < 2 ?? 1) == true) | |
| assert((1 > 2 ?? 1) == false) | |
| assert((nil ?? 1 + 2) == 3) | |
| assert((false ?? 1 + 2) == false) | |
| assert((true ?? 1 + 2) == true) | |
| assert((nil ?? nil ?? nil) == nil) | |
| assert((nil ?? nil ?? 1) == 1) | |
| assert((nil ?? false ?? nil) == false) | |
| assert((nil ?? false ?? 1) == false) | |
| assert((nil ?? 1 ?? nil) == 1) | |
| assert((nil ?? 1 ?? 2) == 1) | |
| end | |
| -- nil-coalescing operator: mixed with not/and/or. | |
| do | |
| assert((not (NIL ?? NUMBER1)) == false) | |
| assert((not (FALSE ?? NUMBER1)) == true) | |
| assert((not (TRUE ?? NUMBER1)) == false) | |
| assert(((not NIL) ?? NUMBER1) == true) | |
| assert(((not FALSE) ?? NUMBER1) == true) | |
| assert(((not TRUE) ?? NUMBER1) == false) | |
| assert(((NIL ?? NUMBER1) and NUMBER2) == 2) | |
| assert((NIL ?? (NUMBER1 and NUMBER2)) == 2) | |
| assert(((NUMBER1 and NUMBER2) ?? NIL) == 2) | |
| assert((NUMBER1 and (NIL ?? NUMBER2)) == 2) | |
| assert(((NIL ?? NUMBER1) or NUMBER2) == 1) | |
| assert((NIL ?? (NUMBER1 or NUMBER2)) == 1) | |
| assert((NIL or NUMBER1 ?? NUMBER2) == 1) | |
| assert(((NIL or NUMBER1) ?? NUMBER2) == 1) | |
| assert((NIL or (NUMBER1 ?? NUMBER2)) == 1) | |
| assert(((NUMBER1 or NUMBER2) ?? NIL) == 1) | |
| assert((NUMBER1 or (NIL ?? NUMBER2)) == 1) | |
| end | |
| -- nil-coalescing operator: precedence. | |
| do | |
| assert((NIL ?? NUMBER1 + NUMBER2) == 3) | |
| assert((NUMBER1 + NUMBER2 ?? 4 + 8) == 3) | |
| assert((FALSE ?? NIL ? 2 : 3) == 3) | |
| assert(((FALSE ?? NIL) ? 2 : 3) == 3) | |
| assert((FALSE ?? (NIL ? 2 : 3)) == false) | |
| assert((not NIL ?? NUMBER1) == true) | |
| assert((NIL ?? NUMBER1 and NUMBER2) == 2) | |
| assert((NIL ?? NUMBER1 or NUMBER2) == 1) | |
| end | |
| -- nil-coalescing operator: short-circuiting. | |
| do | |
| local function bad() error("call short-circuiting failed", 2) end | |
| assert((NUMBER1 ?? bad()) == 1) | |
| assert((NUMBER1 ?? bad() ?? bad()) == 1) | |
| local t = setmetatable({}, { | |
| __index = function() error("access short-circuiting failed", 2) end, | |
| }) | |
| assert((NUMBER1 ?? t.x) == 1) | |
| assert((NUMBER1 ?? t.x ?? t.y) == 1) | |
| local ok, err = pcall(function() return NIL ?? bad() ?? t.x end) | |
| assert(err:match("call")) | |
| end | |
| -- nil-coalescing operator: syntax errors. | |
| do | |
| expect_err("??", "near.*%?%?") | |
| expect_err("a ??", "near.*%?%?") | |
| expect_err("a ?? b", "near.*%?%?") | |
| expect_err("a ?? b = 1", "near.*%?%?") | |
| expect_err("a ?? b += 1", "near.*%?%?") | |
| expect_err("a() ?? b", "near.*%?%?") | |
| expect_err("a ?? b()", "near.*%?%?") | |
| end | |
| NULL = nil | |
| FALSE = nil | |
| TRUE = nil | |
| NUMBER1 = nil | |
| NUMBER2 = nil | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| local function expect_err(code, expect) | |
| local f, err = loadstring(code, "=") | |
| if f ~= nil then | |
| error("unexpected success", 2) | |
| elseif not err:match(expect) then | |
| error('expected "'..expect..'", but got "'..err:gsub("^:1: ", "")..'"', 2) | |
| end | |
| end | |
| local ok, ffi = pcall(require, "ffi") | |
| if ok then | |
| NULL = ffi.new("void *") | |
| else | |
| NULL = "FALLBACK-ANY-NON-NIL-OR-FALSE-OBJECT" -- Only here! | |
| end | |
| NIL = nil | |
| FALSE = false | |
| TRUE = true | |
| NUMBER1 = 1 | |
| NUMBER2 = 2 | |
| collectgarbage() -- Prevent (simple) global store-to-load forwarding. | |
| -- Conditional operator: syntax. | |
| do | |
| assert((NIL ? 1 : 2) == 2) | |
| assert((FALSE ? 1 : 2) == 2) | |
| assert((TRUE ? 1 : 2) == 1) | |
| assert((NULL ? 1 : 2) == 1) | |
| assert((9 ? 1 : 2) == 1) | |
| assert(("" ? 1 : 2) == 1) | |
| assert((NIL?1:2) == 2) | |
| assert((FALSE?1:2) == 2) | |
| assert((TRUE?1:2) == 1) | |
| assert((NIL ? NIL : FALSE) == false) | |
| assert((NIL ? FALSE : NIL) == nil) | |
| assert((FALSE ? NIL : FALSE) == false) | |
| assert((FALSE ? FALSE : NIL) == nil) | |
| assert((TRUE ? NIL : FALSE) == nil) | |
| assert((TRUE ? FALSE : NIL) == false) | |
| assert((NIL == FALSE ? 9 : 11) == 11) | |
| assert((FALSE == FALSE ? 9 : 11) == 9) | |
| assert((NUMBER1 < NUMBER2 ? 9 : 11) == 9) | |
| assert((NUMBER1 > NUMBER2 ? 9 : 11) == 11) | |
| assert((NIL ? NUMBER1 + NUMBER2 : NUMBER1 - NUMBER2) == -1) | |
| assert((FALSE ? NUMBER1 + NUMBER2 : NUMBER1 - NUMBER2) == -1) | |
| assert((TRUE ? NUMBER1 + NUMBER2 : NUMBER1 - NUMBER2) == 3) | |
| assert((NUMBER1 < NUMBER2 ? NUMBER1 + NUMBER2 : NUMBER1 - NUMBER2) == 3) | |
| assert((NUMBER1 > NUMBER2 ? NUMBER1 + NUMBER2 : NUMBER1 - NUMBER2) == -1) | |
| end | |
| -- Conditional operator: constant folding. | |
| do | |
| assert((nil ? 1 : 2) == 2) | |
| assert((false ? 1 : 2) == 2) | |
| assert((true ? 1 : 2) == 1) | |
| assert((9 ? 1 : 2) == 1) | |
| assert(("" ? 1 : 2) == 1) | |
| assert((nil ? nil : false) == false) | |
| assert((nil ? false : nil) == nil) | |
| assert((false ? nil : false) == false) | |
| assert((false ? false : nil) == nil) | |
| assert((true ? nil : false) == nil) | |
| assert((true ? false : nil) == false) | |
| assert((nil == false ? 9 : 11) == 11) | |
| assert((false == false ? 9 : 11) == 9) | |
| assert((1 < 2 ? 9 : 11) == 9) | |
| assert((1 > 2 ? 9 : 11) == 11) | |
| assert((nil ? 1 + 2 : 1 - 2) == -1) | |
| assert((false ? 1 + 2 : 1 - 2) == -1) | |
| assert((true ? 1 + 2 : 1 - 2) == 3) | |
| assert((1 < 2 ? 1 + 2 : 1 - 2) == 3) | |
| assert((1 > 2 ? 1 + 2 : 1 - 2) == -1) | |
| end | |
| -- Conditional operator: mixed with not/and/or. | |
| do | |
| assert((not (NIL ? NUMBER1 : FALSE)) == true) | |
| assert((not (FALSE ? NUMBER1 : FALSE)) == true) | |
| assert((not (TRUE ? NUMBER1 : FALSE)) == false) | |
| assert(((not NIL) ? NUMBER1 : FALSE) == 1) | |
| assert(((not FALSE) ? NUMBER1 : FALSE) == 1) | |
| assert(((not TRUE) ? NUMBER1 : FALSE) == false) | |
| assert(((NIL ? NUMBER1 : FALSE) and NUMBER2) == false) | |
| assert((NIL ? (NUMBER1 and NUMBER2) : FALSE) == false) | |
| assert(((NUMBER1 and NUMBER2) ? NIL : FALSE) == nil) | |
| assert((NUMBER1 and (NIL ? NUMBER2 : FALSE)) == false) | |
| assert(((NIL ? NUMBER1 : FALSE) or NUMBER2) == 2) | |
| assert((NIL ? (NUMBER1 or NUMBER2) : FALSE) == false) | |
| assert((NIL or NUMBER1 ? NUMBER2 : FALSE) == 2) | |
| assert(((NIL or NUMBER1) ? NUMBER2 : FALSE) == 2) | |
| assert((NIL or (NUMBER1 ? NUMBER2 : FALSE)) == 2) | |
| assert(((NUMBER1 or NUMBER2) ? NIL : FALSE) == nil) | |
| assert((NUMBER1 or (NIL ? NUMBER2 : FALSE)) == 1) | |
| end | |
| -- Conditional operator: associativity. | |
| do | |
| assert((FALSE ? NUMBER1 : FALSE ? NUMBER2 : NUMBER1 + NUMBER2) == 3) | |
| assert((TRUE ? NUMBER1 : FALSE ? NUMBER2 : NUMBER1 + NUMBER2) == 1) | |
| assert((FALSE ? NUMBER1 : TRUE ? NUMBER2 : NUMBER1 + NUMBER2) == 2) | |
| assert((TRUE ? NUMBER1 : TRUE ? NUMBER2 : NUMBER1 + NUMBER2) == 1) | |
| assert((FALSE ? NUMBER1 : (FALSE ? NUMBER2 : NUMBER1 + NUMBER2)) == 3) | |
| assert((TRUE ? NUMBER1 : (FALSE ? NUMBER2 : NUMBER1 + NUMBER2)) == 1) | |
| assert((FALSE ? NUMBER1 : (TRUE ? NUMBER2 : NUMBER1 + NUMBER2)) == 2) | |
| assert((TRUE ? NUMBER1 : (TRUE ? NUMBER2 : NUMBER1 + NUMBER2)) == 1) | |
| assert(((FALSE ? NUMBER1 : FALSE) ? NUMBER2 : NUMBER1 + NUMBER2) == 3) | |
| assert(((TRUE ? NUMBER1 : FALSE) ? NUMBER2 : NUMBER1 + NUMBER2) == 2) | |
| assert(((FALSE ? NUMBER1 : TRUE) ? NUMBER2 : NUMBER1 + NUMBER2) == 2) | |
| assert(((TRUE ? NUMBER1 : TRUE) ? NUMBER2 : NUMBER1 + NUMBER2) == 2) | |
| end | |
| -- Conditional operator: short-circuiting. | |
| do | |
| local function bad() error("call short-circuiting failed", 2) end | |
| assert((FALSE ? bad() : NUMBER1) == 1) | |
| assert((TRUE ? NUMBER1 : bad()) == 1) | |
| local t = setmetatable({}, { | |
| __index = function() error("access short-circuiting failed", 2) end, | |
| }) | |
| assert((FALSE ? t.x : NUMBER1) == 1) | |
| assert((TRUE ? NUMBER1 : t.x) == 1) | |
| end | |
| -- Conditional operator: colon parsing. | |
| do | |
| local a = { | |
| x = 1, | |
| b = function(obj1) | |
| return { | |
| x = 2, | |
| c = function(obj2) | |
| return obj1.x + obj2.x + 10 | |
| end, | |
| } | |
| end, | |
| } | |
| local b = function() | |
| return { | |
| x = 3, | |
| c = function(obj3) | |
| return obj3.x + 20 | |
| end, | |
| } | |
| end | |
| local c = function() return 15 end | |
| assert((TRUE ? a : b():c() + 30).x == 1) | |
| assert((FALSE ? a : b():c() + 30) == 53) | |
| assert((TRUE ? a : 0 + b():c() + 30).x == 1) | |
| assert((FALSE ? a : 0 + b():c() + 30) == 53) | |
| assert((TRUE ? (a:b()) : c() + 30).x == 2) | |
| assert((FALSE ? (a:b()) : c() + 30) == 45) | |
| end | |
| -- Conditional operator: forced single return value. | |
| do | |
| local function f() return 1, 2 end | |
| local function g() return 3, 4 end | |
| local a, b = FALSE ? f() : 9 | |
| assert(a == 9 and b == nil) | |
| local a, b = TRUE ? f() : 9 | |
| assert(a == 1 and b == nil) | |
| local a, b = FALSE ? 9 : f() | |
| assert(a == 1 and b == nil) | |
| local a, b = TRUE ? 9 : f() | |
| assert(a == 9 and b == nil) | |
| local a, b = FALSE ? f() : g() | |
| assert(a == 3 and b == nil) | |
| local a, b = TRUE ? f() : g() | |
| assert(a == 1 and b == nil) | |
| end | |
| -- Conditional operator: syntax errors. | |
| do | |
| expect_err("?:", "near.*%?") | |
| expect_err("a?:", "near.*%?") | |
| expect_err("a?b:", "near.*%?") | |
| expect_err("a?:c", "near.*%?") | |
| expect_err("a?b:c", "near.*%?") | |
| expect_err("a?b:c = 1", "near.*%?") | |
| expect_err("(a?b:c) = 1", "near.*=") | |
| expect_err("local x = a ?", "near.*eof") | |
| expect_err("local x = a ? :", "near.*:") | |
| expect_err("local x = a ? b :", "near.*eof") | |
| expect_err("local x = a ? : c", "near.*:") | |
| expect_err("local x = a ? obj:method() : c", "near.*eof") | |
| end | |
| NULL = nil | |
| FALSE = nil | |
| TRUE = nil | |
| NUMBER1 = nil | |
| NUMBER2 = nil | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| NIL = nil | |
| FALSE = false | |
| TRUE = true | |
| NUMBER1 = 1 | |
| NUMBER2 = 2 | |
| collectgarbage() -- Prevent (simple) global store-to-load forwarding. | |
| -- Customary operators: syntax. | |
| do | |
| assert((! NIL) == true) | |
| assert((! FALSE) == true) | |
| assert((! TRUE) == false) | |
| assert((! NUMBER1) == false) | |
| assert((NIL && NUMBER1) == nil) | |
| assert((FALSE && NUMBER1) == false) | |
| assert((TRUE && NUMBER1) == 1) | |
| assert((NIL || NUMBER1) == 1) | |
| assert((FALSE || NUMBER1) == 1) | |
| assert((TRUE || NUMBER1) == true) | |
| end | |
| -- Customary operators: constant folding. | |
| do | |
| assert((! nil) == true) | |
| assert((! false) == true) | |
| assert((! true) == false) | |
| assert((! 1) == false) | |
| assert((nil && 1) == nil) | |
| assert((false && 1) == false) | |
| assert((true && 1) == 1) | |
| assert((nil || 1) == 1) | |
| assert((false || 1) == 1) | |
| assert((true || 1) == true) | |
| end | |
| -- Customary operators: precedence. | |
| do | |
| assert((! NIL && NUMBER1) == 1) | |
| assert(((! NIL) && NUMBER1) == 1) | |
| assert((! (NIL && NUMBER1)) == true) | |
| assert((! NIL || NUMBER1) == true) | |
| assert(((! NIL) || NUMBER1) == true) | |
| assert((! (NIL || NUMBER1)) == false) | |
| assert((NIL && TRUE || NUMBER1) == 1) | |
| assert(((NIL && TRUE) || NUMBER1) == 1) | |
| assert((NIL && (TRUE || NUMBER1)) == nil) | |
| assert((NIL && FALSE || NUMBER1) == 1) | |
| assert(((NIL && FALSE) || NUMBER1) == 1) | |
| assert((NIL && (FALSE || NUMBER1)) == nil) | |
| assert((TRUE && FALSE || NUMBER1) == 1) | |
| assert(((TRUE && FALSE) || NUMBER1) == 1) | |
| assert((TRUE && (FALSE || NUMBER1)) == 1) -- OK. Classic pitfall, use ?: | |
| debug.setmetatable(false, { | |
| __add = function(a, b) | |
| if a == false then return b+10 else return b+20 end | |
| end, | |
| }) | |
| assert((! NUMBER1 + NUMBER2) == 12) | |
| assert(((! NUMBER1) + NUMBER2) == 12) | |
| assert((! (NUMBER1 + NUMBER2)) == false) | |
| assert((TRUE && NUMBER1 + NUMBER2) == 3) | |
| assert((FALSE && NUMBER1 + NUMBER2) == false) | |
| assert((FALSE && (NUMBER1 + NUMBER2)) == false) | |
| assert(((FALSE && NUMBER1) + NUMBER2) == 12) | |
| assert((FALSE || NUMBER1 + NUMBER2) == 3) | |
| assert((TRUE || NUMBER1 + NUMBER2) == true) | |
| assert((TRUE || (NUMBER1 + NUMBER2)) == true) | |
| assert(((TRUE || NUMBER1) + NUMBER2) == 22) | |
| debug.setmetatable(false, nil) | |
| end | |
| -- Customary operators: associativity. | |
| do | |
| assert((TRUE && NUMBER1 && NUMBER2) == 2) | |
| assert(((TRUE && NUMBER1) && NUMBER2) == 2) | |
| assert((TRUE && (NUMBER1 && NUMBER2)) == 2) | |
| assert((FALSE && NUMBER1 && NUMBER2) == false) | |
| assert(((FALSE && NUMBER1) && NUMBER2) == false) | |
| assert((FALSE && (NUMBER1 && NUMBER2)) == false) | |
| assert((TRUE || NUMBER1 || NUMBER2) == true) | |
| assert(((TRUE || NUMBER1) || NUMBER2) == true) | |
| assert((TRUE || (NUMBER1 || NUMBER2)) == true) | |
| assert((FALSE || NUMBER1 || NUMBER2) == 1) | |
| assert(((FALSE || NUMBER1) || NUMBER2) == 1) | |
| assert((FALSE || (NUMBER1 || NUMBER2)) == 1) | |
| end | |
| -- Customary operators: short-circuiting. | |
| do | |
| local function bad() error("call short-circuiting failed", 2) end | |
| assert((FALSE && bad()) == false) | |
| assert((TRUE || bad()) == true) | |
| local t = setmetatable({}, { | |
| __index = function() error("access short-circuiting failed", 2) end, | |
| }) | |
| assert((FALSE && t.x) == false) | |
| assert((TRUE || t.x) == true) | |
| end | |
| NULL = nil | |
| FALSE = nil | |
| TRUE = nil | |
| NUMBER1 = nil | |
| NUMBER2 = nil | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| local function expect_err(code, expect) | |
| local f, err = loadstring(code, "=") | |
| if f ~= nil then | |
| error("unexpected success", 2) | |
| elseif not err:match(expect) then | |
| error('expected "'..expect..'", but got "'..err:gsub("^:1: ", "")..'"', 2) | |
| end | |
| end | |
| -- Short functions: expression syntax. | |
| do | |
| local f0 = ||->11 | |
| assert(f0() == 11) | |
| local f1a = x->x+1 | |
| assert(f1a(10) == 11) | |
| local f1b = |x|->x+1 | |
| assert(f1b(10) == 11) | |
| local f2 = |x, y| -> x + y | |
| assert(f2(10, 2) == 12) | |
| end | |
| -- Short functions: statement syntax. | |
| do | |
| local f00 = ||->do end | |
| assert(f00() == nil) | |
| assert(select("#", f00()) == 0) | |
| local f0 = ||->do return 11 end | |
| assert(f0() == 11) | |
| local f1a = x->do return x+1 end | |
| assert(f1a(10) == 11) | |
| local f1b = |x|->do return x+1 end | |
| assert(f1b(10) == 11) | |
| local f2 = |x, y| -> do return x + y end | |
| assert(f2(10, 2) == 12) | |
| end | |
| -- Short functions: vararg functions. | |
| do | |
| local fv1a = |...| -> ... | |
| local a, b = fv1a(1, 2) | |
| assert(a == 1 and b == 2) | |
| local fv1b = |...| -> do return ... end | |
| local c, d = fv1b(1, 2) | |
| assert(c == 1 and d == 2) | |
| local fv3 = |a, b, ...| -> a + b + ... | |
| assert(fv3(1, 2, 8, 100) == 11) | |
| end | |
| -- Short functions: multiple results. | |
| do | |
| local gg = ||->do return 1, 2 end | |
| local a, b = gg() | |
| assert(a == 1 and b == 2) | |
| local ff = ||->gg() | |
| local c, d = ff() | |
| assert(c == 1 and d == 2) | |
| end | |
| -- Short functions: parse single expression. | |
| do | |
| local a, b = x->x, 1 | |
| assert(type(a) == "function" and b == 1) | |
| local c, d = a(2) | |
| assert(c == 2 and d == nil) | |
| local e, f = |x|->x, 1 | |
| assert(f == 1) | |
| local g, h = ||->a, 1 | |
| assert(h == 1) | |
| local t = { 1, x->x+1, 3, f = x->x+2, g = "g", 4 } | |
| assert(t[1] == 1 and t[2](10) == 11 and t[3] == 3) | |
| assert(t.f(10) == 12 and t.g == "g" and t[4] == 4) | |
| end | |
| -- Short functions: syntax errors. | |
| do | |
| expect_err("local f = -> 1", "unexpected.*%->") | |
| expect_err("local f = || 1", "%->.*expected") | |
| expect_err("local f = |x| 1", "%->.*expected") | |
| expect_err("local f = || ->", "eof") | |
| expect_err("local f = |x| ->", "eof") | |
| expect_err("local f = || -> do", "end.*expected") | |
| expect_err("local f = |x| -> do", "end.*expected") | |
| expect_err("local f = || -> ||", "%->.*expected") | |
| expect_err("local f = |x| -> ||", "%->.*expected") | |
| expect_err("local f = || -> |y|", "%->.*expected") | |
| expect_err("local f = |x| -> |y|", "%->.*expected") | |
| expect_err("local f = || -> ->", "unexpected.*%->") | |
| expect_err("local f = |x| -> ->", "unexpected.*%->") | |
| expect_err("local f = a || ->", "unexpected.*%->") | |
| expect_err("local f = a |x| ->", "unexpected.*%->") | |
| expect_err("|| -> 1", "unexpected.*'||'") | |
| expect_err("|.| -> 1", "unexpected.*'|'") | |
| expect_err("x -> x = 1", "expected.*%->") | |
| expect_err("local f = |x+y| -> a", "'|'.*expected") | |
| expect_err("local f = |x=y| -> a", "'|'.*expected") | |
| expect_err("local f = |x:y| -> a", "'|'.*expected") | |
| expect_err("local f = a ? ||->a:b() : c", "arguments.*expected") | |
| end | |
| -- Short functions: closures. | |
| do | |
| local a = 1 | |
| local fc1 = x -> x + a | |
| assert(fc1(10) == 11) | |
| local b = 1 | |
| (x -> do b = x end)(20) | |
| assert(b == 20) | |
| local fc2 | |
| do | |
| local c = 1 | |
| fc2 = x -> x + c | |
| end | |
| collectgarbage() | |
| assert(fc2(10) == 11) | |
| local fc3g, fc3s | |
| do | |
| local d = 1 | |
| fc3g, fc3s = || -> d, x -> do d = x end | |
| end | |
| collectgarbage() | |
| assert(fc3g() == 1) | |
| assert(fc3s(2) == nil) | |
| assert(fc3g() == 2) | |
| local inv = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 } | |
| local t = { 3, 7, 2, 6 } | |
| table.sort(t, |a, b| -> inv[a] < inv[b]) | |
| assert(t[1] == 7 and t[2] == 6 and t[3] == 3 and t[4] == 2) | |
| end | |
| -- Short functions: precedence. | |
| do | |
| local f = x -> y -> x + y | |
| assert(f(10)(1) == 11) | |
| debug.setmetatable(f, { | |
| __pow = |a, b| -> b(a), | |
| __add = |a, b| -> b(a), | |
| }) | |
| local a = 2 ^ x -> x + 3 | |
| assert(a == 5) | |
| local b = 1 + x -> do return x + 3 end + 8 | |
| assert(b == 12) | |
| debug.setmetatable(f, nil) | |
| end | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| local N = setmetatable({}, { __index = function(_, x) return x end }) | |
| -- FFI bit operators: syntax. | |
| do | |
| assert(~ N[0b1010LL] == 0xfffffffffffffff5LL) | |
| assert(~ N[0b1010ULL] == 0xfffffffffffffff5ULL) | |
| assert(N[0x1122334455667788LL] & N[0x5a5a5a5a5a5a5a5aLL] == 0x1002124050425208LL) | |
| assert(N[0x1122334455667788LL] | N[0x5a5a5a5a5a5a5a5aLL] == 0x5b7a7b5e5f7e7fdaLL) | |
| assert(N[0x1122334455667788LL] ~ N[0x5a5a5a5a5a5a5a5aLL] == 0x4b78691e0f3c2dd2LL) | |
| assert(N[0x55aa55aa55aa55aaLL] << N[4] == 0x5aa55aa55aa55aa0LL) | |
| assert(N[0x55aa55aa55aa55aaLL] >> N[4] == 0x055aa55aa55aa55aLL) | |
| assert(N[0x55aa55aa55aa55aaLL] ~>> N[4] == 0x055aa55aa55aa55aLL) | |
| assert(N[0xaa55aa55aa55aa55LL] >> N[4] == 0x0aa55aa55aa55aa5LL) | |
| assert(N[0xaa55aa55aa55aa55LL] ~>> N[4] == 0xfaa55aa55aa55aa5LL) | |
| assert(N[0x55aa55aa55aa55aaLL] << N[36] == 0x5aa55aa000000000LL) | |
| assert(N[0x55aa55aa55aa55aaLL] >> N[36] == 0x00000000055aa55aLL) | |
| assert(N[0x55aa55aa55aa55aaLL] ~>> N[36] == 0x00000000055aa55aLL) | |
| assert(N[0xaa55aa55aa55aa55LL] >> N[36] == 0x000000000aa55aa5LL) | |
| assert(N[0xaa55aa55aa55aa55LL] ~>> N[36] == 0xfffffffffaa55aa5LL) | |
| end | |
| -- FFI bit operators: constant folding. | |
| do | |
| assert(~ 0b1010LL == 0xfffffffffffffff5LL) | |
| assert(~ 0b1010ULL == 0xfffffffffffffff5ULL) | |
| assert(0x1122334455667788LL & 0x5a5a5a5a5a5a5a5aLL == 0x1002124050425208LL) | |
| assert(0x1122334455667788LL | 0x5a5a5a5a5a5a5a5aLL == 0x5b7a7b5e5f7e7fdaLL) | |
| assert(0x1122334455667788LL ~ 0x5a5a5a5a5a5a5a5aLL == 0x4b78691e0f3c2dd2LL) | |
| assert(0x55aa55aa55aa55aaLL << 4 == 0x5aa55aa55aa55aa0LL) | |
| assert(0x55aa55aa55aa55aaLL >> 4 == 0x055aa55aa55aa55aLL) | |
| assert(0x55aa55aa55aa55aaLL ~>> 4 == 0x055aa55aa55aa55aLL) | |
| assert(0xaa55aa55aa55aa55LL >> 4 == 0x0aa55aa55aa55aa5LL) | |
| assert(0xaa55aa55aa55aa55LL ~>> 4 == 0xfaa55aa55aa55aa5LL) | |
| assert(0x55aa55aa55aa55aaLL << 36 == 0x5aa55aa000000000LL) | |
| assert(0x55aa55aa55aa55aaLL >> 36 == 0x00000000055aa55aLL) | |
| assert(0x55aa55aa55aa55aaLL ~>> 36 == 0x00000000055aa55aLL) | |
| assert(0xaa55aa55aa55aa55LL >> 36 == 0x000000000aa55aa5LL) | |
| assert(0xaa55aa55aa55aa55LL ~>> 36 == 0xfffffffffaa55aa5LL) | |
| end | |
| -- FFI bit operators: coercion. | |
| do | |
| assert(N[0xffffffff] | N[0LL] == 0xffffffffLL) | |
| assert(N[0LL] | N[0xffffffff] == 0xffffffffLL) | |
| assert(N[0xffffffff] | N[0ULL] == 0xffffffffULL) | |
| assert(N[0ULL] | N[0xffffffff] == 0xffffffffULL) | |
| assert(N[0x7ffffffffffffc00] | N[0LL] == 0x7ffffffffffffc00LL) | |
| assert(N[-0x8000000000000000] | N[0LL] == 0x8000000000000000LL) | |
| assert(N[0xfffffffffffff800] | N[0ULL] == 0xfffffffffffff800ULL) | |
| assert((N[0x55aa55aa] | N[0LL]) << N[4] == 0x000000055aa55aa0LL) | |
| assert(N[0x55aa55aa] << N[4LL] == 0x5aa55aa0) | |
| assert((N[-1LL] | N[0ULL]) > 0LL) | |
| assert((N[-1LL] << N[4ULL]) < 0LL) | |
| end | |
| -- FFI bit operators: shift width masking. | |
| do | |
| assert(N[0x55aa55aa55aa55aaLL] << N[64] == 0x55aa55aa55aa55aaLL) | |
| assert(N[0x55aa55aa55aa55aaLL] >> N[64] == 0x55aa55aa55aa55aaLL) | |
| assert(N[0x55aa55aa55aa55aaLL] ~>> N[64] == 0x55aa55aa55aa55aaLL) | |
| assert(N[0xaa55aa55aa55aa55LL] ~>> N[64] == 0xaa55aa55aa55aa55LL) | |
| assert(N[0x55aa55aa55aa55aaLL] << N[68] == 0x5aa55aa55aa55aa0LL) | |
| assert(N[0x55aa55aa55aa55aaLL] >> N[68] == 0x055aa55aa55aa55aLL) | |
| assert(N[0x55aa55aa55aa55aaLL] ~>> N[68] == 0x055aa55aa55aa55aLL) | |
| assert(N[0xaa55aa55aa55aa55LL] ~>> N[68] == 0xfaa55aa55aa55aa5LL) | |
| assert(N[0xaa55aa55aa55aa55LL] << N[-1] == 0x8000000000000000LL) | |
| assert(N[0xaa55aa55aa55aa55LL] >> N[-1] == 0x0000000000000001LL) | |
| assert(N[0xaa55aa55aa55aa55LL] ~>> N[-1] == 0xffffffffffffffffLL) | |
| end | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| -- FFI bit operators: JIT logical ops. | |
| do | |
| local a = 0x123456789abcdef0LL | |
| local y1, y2, y3, y4, y5, y6 | |
| for i=1,100 do | |
| y1 = a & 0x000000005a5a5a5aLL | |
| y2 = a & 0x5a5a5a5a00000000LL | |
| y3 = a & 0xffffffff5a5a5a5aLL | |
| y4 = a & 0x5a5a5a5affffffffLL | |
| y5 = a & 0xffffffff00000000LL | |
| y6 = a & 0x00000000ffffffffLL | |
| end | |
| assert(y1 == 0x000000001a185a50LL) | |
| assert(y2 == 0x1210525800000000LL) | |
| assert(y3 == 0x123456781a185a50LL) | |
| assert(y4 == 0x121052589abcdef0LL) | |
| assert(y5 == 0x1234567800000000LL) | |
| assert(y6 == 0x000000009abcdef0LL) | |
| for i=1,100 do | |
| y1 = a | 0x000000005a5a5a5aLL | |
| y2 = a | 0x5a5a5a5a00000000LL | |
| y3 = a | 0xffffffff5a5a5a5aLL | |
| y4 = a | 0x5a5a5a5affffffffLL | |
| y5 = a | 0xffffffff00000000LL | |
| y6 = a | 0x00000000ffffffffLL | |
| end | |
| assert(y1 == 0x12345678dafedefaLL) | |
| assert(y2 == 0x5a7e5e7a9abcdef0LL) | |
| assert(y3 == 0xffffffffdafedefaLL) | |
| assert(y4 == 0x5a7e5e7affffffffLL) | |
| assert(y5 == 0xffffffff9abcdef0LL) | |
| assert(y6 == 0x12345678ffffffffLL) | |
| for i=1,100 do | |
| y1 = a ~ 0x000000005a5a5a5aLL | |
| y2 = a ~ 0x5a5a5a5a00000000LL | |
| y3 = a ~ 0xffffffff5a5a5a5aLL | |
| y4 = a ~ 0x5a5a5a5affffffffLL | |
| y5 = a ~ 0xffffffff00000000LL | |
| y6 = a ~ 0x00000000ffffffffLL | |
| end | |
| assert(y1 == 0x12345678c0e684aaLL) | |
| assert(y2 == 0x486e0c229abcdef0LL) | |
| assert(y3 == 0xedcba987c0e684aaLL) | |
| assert(y4 == 0x486e0c226543210fLL) | |
| assert(y5 == 0xedcba9879abcdef0LL) | |
| assert(y6 == 0x123456786543210fLL) | |
| end | |
| -- FFI bit operators: JIT shift and logical ops. | |
| do | |
| local a, b = 0x123456789abcdef0LL, 0x31415926535898LL | |
| for i=1,200 do | |
| a = a ~ b; b = (b ~>> 14) + (b << 50) | |
| a = a - b; b = (b << 5) + (b ~>> 59) | |
| b = a ~ b; b = b - (b << 13) - (b >> 51) | |
| end | |
| assert(b == -7993764627526027113LL) | |
| end | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| -- Adapted from bit operations library tests. | |
| local xbit = { | |
| bnot = function(a) return ~a end, | |
| band = function(a, b) return a & b end, | |
| bor = function(a, b) return a | b end, | |
| bxor = function(a, b) return a ~ b end, | |
| lshift = function(a, b) return a << b end, | |
| rshift = function(a, b) return a >> b end, | |
| arshift = function(a, b) return a ~>> b end, | |
| } | |
| local vb = { | |
| 0LL, 1LL, -1LL, 2LL, -2LL, | |
| 0x123456789abcdef0LL, 0x0fedcba987654321LL, | |
| 0x33333333LL, 0x77777777LL, 0x55aa55aaLL, 0xaa55aa55LL, | |
| 0x7fffffffLL, 0x80000000LL, 0xffffffffLL, | |
| 0x3333333333333333LL, 0x7777777777777777LL, | |
| 0x55aa55aa55aa55aaLL, 0xaa55aa55aa55aa55LL, | |
| 0x7fffffffffffffffLL, 0x8000000000000000LL, 0xffffffffffffffffLL, | |
| } | |
| local function cksum(name, s, r) | |
| local z = 0 | |
| for i=1,#s do z = (z + string.byte(s, i)*i) % 2147483629 end | |
| if z ~= r then | |
| error("bit."..name.." test failed (got "..z..", expected "..r..")", 0) | |
| end | |
| end | |
| local function check_unop(name, r) | |
| local f = xbit[name] | |
| local s = "" | |
| if pcall(f) or pcall(f, "z") or pcall(f, true) then | |
| error("bit."..name.." fails to detect argument errors", 0) | |
| end | |
| for _,x in ipairs(vb) do s = s..","..tostring(f(x)) end | |
| cksum(name, s, r) | |
| end | |
| local function check_binop(name, r) | |
| local f = xbit[name] | |
| local s = "" | |
| if pcall(f) or pcall(f, "z") or pcall(f, true) then | |
| error("bit."..name.." fails to detect argument errors", 0) | |
| end | |
| for _,x in ipairs(vb) do | |
| for _,y in ipairs(vb) do s = s..","..tostring(f(x, y)) end | |
| end | |
| cksum(name, s, r) | |
| end | |
| local function check_binop_range(name, r, yb, ye) | |
| local f = xbit[name] | |
| local s = "" | |
| if pcall(f) or pcall(f, "z") or pcall(f, true) or pcall(f, 1, true) then | |
| error("bit."..name.." fails to detect argument errors", 0) | |
| end | |
| for _,x in ipairs(vb) do | |
| for y=yb,ye do s = s..","..tostring(f(x, y)) end | |
| end | |
| cksum(name, s, r) | |
| end | |
| local function check_shift(name, r) | |
| check_binop_range(name, r, 0, 31) | |
| end | |
| -- FFI bit operators: computed value. | |
| do | |
| check_unop("bnot", 2562401) | |
| check_binop("band", 691178007) | |
| check_binop("bor", 1218205008) | |
| check_binop("bxor", 1616063830) | |
| check_shift("lshift", 722026261) | |
| check_shift("rshift", 1938929707) | |
| check_shift("arshift", 1443445799) | |
| end | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| -- Numbers with underscores: parser. | |
| do | |
| assert(1_234 == 1234) | |
| assert(1_ == 1) | |
| assert(0_ == 0) | |
| assert(0_1 == 1) | |
| assert(1_2_3__4__ == 1234) | |
| assert(0x1_2 == 18) | |
| assert(0__x__1__2__ == 18) | |
| assert(0__b__1__0__ == 2) | |
| end | |
| -- Numbers with underscores: rejected by tonumber. | |
| do | |
| assert(not tonumber("1_2")) | |
| assert(not tonumber("0_x2")) | |
| assert(not tonumber("0x_2")) | |
| assert(not tonumber("0x2_")) | |
| end | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| local function expect_err(code, expect) | |
| local f, err = loadstring(code, "=") | |
| if f ~= nil then | |
| error("unexpected success", 2) | |
| elseif not err:match(expect) then | |
| error('expected "'..expect..'", but got "'..err:gsub("^:1: ", "")..'"', 2) | |
| end | |
| end | |
| NUMBER1 = 1 | |
| NUMBER2 = 2 | |
| NUMBER3 = 3 | |
| STRX = "x" | |
| STRY = "y" | |
| collectgarbage() -- Prevent (simple) global store-to-load forwarding. | |
| -- Compound assignment: syntax. | |
| do | |
| do local a = NUMBER3; a += NUMBER2; assert(a == 5) end | |
| do local a = NUMBER3; a -= NUMBER2; assert(a == 1) end | |
| do local a = NUMBER3; a *= NUMBER2; assert(a == 6) end | |
| do local a = NUMBER3; a /= NUMBER2; assert(a == 1.5) end | |
| do local a = NUMBER3; a %= NUMBER2; assert(a == 1) end | |
| do local a = NUMBER3; a &= NUMBER2; assert(a == 2) end | |
| do local a = NUMBER1; a |= NUMBER2; assert(a == 3) end | |
| do local a = NUMBER3; a ~= NUMBER2; assert(a == 1) end | |
| do local a = NUMBER3; a <<= NUMBER2; assert(a == 12) end | |
| do local a = NUMBER3; a >>= NUMBER1; assert(a == 1) end | |
| do local a = NUMBER3; a ~>>= NUMBER1; assert(a == 1) end | |
| do local a = -NUMBER3; a ~>>= NUMBER1; assert(a == -2) end | |
| do local a = STRX; a ..= STRY; assert(a == "xy") end | |
| do local t = { x = NUMBER2 }; t.x += NUMBER3; assert(t.x == 5) end | |
| do local t = { NUMBER2 }; t[1] += NUMBER3; assert(t[1] == 5) end | |
| end | |
| -- Compound assignment: constant folding. | |
| do | |
| do local a = 3; a += 2; assert(a == 5) end | |
| do local a = 3; a -= 2; assert(a == 1) end | |
| do local a = 3; a *= 2; assert(a == 6) end | |
| do local a = 3; a /= 2; assert(a == 1.5) end | |
| do local a = 3; a %= 2; assert(a == 1) end | |
| do local a = 3; a &= 2; assert(a == 2) end | |
| do local a = 1; a |= 2; assert(a == 3) end | |
| do local a = 3; a ~= 2; assert(a == 1) end | |
| do local a = 3; a <<= 2; assert(a == 12) end | |
| do local a = 3; a >>= 1; assert(a == 1) end | |
| do local a = 3; a ~>>= 1; assert(a == 1) end | |
| do local a = -3; a ~>>= 1; assert(a == -2) end | |
| do local a = "x"; a ..= "y"; assert(a == "xy") end | |
| end | |
| -- Compound assignment: indexing metamethods. | |
| do | |
| local mt = { | |
| __index = function(t, k) t.get += 1; return rawget(t, "_"..k) end, | |
| __newindex = function(t, k, v) t.set += 1; rawset(t, "_"..k, v) end, | |
| } | |
| local function proxy() | |
| return setmetatable({ get = 0, set = 0, }, mt) | |
| end | |
| do | |
| local t = proxy() | |
| t.x = NUMBER2 | |
| assert(t.get == 0 and t.set == 1) | |
| t.x += NUMBER3 | |
| assert(t.get == 1 and t.set == 2) | |
| assert(t.x == 5) | |
| assert(t.get == 2 and t.set == 2) | |
| end | |
| do | |
| local t = proxy() | |
| rawset(t, "x", NUMBER2) | |
| assert(t.get == 0 and t.set == 0) | |
| t.x += NUMBER3 | |
| assert(t.get == 0 and t.set == 0) | |
| assert(t.x == 5) | |
| end | |
| end | |
| -- Compound assignment: extra metamethod argument. | |
| if jit and jit.version_num >= 30000 then -- NOT backported to v2.1. | |
| local mt = { __add = function(a, b, c) b.c = c; return a.x + b.x end } | |
| local function adder(x) | |
| return setmetatable({ c = "BAD", x = x }, mt) | |
| end | |
| do | |
| local a = adder(NUMBER2) | |
| local b = adder(NUMBER3) | |
| local y = a + b | |
| assert(y == 5 and b.c == nil) | |
| end | |
| do | |
| local a = adder(NUMBER2) | |
| local b = adder(NUMBER3) | |
| a += b | |
| assert(a == 5 and b.c == true) | |
| end | |
| end | |
| -- Compound assignment: syntax error. | |
| do | |
| expect_err("x + = 1", "near.*%+") | |
| expect_err("+=", "near.*%+") | |
| expect_err("x +=", "near.*eof") | |
| expect_err("+= 1", "near.*%+") | |
| expect_err("(x) += 1", "near.*%+") | |
| expect_err("f() += 1", "near.*%+") | |
| expect_err("x, y += 1", "near.*%+") -- No parallel assignment. | |
| expect_err("x, y += 1, 2", "near.*%+") -- No parallel assignment. | |
| expect_err("x ^= 1", "near.*^") -- No power compound assignment. | |
| end | |
| NUMBER1 = nil | |
| NUMBER2 = nil | |
| NUMBER3 = nil | |
| STRX = nil | |
| STRY = nil | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| local function expect_err(code, expect) | |
| local f, err = loadstring(code, "=") | |
| if f ~= nil then | |
| error("unexpected success", 2) | |
| elseif not err:match(expect) then | |
| error('expected "'..expect..'", but got "'..err:gsub("^:1: ", "")..'"', 2) | |
| end | |
| end | |
| -- const: declaration. | |
| do | |
| const x = 1 | |
| assert(x == 1) | |
| const y, z = 2, 3 | |
| assert(y == 2 and z == 3) | |
| local function f() const u = 2; return x + u end | |
| local u = 10 | |
| assert(f() == 3) | |
| end | |
| -- const: lexical scoping. | |
| do | |
| do const x = 1 end | |
| const x = 2 | |
| do const y = 3 end | |
| local y = 4 | |
| assert(x == 2 and y == 4) | |
| end | |
| -- const: re-assignment error. | |
| do | |
| expect_err("const x = 1; x = 1", "assign to const") | |
| expect_err("const x = 1; x += 1", "assign to const") | |
| expect_err("const x, y = 1, 2; y = 2", "assign to const") | |
| expect_err("const x = 1; function x() end", "assign to const") | |
| expect_err("const x = 1; local function f() x = 1 end", "assign to const") | |
| expect_err("const x = 1; local function f() return function() return function() x = 1 end end end", "assign to const") | |
| -- Check line number of error. | |
| expect_err("const x = 1\na,\nx,\ny = 1, 2, 3\nreturn", ":3:") | |
| expect_err("const x = 1\nfunction x()\nend\nreturn", ":2:") | |
| end | |
| -- const: local re-declaration error. | |
| do | |
| expect_err("const x = 1; const x = 1", "declare const") | |
| expect_err("const x = 1; local x = 1", "declare const") | |
| expect_err("const x = 1; local y, x = 1, 1", "declare const") | |
| expect_err("const x, x = 1, 1", "declare const") | |
| expect_err("const x = 1; local function x() end", "declare const") | |
| expect_err("const x = 1; for x=1,100 do end", "declare const") | |
| expect_err("const x = 1; for x in pairs(_G) do end", "declare const") | |
| end | |
| -- const: upvalue re-declaration error. | |
| do | |
| expect_err("const x = 1; local function f() const x = 1 end", "declare const") | |
| expect_err("const x = 1; local function f() local x = 1 end", "declare const") | |
| expect_err("const x = 1; local function f() return function() return function() const x = 1 end end end", "declare const") | |
| end | |
| -- const: parameter re-declaration error. | |
| do | |
| expect_err("const x = 1; local function f(x) end", "declare const") | |
| expect_err("const x = 1; local f = |x| -> x", "declare const") | |
| end | |
| -- const: soft keyword. | |
| do | |
| do | |
| local const = 1 | |
| assert(const == 1) | |
| const = 2 | |
| assert(const == 2) | |
| const = const | |
| assert(const == 2) | |
| end | |
| do | |
| const const = 1 | |
| assert(const == 1) | |
| end | |
| do | |
| local x = 1 | |
| goto const | |
| x = 2 | |
| ::const:: | |
| assert(x == 1) | |
| end | |
| do | |
| local t = { const = 1 } | |
| assert(t.const == 1) | |
| end | |
| do | |
| local function const() return 1 end | |
| assert(const() == 1) | |
| end | |
| do | |
| local function f(const) return const + 1 end | |
| assert(f(1) == 2) | |
| end | |
| do | |
| local f = const -> const + 1 | |
| assert(f(1) == 2) | |
| assert((const -> const + 1)(1) == 2) | |
| end | |
| end | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| local function expect_err(code, expect) | |
| local f, err = loadstring(code, "=") | |
| if f ~= nil then | |
| error("unexpected success", 2) | |
| elseif not err:match(expect) then | |
| error('expected "'..expect..'", but got "'..err:gsub("^:1: ", "")..'"', 2) | |
| end | |
| end | |
| -- continue: while loop. | |
| do | |
| local sum = 0 | |
| local i = 0 | |
| while i < 100 do | |
| i = i + 1 | |
| if (i & 4) == 0 then continue end | |
| if i >= 70 and i <= 80 then continue end | |
| if i == 95 then break end | |
| sum = sum + i | |
| end | |
| assert(sum == 1830) | |
| end | |
| -- continue: repeat loop. | |
| do | |
| local sum = 0 | |
| local i = 0 | |
| repeat | |
| i = i + 1 | |
| if (i & 4) == 0 then continue end | |
| if i >= 70 and i <= 80 then continue end | |
| if i == 95 then break end | |
| sum = sum + i | |
| until i >= 100 | |
| assert(sum == 1830) | |
| end | |
| -- continue: numeric for loop. | |
| do | |
| local sum = 0 | |
| for i=1,100 do | |
| if (i & 4) == 0 then continue end | |
| if i >= 70 and i <= 80 then continue end | |
| if i == 95 then break end | |
| sum = sum + i | |
| end | |
| assert(sum == 1830) | |
| end | |
| -- continue: generic for loop. | |
| do | |
| local t = {} | |
| for i=1,100 do t[i] = i end | |
| local sum = 0 | |
| for _,i in ipairs(t) do | |
| if (i & 4) == 0 then continue end | |
| if i >= 70 and i <= 80 then continue end | |
| if i == 95 then break end | |
| sum = sum + i | |
| end | |
| assert(sum == 1830) | |
| end | |
| -- continue: nested continue. | |
| do | |
| local sum = 0 | |
| for j=1,10 do | |
| if j == 8 then continue end | |
| for i=1,100 do | |
| if (i & 4) == 0 then continue end | |
| if i >= 70 and i <= 80 then continue end | |
| if i == 95 then break end | |
| sum = sum + i | |
| end | |
| end | |
| assert(sum == 1830*9) | |
| end | |
| -- continue: closures. | |
| do | |
| local t = {} | |
| for i=1,100 do | |
| t[i] = function() return i+2 end | |
| if i >= 70 then | |
| continue | |
| end | |
| end | |
| for i=1,100 do | |
| assert(t[i]() == i+2) | |
| end | |
| local u = {} | |
| local j = 0 | |
| repeat | |
| j = j + 1 | |
| local k = j | |
| if j >= 70 then | |
| continue | |
| end | |
| until (function() u[j] = function() return k+2 end; return k >= 100 end)() | |
| for i=1,100 do | |
| assert(u[i]() == i+2) | |
| end | |
| end | |
| -- continue: syntax errors and semantic errors. | |
| do | |
| expect_err("continue", "loop.*continue") | |
| expect_err("do continue end", "loop.*continue") | |
| expect_err("function f() continue end", "loop.*continue") | |
| expect_err("repeat continue; x = 1 until false", "expected") | |
| expect_err("repeat if x then continue end; local a = a; until not a", "continue.*scope.*'a'") | |
| expect_err("repeat if x then continue end; local a = a; if y then continue end until not a", "continue.*scope.*'a'") | |
| expect_err("repeat if true then local a; continue end; local a = a; until not a", "continue.*scope.*'a'") | |
| end | |
| -- continue: soft keyword. | |
| do | |
| do | |
| local continue = 1 | |
| assert(continue == 1) | |
| continue = 2 | |
| assert(continue == 2) | |
| continue = continue | |
| assert(continue == 2) | |
| end | |
| do | |
| const continue = 1 | |
| assert(continue == 1) | |
| end | |
| do | |
| local x = 1 | |
| goto continue | |
| x = 2 | |
| ::continue:: | |
| assert(x == 1) | |
| end | |
| do | |
| local t = { continue = 1 } | |
| assert(t.continue == 1) | |
| end | |
| do | |
| local function continue() return 1 end | |
| assert(continue() == 1) | |
| end | |
| do | |
| local function f(continue) return continue + 1 end | |
| assert(f(1) == 2) | |
| end | |
| do | |
| local f = continue -> continue + 1 | |
| assert(f(1) == 2) | |
| assert((continue -> continue + 1)(1) == 2) | |
| end | |
| end | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| local function expect_err(code, expect) | |
| local f, err = loadstring(code, "=") | |
| if f ~= nil then | |
| error("unexpected success", 2) | |
| elseif not err:match(expect) then | |
| error('expected "'..expect..'", but got "'..err:gsub("^:1: ", "")..'"', 2) | |
| end | |
| end | |
| local N = setmetatable({}, { __index = function(_, x) return x end }) | |
| -- Floor division: syntax. | |
| do | |
| assert((N[6] // N[2]) == 3) | |
| assert((N[7] // N[2]) == 3) | |
| assert((N[-7] // N[2]) == -4) | |
| end | |
| -- Floor division: constant folding. | |
| do | |
| assert((6 // 2) == 3) | |
| assert((7 // 2) == 3) | |
| assert((-7 // 2) == -4) | |
| end | |
| -- Floor division: compound assignment. | |
| do | |
| local a = N[7] | |
| a //= N[2] | |
| assert(a == 3) | |
| end | |
| -- Floor division: precedence. | |
| do | |
| assert((N[2] + N[7] // N[3] + N[1]) == 5) | |
| assert((N[2] * N[7] // N[3] * N[1]) == 4) | |
| assert((N[2] ^ N[7] // N[3] ^ N[1]) == 42) | |
| end | |
| -- Floor division: associativity. | |
| do | |
| assert((N[9] // N[3] // N[2]) == 1) | |
| assert(((N[9] // N[3]) // N[2]) == 1) | |
| assert((N[9] // (N[3] // N[2])) == 9) | |
| end | |
| -- Floor division: metamethod. | |
| do | |
| local mt = { __idiv = function() return "idiv" end } | |
| local a = setmetatable({}, mt) | |
| local b = setmetatable({}, mt) | |
| assert(a // 1 == "idiv" and 1 // a == "idiv" and a // b == "idiv") | |
| end | |
| -- Floor division: syntax errors. | |
| do | |
| expect_err("//", "near.*//") | |
| expect_err("a //", "near.*//") | |
| expect_err("a // b", "near.*//") | |
| expect_err("local y //", "near.*//") | |
| expect_err("local y = //", "near.*//") | |
| expect_err("local y = a //", "near.*eof") | |
| expect_err("local y = a // //", "near.*//") | |
| end | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| local N = setmetatable({}, { __index = function(_, x) return x end }) | |
| -- FFI floor division: syntax. | |
| do | |
| assert((N[6LL] // N[2LL]) == 3) | |
| assert((N[7LL] // N[2LL]) == 3) | |
| assert((N[-7LL] // N[2LL]) == -4) | |
| assert((N[6ULL] // N[2ULL]) == 3) | |
| assert((N[7ULL] // N[2ULL]) == 3) | |
| end | |
| -- FFI floor division: constant folding. | |
| do | |
| assert((6LL // 2LL) == 3) | |
| assert((7LL // 2LL) == 3) | |
| assert((-7LL // 2LL) == -4) | |
| assert((6ULL // 2ULL) == 3) | |
| assert((7ULL // 2ULL) == 3) | |
| end | |
| -- FFI floor division: compound assignment. | |
| do | |
| local a = N[7LL] | |
| a //= N[2LL] | |
| assert(a == 3) | |
| end | |
| -- FFI floor division: coercion. | |
| do | |
| assert((N[0x1ffffffffLL] // N[2]) % 1 == 0) | |
| assert((N[0x1ffffffff] // N[2LL]) % 1 == 0) | |
| end | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment