github.com/nuvolaris/goja@v0.0.0-20230825100449-967811910c6d/string_ascii.go (about) 1 package goja 2 3 import ( 4 "hash/maphash" 5 "io" 6 "math" 7 "reflect" 8 "strconv" 9 "strings" 10 11 "github.com/nuvolaris/goja/unistring" 12 ) 13 14 type asciiString string 15 16 type asciiRuneReader struct { 17 s asciiString 18 pos int 19 } 20 21 func (rr *asciiRuneReader) ReadRune() (r rune, size int, err error) { 22 if rr.pos < len(rr.s) { 23 r = rune(rr.s[rr.pos]) 24 size = 1 25 rr.pos++ 26 } else { 27 err = io.EOF 28 } 29 return 30 } 31 32 type asciiUtf16Reader struct { 33 s asciiString 34 pos int 35 } 36 37 func (rr *asciiUtf16Reader) readChar() (c uint16, err error) { 38 if rr.pos < len(rr.s) { 39 c = uint16(rr.s[rr.pos]) 40 rr.pos++ 41 } else { 42 err = io.EOF 43 } 44 return 45 } 46 47 func (rr *asciiUtf16Reader) ReadRune() (r rune, size int, err error) { 48 if rr.pos < len(rr.s) { 49 r = rune(rr.s[rr.pos]) 50 rr.pos++ 51 size = 1 52 } else { 53 err = io.EOF 54 } 55 return 56 } 57 58 func (s asciiString) Reader() io.RuneReader { 59 return &asciiRuneReader{ 60 s: s, 61 } 62 } 63 64 func (s asciiString) utf16Reader() utf16Reader { 65 return &asciiUtf16Reader{ 66 s: s, 67 } 68 } 69 70 func (s asciiString) utf16RuneReader() io.RuneReader { 71 return &asciiUtf16Reader{ 72 s: s, 73 } 74 } 75 76 func (s asciiString) utf16Runes() []rune { 77 runes := make([]rune, len(s)) 78 for i := 0; i < len(s); i++ { 79 runes[i] = rune(s[i]) 80 } 81 return runes 82 } 83 84 // ss must be trimmed 85 func stringToInt(ss string) (int64, error) { 86 if ss == "" { 87 return 0, nil 88 } 89 if ss == "-0" { 90 return 0, strconv.ErrSyntax 91 } 92 if len(ss) > 2 { 93 switch ss[:2] { 94 case "0x", "0X": 95 return strconv.ParseInt(ss[2:], 16, 64) 96 case "0b", "0B": 97 return strconv.ParseInt(ss[2:], 2, 64) 98 case "0o", "0O": 99 return strconv.ParseInt(ss[2:], 8, 64) 100 } 101 } 102 return strconv.ParseInt(ss, 10, 64) 103 } 104 105 func (s asciiString) _toInt() (int64, error) { 106 return stringToInt(strings.TrimSpace(string(s))) 107 } 108 109 func isRangeErr(err error) bool { 110 if err, ok := err.(*strconv.NumError); ok { 111 return err.Err == strconv.ErrRange 112 } 113 return false 114 } 115 116 func (s asciiString) _toFloat() (float64, error) { 117 ss := strings.TrimSpace(string(s)) 118 if ss == "" { 119 return 0, nil 120 } 121 if ss == "-0" { 122 var f float64 123 return -f, nil 124 } 125 f, err := strconv.ParseFloat(ss, 64) 126 if isRangeErr(err) { 127 err = nil 128 } 129 return f, err 130 } 131 132 func (s asciiString) ToInteger() int64 { 133 if s == "" { 134 return 0 135 } 136 if s == "Infinity" || s == "+Infinity" { 137 return math.MaxInt64 138 } 139 if s == "-Infinity" { 140 return math.MinInt64 141 } 142 i, err := s._toInt() 143 if err != nil { 144 f, err := s._toFloat() 145 if err == nil { 146 return int64(f) 147 } 148 } 149 return i 150 } 151 152 func (s asciiString) toString() String { 153 return s 154 } 155 156 func (s asciiString) ToString() Value { 157 return s 158 } 159 160 func (s asciiString) String() string { 161 return string(s) 162 } 163 164 func (s asciiString) ToFloat() float64 { 165 if s == "" { 166 return 0 167 } 168 if s == "Infinity" || s == "+Infinity" { 169 return math.Inf(1) 170 } 171 if s == "-Infinity" { 172 return math.Inf(-1) 173 } 174 f, err := s._toFloat() 175 if err != nil { 176 i, err := s._toInt() 177 if err == nil { 178 return float64(i) 179 } 180 f = math.NaN() 181 } 182 return f 183 } 184 185 func (s asciiString) ToBoolean() bool { 186 return s != "" 187 } 188 189 func (s asciiString) ToNumber() Value { 190 if s == "" { 191 return intToValue(0) 192 } 193 if s == "Infinity" || s == "+Infinity" { 194 return _positiveInf 195 } 196 if s == "-Infinity" { 197 return _negativeInf 198 } 199 200 if i, err := s._toInt(); err == nil { 201 return intToValue(i) 202 } 203 204 if f, err := s._toFloat(); err == nil { 205 return floatToValue(f) 206 } 207 208 return _NaN 209 } 210 211 func (s asciiString) ToObject(r *Runtime) *Object { 212 return r._newString(s, r.global.StringPrototype) 213 } 214 215 func (s asciiString) SameAs(other Value) bool { 216 return s.StrictEquals(other) 217 } 218 219 func (s asciiString) Equals(other Value) bool { 220 if s.StrictEquals(other) { 221 return true 222 } 223 224 if o, ok := other.(valueInt); ok { 225 if o1, e := s._toInt(); e == nil { 226 return o1 == int64(o) 227 } 228 return false 229 } 230 231 if o, ok := other.(valueFloat); ok { 232 return s.ToFloat() == float64(o) 233 } 234 235 if o, ok := other.(valueBool); ok { 236 if o1, e := s._toFloat(); e == nil { 237 return o1 == o.ToFloat() 238 } 239 return false 240 } 241 242 if o, ok := other.(*Object); ok { 243 return s.Equals(o.toPrimitive()) 244 } 245 return false 246 } 247 248 func (s asciiString) StrictEquals(other Value) bool { 249 if otherStr, ok := other.(asciiString); ok { 250 return s == otherStr 251 } 252 if otherStr, ok := other.(*importedString); ok { 253 if otherStr.u == nil { 254 return string(s) == otherStr.s 255 } 256 } 257 return false 258 } 259 260 func (s asciiString) baseObject(r *Runtime) *Object { 261 ss := r.stringSingleton 262 ss.value = s 263 ss.setLength() 264 return ss.val 265 } 266 267 func (s asciiString) hash(hash *maphash.Hash) uint64 { 268 _, _ = hash.WriteString(string(s)) 269 h := hash.Sum64() 270 hash.Reset() 271 return h 272 } 273 274 func (s asciiString) CharAt(idx int) uint16 { 275 return uint16(s[idx]) 276 } 277 278 func (s asciiString) Length() int { 279 return len(s) 280 } 281 282 func (s asciiString) Concat(other String) String { 283 a, u := devirtualizeString(other) 284 if u != nil { 285 b := make([]uint16, len(s)+len(u)) 286 b[0] = unistring.BOM 287 for i := 0; i < len(s); i++ { 288 b[i+1] = uint16(s[i]) 289 } 290 copy(b[len(s)+1:], u[1:]) 291 return unicodeString(b) 292 } 293 return s + a 294 } 295 296 func (s asciiString) Substring(start, end int) String { 297 return s[start:end] 298 } 299 300 func (s asciiString) CompareTo(other String) int { 301 switch other := other.(type) { 302 case asciiString: 303 return strings.Compare(string(s), string(other)) 304 case unicodeString: 305 return strings.Compare(string(s), other.String()) 306 case *importedString: 307 return strings.Compare(string(s), other.s) 308 default: 309 panic(newTypeError("Internal bug: unknown string type: %T", other)) 310 } 311 } 312 313 func (s asciiString) index(substr String, start int) int { 314 a, u := devirtualizeString(substr) 315 if u == nil { 316 if start > len(s) { 317 return -1 318 } 319 p := strings.Index(string(s[start:]), string(a)) 320 if p >= 0 { 321 return p + start 322 } 323 } 324 return -1 325 } 326 327 func (s asciiString) lastIndex(substr String, pos int) int { 328 a, u := devirtualizeString(substr) 329 if u == nil { 330 end := pos + len(a) 331 var ss string 332 if end > len(s) { 333 ss = string(s) 334 } else { 335 ss = string(s[:end]) 336 } 337 return strings.LastIndex(ss, string(a)) 338 } 339 return -1 340 } 341 342 func (s asciiString) toLower() String { 343 return asciiString(strings.ToLower(string(s))) 344 } 345 346 func (s asciiString) toUpper() String { 347 return asciiString(strings.ToUpper(string(s))) 348 } 349 350 func (s asciiString) toTrimmedUTF8() string { 351 return strings.TrimSpace(string(s)) 352 } 353 354 func (s asciiString) string() unistring.String { 355 return unistring.String(s) 356 } 357 358 func (s asciiString) Export() interface{} { 359 return string(s) 360 } 361 362 func (s asciiString) ExportType() reflect.Type { 363 return reflectTypeString 364 }