...

Source file src/github.com/dop251/goja/builtin_global.go

Documentation: github.com/dop251/goja

     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  }
   575  

View as plain text