1package goja 2 3import ( 4 "math" 5 6 "github.com/dop251/goja/ftoa" 7) 8 9func (r *Runtime) numberproto_valueOf(call FunctionCall) Value { 10 this := call.This 11 if !isNumber(this) { 12 r.typeErrorResult(true, "Value is not a number") 13 } 14 switch t := this.(type) { 15 case valueInt, valueFloat: 16 return this 17 case *Object: 18 if v, ok := t.self.(*primitiveValueObject); ok { 19 return v.pValue 20 } 21 } 22 23 panic(r.NewTypeError("Number.prototype.valueOf is not generic")) 24} 25 26func isNumber(v Value) bool { 27 switch t := v.(type) { 28 case valueFloat, valueInt: 29 return true 30 case *Object: 31 switch t := t.self.(type) { 32 case *primitiveValueObject: 33 return isNumber(t.pValue) 34 } 35 } 36 return false 37} 38 39func (r *Runtime) numberproto_toString(call FunctionCall) Value { 40 if !isNumber(call.This) { 41 r.typeErrorResult(true, "Value is not a number") 42 } 43 var radix int 44 if arg := call.Argument(0); arg != _undefined { 45 radix = int(arg.ToInteger()) 46 } else { 47 radix = 10 48 } 49 50 if radix < 2 || radix > 36 { 51 panic(r.newError(r.global.RangeError, "toString() radix argument must be between 2 and 36")) 52 } 53 54 num := call.This.ToFloat() 55 56 if math.IsNaN(num) { 57 return stringNaN 58 } 59 60 if math.IsInf(num, 1) { 61 return stringInfinity 62 } 63 64 if math.IsInf(num, -1) { 65 return stringNegInfinity 66 } 67 68 if radix == 10 { 69 return asciiString(fToStr(num, ftoa.ModeStandard, 0)) 70 } 71 72 return asciiString(ftoa.FToBaseStr(num, radix)) 73} 74 75func (r *Runtime) numberproto_toFixed(call FunctionCall) Value { 76 num := r.toNumber(call.This).ToFloat() 77 prec := call.Argument(0).ToInteger() 78 79 if prec < 0 || prec > 100 { 80 panic(r.newError(r.global.RangeError, "toFixed() precision must be between 0 and 100")) 81 } 82 if math.IsNaN(num) { 83 return stringNaN 84 } 85 return asciiString(fToStr(num, ftoa.ModeFixed, int(prec))) 86} 87 88func (r *Runtime) numberproto_toExponential(call FunctionCall) Value { 89 num := r.toNumber(call.This).ToFloat() 90 precVal := call.Argument(0) 91 var prec int64 92 if precVal == _undefined { 93 return asciiString(fToStr(num, ftoa.ModeStandardExponential, 0)) 94 } else { 95 prec = precVal.ToInteger() 96 } 97 98 if math.IsNaN(num) { 99 return stringNaN 100 } 101 if math.IsInf(num, 1) { 102 return stringInfinity 103 } 104 if math.IsInf(num, -1) { 105 return stringNegInfinity 106 } 107 108 if prec < 0 || prec > 100 { 109 panic(r.newError(r.global.RangeError, "toExponential() precision must be between 0 and 100")) 110 } 111 112 return asciiString(fToStr(num, ftoa.ModeExponential, int(prec+1))) 113} 114 115func (r *Runtime) numberproto_toPrecision(call FunctionCall) Value { 116 numVal := r.toNumber(call.This) 117 precVal := call.Argument(0) 118 if precVal == _undefined { 119 return numVal.toString() 120 } 121 num := numVal.ToFloat() 122 prec := precVal.ToInteger() 123 124 if math.IsNaN(num) { 125 return stringNaN 126 } 127 if math.IsInf(num, 1) { 128 return stringInfinity 129 } 130 if math.IsInf(num, -1) { 131 return stringNegInfinity 132 } 133 if prec < 1 || prec > 100 { 134 panic(r.newError(r.global.RangeError, "toPrecision() precision must be between 1 and 100")) 135 } 136 137 return asciiString(fToStr(num, ftoa.ModePrecision, int(prec))) 138} 139 140func (r *Runtime) number_isFinite(call FunctionCall) Value { 141 switch arg := call.Argument(0).(type) { 142 case valueInt: 143 return valueTrue 144 case valueFloat: 145 f := float64(arg) 146 return r.toBoolean(!math.IsInf(f, 0) && !math.IsNaN(f)) 147 default: 148 return valueFalse 149 } 150} 151 152func (r *Runtime) number_isInteger(call FunctionCall) Value { 153 switch arg := call.Argument(0).(type) { 154 case valueInt: 155 return valueTrue 156 case valueFloat: 157 f := float64(arg) 158 return r.toBoolean(!math.IsNaN(f) && !math.IsInf(f, 0) && math.Floor(f) == f) 159 default: 160 return valueFalse 161 } 162} 163 164func (r *Runtime) number_isNaN(call FunctionCall) Value { 165 if f, ok := call.Argument(0).(valueFloat); ok && math.IsNaN(float64(f)) { 166 return valueTrue 167 } 168 return valueFalse 169} 170 171func (r *Runtime) number_isSafeInteger(call FunctionCall) Value { 172 arg := call.Argument(0) 173 if i, ok := arg.(valueInt); ok && i >= -(maxInt-1) && i <= maxInt-1 { 174 return valueTrue 175 } 176 if arg == _negativeZero { 177 return valueTrue 178 } 179 return valueFalse 180} 181 182func (r *Runtime) initNumber() { 183 r.global.NumberPrototype = r.newPrimitiveObject(valueInt(0), r.global.ObjectPrototype, classNumber) 184 o := r.global.NumberPrototype.self 185 o._putProp("toExponential", r.newNativeFunc(r.numberproto_toExponential, nil, "toExponential", nil, 1), true, false, true) 186 o._putProp("toFixed", r.newNativeFunc(r.numberproto_toFixed, nil, "toFixed", nil, 1), true, false, true) 187 o._putProp("toLocaleString", r.newNativeFunc(r.numberproto_toString, nil, "toLocaleString", nil, 0), true, false, true) 188 o._putProp("toPrecision", r.newNativeFunc(r.numberproto_toPrecision, nil, "toPrecision", nil, 1), true, false, true) 189 o._putProp("toString", r.newNativeFunc(r.numberproto_toString, nil, "toString", nil, 1), true, false, true) 190 o._putProp("valueOf", r.newNativeFunc(r.numberproto_valueOf, nil, "valueOf", nil, 0), true, false, true) 191 192 r.global.Number = r.newNativeFunc(r.builtin_Number, r.builtin_newNumber, "Number", r.global.NumberPrototype, 1) 193 o = r.global.Number.self 194 o._putProp("EPSILON", _epsilon, false, false, false) 195 o._putProp("isFinite", r.newNativeFunc(r.number_isFinite, nil, "isFinite", nil, 1), true, false, true) 196 o._putProp("isInteger", r.newNativeFunc(r.number_isInteger, nil, "isInteger", nil, 1), true, false, true) 197 o._putProp("isNaN", r.newNativeFunc(r.number_isNaN, nil, "isNaN", nil, 1), true, false, true) 198 o._putProp("isSafeInteger", r.newNativeFunc(r.number_isSafeInteger, nil, "isSafeInteger", nil, 1), true, false, true) 199 o._putProp("MAX_SAFE_INTEGER", valueInt(maxInt-1), false, false, false) 200 o._putProp("MIN_SAFE_INTEGER", valueInt(-(maxInt - 1)), false, false, false) 201 o._putProp("MIN_VALUE", valueFloat(math.SmallestNonzeroFloat64), false, false, false) 202 o._putProp("MAX_VALUE", valueFloat(math.MaxFloat64), false, false, false) 203 o._putProp("NaN", _NaN, false, false, false) 204 o._putProp("NEGATIVE_INFINITY", _negativeInf, false, false, false) 205 o._putProp("parseFloat", r.Get("parseFloat"), true, false, true) 206 o._putProp("parseInt", r.Get("parseInt"), true, false, true) 207 o._putProp("POSITIVE_INFINITY", _positiveInf, false, false, false) 208 r.addToGlobal("Number", r.global.Number) 209 210} 211