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 }