aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilipp Janda <siffiejoe@gmx.net>2015-01-17 20:36:32 +0100
committerPhilipp Janda <siffiejoe@gmx.net>2015-01-17 20:36:32 +0100
commit4c062846ae003dd747dfcd3eca91493c7eee4f50 (patch)
tree583f36eab79954b8bb354d81f4f08cf1472be2b5
parent64783408a4a108812f22268c12f71c75f5399d81 (diff)
downloadlua-compat-5.3-4c062846ae003dd747dfcd3eca91493c7eee4f50.tar.gz
lua-compat-5.3-4c062846ae003dd747dfcd3eca91493c7eee4f50.tar.bz2
lua-compat-5.3-4c062846ae003dd747dfcd3eca91493c7eee4f50.zip
table library (except table.sort for now) respects metamethods
-rw-r--r--README.md5
-rw-r--r--compat53.lua158
-rwxr-xr-xtests/test.lua116
3 files changed, 265 insertions, 14 deletions
diff --git a/README.md b/README.md
index 5adaa38..b788094 100644
--- a/README.md
+++ b/README.md
@@ -66,6 +66,8 @@ your project:
66* `math.maxinteger` and `math.mininteger`, `math.tointeger`, `math.type`, 66* `math.maxinteger` and `math.mininteger`, `math.tointeger`, `math.type`,
67 and `math.ult` 67 and `math.ult`
68* `ipairs` respects `__index` metamethod 68* `ipairs` respects `__index` metamethod
69* `table.move`
70* `table` library (except `table.sort`) respects metamethods
69 71
70### C 72### C
71 73
@@ -112,9 +114,8 @@ For Lua 5.1 additionally:
112 114
113* bit operators 115* bit operators
114* integer division operator 116* integer division operator
115* `table.move`
116* `coroutine.isyieldable` 117* `coroutine.isyieldable`
117* `table` library doesn't respect metamethods yet 118* `table.sort` doesn't respect metamethods yet
118* Lua 5.1: `_ENV`, `goto`, labels, ephemeron tables, etc. See 119* Lua 5.1: `_ENV`, `goto`, labels, ephemeron tables, etc. See
119 [`lua-compat-5.2`][2] for a detailed list. 120 [`lua-compat-5.2`][2] for a detailed list.
120* the following C API functions/macros: 121* the following C API functions/macros:
diff --git a/compat53.lua b/compat53.lua
index 8bf6bd8..761d554 100644
--- a/compat53.lua
+++ b/compat53.lua
@@ -1,12 +1,31 @@
1local lua_version = _VERSION:sub(-3) 1local lua_version = _VERSION:sub(-3)
2 2
3if lua_version ~= "5.3" then 3if lua_version < "5.3" then
4 local _type = type 4 -- local aliases for commonly used functions
5 local type, select, error = type, select, error
6
5 -- select the most powerful getmetatable function available 7 -- select the most powerful getmetatable function available
6 local gmt = _type(debug) == "table" and debug.getmetatable or 8 local gmt = type(debug) == "table" and debug.getmetatable or
7 getmetatable or function() return false end 9 getmetatable or function() return false end
10
11 -- type checking functions
8 local checkinteger -- forward declararation 12 local checkinteger -- forward declararation
9 13
14 local function argcheck(cond, i, f, extra)
15 if not cond then
16 error("bad argument #"..i.." to '"..f.."' ("..extra..")", 0)
17 end
18 end
19
20 local function checktype(x, t, i, f)
21 local xt = type(x)
22 if xt ~= t then
23 error("bad argument #"..i.." to '"..f.."' ("..t..
24 " expected, got "..xt..")", 0)
25 end
26 end
27
28
10 -- load utf8 library 29 -- load utf8 library
11 local ok, utf8lib = pcall(require, "compat53.utf8") 30 local ok, utf8lib = pcall(require, "compat53.utf8")
12 if ok then 31 if ok then
@@ -17,6 +36,7 @@ if lua_version ~= "5.3" then
17 end 36 end
18 end 37 end
19 38
39
20 -- use Roberto's struct module for string packing/unpacking for now 40 -- use Roberto's struct module for string packing/unpacking for now
21 -- maybe we'll later extract the functions from the 5.3 string 41 -- maybe we'll later extract the functions from the 5.3 string
22 -- library for greater compatiblity, but it uses the 5.3 buffer API 42 -- library for greater compatiblity, but it uses the 5.3 buffer API
@@ -47,14 +67,14 @@ if lua_version ~= "5.3" then
47 math.mininteger = minint 67 math.mininteger = minint
48 68
49 function math.tointeger(n) 69 function math.tointeger(n)
50 if _type(n) == "number" and n <= maxint and n >= minint and n % 1 == 0 then 70 if type(n) == "number" and n <= maxint and n >= minint and n % 1 == 0 then
51 return n 71 return n
52 end 72 end
53 return nil 73 return nil
54 end 74 end
55 75
56 function math.type(n) 76 function math.type(n)
57 if _type(n) == "number" then 77 if type(n) == "number" then
58 if n <= maxint and n >= minint and n % 1 == 0 then 78 if n <= maxint and n >= minint and n % 1 == 0 then
59 return "integer" 79 return "integer"
60 else 80 else
@@ -65,15 +85,14 @@ if lua_version ~= "5.3" then
65 end 85 end
66 end 86 end
67 87
68 local _error = error
69 function checkinteger(x, i, f) 88 function checkinteger(x, i, f)
70 local t = _type(x) 89 local t = type(x)
71 if t ~= "number" then 90 if t ~= "number" then
72 _error("bad argument #"..i.." to '"..f.. 91 error("bad argument #"..i.." to '"..f..
73 "' (number expected, got "..t..")", 0) 92 "' (number expected, got "..t..")", 0)
74 elseif x > maxint or x < minint or x % 1 ~= 0 then 93 elseif x > maxint or x < minint or x % 1 ~= 0 then
75 _error("bad argument #"..i.." to '"..f.. 94 error("bad argument #"..i.." to '"..f..
76 "' (number has no integer representation)", 0) 95 "' (number has no integer representation)", 0)
77 else 96 else
78 return x 97 return x
79 end 98 end
@@ -112,6 +131,123 @@ if lua_version ~= "5.3" then
112 end 131 end
113 end 132 end
114 133
134
135 -- update table library
136 do
137 local table_concat = table.concat
138 function table.concat(list, sep, i, j)
139 local mt = gmt(list)
140 if type(mt) == "table" and type(mt.__len) == "function" then
141 local src = list
142 list, i, j = {}, i or 1, j or mt.__len(src)
143 for k = i, j do
144 list[k] = src[k]
145 end
146 end
147 return table_concat(list, sep, i, j)
148 end
149
150 local table_insert = table.insert
151 function table.insert(list, ...)
152 local mt = gmt(list)
153 local has_mt = type(mt) == "table"
154 local has_len = has_mt and type(mt.__len) == "function"
155 if has_mt and (has_len or mt.__index or mt.__newindex) then
156 local e = (has_len and mt.__len(list) or #list)+1
157 local nargs, pos, value = select('#', ...), ...
158 if nargs == 1 then
159 pos, value = e, pos
160 elseif nargs == 2 then
161 pos = checkinteger(pos, "2", "table.insert")
162 argcheck(1 <= pos and pos <= e, "2", "table.insert",
163 "position out of bounds" )
164 else
165 error("wrong number of arguments to 'insert'", 0)
166 end
167 for i = e-1, pos, -1 do
168 list[i+1] = list[i]
169 end
170 list[pos] = value
171 else
172 return table_insert(list, ...)
173 end
174 end
175
176 function table.move(a1, f, e, t, a2)
177 a2 = a2 or a1
178 f = checkinteger(f, "2", "table.move")
179 argcheck(f > 0, "2", "table.move",
180 "initial position must be positive")
181 e = checkinteger(e, "3", "table.move")
182 t = checkinteger(t, "4", "table.move")
183 if e >= f then
184 local m, n, d = 0, e-f, 1
185 if t > f then m, n, d = n, m, -1 end
186 for i = m, n, d do
187 a2[t+i] = a1[f+i]
188 end
189 end
190 return a2
191 end
192
193 local table_remove = table.remove
194 function table.remove(list, pos)
195 local mt = gmt(list)
196 local has_mt = type(mt) == "table"
197 local has_len = has_mt and type(mt.__len) == "function"
198 if has_mt and (has_len or mt.__index or mt.__newindex) then
199 local e = (has_len and mt.__len(list) or #list)
200 pos = pos ~= nil and checkinteger(pos, "2", "table.remove") or e
201 if pos ~= e then
202 argcheck(1 <= pos and pos <= e+1, "2", "table.remove",
203 "position out of bounds" )
204 end
205 local result = list[pos]
206 while pos < e do
207 list[pos] = list[pos+1]
208 pos = pos + 1
209 end
210 list[pos] = nil
211 return result
212 else
213 return table_remove(list, pos)
214 end
215 end
216
217 -- TODO: table.sort
218
219 local table_unpack = lua_version == "5.1" and unpack or table.unpack
220 local function unpack_helper(list, i, j, ...)
221 if j < i then
222 return ...
223 else
224 return unpack_helper(list, i, j-1, list[j], ...)
225 end
226 end
227 function table.unpack(list, i, j)
228 local mt = gmt(list)
229 local has_mt = type(mt) == "table"
230 local has_len = has_mt and type(mt.__len) == "function"
231 if has_mt and (has_len or mt.__index) then
232 i, j = i or 1, j or (has_len and mt.__len(list)) or #list
233 return unpack_helper(list, i, j)
234 else
235 return table_unpack(list, i, j)
236 end
237 end
238 end
239
240
241 if lua_version == "5.1" then
242 -- detect LuaJIT (including LUAJIT_ENABLE_LUA52COMPAT compilation flag)
243 local is_luajit = (string.dump(function() end) or ""):sub(1, 3) == "\027LJ"
244 local is_luajit52 = is_luajit and
245 #setmetatable({}, { __len = function() return 1 end }) == 1
246
247 -- TODO: add functions from lua-compat-5.2
248
249 end
250
115end 251end
116 252
117-- vi: set expandtab softtabstop=3 shiftwidth=3 : 253-- vi: set expandtab softtabstop=3 shiftwidth=3 :
diff --git a/tests/test.lua b/tests/test.lua
index ab25820..7e1c9da 100755
--- a/tests/test.lua
+++ b/tests/test.lua
@@ -1,6 +1,6 @@
1#!/usr/bin/env lua 1#!/usr/bin/env lua
2 2
3local F, ___ 3local F, tproxy, ___
4do 4do
5 local type, unpack = type, table.unpack or unpack 5 local type, unpack = type, table.unpack or unpack
6 function F(...) 6 function F(...)
@@ -13,6 +13,13 @@ do
13 end 13 end
14 return unpack(args, 1, n) 14 return unpack(args, 1, n)
15 end 15 end
16 function tproxy(t)
17 return setmetatable({}, {
18 __index = t,
19 __newindex = t,
20 __len = function() return #t end,
21 }), t
22 end
16 local sep = ("="):rep(70) 23 local sep = ("="):rep(70)
17 function ___() 24 function ___()
18 print(sep) 25 print(sep)
@@ -33,6 +40,113 @@ end
33 40
34 41
35___'' 42___''
43do
44 local p, t = tproxy{ "a", "b", "c" }
45 print("table.concat", table.concat(p))
46 print("table.concat", table.concat(p, ",", 2))
47 print("table.concat", table.concat(p, ".", 1, 2))
48 print("table.concat", table.concat(t))
49 print("table.concat", table.concat(t, ",", 2))
50 print("table.concat", table.concat(t, ".", 1, 2))
51end
52
53
54___''
55do
56 local p, t = tproxy{ "a", "b", "c" }
57 table.insert(p, "d")
58 print("table.insert", next(p), t[4])
59 table.insert(p, 1, "z")
60 print("table.insert", next(p), t[1], t[2])
61 table.insert(p, 2, "y")
62 print("table.insert", next(p), t[1], t[2], p[3])
63 t = { "a", "b", "c" }
64 table.insert(t, "d")
65 print("table.insert", t[1], t[2], t[3], t[4])
66 table.insert(t, 1, "z")
67 print("table.insert", t[1], t[2], t[3], t[4], t[5])
68 table.insert(t, 2, "y")
69 print("table.insert", t[1], t[2], t[3], t[4], t[5])
70end
71
72
73___''
74do
75 local ps, s = tproxy{ "a", "b", "c", "d" }
76 local pd, d = tproxy{ "A", "B", "C", "D" }
77 table.move(ps, 1, 4, 1, pd)
78 print("table.move", next(pd), d[1], d[2], d[3], d[4])
79 pd, d = tproxy{ "A", "B", "C", "D" }
80 table.move(ps, 2, 4, 1, pd)
81 print("table.move", next(pd), d[1], d[2], d[3], d[4])
82 pd, d = tproxy{ "A", "B", "C", "D" }
83 table.move(ps, 2, 3, 4, pd)
84 print("table.move", next(pd), d[1], d[2], d[3], d[4], d[5])
85 table.move(ps, 2, 4, 1)
86 print("table.move", next(ps), s[1], s[2], s[3], s[4])
87 ps, s = tproxy{ "a", "b", "c", "d" }
88 table.move(ps, 2, 3, 4)
89 print("table.move", next(ps), s[1], s[2], s[3], s[4], s[5])
90 s = { "a", "b", "c", "d" }
91 d = { "A", "B", "C", "D" }
92 table.move(s, 1, 4, 1, d)
93 print("table.move", d[1], d[2], d[3], d[4])
94 d = { "A", "B", "C", "D" }
95 table.move(s, 2, 4, 1, d)
96 print("table.move", d[1], d[2], d[3], d[4])
97 d = { "A", "B", "C", "D" }
98 table.move(s, 2, 3, 4, d)
99 print("table.move", d[1], d[2], d[3], d[4], d[5])
100 table.move(s, 2, 4, 1)
101 print("table.move", s[1], s[2], s[3], s[4])
102 s = { "a", "b", "c", "d" }
103 table.move(s, 2, 3, 4)
104 print("table.move", s[1], s[2], s[3], s[4], s[5])
105end
106
107
108___''
109do
110 local p, t = tproxy{ "a", "b", "c", "d", "e" }
111 print("table.remove", table.remove(p))
112 print("table.remove", next(p), t[1], t[2], t[3], t[4], t[5])
113 print("table.remove", table.remove(p, 1))
114 print("table.remove", next(p), t[1], t[2], t[3], t[4])
115 print("table.remove", table.remove(p, 2))
116 print("table.remove", next(p), t[1], t[2], t[3])
117 print("table.remove", table.remove(p, 3))
118 print("table.remove", next(p), t[1], t[2], t[3])
119 p, t = tproxy{}
120 print("table.remove", table.remove(p))
121 print("table.remove", next(p), next(t))
122 t = { "a", "b", "c", "d", "e" }
123 print("table.remove", table.remove(t))
124 print("table.remove", t[1], t[2], t[3], t[4], t[5])
125 print("table.remove", table.remove(t, 1))
126 print("table.remove", t[1], t[2], t[3], t[4])
127 print("table.remove", table.remove(t, 2))
128 print("table.remove", t[1], t[2], t[3])
129 print("table.remove", table.remove(t, 3))
130 print("table.remove", t[1], t[2], t[3])
131 t = {}
132 print("table.remove", table.remove(t))
133 print("table.remove", next(t))
134end
135
136
137___''
138do
139 local p, t = tproxy{ "a", "b", "c" }
140 print("table.unpack", table.unpack(p))
141 print("table.unpack", table.unpack(p, 2))
142 print("table.unpack", table.unpack(p, 1, 2))
143 print("table.unpack", table.unpack(t))
144 print("table.unpack", table.unpack(t, 2))
145 print("table.unpack", table.unpack(t, 1, 2))
146end
147
148
149___''
36print("math.maxinteger", math.maxinteger+1 > math.maxinteger) 150print("math.maxinteger", math.maxinteger+1 > math.maxinteger)
37print("math.mininteger", math.mininteger-1 < math.mininteger) 151print("math.mininteger", math.mininteger-1 < math.mininteger)
38 152