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
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
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
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
467
468 case base == 0:
469
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
488
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
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
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
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 }
575
View as plain text