1 package goja
2
3 import (
4 "hash/maphash"
5 "io"
6 "math"
7 "reflect"
8 "strconv"
9 "strings"
10
11 "github.com/dop251/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
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.getStringPrototype())
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.getStringSingleton()
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 }
365
View as plain text