...
1 package goja
2
3 import (
4 "hash/maphash"
5 "io"
6 "math"
7 "reflect"
8 "strings"
9 "unicode/utf16"
10 "unicode/utf8"
11
12 "github.com/dop251/goja/parser"
13 "github.com/dop251/goja/unistring"
14
15 "golang.org/x/text/cases"
16 "golang.org/x/text/language"
17 )
18
19
20
21
22
23
24 type importedString struct {
25 s string
26 u unicodeString
27
28 scanned bool
29 }
30
31 func (i *importedString) scan() {
32 i.u = unistring.Scan(i.s)
33 i.scanned = true
34 }
35
36 func (i *importedString) ensureScanned() {
37 if !i.scanned {
38 i.scan()
39 }
40 }
41
42 func (i *importedString) ToInteger() int64 {
43 i.ensureScanned()
44 if i.u != nil {
45 return 0
46 }
47 return asciiString(i.s).ToInteger()
48 }
49
50 func (i *importedString) toString() String {
51 return i
52 }
53
54 func (i *importedString) string() unistring.String {
55 i.ensureScanned()
56 if i.u != nil {
57 return unistring.FromUtf16(i.u)
58 }
59 return unistring.String(i.s)
60 }
61
62 func (i *importedString) ToString() Value {
63 return i
64 }
65
66 func (i *importedString) String() string {
67 return i.s
68 }
69
70 func (i *importedString) ToFloat() float64 {
71 i.ensureScanned()
72 if i.u != nil {
73 return math.NaN()
74 }
75 return asciiString(i.s).ToFloat()
76 }
77
78 func (i *importedString) ToNumber() Value {
79 i.ensureScanned()
80 if i.u != nil {
81 return i.u.ToNumber()
82 }
83 return asciiString(i.s).ToNumber()
84 }
85
86 func (i *importedString) ToBoolean() bool {
87 return len(i.s) != 0
88 }
89
90 func (i *importedString) ToObject(r *Runtime) *Object {
91 return r._newString(i, r.getStringPrototype())
92 }
93
94 func (i *importedString) SameAs(other Value) bool {
95 return i.StrictEquals(other)
96 }
97
98 func (i *importedString) Equals(other Value) bool {
99 if i.StrictEquals(other) {
100 return true
101 }
102 i.ensureScanned()
103 if i.u != nil {
104 return i.u.Equals(other)
105 }
106 return asciiString(i.s).Equals(other)
107 }
108
109 func (i *importedString) StrictEquals(other Value) bool {
110 switch otherStr := other.(type) {
111 case asciiString:
112 if i.u != nil {
113 return false
114 }
115 return i.s == string(otherStr)
116 case unicodeString:
117 i.ensureScanned()
118 if i.u != nil && i.u.equals(otherStr) {
119 return true
120 }
121 case *importedString:
122 return i.s == otherStr.s
123 }
124 return false
125 }
126
127 func (i *importedString) Export() interface{} {
128 return i.s
129 }
130
131 func (i *importedString) ExportType() reflect.Type {
132 return reflectTypeString
133 }
134
135 func (i *importedString) baseObject(r *Runtime) *Object {
136 i.ensureScanned()
137 if i.u != nil {
138 return i.u.baseObject(r)
139 }
140 return asciiString(i.s).baseObject(r)
141 }
142
143 func (i *importedString) hash(hasher *maphash.Hash) uint64 {
144 i.ensureScanned()
145 if i.u != nil {
146 return i.u.hash(hasher)
147 }
148 return asciiString(i.s).hash(hasher)
149 }
150
151 func (i *importedString) CharAt(idx int) uint16 {
152 i.ensureScanned()
153 if i.u != nil {
154 return i.u.CharAt(idx)
155 }
156 return asciiString(i.s).CharAt(idx)
157 }
158
159 func (i *importedString) Length() int {
160 i.ensureScanned()
161 if i.u != nil {
162 return i.u.Length()
163 }
164 return asciiString(i.s).Length()
165 }
166
167 func (i *importedString) Concat(v String) String {
168 if !i.scanned {
169 if v, ok := v.(*importedString); ok {
170 if !v.scanned {
171 return &importedString{s: i.s + v.s}
172 }
173 }
174 i.ensureScanned()
175 }
176 if i.u != nil {
177 return i.u.Concat(v)
178 }
179 return asciiString(i.s).Concat(v)
180 }
181
182 func (i *importedString) Substring(start, end int) String {
183 i.ensureScanned()
184 if i.u != nil {
185 return i.u.Substring(start, end)
186 }
187 return asciiString(i.s).Substring(start, end)
188 }
189
190 func (i *importedString) CompareTo(v String) int {
191 return strings.Compare(i.s, v.String())
192 }
193
194 func (i *importedString) Reader() io.RuneReader {
195 if i.scanned {
196 if i.u != nil {
197 return i.u.Reader()
198 }
199 return asciiString(i.s).Reader()
200 }
201 return strings.NewReader(i.s)
202 }
203
204 type stringUtf16Reader struct {
205 s string
206 pos int
207 second uint16
208 }
209
210 func (s *stringUtf16Reader) readChar() (c uint16, err error) {
211 if s.second != 0 {
212 c, s.second = s.second, 0
213 return
214 }
215 if s.pos < len(s.s) {
216 r1, size1 := utf8.DecodeRuneInString(s.s[s.pos:])
217 s.pos += size1
218 if r1 <= 0xFFFF {
219 c = uint16(r1)
220 } else {
221 first, second := utf16.EncodeRune(r1)
222 c, s.second = uint16(first), uint16(second)
223 }
224 } else {
225 err = io.EOF
226 }
227 return
228 }
229
230 func (s *stringUtf16Reader) ReadRune() (r rune, size int, err error) {
231 c, err := s.readChar()
232 if err != nil {
233 return
234 }
235 r = rune(c)
236 size = 1
237 return
238 }
239
240 func (i *importedString) utf16Reader() utf16Reader {
241 if i.scanned {
242 if i.u != nil {
243 return i.u.utf16Reader()
244 }
245 return asciiString(i.s).utf16Reader()
246 }
247 return &stringUtf16Reader{
248 s: i.s,
249 }
250 }
251
252 func (i *importedString) utf16RuneReader() io.RuneReader {
253 if i.scanned {
254 if i.u != nil {
255 return i.u.utf16RuneReader()
256 }
257 return asciiString(i.s).utf16RuneReader()
258 }
259 return &stringUtf16Reader{
260 s: i.s,
261 }
262 }
263
264 func (i *importedString) utf16Runes() []rune {
265 i.ensureScanned()
266 if i.u != nil {
267 return i.u.utf16Runes()
268 }
269 return asciiString(i.s).utf16Runes()
270 }
271
272 func (i *importedString) index(v String, start int) int {
273 i.ensureScanned()
274 if i.u != nil {
275 return i.u.index(v, start)
276 }
277 return asciiString(i.s).index(v, start)
278 }
279
280 func (i *importedString) lastIndex(v String, pos int) int {
281 i.ensureScanned()
282 if i.u != nil {
283 return i.u.lastIndex(v, pos)
284 }
285 return asciiString(i.s).lastIndex(v, pos)
286 }
287
288 func (i *importedString) toLower() String {
289 i.ensureScanned()
290 if i.u != nil {
291 return toLower(i.s)
292 }
293 return asciiString(i.s).toLower()
294 }
295
296 func (i *importedString) toUpper() String {
297 i.ensureScanned()
298 if i.u != nil {
299 caser := cases.Upper(language.Und)
300 return newStringValue(caser.String(i.s))
301 }
302 return asciiString(i.s).toUpper()
303 }
304
305 func (i *importedString) toTrimmedUTF8() string {
306 return strings.Trim(i.s, parser.WhitespaceChars)
307 }
308
View as plain text