github.com/dop251/goja@v0.0.0-20240220182346-e401ed450204/builtin_global.go (about) 1 package goja 2 3 import ( 4 "errors" 5 "github.com/dop251/goja/unistring" 6 "io" 7 "math" 8 "regexp" 9 "strconv" 10 "strings" 11 "sync" 12 "unicode/utf8" 13 ) 14 15 const hexUpper = "0123456789ABCDEF" 16 17 var ( 18 parseFloatRegexp = regexp.MustCompile(`^([+-]?(?:Infinity|[0-9]*\.?[0-9]*(?:[eE][+-]?[0-9]+)?))`) 19 ) 20 21 func (r *Runtime) builtin_isNaN(call FunctionCall) Value { 22 if math.IsNaN(call.Argument(0).ToFloat()) { 23 return valueTrue 24 } else { 25 return valueFalse 26 } 27 } 28 29 func (r *Runtime) builtin_parseInt(call FunctionCall) Value { 30 str := call.Argument(0).toString().toTrimmedUTF8() 31 radix := int(toInt32(call.Argument(1))) 32 v, _ := parseInt(str, radix) 33 return v 34 } 35 36 func (r *Runtime) builtin_parseFloat(call FunctionCall) Value { 37 m := parseFloatRegexp.FindStringSubmatch(call.Argument(0).toString().toTrimmedUTF8()) 38 if len(m) == 2 { 39 if s := m[1]; s != "" && s != "+" && s != "-" { 40 switch s { 41 case "+", "-": 42 case "Infinity", "+Infinity": 43 return _positiveInf 44 case "-Infinity": 45 return _negativeInf 46 default: 47 f, err := strconv.ParseFloat(s, 64) 48 if err == nil || isRangeErr(err) { 49 return floatToValue(f) 50 } 51 } 52 } 53 } 54 return _NaN 55 } 56 57 func (r *Runtime) builtin_isFinite(call FunctionCall) Value { 58 f := call.Argument(0).ToFloat() 59 if math.IsNaN(f) || math.IsInf(f, 0) { 60 return valueFalse 61 } 62 return valueTrue 63 } 64 65 func (r *Runtime) _encode(uriString String, unescaped *[256]bool) String { 66 reader := uriString.Reader() 67 utf8Buf := make([]byte, utf8.UTFMax) 68 needed := false 69 l := 0 70 for { 71 rn, _, err := reader.ReadRune() 72 if err != nil { 73 if err != io.EOF { 74 panic(r.newError(r.getURIError(), "Malformed URI")) 75 } 76 break 77 } 78 79 if rn >= utf8.RuneSelf { 80 needed = true 81 l += utf8.EncodeRune(utf8Buf, rn) * 3 82 } else if !unescaped[rn] { 83 needed = true 84 l += 3 85 } else { 86 l++ 87 } 88 } 89 90 if !needed { 91 return uriString 92 } 93 94 buf := make([]byte, l) 95 i := 0 96 reader = uriString.Reader() 97 for { 98 rn, _, err := reader.ReadRune() 99 if err == io.EOF { 100 break 101 } 102 103 if rn >= utf8.RuneSelf { 104 n := utf8.EncodeRune(utf8Buf, rn) 105 for _, b := range utf8Buf[:n] { 106 buf[i] = '%' 107 buf[i+1] = hexUpper[b>>4] 108 buf[i+2] = hexUpper[b&15] 109 i += 3 110 } 111 } else if !unescaped[rn] { 112 buf[i] = '%' 113 buf[i+1] = hexUpper[rn>>4] 114 buf[i+2] = hexUpper[rn&15] 115 i += 3 116 } else { 117 buf[i] = byte(rn) 118 i++ 119 } 120 } 121 return asciiString(buf) 122 } 123 124 func (r *Runtime) _decode(sv String, reservedSet *[256]bool) String { 125 s := sv.String() 126 hexCount := 0 127 for i := 0; i < len(s); { 128 switch s[i] { 129 case '%': 130 if i+2 >= len(s) || !ishex(s[i+1]) || !ishex(s[i+2]) { 131 panic(r.newError(r.getURIError(), "Malformed URI")) 132 } 133 c := unhex(s[i+1])<<4 | unhex(s[i+2]) 134 if !reservedSet[c] { 135 hexCount++ 136 } 137 i += 3 138 default: 139 i++ 140 } 141 } 142 143 if hexCount == 0 { 144 return sv 145 } 146 147 t := make([]byte, len(s)-hexCount*2) 148 j := 0 149 isUnicode := false 150 for i := 0; i < len(s); { 151 ch := s[i] 152 switch ch { 153 case '%': 154 c := unhex(s[i+1])<<4 | unhex(s[i+2]) 155 if reservedSet[c] { 156 t[j] = s[i] 157 t[j+1] = s[i+1] 158 t[j+2] = s[i+2] 159 j += 3 160 } else { 161 t[j] = c 162 if c >= utf8.RuneSelf { 163 isUnicode = true 164 } 165 j++ 166 } 167 i += 3 168 default: 169 if ch >= utf8.RuneSelf { 170 isUnicode = true 171 } 172 t[j] = ch 173 j++ 174 i++ 175 } 176 } 177 178 if !isUnicode { 179 return asciiString(t) 180 } 181 182 us := make([]rune, 0, len(s)) 183 for len(t) > 0 { 184 rn, size := utf8.DecodeRune(t) 185 if rn == utf8.RuneError { 186 if size != 3 || t[0] != 0xef || t[1] != 0xbf || t[2] != 0xbd { 187 panic(r.newError(r.getURIError(), "Malformed URI")) 188 } 189 } 190 us = append(us, rn) 191 t = t[size:] 192 } 193 return unicodeStringFromRunes(us) 194 } 195 196 func ishex(c byte) bool { 197 switch { 198 case '0' <= c && c <= '9': 199 return true 200 case 'a' <= c && c <= 'f': 201 return true 202 case 'A' <= c && c <= 'F': 203 return true 204 } 205 return false 206 } 207 208 func unhex(c byte) byte { 209 switch { 210 case '0' <= c && c <= '9': 211 return c - '0' 212 case 'a' <= c && c <= 'f': 213 return c - 'a' + 10 214 case 'A' <= c && c <= 'F': 215 return c - 'A' + 10 216 } 217 return 0 218 } 219 220 func (r *Runtime) builtin_decodeURI(call FunctionCall) Value { 221 uriString := call.Argument(0).toString() 222 return r._decode(uriString, &uriReservedHash) 223 } 224 225 func (r *Runtime) builtin_decodeURIComponent(call FunctionCall) Value { 226 uriString := call.Argument(0).toString() 227 return r._decode(uriString, &emptyEscapeSet) 228 } 229 230 func (r *Runtime) builtin_encodeURI(call FunctionCall) Value { 231 uriString := call.Argument(0).toString() 232 return r._encode(uriString, &uriReservedUnescapedHash) 233 } 234 235 func (r *Runtime) builtin_encodeURIComponent(call FunctionCall) Value { 236 uriString := call.Argument(0).toString() 237 return r._encode(uriString, &uriUnescaped) 238 } 239 240 func (r *Runtime) builtin_escape(call FunctionCall) Value { 241 s := call.Argument(0).toString() 242 var sb strings.Builder 243 l := s.Length() 244 for i := 0; i < l; i++ { 245 r := s.CharAt(i) 246 if r >= 'A' && r <= 'Z' || r >= 'a' && r <= 'z' || r >= '0' && r <= '9' || 247 r == '@' || r == '*' || r == '_' || r == '+' || r == '-' || r == '.' || r == '/' { 248 sb.WriteByte(byte(r)) 249 } else if r <= 0xff { 250 sb.WriteByte('%') 251 sb.WriteByte(hexUpper[r>>4]) 252 sb.WriteByte(hexUpper[r&0xf]) 253 } else { 254 sb.WriteString("%u") 255 sb.WriteByte(hexUpper[r>>12]) 256 sb.WriteByte(hexUpper[(r>>8)&0xf]) 257 sb.WriteByte(hexUpper[(r>>4)&0xf]) 258 sb.WriteByte(hexUpper[r&0xf]) 259 } 260 } 261 return asciiString(sb.String()) 262 } 263 264 func (r *Runtime) builtin_unescape(call FunctionCall) Value { 265 s := call.Argument(0).toString() 266 l := s.Length() 267 var asciiBuf []byte 268 var unicodeBuf []uint16 269 _, u := devirtualizeString(s) 270 unicode := u != nil 271 if unicode { 272 unicodeBuf = make([]uint16, 1, l+1) 273 unicodeBuf[0] = unistring.BOM 274 } else { 275 asciiBuf = make([]byte, 0, l) 276 } 277 for i := 0; i < l; { 278 r := s.CharAt(i) 279 if r == '%' { 280 if i <= l-6 && s.CharAt(i+1) == 'u' { 281 c0 := s.CharAt(i + 2) 282 c1 := s.CharAt(i + 3) 283 c2 := s.CharAt(i + 4) 284 c3 := s.CharAt(i + 5) 285 if c0 <= 0xff && ishex(byte(c0)) && 286 c1 <= 0xff && ishex(byte(c1)) && 287 c2 <= 0xff && ishex(byte(c2)) && 288 c3 <= 0xff && ishex(byte(c3)) { 289 r = uint16(unhex(byte(c0)))<<12 | 290 uint16(unhex(byte(c1)))<<8 | 291 uint16(unhex(byte(c2)))<<4 | 292 uint16(unhex(byte(c3))) 293 i += 5 294 goto out 295 } 296 } 297 if i <= l-3 { 298 c0 := s.CharAt(i + 1) 299 c1 := s.CharAt(i + 2) 300 if c0 <= 0xff && ishex(byte(c0)) && 301 c1 <= 0xff && ishex(byte(c1)) { 302 r = uint16(unhex(byte(c0))<<4 | unhex(byte(c1))) 303 i += 2 304 } 305 } 306 } 307 out: 308 if r >= utf8.RuneSelf && !unicode { 309 unicodeBuf = make([]uint16, 1, l+1) 310 unicodeBuf[0] = unistring.BOM 311 for _, b := range asciiBuf { 312 unicodeBuf = append(unicodeBuf, uint16(b)) 313 } 314 asciiBuf = nil 315 unicode = true 316 } 317 if unicode { 318 unicodeBuf = append(unicodeBuf, r) 319 } else { 320 asciiBuf = append(asciiBuf, byte(r)) 321 } 322 i++ 323 } 324 if unicode { 325 return unicodeString(unicodeBuf) 326 } 327 328 return asciiString(asciiBuf) 329 } 330 331 func createGlobalObjectTemplate() *objectTemplate { 332 t := newObjectTemplate() 333 t.protoFactory = func(r *Runtime) *Object { 334 return r.global.ObjectPrototype 335 } 336 337 t.putStr("Object", func(r *Runtime) Value { return valueProp(r.getObject(), true, false, true) }) 338 t.putStr("Function", func(r *Runtime) Value { return valueProp(r.getFunction(), true, false, true) }) 339 t.putStr("Array", func(r *Runtime) Value { return valueProp(r.getArray(), true, false, true) }) 340 t.putStr("String", func(r *Runtime) Value { return valueProp(r.getString(), true, false, true) }) 341 t.putStr("Number", func(r *Runtime) Value { return valueProp(r.getNumber(), true, false, true) }) 342 t.putStr("RegExp", func(r *Runtime) Value { return valueProp(r.getRegExp(), true, false, true) }) 343 t.putStr("Date", func(r *Runtime) Value { return valueProp(r.getDate(), true, false, true) }) 344 t.putStr("Boolean", func(r *Runtime) Value { return valueProp(r.getBoolean(), true, false, true) }) 345 t.putStr("Proxy", func(r *Runtime) Value { return valueProp(r.getProxy(), true, false, true) }) 346 t.putStr("Reflect", func(r *Runtime) Value { return valueProp(r.getReflect(), true, false, true) }) 347 t.putStr("Error", func(r *Runtime) Value { return valueProp(r.getError(), true, false, true) }) 348 t.putStr("AggregateError", func(r *Runtime) Value { return valueProp(r.getAggregateError(), true, false, true) }) 349 t.putStr("TypeError", func(r *Runtime) Value { return valueProp(r.getTypeError(), true, false, true) }) 350 t.putStr("ReferenceError", func(r *Runtime) Value { return valueProp(r.getReferenceError(), true, false, true) }) 351 t.putStr("SyntaxError", func(r *Runtime) Value { return valueProp(r.getSyntaxError(), true, false, true) }) 352 t.putStr("RangeError", func(r *Runtime) Value { return valueProp(r.getRangeError(), true, false, true) }) 353 t.putStr("EvalError", func(r *Runtime) Value { return valueProp(r.getEvalError(), true, false, true) }) 354 t.putStr("URIError", func(r *Runtime) Value { return valueProp(r.getURIError(), true, false, true) }) 355 t.putStr("GoError", func(r *Runtime) Value { return valueProp(r.getGoError(), true, false, true) }) 356 357 t.putStr("eval", func(r *Runtime) Value { return valueProp(r.getEval(), true, false, true) }) 358 359 t.putStr("Math", func(r *Runtime) Value { return valueProp(r.getMath(), true, false, true) }) 360 t.putStr("JSON", func(r *Runtime) Value { return valueProp(r.getJSON(), true, false, true) }) 361 addTypedArrays(t) 362 t.putStr("Symbol", func(r *Runtime) Value { return valueProp(r.getSymbol(), true, false, true) }) 363 t.putStr("WeakSet", func(r *Runtime) Value { return valueProp(r.getWeakSet(), true, false, true) }) 364 t.putStr("WeakMap", func(r *Runtime) Value { return valueProp(r.getWeakMap(), true, false, true) }) 365 t.putStr("Map", func(r *Runtime) Value { return valueProp(r.getMap(), true, false, true) }) 366 t.putStr("Set", func(r *Runtime) Value { return valueProp(r.getSet(), true, false, true) }) 367 t.putStr("Promise", func(r *Runtime) Value { return valueProp(r.getPromise(), true, false, true) }) 368 369 t.putStr("globalThis", func(r *Runtime) Value { return valueProp(r.globalObject, true, false, true) }) 370 t.putStr("NaN", func(r *Runtime) Value { return valueProp(_NaN, false, false, false) }) 371 t.putStr("undefined", func(r *Runtime) Value { return valueProp(_undefined, false, false, false) }) 372 t.putStr("Infinity", func(r *Runtime) Value { return valueProp(_positiveInf, false, false, false) }) 373 374 t.putStr("isNaN", func(r *Runtime) Value { return r.methodProp(r.builtin_isNaN, "isNaN", 1) }) 375 t.putStr("parseInt", func(r *Runtime) Value { return valueProp(r.getParseInt(), true, false, true) }) 376 t.putStr("parseFloat", func(r *Runtime) Value { return valueProp(r.getParseFloat(), true, false, true) }) 377 t.putStr("isFinite", func(r *Runtime) Value { return r.methodProp(r.builtin_isFinite, "isFinite", 1) }) 378 t.putStr("decodeURI", func(r *Runtime) Value { return r.methodProp(r.builtin_decodeURI, "decodeURI", 1) }) 379 t.putStr("decodeURIComponent", func(r *Runtime) Value { return r.methodProp(r.builtin_decodeURIComponent, "decodeURIComponent", 1) }) 380 t.putStr("encodeURI", func(r *Runtime) Value { return r.methodProp(r.builtin_encodeURI, "encodeURI", 1) }) 381 t.putStr("encodeURIComponent", func(r *Runtime) Value { return r.methodProp(r.builtin_encodeURIComponent, "encodeURIComponent", 1) }) 382 t.putStr("escape", func(r *Runtime) Value { return r.methodProp(r.builtin_escape, "escape", 1) }) 383 t.putStr("unescape", func(r *Runtime) Value { return r.methodProp(r.builtin_unescape, "unescape", 1) }) 384 385 // TODO: Annex B 386 387 t.putSym(SymToStringTag, func(r *Runtime) Value { return valueProp(asciiString(classGlobal), false, false, true) }) 388 389 return t 390 } 391 392 var globalObjectTemplate *objectTemplate 393 var globalObjectTemplateOnce sync.Once 394 395 func getGlobalObjectTemplate() *objectTemplate { 396 globalObjectTemplateOnce.Do(func() { 397 globalObjectTemplate = createGlobalObjectTemplate() 398 }) 399 return globalObjectTemplate 400 } 401 402 func (r *Runtime) getEval() *Object { 403 ret := r.global.Eval 404 if ret == nil { 405 ret = r.newNativeFunc(r.builtin_eval, "eval", 1) 406 r.global.Eval = ret 407 } 408 return ret 409 } 410 411 func digitVal(d byte) int { 412 var v byte 413 switch { 414 case '0' <= d && d <= '9': 415 v = d - '0' 416 case 'a' <= d && d <= 'z': 417 v = d - 'a' + 10 418 case 'A' <= d && d <= 'Z': 419 v = d - 'A' + 10 420 default: 421 return 36 422 } 423 return int(v) 424 } 425 426 // ECMAScript compatible version of strconv.ParseInt 427 func parseInt(s string, base int) (Value, error) { 428 var n int64 429 var err error 430 var cutoff, maxVal int64 431 var sign bool 432 i := 0 433 434 if len(s) < 1 { 435 err = strconv.ErrSyntax 436 goto Error 437 } 438 439 switch s[0] { 440 case '-': 441 sign = true 442 s = s[1:] 443 case '+': 444 s = s[1:] 445 } 446 447 if len(s) < 1 { 448 err = strconv.ErrSyntax 449 goto Error 450 } 451 452 // Look for hex prefix. 453 if s[0] == '0' && len(s) > 1 && (s[1] == 'x' || s[1] == 'X') { 454 if base == 0 || base == 16 { 455 base = 16 456 s = s[2:] 457 } 458 } 459 460 switch { 461 case len(s) < 1: 462 err = strconv.ErrSyntax 463 goto Error 464 465 case 2 <= base && base <= 36: 466 // valid base; nothing to do 467 468 case base == 0: 469 // Look for hex prefix. 470 switch { 471 case s[0] == '0' && len(s) > 1 && (s[1] == 'x' || s[1] == 'X'): 472 if len(s) < 3 { 473 err = strconv.ErrSyntax 474 goto Error 475 } 476 base = 16 477 s = s[2:] 478 default: 479 base = 10 480 } 481 482 default: 483 err = errors.New("invalid base " + strconv.Itoa(base)) 484 goto Error 485 } 486 487 // Cutoff is the smallest number such that cutoff*base > maxInt64. 488 // Use compile-time constants for common cases. 489 switch base { 490 case 10: 491 cutoff = math.MaxInt64/10 + 1 492 case 16: 493 cutoff = math.MaxInt64/16 + 1 494 default: 495 cutoff = math.MaxInt64/int64(base) + 1 496 } 497 498 maxVal = math.MaxInt64 499 for ; i < len(s); i++ { 500 if n >= cutoff { 501 // n*base overflows 502 return parseLargeInt(float64(n), s[i:], base, sign) 503 } 504 v := digitVal(s[i]) 505 if v >= base { 506 break 507 } 508 n *= int64(base) 509 510 n1 := n + int64(v) 511 if n1 < n || n1 > maxVal { 512 // n+v overflows 513 return parseLargeInt(float64(n)+float64(v), s[i+1:], base, sign) 514 } 515 n = n1 516 } 517 518 if i == 0 { 519 err = strconv.ErrSyntax 520 goto Error 521 } 522 523 if sign { 524 n = -n 525 } 526 return intToValue(n), nil 527 528 Error: 529 return _NaN, err 530 } 531 532 func parseLargeInt(n float64, s string, base int, sign bool) (Value, error) { 533 i := 0 534 b := float64(base) 535 for ; i < len(s); i++ { 536 v := digitVal(s[i]) 537 if v >= base { 538 break 539 } 540 n = n*b + float64(v) 541 } 542 if sign { 543 n = -n 544 } 545 // We know it can't be represented as int, so use valueFloat instead of floatToValue 546 return valueFloat(n), nil 547 } 548 549 var ( 550 uriUnescaped [256]bool 551 uriReserved [256]bool 552 uriReservedHash [256]bool 553 uriReservedUnescapedHash [256]bool 554 emptyEscapeSet [256]bool 555 ) 556 557 func init() { 558 for _, c := range "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.!~*'()" { 559 uriUnescaped[c] = true 560 } 561 562 for _, c := range ";/?:@&=+$," { 563 uriReserved[c] = true 564 } 565 566 for i := 0; i < 256; i++ { 567 if uriUnescaped[i] || uriReserved[i] { 568 uriReservedUnescapedHash[i] = true 569 } 570 uriReservedHash[i] = uriReserved[i] 571 } 572 uriReservedUnescapedHash['#'] = true 573 uriReservedHash['#'] = true 574 }