Browse Source

added some lua base libraries and some 5.1 unit tests

Jaromil 1 year ago
parent
commit
c8065354ce
10 changed files with 1207 additions and 6 deletions
  1. 10 1
      Makefile
  2. 7 3
      src/decode-exec.c
  3. 0 2
      src/hello.lua
  4. 17 0
      src/lua_functions.c
  5. 240 0
      test/constructs.lua
  6. 11 0
      test/decode-test.conf
  7. 127 0
      test/locals.lua
  8. 396 0
      test/nextvar.lua
  9. 273 0
      test/pm.lua
  10. 126 0
      test/vararg.lua

+ 10 - 1
Makefile

@@ -2,6 +2,7 @@ pwd := $(shell pwd)
2 2
 luasand := ${pwd}/build/lua_sandbox
3 3
 musl := ${pwd}/build/musl
4 4
 musl-gcc := ${musl}/obj/musl-gcc
5
+test-exec := ${pwd}/src/decode-exec -c ${pwd}/test/decode-test.conf
5 6
 
6 7
 all: bootstrap-check patches luasandbox luanacha
7 8
 	make -C src
@@ -29,7 +30,15 @@ luanacha:
29 30
 # 	make -C lib/gmp -j2
30 31
 
31 32
 check:
32
-	src/decode-exec -c src/decode-exec.conf test/test_luanacha.lua
33
+	${test-exec} test/vararg.lua
34
+	${test-exec} test/pm.lua
35
+	${test-exec} test/nextvar.lua
36
+	${test-exec} test/locals.lua
37
+	${test-exec} test/constructs.lua
38
+	${test-exec} test/test_luanacha.lua
39
+	@echo "----------------"
40
+	@echo "All tests passed"
41
+	@echo "----------------"
33 42
 
34 43
 clean:
35 44
 	rm -rf ${luasand}

+ 7 - 3
src/decode-exec.c

@@ -34,6 +34,7 @@ extern const struct luaL_Reg luanachalib;
34 34
 
35 35
 // prototypes from lua_functions
36 36
 void lsb_setglobal_string(lsb_lua_sandbox *lsb, char *key, char *val);
37
+void lsb_openlibs(lsb_lua_sandbox *lsb);
37 38
 // from timing.c
38 39
 // extern int set_hook(lua_State *L);
39 40
 
@@ -96,8 +97,10 @@ int main(int argc, char **argv) {
96 97
 	act("code: %s", codefile);
97 98
 
98 99
 	conf = lsb_read_file(conffile);
99
-	if(!conf) error("Error loading configuration: %s",conffile);
100
-	else act("conf: %s", conffile);
100
+	if(!conf) {
101
+		error("Error loading configuration: %s",conffile);
102
+		exit(1);
103
+	} else act("conf: %s", conffile);
101 104
 	func("\n%s",conf);
102 105
 
103 106
 	lsb_logger lsb_vm_logger = { .context = codefile, .cb = logger };
@@ -110,7 +113,7 @@ int main(int argc, char **argv) {
110 113
 		const char *r;
111 114
 		// load our own extensions
112 115
 		lib = &luanachalib;
113
-		notice("Loading crypto extensions");
116
+		func("loading crypto extensions");
114 117
 		for (; lib->func; lib++) {
115 118
 			func("%s",lib->name);
116 119
 			lsb_add_function(lsb, lib->func, lib->name);
@@ -118,6 +121,7 @@ int main(int argc, char **argv) {
118 121
 
119 122
 		// initialise global variables
120 123
 		lsb_setglobal_string(lsb, "VERSION", VERSION);
124
+		lsb_openlibs(lsb);
121 125
 
122 126
 		r = lsb_init(lsb, NULL);
123 127
 		if(r) {

+ 0 - 2
src/hello.lua

@@ -1,2 +0,0 @@
1
-print("Hello world.")
2
-

+ 17 - 0
src/lua_functions.c

@@ -18,11 +18,28 @@
18 18
  * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 19
  */
20 20
 
21
+#include <jutils.h>
21 22
 #include <luasandbox.h>
22 23
 #include <luasandbox/lua.h>
24
+#include <luasandbox/lualib.h>
23 25
 
24 26
 void lsb_setglobal_string(lsb_lua_sandbox *lsb, char *key, char *val) {
25 27
 	lua_State* L = lsb_get_lua(lsb);
26 28
 	lua_pushstring(L, val);
27 29
 	lua_setglobal(L, key);
28 30
 }
31
+
32
+void lsb_openlibs(lsb_lua_sandbox *lsb) {
33
+	lua_State* L = lsb_get_lua(lsb);
34
+	func("Loading base libraries:");
35
+	func("coroutine");
36
+	luaopen_coroutine(L);
37
+	func("table");
38
+	luaopen_table(L);
39
+	func("string");
40
+	luaopen_string(L);
41
+	func("math");
42
+	luaopen_math(L);
43
+	func("debug");
44
+	luaopen_debug(L);
45
+}

+ 240 - 0
test/constructs.lua

@@ -0,0 +1,240 @@
1
+print "testing syntax"
2
+
3
+-- testing priorities
4
+
5
+assert(2^3^2 == 2^(3^2));
6
+assert(2^3*4 == (2^3)*4);
7
+assert(2^-2 == 1/4 and -2^- -2 == - - -4);
8
+assert(not nil and 2 and not(2>3 or 3<2));
9
+assert(-3-1-5 == 0+0-9);
10
+assert(-2^2 == -4 and (-2)^2 == 4 and 2*2-3-1 == 0);
11
+assert(2*1+3/3 == 3 and 1+2 .. 3*1 == "33");
12
+assert(not(2+1 > 3*1) and "a".."b" > "a");
13
+
14
+assert(not ((true or false) and nil))
15
+assert(      true or false  and nil)
16
+
17
+local a,b = 1,nil;
18
+assert(-(1 or 2) == -1 and (1 and 2)+(-1.25 or -4) == 0.75);
19
+x = ((b or a)+1 == 2 and (10 or a)+1 == 11); assert(x);
20
+x = (((2<3) or 1) == true and (2<3 and 4) == 4); assert(x);
21
+
22
+x,y=1,2;
23
+assert((x>y) and x or y == 2);
24
+x,y=2,1;
25
+assert((x>y) and x or y == 2);
26
+
27
+assert(1234567890 == tonumber('1234567890') and 1234567890+1 == 1234567891)
28
+
29
+
30
+-- silly loops
31
+repeat until 1; repeat until true;
32
+while false do end; while nil do end;
33
+
34
+do  -- test old bug (first name could not be an `upvalue')
35
+ local a; function f(x) x={a=1}; x={x=1}; x={G=1} end
36
+end
37
+
38
+function f (i)
39
+  if type(i) ~= 'number' then return i,'jojo'; end;
40
+  if i > 0 then return i, f(i-1); end;
41
+end
42
+
43
+x = {f(3), f(5), f(10);};
44
+assert(x[1] == 3 and x[2] == 5 and x[3] == 10 and x[4] == 9 and x[12] == 1);
45
+assert(x[nil] == nil)
46
+x = {f'alo', f'xixi', nil};
47
+assert(x[1] == 'alo' and x[2] == 'xixi' and x[3] == nil);
48
+x = {f'alo'..'xixi'};
49
+assert(x[1] == 'aloxixi')
50
+x = {f{}}
51
+assert(x[2] == 'jojo' and type(x[1]) == 'table')
52
+
53
+
54
+local f = function (i)
55
+  if i < 10 then return 'a';
56
+  elseif i < 20 then return 'b';
57
+  elseif i < 30 then return 'c';
58
+  end;
59
+end
60
+
61
+assert(f(3) == 'a' and f(12) == 'b' and f(26) == 'c' and f(100) == nil)
62
+
63
+for i=1,1000 do break; end;
64
+n=100;
65
+i=3;
66
+t = {};
67
+a=nil
68
+while not a do
69
+  a=0; for i=1,n do for i=i,1,-1 do a=a+1; t[i]=1; end; end;
70
+end
71
+assert(a == n*(n+1)/2 and i==3);
72
+assert(t[1] and t[n] and not t[0] and not t[n+1])
73
+
74
+function f(b)
75
+  local x = 1;
76
+  repeat
77
+    local a;
78
+    if b==1 then local b=1; x=10; break
79
+    elseif b==2 then x=20; break;
80
+    elseif b==3 then x=30;
81
+    else local a,b,c,d=math.sin(1); x=x+1;
82
+    end
83
+  until x>=12;
84
+  return x;
85
+end;
86
+
87
+assert(f(1) == 10 and f(2) == 20 and f(3) == 30 and f(4)==12)
88
+
89
+
90
+local f = function (i)
91
+  if i < 10 then return 'a'
92
+  elseif i < 20 then return 'b'
93
+  elseif i < 30 then return 'c'
94
+  else return 8
95
+  end
96
+end
97
+
98
+assert(f(3) == 'a' and f(12) == 'b' and f(26) == 'c' and f(100) == 8)
99
+
100
+local a, b = nil, 23
101
+x = {f(100)*2+3 or a, a or b+2}
102
+assert(x[1] == 19 and x[2] == 25)
103
+x = {f=2+3 or a, a = b+2}
104
+assert(x.f == 5 and x.a == 25)
105
+
106
+a={y=1}
107
+x = {a.y}
108
+assert(x[1] == 1)
109
+
110
+function f(i)
111
+  while 1 do
112
+    if i>0 then i=i-1;
113
+    else return; end;
114
+  end;
115
+end;
116
+
117
+function g(i)
118
+  while 1 do
119
+    if i>0 then i=i-1
120
+    else return end
121
+  end
122
+end
123
+
124
+f(10); g(10);
125
+
126
+do
127
+  function f () return 1,2,3; end
128
+  local a, b, c = f();
129
+  assert(a==1 and b==2 and c==3)
130
+  a, b, c = (f());
131
+  assert(a==1 and b==nil and c==nil)
132
+end
133
+
134
+local a,b = 3 and f();
135
+assert(a==1 and b==nil)
136
+
137
+function g() f(); return; end;
138
+assert(g() == nil)
139
+function g() return nil or f() end
140
+a,b = g()
141
+assert(a==1 and b==nil)
142
+
143
+print'+';
144
+
145
+
146
+f = [[
147
+return function ( a , b , c , d , e )
148
+  local x = a >= b or c or ( d and e ) or nil
149
+  return x
150
+end , { a = 1 , b = 2 >= 1 , } or { 1 };
151
+]]
152
+f = string.gsub(f, "%s+", "\n");   -- force a SETLINE between opcodes
153
+f,a = loadstring(f)();
154
+assert(a.a == 1 and a.b)
155
+
156
+function g (a,b,c,d,e)
157
+  if not (a>=b or c or d and e or nil) then return 0; else return 1; end;
158
+end
159
+
160
+function h (a,b,c,d,e)
161
+  while (a>=b or c or (d and e) or nil) do return 1; end;
162
+  return 0;
163
+end;
164
+
165
+assert(f(2,1) == true and g(2,1) == 1 and h(2,1) == 1)
166
+assert(f(1,2,'a') == 'a' and g(1,2,'a') == 1 and h(1,2,'a') == 1)
167
+assert(f(1,2,'a')
168
+~=          -- force SETLINE before nil
169
+nil, "")
170
+assert(f(1,2,'a') == 'a' and g(1,2,'a') == 1 and h(1,2,'a') == 1)
171
+assert(f(1,2,nil,1,'x') == 'x' and g(1,2,nil,1,'x') == 1 and
172
+                                   h(1,2,nil,1,'x') == 1)
173
+assert(f(1,2,nil,nil,'x') == nil and g(1,2,nil,nil,'x') == 0 and
174
+                                     h(1,2,nil,nil,'x') == 0)
175
+assert(f(1,2,nil,1,nil) == nil and g(1,2,nil,1,nil) == 0 and
176
+                                   h(1,2,nil,1,nil) == 0)
177
+
178
+assert(1 and 2<3 == true and 2<3 and 'a'<'b' == true)
179
+x = 2<3 and not 3; assert(x==false)
180
+x = 2<1 or (2>1 and 'a'); assert(x=='a')
181
+
182
+
183
+do
184
+  local a; if nil then a=1; else a=2; end;    -- this nil comes as PUSHNIL 2
185
+  assert(a==2)
186
+end
187
+
188
+function F(a)
189
+  assert(debug.getinfo(1, "n").name == 'F')
190
+  return a,2,3
191
+end
192
+
193
+a,b = F(1)~=nil; assert(a == true and b == nil);
194
+a,b = F(nil)==nil; assert(a == true and b == nil)
195
+
196
+----------------------------------------------------------------
197
+-- creates all combinations of 
198
+-- [not] ([not] arg op [not] (arg op [not] arg ))
199
+-- and tests each one
200
+
201
+function ID(x) return x end
202
+
203
+function f(t, i)
204
+  local b = t.n
205
+  local res = math.mod(math.floor(i/c), b)+1
206
+  c = c*b
207
+  return t[res]
208
+end
209
+
210
+local arg = {" ( 1 < 2 ) ", " ( 1 >= 2 ) ", " F ( ) ", "  nil "; n=4}
211
+
212
+local op = {" and ", " or ", " == ", " ~= "; n=4}
213
+
214
+local neg = {" ", " not "; n=2}
215
+
216
+local i = 0
217
+repeat
218
+  c = 1
219
+  local s = f(neg, i)..'ID('..f(neg, i)..f(arg, i)..f(op, i)..
220
+            f(neg, i)..'ID('..f(arg, i)..f(op, i)..f(neg, i)..f(arg, i)..'))'
221
+  local s1 = string.gsub(s, 'ID', '')
222
+  K,X,NX,WX1,WX2 = nil
223
+  s = string.format([[
224
+      local a = %s
225
+      local b = not %s
226
+      K = b
227
+      local xxx; 
228
+      if %s then X = a  else X = b end
229
+      if %s then NX = b  else NX = a end
230
+      while %s do WX1 = a; break end
231
+      while %s do WX2 = a; break end
232
+      repeat if (%s) then break end; assert(b)  until not(%s)
233
+  ]], s1, s, s1, s, s1, s, s1, s, s)
234
+  assert(loadstring(s))()
235
+  assert(X and not NX and not WX1 == K and not WX2 == K)
236
+  if math.mod(i,4000) == 0 then print('+') end
237
+  i = i+1
238
+until i==c
239
+
240
+print'OK'

+ 11 - 0
test/decode-test.conf

@@ -0,0 +1,11 @@
1
+memory_limit = 0
2
+instruction_limit = 0
3
+output_limit = 64*1024
4
+log_level = 7
5
+path = '/dev/null'
6
+cpath = '/dev/null'
7
+remove_entries = {
8
+	[''] = {'dofile','load', 'loadfile','newproxy'},
9
+	os = {'getenv','execute','exit','remove','rename',
10
+		  'setlocale','tmpname'} }
11
+disable_modules = {io = 1}

+ 127 - 0
test/locals.lua

@@ -0,0 +1,127 @@
1
+print('testing local variables plus some extra stuff')
2
+
3
+do
4
+  local i = 10
5
+  do local i = 100; assert(i==100) end
6
+  do local i = 1000; assert(i==1000) end
7
+  assert(i == 10)
8
+  if i ~= 10 then
9
+    local i = 20
10
+  else
11
+    local i = 30
12
+    assert(i == 30)
13
+  end
14
+end
15
+
16
+
17
+
18
+f = nil
19
+
20
+local f
21
+x = 1
22
+
23
+a = nil
24
+loadstring('local a = {}')()
25
+assert(type(a) ~= 'table')
26
+
27
+function f (a)
28
+  local _1, _2, _3, _4, _5
29
+  local _6, _7, _8, _9, _10
30
+  local x = 3
31
+  local b = a
32
+  local c,d = a,b
33
+  if (d == b) then
34
+    local x = 'q'
35
+    x = b
36
+    assert(x == 2)
37
+  else
38
+    assert(nil)
39
+  end
40
+  assert(x == 3)
41
+  local f = 10
42
+end
43
+
44
+local b=10
45
+local a; repeat local b; a,b=1,2; assert(a+1==b); until a+b==3
46
+
47
+
48
+assert(x == 1)
49
+
50
+f(2)
51
+assert(type(f) == 'function')
52
+
53
+
54
+-- testing globals ;-)
55
+do
56
+  local f = {}
57
+  local _G = _G
58
+  for i=1,10 do f[i] = function (x) A=A+1; return A, _G.getfenv(x) end end
59
+  A=10; assert(f[1]() == 11)
60
+  for i=1,10 do assert(setfenv(f[i], {A=i}) == f[i]) end
61
+  assert(f[3]() == 4 and A == 11)
62
+  local a,b = f[8](1)
63
+  assert(b.A == 9)
64
+  a,b = f[8](0)
65
+  assert(b.A == 11)   -- `real' global
66
+  local g
67
+  local function f () assert(setfenv(2, {a='10'}) == g) end
68
+  g = function () f(); _G.assert(_G.getfenv(1).a == '10') end
69
+  g(); assert(getfenv(g).a == '10')
70
+end
71
+
72
+-- test for global table of loaded chunks
73
+local function foo (s)
74
+  return loadstring(s)
75
+end
76
+
77
+assert(getfenv(foo("")) == _G)
78
+local a = {loadstring = loadstring} 
79
+setfenv(foo, a)
80
+assert(getfenv(foo("")) == _G)
81
+setfenv(0, a)  -- change global environment
82
+assert(getfenv(foo("")) == a)
83
+setfenv(0, _G)
84
+
85
+
86
+-- testing limits for special instructions
87
+
88
+local a
89
+local p = 4
90
+for i=2,31 do
91
+  for j=-3,3 do
92
+    assert(loadstring(string.format([[local a=%s;a=a+
93
+                                            %s;
94
+                                      assert(a
95
+                                      ==2^%s)]], j, p-j, i))) ()
96
+    assert(loadstring(string.format([[local a=%s;
97
+                                      a=a-%s;
98
+                                      assert(a==-2^%s)]], -j, p-j, i))) ()
99
+    assert(loadstring(string.format([[local a,b=0,%s;
100
+                                      a=b-%s;
101
+                                      assert(a==-2^%s)]], -j, p-j, i))) ()
102
+  end
103
+  p =2*p
104
+end
105
+
106
+print'+'
107
+
108
+
109
+if rawget(_G, "querytab") then
110
+  -- testing clearing of dead elements from tables
111
+  collectgarbage("stop")   -- stop GC
112
+  local a = {[{}] = 4, [3] = 0, alo = 1, 
113
+             a1234567890123456789012345678901234567890 = 10}
114
+
115
+  local t = querytab(a)
116
+
117
+  for k,_ in pairs(a) do a[k] = nil end
118
+  collectgarbage()   -- restore GC and collect dead fiels in `a'
119
+  for i=0,t-1 do
120
+    local k = querytab(a, i)
121
+    assert(k == nil or type(k) == 'number' or k == 'alo')
122
+  end
123
+end
124
+
125
+print('OK')
126
+
127
+return 5,f

+ 396 - 0
test/nextvar.lua

@@ -0,0 +1,396 @@
1
+print('testing tables, next, and for')
2
+
3
+local a = {}
4
+
5
+-- make sure table has lots of space in hash part
6
+for i=1,100 do a[i.."+"] = true end
7
+for i=1,100 do a[i.."+"] = nil end
8
+-- fill hash part with numeric indices testing size operator
9
+for i=1,100 do
10
+  a[i] = true
11
+  assert(#a == i)
12
+end
13
+
14
+
15
+if T then
16
+-- testing table sizes
17
+
18
+local l2 = math.log(2)
19
+local function log2 (x) return math.log(x)/l2 end
20
+
21
+local function mp2 (n)   -- minimum power of 2 >= n
22
+  local mp = 2^math.ceil(log2(n))
23
+  assert(n == 0 or (mp/2 < n and n <= mp))
24
+  return mp
25
+end
26
+
27
+local function fb (n)
28
+  local r, nn = T.int2fb(n)
29
+  assert(r < 256)
30
+  return nn
31
+end
32
+
33
+-- test fb function
34
+local a = 1
35
+local lim = 2^30
36
+while a < lim do
37
+  local n = fb(a)
38
+  assert(a <= n and n <= a*1.125)
39
+  a = math.ceil(a*1.3)
40
+end
41
+
42
+ 
43
+local function check (t, na, nh)
44
+  local a, h = T.querytab(t)
45
+  if a ~= na or h ~= nh then
46
+    print(na, nh, a, h)
47
+    assert(nil)
48
+  end
49
+end
50
+
51
+-- testing constructor sizes
52
+local lim = 40
53
+local s = 'return {'
54
+for i=1,lim do
55
+  s = s..i..','
56
+  local s = s
57
+  for k=0,lim do 
58
+    local t = loadstring(s..'}')()
59
+    assert(#t == i)
60
+    check(t, fb(i), mp2(k))
61
+    s = string.format('%sa%d=%d,', s, k, k)
62
+  end
63
+end
64
+
65
+
66
+-- tests with unknown number of elements
67
+local a = {}
68
+for i=1,lim do a[i] = i end   -- build auxiliary table
69
+for k=0,lim do
70
+  local a = {unpack(a,1,k)}
71
+  assert(#a == k)
72
+  check(a, k, 0)
73
+  a = {1,2,3,unpack(a,1,k)}
74
+  check(a, k+3, 0)
75
+  assert(#a == k + 3)
76
+end
77
+
78
+
79
+print'+'
80
+
81
+-- testing tables dynamically built
82
+local lim = 130
83
+local a = {}; a[2] = 1; check(a, 0, 1)
84
+a = {}; a[0] = 1; check(a, 0, 1); a[2] = 1; check(a, 0, 2)
85
+a = {}; a[0] = 1; a[1] = 1; check(a, 1, 1)
86
+a = {}
87
+for i = 1,lim do
88
+  a[i] = 1
89
+  assert(#a == i)
90
+  check(a, mp2(i), 0)
91
+end
92
+
93
+a = {}
94
+for i = 1,lim do
95
+  a['a'..i] = 1
96
+  assert(#a == 0)
97
+  check(a, 0, mp2(i))
98
+end
99
+
100
+a = {}
101
+for i=1,16 do a[i] = i end
102
+check(a, 16, 0)
103
+for i=1,11 do a[i] = nil end
104
+for i=30,40 do a[i] = nil end   -- force a rehash (?)
105
+check(a, 0, 8)
106
+a[10] = 1
107
+for i=30,40 do a[i] = nil end   -- force a rehash (?)
108
+check(a, 0, 8)
109
+for i=1,14 do a[i] = nil end
110
+for i=30,50 do a[i] = nil end   -- force a rehash (?)
111
+check(a, 0, 4)
112
+
113
+-- reverse filling
114
+for i=1,lim do
115
+  local a = {}
116
+  for i=i,1,-1 do a[i] = i end   -- fill in reverse
117
+  check(a, mp2(i), 0)
118
+end
119
+
120
+-- size tests for vararg
121
+lim = 35
122
+function foo (n, ...)
123
+  local arg = {...}
124
+  check(arg, n, 0)
125
+  assert(select('#', ...) == n)
126
+  arg[n+1] = true
127
+  check(arg, mp2(n+1), 0)
128
+  arg.x = true
129
+  check(arg, mp2(n+1), 1)
130
+end
131
+local a = {}
132
+for i=1,lim do a[i] = true; foo(i, unpack(a)) end
133
+
134
+end
135
+
136
+
137
+-- test size operation on empty tables
138
+assert(#{} == 0)
139
+assert(#{nil} == 0)
140
+assert(#{nil, nil} == 0)
141
+assert(#{nil, nil, nil} == 0)
142
+assert(#{nil, nil, nil, nil} == 0)
143
+print'+'
144
+
145
+
146
+local nofind = {}
147
+
148
+a,b,c = 1,2,3
149
+a,b,c = nil
150
+
151
+local function find (name)
152
+  local n,v
153
+  while 1 do
154
+    n,v = next(_G, n)
155
+    if not n then return nofind end
156
+    assert(v ~= nil)
157
+    if n == name then return v end
158
+  end
159
+end
160
+
161
+local function find1 (name)
162
+  for n,v in pairs(_G) do
163
+    if n==name then return v end
164
+  end
165
+  return nil  -- not found
166
+end
167
+
168
+do   -- create 10000 new global variables
169
+  for i=1,10000 do _G[i] = i end
170
+end
171
+
172
+
173
+a = {x=90, y=8, z=23}
174
+assert(table.foreach(a, function(i,v) if i=='x' then return v end end) == 90)
175
+assert(table.foreach(a, function(i,v) if i=='a' then return v end end) == nil)
176
+table.foreach({}, error)
177
+
178
+table.foreachi({x=10, y=20}, error)
179
+local a = {n = 1}
180
+table.foreachi({n=3}, function (i, v)
181
+  assert(a.n == i and not v)
182
+  a.n=a.n+1
183
+end)
184
+a = {10,20,30,nil,50}
185
+table.foreachi(a, function (i,v) assert(a[i] == v) end)
186
+assert(table.foreachi({'a', 'b', 'c'}, function (i,v)
187
+         if i==2 then return v end
188
+       end) == 'b')
189
+
190
+
191
+assert(print==find("print") and print == find1("print"))
192
+assert(_G["print"]==find("print"))
193
+assert(assert==find1("assert"))
194
+assert(nofind==find("return"))
195
+assert(not find1("return"))
196
+_G["ret" .. "urn"] = nil
197
+assert(nofind==find("return"))
198
+_G["xxx"] = 1
199
+assert(xxx==find("xxx"))
200
+print('+')
201
+
202
+a = {}
203
+for i=0,10000 do
204
+  if math.mod(i,10) ~= 0 then
205
+    a['x'..i] = i
206
+  end
207
+end
208
+
209
+n = {n=0}
210
+for i,v in pairs(a) do
211
+  n.n = n.n+1
212
+  assert(i and v and a[i] == v)
213
+end
214
+assert(n.n == 9000)
215
+a = nil
216
+
217
+-- remove those 10000 new global variables
218
+for i=1,10000 do _G[i] = nil end
219
+
220
+do   -- clear global table
221
+  local a = {}
222
+  local preserve = {io = 1, string = 1, debug = 1, os = 1,
223
+                    coroutine = 1, table = 1, math = 1}
224
+  for n,v in pairs(_G) do a[n]=v end
225
+  for n,v in pairs(a) do
226
+    if not preserve[n] and type(v) ~= "function" and
227
+       not string.find(n, "^[%u_]") then
228
+     _G[n] = nil
229
+    end
230
+    collectgarbage()
231
+  end
232
+end
233
+
234
+local function foo ()
235
+  local getfenv, setfenv, assert, next =
236
+        getfenv, setfenv, assert, next
237
+  local n = {gl1=3}
238
+  setfenv(foo, n)
239
+  assert(getfenv(foo) == getfenv(1))
240
+  assert(getfenv(foo) == n)
241
+  assert(print == nil and gl1 == 3)
242
+  gl1 = nil
243
+  gl = 1
244
+  assert(n.gl == 1 and next(n, 'gl') == nil)
245
+end
246
+foo()
247
+
248
+print'+'
249
+
250
+local function checknext (a)
251
+  local b = {}
252
+  table.foreach(a, function (k,v) b[k] = v end)
253
+  for k,v in pairs(b) do assert(a[k] == v) end
254
+  for k,v in pairs(a) do assert(b[k] == v) end
255
+  b = {}
256
+  do local k,v = next(a); while k do b[k] = v; k,v = next(a,k) end end
257
+  for k,v in pairs(b) do assert(a[k] == v) end
258
+  for k,v in pairs(a) do assert(b[k] == v) end
259
+end
260
+
261
+checknext{1,x=1,y=2,z=3}
262
+checknext{1,2,x=1,y=2,z=3}
263
+checknext{1,2,3,x=1,y=2,z=3}
264
+checknext{1,2,3,4,x=1,y=2,z=3}
265
+checknext{1,2,3,4,5,x=1,y=2,z=3}
266
+
267
+assert(table.getn{} == 0)
268
+assert(table.getn{[-1] = 2} == 0)
269
+assert(table.getn{1,2,3,nil,nil} == 3)
270
+for i=0,40 do
271
+  local a = {}
272
+  for j=1,i do a[j]=j end
273
+  assert(table.getn(a) == i)
274
+end
275
+
276
+
277
+assert(table.maxn{} == 0)
278
+assert(table.maxn{["1000"] = true} == 0)
279
+assert(table.maxn{["1000"] = true, [24.5] = 3} == 24.5)
280
+assert(table.maxn{[1000] = true} == 1000)
281
+assert(table.maxn{[10] = true, [100*math.pi] = print} == 100*math.pi)
282
+
283
+
284
+-- int overflow
285
+a = {}
286
+for i=0,50 do a[math.pow(2,i)] = true end
287
+assert(a[table.getn(a)])
288
+
289
+print("+")
290
+
291
+
292
+-- erasing values
293
+local t = {[{1}] = 1, [{2}] = 2, [string.rep("x ", 4)] = 3,
294
+           [100.3] = 4, [4] = 5}
295
+
296
+local n = 0
297
+for k, v in pairs( t ) do
298
+  n = n+1
299
+  assert(t[k] == v)
300
+  t[k] = nil
301
+  collectgarbage()
302
+  assert(t[k] == nil)
303
+end
304
+assert(n == 5)
305
+
306
+
307
+local function test (a)
308
+  table.insert(a, 10); table.insert(a, 2, 20);
309
+  table.insert(a, 1, -1); table.insert(a, 40);
310
+  table.insert(a, table.getn(a)+1, 50)
311
+  table.insert(a, 2, -2)
312
+  assert(table.remove(a,1) == -1)
313
+  assert(table.remove(a,1) == -2)
314
+  assert(table.remove(a,1) == 10)
315
+  assert(table.remove(a,1) == 20)
316
+  assert(table.remove(a,1) == 40)
317
+  assert(table.remove(a,1) == 50)
318
+  assert(table.remove(a,1) == nil)
319
+end
320
+
321
+a = {n=0, [-7] = "ban"}
322
+test(a)
323
+assert(a.n == 0 and a[-7] == "ban")
324
+
325
+a = {[-7] = "ban"};
326
+test(a)
327
+assert(a.n == nil and table.getn(a) == 0 and a[-7] == "ban")
328
+
329
+
330
+table.insert(a, 1, 10); table.insert(a, 1, 20); table.insert(a, 1, -1)
331
+assert(table.remove(a) == 10)
332
+assert(table.remove(a) == 20)
333
+assert(table.remove(a) == -1)
334
+
335
+a = {'c', 'd'}
336
+table.insert(a, 3, 'a')
337
+table.insert(a, 'b')
338
+assert(table.remove(a, 1) == 'c')
339
+assert(table.remove(a, 1) == 'd')
340
+assert(table.remove(a, 1) == 'a')
341
+assert(table.remove(a, 1) == 'b')
342
+assert(table.getn(a) == 0 and a.n == nil)
343
+print("+")
344
+
345
+a = {}
346
+for i=1,1000 do
347
+  a[i] = i; a[i-1] = nil
348
+end
349
+assert(next(a,nil) == 1000 and next(a,1000) == nil)
350
+
351
+assert(next({}) == nil)
352
+assert(next({}, nil) == nil)
353
+
354
+for a,b in pairs{} do error"not here" end
355
+for i=1,0 do error'not here' end
356
+for i=0,1,-1 do error'not here' end
357
+a = nil; for i=1,1 do assert(not a); a=1 end; assert(a)
358
+a = nil; for i=1,1,-1 do assert(not a); a=1 end; assert(a)
359
+
360
+a = 0; for i=0, 1, 0.1 do a=a+1 end; assert(a==11)
361
+-- precision problems
362
+--a = 0; for i=1, 0, -0.01 do a=a+1 end; assert(a==101)
363
+a = 0; for i=0, 0.999999999, 0.1 do a=a+1 end; assert(a==10)
364
+a = 0; for i=1, 1, 1 do a=a+1 end; assert(a==1)
365
+a = 0; for i=1e10, 1e10, -1 do a=a+1 end; assert(a==1)
366
+a = 0; for i=1, 0.99999, 1 do a=a+1 end; assert(a==0)
367
+a = 0; for i=99999, 1e5, -1 do a=a+1 end; assert(a==0)
368
+a = 0; for i=1, 0.99999, -1 do a=a+1 end; assert(a==1)
369
+
370
+-- conversion
371
+a = 0; for i="10","1","-2" do a=a+1 end; assert(a==5)
372
+
373
+
374
+collectgarbage()
375
+
376
+
377
+-- testing generic 'for'
378
+
379
+local function f (n, p)
380
+  local t = {}; for i=1,p do t[i] = i*10 end
381
+  return function (_,n)
382
+           if n > 0 then
383
+             n = n-1
384
+             return n, unpack(t)
385
+           end
386
+         end, nil, n
387
+end
388
+
389
+local x = 0
390
+for n,a,b,c,d in f(5,3) do
391
+  x = x+1
392
+  assert(a == 10 and b == 20 and c == 30 and d == nil)
393
+end
394
+assert(x == 5)
395
+
396
+print"OK"

+ 273 - 0
test/pm.lua

@@ -0,0 +1,273 @@
1
+print('testing pattern matching')
2
+
3
+function f(s, p)
4
+  local i,e = string.find(s, p)
5
+  if i then return string.sub(s, i, e) end
6
+end
7
+
8
+function f1(s, p)
9
+  p = string.gsub(p, "%%([0-9])", function (s) return "%" .. (s+1) end)
10
+  p = string.gsub(p, "^(^?)", "%1()", 1)
11
+  p = string.gsub(p, "($?)$", "()%1", 1)
12
+  local t = {string.match(s, p)}
13
+  return string.sub(s, t[1], t[#t] - 1)
14
+end
15
+
16
+a,b = string.find('', '')    -- empty patterns are tricky
17
+assert(a == 1 and b == 0);
18
+a,b = string.find('alo', '')
19
+assert(a == 1 and b == 0)
20
+a,b = string.find('a\0o a\0o a\0o', 'a', 1)   -- first position
21
+assert(a == 1 and b == 1)
22
+a,b = string.find('a\0o a\0o a\0o', 'a\0o', 2)   -- starts in the midle
23
+assert(a == 5 and b == 7)
24
+a,b = string.find('a\0o a\0o a\0o', 'a\0o', 9)   -- starts in the midle
25
+assert(a == 9 and b == 11)
26
+a,b = string.find('a\0a\0a\0a\0\0ab', '\0ab', 2);  -- finds at the end
27
+assert(a == 9 and b == 11);
28
+a,b = string.find('a\0a\0a\0a\0\0ab', 'b')    -- last position
29
+assert(a == 11 and b == 11)
30
+assert(string.find('a\0a\0a\0a\0\0ab', 'b\0') == nil)   -- check ending
31
+assert(string.find('', '\0') == nil)
32
+assert(string.find('alo123alo', '12') == 4)
33
+assert(string.find('alo123alo', '^12') == nil)
34
+
35
+assert(f('aloALO', '%l*') == 'alo')
36
+assert(f('aLo_ALO', '%a*') == 'aLo')
37
+
38
+assert(f('aaab', 'a*') == 'aaa');
39
+assert(f('aaa', '^.*$') == 'aaa');
40
+assert(f('aaa', 'b*') == '');
41
+assert(f('aaa', 'ab*a') == 'aa')
42
+assert(f('aba', 'ab*a') == 'aba')
43
+assert(f('aaab', 'a+') == 'aaa')
44
+assert(f('aaa', '^.+$') == 'aaa')
45
+assert(f('aaa', 'b+') == nil)
46
+assert(f('aaa', 'ab+a') == nil)
47
+assert(f('aba', 'ab+a') == 'aba')
48
+assert(f('a$a', '.$') == 'a')
49
+assert(f('a$a', '.%$') == 'a$')
50
+assert(f('a$a', '.$.') == 'a$a')
51
+assert(f('a$a', '$$') == nil)
52
+assert(f('a$b', 'a$') == nil)
53
+assert(f('a$a', '$') == '')
54
+assert(f('', 'b*') == '')
55
+assert(f('aaa', 'bb*') == nil)
56
+assert(f('aaab', 'a-') == '')
57
+assert(f('aaa', '^.-$') == 'aaa')
58
+assert(f('aabaaabaaabaaaba', 'b.*b') == 'baaabaaabaaab')
59
+assert(f('aabaaabaaabaaaba', 'b.-b') == 'baaab')
60
+assert(f('alo xo', '.o$') == 'xo')
61
+assert(f(' \n isto é assim', '%S%S*') == 'isto')
62
+assert(f(' \n isto é assim', '%S*$') == 'assim')
63
+assert(f(' \n isto é assim', '[a-z]*$') == 'assim')
64
+assert(f('um caracter ? extra', '[^%sa-z]') == '?')
65
+assert(f('', 'a?') == '')
66
+assert(f('á', 'á?') == 'á')
67
+assert(f('ábl', 'á?b?l?') == 'ábl')
68
+assert(f('  ábl', 'á?b?l?') == '')
69
+assert(f('aa', '^aa?a?a') == 'aa')
70
+assert(f(']]]áb', '[^]]') == 'á')
71
+assert(f("0alo alo", "%x*") == "0a")
72
+assert(f("alo alo", "%C+") == "alo alo")
73
+print('+')
74
+
75
+assert(f1('alo alx 123 b\0o b\0o', '(..*) %1') == "b\0o b\0o")
76
+assert(f1('axz123= 4= 4 34', '(.+)=(.*)=%2 %1') == '3= 4= 4 3')
77
+assert(f1('=======', '^(=*)=%1$') == '=======')
78
+assert(string.match('==========', '^([=]*)=%1$') == nil)
79
+
80
+local function range (i, j)
81
+  if i <= j then
82
+    return i, range(i+1, j)
83
+  end
84
+end
85
+
86
+local abc = string.char(range(0, 255));
87
+
88
+assert(string.len(abc) == 256)
89
+
90
+function strset (p)
91
+  local res = {s=''}
92
+  string.gsub(abc, p, function (c) res.s = res.s .. c end)
93
+  return res.s
94
+end;
95
+
96
+assert(string.len(strset('[\200-\210]')) == 11)
97
+
98
+assert(strset('[a-z]') == "abcdefghijklmnopqrstuvwxyz")
99
+assert(strset('[a-z%d]') == strset('[%da-uu-z]'))
100
+assert(strset('[a-]') == "-a")
101
+assert(strset('[^%W]') == strset('[%w]'))
102
+assert(strset('[]%%]') == '%]')
103
+assert(strset('[a%-z]') == '-az')
104
+assert(strset('[%^%[%-a%]%-b]') == '-[]^ab')
105
+assert(strset('%Z') == strset('[\1-\255]'))
106
+assert(strset('.') == strset('[\1-\255%z]'))
107
+print('+');
108
+
109
+assert(string.match("alo xyzK", "(%w+)K") == "xyz")
110
+assert(string.match("254 K", "(%d*)K") == "")
111
+assert(string.match("alo ", "(%w*)$") == "")
112
+assert(string.match("alo ", "(%w+)$") == nil)
113
+assert(string.find("(álo)", "%(á") == 1)
114
+local a, b, c, d, e = string.match("âlo alo", "^(((.).).* (%w*))$")
115
+assert(a == 'âlo alo' and b == 'âl' and c == 'â' and d == 'alo' and e == nil)
116
+a, b, c, d  = string.match('0123456789', '(.+(.?)())')
117
+assert(a == '0123456789' and b == '' and c == 11 and d == nil)
118
+print('+')
119
+
120
+assert(string.gsub('ülo ülo', 'ü', 'x') == 'xlo xlo')
121
+assert(string.gsub('alo úlo  ', ' +$', '') == 'alo úlo')  -- trim
122
+assert(string.gsub('  alo alo  ', '^%s*(.-)%s*$', '%1') == 'alo alo')  -- double trim
123
+assert(string.gsub('alo  alo  \n 123\n ', '%s+', ' ') == 'alo alo 123 ')
124
+t = "abç d"
125
+a, b = string.gsub(t, '(.)', '%1@')
126
+assert('@'..a == string.gsub(t, '', '@') and b == 5)
127
+a, b = string.gsub('abçd', '(.)', '%0@', 2)
128
+assert(a == 'a@b@çd' and b == 2)
129
+assert(string.gsub('alo alo', '()[al]', '%1') == '12o 56o')
130
+assert(string.gsub("abc=xyz", "(%w*)(%p)(%w+)", "%3%2%1-%0") ==
131
+              "xyz=abc-abc=xyz")
132
+assert(string.gsub("abc", "%w", "%1%0") == "aabbcc")
133
+assert(string.gsub("abc", "%w+", "%0%1") == "abcabc")
134
+assert(string.gsub('áéí', '$', '\0óú') == 'áéí\0óú')
135
+assert(string.gsub('', '^', 'r') == 'r')
136
+assert(string.gsub('', '$', 'r') == 'r')
137
+print('+')
138
+
139
+assert(string.gsub("um (dois) tres (quatro)", "(%(%w+%))", string.upper) ==
140
+            "um (DOIS) tres (QUATRO)")
141
+
142
+do
143
+  local function setglobal (n,v) rawset(_G, n, v) end
144
+  string.gsub("a=roberto,roberto=a", "(%w+)=(%w%w*)", setglobal)
145
+  assert(_G.a=="roberto" and _G.roberto=="a")
146
+end
147
+
148
+function f(a,b) return string.gsub(a,'.',b) end
149
+assert(string.gsub("trocar tudo em |teste|b| é |beleza|al|", "|([^|]*)|([^|]*)|", f) ==
150
+            "trocar tudo em bbbbb é alalalalalal")
151
+
152
+local function dostring (s) return loadstring(s)() or "" end
153
+assert(string.gsub("alo $a=1$ novamente $return a$", "$([^$]*)%$", dostring) ==
154
+            "alo  novamente 1")
155
+
156
+x = string.gsub("$x=string.gsub('alo', '.', string.upper)$ assim vai para $return x$",
157
+         "$([^$]*)%$", dostring)
158
+assert(x == ' assim vai para ALO')
159
+
160
+t = {}
161
+s = 'a alo jose  joao'
162
+r = string.gsub(s, '()(%w+)()', function (a,w,b)
163
+      assert(string.len(w) == b-a);
164
+      t[a] = b-a;
165
+    end)
166
+assert(s == r and t[1] == 1 and t[3] == 3 and t[7] == 4 and t[13] == 4)
167
+
168
+
169
+function isbalanced (s)
170
+  return string.find(string.gsub(s, "%b()", ""), "[()]") == nil
171
+end
172
+
173
+assert(isbalanced("(9 ((8))(\0) 7) \0\0 a b ()(c)() a"))
174
+assert(not isbalanced("(9 ((8) 7) a b (\0 c) a"))
175
+assert(string.gsub("alo 'oi' alo", "%b''", '"') == 'alo " alo')
176
+
177
+
178
+local t = {"apple", "orange", "lime"; n=0}
179
+assert(string.gsub("x and x and x", "x", function () t.n=t.n+1; return t[t.n] end)
180
+        == "apple and orange and lime")
181
+
182
+t = {n=0}
183
+string.gsub("first second word", "%w%w*", function (w) t.n=t.n+1; t[t.n] = w end)
184
+assert(t[1] == "first" and t[2] == "second" and t[3] == "word" and t.n == 3)
185
+
186
+t = {n=0}
187
+assert(string.gsub("first second word", "%w+",
188
+         function (w) t.n=t.n+1; t[t.n] = w end, 2) == "first second word")
189
+assert(t[1] == "first" and t[2] == "second" and t[3] == nil)
190
+
191
+assert(not pcall(string.gsub, "alo", "(.", print))
192
+assert(not pcall(string.gsub, "alo", ".)", print))
193
+assert(not pcall(string.gsub, "alo", "(.", {}))
194
+assert(not pcall(string.gsub, "alo", "(.)", "%2"))
195
+assert(not pcall(string.gsub, "alo", "(%1)", "a"))
196
+assert(not pcall(string.gsub, "alo", "(%0)", "a"))
197
+
198
+-- big strings
199
+local a = string.rep('a', 300000)
200
+assert(string.find(a, '^a*.?$'))
201
+assert(not string.find(a, '^a*.?b$'))
202
+assert(string.find(a, '^a-.?$'))
203
+
204
+-- deep nest of gsubs
205
+function rev (s)
206
+  return string.gsub(s, "(.)(.+)", function (c,s1) return rev(s1)..c end)
207
+end
208
+
209
+local x = string.rep('012345', 10)
210
+assert(rev(rev(x)) == x)
211
+
212
+
213
+-- gsub with tables
214
+assert(string.gsub("alo alo", ".", {}) == "alo alo")
215
+assert(string.gsub("alo alo", "(.)", {a="AA", l=""}) == "AAo AAo")
216
+assert(string.gsub("alo alo", "(.).", {a="AA", l="K"}) == "AAo AAo")
217
+assert(string.gsub("alo alo", "((.)(.?))", {al="AA", o=false}) == "AAo AAo")
218
+
219
+assert(string.gsub("alo alo", "().", {2,5,6}) == "256 alo")
220
+
221
+t = {}; setmetatable(t, {__index = function (t,s) return string.upper(s) end})
222
+assert(string.gsub("a alo b hi", "%w%w+", t) == "a ALO b HI")
223
+
224
+
225
+-- tests for gmatch
226
+assert(string.gfind == string.gmatch)
227
+local a = 0
228
+for i in string.gmatch('abcde', '()') do assert(i == a+1); a=i end
229
+assert(a==6)
230
+
231
+t = {n=0}
232
+for w in string.gmatch("first second word", "%w+") do
233
+      t.n=t.n+1; t[t.n] = w
234
+end
235
+assert(t[1] == "first" and t[2] == "second" and t[3] == "word")
236
+
237
+t = {3, 6, 9}
238
+for i in string.gmatch ("xuxx uu ppar r", "()(.)%2") do
239
+  assert(i == table.remove(t, 1))
240
+end
241
+assert(table.getn(t) == 0)
242
+
243
+t = {}
244
+for i,j in string.gmatch("13 14 10 = 11, 15= 16, 22=23", "(%d+)%s*=%s*(%d+)") do
245
+  t[i] = j
246
+end
247
+a = 0
248
+for k,v in pairs(t) do assert(k+1 == v+0); a=a+1 end
249
+assert(a == 3)
250
+
251
+
252
+-- tests for `%f' (`frontiers')
253
+
254
+assert(string.gsub("aaa aa a aaa a", "%f[%w]a", "x") == "xaa xa x xaa x")
255
+assert(string.gsub("[[]] [][] [[[[", "%f[[].", "x") == "x[]] x]x] x[[[")
256
+assert(string.gsub("01abc45de3", "%f[%d]", ".") == ".01abc.45de.3")
257
+assert(string.gsub("01abc45 de3x", "%f[%D]%w", ".") == "01.bc45 de3.")
258
+assert(string.gsub("function", "%f[\1-\255]%w", ".") == ".unction")
259
+assert(string.gsub("function", "%f[^\1-\255]", ".") == "function.")
260
+
261
+local i, e = string.find(" alo aalo allo", "%f[%S].-%f[%s].-%f[%S]")
262
+assert(i == 2 and e == 5)
263
+local k = string.match(" alo aalo allo", "%f[%S](.-%f[%s].-%f[%S])")
264
+assert(k == 'alo ')
265
+
266
+local a = {1, 5, 9, 14, 17,}
267
+for k in string.gmatch("alo alo th02 is 1hat", "()%f[%w%d]") do
268
+  assert(table.remove(a, 1) == k)
269
+end
270
+assert(table.getn(a) == 0)
271
+
272
+
273
+print('OK')

+ 126 - 0
test/vararg.lua

@@ -0,0 +1,126 @@
1
+print('testing vararg')
2
+
3
+_G.arg = nil
4
+
5
+function f(a, ...)
6
+  assert(type(arg) == 'table')
7
+  assert(type(arg.n) == 'number')
8
+  for i=1,arg.n do assert(a[i]==arg[i]) end
9
+  return arg.n
10
+end
11
+
12
+function c12 (...)
13
+  assert(arg == nil)
14
+  local x = {...}; x.n = table.getn(x)
15
+  local res = (x.n==2 and x[1] == 1 and x[2] == 2)
16
+  if res then res = 55 end
17
+  return res, 2
18
+end
19
+
20
+function vararg (...) return arg end
21
+
22
+local call = function (f, args) return f(unpack(args, 1, args.n)) end
23
+
24
+assert(f() == 0)
25
+assert(f({1,2,3}, 1, 2, 3) == 3)
26
+assert(f({"alo", nil, 45, f, nil}, "alo", nil, 45, f, nil) == 5)
27
+
28
+assert(c12(1,2)==55)
29
+a,b = assert(call(c12, {1,2}))
30
+assert(a == 55 and b == 2)
31
+a = call(c12, {1,2;n=2})
32
+assert(a == 55 and b == 2)
33
+a = call(c12, {1,2;n=1})
34
+assert(not a)
35
+assert(c12(1,2,3) == false)
36
+local a = vararg(call(next, {_G,nil;n=2}))
37
+local b,c = next(_G)
38
+assert(a[1] == b and a[2] == c and a.n == 2)
39
+a = vararg(call(call, {c12, {1,2}}))
40
+assert(a.n == 2 and a[1] == 55 and a[2] == 2)
41
+a = call(print, {'+'})
42
+assert(a == nil)
43
+
44
+local t = {1, 10}
45
+function t:f (...) return self[arg[1]]+arg.n end
46
+assert(t:f(1,4) == 3 and t:f(2) == 11)
47
+print('+')
48
+
49
+lim = 20
50
+local i, a = 1, {}
51
+while i <= lim do a[i] = i+0.3; i=i+1 end
52
+
53
+function f(a, b, c, d, ...)
54
+  local more = {...}
55
+  assert(a == 1.3 and more[1] == 5.3 and
56
+         more[lim-4] == lim+0.3 and not more[lim-3])
57
+end
58
+
59
+function g(a,b,c)
60
+  assert(a == 1.3 and b == 2.3 and c == 3.3)
61
+end
62
+
63
+call(f, a)
64
+call(g, a)
65
+
66
+a = {}
67
+i = 1
68
+while i <= lim do a[i] = i; i=i+1 end
69
+assert(call(math.max, a) == lim)
70
+
71
+print("+")
72
+
73
+
74
+-- new-style varargs
75
+
76
+function oneless (a, ...) return ... end
77
+
78
+function f (n, a, ...)
79
+  local b
80
+  assert(arg == nil)
81
+  if n == 0 then
82
+    local b, c, d = ...
83
+    return a, b, c, d, oneless(oneless(oneless(...)))
84
+  else
85
+    n, b, a = n-1, ..., a
86
+    assert(b == ...)
87
+    return f(n, a, ...)
88
+  end
89
+end
90
+
91
+a,b,c,d,e = assert(f(10,5,4,3,2,1))
92
+assert(a==5 and b==4 and c==3 and d==2 and e==1)
93
+
94
+a,b,c,d,e = f(4)
95
+assert(a==nil and b==nil and c==nil and d==nil and e==nil)
96
+
97
+
98
+-- varargs for main chunks
99
+f = loadstring[[ return {...} ]]
100
+x = f(2,3)
101
+assert(x[1] == 2 and x[2] == 3 and x[3] == nil)
102
+
103
+
104
+f = loadstring[[
105
+  local x = {...}
106
+  for i=1,select('#', ...) do assert(x[i] == select(i, ...)) end
107
+  assert(x[select('#', ...)+1] == nil)
108
+  return true
109
+]]
110
+
111
+assert(f("a", "b", nil, {}, assert))
112
+assert(f())
113
+
114
+a = {select(3, unpack{10,20,30,40})}
115
+assert(table.getn(a) == 2 and a[1] == 30 and a[2] == 40)
116
+a = {select(1)}
117
+assert(next(a) == nil)
118
+a = {select(-1, 3, 5, 7)}
119
+assert(a[1] == 7 and a[2] == nil)
120
+a = {select(-2, 3, 5, 7)}
121
+assert(a[1] == 5 and a[2] == 7 and a[3] == nil)
122
+pcall(select, 10000)
123
+pcall(select, -10000)
124
+
125
+print('OK')
126
+