forked from purescript/purescript-integers
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathInt.lua
More file actions
105 lines (103 loc) · 3.29 KB
/
Copy pathInt.lua
File metadata and controls
105 lines (103 loc) · 3.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
-- Shared helpers for the Data.Int FFI. PureScript Int is 32-bit two's
-- complement; these mirror the JS semantics the upstream FFI relies on.
-- JS ToInt32: truncate toward zero, then wrap to signed 32-bit.
local function toInt32(n)
n = math.modf(n)
n = n % 0x100000000
if n >= 0x80000000 then n = n - 0x100000000 end
return n
end
-- Value of a single base-36 digit (0-9, a-z / A-Z), or nil if not a digit.
local function digitValue(c)
local b = c:byte()
if b >= 48 and b <= 57 then return b - 48 end
if b >= 97 and b <= 122 then return b - 97 + 10 end
if b >= 65 and b <= 90 then return b - 65 + 10 end
return nil
end
return {
fromNumberImpl = (function(just)
return function(nothing)
return function(n)
-- Just only for an integral value inside the Int32 range (JS:
-- `(n | 0) === n ? just(n) : nothing`); otherwise Nothing.
local i = math.modf(n)
if i == n and n >= -2147483648 and n <= 2147483647 then return just(n) end
return nothing
end
end
end),
toNumber = (function(n) return n end),
fromStringAsImpl = (function(just)
return function(nothing)
return function(radix)
return function(s)
-- Mirror the JS regex `^[+-]?<digits>+$` + Int32 range check:
-- parse the sign ourselves (Lua 5.1 `tonumber` mishandles a leading
-- '-' in non-decimal bases) and reject any illegal digit, fractional
-- point, or surrounding whitespace that `tonumber` would tolerate.
local sign, body = 1, s
local first = s:sub(1, 1)
if first == "-" then
sign, body = -1, s:sub(2)
elseif first == "+" then
body = s:sub(2)
end
if #body == 0 then return nothing end
local n = 0
for i = 1, #body do
local d = digitValue(body:sub(i, i))
if d == nil or d >= radix then return nothing end
n = n * radix + d
end
n = sign * n
if n < -2147483648 or n > 2147483647 then return nothing end
return just(n)
end
end
end
end),
toStringAs = (function(radix)
return function(i)
local floor, insert = math.floor, table.insert
local n = floor(i)
if radix == 10 then return tostring(n) end
-- JS Number.prototype.toString(radix) uses lowercase digits.
local digits = "0123456789abcdefghijklmnopqrstuvwxyz"
local t = {}
local sign = ""
if n < 0 then
sign = "-"
n = -n
end
repeat
local d = (n % radix) + 1
n = floor(n / radix)
insert(t, 1, digits:sub(d, d))
until n == 0
return sign .. table.concat(t, "")
end
end),
quot = (function(x)
return function(y)
if y == 0 then return 0 end
local q, _ = math.modf(x / y)
return q
end
end),
rem = (function(x)
return function(y)
-- Truncated remainder with the sign of the dividend (JS `x % y`),
-- consistent with `quot`; Lua's `%` is floored and differs in sign.
if y == 0 then return 0 end
local q = math.modf(x / y)
return x - q * y
end
end),
pow = (function(x)
return function(y)
-- JS `Math.pow(x, y) | 0`: truncate toward zero and wrap to Int32.
return toInt32(math.pow(x, y))
end
end)
}