lua

A copy of the Lua development repository
Log | Files | Refs | README

errors.lua (21209B)


      1 -- $Id: testes/errors.lua $
      2 -- See Copyright Notice in file all.lua
      3 
      4 print("testing errors")
      5 
      6 local debug = require"debug"
      7 
      8 -- avoid problems with 'strict' module (which may generate other error messages)
      9 local mt = getmetatable(_G) or {}
     10 local oldmm = mt.__index
     11 mt.__index = nil
     12 
     13 local function checkerr (msg, f, ...)
     14   local st, err = pcall(f, ...)
     15   assert(not st and string.find(err, msg))
     16 end
     17 
     18 
     19 local function doit (s)
     20   local f, msg = load(s)
     21   if not f then return msg end
     22   local cond, msg = pcall(f)
     23   return (not cond) and msg
     24 end
     25 
     26 
     27 local function checkmessage (prog, msg, debug)
     28   local m = doit(prog)
     29   if debug then print(m, msg) end
     30   assert(string.find(m, msg, 1, true))
     31 end
     32 
     33 local function checksyntax (prog, extra, token, line)
     34   local msg = doit(prog)
     35   if not string.find(token, "^<%a") and not string.find(token, "^char%(")
     36     then token = "'"..token.."'" end
     37   token = string.gsub(token, "(%p)", "%%%1")
     38   local pt = string.format([[^%%[string ".*"%%]:%d: .- near %s$]],
     39                            line, token)
     40   assert(string.find(msg, pt))
     41   assert(string.find(msg, msg, 1, true))
     42 end
     43 
     44 
     45 -- test error message with no extra info
     46 assert(doit("error('hi', 0)") == 'hi')
     47 
     48 -- test nil error message
     49 assert(doit("error()") == "<error object is nil>")
     50 
     51 
     52 -- test common errors/errors that crashed in the past
     53 assert(doit("table.unpack({}, 1, n=2^30)"))
     54 assert(doit("a=math.sin()"))
     55 assert(not doit("tostring(1)") and doit("tostring()"))
     56 assert(doit"tonumber()")
     57 assert(doit"repeat until 1; a")
     58 assert(doit"return;;")
     59 assert(doit"assert(false)")
     60 assert(doit"assert(nil)")
     61 assert(doit("function a (... , ...) end"))
     62 assert(doit("function a (, ...) end"))
     63 assert(doit("local t={}; t = t[#t] + 1"))
     64 
     65 checksyntax([[
     66   local a = {4
     67 
     68 ]], "'}' expected (to close '{' at line 1)", "<eof>", 3)
     69 
     70 
     71 do   -- testing errors in goto/break
     72   local function checksyntax (prog, msg, line)
     73     local st, err = load(prog)
     74     assert(string.find(err, "line " .. line))
     75     assert(string.find(err, msg, 1, true))
     76   end
     77 
     78   checksyntax([[
     79     ::A:: a = 1
     80     ::A::
     81   ]], "label 'A' already defined", 1)
     82 
     83   checksyntax([[
     84     a = 1
     85     goto A
     86     do ::A:: end
     87   ]], "no visible label 'A'", 2)
     88 
     89 end
     90 
     91 
     92 if not T then
     93   (Message or print)
     94     ('\n >>> testC not active: skipping tests for messages in C <<<\n')
     95 else
     96   print "testing memory error message"
     97   local a = {}
     98   for i = 1, 10000 do a[i] = true end   -- preallocate array
     99   collectgarbage()
    100   T.totalmem(T.totalmem() + 10000)
    101   -- force a memory error (by a small margin)
    102   local st, msg = pcall(function()
    103     for i = 1, 100000 do a[i] = tostring(i) end
    104   end)
    105   T.totalmem(0)
    106   assert(not st and msg == "not enough" .. " memory")
    107 
    108   -- stack space for luaL_traceback (bug in 5.4.6)
    109   local res = T.testC[[
    110     # push 16 elements on the stack
    111     pushnum 1; pushnum 1; pushnum 1; pushnum 1; pushnum 1;
    112     pushnum 1; pushnum 1; pushnum 1; pushnum 1; pushnum 1;
    113     pushnum 1; pushnum 1; pushnum 1; pushnum 1; pushnum 1;
    114     pushnum 1;
    115     # traceback should work with 4 remaining slots
    116     traceback xuxu 1;
    117     return 1
    118   ]]
    119   assert(string.find(res, "xuxu.-main chunk"))
    120 
    121   do   -- tests for error messages about extra arguments from __call
    122     local function createobj (n)
    123       -- function that raises an error on its n-th argument
    124       local code = string.format("argerror %d 'msg'", n)
    125       local func = T.makeCfunc(code)
    126       -- create a chain of 2 __call objects
    127       local M = setmetatable({}, {__call = func})
    128       M = setmetatable({}, {__call = M})
    129       -- put it as a method for a new object
    130       return {foo = M}
    131     end
    132 
    133   _G.a = createobj(1)   -- error in first (extra) argument
    134   checkmessage("a:foo()", "bad extra argument #1")
    135 
    136   _G.a = createobj(2)   -- error in second (extra) argument
    137   checkmessage("a:foo()", "bad extra argument #2")
    138 
    139   _G.a = createobj(3)   -- error in self (after two extra arguments)
    140   checkmessage("a:foo()", "bad self")
    141 
    142   _G.a = createobj(4)  -- error in first regular argument (after self)
    143   checkmessage("a:foo()", "bad argument #1")
    144   end
    145 end
    146 
    147 
    148 -- tests for better error messages
    149 
    150 checkmessage("a = {} + 1", "arithmetic")
    151 checkmessage("a = {} | 1", "bitwise operation")
    152 checkmessage("a = {} < 1", "attempt to compare")
    153 checkmessage("a = {} <= 1", "attempt to compare")
    154 
    155 checkmessage("aaa=1; bbbb=2; aaa=math.sin(3)+bbbb(3)", "global 'bbbb'")
    156 checkmessage("aaa={}; do local aaa=1 end aaa:bbbb(3)", "method 'bbbb'")
    157 checkmessage("local a={}; a.bbbb(3)", "field 'bbbb'")
    158 assert(not string.find(doit"aaa={13}; local bbbb=1; aaa[bbbb](3)", "'bbbb'"))
    159 checkmessage("aaa={13}; local bbbb=1; aaa[bbbb](3)", "number")
    160 checkmessage("aaa=(1)..{}", "a table value")
    161 
    162 -- bug in 5.4.6
    163 checkmessage("a = {_ENV = {}}; print(a._ENV.x + 1)", "field 'x'")
    164 
    165 _G.aaa, _G.bbbb = nil
    166 
    167 -- calls
    168 checkmessage("local a; a(13)", "local 'a'")
    169 checkmessage([[
    170   local a = setmetatable({}, {__add = 34})
    171   a = a + 1
    172 ]], "metamethod 'add'")
    173 checkmessage([[
    174   local a = setmetatable({}, {__lt = {}})
    175   a = a > a
    176 ]], "metamethod 'lt'")
    177 
    178 -- tail calls
    179 checkmessage("local a={}; return a.bbbb(3)", "field 'bbbb'")
    180 checkmessage("aaa={}; do local aaa=1 end; return aaa:bbbb(3)", "method 'bbbb'")
    181 
    182 checkmessage("aaa = #print", "length of a function value")
    183 checkmessage("aaa = #3", "length of a number value")
    184 
    185 _G.aaa = nil
    186 
    187 checkmessage("aaa.bbb:ddd(9)", "global 'aaa'")
    188 checkmessage("local aaa={bbb=1}; aaa.bbb:ddd(9)", "field 'bbb'")
    189 checkmessage("local aaa={bbb={}}; aaa.bbb:ddd(9)", "method 'ddd'")
    190 checkmessage("local a,b,c; (function () a = b+1.1 end)()", "upvalue 'b'")
    191 assert(not doit"local aaa={bbb={ddd=next}}; aaa.bbb:ddd(nil)")
    192 
    193 -- upvalues being indexed do not go to the stack
    194 checkmessage("local a,b,cc; (function () a = cc[1] end)()", "upvalue 'cc'")
    195 checkmessage("local a,b,cc; (function () a.x = 1 end)()", "upvalue 'a'")
    196 
    197 checkmessage("local _ENV = {x={}}; a = a + 1", "global 'a'")
    198 
    199 checkmessage("BB=1; local aaa={}; x=aaa+BB", "local 'aaa'")
    200 checkmessage("aaa={}; x=3.3/aaa", "global 'aaa'")
    201 checkmessage("aaa=2; BB=nil;x=aaa*BB", "global 'BB'")
    202 checkmessage("aaa={}; x=-aaa", "global 'aaa'")
    203 
    204 -- short circuit
    205 checkmessage("aaa=1; local aaa,bbbb=2,3; aaa = math.sin(1) and bbbb(3)",
    206        "local 'bbbb'")
    207 checkmessage("aaa=1; local aaa,bbbb=2,3; aaa = bbbb(1) or aaa(3)",
    208              "local 'bbbb'")
    209 checkmessage("local a,b,c,f = 1,1,1; f((a and b) or c)", "local 'f'")
    210 checkmessage("local a,b,c = 1,1,1; ((a and b) or c)()", "call a number value")
    211 assert(not string.find(doit"aaa={}; x=(aaa or aaa)+(aaa and aaa)", "'aaa'"))
    212 assert(not string.find(doit"aaa={}; (aaa or aaa)()", "'aaa'"))
    213 
    214 checkmessage("print(print < 10)", "function with number")
    215 checkmessage("print(print < print)", "two function values")
    216 checkmessage("print('10' < 10)", "string with number")
    217 checkmessage("print(10 < '23')", "number with string")
    218 
    219 -- float->integer conversions
    220 checkmessage("local a = 2.0^100; x = a << 2", "local a")
    221 checkmessage("local a = 1 >> 2.0^100", "has no integer representation")
    222 checkmessage("local a = 10.1 << 2.0^100", "has no integer representation")
    223 checkmessage("local a = 2.0^100 & 1", "has no integer representation")
    224 checkmessage("local a = 2.0^100 & 1e100", "has no integer representation")
    225 checkmessage("local a = 2.0 | 1e40", "has no integer representation")
    226 checkmessage("local a = 2e100 ~ 1", "has no integer representation")
    227 checkmessage("string.sub('a', 2.0^100)", "has no integer representation")
    228 checkmessage("string.rep('a', 3.3)", "has no integer representation")
    229 checkmessage("return 6e40 & 7", "has no integer representation")
    230 checkmessage("return 34 << 7e30", "has no integer representation")
    231 checkmessage("return ~-3e40", "has no integer representation")
    232 checkmessage("return ~-3.009", "has no integer representation")
    233 checkmessage("return 3.009 & 1", "has no integer representation")
    234 checkmessage("return 34 >> {}", "table value")
    235 checkmessage("aaa = 24 // 0", "divide by zero")
    236 checkmessage("aaa = 1 % 0", "'n%0'")
    237 
    238 
    239 -- type error for an object which is neither in an upvalue nor a register.
    240 -- The following code will try to index the value 10 that is stored in
    241 -- the metatable, without moving it to a register.
    242 checkmessage("local a = setmetatable({}, {__index = 10}).x",
    243              "attempt to index a number value")
    244 
    245 
    246 -- numeric for loops
    247 checkmessage("for i = {}, 10 do end", "table")
    248 checkmessage("for i = io.stdin, 10 do end", "FILE")
    249 checkmessage("for i = {}, 10 do end", "initial value")
    250 checkmessage("for i = 1, 'x', 10 do end", "string")
    251 checkmessage("for i = 1, {}, 10 do end", "limit")
    252 checkmessage("for i = 1, {} do end", "limit")
    253 checkmessage("for i = 1, 10, print do end", "step")
    254 checkmessage("for i = 1, 10, print do end", "function")
    255 
    256 -- passing light userdata instead of full userdata
    257 _G.D = debug
    258 checkmessage([[
    259   -- create light udata
    260   local x = D.upvalueid(function () return debug end, 1)
    261   D.setuservalue(x, {})
    262 ]], "light userdata")
    263 _G.D = nil
    264 
    265 do   -- named objects (field '__name')
    266   checkmessage("math.sin(io.input())", "(number expected, got FILE*)")
    267   _G.XX = setmetatable({}, {__name = "My Type"})
    268   assert(string.find(tostring(XX), "^My Type"))
    269   checkmessage("io.input(XX)", "(FILE* expected, got My Type)")
    270   checkmessage("return XX + 1", "on a My Type value")
    271   checkmessage("return ~io.stdin", "on a FILE* value")
    272   checkmessage("return XX < XX", "two My Type values")
    273   checkmessage("return {} < XX", "table with My Type")
    274   checkmessage("return XX < io.stdin", "My Type with FILE*")
    275   _G.XX = nil
    276 
    277   if T then   -- extra tests for 'luaL_tolstring'
    278     -- bug in 5.4.3; 'luaL_tolstring' with negative indices
    279     local x = setmetatable({}, {__name="TABLE"})
    280     assert(T.testC("Ltolstring -1; return 1", x) == tostring(x))
    281 
    282     local a, b = T.testC("pushint 10; Ltolstring -2; return 2", x)
    283     assert(a == 10 and b == tostring(x))
    284 
    285     setmetatable(x, {__tostring=function (o)
    286       assert(o == x)
    287       return "ABC"
    288     end})
    289     local a, b, c = T.testC("pushint 10; Ltolstring -2; return 3", x)
    290     assert(a == x and b == 10 and c == "ABC")
    291   end
    292 end
    293 
    294 -- global functions
    295 checkmessage("(io.write or print){}", "io.write")
    296 checkmessage("(collectgarbage or print){}", "collectgarbage")
    297 
    298 -- errors in functions without debug info
    299 do
    300   local f = function (a) return a + 1 end
    301   f = assert(load(string.dump(f, true)))
    302   assert(f(3) == 4)
    303   checkerr("^%?:%-1:", f, {})
    304 
    305   -- code with a move to a local var ('OP_MOV A B' with A<B)
    306   f = function () local a; a = {}; return a + 2 end
    307   -- no debug info (so that 'a' is unknown)
    308   f = assert(load(string.dump(f, true)))
    309   -- symbolic execution should not get lost
    310   checkerr("^%?:%-1:.*table value", f)
    311 end
    312 
    313 
    314 -- tests for field accesses after RK limit
    315 local t = {}
    316 for i = 1, 1000 do
    317   t[i] = "aaa = x" .. i
    318 end
    319 local s = table.concat(t, "; ")
    320 t = nil
    321 checkmessage(s.."; aaa = bbb + 1", "global 'bbb'")
    322 checkmessage("local _ENV=_ENV;"..s.."; aaa = bbb + 1", "global 'bbb'")
    323 checkmessage(s.."; local t = {}; aaa = t.bbb + 1", "field 'bbb'")
    324 -- cannot use 'self' opcode
    325 checkmessage(s.."; local t = {}; t:bbb()", "field 'bbb'")
    326 
    327 checkmessage([[aaa=9
    328 repeat until 3==3
    329 local x=math.sin(math.cos(3))
    330 if math.sin(1) == x then return math.sin(1) end   -- tail call
    331 local a,b = 1, {
    332   {x='a'..'b'..'c', y='b', z=x},
    333   {1,2,3,4,5} or 3+3<=3+3,
    334   3+1>3+1,
    335   {d = x and aaa[x or y]}}
    336 ]], "global 'aaa'")
    337 
    338 checkmessage([[
    339 local x,y = {},1
    340 if math.sin(1) == 0 then return 3 end    -- return
    341 x.a()]], "field 'a'")
    342 
    343 checkmessage([[
    344 prefix = nil
    345 insert = nil
    346 while 1 do
    347   local a
    348   if nil then break end
    349   insert(prefix, a)
    350 end]], "global 'insert'")
    351 
    352 checkmessage([[  -- tail call
    353   return math.sin("a")
    354 ]], "sin")
    355 
    356 checkmessage([[collectgarbage("nooption")]], "invalid option")
    357 
    358 checkmessage([[x = print .. "a"]], "concatenate")
    359 checkmessage([[x = "a" .. false]], "concatenate")
    360 checkmessage([[x = {} .. 2]], "concatenate")
    361 
    362 checkmessage("getmetatable(io.stdin).__gc()", "no value")
    363 
    364 checkmessage([[
    365 local Var
    366 local function main()
    367   NoSuchName (function() Var=0 end)
    368 end
    369 main()
    370 ]], "global 'NoSuchName'")
    371 print'+'
    372 
    373 aaa = {}; setmetatable(aaa, {__index = string})
    374 checkmessage("aaa:sub()", "bad self")
    375 checkmessage("string.sub('a', {})", "#2")
    376 checkmessage("('a'):sub{}", "#1")
    377 
    378 checkmessage("table.sort({1,2,3}, table.sort)", "'table.sort'")
    379 checkmessage("string.gsub('s', 's', setmetatable)", "'setmetatable'")
    380 
    381 _G.aaa = nil
    382 
    383 
    384 -- tests for errors in coroutines
    385 
    386 local function f (n)
    387   local c = coroutine.create(f)
    388   local a,b = coroutine.resume(c)
    389   return b
    390 end
    391 assert(string.find(f(), "C stack overflow"))
    392 
    393 checkmessage("coroutine.yield()", "outside a coroutine")
    394 
    395 f = coroutine.wrap(function () table.sort({1,2,3}, coroutine.yield) end)
    396 checkerr("yield across", f)
    397 
    398 
    399 -- testing size of 'source' info; size of buffer for that info is
    400 -- LUA_IDSIZE, declared as 60 in luaconf. Get one position for '\0'.
    401 local idsize = 60 - 1
    402 local function checksize (source)
    403   -- syntax error
    404   local _, msg = load("x", source)
    405   msg = string.match(msg, "^([^:]*):")   -- get source (1st part before ':')
    406   assert(msg:len() <= idsize)
    407 end
    408 
    409 for i = 60 - 10, 60 + 10 do   -- check border cases around 60
    410   checksize("@" .. string.rep("x", i))   -- file names
    411   checksize(string.rep("x", i - 10))     -- string sources
    412   checksize("=" .. string.rep("x", i))   -- exact sources
    413 end
    414 
    415 
    416 -- testing line error
    417 
    418 local function lineerror (s, l)
    419   local err,msg = pcall(load(s))
    420   local line = tonumber(string.match(msg, ":(%d+):"))
    421   assert(line == l or (not line and not l))
    422 end
    423 
    424 lineerror("local a\n for i=1,'a' do \n print(i) \n end", 2)
    425 lineerror("\n local a \n for k,v in 3 \n do \n print(k) \n end", 3)
    426 lineerror("\n\n for k,v in \n 3 \n do \n print(k) \n end", 4)
    427 lineerror("function a.x.y ()\na=a+1\nend", 1)
    428 
    429 lineerror("a = \na\n+\n{}", 3)
    430 lineerror("a = \n3\n+\n(\n4\n/\nprint)", 6)
    431 lineerror("a = \nprint\n+\n(\n4\n/\n7)", 3)
    432 
    433 lineerror("a\n=\n-\n\nprint\n;", 3)
    434 
    435 lineerror([[
    436 a
    437 (     -- <<
    438 23)
    439 ]], 2)
    440 
    441 lineerror([[
    442 local a = {x = 13}
    443 a
    444 .
    445 x
    446 (     -- <<
    447 23
    448 )
    449 ]], 5)
    450 
    451 lineerror([[
    452 local a = {x = 13}
    453 a
    454 .
    455 x
    456 (
    457 23 + a
    458 )
    459 ]], 6)
    460 
    461 local p = [[
    462   function g() f() end
    463   function f(x) error('a', XX) end
    464 g()
    465 ]]
    466 XX=3;lineerror((p), 3)
    467 XX=0;lineerror((p), false)
    468 XX=1;lineerror((p), 2)
    469 XX=2;lineerror((p), 1)
    470 _G.XX, _G.g, _G.f = nil
    471 
    472 
    473 lineerror([[
    474 local b = false
    475 if not b then
    476   error 'test'
    477 end]], 3)
    478 
    479 lineerror([[
    480 local b = false
    481 if not b then
    482   if not b then
    483     if not b then
    484       error 'test'
    485     end
    486   end
    487 end]], 5)
    488 
    489 
    490 -- bug in 5.4.0
    491 lineerror([[
    492   local a = 0
    493   local b = 1
    494   local c = b % a
    495 ]], 3)
    496 
    497 do
    498   -- Force a negative estimate for base line. Error in instruction 2
    499   -- (after VARARGPREP, GETGLOBAL), with first absolute line information
    500   -- (forced by too many lines) in instruction 0.
    501   local s = string.format("%s return __A.x", string.rep("\n", 300))
    502   lineerror(s, 301)
    503 end
    504 
    505 
    506 if not _soft then
    507   -- several tests that exaust the Lua stack
    508   collectgarbage()
    509   print"testing stack overflow"
    510   local C = 0
    511   -- get line where stack overflow will happen
    512   local l = debug.getinfo(1, "l").currentline + 1
    513   local function auxy () C=C+1; auxy() end     -- produce a stack overflow
    514   function YY ()
    515     collectgarbage("stop")   -- avoid running finalizers without stack space
    516     auxy()
    517     collectgarbage("restart")
    518   end
    519 
    520   local function checkstackmessage (m)
    521     print("(expected stack overflow after " .. C .. " calls)")
    522     C = 0    -- prepare next count
    523     return (string.find(m, "stack overflow"))
    524   end
    525   -- repeated stack overflows (to check stack recovery)
    526   assert(checkstackmessage(doit('YY()')))
    527   assert(checkstackmessage(doit('YY()')))
    528   assert(checkstackmessage(doit('YY()')))
    529 
    530   _G.YY = nil
    531 
    532 
    533   -- error lines in stack overflow
    534   local l1
    535   local function g(x)
    536     l1 = debug.getinfo(x, "l").currentline + 2
    537     collectgarbage("stop")   -- avoid running finalizers without stack space
    538     auxy()
    539     collectgarbage("restart")
    540   end
    541   local _, stackmsg = xpcall(g, debug.traceback, 1)
    542   print('+')
    543   local stack = {}
    544   for line in string.gmatch(stackmsg, "[^\n]*") do
    545     local curr = string.match(line, ":(%d+):")
    546     if curr then table.insert(stack, tonumber(curr)) end
    547   end
    548   local i=1
    549   while stack[i] ~= l1 do
    550     assert(stack[i] == l)
    551     i = i+1
    552   end
    553   assert(i > 15)
    554 
    555 
    556   -- error in error handling
    557   local res, msg = xpcall(error, error)
    558   assert(not res and msg == 'error in error handling')
    559   print('+')
    560 
    561   local function f (x)
    562     if x==0 then error('a\n')
    563     else
    564       local aux = function () return f(x-1) end
    565       local a,b = xpcall(aux, aux)
    566       return a,b
    567     end
    568   end
    569   f(3)
    570 
    571   local function loop (x,y,z) return 1 + loop(x, y, z) end
    572  
    573   local res, msg = xpcall(loop, function (m)
    574     assert(string.find(m, "stack overflow"))
    575     checkerr("error handling", loop)
    576     assert(math.sin(0) == 0)
    577     return 15
    578   end)
    579   assert(msg == 15)
    580 
    581   local f = function ()
    582     for i = 999900, 1000000, 1 do table.unpack({}, 1, i) end
    583   end
    584   checkerr("too many results", f)
    585 
    586 end
    587 
    588 
    589 do  -- errors in error handle that not necessarily go forever
    590   local function err (n)   -- function to be used as message handler
    591     -- generate an error unless n is zero, so that there is a limited
    592     -- loop of errors
    593     if type(n) ~= "number" then   -- some other error?
    594       return n   -- report it
    595     elseif n == 0 then
    596       return "END"   -- that will be the final message
    597     else error(n - 1)   -- does the loop
    598     end
    599   end
    600 
    601   local res, msg = xpcall(error, err, 170)
    602   assert(not res and msg == "END")
    603 
    604   -- too many levels
    605   local res, msg = xpcall(error, err, 300)
    606   assert(not res and msg == "C stack overflow")
    607 end
    608 
    609 
    610 do
    611   -- non string messages
    612   local t = {}
    613   local res, msg = pcall(function () error(t) end)
    614   assert(not res and msg == t)
    615 
    616   res, msg = pcall(function () error(nil) end)
    617   assert(not res and msg == "<error object is nil>")
    618 
    619   local function f() error{msg='x'} end
    620   res, msg = xpcall(f, function (r) return {msg=r.msg..'y'} end)
    621   assert(msg.msg == 'xy')
    622 
    623   -- 'assert' with extra arguments
    624   res, msg = pcall(assert, false, "X", t)
    625   assert(not res and msg == "X")
    626  
    627   -- 'assert' with no message
    628   res, msg = pcall(function () assert(false) end)
    629   local line = string.match(msg, "%w+%.lua:(%d+): assertion failed!$")
    630   assert(tonumber(line) == debug.getinfo(1, "l").currentline - 2)
    631 
    632   -- 'assert' with non-string messages
    633   res, msg = pcall(assert, false, t)
    634   assert(not res and msg == t)
    635 
    636   res, msg = pcall(assert, nil, nil)
    637   assert(not res and type(msg) == "string")
    638 
    639   -- 'assert' without arguments
    640   res, msg = pcall(assert)
    641   assert(not res and string.find(msg, "value expected"))
    642 end
    643 
    644 -- xpcall with arguments
    645 local a, b, c = xpcall(string.find, error, "alo", "al")
    646 assert(a and b == 1 and c == 2)
    647 a, b, c = xpcall(string.find, function (x) return {} end, true, "al")
    648 assert(not a and type(b) == "table" and c == nil)
    649 
    650 
    651 print("testing tokens in error messages")
    652 checksyntax("syntax error", "", "error", 1)
    653 checksyntax("1.000", "", "1.000", 1)
    654 checksyntax("[[a]]", "", "[[a]]", 1)
    655 checksyntax("'aa'", "", "'aa'", 1)
    656 checksyntax("while << do end", "", "<<", 1)
    657 checksyntax("for >> do end", "", ">>", 1)
    658 
    659 -- test invalid non-printable char in a chunk
    660 checksyntax("a\1a = 1", "", "<\\1>", 1)
    661 
    662 -- test 255 as first char in a chunk
    663 checksyntax("\255a = 1", "", "<\\255>", 1)
    664 
    665 doit('I = load("a=9+"); aaa=3')
    666 assert(_G.aaa==3 and not _G.I)
    667 _G.I,_G.aaa = nil
    668 print('+')
    669 
    670 local lim = 1000
    671 if _soft then lim = 100 end
    672 for i=1,lim do
    673   doit('a = ')
    674   doit('a = 4+nil')
    675 end
    676 
    677 
    678 -- testing syntax limits
    679 
    680 local function testrep (init, rep, close, repc, finalresult)
    681   local s = init .. string.rep(rep, 100) .. close .. string.rep(repc, 100)
    682   local res, msg = load(s)
    683   assert(res)   -- 100 levels is OK
    684   if (finalresult) then
    685     assert(res() == finalresult)
    686   end
    687   s = init .. string.rep(rep, 500)
    688   local res, msg = load(s)   -- 500 levels not ok
    689   assert(not res and (string.find(msg, "too many") or
    690                       string.find(msg, "overflow")))
    691 end
    692 
    693 testrep("local a; a", ",a", "= 1", ",1")    -- multiple assignment
    694 testrep("local a; a=", "{", "0", "}")
    695 testrep("return ", "(", "2", ")", 2)
    696 testrep("local function a (x) return x end; return ", "a(", "2.2", ")", 2.2)
    697 testrep("", "do ", "", " end")
    698 testrep("", "while a do ", "", " end")
    699 testrep("local a; ", "if a then else ", "", " end")
    700 testrep("", "function foo () ", "", " end")
    701 testrep("local a = ''; return ", "a..", "'a'", "", "a")
    702 testrep("local a = 1; return ", "a^", "a", "", 1)
    703 
    704 checkmessage("a = f(x" .. string.rep(",x", 260) .. ")", "too many registers")
    705 
    706 
    707 -- testing other limits
    708 
    709 -- upvalues
    710 local lim = 127
    711 local  s = "local function fooA ()\n  local "
    712 for j = 1,lim do
    713   s = s.."a"..j..", "
    714 end
    715 s = s.."b,c\n"
    716 s = s.."local function fooB ()\n  local "
    717 for j = 1,lim do
    718   s = s.."b"..j..", "
    719 end
    720 s = s.."b\n"
    721 s = s.."function fooC () return b+c"
    722 local c = 1+2
    723 for j = 1,lim do
    724   s = s.."+a"..j.."+b"..j
    725   c = c + 2
    726 end
    727 s = s.."\nend  end end"
    728 local a,b = load(s)
    729 assert(c > 255 and string.find(b, "too many upvalues") and
    730        string.find(b, "line 5"))
    731 
    732 -- local variables
    733 s = "\nfunction foo ()\n  local "
    734 for j = 1,300 do
    735   s = s.."a"..j..", "
    736 end
    737 s = s.."b\n"
    738 local a,b = load(s)
    739 assert(string.find(b, "line 2") and string.find(b, "too many local variables"))
    740 
    741 mt.__index = oldmm
    742 
    743 print('OK')