summaryrefslogtreecommitdiff
path: root/testes/bwcoercion.lua
diff options
context:
space:
mode:
Diffstat (limited to 'testes/bwcoercion.lua')
-rw-r--r--testes/bwcoercion.lua78
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 @@
+local tonumber, tointeger = tonumber, math.tointeger
+local type, getmetatable, rawget, error = type, getmetatable, rawget, error
+local strsub = string.sub
+
+local print = print
+
+_ENV = nil
+
+-- Try to convert a value to an integer, without assuming any coercion.
+local function toint (x)
+ x = tonumber(x) -- handle numerical strings
+ if not x then
+ return false -- not coercible to a number
+ end
+ return tointeger(x)
+end
+
+
+-- If operation fails, maybe second operand has a metamethod that should
+-- have been called if not for this string metamethod, so try to
+-- call it.
+local function trymt (x, y, mtname)
+ if type(y) ~= "string" then -- avoid recalling original metamethod
+ local mt = getmetatable(y)
+ local mm = mt and rawget(mt, mtname)
+ if mm then
+ return mm(x, y)
+ end
+ end
+ -- if any test fails, there is no other metamethod to be called
+ error("attempt to '" .. strsub(mtname, 3) ..
+ "' a " .. type(x) .. " with a " .. type(y), 4)
+end
+
+
+local function checkargs (x, y, mtname)
+ local xi = toint(x)
+ local yi = toint(y)
+ if xi and yi then
+ return xi, yi
+ else
+ return trymt(x, y, mtname), nil
+ end
+end
+
+
+local smt = getmetatable("")
+
+smt.__band = function (x, y)
+ local x, y = checkargs(x, y, "__band")
+ return y and x & y or x
+end
+
+smt.__bor = function (x, y)
+ local x, y = checkargs(x, y, "__bor")
+ return y and x | y or x
+end
+
+smt.__bxor = function (x, y)
+ local x, y = checkargs(x, y, "__bxor")
+ return y and x ~ y or x
+end
+
+smt.__shl = function (x, y)
+ local x, y = checkargs(x, y, "__shl")
+ return y and x << y or x
+end
+
+smt.__shr = function (x, y)
+ local x, y = checkargs(x, y, "__shr")
+ return y and x >> y or x
+end
+
+smt.__bnot = function (x)
+ local x, y = checkargs(x, x, "__bnot")
+ return y and ~x or x
+end
+