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