diff options
Diffstat (limited to 'testes/bwcoercion.lua')
-rw-r--r-- | testes/bwcoercion.lua | 78 |
1 files changed, 78 insertions, 0 deletions
diff --git a/testes/bwcoercion.lua b/testes/bwcoercion.lua new file mode 100644 index 00000000..cd735ab0 --- /dev/null +++ b/testes/bwcoercion.lua | |||
@@ -0,0 +1,78 @@ | |||
1 | local tonumber, tointeger = tonumber, math.tointeger | ||
2 | local type, getmetatable, rawget, error = type, getmetatable, rawget, error | ||
3 | local strsub = string.sub | ||
4 | |||
5 | local print = print | ||
6 | |||
7 | _ENV = nil | ||
8 | |||
9 | -- Try to convert a value to an integer, without assuming any coercion. | ||
10 | local function toint (x) | ||
11 | x = tonumber(x) -- handle numerical strings | ||
12 | if not x then | ||
13 | return false -- not coercible to a number | ||
14 | end | ||
15 | return tointeger(x) | ||
16 | end | ||
17 | |||
18 | |||
19 | -- If operation fails, maybe second operand has a metamethod that should | ||
20 | -- have been called if not for this string metamethod, so try to | ||
21 | -- call it. | ||
22 | local function trymt (x, y, mtname) | ||
23 | if type(y) ~= "string" then -- avoid recalling original metamethod | ||
24 | local mt = getmetatable(y) | ||
25 | local mm = mt and rawget(mt, mtname) | ||
26 | if mm then | ||
27 | return mm(x, y) | ||
28 | end | ||
29 | end | ||
30 | -- if any test fails, there is no other metamethod to be called | ||
31 | error("attempt to '" .. strsub(mtname, 3) .. | ||
32 | "' a " .. type(x) .. " with a " .. type(y), 4) | ||
33 | end | ||
34 | |||
35 | |||
36 | local function checkargs (x, y, mtname) | ||
37 | local xi = toint(x) | ||
38 | local yi = toint(y) | ||
39 | if xi and yi then | ||
40 | return xi, yi | ||
41 | else | ||
42 | return trymt(x, y, mtname), nil | ||
43 | end | ||
44 | end | ||
45 | |||
46 | |||
47 | local smt = getmetatable("") | ||
48 | |||
49 | smt.__band = function (x, y) | ||
50 | local x, y = checkargs(x, y, "__band") | ||
51 | return y and x & y or x | ||
52 | end | ||
53 | |||
54 | smt.__bor = function (x, y) | ||
55 | local x, y = checkargs(x, y, "__bor") | ||
56 | return y and x | y or x | ||
57 | end | ||
58 | |||
59 | smt.__bxor = function (x, y) | ||
60 | local x, y = checkargs(x, y, "__bxor") | ||
61 | return y and x ~ y or x | ||
62 | end | ||
63 | |||
64 | smt.__shl = function (x, y) | ||
65 | local x, y = checkargs(x, y, "__shl") | ||
66 | return y and x << y or x | ||
67 | end | ||
68 | |||
69 | smt.__shr = function (x, y) | ||
70 | local x, y = checkargs(x, y, "__shr") | ||
71 | return y and x >> y or x | ||
72 | end | ||
73 | |||
74 | smt.__bnot = function (x) | ||
75 | local x, y = checkargs(x, x, "__bnot") | ||
76 | return y and ~x or x | ||
77 | end | ||
78 | |||