summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md4
-rw-r--r--src/lapi.js10
-rw-r--r--src/lbaselib.js28
-rw-r--r--tests/lbaselib.js47
4 files changed, 86 insertions, 3 deletions
diff --git a/README.md b/README.md
index 3174ecb..75768b7 100644
--- a/README.md
+++ b/README.md
@@ -76,6 +76,7 @@
- [x] lua_remove
- [x] lua_rotate
- [x] lua_insert
+ - [x] lua_stringtonumber
- [ ] lua_arith
- [ ] lua_close
- [ ] lua_compare
@@ -129,7 +130,6 @@
- [ ] lua_setupvalue
- [ ] lua_setuservalue
- [ ] lua_status
- - [ ] lua_stringtonumber
- [ ] lua_tocfunction
- [ ] lua_tothread
- [ ] lua_touserdata
@@ -214,11 +214,11 @@
- [x] collectgarbage (unavailable)
- [x] ipairs
- [x] select
+ - [x] tonumber
- [ ] assert
- [ ] next
- [ ] pairs
- [ ] rawlen
- - [ ] tonumber
- [ ] dofile
- [ ] loadfile
- [ ] load
diff --git a/src/lapi.js b/src/lapi.js
index bc4dd54..19e3090 100644
--- a/src/lapi.js
+++ b/src/lapi.js
@@ -488,6 +488,13 @@ const lua_topointer = function(L, idx) {
}
};
+const lua_stringtonumber = function(L, s) {
+ let number = parseFloat(s);
+ L.stack[L.top++] = new TValue(number % 1 !== 0 ? CT.LUA_TNUMFLT : CT.LUA_TNUMINT, number);
+ assert(L.top <= L.ci.top, "stack overflow");
+ return s.length;
+};
+
const f_call = function(L, ud) {
ldo.luaD_callnoyield(L, ud.funcOff, ud.nresults);
};
@@ -705,4 +712,5 @@ module.exports.lua_error = lua_error;
module.exports.lua_insert = lua_insert;
module.exports.lua_gc = lua_gc;
module.exports.lua_getallocf = lua_getallocf;
-module.exports.lua_getextraspace = lua_getextraspace; \ No newline at end of file
+module.exports.lua_getextraspace = lua_getextraspace;
+module.exports.lua_stringtonumber = lua_stringtonumber; \ No newline at end of file
diff --git a/src/lbaselib.js b/src/lbaselib.js
index 19a990e..9cc4fb1 100644
--- a/src/lbaselib.js
+++ b/src/lbaselib.js
@@ -127,6 +127,33 @@ const luaB_ipairs = function(L) {
return 3;
};
+const luaB_tonumber = function(L) {
+ if (lapi.lua_type(L, 2) <= 0) { /* standard conversion? */
+ lauxlib.luaL_checkany(L, 1);
+ if (lapi.lua_type(L, 1) === CT.LUA_TNUMBER) { /* already a number? */
+ lapi.lua_settop(L, 1);
+ return 1;
+ } else {
+ let s = lapi.lua_tostring(L, 1);
+ if (s !== null && lapi.lua_stringtonumber(L, s) === s.length)
+ return 1; /* successful conversion to number */
+ }
+ } else {
+ let base = lauxlib.luaL_checkinteger(L, 2);
+ lauxlib.luaL_checktype(L, 1, CT.LUA_TSTRING); /* no numbers as strings */
+ let s = lapi.lua_tostring(L, 1);
+ lauxlib.luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range");
+ let n = parseInt(s, base);
+ if (!isNaN(n)) {
+ lapi.lua_pushinteger(L, n);
+ return 1;
+ }
+ }
+
+ lapi.lua_pushnil(L);
+ return 1;
+};
+
const luaB_error = function(L) {
let level = lauxlib.luaL_optinteger(L, 2, 1);
lapi.lua_settop(L, 1);
@@ -195,6 +222,7 @@ const base_funcs = {
"collectgarbage": function () {},
"print": luaB_print,
"tostring": luaB_tostring,
+ "tonumber": luaB_tonumber,
"getmetatable": luaB_getmetatable,
"ipairs": luaB_ipairs,
"select": luaB_select,
diff --git a/tests/lbaselib.js b/tests/lbaselib.js
index 73d13a3..6dc6bfb 100644
--- a/tests/lbaselib.js
+++ b/tests/lbaselib.js
@@ -442,4 +442,51 @@ test('select', function (t) {
[2, 3],
"Correct element(s) on the stack"
);
+});
+
+
+test('tonumber', function (t) {
+ let luaCode = `
+ return tonumber('123'), tonumber('12.3'), tonumber('az', 36), tonumber('10', 2)
+ `, L;
+
+ t.plan(5);
+
+ t.doesNotThrow(function () {
+
+ let bc = toByteCode(luaCode).dataView;
+
+ L = lauxlib.luaL_newstate();
+
+ linit.luaL_openlibs(L);
+
+ lapi.lua_load(L, bc, "test-tonumber");
+
+ lapi.lua_call(L, 0, -1);
+
+ }, "JS Lua program ran without error");
+
+ t.strictEqual(
+ lapi.lua_tonumber(L, -4),
+ 123,
+ "Correct element(s) on the stack"
+ );
+
+ t.strictEqual(
+ lapi.lua_tonumber(L, -3),
+ 12.3,
+ "Correct element(s) on the stack"
+ );
+
+ t.strictEqual(
+ lapi.lua_tonumber(L, -2),
+ 395,
+ "Correct element(s) on the stack"
+ );
+
+ t.strictEqual(
+ lapi.lua_tonumber(L, -1),
+ 2,
+ "Correct element(s) on the stack"
+ );
}); \ No newline at end of file