From 94a301a27a8a75c4684790a99a898262b8354f68 Mon Sep 17 00:00:00 2001
From: Benoit Giannangeli <giann008@gmail.com>
Date: Sun, 26 Feb 2017 15:13:22 +0100
Subject: math.random/randomseed

---
 src/lapi.js     |   2 +-
 src/lmathlib.js | 134 +++++++++++++++++++++++++++++++++++++++++++-------------
 src/luaconf.js  |   5 ++-
 src/lvm.js      |   2 +-
 4 files changed, 108 insertions(+), 35 deletions(-)

(limited to 'src')

diff --git a/src/lapi.js b/src/lapi.js
index 4eb55cd..d0c099f 100644
--- a/src/lapi.js
+++ b/src/lapi.js
@@ -545,7 +545,7 @@ const lua_topointer = function(L, idx) {
 
 const lua_compare = function(L, index1, index2, op) {
     let o1 = index2addr(L, index1);
-    let o2 = index2addr(L, index1);
+    let o2 = index2addr(L, index2);
 
     return lua_compare_(L, o1, o2, op);
 };
diff --git a/src/lmathlib.js b/src/lmathlib.js
index f4cc978..54bdc46 100644
--- a/src/lmathlib.js
+++ b/src/lmathlib.js
@@ -1,18 +1,55 @@
 /* jshint esversion: 6 */
 "use strict";
 
-const assert  = require('assert');
+const assert     = require('assert');
+const seedrandom = require('seedrandom');
 
-const lua     = require('./lua.js');
-const lapi    = require('./lapi.js');
-const lauxlib = require('./lauxlib.js');
-const lstate  = require('./lstate.js');
-const ldo     = require('./ldo.js');
-const ldebug  = require('./ldebug.js');
-const llimit  = require('./llimit.js');
-const CT      = lua.constant_types;
-const TS      = lua.thread_status;
+const lua        = require('./lua.js');
+const lapi       = require('./lapi.js');
+const lauxlib    = require('./lauxlib.js');
+const lstate     = require('./lstate.js');
+const ldo        = require('./ldo.js');
+const ldebug     = require('./ldebug.js');
+const llimit     = require('./llimit.js');
+const luaconf    = require('./luaconf.js');
+const CT         = lua.constant_types;
+const TS         = lua.thread_status;
 
+var RNG          = seedrandom();
+
+const math_randomseed = function(L) {
+    RNG = seedrandom(Math.abs(lauxlib.luaL_checknumber(L, 1)));
+};
+
+const math_random = function(L) {
+    let low, up;
+    let r = RNG();
+    switch (lapi.lua_gettop(L)) {  /* check number of arguments */
+        case 0:
+            lapi.lua_pushnumber(L, r);  /* Number between 0 and 1 */
+            return 1;
+        case 1: {
+            low = 1;
+            up = lauxlib.luaL_checkinteger(L, 1);
+            break;
+        }
+        case 2: {
+            low = lauxlib.luaL_checkinteger(L, 1);
+            up = lauxlib.luaL_checkinteger(L, 2);
+            break;
+        }
+        default: return lauxlib.luaL_error(L, "wrong number of arguments");
+    }
+
+    /* random integer in the interval [low, up] */
+    lauxlib.luaL_argcheck(L, low <= up, 1, "interval is empty");
+    lauxlib.luaL_argcheck(L, low >= 0 || up <= Number.MAX_SAFE_INTEGER + low, 1,
+            "interval too large");
+
+    r *= (up - low) + 1;
+    lapi.lua_pushinteger(L, r + low);
+    return 1;
+};
 
 const math_abs = function(L) {
     if (lapi.lua_isinteger(L, 1))
@@ -53,7 +90,7 @@ const math_atan = function(L) {
 };
 
 const math_toint = function(L) {
-    let n = lapi.lua_tointegerx(L, 1)
+    let n = lapi.lua_tointegerx(L, 1);
     if (n !== false)
         lapi.lua_pushinteger(L, n);
     else {
@@ -91,6 +128,7 @@ const math_ceil = function(L) {
 
 const math_sqrt = function(L) {
     lapi.lua_pushnumber(L, Math.sqrt(lauxlib.luaL_checknumber(L, 1)));
+    return 1;
 };
 
 const math_ult = function(L) {
@@ -102,6 +140,7 @@ const math_ult = function(L) {
 
 const math_log = function(L) {
     let x = lauxlib.luaL_checknumber(L, 1);
+    let res;
     if (lapi.lua_isnoneornil(L, 2))
         res = Math.log(x);
     else {
@@ -129,6 +168,7 @@ const math_deg = function(L) {
 
 const math_rad = function(L) {
     lapi.lua_pushnumber(L, lauxlib.luaL_checknumber(L, 1) * (Math.PI / 180));
+    return 1;
 };
 
 const math_min = function(L) {
@@ -168,27 +208,59 @@ const math_type = function(L) {
     return 1;
 };
 
+const math_fmod = function(L) {
+    if (lapi.lua_isinteger(L, 1) && lapi.lua_isinteger(L, 2)) {
+        let d = lapi.lua_tointeger(L, 2);
+        if (Math.abs(d) + 1 <= 1) {
+            lauxlib.luaL_argcheck(L, d !== 0, 2, "zero");
+            lapi.lua_pushinteger(L, 0);
+        } else
+            lapi.lua_pushinteger(L, lapi.lua_tointeger(L, 1) % d);
+    } else {
+        let a = lauxlib.luaL_checknumber(L, 1);
+        let b = lauxlib.luaL_checknumber(L, 2);
+        lapi.lua_pushnumber(L, Number((a - (Math.floor(a / b) * b)).toPrecision(8)));
+    }
+    return 1;
+};
+
+const math_modf = function(L) {
+    if (lapi.lua_isinteger(L, 1)) {
+        lapi.lua_settop(L, 1);  /* number is its own integer part */
+        lapi.lua_pushnumber(L, 0);  /* no fractional part */
+    } else {
+        let n = lauxlib.luaL_checknumber(L, 1);
+        let ip = n < 0 ? Math.ceil(n) : Math.floor(n);
+        pushnumint(L, ip);
+        lapi.lua_pushnumber(L, n === ip ? 0 : n - ip);
+    }
+    return 2;
+};
+
 const mathlib = {
-    "abs":       math_abs,
-    "acos":      math_acos,
-    "asin":      math_asin,
-    "atan":      math_atan,
-    "ceil":      math_ceil,
-    "cos":       math_cos,
-    "deg":       math_deg,
-    "exp":       math_exp,
-    "floor":     math_floor,
-    "log":       math_log,
-    "max":       math_max,
-    "min":       math_min,
-    "rad":       math_rad,
-    "sin":       math_sin,
-    "sqrt":      math_sqrt,
-    "sqrt":      math_sqrt,
-    "tan":       math_tan,
-    "tointeger": math_toint,
-    "type":      math_type,
-    "ult":       math_ult
+    "abs":        math_abs,
+    "acos":       math_acos,
+    "asin":       math_asin,
+    "atan":       math_atan,
+    "ceil":       math_ceil,
+    "cos":        math_cos,
+    "deg":        math_deg,
+    "exp":        math_exp,
+    "floor":      math_floor,
+    "fmod":       math_fmod,
+    "log":        math_log,
+    "max":        math_max,
+    "min":        math_min,
+    "modf":       math_modf,
+    "rad":        math_rad,
+    "random":     math_random,
+    "randomseed": math_randomseed,
+    "sin":        math_sin,
+    "sqrt":       math_sqrt,
+    "tan":        math_tan,
+    "tointeger":  math_toint,
+    "type":       math_type,
+    "ult":        math_ult
 };
 
 const luaopen_math = function(L) {
diff --git a/src/luaconf.js b/src/luaconf.js
index 7297b28..f0066de 100644
--- a/src/luaconf.js
+++ b/src/luaconf.js
@@ -20,5 +20,6 @@ const lua_numbertointeger = function(n) {
     return n|0;
 };
 
-module.exports.LUAI_MAXSTACK = LUAI_MAXSTACK;
-module.exports.LUA_IDSIZE    = LUA_IDSIZE;
\ No newline at end of file
+module.exports.LUAI_MAXSTACK       = LUAI_MAXSTACK;
+module.exports.LUA_IDSIZE          = LUA_IDSIZE;
+module.exports.lua_numbertointeger = lua_numbertointeger;
\ No newline at end of file
diff --git a/src/lvm.js b/src/lvm.js
index d623a72..d987cc1 100644
--- a/src/lvm.js
+++ b/src/lvm.js
@@ -838,7 +838,7 @@ const luaV_tointeger = function(obj, mode) {
     } else if (obj.ttisinteger()) {
         return obj.value|0;
     } else if (obj.ttisstring()) {
-        return luaV_tointeger(parseFloat(obj.value), mode); // TODO: luaO_str2num
+        return luaV_tointeger(new TValue(CT.LUA_TNUMFLT, parseFloat(obj.value)), mode); // TODO: luaO_str2num
     }
 
     return false;
-- 
cgit v1.2.3-70-g09d2