1 package goja
2
3 import (
4 "io"
5 "strconv"
6 "strings"
7 "unicode/utf8"
8
9 "github.com/dop251/goja/unistring"
10 )
11
12 const (
13 __proto__ = "__proto__"
14 )
15
16 var (
17 stringTrue String = asciiString("true")
18 stringFalse String = asciiString("false")
19 stringNull String = asciiString("null")
20 stringUndefined String = asciiString("undefined")
21 stringObjectC String = asciiString("object")
22 stringFunction String = asciiString("function")
23 stringBoolean String = asciiString("boolean")
24 stringString String = asciiString("string")
25 stringSymbol String = asciiString("symbol")
26 stringNumber String = asciiString("number")
27 stringNaN String = asciiString("NaN")
28 stringInfinity = asciiString("Infinity")
29 stringNegInfinity = asciiString("-Infinity")
30 stringBound_ String = asciiString("bound ")
31 stringEmpty String = asciiString("")
32
33 stringError String = asciiString("Error")
34 stringAggregateError String = asciiString("AggregateError")
35 stringTypeError String = asciiString("TypeError")
36 stringReferenceError String = asciiString("ReferenceError")
37 stringSyntaxError String = asciiString("SyntaxError")
38 stringRangeError String = asciiString("RangeError")
39 stringEvalError String = asciiString("EvalError")
40 stringURIError String = asciiString("URIError")
41 stringGoError String = asciiString("GoError")
42
43 stringObjectNull String = asciiString("[object Null]")
44 stringObjectUndefined String = asciiString("[object Undefined]")
45 stringInvalidDate String = asciiString("Invalid Date")
46 )
47
48 type utf16Reader interface {
49 readChar() (c uint16, err error)
50 }
51
52
53
54
55
56 type String interface {
57 Value
58 CharAt(int) uint16
59 Length() int
60 Concat(String) String
61 Substring(start, end int) String
62 CompareTo(String) int
63 Reader() io.RuneReader
64 utf16Reader() utf16Reader
65 utf16RuneReader() io.RuneReader
66 utf16Runes() []rune
67 index(String, int) int
68 lastIndex(String, int) int
69 toLower() String
70 toUpper() String
71 toTrimmedUTF8() string
72 }
73
74 type stringIterObject struct {
75 baseObject
76 reader io.RuneReader
77 }
78
79 func isUTF16FirstSurrogate(c uint16) bool {
80 return c >= 0xD800 && c <= 0xDBFF
81 }
82
83 func isUTF16SecondSurrogate(c uint16) bool {
84 return c >= 0xDC00 && c <= 0xDFFF
85 }
86
87 func (si *stringIterObject) next() Value {
88 if si.reader == nil {
89 return si.val.runtime.createIterResultObject(_undefined, true)
90 }
91 r, _, err := si.reader.ReadRune()
92 if err == io.EOF {
93 si.reader = nil
94 return si.val.runtime.createIterResultObject(_undefined, true)
95 }
96 return si.val.runtime.createIterResultObject(stringFromRune(r), false)
97 }
98
99 func stringFromRune(r rune) String {
100 if r < utf8.RuneSelf {
101 var sb strings.Builder
102 sb.WriteByte(byte(r))
103 return asciiString(sb.String())
104 }
105 var sb unicodeStringBuilder
106 sb.WriteRune(r)
107 return sb.String()
108 }
109
110 func (r *Runtime) createStringIterator(s String) Value {
111 o := &Object{runtime: r}
112
113 si := &stringIterObject{
114 reader: &lenientUtf16Decoder{utf16Reader: s.utf16Reader()},
115 }
116 si.class = classObject
117 si.val = o
118 si.extensible = true
119 o.self = si
120 si.prototype = r.getStringIteratorPrototype()
121 si.init()
122
123 return o
124 }
125
126 type stringObject struct {
127 baseObject
128 value String
129 length int
130 lengthProp valueProperty
131 }
132
133 func newStringValue(s string) String {
134 if u := unistring.Scan(s); u != nil {
135 return unicodeString(u)
136 }
137 return asciiString(s)
138 }
139
140 func stringValueFromRaw(raw unistring.String) String {
141 if b := raw.AsUtf16(); b != nil {
142 return unicodeString(b)
143 }
144 return asciiString(raw)
145 }
146
147 func (s *stringObject) init() {
148 s.baseObject.init()
149 s.setLength()
150 }
151
152 func (s *stringObject) setLength() {
153 if s.value != nil {
154 s.length = s.value.Length()
155 }
156 s.lengthProp.value = intToValue(int64(s.length))
157 s._put("length", &s.lengthProp)
158 }
159
160 func (s *stringObject) getStr(name unistring.String, receiver Value) Value {
161 if i := strToGoIdx(name); i >= 0 && i < s.length {
162 return s._getIdx(i)
163 }
164 return s.baseObject.getStr(name, receiver)
165 }
166
167 func (s *stringObject) getIdx(idx valueInt, receiver Value) Value {
168 i := int(idx)
169 if i >= 0 && i < s.length {
170 return s._getIdx(i)
171 }
172 return s.baseObject.getStr(idx.string(), receiver)
173 }
174
175 func (s *stringObject) getOwnPropStr(name unistring.String) Value {
176 if i := strToGoIdx(name); i >= 0 && i < s.length {
177 val := s._getIdx(i)
178 return &valueProperty{
179 value: val,
180 enumerable: true,
181 }
182 }
183
184 return s.baseObject.getOwnPropStr(name)
185 }
186
187 func (s *stringObject) getOwnPropIdx(idx valueInt) Value {
188 i := int64(idx)
189 if i >= 0 {
190 if i < int64(s.length) {
191 val := s._getIdx(int(i))
192 return &valueProperty{
193 value: val,
194 enumerable: true,
195 }
196 }
197 return nil
198 }
199
200 return s.baseObject.getOwnPropStr(idx.string())
201 }
202
203 func (s *stringObject) _getIdx(idx int) Value {
204 return s.value.Substring(idx, idx+1)
205 }
206
207 func (s *stringObject) setOwnStr(name unistring.String, val Value, throw bool) bool {
208 if i := strToGoIdx(name); i >= 0 && i < s.length {
209 s.val.runtime.typeErrorResult(throw, "Cannot assign to read only property '%d' of a String", i)
210 return false
211 }
212
213 return s.baseObject.setOwnStr(name, val, throw)
214 }
215
216 func (s *stringObject) setOwnIdx(idx valueInt, val Value, throw bool) bool {
217 i := int64(idx)
218 if i >= 0 && i < int64(s.length) {
219 s.val.runtime.typeErrorResult(throw, "Cannot assign to read only property '%d' of a String", i)
220 return false
221 }
222
223 return s.baseObject.setOwnStr(idx.string(), val, throw)
224 }
225
226 func (s *stringObject) setForeignStr(name unistring.String, val, receiver Value, throw bool) (bool, bool) {
227 return s._setForeignStr(name, s.getOwnPropStr(name), val, receiver, throw)
228 }
229
230 func (s *stringObject) setForeignIdx(idx valueInt, val, receiver Value, throw bool) (bool, bool) {
231 return s._setForeignIdx(idx, s.getOwnPropIdx(idx), val, receiver, throw)
232 }
233
234 func (s *stringObject) defineOwnPropertyStr(name unistring.String, descr PropertyDescriptor, throw bool) bool {
235 if i := strToGoIdx(name); i >= 0 && i < s.length {
236 _, ok := s._defineOwnProperty(name, &valueProperty{enumerable: true}, descr, throw)
237 return ok
238 }
239
240 return s.baseObject.defineOwnPropertyStr(name, descr, throw)
241 }
242
243 func (s *stringObject) defineOwnPropertyIdx(idx valueInt, descr PropertyDescriptor, throw bool) bool {
244 i := int64(idx)
245 if i >= 0 && i < int64(s.length) {
246 s.val.runtime.typeErrorResult(throw, "Cannot redefine property: %d", i)
247 return false
248 }
249
250 return s.baseObject.defineOwnPropertyStr(idx.string(), descr, throw)
251 }
252
253 type stringPropIter struct {
254 str String
255 obj *stringObject
256 idx, length int
257 }
258
259 func (i *stringPropIter) next() (propIterItem, iterNextFunc) {
260 if i.idx < i.length {
261 name := strconv.Itoa(i.idx)
262 i.idx++
263 return propIterItem{name: asciiString(name), enumerable: _ENUM_TRUE}, i.next
264 }
265
266 return i.obj.baseObject.iterateStringKeys()()
267 }
268
269 func (s *stringObject) iterateStringKeys() iterNextFunc {
270 return (&stringPropIter{
271 str: s.value,
272 obj: s,
273 length: s.length,
274 }).next
275 }
276
277 func (s *stringObject) stringKeys(all bool, accum []Value) []Value {
278 for i := 0; i < s.length; i++ {
279 accum = append(accum, asciiString(strconv.Itoa(i)))
280 }
281
282 return s.baseObject.stringKeys(all, accum)
283 }
284
285 func (s *stringObject) deleteStr(name unistring.String, throw bool) bool {
286 if i := strToGoIdx(name); i >= 0 && i < s.length {
287 s.val.runtime.typeErrorResult(throw, "Cannot delete property '%d' of a String", i)
288 return false
289 }
290
291 return s.baseObject.deleteStr(name, throw)
292 }
293
294 func (s *stringObject) deleteIdx(idx valueInt, throw bool) bool {
295 i := int64(idx)
296 if i >= 0 && i < int64(s.length) {
297 s.val.runtime.typeErrorResult(throw, "Cannot delete property '%d' of a String", i)
298 return false
299 }
300
301 return s.baseObject.deleteStr(idx.string(), throw)
302 }
303
304 func (s *stringObject) hasOwnPropertyStr(name unistring.String) bool {
305 if i := strToGoIdx(name); i >= 0 && i < s.length {
306 return true
307 }
308 return s.baseObject.hasOwnPropertyStr(name)
309 }
310
311 func (s *stringObject) hasOwnPropertyIdx(idx valueInt) bool {
312 i := int64(idx)
313 if i >= 0 && i < int64(s.length) {
314 return true
315 }
316 return s.baseObject.hasOwnPropertyStr(idx.string())
317 }
318
319 func devirtualizeString(s String) (asciiString, unicodeString) {
320 switch s := s.(type) {
321 case asciiString:
322 return s, nil
323 case unicodeString:
324 return "", s
325 case *importedString:
326 s.ensureScanned()
327 if s.u != nil {
328 return "", s.u
329 }
330 return asciiString(s.s), nil
331 default:
332 panic(unknownStringTypeErr(s))
333 }
334 }
335
336 func unknownStringTypeErr(v Value) interface{} {
337 return newTypeError("Internal bug: unknown string type: %T", v)
338 }
339
340
341
342
343 func StringFromUTF16(chars []uint16) String {
344 isAscii := true
345 for _, c := range chars {
346 if c >= utf8.RuneSelf {
347 isAscii = false
348 break
349 }
350 }
351 if isAscii {
352 var sb strings.Builder
353 sb.Grow(len(chars))
354 for _, c := range chars {
355 sb.WriteByte(byte(c))
356 }
357 return asciiString(sb.String())
358 }
359 buf := make([]uint16, len(chars)+1)
360 buf[0] = unistring.BOM
361 copy(buf[1:], chars)
362 return unicodeString(buf)
363 }
364
View as plain text