neyuki 0.1.1

A small Lua-like scripting language implemented in Rust
local table = require("@neyuki/table")

local math = {}

function checkNumber(n: number, name: string)
    if (n == nil) then error(name .. " must be provided") end
    if (type(n) != "number") then error(name .. " must be a number") end
end


function math.sqrt(n: number): number
    checkNumber(n, "number")
    if (n < 0) then error("n must be non-negative") end

    return __sqrt(n)
end

math.huge = 1 / 0
math.phi = (1 + math.sqrt(5)) / 2
math.e = 2.71828182845904523536
math.pi = 3.14159265358979323846
math.sqrt2 = math.sqrt(2)
math.tau = 2*math.pi

function math.random(min: number?, max: number?): number
    if (min == nil and max == nil) then
        return __random_float()
    elseif (max == nil) then
        checkNumber(min, "m")
        if (min < 1) then error("m must be greater than or equal to 1") end
        return __random_int(1, min)
    else
        checkNumber(min, "min")
        checkNumber(max, "max")
        if (min > max) then error("min must be less than or equal to max") end
        return __random_int(min, max)
    end
end

function getNumberTable(...: number|{}): {number}
    local t = {}
    local function handle(obj: number|{})
        if type(obj) == "number" then
            table.insert(t, obj)
        elseif type(obj) == "table" then
            for _, n in obj do
                handle(n)
            end
        else
            error("Invalid argument type: " .. type(obj))
        end
    end
    handle({...})
    return t
end

function math.max(n1: number, n2: number, ...: number): number
    local t = getNumberTable(n1, n2, {...})
    local max = t[1]
    for _, n in t do
        if n > max then
            max = n
        end
    end
    return max
end

function math.min(n1: number, n2: number, ...: number): number
    local t = getNumberTable(n1, n2, {...})
    local min = t[1]
    for _, n in t do
        if n < min then
            min = n
        end
    end
    return min
end

function math.exp(n: number): number -- exponent e^n
    if (n == nil) then error("n must be provided") end
    if (type(n) != "number") then error("n must be a number") end

    return math.e ^ n
end

function math.abs(n: number): number
    checkNumber(n, "number")
    if (n < 0) then
        return -n
    else
        return n
    end
end

function math.clamp(n: number, min: number, max: number): number
    checkNumber(n, "number")
    checkNumber(min, "min")
    checkNumber(max, "max")
    if (min > max) then error("min must be less than or equal to max") end
    if (n < min) then
        return min
    elseif (n > max) then
        return max
    else
        return n
    end
end

function math.floor(n: number): int
    checkNumber(n, "number")
    return __floor(n)
end

function math.ceil(n: number): int
    checkNumber(n, "n")
    return __ceil(n)
end

function math.round(n: number): int
    checkNumber(n, "n")
    return __round(n)
end

function math.pow(base: number, exponent: number): number
    checkNumber(base, "base")
    checkNumber(exponent, "exponent")
    return __pow(base, exponent)
end

function math.log(n: number, base: number?): number
    checkNumber(n, "n")
    if (base != nil) then checkNumber(base, "base") end
    return __log(n, base)
end

function math.log10(n: number): number
    checkNumber(n, "n")
    return __log10(n)
end

function math.sin(n: number): number
    checkNumber(n, "n")
    return __sin(n)
end

function math.cos(n: number): number
    checkNumber(n, "n")
    return __cos(n)
end

function math.tan(n: number): number
    checkNumber(n, "n")
    return __tan(n)
end

function math.asin(n: number): number
    checkNumber(n, "n")
    return __asin(n)
end

function math.acos(n: number): number
    checkNumber(n, "n")
    return __acos(n)
end

function math.atan(n: number): number
    checkNumber(n, "n")
    return __atan(n)
end

function math.atan2(y: number, x: number): number
    checkNumber(y, "y")
    checkNumber(x, "x")
    return __atan2(y, x)
end

function math.sinh(n: number): number
    checkNumber(n, "n")
    return __sinh(n)
end

function math.cosh(n: number): number
    checkNumber(n, "n")
    return __cosh(n)
end

function math.tanh(n: number): number
    checkNumber(n, "n")
    return __tanh(n)
end

function math.deg(radians: number): number
    checkNumber(radians, "radians")
    return radians * (180 / math.pi)
end

function math.rad(degrees: number): number
    checkNumber(degrees, "degrees")
    return degrees * (math.pi / 180)
end

function math.fmod(a: number, b: number): number -- remainder with the sign of a
    checkNumber(a, "a")
    checkNumber(b, "b")
    return __fmod(a, b)
end

function math.modf(n: number): (number, number) -- integral part, fractional part
    checkNumber(n, "n")
    return __modf(n)
end

function math.frexp(n: number): (number, int) -- mantissa in [0.5, 1) and exponent, n = m * 2^e
    checkNumber(n, "n")
    return __frexp(n)
end

function math.ldexp(mantissa: number, exponent: int): number -- mantissa * 2^exponent
    checkNumber(mantissa, "mantissa")
    checkNumber(exponent, "exponent")
    return __ldexp(mantissa, exponent)
end

function math.isfinite(n: number): bool
    checkNumber(n, "n")
    return __isfinite(n)
end

function math.isinf(n: number): bool
    checkNumber(n, "n")
    return __isinf(n)
end

function math.lerp(a: number, b: number, t: number): number
    checkNumber(a, "a")
    checkNumber(b, "b")
    checkNumber(t, "t")
    return a + (b - a) * t
end

function math.map(n: number, inMin: number, inMax: number, outMin: number, outMax: number): number
    checkNumber(n, "n")
    checkNumber(inMin, "inMin")
    checkNumber(inMax, "inMax")
    checkNumber(outMin, "outMin")
    checkNumber(outMax, "outMax")
    if (inMin == inMax) then error("inMin and inMax must differ") end
    return outMin + (n - inMin) * (outMax - outMin) / (inMax - inMin)
end

function math.noise(x: number, y: number?, z: number?): number -- Perlin noise in roughly [-1, 1]
    checkNumber(x, "x")
    if (y != nil) then checkNumber(y, "y") end
    if (z != nil) then checkNumber(z, "z") end
    return __noise(x, y, z)
end

return table.freeze(math)