diff --git a/client/space_lua/stdlib/math.ts b/client/space_lua/stdlib/math.ts index ce659ebd..bffaf8e5 100644 --- a/client/space_lua/stdlib/math.ts +++ b/client/space_lua/stdlib/math.ts @@ -40,6 +40,27 @@ export const mathApi = new LuaTable({ } return null; }), + + /** + * If the value x is representable as a Lua integer, returns an + * integer with that value. Otherwise returns nil. + */ + tointeger: new LuaBuiltinFunction((_sf, x?: any) => { + if (x === undefined || x === null) return null; + if (typeof x === "number") { + // plain integer + if (Number.isInteger(x)) return x; + return null; + } + if (isTaggedFloat(x)) { + // float with integer value e.g. 3.0 + if (Number.isInteger(x.value)) return x.value; + return null; + } + if (typeof x === "bigint") return x; + return null; + }), + /** * When called without arguments, returns a pseudo-random float with * uniform distribution in the range [0,1). When called with two diff --git a/client/space_lua/stdlib/math_test.lua b/client/space_lua/stdlib/math_test.lua index 921c0ac8..37a877f9 100644 --- a/client/space_lua/stdlib/math_test.lua +++ b/client/space_lua/stdlib/math_test.lua @@ -171,3 +171,29 @@ do assertEquals(f2, 3, "floor(8*0.49)") assertEquals(f3, 4, "floor(9*0.5)") end + +-- math.tointeger +do + -- integers pass through unchanged + assertEquals(math.tointeger(0), 0, "tointeger(0)") + assertEquals(math.tointeger(42), 42, "tointeger(42)") + assertEquals(math.tointeger(-7), -7, "tointeger(-7)") + assertEquals(math.type(math.tointeger(1)), "integer", "tointeger result is integer") + + -- float with whole value yields integer + assertEquals(math.tointeger(3.0), 3, "tointeger(3.0)") + assertEquals(math.tointeger(-1.0), -1, "tointeger(-1.0)") + assertEquals(math.type(math.tointeger(3.0)), "integer", "tointeger(3.0) type") + + -- float with fractional part yields nil + assertEquals(math.tointeger(3.5), nil, "tointeger(3.5)") + assertEquals(math.tointeger(-0.1), nil, "tointeger(-0.1)") + + -- non-numbers yields nil (no error) + assertEquals(math.tointeger("3"), nil, "tointeger(string)") + assertEquals(math.tointeger(nil), nil, "tointeger(nil)") + + -- inf and nan yields nil + assertEquals(math.tointeger(1/0), nil, "tointeger(inf)") + assertEquals(math.tointeger(0/0), nil, "tointeger(nan)") +end