package goja
import (
"math"
"sync"
"github.com/dop251/goja/ftoa"
)
func (r *Runtime ) toNumber (v Value ) Value {
switch t := v .(type ) {
case valueFloat , valueInt :
return v
case *Object :
switch t := t .self .(type ) {
case *primitiveValueObject :
return r .toNumber (t .pValue )
case *objectGoReflect :
if t .class == classNumber && t .valueOf != nil {
return t .valueOf ()
}
}
if t == r .global .NumberPrototype {
return _positiveZero
}
}
panic (r .NewTypeError ("Value is not a number: %s" , v ))
}
func (r *Runtime ) numberproto_valueOf (call FunctionCall ) Value {
return r .toNumber (call .This )
}
func (r *Runtime ) numberproto_toString (call FunctionCall ) Value {
var numVal Value
switch t := call .This .(type ) {
case valueFloat , valueInt :
numVal = t
case *Object :
switch t := t .self .(type ) {
case *primitiveValueObject :
numVal = r .toNumber (t .pValue )
case *objectGoReflect :
if t .class == classNumber {
if t .toString != nil {
return t .toString ()
}
if t .valueOf != nil {
numVal = t .valueOf ()
}
}
}
if t == r .global .NumberPrototype {
return asciiString ("0" )
}
}
if numVal == nil {
panic (r .NewTypeError ("Value is not a number" ))
}
var radix int
if arg := call .Argument (0 ); arg != _undefined {
radix = int (arg .ToInteger ())
} else {
radix = 10
}
if radix < 2 || radix > 36 {
panic (r .newError (r .getRangeError (), "toString() radix argument must be between 2 and 36" ))
}
num := numVal .ToFloat ()
if math .IsNaN (num ) {
return stringNaN
}
if math .IsInf (num , 1 ) {
return stringInfinity
}
if math .IsInf (num , -1 ) {
return stringNegInfinity
}
if radix == 10 {
return asciiString (fToStr (num , ftoa .ModeStandard , 0 ))
}
return asciiString (ftoa .FToBaseStr (num , radix ))
}
func (r *Runtime ) numberproto_toFixed (call FunctionCall ) Value {
num := r .toNumber (call .This ).ToFloat ()
prec := call .Argument (0 ).ToInteger ()
if prec < 0 || prec > 100 {
panic (r .newError (r .getRangeError (), "toFixed() precision must be between 0 and 100" ))
}
if math .IsNaN (num ) {
return stringNaN
}
return asciiString (fToStr (num , ftoa .ModeFixed , int (prec )))
}
func (r *Runtime ) numberproto_toExponential (call FunctionCall ) Value {
num := r .toNumber (call .This ).ToFloat ()
precVal := call .Argument (0 )
var prec int64
if precVal == _undefined {
return asciiString (fToStr (num , ftoa .ModeStandardExponential , 0 ))
} else {
prec = precVal .ToInteger ()
}
if math .IsNaN (num ) {
return stringNaN
}
if math .IsInf (num , 1 ) {
return stringInfinity
}
if math .IsInf (num , -1 ) {
return stringNegInfinity
}
if prec < 0 || prec > 100 {
panic (r .newError (r .getRangeError (), "toExponential() precision must be between 0 and 100" ))
}
return asciiString (fToStr (num , ftoa .ModeExponential , int (prec +1 )))
}
func (r *Runtime ) numberproto_toPrecision (call FunctionCall ) Value {
numVal := r .toNumber (call .This )
precVal := call .Argument (0 )
if precVal == _undefined {
return numVal .toString ()
}
num := numVal .ToFloat ()
prec := precVal .ToInteger ()
if math .IsNaN (num ) {
return stringNaN
}
if math .IsInf (num , 1 ) {
return stringInfinity
}
if math .IsInf (num , -1 ) {
return stringNegInfinity
}
if prec < 1 || prec > 100 {
panic (r .newError (r .getRangeError (), "toPrecision() precision must be between 1 and 100" ))
}
return asciiString (fToStr (num , ftoa .ModePrecision , int (prec )))
}
func (r *Runtime ) number_isFinite (call FunctionCall ) Value {
switch arg := call .Argument (0 ).(type ) {
case valueInt :
return valueTrue
case valueFloat :
f := float64 (arg )
return r .toBoolean (!math .IsInf (f , 0 ) && !math .IsNaN (f ))
default :
return valueFalse
}
}
func (r *Runtime ) number_isInteger (call FunctionCall ) Value {
switch arg := call .Argument (0 ).(type ) {
case valueInt :
return valueTrue
case valueFloat :
f := float64 (arg )
return r .toBoolean (!math .IsNaN (f ) && !math .IsInf (f , 0 ) && math .Floor (f ) == f )
default :
return valueFalse
}
}
func (r *Runtime ) number_isNaN (call FunctionCall ) Value {
if f , ok := call .Argument (0 ).(valueFloat ); ok && math .IsNaN (float64 (f )) {
return valueTrue
}
return valueFalse
}
func (r *Runtime ) number_isSafeInteger (call FunctionCall ) Value {
arg := call .Argument (0 )
if i , ok := arg .(valueInt ); ok && i >= -(maxInt -1 ) && i <= maxInt -1 {
return valueTrue
}
if arg == _negativeZero {
return valueTrue
}
return valueFalse
}
func createNumberProtoTemplate() *objectTemplate {
t := newObjectTemplate ()
t .protoFactory = func (r *Runtime ) *Object {
return r .global .ObjectPrototype
}
t .putStr ("constructor" , func (r *Runtime ) Value { return valueProp (r .getNumber (), true , false , true ) })
t .putStr ("toExponential" , func (r *Runtime ) Value { return r .methodProp (r .numberproto_toExponential , "toExponential" , 1 ) })
t .putStr ("toFixed" , func (r *Runtime ) Value { return r .methodProp (r .numberproto_toFixed , "toFixed" , 1 ) })
t .putStr ("toLocaleString" , func (r *Runtime ) Value { return r .methodProp (r .numberproto_toString , "toLocaleString" , 0 ) })
t .putStr ("toPrecision" , func (r *Runtime ) Value { return r .methodProp (r .numberproto_toPrecision , "toPrecision" , 1 ) })
t .putStr ("toString" , func (r *Runtime ) Value { return r .methodProp (r .numberproto_toString , "toString" , 1 ) })
t .putStr ("valueOf" , func (r *Runtime ) Value { return r .methodProp (r .numberproto_valueOf , "valueOf" , 0 ) })
return t
}
var numberProtoTemplate *objectTemplate
var numberProtoTemplateOnce sync .Once
func getNumberProtoTemplate() *objectTemplate {
numberProtoTemplateOnce .Do (func () {
numberProtoTemplate = createNumberProtoTemplate ()
})
return numberProtoTemplate
}
func (r *Runtime ) getNumberPrototype () *Object {
ret := r .global .NumberPrototype
if ret == nil {
ret = &Object {runtime : r }
r .global .NumberPrototype = ret
o := r .newTemplatedObject (getNumberProtoTemplate (), ret )
o .class = classNumber
}
return ret
}
func (r *Runtime ) getParseFloat () *Object {
ret := r .global .parseFloat
if ret == nil {
ret = r .newNativeFunc (r .builtin_parseFloat , "parseFloat" , 1 )
r .global .parseFloat = ret
}
return ret
}
func (r *Runtime ) getParseInt () *Object {
ret := r .global .parseInt
if ret == nil {
ret = r .newNativeFunc (r .builtin_parseInt , "parseInt" , 2 )
r .global .parseInt = ret
}
return ret
}
func createNumberTemplate() *objectTemplate {
t := newObjectTemplate ()
t .protoFactory = func (r *Runtime ) *Object {
return r .getFunctionPrototype ()
}
t .putStr ("length" , func (r *Runtime ) Value { return valueProp (intToValue (1 ), false , false , true ) })
t .putStr ("name" , func (r *Runtime ) Value { return valueProp (asciiString ("Number" ), false , false , true ) })
t .putStr ("prototype" , func (r *Runtime ) Value { return valueProp (r .getNumberPrototype (), false , false , false ) })
t .putStr ("EPSILON" , func (r *Runtime ) Value { return valueProp (_epsilon , false , false , false ) })
t .putStr ("isFinite" , func (r *Runtime ) Value { return r .methodProp (r .number_isFinite , "isFinite" , 1 ) })
t .putStr ("isInteger" , func (r *Runtime ) Value { return r .methodProp (r .number_isInteger , "isInteger" , 1 ) })
t .putStr ("isNaN" , func (r *Runtime ) Value { return r .methodProp (r .number_isNaN , "isNaN" , 1 ) })
t .putStr ("isSafeInteger" , func (r *Runtime ) Value { return r .methodProp (r .number_isSafeInteger , "isSafeInteger" , 1 ) })
t .putStr ("MAX_SAFE_INTEGER" , func (r *Runtime ) Value { return valueProp (valueInt (maxInt -1 ), false , false , false ) })
t .putStr ("MIN_SAFE_INTEGER" , func (r *Runtime ) Value { return valueProp (valueInt (-(maxInt - 1 )), false , false , false ) })
t .putStr ("MIN_VALUE" , func (r *Runtime ) Value { return valueProp (valueFloat (math .SmallestNonzeroFloat64 ), false , false , false ) })
t .putStr ("MAX_VALUE" , func (r *Runtime ) Value { return valueProp (valueFloat (math .MaxFloat64 ), false , false , false ) })
t .putStr ("NaN" , func (r *Runtime ) Value { return valueProp (_NaN , false , false , false ) })
t .putStr ("NEGATIVE_INFINITY" , func (r *Runtime ) Value { return valueProp (_negativeInf , false , false , false ) })
t .putStr ("parseFloat" , func (r *Runtime ) Value { return valueProp (r .getParseFloat (), true , false , true ) })
t .putStr ("parseInt" , func (r *Runtime ) Value { return valueProp (r .getParseInt (), true , false , true ) })
t .putStr ("POSITIVE_INFINITY" , func (r *Runtime ) Value { return valueProp (_positiveInf , false , false , false ) })
return t
}
var numberTemplate *objectTemplate
var numberTemplateOnce sync .Once
func getNumberTemplate() *objectTemplate {
numberTemplateOnce .Do (func () {
numberTemplate = createNumberTemplate ()
})
return numberTemplate
}
func (r *Runtime ) getNumber () *Object {
ret := r .global .Number
if ret == nil {
ret = &Object {runtime : r }
r .global .Number = ret
r .newTemplatedFuncObject (getNumberTemplate (), ret , r .builtin_Number ,
r .wrapNativeConstruct (r .builtin_newNumber , ret , r .getNumberPrototype ()))
}
return ret
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .