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