lua

A copy of the Lua development repository
Log | Files | Refs | README

bwcoercion.lua (1791B)


      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