Roger Meier | 6cf0ffc | 2014-04-05 00:45:42 +0200 | [diff] [blame] | 1 | // |
| 2 | // Licensed to the Apache Software Foundation (ASF) under one |
| 3 | // or more contributor license agreements. See the NOTICE file |
| 4 | // distributed with this work for additional information |
| 5 | // regarding copyright ownership. The ASF licenses this file |
| 6 | // to you under the Apache License, Version 2.0 (the |
| 7 | // "License"); you may not use this file except in compliance |
| 8 | // with the License. You may obtain a copy of the License at |
| 9 | // |
| 10 | // http://www.apache.org/licenses/LICENSE-2.0 |
| 11 | // |
| 12 | // Unless required by applicable law or agreed to in writing, |
| 13 | // software distributed under the License is distributed on an |
| 14 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| 15 | // KIND, either express or implied. See the License for the |
| 16 | // specific language governing permissions and limitations |
| 17 | // under the License. |
| 18 | // |
| 19 | |
| 20 | #include <lua.h> |
| 21 | #include <lauxlib.h> |
| 22 | #include <stdlib.h> |
| 23 | #include <math.h> |
| 24 | #include <inttypes.h> |
| 25 | #include <string.h> |
| 26 | |
| 27 | extern const char * LONG_NUM_TYPE; |
| 28 | extern int64_t lualongnumber_checklong(lua_State *L, int index); |
| 29 | extern int64_t lualongnumber_pushlong(lua_State *L, int64_t *val); |
| 30 | |
| 31 | //////////////////////////////////////////////////////////////////////////////// |
| 32 | |
| 33 | static void l_serialize(char *buf, int len, int64_t val) { |
| 34 | snprintf(buf, len, "%"PRId64, val); |
| 35 | } |
| 36 | |
| 37 | static int64_t l_deserialize(const char *buf) { |
| 38 | int64_t data; |
| 39 | int rv; |
| 40 | // Support hex prefixed with '0x' |
| 41 | if (strstr(buf, "0x") == buf) { |
| 42 | rv = sscanf(buf, "%"PRIx64, &data); |
| 43 | } else { |
| 44 | rv = sscanf(buf, "%"PRId64, &data); |
| 45 | } |
| 46 | if (rv == 1) { |
| 47 | return data; |
| 48 | } |
| 49 | return 0; // Failed |
| 50 | } |
| 51 | |
| 52 | //////////////////////////////////////////////////////////////////////////////// |
| 53 | |
| 54 | static int l_new(lua_State *L) { |
| 55 | int64_t val; |
| 56 | const char *str = NULL; |
| 57 | if (lua_type(L, 1) == LUA_TSTRING) { |
| 58 | str = lua_tostring(L, 1); |
| 59 | val = l_deserialize(str); |
| 60 | } else if (lua_type(L, 1) == LUA_TNUMBER) { |
| 61 | val = (int64_t)lua_tonumber(L, 1); |
| 62 | str = (const char *)1; |
| 63 | } |
| 64 | lualongnumber_pushlong(L, (str ? &val : NULL)); |
| 65 | return 1; |
| 66 | } |
| 67 | |
| 68 | //////////////////////////////////////////////////////////////////////////////// |
| 69 | |
| 70 | // a + b |
| 71 | static int l_add(lua_State *L) { |
| 72 | int64_t a, b, c; |
| 73 | a = lualongnumber_checklong(L, 1); |
| 74 | b = lualongnumber_checklong(L, 2); |
| 75 | c = a + b; |
| 76 | lualongnumber_pushlong(L, &c); |
| 77 | return 1; |
| 78 | } |
| 79 | |
| 80 | // a / b |
| 81 | static int l_div(lua_State *L) { |
| 82 | int64_t a, b, c; |
| 83 | a = lualongnumber_checklong(L, 1); |
| 84 | b = lualongnumber_checklong(L, 2); |
| 85 | c = a / b; |
| 86 | lualongnumber_pushlong(L, &c); |
| 87 | return 1; |
| 88 | } |
| 89 | |
| 90 | // a == b (both a and b are lualongnumber's) |
| 91 | static int l_eq(lua_State *L) { |
| 92 | int64_t a, b; |
| 93 | a = lualongnumber_checklong(L, 1); |
| 94 | b = lualongnumber_checklong(L, 2); |
| 95 | lua_pushboolean(L, (a == b ? 1 : 0)); |
| 96 | return 1; |
| 97 | } |
| 98 | |
| 99 | // garbage collection |
| 100 | static int l_gc(lua_State *L) { |
| 101 | lua_pushnil(L); |
| 102 | lua_setmetatable(L, 1); |
| 103 | return 0; |
| 104 | } |
| 105 | |
| 106 | // a < b |
| 107 | static int l_lt(lua_State *L) { |
| 108 | int64_t a, b; |
| 109 | a = lualongnumber_checklong(L, 1); |
| 110 | b = lualongnumber_checklong(L, 2); |
| 111 | lua_pushboolean(L, (a < b ? 1 : 0)); |
| 112 | return 1; |
| 113 | } |
| 114 | |
| 115 | // a <= b |
| 116 | static int l_le(lua_State *L) { |
| 117 | int64_t a, b; |
| 118 | a = lualongnumber_checklong(L, 1); |
| 119 | b = lualongnumber_checklong(L, 2); |
| 120 | lua_pushboolean(L, (a <= b ? 1 : 0)); |
| 121 | return 1; |
| 122 | } |
| 123 | |
| 124 | // a % b |
| 125 | static int l_mod(lua_State *L) { |
| 126 | int64_t a, b, c; |
| 127 | a = lualongnumber_checklong(L, 1); |
| 128 | b = lualongnumber_checklong(L, 2); |
| 129 | c = a % b; |
| 130 | lualongnumber_pushlong(L, &c); |
| 131 | return 1; |
| 132 | } |
| 133 | |
| 134 | // a * b |
| 135 | static int l_mul(lua_State *L) { |
| 136 | int64_t a, b, c; |
| 137 | a = lualongnumber_checklong(L, 1); |
| 138 | b = lualongnumber_checklong(L, 2); |
| 139 | c = a * b; |
| 140 | lualongnumber_pushlong(L, &c); |
| 141 | return 1; |
| 142 | } |
| 143 | |
| 144 | // a ^ b |
| 145 | static int l_pow(lua_State *L) { |
| 146 | long double a, b; |
| 147 | int64_t c; |
| 148 | a = (long double)lualongnumber_checklong(L, 1); |
| 149 | b = (long double)lualongnumber_checklong(L, 2); |
| 150 | c = (int64_t)pow(a, b); |
| 151 | lualongnumber_pushlong(L, &c); |
| 152 | return 1; |
| 153 | } |
| 154 | |
| 155 | // a - b |
| 156 | static int l_sub(lua_State *L) { |
| 157 | int64_t a, b, c; |
| 158 | a = lualongnumber_checklong(L, 1); |
| 159 | b = lualongnumber_checklong(L, 2); |
| 160 | c = a - b; |
| 161 | lualongnumber_pushlong(L, &c); |
| 162 | return 1; |
| 163 | } |
| 164 | |
| 165 | // tostring() |
| 166 | static int l_tostring(lua_State *L) { |
| 167 | int64_t a; |
| 168 | char str[256]; |
| 169 | l_serialize(str, 256, lualongnumber_checklong(L, 1)); |
| 170 | lua_pushstring(L, str); |
| 171 | return 1; |
| 172 | } |
| 173 | |
| 174 | // -a |
| 175 | static int l_unm(lua_State *L) { |
| 176 | int64_t a, c; |
| 177 | a = lualongnumber_checklong(L, 1); |
| 178 | c = -a; |
| 179 | lualongnumber_pushlong(L, &c); |
| 180 | return 1; |
| 181 | } |
| 182 | |
| 183 | //////////////////////////////////////////////////////////////////////////////// |
| 184 | |
| 185 | static const luaL_Reg methods[] = { |
| 186 | {"__add", l_add}, |
| 187 | {"__div", l_div}, |
| 188 | {"__eq", l_eq}, |
| 189 | {"__gc", l_gc}, |
| 190 | {"__lt", l_lt}, |
| 191 | {"__le", l_le}, |
| 192 | {"__mod", l_mod}, |
| 193 | {"__mul", l_mul}, |
| 194 | {"__pow", l_pow}, |
| 195 | {"__sub", l_sub}, |
| 196 | {"__tostring", l_tostring}, |
| 197 | {"__unm", l_unm}, |
| 198 | {NULL, NULL}, |
| 199 | }; |
| 200 | |
| 201 | static const luaL_Reg funcs[] = { |
| 202 | {"new", l_new}, |
| 203 | {NULL, NULL} |
| 204 | }; |
| 205 | |
| 206 | //////////////////////////////////////////////////////////////////////////////// |
| 207 | |
| 208 | static void set_methods(lua_State *L, |
| 209 | const char *metatablename, |
| 210 | const struct luaL_Reg *methods) { |
| 211 | luaL_getmetatable(L, metatablename); // mt |
| 212 | // No need for a __index table since everything is __* |
| 213 | for (; methods->name; methods++) { |
| 214 | lua_pushstring(L, methods->name); // mt, "name" |
| 215 | lua_pushcfunction(L, methods->func); // mt, "name", func |
| 216 | lua_rawset(L, -3); // mt |
| 217 | } |
| 218 | lua_pop(L, 1); |
| 219 | } |
| 220 | |
| 221 | LUALIB_API int luaopen_liblualongnumber(lua_State *L) { |
| 222 | luaL_newmetatable(L, LONG_NUM_TYPE); |
| 223 | lua_pop(L, 1); |
| 224 | set_methods(L, LONG_NUM_TYPE, methods); |
| 225 | |
| 226 | luaL_register(L, "liblualongnumber", funcs); |
| 227 | return 1; |
| 228 | } |