123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364 |
- package goja
- import (
- "io"
- "strconv"
- "strings"
- "unicode/utf8"
- "github.com/dop251/goja/unistring"
- )
- const (
- __proto__ = "__proto__"
- )
- var (
- stringTrue String = asciiString("true")
- stringFalse String = asciiString("false")
- stringNull String = asciiString("null")
- stringUndefined String = asciiString("undefined")
- stringObjectC String = asciiString("object")
- stringFunction String = asciiString("function")
- stringBoolean String = asciiString("boolean")
- stringString String = asciiString("string")
- stringSymbol String = asciiString("symbol")
- stringNumber String = asciiString("number")
- stringBigInt String = asciiString("bigint")
- stringNaN String = asciiString("NaN")
- stringInfinity = asciiString("Infinity")
- stringNegInfinity = asciiString("-Infinity")
- stringBound_ String = asciiString("bound ")
- stringEmpty String = asciiString("")
- stringError String = asciiString("Error")
- stringAggregateError String = asciiString("AggregateError")
- stringTypeError String = asciiString("TypeError")
- stringReferenceError String = asciiString("ReferenceError")
- stringSyntaxError String = asciiString("SyntaxError")
- stringRangeError String = asciiString("RangeError")
- stringEvalError String = asciiString("EvalError")
- stringURIError String = asciiString("URIError")
- stringGoError String = asciiString("GoError")
- stringObjectNull String = asciiString("[object Null]")
- stringObjectUndefined String = asciiString("[object Undefined]")
- stringInvalidDate String = asciiString("Invalid Date")
- )
- type utf16Reader interface {
- readChar() (c uint16, err error)
- }
- // String represents an ECMAScript string Value. Its internal representation depends on the contents of the
- // string, but in any case it is capable of holding any UTF-16 string, either valid or invalid.
- // Instances of this type, as any other primitive values, are goroutine-safe and can be passed between runtimes.
- // Strings can be created using Runtime.ToValue(goString) or StringFromUTF16.
- type String interface {
- Value
- CharAt(int) uint16
- Length() int
- Concat(String) String
- Substring(start, end int) String
- CompareTo(String) int
- Reader() io.RuneReader
- utf16Reader() utf16Reader
- utf16RuneReader() io.RuneReader
- utf16Runes() []rune
- index(String, int) int
- lastIndex(String, int) int
- toLower() String
- toUpper() String
- toTrimmedUTF8() string
- }
- type stringIterObject struct {
- baseObject
- reader io.RuneReader
- }
- func isUTF16FirstSurrogate(c uint16) bool {
- return c >= 0xD800 && c <= 0xDBFF
- }
- func isUTF16SecondSurrogate(c uint16) bool {
- return c >= 0xDC00 && c <= 0xDFFF
- }
- func (si *stringIterObject) next() Value {
- if si.reader == nil {
- return si.val.runtime.createIterResultObject(_undefined, true)
- }
- r, _, err := si.reader.ReadRune()
- if err == io.EOF {
- si.reader = nil
- return si.val.runtime.createIterResultObject(_undefined, true)
- }
- return si.val.runtime.createIterResultObject(stringFromRune(r), false)
- }
- func stringFromRune(r rune) String {
- if r < utf8.RuneSelf {
- var sb strings.Builder
- sb.WriteByte(byte(r))
- return asciiString(sb.String())
- }
- var sb unicodeStringBuilder
- sb.WriteRune(r)
- return sb.String()
- }
- func (r *Runtime) createStringIterator(s String) Value {
- o := &Object{runtime: r}
- si := &stringIterObject{
- reader: &lenientUtf16Decoder{utf16Reader: s.utf16Reader()},
- }
- si.class = classObject
- si.val = o
- si.extensible = true
- o.self = si
- si.prototype = r.getStringIteratorPrototype()
- si.init()
- return o
- }
- type stringObject struct {
- baseObject
- value String
- length int
- lengthProp valueProperty
- }
- func newStringValue(s string) String {
- if u := unistring.Scan(s); u != nil {
- return unicodeString(u)
- }
- return asciiString(s)
- }
- func stringValueFromRaw(raw unistring.String) String {
- if b := raw.AsUtf16(); b != nil {
- return unicodeString(b)
- }
- return asciiString(raw)
- }
- func (s *stringObject) init() {
- s.baseObject.init()
- s.setLength()
- }
- func (s *stringObject) setLength() {
- if s.value != nil {
- s.length = s.value.Length()
- }
- s.lengthProp.value = intToValue(int64(s.length))
- s._put("length", &s.lengthProp)
- }
- func (s *stringObject) getStr(name unistring.String, receiver Value) Value {
- if i := strToGoIdx(name); i >= 0 && i < s.length {
- return s._getIdx(i)
- }
- return s.baseObject.getStr(name, receiver)
- }
- func (s *stringObject) getIdx(idx valueInt, receiver Value) Value {
- i := int(idx)
- if i >= 0 && i < s.length {
- return s._getIdx(i)
- }
- return s.baseObject.getStr(idx.string(), receiver)
- }
- func (s *stringObject) getOwnPropStr(name unistring.String) Value {
- if i := strToGoIdx(name); i >= 0 && i < s.length {
- val := s._getIdx(i)
- return &valueProperty{
- value: val,
- enumerable: true,
- }
- }
- return s.baseObject.getOwnPropStr(name)
- }
- func (s *stringObject) getOwnPropIdx(idx valueInt) Value {
- i := int64(idx)
- if i >= 0 {
- if i < int64(s.length) {
- val := s._getIdx(int(i))
- return &valueProperty{
- value: val,
- enumerable: true,
- }
- }
- return nil
- }
- return s.baseObject.getOwnPropStr(idx.string())
- }
- func (s *stringObject) _getIdx(idx int) Value {
- return s.value.Substring(idx, idx+1)
- }
- func (s *stringObject) setOwnStr(name unistring.String, val Value, throw bool) bool {
- if i := strToGoIdx(name); i >= 0 && i < s.length {
- s.val.runtime.typeErrorResult(throw, "Cannot assign to read only property '%d' of a String", i)
- return false
- }
- return s.baseObject.setOwnStr(name, val, throw)
- }
- func (s *stringObject) setOwnIdx(idx valueInt, val Value, throw bool) bool {
- i := int64(idx)
- if i >= 0 && i < int64(s.length) {
- s.val.runtime.typeErrorResult(throw, "Cannot assign to read only property '%d' of a String", i)
- return false
- }
- return s.baseObject.setOwnStr(idx.string(), val, throw)
- }
- func (s *stringObject) setForeignStr(name unistring.String, val, receiver Value, throw bool) (bool, bool) {
- return s._setForeignStr(name, s.getOwnPropStr(name), val, receiver, throw)
- }
- func (s *stringObject) setForeignIdx(idx valueInt, val, receiver Value, throw bool) (bool, bool) {
- return s._setForeignIdx(idx, s.getOwnPropIdx(idx), val, receiver, throw)
- }
- func (s *stringObject) defineOwnPropertyStr(name unistring.String, descr PropertyDescriptor, throw bool) bool {
- if i := strToGoIdx(name); i >= 0 && i < s.length {
- _, ok := s._defineOwnProperty(name, &valueProperty{enumerable: true}, descr, throw)
- return ok
- }
- return s.baseObject.defineOwnPropertyStr(name, descr, throw)
- }
- func (s *stringObject) defineOwnPropertyIdx(idx valueInt, descr PropertyDescriptor, throw bool) bool {
- i := int64(idx)
- if i >= 0 && i < int64(s.length) {
- s.val.runtime.typeErrorResult(throw, "Cannot redefine property: %d", i)
- return false
- }
- return s.baseObject.defineOwnPropertyStr(idx.string(), descr, throw)
- }
- type stringPropIter struct {
- str String // separate, because obj can be the singleton
- obj *stringObject
- idx, length int
- }
- func (i *stringPropIter) next() (propIterItem, iterNextFunc) {
- if i.idx < i.length {
- name := strconv.Itoa(i.idx)
- i.idx++
- return propIterItem{name: asciiString(name), enumerable: _ENUM_TRUE}, i.next
- }
- return i.obj.baseObject.iterateStringKeys()()
- }
- func (s *stringObject) iterateStringKeys() iterNextFunc {
- return (&stringPropIter{
- str: s.value,
- obj: s,
- length: s.length,
- }).next
- }
- func (s *stringObject) stringKeys(all bool, accum []Value) []Value {
- for i := 0; i < s.length; i++ {
- accum = append(accum, asciiString(strconv.Itoa(i)))
- }
- return s.baseObject.stringKeys(all, accum)
- }
- func (s *stringObject) deleteStr(name unistring.String, throw bool) bool {
- if i := strToGoIdx(name); i >= 0 && i < s.length {
- s.val.runtime.typeErrorResult(throw, "Cannot delete property '%d' of a String", i)
- return false
- }
- return s.baseObject.deleteStr(name, throw)
- }
- func (s *stringObject) deleteIdx(idx valueInt, throw bool) bool {
- i := int64(idx)
- if i >= 0 && i < int64(s.length) {
- s.val.runtime.typeErrorResult(throw, "Cannot delete property '%d' of a String", i)
- return false
- }
- return s.baseObject.deleteStr(idx.string(), throw)
- }
- func (s *stringObject) hasOwnPropertyStr(name unistring.String) bool {
- if i := strToGoIdx(name); i >= 0 && i < s.length {
- return true
- }
- return s.baseObject.hasOwnPropertyStr(name)
- }
- func (s *stringObject) hasOwnPropertyIdx(idx valueInt) bool {
- i := int64(idx)
- if i >= 0 && i < int64(s.length) {
- return true
- }
- return s.baseObject.hasOwnPropertyStr(idx.string())
- }
- func devirtualizeString(s String) (asciiString, unicodeString) {
- switch s := s.(type) {
- case asciiString:
- return s, nil
- case unicodeString:
- return "", s
- case *importedString:
- s.ensureScanned()
- if s.u != nil {
- return "", s.u
- }
- return asciiString(s.s), nil
- default:
- panic(unknownStringTypeErr(s))
- }
- }
- func unknownStringTypeErr(v Value) interface{} {
- return newTypeError("Internal bug: unknown string type: %T", v)
- }
- // StringFromUTF16 creates a string value from an array of UTF-16 code units. The result is a copy, so the initial
- // slice can be modified after calling this function (but it must not be modified while the function is running).
- // No validation of any kind is performed.
- func StringFromUTF16(chars []uint16) String {
- isAscii := true
- for _, c := range chars {
- if c >= utf8.RuneSelf {
- isAscii = false
- break
- }
- }
- if isAscii {
- var sb strings.Builder
- sb.Grow(len(chars))
- for _, c := range chars {
- sb.WriteByte(byte(c))
- }
- return asciiString(sb.String())
- }
- buf := make([]uint16, len(chars)+1)
- buf[0] = unistring.BOM
- copy(buf[1:], chars)
- return unicodeString(buf)
- }
|