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