MIRROR: javascript for 馃悳's, a tiny runtime with big ambitions
1#include <float.h>
2
3#include "ant.h"
4#include "errors.h"
5#include "internal.h"
6#include "runtime.h"
7
8#include "modules/symbol.h"
9#include "modules/crypto.h"
10
11#if DBL_MANT_DIG >= 64
12#error "Unsupported double mantissa width for Math.random"
13#endif
14
15enum {
16 MATH_RANDOM_MANTISSA_BITS = DBL_MANT_DIG,
17 MATH_RANDOM_DISCARD_BITS = 64 - DBL_MANT_DIG,
18};
19
20static const double math_random_scale =
21 1.0 / (double)(UINT64_C(1) << MATH_RANDOM_MANTISSA_BITS);
22
23static ant_value_t builtin_Math_abs(ant_params_t) {
24 double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]);
25 if (isnan(x)) return tov(JS_NAN);
26 return tov(fabs(x));
27}
28
29static ant_value_t builtin_Math_acos(ant_params_t) {
30 double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]);
31 if (isnan(x)) return tov(JS_NAN);
32 return tov(acos(x));
33}
34
35static ant_value_t builtin_Math_acosh(ant_params_t) {
36 double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]);
37 if (isnan(x)) return tov(JS_NAN);
38 return tov(acosh(x));
39}
40
41static ant_value_t builtin_Math_asin(ant_params_t) {
42 double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]);
43 if (isnan(x)) return tov(JS_NAN);
44 return tov(asin(x));
45}
46
47static ant_value_t builtin_Math_asinh(ant_params_t) {
48 double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]);
49 if (isnan(x)) return tov(JS_NAN);
50 return tov(asinh(x));
51}
52
53static ant_value_t builtin_Math_atan(ant_params_t) {
54 double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]);
55 if (isnan(x)) return tov(JS_NAN);
56 return tov(atan(x));
57}
58
59static ant_value_t builtin_Math_atanh(ant_params_t) {
60 double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]);
61 if (isnan(x)) return tov(JS_NAN);
62 return tov(atanh(x));
63}
64
65static ant_value_t builtin_Math_atan2(ant_params_t) {
66 double y = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]);
67 double x = (nargs < 2) ? JS_NAN : js_to_number(js, args[1]);
68 if (isnan(y) || isnan(x)) return tov(JS_NAN);
69 return tov(atan2(y, x));
70}
71
72static ant_value_t builtin_Math_cbrt(ant_params_t) {
73 double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]);
74 if (isnan(x)) return tov(JS_NAN);
75 return tov(cbrt(x));
76}
77
78static ant_value_t builtin_Math_ceil(ant_params_t) {
79 double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]);
80 if (isnan(x)) return tov(JS_NAN);
81 return tov(ceil(x));
82}
83
84static ant_value_t builtin_Math_clz32(ant_params_t) {
85 if (nargs < 1) return tov(32);
86 uint32_t n = js_to_uint32(js_to_number(js, args[0]));
87 if (n == 0) return tov(32);
88 int lz = __builtin_clz(n);
89 if (sizeof(unsigned int) > sizeof(uint32_t)) {
90 lz -= (int)((sizeof(unsigned int) - sizeof(uint32_t)) * 8);
91 }
92 return tov((double)lz);
93}
94
95static ant_value_t builtin_Math_cos(ant_params_t) {
96 double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]);
97 if (isnan(x)) return tov(JS_NAN);
98 return tov(cos(x));
99}
100
101static ant_value_t builtin_Math_cosh(ant_params_t) {
102 double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]);
103 if (isnan(x)) return tov(JS_NAN);
104 return tov(cosh(x));
105}
106
107static ant_value_t builtin_Math_exp(ant_params_t) {
108 double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]);
109 if (isnan(x)) return tov(JS_NAN);
110 return tov(exp(x));
111}
112
113static ant_value_t builtin_Math_expm1(ant_params_t) {
114 double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]);
115 if (isnan(x)) return tov(JS_NAN);
116 return tov(expm1(x));
117}
118
119static ant_value_t builtin_Math_floor(ant_params_t) {
120 double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]);
121 if (isnan(x)) return tov(JS_NAN);
122 return tov(floor(x));
123}
124
125static ant_value_t builtin_Math_fround(ant_params_t) {
126 double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]);
127 if (isnan(x)) return tov(JS_NAN);
128 return tov((double)(float)x);
129}
130
131static ant_value_t builtin_Math_hypot(ant_params_t) {
132 if (nargs == 0) return tov(0.0);
133 double acc = 0.0;
134 bool saw_nan = false;
135 for (int i = 0; i < nargs; i++) {
136 double v = js_to_number(js, args[i]);
137 if (isinf(v)) return tov(JS_INF);
138 if (isnan(v)) { saw_nan = true; continue; }
139 acc = hypot(acc, v);
140 }
141 if (saw_nan) return tov(JS_NAN);
142 return tov(acc);
143}
144
145static ant_value_t builtin_Math_imul(ant_params_t) {
146 if (nargs < 2) return tov(0);
147 int32_t a = js_to_int32(js_to_number(js, args[0]));
148 int32_t b = js_to_int32(js_to_number(js, args[1]));
149 return tov((double)((int32_t)((uint32_t)a * (uint32_t)b)));
150}
151
152static ant_value_t builtin_Math_log(ant_params_t) {
153 double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]);
154 if (isnan(x)) return tov(JS_NAN);
155 return tov(log(x));
156}
157
158static ant_value_t builtin_Math_log1p(ant_params_t) {
159 double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]);
160 if (isnan(x)) return tov(JS_NAN);
161 return tov(log1p(x));
162}
163
164static ant_value_t builtin_Math_log10(ant_params_t) {
165 double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]);
166 if (isnan(x)) return tov(JS_NAN);
167 return tov(log10(x));
168}
169
170static ant_value_t builtin_Math_log2(ant_params_t) {
171 double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]);
172 if (isnan(x)) return tov(JS_NAN);
173 return tov(log2(x));
174}
175
176static ant_value_t builtin_Math_max(ant_params_t) {
177 if (nargs == 0) return tov(JS_NEG_INF);
178 double max_val = js_to_number(js, args[0]);
179 if (isnan(max_val)) return tov(JS_NAN);
180 for (int i = 1; i < nargs; i++) {
181 double v = js_to_number(js, args[i]);
182 if (isnan(v)) return tov(JS_NAN);
183 if (v > max_val) { max_val = v; continue; }
184 if (v == 0.0 && max_val == 0.0 && !signbit(v) && signbit(max_val)) max_val = v;
185 }
186 return tov(max_val);
187}
188
189static ant_value_t builtin_Math_min(ant_params_t) {
190 if (nargs == 0) return tov(JS_INF);
191 double min_val = js_to_number(js, args[0]);
192 if (isnan(min_val)) return tov(JS_NAN);
193 for (int i = 1; i < nargs; i++) {
194 double v = js_to_number(js, args[i]);
195 if (isnan(v)) return tov(JS_NAN);
196 if (v < min_val) {
197 min_val = v;
198 continue;
199 }
200 if (v == 0.0
201 && min_val == 0.0
202 && signbit(v)
203 && !signbit(min_val)
204 ) min_val = v;
205 }
206 return tov(min_val);
207}
208
209static ant_value_t builtin_Math_pow(ant_params_t) {
210 double base = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]);
211 double exp = (nargs < 2) ? JS_NAN : js_to_number(js, args[1]);
212 if (isnan(base) || isnan(exp)) return tov(JS_NAN);
213 return tov(pow(base, exp));
214}
215
216static ant_value_t builtin_Math_random(ant_params_t) {
217 uint64_t r = 0;
218 if (crypto_fill_random(&r, sizeof(r)) < 0) {
219 return js_mkerr(js, "secure random generation failed");
220 }
221
222 uint64_t fraction = r >> MATH_RANDOM_DISCARD_BITS;
223 return tov((double)fraction * math_random_scale);
224}
225
226static ant_value_t builtin_Math_round(ant_params_t) {
227 double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]);
228 if (isnan(x) || isinf(x) || x == 0.0) return tov(x);
229 if (x < 0.0 && x >= -0.5) return tov(-0.0);
230 return tov(floor(x + 0.5));
231}
232
233static ant_value_t builtin_Math_sign(ant_params_t) {
234 double v = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]);
235 if (isnan(v)) return tov(JS_NAN);
236 if (v > 0) return tov(1.0);
237 if (v < 0) return tov(-1.0);
238 return tov(v);
239}
240
241static ant_value_t builtin_Math_sin(ant_params_t) {
242 double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]);
243 if (isnan(x)) return tov(JS_NAN);
244 return tov(sin(x));
245}
246
247static ant_value_t builtin_Math_sinh(ant_params_t) {
248 double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]);
249 if (isnan(x)) return tov(JS_NAN);
250 return tov(sinh(x));
251}
252
253static ant_value_t builtin_Math_sqrt(ant_params_t) {
254 double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]);
255 if (isnan(x)) return tov(JS_NAN);
256 return tov(sqrt(x));
257}
258
259static ant_value_t builtin_Math_tan(ant_params_t) {
260 double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]);
261 if (isnan(x)) return tov(JS_NAN);
262 return tov(tan(x));
263}
264
265static ant_value_t builtin_Math_tanh(ant_params_t) {
266 double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]);
267 if (isnan(x)) return tov(JS_NAN);
268 return tov(tanh(x));
269}
270
271static ant_value_t builtin_Math_trunc(ant_params_t) {
272 double x = (nargs < 1) ? JS_NAN : js_to_number(js, args[0]);
273 if (isnan(x)) return tov(JS_NAN);
274 return tov(trunc(x));
275}
276
277void init_math_module(void) {
278 ant_t *js = rt->js;
279
280 ant_value_t glob = js_glob(js);
281 ant_value_t math_obj = mkobj(js, 0);
282 ant_value_t object_proto = js->sym.object_proto;
283
284 js_set_proto_init(math_obj, object_proto);
285 js_setprop(js, math_obj, js_mkstr(js, "E", 1), tov(M_E));
286 js_setprop(js, math_obj, js_mkstr(js, "LN10", 4), tov(M_LN10));
287 js_setprop(js, math_obj, js_mkstr(js, "LN2", 3), tov(M_LN2));
288 js_setprop(js, math_obj, js_mkstr(js, "LOG10E", 6), tov(M_LOG10E));
289 js_setprop(js, math_obj, js_mkstr(js, "LOG2E", 5), tov(M_LOG2E));
290 js_setprop(js, math_obj, js_mkstr(js, "PI", 2), tov(M_PI));
291 js_setprop(js, math_obj, js_mkstr(js, "SQRT1_2", 7), tov(M_SQRT1_2));
292 js_setprop(js, math_obj, js_mkstr(js, "SQRT2", 5), tov(M_SQRT2));
293 js_setprop(js, math_obj, js_mkstr(js, "abs", 3), js_mkfun(builtin_Math_abs));
294 js_setprop(js, math_obj, js_mkstr(js, "acos", 4), js_mkfun(builtin_Math_acos));
295 js_setprop(js, math_obj, js_mkstr(js, "acosh", 5), js_mkfun(builtin_Math_acosh));
296 js_setprop(js, math_obj, js_mkstr(js, "asin", 4), js_mkfun(builtin_Math_asin));
297 js_setprop(js, math_obj, js_mkstr(js, "asinh", 5), js_mkfun(builtin_Math_asinh));
298 js_setprop(js, math_obj, js_mkstr(js, "atan", 4), js_mkfun(builtin_Math_atan));
299 js_setprop(js, math_obj, js_mkstr(js, "atanh", 5), js_mkfun(builtin_Math_atanh));
300 js_setprop(js, math_obj, js_mkstr(js, "atan2", 5), js_mkfun(builtin_Math_atan2));
301 js_setprop(js, math_obj, js_mkstr(js, "cbrt", 4), js_mkfun(builtin_Math_cbrt));
302 js_setprop(js, math_obj, js_mkstr(js, "ceil", 4), js_mkfun(builtin_Math_ceil));
303 js_setprop(js, math_obj, js_mkstr(js, "clz32", 5), js_mkfun(builtin_Math_clz32));
304 js_setprop(js, math_obj, js_mkstr(js, "cos", 3), js_mkfun(builtin_Math_cos));
305 js_setprop(js, math_obj, js_mkstr(js, "cosh", 4), js_mkfun(builtin_Math_cosh));
306 js_setprop(js, math_obj, js_mkstr(js, "exp", 3), js_mkfun(builtin_Math_exp));
307 js_setprop(js, math_obj, js_mkstr(js, "expm1", 5), js_mkfun(builtin_Math_expm1));
308 js_setprop(js, math_obj, js_mkstr(js, "floor", 5), js_mkfun(builtin_Math_floor));
309 js_setprop(js, math_obj, js_mkstr(js, "fround", 6), js_mkfun(builtin_Math_fround));
310 js_setprop(js, math_obj, js_mkstr(js, "hypot", 5), js_mkfun(builtin_Math_hypot));
311 js_setprop(js, math_obj, js_mkstr(js, "imul", 4), js_mkfun(builtin_Math_imul));
312 js_setprop(js, math_obj, js_mkstr(js, "log", 3), js_mkfun(builtin_Math_log));
313 js_setprop(js, math_obj, js_mkstr(js, "log1p", 5), js_mkfun(builtin_Math_log1p));
314 js_setprop(js, math_obj, js_mkstr(js, "log10", 5), js_mkfun(builtin_Math_log10));
315 js_setprop(js, math_obj, js_mkstr(js, "log2", 4), js_mkfun(builtin_Math_log2));
316 js_setprop(js, math_obj, js_mkstr(js, "max", 3), js_mkfun(builtin_Math_max));
317 js_setprop(js, math_obj, js_mkstr(js, "min", 3), js_mkfun(builtin_Math_min));
318 js_setprop(js, math_obj, js_mkstr(js, "pow", 3), js_mkfun(builtin_Math_pow));
319 js_setprop(js, math_obj, js_mkstr(js, "random", 6), js_mkfun(builtin_Math_random));
320 js_setprop(js, math_obj, js_mkstr(js, "round", 5), js_mkfun(builtin_Math_round));
321 js_setprop(js, math_obj, js_mkstr(js, "sign", 4), js_mkfun(builtin_Math_sign));
322 js_setprop(js, math_obj, js_mkstr(js, "sin", 3), js_mkfun(builtin_Math_sin));
323 js_setprop(js, math_obj, js_mkstr(js, "sinh", 4), js_mkfun(builtin_Math_sinh));
324 js_setprop(js, math_obj, js_mkstr(js, "sqrt", 4), js_mkfun(builtin_Math_sqrt));
325 js_setprop(js, math_obj, js_mkstr(js, "tan", 3), js_mkfun(builtin_Math_tan));
326 js_setprop(js, math_obj, js_mkstr(js, "tanh", 4), js_mkfun(builtin_Math_tanh));
327 js_setprop(js, math_obj, js_mkstr(js, "trunc", 5), js_mkfun(builtin_Math_trunc));
328
329 js_set_sym(js, math_obj, get_toStringTag_sym(), js_mkstr(js, "Math", 4));
330 js_setprop(js, glob, js_mkstr(js, "Math", 4), math_obj);
331}