retex-lua 1.0.0

Embedded Lua and the LuaTeX Lua API for retex
Documentation
//! Lua 5.1/5.2 compatibility functions that LuaTeX's Lua 5.3 provides.

use mlua::Lua;

const COMPAT_LUA: &str = include_str!("compat.lua");

/// Installs `unpack`, `loadstring`, `module`, `bit32` and the old `math`
/// functions.
pub fn install(lua: &Lua) -> mlua::Result<()> {
    lua.load(COMPAT_LUA).set_name("=compat").exec()
}

#[cfg(test)]
mod tests {
    fn eval(code: &str) -> String {
        // `module` needs the debug library, which only the host enables.
        let host = crate::LuaTexHost::new().unwrap();
        host.lua().load(code).eval::<String>().unwrap()
    }

    // Expected values observed with texlua (LuaTeX 1.22).
    #[test]
    fn bit32_matches_texlua() {
        let r = eval(
            "local b = bit32
            return table.concat({b.band(0xF0F0,0xFF00), b.bor(1,2,4), b.bxor(5,3), b.bnot(0),
              b.lshift(1,31), b.lshift(1,32), b.rshift(-1,4), b.arshift(0x80000000,4),
              b.arshift(-1,40), b.lrotate(0x80000001,1), b.rrotate(1,1), b.extract(0xABCD,4,8),
              b.replace(0,0xF,8,4), tostring(b.btest(1,2)), b.band(), b.band(2^32+3, 1.0),
              select(2, pcall(b.extract,1,30,4))}, ' ')",
        );
        assert_eq!(
            r,
            "61440 7 6 4294967295 2147483648 0 268435455 4160749568 4294967295 3 \
             2147483648 188 3840 false 4294967295 1 trying to access non-existent bits"
        );
    }

    #[test]
    fn math_and_globals() {
        let r = eval(
            "local m, e = math.frexp(-0.3)
            local z = math.frexp(0)
            return table.concat({math.frexp(8), m, e, z, math.ldexp(0.75,4), math.pow(2,10),
              math.log10(1000), math.cosh(1), unpack({1,2,3}), loadstring('return 7')()}, ' ')",
        );
        assert_eq!(r, "0.5 -0.6 -1 0.0 12.0 1024.0 3.0 1.5430806348152 1 7");
    }

    #[test]
    fn hyperbolic_and_atan2() {
        // Values printed by texlua (LuaTeX 1.22).
        let r = eval(
            "return table.concat({math.atan2(1,2), math.sinh(1), math.tanh(1), math.atan2(1),
              math.tanh(50)}, ' ')",
        );
        assert_eq!(
            r,
            "0.46364760900081 1.1752011936438 0.76159415595576 0.78539816339745 1.0"
        );
    }

    #[test]
    fn module_sets_environment() {
        let r = eval(
            "local chunk = load('module(\"a.b\", package.seeall); x = 1; function f() return x + 1 end')
            chunk()
            return table.concat({a.b.f(), a.b._NAME, a.b._PACKAGE, tostring(package.loaded['a.b'] == a.b),
              tostring(rawget(_G, 'x'))}, ' ')",
        );
        assert_eq!(r, "2 a.b a. true nil");
    }
}