diff options
Diffstat (limited to '')
| -rw-r--r-- | testes/errors.lua | 537 |
1 files changed, 537 insertions, 0 deletions
diff --git a/testes/errors.lua b/testes/errors.lua new file mode 100644 index 00000000..79d746c7 --- /dev/null +++ b/testes/errors.lua | |||
| @@ -0,0 +1,537 @@ | |||
| 1 | -- $Id: errors.lua,v 1.94 2016/12/21 19:23:02 roberto Exp $ | ||
| 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 f == nil 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) | ||
| 28 | local m = doit(prog) | ||
| 29 | assert(string.find(m, msg, 1, true)) | ||
| 30 | end | ||
| 31 | |||
| 32 | local function checksyntax (prog, extra, token, line) | ||
| 33 | local msg = doit(prog) | ||
| 34 | if not string.find(token, "^<%a") and not string.find(token, "^char%(") | ||
| 35 | then token = "'"..token.."'" end | ||
| 36 | token = string.gsub(token, "(%p)", "%%%1") | ||
| 37 | local pt = string.format([[^%%[string ".*"%%]:%d: .- near %s$]], | ||
| 38 | line, token) | ||
| 39 | assert(string.find(msg, pt)) | ||
| 40 | assert(string.find(msg, msg, 1, true)) | ||
| 41 | end | ||
| 42 | |||
| 43 | |||
| 44 | -- test error message with no extra info | ||
| 45 | assert(doit("error('hi', 0)") == 'hi') | ||
| 46 | |||
| 47 | -- test error message with no info | ||
| 48 | assert(doit("error()") == nil) | ||
| 49 | |||
| 50 | |||
| 51 | -- test common errors/errors that crashed in the past | ||
| 52 | assert(doit("table.unpack({}, 1, n=2^30)")) | ||
| 53 | assert(doit("a=math.sin()")) | ||
| 54 | assert(not doit("tostring(1)") and doit("tostring()")) | ||
| 55 | assert(doit"tonumber()") | ||
| 56 | assert(doit"repeat until 1; a") | ||
| 57 | assert(doit"return;;") | ||
| 58 | assert(doit"assert(false)") | ||
| 59 | assert(doit"assert(nil)") | ||
| 60 | assert(doit("function a (... , ...) end")) | ||
| 61 | assert(doit("function a (, ...) end")) | ||
| 62 | assert(doit("local t={}; t = t[#t] + 1")) | ||
| 63 | |||
| 64 | checksyntax([[ | ||
| 65 | local a = {4 | ||
| 66 | |||
| 67 | ]], "'}' expected (to close '{' at line 1)", "<eof>", 3) | ||
| 68 | |||
| 69 | |||
| 70 | -- tests for better error messages | ||
| 71 | |||
| 72 | checkmessage("a = {} + 1", "arithmetic") | ||
| 73 | checkmessage("a = {} | 1", "bitwise operation") | ||
| 74 | checkmessage("a = {} < 1", "attempt to compare") | ||
| 75 | checkmessage("a = {} <= 1", "attempt to compare") | ||
| 76 | |||
| 77 | checkmessage("a=1; bbbb=2; a=math.sin(3)+bbbb(3)", "global 'bbbb'") | ||
| 78 | checkmessage("a={}; do local a=1 end a:bbbb(3)", "method 'bbbb'") | ||
| 79 | checkmessage("local a={}; a.bbbb(3)", "field 'bbbb'") | ||
| 80 | assert(not string.find(doit"a={13}; local bbbb=1; a[bbbb](3)", "'bbbb'")) | ||
| 81 | checkmessage("a={13}; local bbbb=1; a[bbbb](3)", "number") | ||
| 82 | checkmessage("a=(1)..{}", "a table value") | ||
| 83 | |||
| 84 | checkmessage("a = #print", "length of a function value") | ||
| 85 | checkmessage("a = #3", "length of a number value") | ||
| 86 | |||
| 87 | aaa = nil | ||
| 88 | checkmessage("aaa.bbb:ddd(9)", "global 'aaa'") | ||
| 89 | checkmessage("local aaa={bbb=1}; aaa.bbb:ddd(9)", "field 'bbb'") | ||
| 90 | checkmessage("local aaa={bbb={}}; aaa.bbb:ddd(9)", "method 'ddd'") | ||
| 91 | checkmessage("local a,b,c; (function () a = b+1 end)()", "upvalue 'b'") | ||
| 92 | assert(not doit"local aaa={bbb={ddd=next}}; aaa.bbb:ddd(nil)") | ||
| 93 | |||
| 94 | -- upvalues being indexed do not go to the stack | ||
| 95 | checkmessage("local a,b,cc; (function () a = cc[1] end)()", "upvalue 'cc'") | ||
| 96 | checkmessage("local a,b,cc; (function () a.x = 1 end)()", "upvalue 'a'") | ||
| 97 | |||
| 98 | checkmessage("local _ENV = {x={}}; a = a + 1", "global 'a'") | ||
| 99 | |||
| 100 | checkmessage("b=1; local aaa='a'; x=aaa+b", "local 'aaa'") | ||
| 101 | checkmessage("aaa={}; x=3/aaa", "global 'aaa'") | ||
| 102 | checkmessage("aaa='2'; b=nil;x=aaa*b", "global 'b'") | ||
| 103 | checkmessage("aaa={}; x=-aaa", "global 'aaa'") | ||
| 104 | |||
| 105 | -- short circuit | ||
| 106 | checkmessage("a=1; local a,bbbb=2,3; a = math.sin(1) and bbbb(3)", | ||
| 107 | "local 'bbbb'") | ||
| 108 | checkmessage("a=1; local a,bbbb=2,3; a = bbbb(1) or a(3)", "local 'bbbb'") | ||
| 109 | checkmessage("local a,b,c,f = 1,1,1; f((a and b) or c)", "local 'f'") | ||
| 110 | checkmessage("local a,b,c = 1,1,1; ((a and b) or c)()", "call a number value") | ||
| 111 | assert(not string.find(doit"aaa={}; x=(aaa or aaa)+(aaa and aaa)", "'aaa'")) | ||
| 112 | assert(not string.find(doit"aaa={}; (aaa or aaa)()", "'aaa'")) | ||
| 113 | |||
| 114 | checkmessage("print(print < 10)", "function with number") | ||
| 115 | checkmessage("print(print < print)", "two function values") | ||
| 116 | checkmessage("print('10' < 10)", "string with number") | ||
| 117 | checkmessage("print(10 < '23')", "number with string") | ||
| 118 | |||
| 119 | -- float->integer conversions | ||
| 120 | checkmessage("local a = 2.0^100; x = a << 2", "local a") | ||
| 121 | checkmessage("local a = 1 >> 2.0^100", "has no integer representation") | ||
| 122 | checkmessage("local a = '10' << 2.0^100", "has no integer representation") | ||
| 123 | checkmessage("local a = 2.0^100 & 1", "has no integer representation") | ||
| 124 | checkmessage("local a = 2.0^100 & '1'", "has no integer representation") | ||
| 125 | checkmessage("local a = 2.0 | 1e40", "has no integer representation") | ||
| 126 | checkmessage("local a = 2e100 ~ 1", "has no integer representation") | ||
| 127 | checkmessage("string.sub('a', 2.0^100)", "has no integer representation") | ||
| 128 | checkmessage("string.rep('a', 3.3)", "has no integer representation") | ||
| 129 | checkmessage("return 6e40 & 7", "has no integer representation") | ||
| 130 | checkmessage("return 34 << 7e30", "has no integer representation") | ||
| 131 | checkmessage("return ~-3e40", "has no integer representation") | ||
| 132 | checkmessage("return ~-3.009", "has no integer representation") | ||
| 133 | checkmessage("return 3.009 & 1", "has no integer representation") | ||
| 134 | checkmessage("return 34 >> {}", "table value") | ||
| 135 | checkmessage("a = 24 // 0", "divide by zero") | ||
| 136 | checkmessage("a = 1 % 0", "'n%0'") | ||
| 137 | |||
| 138 | |||
| 139 | -- passing light userdata instead of full userdata | ||
| 140 | _G.D = debug | ||
| 141 | checkmessage([[ | ||
| 142 | -- create light udata | ||
| 143 | local x = D.upvalueid(function () return debug end, 1) | ||
| 144 | D.setuservalue(x, {}) | ||
| 145 | ]], "light userdata") | ||
| 146 | _G.D = nil | ||
| 147 | |||
| 148 | do -- named objects (field '__name') | ||
| 149 | checkmessage("math.sin(io.input())", "(number expected, got FILE*)") | ||
| 150 | _G.XX = setmetatable({}, {__name = "My Type"}) | ||
| 151 | assert(string.find(tostring(XX), "^My Type")) | ||
| 152 | checkmessage("io.input(XX)", "(FILE* expected, got My Type)") | ||
| 153 | checkmessage("return XX + 1", "on a My Type value") | ||
| 154 | checkmessage("return ~io.stdin", "on a FILE* value") | ||
| 155 | checkmessage("return XX < XX", "two My Type values") | ||
| 156 | checkmessage("return {} < XX", "table with My Type") | ||
| 157 | checkmessage("return XX < io.stdin", "My Type with FILE*") | ||
| 158 | _G.XX = nil | ||
| 159 | end | ||
| 160 | |||
| 161 | -- global functions | ||
| 162 | checkmessage("(io.write or print){}", "io.write") | ||
| 163 | checkmessage("(collectgarbage or print){}", "collectgarbage") | ||
| 164 | |||
| 165 | -- errors in functions without debug info | ||
| 166 | do | ||
| 167 | local f = function (a) return a + 1 end | ||
| 168 | f = assert(load(string.dump(f, true))) | ||
| 169 | assert(f(3) == 4) | ||
| 170 | checkerr("^%?:%-1:", f, {}) | ||
| 171 | |||
| 172 | -- code with a move to a local var ('OP_MOV A B' with A<B) | ||
| 173 | f = function () local a; a = {}; return a + 2 end | ||
| 174 | -- no debug info (so that 'a' is unknown) | ||
| 175 | f = assert(load(string.dump(f, true))) | ||
| 176 | -- symbolic execution should not get lost | ||
| 177 | checkerr("^%?:%-1:.*table value", f) | ||
| 178 | end | ||
| 179 | |||
| 180 | |||
| 181 | -- tests for field accesses after RK limit | ||
| 182 | local t = {} | ||
| 183 | for i = 1, 1000 do | ||
| 184 | t[i] = "a = x" .. i | ||
| 185 | end | ||
| 186 | local s = table.concat(t, "; ") | ||
| 187 | t = nil | ||
| 188 | checkmessage(s.."; a = bbb + 1", "global 'bbb'") | ||
| 189 | checkmessage("local _ENV=_ENV;"..s.."; a = bbb + 1", "global 'bbb'") | ||
| 190 | checkmessage(s.."; local t = {}; a = t.bbb + 1", "field 'bbb'") | ||
| 191 | checkmessage(s.."; local t = {}; t:bbb()", "method 'bbb'") | ||
| 192 | |||
| 193 | checkmessage([[aaa=9 | ||
| 194 | repeat until 3==3 | ||
| 195 | local x=math.sin(math.cos(3)) | ||
| 196 | if math.sin(1) == x then return math.sin(1) end -- tail call | ||
| 197 | local a,b = 1, { | ||
| 198 | {x='a'..'b'..'c', y='b', z=x}, | ||
| 199 | {1,2,3,4,5} or 3+3<=3+3, | ||
| 200 | 3+1>3+1, | ||
| 201 | {d = x and aaa[x or y]}} | ||
| 202 | ]], "global 'aaa'") | ||
| 203 | |||
| 204 | checkmessage([[ | ||
| 205 | local x,y = {},1 | ||
| 206 | if math.sin(1) == 0 then return 3 end -- return | ||
| 207 | x.a()]], "field 'a'") | ||
| 208 | |||
| 209 | checkmessage([[ | ||
| 210 | prefix = nil | ||
| 211 | insert = nil | ||
| 212 | while 1 do | ||
| 213 | local a | ||
| 214 | if nil then break end | ||
| 215 | insert(prefix, a) | ||
| 216 | end]], "global 'insert'") | ||
| 217 | |||
| 218 | checkmessage([[ -- tail call | ||
| 219 | return math.sin("a") | ||
| 220 | ]], "'sin'") | ||
| 221 | |||
| 222 | checkmessage([[collectgarbage("nooption")]], "invalid option") | ||
| 223 | |||
| 224 | checkmessage([[x = print .. "a"]], "concatenate") | ||
| 225 | checkmessage([[x = "a" .. false]], "concatenate") | ||
| 226 | checkmessage([[x = {} .. 2]], "concatenate") | ||
| 227 | |||
| 228 | checkmessage("getmetatable(io.stdin).__gc()", "no value") | ||
| 229 | |||
| 230 | checkmessage([[ | ||
| 231 | local Var | ||
| 232 | local function main() | ||
| 233 | NoSuchName (function() Var=0 end) | ||
| 234 | end | ||
| 235 | main() | ||
| 236 | ]], "global 'NoSuchName'") | ||
| 237 | print'+' | ||
| 238 | |||
| 239 | a = {}; setmetatable(a, {__index = string}) | ||
| 240 | checkmessage("a:sub()", "bad self") | ||
| 241 | checkmessage("string.sub('a', {})", "#2") | ||
| 242 | checkmessage("('a'):sub{}", "#1") | ||
| 243 | |||
| 244 | checkmessage("table.sort({1,2,3}, table.sort)", "'table.sort'") | ||
| 245 | checkmessage("string.gsub('s', 's', setmetatable)", "'setmetatable'") | ||
| 246 | |||
| 247 | -- tests for errors in coroutines | ||
| 248 | |||
| 249 | local function f (n) | ||
| 250 | local c = coroutine.create(f) | ||
| 251 | local a,b = coroutine.resume(c) | ||
| 252 | return b | ||
| 253 | end | ||
| 254 | assert(string.find(f(), "C stack overflow")) | ||
| 255 | |||
| 256 | checkmessage("coroutine.yield()", "outside a coroutine") | ||
| 257 | |||
| 258 | f = coroutine.wrap(function () table.sort({1,2,3}, coroutine.yield) end) | ||
| 259 | checkerr("yield across", f) | ||
| 260 | |||
| 261 | |||
| 262 | -- testing size of 'source' info; size of buffer for that info is | ||
| 263 | -- LUA_IDSIZE, declared as 60 in luaconf. Get one position for '\0'. | ||
| 264 | idsize = 60 - 1 | ||
| 265 | local function checksize (source) | ||
| 266 | -- syntax error | ||
| 267 | local _, msg = load("x", source) | ||
| 268 | msg = string.match(msg, "^([^:]*):") -- get source (1st part before ':') | ||
| 269 | assert(msg:len() <= idsize) | ||
| 270 | end | ||
| 271 | |||
| 272 | for i = 60 - 10, 60 + 10 do -- check border cases around 60 | ||
| 273 | checksize("@" .. string.rep("x", i)) -- file names | ||
| 274 | checksize(string.rep("x", i - 10)) -- string sources | ||
| 275 | checksize("=" .. string.rep("x", i)) -- exact sources | ||
| 276 | end | ||
| 277 | |||
| 278 | |||
| 279 | -- testing line error | ||
| 280 | |||
| 281 | local function lineerror (s, l) | ||
| 282 | local err,msg = pcall(load(s)) | ||
| 283 | local line = string.match(msg, ":(%d+):") | ||
| 284 | assert((line and line+0) == l) | ||
| 285 | end | ||
| 286 | |||
| 287 | lineerror("local a\n for i=1,'a' do \n print(i) \n end", 2) | ||
| 288 | lineerror("\n local a \n for k,v in 3 \n do \n print(k) \n end", 3) | ||
| 289 | lineerror("\n\n for k,v in \n 3 \n do \n print(k) \n end", 4) | ||
| 290 | lineerror("function a.x.y ()\na=a+1\nend", 1) | ||
| 291 | |||
| 292 | lineerror("a = \na\n+\n{}", 3) | ||
| 293 | lineerror("a = \n3\n+\n(\n4\n/\nprint)", 6) | ||
| 294 | lineerror("a = \nprint\n+\n(\n4\n/\n7)", 3) | ||
| 295 | |||
| 296 | lineerror("a\n=\n-\n\nprint\n;", 3) | ||
| 297 | |||
| 298 | lineerror([[ | ||
| 299 | a | ||
| 300 | ( | ||
| 301 | 23) | ||
| 302 | ]], 1) | ||
| 303 | |||
| 304 | lineerror([[ | ||
| 305 | local a = {x = 13} | ||
| 306 | a | ||
| 307 | . | ||
| 308 | x | ||
| 309 | ( | ||
| 310 | 23 | ||
| 311 | ) | ||
| 312 | ]], 2) | ||
| 313 | |||
| 314 | lineerror([[ | ||
| 315 | local a = {x = 13} | ||
| 316 | a | ||
| 317 | . | ||
| 318 | x | ||
| 319 | ( | ||
| 320 | 23 + a | ||
| 321 | ) | ||
| 322 | ]], 6) | ||
| 323 | |||
| 324 | local p = [[ | ||
| 325 | function g() f() end | ||
| 326 | function f(x) error('a', X) end | ||
| 327 | g() | ||
| 328 | ]] | ||
| 329 | X=3;lineerror((p), 3) | ||
| 330 | X=0;lineerror((p), nil) | ||
| 331 | X=1;lineerror((p), 2) | ||
| 332 | X=2;lineerror((p), 1) | ||
| 333 | |||
| 334 | |||
| 335 | if not _soft then | ||
| 336 | -- several tests that exaust the Lua stack | ||
| 337 | collectgarbage() | ||
| 338 | print"testing stack overflow" | ||
| 339 | C = 0 | ||
| 340 | local l = debug.getinfo(1, "l").currentline; function y () C=C+1; y() end | ||
| 341 | |||
| 342 | local function checkstackmessage (m) | ||
| 343 | return (string.find(m, "^.-:%d+: stack overflow")) | ||
| 344 | end | ||
| 345 | -- repeated stack overflows (to check stack recovery) | ||
| 346 | assert(checkstackmessage(doit('y()'))) | ||
| 347 | print('+') | ||
| 348 | assert(checkstackmessage(doit('y()'))) | ||
| 349 | print('+') | ||
| 350 | assert(checkstackmessage(doit('y()'))) | ||
| 351 | print('+') | ||
| 352 | |||
| 353 | |||
| 354 | -- error lines in stack overflow | ||
| 355 | C = 0 | ||
| 356 | local l1 | ||
| 357 | local function g(x) | ||
| 358 | l1 = debug.getinfo(x, "l").currentline; y() | ||
| 359 | end | ||
| 360 | local _, stackmsg = xpcall(g, debug.traceback, 1) | ||
| 361 | print('+') | ||
| 362 | local stack = {} | ||
| 363 | for line in string.gmatch(stackmsg, "[^\n]*") do | ||
| 364 | local curr = string.match(line, ":(%d+):") | ||
| 365 | if curr then table.insert(stack, tonumber(curr)) end | ||
| 366 | end | ||
| 367 | local i=1 | ||
| 368 | while stack[i] ~= l1 do | ||
| 369 | assert(stack[i] == l) | ||
| 370 | i = i+1 | ||
| 371 | end | ||
| 372 | assert(i > 15) | ||
| 373 | |||
| 374 | |||
| 375 | -- error in error handling | ||
| 376 | local res, msg = xpcall(error, error) | ||
| 377 | assert(not res and type(msg) == 'string') | ||
| 378 | print('+') | ||
| 379 | |||
| 380 | local function f (x) | ||
| 381 | if x==0 then error('a\n') | ||
| 382 | else | ||
| 383 | local aux = function () return f(x-1) end | ||
| 384 | local a,b = xpcall(aux, aux) | ||
| 385 | return a,b | ||
| 386 | end | ||
| 387 | end | ||
| 388 | f(3) | ||
| 389 | |||
| 390 | local function loop (x,y,z) return 1 + loop(x, y, z) end | ||
| 391 | |||
| 392 | local res, msg = xpcall(loop, function (m) | ||
| 393 | assert(string.find(m, "stack overflow")) | ||
| 394 | checkerr("error handling", loop) | ||
| 395 | assert(math.sin(0) == 0) | ||
| 396 | return 15 | ||
| 397 | end) | ||
| 398 | assert(msg == 15) | ||
| 399 | |||
| 400 | local f = function () | ||
| 401 | for i = 999900, 1000000, 1 do table.unpack({}, 1, i) end | ||
| 402 | end | ||
| 403 | checkerr("too many results", f) | ||
| 404 | |||
| 405 | end | ||
| 406 | |||
| 407 | |||
| 408 | do | ||
| 409 | -- non string messages | ||
| 410 | local t = {} | ||
| 411 | local res, msg = pcall(function () error(t) end) | ||
| 412 | assert(not res and msg == t) | ||
| 413 | |||
| 414 | res, msg = pcall(function () error(nil) end) | ||
| 415 | assert(not res and msg == nil) | ||
| 416 | |||
| 417 | local function f() error{msg='x'} end | ||
| 418 | res, msg = xpcall(f, function (r) return {msg=r.msg..'y'} end) | ||
| 419 | assert(msg.msg == 'xy') | ||
| 420 | |||
| 421 | -- 'assert' with extra arguments | ||
| 422 | res, msg = pcall(assert, false, "X", t) | ||
| 423 | assert(not res and msg == "X") | ||
| 424 | |||
| 425 | -- 'assert' with no message | ||
| 426 | res, msg = pcall(function () assert(false) end) | ||
| 427 | local line = string.match(msg, "%w+%.lua:(%d+): assertion failed!$") | ||
| 428 | assert(tonumber(line) == debug.getinfo(1, "l").currentline - 2) | ||
| 429 | |||
| 430 | -- 'assert' with non-string messages | ||
| 431 | res, msg = pcall(assert, false, t) | ||
| 432 | assert(not res and msg == t) | ||
| 433 | |||
| 434 | res, msg = pcall(assert, nil, nil) | ||
| 435 | assert(not res and msg == nil) | ||
| 436 | |||
| 437 | -- 'assert' without arguments | ||
| 438 | res, msg = pcall(assert) | ||
| 439 | assert(not res and string.find(msg, "value expected")) | ||
| 440 | end | ||
| 441 | |||
| 442 | -- xpcall with arguments | ||
| 443 | a, b, c = xpcall(string.find, error, "alo", "al") | ||
| 444 | assert(a and b == 1 and c == 2) | ||
| 445 | a, b, c = xpcall(string.find, function (x) return {} end, true, "al") | ||
| 446 | assert(not a and type(b) == "table" and c == nil) | ||
| 447 | |||
| 448 | |||
| 449 | print("testing tokens in error messages") | ||
| 450 | checksyntax("syntax error", "", "error", 1) | ||
| 451 | checksyntax("1.000", "", "1.000", 1) | ||
| 452 | checksyntax("[[a]]", "", "[[a]]", 1) | ||
| 453 | checksyntax("'aa'", "", "'aa'", 1) | ||
| 454 | checksyntax("while << do end", "", "<<", 1) | ||
| 455 | checksyntax("for >> do end", "", ">>", 1) | ||
| 456 | |||
| 457 | -- test invalid non-printable char in a chunk | ||
| 458 | checksyntax("a\1a = 1", "", "<\\1>", 1) | ||
| 459 | |||
| 460 | -- test 255 as first char in a chunk | ||
| 461 | checksyntax("\255a = 1", "", "<\\255>", 1) | ||
| 462 | |||
| 463 | doit('I = load("a=9+"); a=3') | ||
| 464 | assert(a==3 and I == nil) | ||
| 465 | print('+') | ||
| 466 | |||
| 467 | lim = 1000 | ||
| 468 | if _soft then lim = 100 end | ||
| 469 | for i=1,lim do | ||
| 470 | doit('a = ') | ||
| 471 | doit('a = 4+nil') | ||
| 472 | end | ||
| 473 | |||
| 474 | |||
| 475 | -- testing syntax limits | ||
| 476 | |||
| 477 | local maxClevel = 200 -- LUAI_MAXCCALLS (in llimits.h) | ||
| 478 | |||
| 479 | local function testrep (init, rep, close, repc) | ||
| 480 | local s = init .. string.rep(rep, maxClevel - 10) .. close .. | ||
| 481 | string.rep(repc, maxClevel - 10) | ||
| 482 | assert(load(s)) -- 190 levels is OK | ||
| 483 | s = init .. string.rep(rep, maxClevel + 1) | ||
| 484 | checkmessage(s, "too many C levels") | ||
| 485 | end | ||
| 486 | |||
| 487 | testrep("local a; a", ",a", "= 1", ",1") -- multiple assignment | ||
| 488 | testrep("local a; a=", "{", "0", "}") | ||
| 489 | testrep("local a; a=", "(", "2", ")") | ||
| 490 | testrep("local a; ", "a(", "2", ")") | ||
| 491 | testrep("", "do ", "", " end") | ||
| 492 | testrep("", "while a do ", "", " end") | ||
| 493 | testrep("local a; ", "if a then else ", "", " end") | ||
| 494 | testrep("", "function foo () ", "", " end") | ||
| 495 | testrep("local a; a=", "a..", "a", "") | ||
| 496 | testrep("local a; a=", "a^", "a", "") | ||
| 497 | |||
| 498 | checkmessage("a = f(x" .. string.rep(",x", 260) .. ")", "too many registers") | ||
| 499 | |||
| 500 | |||
| 501 | -- testing other limits | ||
| 502 | |||
| 503 | -- upvalues | ||
| 504 | local lim = 127 | ||
| 505 | local s = "local function fooA ()\n local " | ||
| 506 | for j = 1,lim do | ||
| 507 | s = s.."a"..j..", " | ||
| 508 | end | ||
| 509 | s = s.."b,c\n" | ||
| 510 | s = s.."local function fooB ()\n local " | ||
| 511 | for j = 1,lim do | ||
| 512 | s = s.."b"..j..", " | ||
| 513 | end | ||
| 514 | s = s.."b\n" | ||
| 515 | s = s.."function fooC () return b+c" | ||
| 516 | local c = 1+2 | ||
| 517 | for j = 1,lim do | ||
| 518 | s = s.."+a"..j.."+b"..j | ||
| 519 | c = c + 2 | ||
| 520 | end | ||
| 521 | s = s.."\nend end end" | ||
| 522 | local a,b = load(s) | ||
| 523 | assert(c > 255 and string.find(b, "too many upvalues") and | ||
| 524 | string.find(b, "line 5")) | ||
| 525 | |||
| 526 | -- local variables | ||
| 527 | s = "\nfunction foo ()\n local " | ||
| 528 | for j = 1,300 do | ||
| 529 | s = s.."a"..j..", " | ||
| 530 | end | ||
| 531 | s = s.."b\n" | ||
| 532 | local a,b = load(s) | ||
| 533 | assert(string.find(b, "line 2") and string.find(b, "too many local variables")) | ||
| 534 | |||
| 535 | mt.__index = oldmm | ||
| 536 | |||
| 537 | print('OK') | ||
