1package goja
2
3import (
4	"math"
5)
6
7func (r *Runtime) math_abs(call FunctionCall) Value {
8	return floatToValue(math.Abs(call.Argument(0).ToFloat()))
9}
10
11func (r *Runtime) math_acos(call FunctionCall) Value {
12	return floatToValue(math.Acos(call.Argument(0).ToFloat()))
13}
14
15func (r *Runtime) math_asin(call FunctionCall) Value {
16	return floatToValue(math.Asin(call.Argument(0).ToFloat()))
17}
18
19func (r *Runtime) math_atan(call FunctionCall) Value {
20	return floatToValue(math.Atan(call.Argument(0).ToFloat()))
21}
22
23func (r *Runtime) math_atan2(call FunctionCall) Value {
24	y := call.Argument(0).ToFloat()
25	x := call.Argument(1).ToFloat()
26
27	return floatToValue(math.Atan2(y, x))
28}
29
30func (r *Runtime) math_ceil(call FunctionCall) Value {
31	return floatToValue(math.Ceil(call.Argument(0).ToFloat()))
32}
33
34func (r *Runtime) math_cos(call FunctionCall) Value {
35	return floatToValue(math.Cos(call.Argument(0).ToFloat()))
36}
37
38func (r *Runtime) math_exp(call FunctionCall) Value {
39	return floatToValue(math.Exp(call.Argument(0).ToFloat()))
40}
41
42func (r *Runtime) math_floor(call FunctionCall) Value {
43	return floatToValue(math.Floor(call.Argument(0).ToFloat()))
44}
45
46func (r *Runtime) math_log(call FunctionCall) Value {
47	return floatToValue(math.Log(call.Argument(0).ToFloat()))
48}
49
50func (r *Runtime) math_max(call FunctionCall) Value {
51	if len(call.Arguments) == 0 {
52		return _negativeInf
53	}
54
55	result := call.Arguments[0].ToFloat()
56	if math.IsNaN(result) {
57		return _NaN
58	}
59	for _, arg := range call.Arguments[1:] {
60		f := arg.ToFloat()
61		if math.IsNaN(f) {
62			return _NaN
63		}
64		result = math.Max(result, f)
65	}
66	return floatToValue(result)
67}
68
69func (r *Runtime) math_min(call FunctionCall) Value {
70	if len(call.Arguments) == 0 {
71		return _positiveInf
72	}
73
74	result := call.Arguments[0].ToFloat()
75	if math.IsNaN(result) {
76		return _NaN
77	}
78	for _, arg := range call.Arguments[1:] {
79		f := arg.ToFloat()
80		if math.IsNaN(f) {
81			return _NaN
82		}
83		result = math.Min(result, f)
84	}
85	return floatToValue(result)
86}
87
88func (r *Runtime) math_pow(call FunctionCall) Value {
89	x := call.Argument(0)
90	y := call.Argument(1)
91	if x, ok := x.assertInt(); ok {
92		if y, ok := y.assertInt(); ok && y >= 0 && y < 64 {
93			if y == 0 {
94				return intToValue(1)
95			}
96			if x == 0 {
97				return intToValue(0)
98			}
99			ip := ipow(x, y)
100			if ip != 0 {
101				return intToValue(ip)
102			}
103		}
104	}
105
106	return floatToValue(math.Pow(x.ToFloat(), y.ToFloat()))
107}
108
109func (r *Runtime) math_random(call FunctionCall) Value {
110	return floatToValue(r.rand())
111}
112
113func (r *Runtime) math_round(call FunctionCall) Value {
114	f := call.Argument(0).ToFloat()
115	if math.IsNaN(f) {
116		return _NaN
117	}
118
119	if f == 0 && math.Signbit(f) {
120		return _negativeZero
121	}
122
123	t := math.Trunc(f)
124
125	if f >= 0 {
126		if f-t >= 0.5 {
127			return floatToValue(t + 1)
128		}
129	} else {
130		if t-f > 0.5 {
131			return floatToValue(t - 1)
132		}
133	}
134
135	return floatToValue(t)
136}
137
138func (r *Runtime) math_sin(call FunctionCall) Value {
139	return floatToValue(math.Sin(call.Argument(0).ToFloat()))
140}
141
142func (r *Runtime) math_sqrt(call FunctionCall) Value {
143	return floatToValue(math.Sqrt(call.Argument(0).ToFloat()))
144}
145
146func (r *Runtime) math_tan(call FunctionCall) Value {
147	return floatToValue(math.Tan(call.Argument(0).ToFloat()))
148}
149
150func (r *Runtime) createMath(val *Object) objectImpl {
151	m := &baseObject{
152		class:      "Math",
153		val:        val,
154		extensible: true,
155		prototype:  r.global.ObjectPrototype,
156	}
157	m.init()
158
159	m._putProp("E", valueFloat(math.E), false, false, false)
160	m._putProp("LN10", valueFloat(math.Ln10), false, false, false)
161	m._putProp("LN2", valueFloat(math.Ln2), false, false, false)
162	m._putProp("LOG2E", valueFloat(math.Log2E), false, false, false)
163	m._putProp("LOG10E", valueFloat(math.Log10E), false, false, false)
164	m._putProp("PI", valueFloat(math.Pi), false, false, false)
165	m._putProp("SQRT1_2", valueFloat(sqrt1_2), false, false, false)
166	m._putProp("SQRT2", valueFloat(math.Sqrt2), false, false, false)
167
168	m._putProp("abs", r.newNativeFunc(r.math_abs, nil, "abs", nil, 1), true, false, true)
169	m._putProp("acos", r.newNativeFunc(r.math_acos, nil, "acos", nil, 1), true, false, true)
170	m._putProp("asin", r.newNativeFunc(r.math_asin, nil, "asin", nil, 1), true, false, true)
171	m._putProp("atan", r.newNativeFunc(r.math_atan, nil, "atan", nil, 1), true, false, true)
172	m._putProp("atan2", r.newNativeFunc(r.math_atan2, nil, "atan2", nil, 2), true, false, true)
173	m._putProp("ceil", r.newNativeFunc(r.math_ceil, nil, "ceil", nil, 1), true, false, true)
174	m._putProp("cos", r.newNativeFunc(r.math_cos, nil, "cos", nil, 1), true, false, true)
175	m._putProp("exp", r.newNativeFunc(r.math_exp, nil, "exp", nil, 1), true, false, true)
176	m._putProp("floor", r.newNativeFunc(r.math_floor, nil, "floor", nil, 1), true, false, true)
177	m._putProp("log", r.newNativeFunc(r.math_log, nil, "log", nil, 1), true, false, true)
178	m._putProp("max", r.newNativeFunc(r.math_max, nil, "max", nil, 2), true, false, true)
179	m._putProp("min", r.newNativeFunc(r.math_min, nil, "min", nil, 2), true, false, true)
180	m._putProp("pow", r.newNativeFunc(r.math_pow, nil, "pow", nil, 2), true, false, true)
181	m._putProp("random", r.newNativeFunc(r.math_random, nil, "random", nil, 0), true, false, true)
182	m._putProp("round", r.newNativeFunc(r.math_round, nil, "round", nil, 1), true, false, true)
183	m._putProp("sin", r.newNativeFunc(r.math_sin, nil, "sin", nil, 1), true, false, true)
184	m._putProp("sqrt", r.newNativeFunc(r.math_sqrt, nil, "sqrt", nil, 1), true, false, true)
185	m._putProp("tan", r.newNativeFunc(r.math_tan, nil, "tan", nil, 1), true, false, true)
186
187	return m
188}
189
190func (r *Runtime) initMath() {
191	r.addToGlobal("Math", r.newLazyObject(r.createMath))
192}
193