builtin_bigint.go 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. package goja
  2. import (
  3. "fmt"
  4. "hash/maphash"
  5. "math"
  6. "math/big"
  7. "reflect"
  8. "strconv"
  9. "sync"
  10. "github.com/dop251/goja/unistring"
  11. )
  12. type valueBigInt big.Int
  13. func (v *valueBigInt) ToInteger() int64 {
  14. v.ToNumber()
  15. return 0
  16. }
  17. func (v *valueBigInt) toString() String {
  18. return asciiString((*big.Int)(v).String())
  19. }
  20. func (v *valueBigInt) string() unistring.String {
  21. return unistring.String(v.String())
  22. }
  23. func (v *valueBigInt) ToString() Value {
  24. return v
  25. }
  26. func (v *valueBigInt) String() string {
  27. return (*big.Int)(v).String()
  28. }
  29. func (v *valueBigInt) ToFloat() float64 {
  30. v.ToNumber()
  31. return 0
  32. }
  33. func (v *valueBigInt) ToNumber() Value {
  34. panic(typeError("Cannot convert a BigInt value to a number"))
  35. }
  36. func (v *valueBigInt) ToBoolean() bool {
  37. return (*big.Int)(v).Sign() != 0
  38. }
  39. func (v *valueBigInt) ToObject(r *Runtime) *Object {
  40. return r.newPrimitiveObject(v, r.getBigIntPrototype(), classObject)
  41. }
  42. func (v *valueBigInt) SameAs(other Value) bool {
  43. if o, ok := other.(*valueBigInt); ok {
  44. return (*big.Int)(v).Cmp((*big.Int)(o)) == 0
  45. }
  46. return false
  47. }
  48. func (v *valueBigInt) Equals(other Value) bool {
  49. switch o := other.(type) {
  50. case *valueBigInt:
  51. return (*big.Int)(v).Cmp((*big.Int)(o)) == 0
  52. case valueInt:
  53. return (*big.Int)(v).Cmp(big.NewInt(int64(o))) == 0
  54. case valueFloat:
  55. if IsInfinity(o) || math.IsNaN(float64(o)) {
  56. return false
  57. }
  58. if f := big.NewFloat(float64(o)); f.IsInt() {
  59. i, _ := f.Int(nil)
  60. return (*big.Int)(v).Cmp(i) == 0
  61. }
  62. return false
  63. case String:
  64. bigInt, err := stringToBigInt(o.toTrimmedUTF8())
  65. if err != nil {
  66. return false
  67. }
  68. return bigInt.Cmp((*big.Int)(v)) == 0
  69. case valueBool:
  70. return (*big.Int)(v).Int64() == o.ToInteger()
  71. case *Object:
  72. return v.Equals(o.toPrimitiveNumber())
  73. }
  74. return false
  75. }
  76. func (v *valueBigInt) StrictEquals(other Value) bool {
  77. o, ok := other.(*valueBigInt)
  78. if ok {
  79. return (*big.Int)(v).Cmp((*big.Int)(o)) == 0
  80. }
  81. return false
  82. }
  83. func (v *valueBigInt) Export() interface{} {
  84. return new(big.Int).Set((*big.Int)(v))
  85. }
  86. func (v *valueBigInt) ExportType() reflect.Type {
  87. return typeBigInt
  88. }
  89. func (v *valueBigInt) baseObject(rt *Runtime) *Object {
  90. return rt.getBigIntPrototype()
  91. }
  92. func (v *valueBigInt) hash(hash *maphash.Hash) uint64 {
  93. var sign byte
  94. if (*big.Int)(v).Sign() < 0 {
  95. sign = 0x01
  96. } else {
  97. sign = 0x00
  98. }
  99. _ = hash.WriteByte(sign)
  100. _, _ = hash.Write((*big.Int)(v).Bytes())
  101. h := hash.Sum64()
  102. hash.Reset()
  103. return h
  104. }
  105. func toBigInt(value Value) *valueBigInt {
  106. // Undefined Throw a TypeError exception.
  107. // Null Throw a TypeError exception.
  108. // Boolean Return 1n if prim is true and 0n if prim is false.
  109. // BigInt Return prim.
  110. // Number Throw a TypeError exception.
  111. // String 1. Let n be StringToBigInt(prim).
  112. // 2. If n is undefined, throw a SyntaxError exception.
  113. // 3. Return n.
  114. // Symbol Throw a TypeError exception.
  115. switch prim := value.(type) {
  116. case *valueBigInt:
  117. return prim
  118. case String:
  119. bigInt, err := stringToBigInt(prim.toTrimmedUTF8())
  120. if err != nil {
  121. panic(syntaxError(fmt.Sprintf("Cannot convert %s to a BigInt", prim)))
  122. }
  123. return (*valueBigInt)(bigInt)
  124. case valueBool:
  125. return (*valueBigInt)(big.NewInt(prim.ToInteger()))
  126. case *Symbol:
  127. panic(typeError("Cannot convert Symbol to a BigInt"))
  128. case *Object:
  129. return toBigInt(prim.toPrimitiveNumber())
  130. default:
  131. panic(typeError(fmt.Sprintf("Cannot convert %s to a BigInt", prim)))
  132. }
  133. }
  134. func numberToBigInt(v Value) *valueBigInt {
  135. switch v := toNumeric(v).(type) {
  136. case *valueBigInt:
  137. return v
  138. case valueInt:
  139. return (*valueBigInt)(big.NewInt(v.ToInteger()))
  140. case valueFloat:
  141. if IsInfinity(v) || math.IsNaN(float64(v)) {
  142. panic(rangeError(fmt.Sprintf("Cannot convert %s to a BigInt", v)))
  143. }
  144. if f := big.NewFloat(float64(v)); f.IsInt() {
  145. n, _ := f.Int(nil)
  146. return (*valueBigInt)(n)
  147. }
  148. panic(rangeError(fmt.Sprintf("Cannot convert %s to a BigInt", v)))
  149. case *Object:
  150. prim := v.toPrimitiveNumber()
  151. switch prim.(type) {
  152. case valueInt, valueFloat:
  153. return numberToBigInt(prim)
  154. default:
  155. return toBigInt(prim)
  156. }
  157. default:
  158. panic(newTypeError("Cannot convert %s to a BigInt", v))
  159. }
  160. }
  161. func stringToBigInt(str string) (*big.Int, error) {
  162. var bigint big.Int
  163. n, err := stringToInt(str)
  164. if err != nil {
  165. switch {
  166. case isRangeErr(err):
  167. bigint.SetString(str, 0)
  168. case err == strconv.ErrSyntax:
  169. default:
  170. return nil, strconv.ErrSyntax
  171. }
  172. } else {
  173. bigint.SetInt64(n)
  174. }
  175. return &bigint, nil
  176. }
  177. func (r *Runtime) thisBigIntValue(value Value) Value {
  178. switch t := value.(type) {
  179. case *valueBigInt:
  180. return t
  181. case *Object:
  182. switch t := t.self.(type) {
  183. case *primitiveValueObject:
  184. return r.thisBigIntValue(t.pValue)
  185. case *objectGoReflect:
  186. if t.exportType() == typeBigInt && t.valueOf != nil {
  187. return t.valueOf()
  188. }
  189. }
  190. }
  191. panic(r.NewTypeError("requires that 'this' be a BigInt"))
  192. }
  193. func (r *Runtime) bigintproto_valueOf(call FunctionCall) Value {
  194. return r.thisBigIntValue(call.This)
  195. }
  196. func (r *Runtime) bigintproto_toString(call FunctionCall) Value {
  197. x := (*big.Int)(r.thisBigIntValue(call.This).(*valueBigInt))
  198. radix := call.Argument(0)
  199. var radixMV int
  200. if radix == _undefined {
  201. radixMV = 10
  202. } else {
  203. radixMV = int(radix.ToInteger())
  204. if radixMV < 2 || radixMV > 36 {
  205. panic(r.newError(r.getRangeError(), "radix must be an integer between 2 and 36"))
  206. }
  207. }
  208. return asciiString(x.Text(radixMV))
  209. }
  210. func (r *Runtime) bigint_asIntN(call FunctionCall) Value {
  211. if len(call.Arguments) < 2 {
  212. panic(r.NewTypeError("Cannot convert undefined to a BigInt"))
  213. }
  214. bits := r.toIndex(call.Argument(0).ToNumber())
  215. if bits < 0 {
  216. panic(r.NewTypeError("Invalid value: not (convertible to) a safe integer"))
  217. }
  218. bigint := toBigInt(call.Argument(1))
  219. twoToBits := new(big.Int).Lsh(big.NewInt(1), uint(bits))
  220. mod := new(big.Int).Mod((*big.Int)(bigint), twoToBits)
  221. if bits > 0 && mod.Cmp(new(big.Int).Lsh(big.NewInt(1), uint(bits-1))) >= 0 {
  222. return (*valueBigInt)(mod.Sub(mod, twoToBits))
  223. } else {
  224. return (*valueBigInt)(mod)
  225. }
  226. }
  227. func (r *Runtime) bigint_asUintN(call FunctionCall) Value {
  228. if len(call.Arguments) < 2 {
  229. panic(r.NewTypeError("Cannot convert undefined to a BigInt"))
  230. }
  231. bits := r.toIndex(call.Argument(0).ToNumber())
  232. if bits < 0 {
  233. panic(r.NewTypeError("Invalid value: not (convertible to) a safe integer"))
  234. }
  235. bigint := (*big.Int)(toBigInt(call.Argument(1)))
  236. ret := new(big.Int).Mod(bigint, new(big.Int).Lsh(big.NewInt(1), uint(bits)))
  237. return (*valueBigInt)(ret)
  238. }
  239. var bigintTemplate *objectTemplate
  240. var bigintTemplateOnce sync.Once
  241. func getBigIntTemplate() *objectTemplate {
  242. bigintTemplateOnce.Do(func() {
  243. bigintTemplate = createBigIntTemplate()
  244. })
  245. return bigintTemplate
  246. }
  247. func createBigIntTemplate() *objectTemplate {
  248. t := newObjectTemplate()
  249. t.protoFactory = func(r *Runtime) *Object {
  250. return r.getFunctionPrototype()
  251. }
  252. t.putStr("name", func(r *Runtime) Value { return valueProp(asciiString("BigInt"), false, false, true) })
  253. t.putStr("length", func(r *Runtime) Value { return valueProp(intToValue(1), false, false, true) })
  254. t.putStr("prototype", func(r *Runtime) Value { return valueProp(r.getBigIntPrototype(), false, false, false) })
  255. t.putStr("asIntN", func(r *Runtime) Value { return r.methodProp(r.bigint_asIntN, "asIntN", 2) })
  256. t.putStr("asUintN", func(r *Runtime) Value { return r.methodProp(r.bigint_asUintN, "asUintN", 2) })
  257. return t
  258. }
  259. func (r *Runtime) builtin_BigInt(call FunctionCall) Value {
  260. if len(call.Arguments) > 0 {
  261. switch v := call.Argument(0).(type) {
  262. case *valueBigInt, valueInt, valueFloat, *Object:
  263. return numberToBigInt(v)
  264. default:
  265. return toBigInt(v)
  266. }
  267. }
  268. return (*valueBigInt)(big.NewInt(0))
  269. }
  270. func (r *Runtime) builtin_newBigInt(args []Value, newTarget *Object) *Object {
  271. if newTarget != nil {
  272. panic(r.NewTypeError("BigInt is not a constructor"))
  273. }
  274. var v Value
  275. if len(args) > 0 {
  276. v = numberToBigInt(args[0])
  277. } else {
  278. v = (*valueBigInt)(big.NewInt(0))
  279. }
  280. return r.newPrimitiveObject(v, newTarget, classObject)
  281. }
  282. func (r *Runtime) getBigInt() *Object {
  283. ret := r.global.BigInt
  284. if ret == nil {
  285. ret = &Object{runtime: r}
  286. r.global.BigInt = ret
  287. r.newTemplatedFuncObject(getBigIntTemplate(), ret, r.builtin_BigInt,
  288. r.wrapNativeConstruct(r.builtin_newBigInt, ret, r.getBigIntPrototype()))
  289. }
  290. return ret
  291. }
  292. func createBigIntProtoTemplate() *objectTemplate {
  293. t := newObjectTemplate()
  294. t.protoFactory = func(r *Runtime) *Object {
  295. return r.global.ObjectPrototype
  296. }
  297. t.putStr("length", func(r *Runtime) Value { return valueProp(intToValue(0), false, false, true) })
  298. t.putStr("name", func(r *Runtime) Value { return valueProp(asciiString("BigInt"), false, false, true) })
  299. t.putStr("constructor", func(r *Runtime) Value { return valueProp(r.getBigInt(), true, false, true) })
  300. t.putStr("toLocaleString", func(r *Runtime) Value { return r.methodProp(r.bigintproto_toString, "toLocaleString", 0) })
  301. t.putStr("toString", func(r *Runtime) Value { return r.methodProp(r.bigintproto_toString, "toString", 0) })
  302. t.putStr("valueOf", func(r *Runtime) Value { return r.methodProp(r.bigintproto_valueOf, "valueOf", 0) })
  303. t.putSym(SymToStringTag, func(r *Runtime) Value { return valueProp(asciiString("BigInt"), false, false, true) })
  304. return t
  305. }
  306. var bigintProtoTemplate *objectTemplate
  307. var bigintProtoTemplateOnce sync.Once
  308. func getBigIntProtoTemplate() *objectTemplate {
  309. bigintProtoTemplateOnce.Do(func() {
  310. bigintProtoTemplate = createBigIntProtoTemplate()
  311. })
  312. return bigintProtoTemplate
  313. }
  314. func (r *Runtime) getBigIntPrototype() *Object {
  315. ret := r.global.BigIntPrototype
  316. if ret == nil {
  317. ret = &Object{runtime: r}
  318. r.global.BigIntPrototype = ret
  319. o := r.newTemplatedObject(getBigIntProtoTemplate(), ret)
  320. o.class = classObject
  321. }
  322. return ret
  323. }