go.ketch.com/lib/goja@v0.0.1/string.go (about)

     1  package goja
     2  
     3  import (
     4  	"io"
     5  	"strconv"
     6  	"strings"
     7  	"unicode/utf8"
     8  
     9  	"go.ketch.com/lib/goja/unistring"
    10  )
    11  
    12  const (
    13  	__proto__ = "__proto__"
    14  )
    15  
    16  var (
    17  	stringTrue        valueString = asciiString("true")
    18  	stringFalse       valueString = asciiString("false")
    19  	stringNull        valueString = asciiString("null")
    20  	stringUndefined   valueString = asciiString("undefined")
    21  	stringObjectC     valueString = asciiString("object")
    22  	stringFunction    valueString = asciiString("function")
    23  	stringBoolean     valueString = asciiString("boolean")
    24  	stringString      valueString = asciiString("string")
    25  	stringSymbol      valueString = asciiString("symbol")
    26  	stringNumber      valueString = asciiString("number")
    27  	stringNaN         valueString = asciiString("NaN")
    28  	stringInfinity                = asciiString("Infinity")
    29  	stringNegInfinity             = asciiString("-Infinity")
    30  	stringBound_      valueString = asciiString("bound ")
    31  	stringEmpty       valueString = asciiString("")
    32  
    33  	stringError          valueString = asciiString("Error")
    34  	stringAggregateError valueString = asciiString("AggregateError")
    35  	stringTypeError      valueString = asciiString("TypeError")
    36  	stringReferenceError valueString = asciiString("ReferenceError")
    37  	stringSyntaxError    valueString = asciiString("SyntaxError")
    38  	stringRangeError     valueString = asciiString("RangeError")
    39  	stringEvalError      valueString = asciiString("EvalError")
    40  	stringURIError       valueString = asciiString("URIError")
    41  	stringGoError        valueString = asciiString("GoError")
    42  
    43  	stringObjectNull      valueString = asciiString("[object Null]")
    44  	stringObjectUndefined valueString = asciiString("[object Undefined]")
    45  	stringInvalidDate     valueString = asciiString("Invalid Date")
    46  )
    47  
    48  type valueString interface {
    49  	Value
    50  	charAt(int) rune
    51  	length() int
    52  	concat(valueString) valueString
    53  	substring(start, end int) valueString
    54  	compareTo(valueString) int
    55  	reader() io.RuneReader
    56  	utf16Reader() io.RuneReader
    57  	utf16Runes() []rune
    58  	index(valueString, int) int
    59  	lastIndex(valueString, int) int
    60  	toLower() valueString
    61  	toUpper() valueString
    62  	toTrimmedUTF8() string
    63  }
    64  
    65  type stringIterObject struct {
    66  	baseObject
    67  	reader io.RuneReader
    68  }
    69  
    70  func isUTF16FirstSurrogate(r rune) bool {
    71  	return r >= 0xD800 && r <= 0xDBFF
    72  }
    73  
    74  func isUTF16SecondSurrogate(r rune) bool {
    75  	return r >= 0xDC00 && r <= 0xDFFF
    76  }
    77  
    78  func (si *stringIterObject) next() Value {
    79  	if si.reader == nil {
    80  		return si.val.runtime.createIterResultObject(_undefined, true)
    81  	}
    82  	r, _, err := si.reader.ReadRune()
    83  	if err == io.EOF {
    84  		si.reader = nil
    85  		return si.val.runtime.createIterResultObject(_undefined, true)
    86  	}
    87  	return si.val.runtime.createIterResultObject(stringFromRune(r), false)
    88  }
    89  
    90  func stringFromRune(r rune) valueString {
    91  	if r < utf8.RuneSelf {
    92  		var sb strings.Builder
    93  		sb.WriteByte(byte(r))
    94  		return asciiString(sb.String())
    95  	}
    96  	var sb unicodeStringBuilder
    97  	sb.WriteRune(r)
    98  	return sb.String()
    99  }
   100  
   101  func (r *Runtime) createStringIterator(s valueString) Value {
   102  	o := &Object{runtime: r}
   103  
   104  	si := &stringIterObject{
   105  		reader: &lenientUtf16Decoder{utf16Reader: s.utf16Reader()},
   106  	}
   107  	si.class = classStringIterator
   108  	si.val = o
   109  	si.extensible = true
   110  	o.self = si
   111  	si.prototype = r.global.StringIteratorPrototype
   112  	si.init()
   113  
   114  	return o
   115  }
   116  
   117  type stringObject struct {
   118  	baseObject
   119  	value      valueString
   120  	length     int
   121  	lengthProp valueProperty
   122  }
   123  
   124  func newStringValue(s string) valueString {
   125  	if u := unistring.Scan(s); u != nil {
   126  		return unicodeString(u)
   127  	}
   128  	return asciiString(s)
   129  }
   130  
   131  func stringValueFromRaw(raw unistring.String) valueString {
   132  	if b := raw.AsUtf16(); b != nil {
   133  		return unicodeString(b)
   134  	}
   135  	return asciiString(raw)
   136  }
   137  
   138  func (s *stringObject) init() {
   139  	s.baseObject.init()
   140  	s.setLength()
   141  }
   142  
   143  func (s *stringObject) setLength() {
   144  	if s.value != nil {
   145  		s.length = s.value.length()
   146  	}
   147  	s.lengthProp.value = intToValue(int64(s.length))
   148  	s._put("length", &s.lengthProp)
   149  }
   150  
   151  func (s *stringObject) getStr(name unistring.String, receiver Value) Value {
   152  	if i := strToGoIdx(name); i >= 0 && i < s.length {
   153  		return s._getIdx(i)
   154  	}
   155  	return s.baseObject.getStr(name, receiver)
   156  }
   157  
   158  func (s *stringObject) getIdx(idx valueInt, receiver Value) Value {
   159  	i := int(idx)
   160  	if i >= 0 && i < s.length {
   161  		return s._getIdx(i)
   162  	}
   163  	return s.baseObject.getStr(idx.string(), receiver)
   164  }
   165  
   166  func (s *stringObject) getOwnPropStr(name unistring.String) Value {
   167  	if i := strToGoIdx(name); i >= 0 && i < s.length {
   168  		val := s._getIdx(i)
   169  		return &valueProperty{
   170  			value:      val,
   171  			enumerable: true,
   172  		}
   173  	}
   174  
   175  	return s.baseObject.getOwnPropStr(name)
   176  }
   177  
   178  func (s *stringObject) getOwnPropIdx(idx valueInt) Value {
   179  	i := int64(idx)
   180  	if i >= 0 {
   181  		if i < int64(s.length) {
   182  			val := s._getIdx(int(i))
   183  			return &valueProperty{
   184  				value:      val,
   185  				enumerable: true,
   186  			}
   187  		}
   188  		return nil
   189  	}
   190  
   191  	return s.baseObject.getOwnPropStr(idx.string())
   192  }
   193  
   194  func (s *stringObject) _getIdx(idx int) Value {
   195  	return s.value.substring(idx, idx+1)
   196  }
   197  
   198  func (s *stringObject) setOwnStr(name unistring.String, val Value, throw bool) bool {
   199  	if i := strToGoIdx(name); i >= 0 && i < s.length {
   200  		s.val.runtime.typeErrorResult(throw, "Cannot assign to read only property '%d' of a String", i)
   201  		return false
   202  	}
   203  
   204  	return s.baseObject.setOwnStr(name, val, throw)
   205  }
   206  
   207  func (s *stringObject) setOwnIdx(idx valueInt, val Value, throw bool) bool {
   208  	i := int64(idx)
   209  	if i >= 0 && i < int64(s.length) {
   210  		s.val.runtime.typeErrorResult(throw, "Cannot assign to read only property '%d' of a String", i)
   211  		return false
   212  	}
   213  
   214  	return s.baseObject.setOwnStr(idx.string(), val, throw)
   215  }
   216  
   217  func (s *stringObject) setForeignStr(name unistring.String, val, receiver Value, throw bool) (bool, bool) {
   218  	return s._setForeignStr(name, s.getOwnPropStr(name), val, receiver, throw)
   219  }
   220  
   221  func (s *stringObject) setForeignIdx(idx valueInt, val, receiver Value, throw bool) (bool, bool) {
   222  	return s._setForeignIdx(idx, s.getOwnPropIdx(idx), val, receiver, throw)
   223  }
   224  
   225  func (s *stringObject) defineOwnPropertyStr(name unistring.String, descr PropertyDescriptor, throw bool) bool {
   226  	if i := strToGoIdx(name); i >= 0 && i < s.length {
   227  		_, ok := s._defineOwnProperty(name, &valueProperty{enumerable: true}, descr, throw)
   228  		return ok
   229  	}
   230  
   231  	return s.baseObject.defineOwnPropertyStr(name, descr, throw)
   232  }
   233  
   234  func (s *stringObject) defineOwnPropertyIdx(idx valueInt, descr PropertyDescriptor, throw bool) bool {
   235  	i := int64(idx)
   236  	if i >= 0 && i < int64(s.length) {
   237  		s.val.runtime.typeErrorResult(throw, "Cannot redefine property: %d", i)
   238  		return false
   239  	}
   240  
   241  	return s.baseObject.defineOwnPropertyStr(idx.string(), descr, throw)
   242  }
   243  
   244  type stringPropIter struct {
   245  	str         valueString // separate, because obj can be the singleton
   246  	obj         *stringObject
   247  	idx, length int
   248  }
   249  
   250  func (i *stringPropIter) next() (propIterItem, iterNextFunc) {
   251  	if i.idx < i.length {
   252  		name := strconv.Itoa(i.idx)
   253  		i.idx++
   254  		return propIterItem{name: asciiString(name), enumerable: _ENUM_TRUE}, i.next
   255  	}
   256  
   257  	return i.obj.baseObject.iterateStringKeys()()
   258  }
   259  
   260  func (s *stringObject) iterateStringKeys() iterNextFunc {
   261  	return (&stringPropIter{
   262  		str:    s.value,
   263  		obj:    s,
   264  		length: s.length,
   265  	}).next
   266  }
   267  
   268  func (s *stringObject) stringKeys(all bool, accum []Value) []Value {
   269  	for i := 0; i < s.length; i++ {
   270  		accum = append(accum, asciiString(strconv.Itoa(i)))
   271  	}
   272  
   273  	return s.baseObject.stringKeys(all, accum)
   274  }
   275  
   276  func (s *stringObject) deleteStr(name unistring.String, throw bool) bool {
   277  	if i := strToGoIdx(name); i >= 0 && i < s.length {
   278  		s.val.runtime.typeErrorResult(throw, "Cannot delete property '%d' of a String", i)
   279  		return false
   280  	}
   281  
   282  	return s.baseObject.deleteStr(name, throw)
   283  }
   284  
   285  func (s *stringObject) deleteIdx(idx valueInt, throw bool) bool {
   286  	i := int64(idx)
   287  	if i >= 0 && i < int64(s.length) {
   288  		s.val.runtime.typeErrorResult(throw, "Cannot delete property '%d' of a String", i)
   289  		return false
   290  	}
   291  
   292  	return s.baseObject.deleteStr(idx.string(), throw)
   293  }
   294  
   295  func (s *stringObject) hasOwnPropertyStr(name unistring.String) bool {
   296  	if i := strToGoIdx(name); i >= 0 && i < s.length {
   297  		return true
   298  	}
   299  	return s.baseObject.hasOwnPropertyStr(name)
   300  }
   301  
   302  func (s *stringObject) hasOwnPropertyIdx(idx valueInt) bool {
   303  	i := int64(idx)
   304  	if i >= 0 && i < int64(s.length) {
   305  		return true
   306  	}
   307  	return s.baseObject.hasOwnPropertyStr(idx.string())
   308  }
   309  
   310  func devirtualizeString(s valueString) (asciiString, unicodeString) {
   311  	switch s := s.(type) {
   312  	case asciiString:
   313  		return s, nil
   314  	case unicodeString:
   315  		return "", s
   316  	case *importedString:
   317  		s.ensureScanned()
   318  		if s.u != nil {
   319  			return "", s.u
   320  		}
   321  		return asciiString(s.s), nil
   322  	default:
   323  		panic(unknownStringTypeErr(s))
   324  	}
   325  }
   326  
   327  func unknownStringTypeErr(v Value) interface{} {
   328  	return newTypeError("Internal bug: unknown string type: %T", v)
   329  }