1 package goja
2
3 import (
4 "math"
5 "math/bits"
6 "sync"
7 )
8
9 func (r *Runtime) math_abs(call FunctionCall) Value {
10 return floatToValue(math.Abs(call.Argument(0).ToFloat()))
11 }
12
13 func (r *Runtime) math_acos(call FunctionCall) Value {
14 return floatToValue(math.Acos(call.Argument(0).ToFloat()))
15 }
16
17 func (r *Runtime) math_acosh(call FunctionCall) Value {
18 return floatToValue(math.Acosh(call.Argument(0).ToFloat()))
19 }
20
21 func (r *Runtime) math_asin(call FunctionCall) Value {
22 return floatToValue(math.Asin(call.Argument(0).ToFloat()))
23 }
24
25 func (r *Runtime) math_asinh(call FunctionCall) Value {
26 return floatToValue(math.Asinh(call.Argument(0).ToFloat()))
27 }
28
29 func (r *Runtime) math_atan(call FunctionCall) Value {
30 return floatToValue(math.Atan(call.Argument(0).ToFloat()))
31 }
32
33 func (r *Runtime) math_atanh(call FunctionCall) Value {
34 return floatToValue(math.Atanh(call.Argument(0).ToFloat()))
35 }
36
37 func (r *Runtime) math_atan2(call FunctionCall) Value {
38 y := call.Argument(0).ToFloat()
39 x := call.Argument(1).ToFloat()
40
41 return floatToValue(math.Atan2(y, x))
42 }
43
44 func (r *Runtime) math_cbrt(call FunctionCall) Value {
45 return floatToValue(math.Cbrt(call.Argument(0).ToFloat()))
46 }
47
48 func (r *Runtime) math_ceil(call FunctionCall) Value {
49 return floatToValue(math.Ceil(call.Argument(0).ToFloat()))
50 }
51
52 func (r *Runtime) math_clz32(call FunctionCall) Value {
53 return intToValue(int64(bits.LeadingZeros32(toUint32(call.Argument(0)))))
54 }
55
56 func (r *Runtime) math_cos(call FunctionCall) Value {
57 return floatToValue(math.Cos(call.Argument(0).ToFloat()))
58 }
59
60 func (r *Runtime) math_cosh(call FunctionCall) Value {
61 return floatToValue(math.Cosh(call.Argument(0).ToFloat()))
62 }
63
64 func (r *Runtime) math_exp(call FunctionCall) Value {
65 return floatToValue(math.Exp(call.Argument(0).ToFloat()))
66 }
67
68 func (r *Runtime) math_expm1(call FunctionCall) Value {
69 return floatToValue(math.Expm1(call.Argument(0).ToFloat()))
70 }
71
72 func (r *Runtime) math_floor(call FunctionCall) Value {
73 return floatToValue(math.Floor(call.Argument(0).ToFloat()))
74 }
75
76 func (r *Runtime) math_fround(call FunctionCall) Value {
77 return floatToValue(float64(float32(call.Argument(0).ToFloat())))
78 }
79
80 func (r *Runtime) math_hypot(call FunctionCall) Value {
81 var max float64
82 var hasNaN bool
83 absValues := make([]float64, 0, len(call.Arguments))
84 for _, v := range call.Arguments {
85 arg := nilSafe(v).ToFloat()
86 if math.IsNaN(arg) {
87 hasNaN = true
88 } else {
89 abs := math.Abs(arg)
90 if abs > max {
91 max = abs
92 }
93 absValues = append(absValues, abs)
94 }
95 }
96 if math.IsInf(max, 1) {
97 return _positiveInf
98 }
99 if hasNaN {
100 return _NaN
101 }
102 if max == 0 {
103 return _positiveZero
104 }
105
106
107
108 var sum, compensation float64
109 for _, n := range absValues {
110 n /= max
111 summand := n*n - compensation
112 preliminary := sum + summand
113 compensation = (preliminary - sum) - summand
114 sum = preliminary
115 }
116 return floatToValue(math.Sqrt(sum) * max)
117 }
118
119 func (r *Runtime) math_imul(call FunctionCall) Value {
120 x := toUint32(call.Argument(0))
121 y := toUint32(call.Argument(1))
122 return intToValue(int64(int32(x * y)))
123 }
124
125 func (r *Runtime) math_log(call FunctionCall) Value {
126 return floatToValue(math.Log(call.Argument(0).ToFloat()))
127 }
128
129 func (r *Runtime) math_log1p(call FunctionCall) Value {
130 return floatToValue(math.Log1p(call.Argument(0).ToFloat()))
131 }
132
133 func (r *Runtime) math_log10(call FunctionCall) Value {
134 return floatToValue(math.Log10(call.Argument(0).ToFloat()))
135 }
136
137 func (r *Runtime) math_log2(call FunctionCall) Value {
138 return floatToValue(math.Log2(call.Argument(0).ToFloat()))
139 }
140
141 func (r *Runtime) math_max(call FunctionCall) Value {
142 result := math.Inf(-1)
143 args := call.Arguments
144 for i, arg := range args {
145 n := nilSafe(arg).ToFloat()
146 if math.IsNaN(n) {
147 args = args[i+1:]
148 goto NaNLoop
149 }
150 result = math.Max(result, n)
151 }
152
153 return floatToValue(result)
154
155 NaNLoop:
156
157 for _, arg := range args {
158 nilSafe(arg).ToFloat()
159 }
160 return _NaN
161 }
162
163 func (r *Runtime) math_min(call FunctionCall) Value {
164 result := math.Inf(1)
165 args := call.Arguments
166 for i, arg := range args {
167 n := nilSafe(arg).ToFloat()
168 if math.IsNaN(n) {
169 args = args[i+1:]
170 goto NaNLoop
171 }
172 result = math.Min(result, n)
173 }
174
175 return floatToValue(result)
176
177 NaNLoop:
178
179 for _, arg := range args {
180 nilSafe(arg).ToFloat()
181 }
182 return _NaN
183 }
184
185 func pow(x, y Value) Value {
186 if x, ok := x.(valueInt); ok {
187 if y, ok := y.(valueInt); ok && y >= 0 {
188 if y == 0 {
189 return intToValue(1)
190 }
191 if x == 0 {
192 return intToValue(0)
193 }
194 ip := ipow(int64(x), int64(y))
195 if ip != 0 {
196 return intToValue(ip)
197 }
198 }
199 }
200 xf := x.ToFloat()
201 yf := y.ToFloat()
202 if math.Abs(xf) == 1 && math.IsInf(yf, 0) {
203 return _NaN
204 }
205 if xf == 1 && math.IsNaN(yf) {
206 return _NaN
207 }
208 return floatToValue(math.Pow(xf, yf))
209 }
210
211 func (r *Runtime) math_pow(call FunctionCall) Value {
212 return pow(call.Argument(0), call.Argument(1))
213 }
214
215 func (r *Runtime) math_random(call FunctionCall) Value {
216 return floatToValue(r.rand())
217 }
218
219 func (r *Runtime) math_round(call FunctionCall) Value {
220 f := call.Argument(0).ToFloat()
221 if math.IsNaN(f) {
222 return _NaN
223 }
224
225 if f == 0 && math.Signbit(f) {
226 return _negativeZero
227 }
228
229 t := math.Trunc(f)
230
231 if f >= 0 {
232 if f-t >= 0.5 {
233 return floatToValue(t + 1)
234 }
235 } else {
236 if t-f > 0.5 {
237 return floatToValue(t - 1)
238 }
239 }
240
241 return floatToValue(t)
242 }
243
244 func (r *Runtime) math_sign(call FunctionCall) Value {
245 arg := call.Argument(0)
246 num := arg.ToFloat()
247 if math.IsNaN(num) || num == 0 {
248 return arg
249 }
250 if num > 0 {
251 return intToValue(1)
252 }
253 return intToValue(-1)
254 }
255
256 func (r *Runtime) math_sin(call FunctionCall) Value {
257 return floatToValue(math.Sin(call.Argument(0).ToFloat()))
258 }
259
260 func (r *Runtime) math_sinh(call FunctionCall) Value {
261 return floatToValue(math.Sinh(call.Argument(0).ToFloat()))
262 }
263
264 func (r *Runtime) math_sqrt(call FunctionCall) Value {
265 return floatToValue(math.Sqrt(call.Argument(0).ToFloat()))
266 }
267
268 func (r *Runtime) math_tan(call FunctionCall) Value {
269 return floatToValue(math.Tan(call.Argument(0).ToFloat()))
270 }
271
272 func (r *Runtime) math_tanh(call FunctionCall) Value {
273 return floatToValue(math.Tanh(call.Argument(0).ToFloat()))
274 }
275
276 func (r *Runtime) math_trunc(call FunctionCall) Value {
277 arg := call.Argument(0)
278 if i, ok := arg.(valueInt); ok {
279 return i
280 }
281 return floatToValue(math.Trunc(arg.ToFloat()))
282 }
283
284 func createMathTemplate() *objectTemplate {
285 t := newObjectTemplate()
286 t.protoFactory = func(r *Runtime) *Object {
287 return r.global.ObjectPrototype
288 }
289
290 t.putStr("E", func(r *Runtime) Value { return valueProp(valueFloat(math.E), false, false, false) })
291 t.putStr("LN10", func(r *Runtime) Value { return valueProp(valueFloat(math.Ln10), false, false, false) })
292 t.putStr("LN2", func(r *Runtime) Value { return valueProp(valueFloat(math.Ln2), false, false, false) })
293 t.putStr("LOG10E", func(r *Runtime) Value { return valueProp(valueFloat(math.Log10E), false, false, false) })
294 t.putStr("LOG2E", func(r *Runtime) Value { return valueProp(valueFloat(math.Log2E), false, false, false) })
295 t.putStr("PI", func(r *Runtime) Value { return valueProp(valueFloat(math.Pi), false, false, false) })
296 t.putStr("SQRT1_2", func(r *Runtime) Value { return valueProp(valueFloat(sqrt1_2), false, false, false) })
297 t.putStr("SQRT2", func(r *Runtime) Value { return valueProp(valueFloat(math.Sqrt2), false, false, false) })
298
299 t.putSym(SymToStringTag, func(r *Runtime) Value { return valueProp(asciiString(classMath), false, false, true) })
300
301 t.putStr("abs", func(r *Runtime) Value { return r.methodProp(r.math_abs, "abs", 1) })
302 t.putStr("acos", func(r *Runtime) Value { return r.methodProp(r.math_acos, "acos", 1) })
303 t.putStr("acosh", func(r *Runtime) Value { return r.methodProp(r.math_acosh, "acosh", 1) })
304 t.putStr("asin", func(r *Runtime) Value { return r.methodProp(r.math_asin, "asin", 1) })
305 t.putStr("asinh", func(r *Runtime) Value { return r.methodProp(r.math_asinh, "asinh", 1) })
306 t.putStr("atan", func(r *Runtime) Value { return r.methodProp(r.math_atan, "atan", 1) })
307 t.putStr("atanh", func(r *Runtime) Value { return r.methodProp(r.math_atanh, "atanh", 1) })
308 t.putStr("atan2", func(r *Runtime) Value { return r.methodProp(r.math_atan2, "atan2", 2) })
309 t.putStr("cbrt", func(r *Runtime) Value { return r.methodProp(r.math_cbrt, "cbrt", 1) })
310 t.putStr("ceil", func(r *Runtime) Value { return r.methodProp(r.math_ceil, "ceil", 1) })
311 t.putStr("clz32", func(r *Runtime) Value { return r.methodProp(r.math_clz32, "clz32", 1) })
312 t.putStr("cos", func(r *Runtime) Value { return r.methodProp(r.math_cos, "cos", 1) })
313 t.putStr("cosh", func(r *Runtime) Value { return r.methodProp(r.math_cosh, "cosh", 1) })
314 t.putStr("exp", func(r *Runtime) Value { return r.methodProp(r.math_exp, "exp", 1) })
315 t.putStr("expm1", func(r *Runtime) Value { return r.methodProp(r.math_expm1, "expm1", 1) })
316 t.putStr("floor", func(r *Runtime) Value { return r.methodProp(r.math_floor, "floor", 1) })
317 t.putStr("fround", func(r *Runtime) Value { return r.methodProp(r.math_fround, "fround", 1) })
318 t.putStr("hypot", func(r *Runtime) Value { return r.methodProp(r.math_hypot, "hypot", 2) })
319 t.putStr("imul", func(r *Runtime) Value { return r.methodProp(r.math_imul, "imul", 2) })
320 t.putStr("log", func(r *Runtime) Value { return r.methodProp(r.math_log, "log", 1) })
321 t.putStr("log1p", func(r *Runtime) Value { return r.methodProp(r.math_log1p, "log1p", 1) })
322 t.putStr("log10", func(r *Runtime) Value { return r.methodProp(r.math_log10, "log10", 1) })
323 t.putStr("log2", func(r *Runtime) Value { return r.methodProp(r.math_log2, "log2", 1) })
324 t.putStr("max", func(r *Runtime) Value { return r.methodProp(r.math_max, "max", 2) })
325 t.putStr("min", func(r *Runtime) Value { return r.methodProp(r.math_min, "min", 2) })
326 t.putStr("pow", func(r *Runtime) Value { return r.methodProp(r.math_pow, "pow", 2) })
327 t.putStr("random", func(r *Runtime) Value { return r.methodProp(r.math_random, "random", 0) })
328 t.putStr("round", func(r *Runtime) Value { return r.methodProp(r.math_round, "round", 1) })
329 t.putStr("sign", func(r *Runtime) Value { return r.methodProp(r.math_sign, "sign", 1) })
330 t.putStr("sin", func(r *Runtime) Value { return r.methodProp(r.math_sin, "sin", 1) })
331 t.putStr("sinh", func(r *Runtime) Value { return r.methodProp(r.math_sinh, "sinh", 1) })
332 t.putStr("sqrt", func(r *Runtime) Value { return r.methodProp(r.math_sqrt, "sqrt", 1) })
333 t.putStr("tan", func(r *Runtime) Value { return r.methodProp(r.math_tan, "tan", 1) })
334 t.putStr("tanh", func(r *Runtime) Value { return r.methodProp(r.math_tanh, "tanh", 1) })
335 t.putStr("trunc", func(r *Runtime) Value { return r.methodProp(r.math_trunc, "trunc", 1) })
336
337 return t
338 }
339
340 var mathTemplate *objectTemplate
341 var mathTemplateOnce sync.Once
342
343 func getMathTemplate() *objectTemplate {
344 mathTemplateOnce.Do(func() {
345 mathTemplate = createMathTemplate()
346 })
347 return mathTemplate
348 }
349
350 func (r *Runtime) getMath() *Object {
351 ret := r.global.Math
352 if ret == nil {
353 ret = &Object{runtime: r}
354 r.global.Math = ret
355 r.newTemplatedObject(getMathTemplate(), ret)
356 }
357 return ret
358 }
359
View as plain text