bwcoercion.lua 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. local tonumber, tointeger = tonumber, math.tointeger
  2. local type, getmetatable, rawget, error = type, getmetatable, rawget, error
  3. local strsub = string.sub
  4. local print = print
  5. global none
  6. -- Try to convert a value to an integer, without assuming any coercion.
  7. local function toint (x)
  8. x = tonumber(x) -- handle numerical strings
  9. if not x then
  10. return false -- not coercible to a number
  11. end
  12. return tointeger(x)
  13. end
  14. -- If operation fails, maybe second operand has a metamethod that should
  15. -- have been called if not for this string metamethod, so try to
  16. -- call it.
  17. local function trymt (x, y, mtname)
  18. if type(y) ~= "string" then -- avoid recalling original metamethod
  19. local mt = getmetatable(y)
  20. local mm = mt and rawget(mt, mtname)
  21. if mm then
  22. return mm(x, y)
  23. end
  24. end
  25. -- if any test fails, there is no other metamethod to be called
  26. error("attempt to '" .. strsub(mtname, 3) ..
  27. "' a " .. type(x) .. " with a " .. type(y), 4)
  28. end
  29. local function checkargs (x, y, mtname)
  30. local xi = toint(x)
  31. local yi = toint(y)
  32. if xi and yi then
  33. return xi, yi
  34. else
  35. return trymt(x, y, mtname), nil
  36. end
  37. end
  38. local smt = getmetatable("")
  39. smt.__band = function (x, y)
  40. local x, y = checkargs(x, y, "__band")
  41. return y and x & y or x
  42. end
  43. smt.__bor = function (x, y)
  44. local x, y = checkargs(x, y, "__bor")
  45. return y and x | y or x
  46. end
  47. smt.__bxor = function (x, y)
  48. local x, y = checkargs(x, y, "__bxor")
  49. return y and x ~ y or x
  50. end
  51. smt.__shl = function (x, y)
  52. local x, y = checkargs(x, y, "__shl")
  53. return y and x << y or x
  54. end
  55. smt.__shr = function (x, y)
  56. local x, y = checkargs(x, y, "__shr")
  57. return y and x >> y or x
  58. end
  59. smt.__bnot = function (x)
  60. local x, y = checkargs(x, x, "__bnot")
  61. return y and ~x or x
  62. end