Source file src/pkg/syscall/js/js.go
1
2
3
4
5
6
7
8
9
10
11
12 package js
13
14 import (
15 "unsafe"
16 )
17
18
19
20
21
22
23
24 type ref uint64
25
26
27 const nanHead = 0x7FF80000
28
29
30 type Wrapper interface {
31
32 JSValue() Value
33 }
34
35
36 type Value struct {
37 ref ref
38 }
39
40
41 func (v Value) JSValue() Value {
42 return v
43 }
44
45 func makeValue(v ref) Value {
46 return Value{ref: v}
47 }
48
49 func predefValue(id uint32) Value {
50 return Value{ref: nanHead<<32 | ref(id)}
51 }
52
53 func floatValue(f float64) Value {
54 if f == 0 {
55 return valueZero
56 }
57 if f != f {
58 return valueNaN
59 }
60 return Value{ref: *(*ref)(unsafe.Pointer(&f))}
61 }
62
63
64 type Error struct {
65
66 Value
67 }
68
69
70 func (e Error) Error() string {
71 return "JavaScript error: " + e.Get("message").String()
72 }
73
74 var (
75 valueUndefined = Value{ref: 0}
76 valueNaN = predefValue(0)
77 valueZero = predefValue(1)
78 valueNull = predefValue(2)
79 valueTrue = predefValue(3)
80 valueFalse = predefValue(4)
81 valueGlobal = predefValue(5)
82 jsGo = predefValue(6)
83
84 objectConstructor = valueGlobal.Get("Object")
85 arrayConstructor = valueGlobal.Get("Array")
86 )
87
88
89 func Undefined() Value {
90 return valueUndefined
91 }
92
93
94 func Null() Value {
95 return valueNull
96 }
97
98
99 func Global() Value {
100 return valueGlobal
101 }
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117 func ValueOf(x interface{}) Value {
118 switch x := x.(type) {
119 case Value:
120 return x
121 case Wrapper:
122 return x.JSValue()
123 case nil:
124 return valueNull
125 case bool:
126 if x {
127 return valueTrue
128 } else {
129 return valueFalse
130 }
131 case int:
132 return floatValue(float64(x))
133 case int8:
134 return floatValue(float64(x))
135 case int16:
136 return floatValue(float64(x))
137 case int32:
138 return floatValue(float64(x))
139 case int64:
140 return floatValue(float64(x))
141 case uint:
142 return floatValue(float64(x))
143 case uint8:
144 return floatValue(float64(x))
145 case uint16:
146 return floatValue(float64(x))
147 case uint32:
148 return floatValue(float64(x))
149 case uint64:
150 return floatValue(float64(x))
151 case uintptr:
152 return floatValue(float64(x))
153 case unsafe.Pointer:
154 return floatValue(float64(uintptr(x)))
155 case float32:
156 return floatValue(float64(x))
157 case float64:
158 return floatValue(x)
159 case string:
160 return makeValue(stringVal(x))
161 case []interface{}:
162 a := arrayConstructor.New(len(x))
163 for i, s := range x {
164 a.SetIndex(i, s)
165 }
166 return a
167 case map[string]interface{}:
168 o := objectConstructor.New()
169 for k, v := range x {
170 o.Set(k, v)
171 }
172 return o
173 default:
174 panic("ValueOf: invalid value")
175 }
176 }
177
178 func stringVal(x string) ref
179
180
181 type Type int
182
183 const (
184 TypeUndefined Type = iota
185 TypeNull
186 TypeBoolean
187 TypeNumber
188 TypeString
189 TypeSymbol
190 TypeObject
191 TypeFunction
192 )
193
194 func (t Type) String() string {
195 switch t {
196 case TypeUndefined:
197 return "undefined"
198 case TypeNull:
199 return "null"
200 case TypeBoolean:
201 return "boolean"
202 case TypeNumber:
203 return "number"
204 case TypeString:
205 return "string"
206 case TypeSymbol:
207 return "symbol"
208 case TypeObject:
209 return "object"
210 case TypeFunction:
211 return "function"
212 default:
213 panic("bad type")
214 }
215 }
216
217 func (t Type) isObject() bool {
218 return t == TypeObject || t == TypeFunction
219 }
220
221
222
223 func (v Value) Type() Type {
224 switch v.ref {
225 case valueUndefined.ref:
226 return TypeUndefined
227 case valueNull.ref:
228 return TypeNull
229 case valueTrue.ref, valueFalse.ref:
230 return TypeBoolean
231 }
232 if v.isNumber() {
233 return TypeNumber
234 }
235 typeFlag := v.ref >> 32 & 3
236 switch typeFlag {
237 case 1:
238 return TypeString
239 case 2:
240 return TypeSymbol
241 case 3:
242 return TypeFunction
243 default:
244 return TypeObject
245 }
246 }
247
248
249
250 func (v Value) Get(p string) Value {
251 if vType := v.Type(); !vType.isObject() {
252 panic(&ValueError{"Value.Get", vType})
253 }
254 return makeValue(valueGet(v.ref, p))
255 }
256
257 func valueGet(v ref, p string) ref
258
259
260
261 func (v Value) Set(p string, x interface{}) {
262 if vType := v.Type(); !vType.isObject() {
263 panic(&ValueError{"Value.Set", vType})
264 }
265 valueSet(v.ref, p, ValueOf(x).ref)
266 }
267
268 func valueSet(v ref, p string, x ref)
269
270
271
272 func (v Value) Index(i int) Value {
273 if vType := v.Type(); !vType.isObject() {
274 panic(&ValueError{"Value.Index", vType})
275 }
276 return makeValue(valueIndex(v.ref, i))
277 }
278
279 func valueIndex(v ref, i int) ref
280
281
282
283 func (v Value) SetIndex(i int, x interface{}) {
284 if vType := v.Type(); !vType.isObject() {
285 panic(&ValueError{"Value.SetIndex", vType})
286 }
287 valueSetIndex(v.ref, i, ValueOf(x).ref)
288 }
289
290 func valueSetIndex(v ref, i int, x ref)
291
292 func makeArgs(args []interface{}) []ref {
293 argVals := make([]ref, len(args))
294 for i, arg := range args {
295 argVals[i] = ValueOf(arg).ref
296 }
297 return argVals
298 }
299
300
301
302 func (v Value) Length() int {
303 if vType := v.Type(); !vType.isObject() {
304 panic(&ValueError{"Value.SetIndex", vType})
305 }
306 return valueLength(v.ref)
307 }
308
309 func valueLength(v ref) int
310
311
312
313
314 func (v Value) Call(m string, args ...interface{}) Value {
315 res, ok := valueCall(v.ref, m, makeArgs(args))
316 if !ok {
317 if vType := v.Type(); !vType.isObject() {
318 panic(&ValueError{"Value.Call", vType})
319 }
320 if propType := v.Get(m).Type(); propType != TypeFunction {
321 panic("syscall/js: Value.Call: property " + m + " is not a function, got " + propType.String())
322 }
323 panic(Error{makeValue(res)})
324 }
325 return makeValue(res)
326 }
327
328 func valueCall(v ref, m string, args []ref) (ref, bool)
329
330
331
332
333 func (v Value) Invoke(args ...interface{}) Value {
334 res, ok := valueInvoke(v.ref, makeArgs(args))
335 if !ok {
336 if vType := v.Type(); vType != TypeFunction {
337 panic(&ValueError{"Value.Invoke", vType})
338 }
339 panic(Error{makeValue(res)})
340 }
341 return makeValue(res)
342 }
343
344 func valueInvoke(v ref, args []ref) (ref, bool)
345
346
347
348
349 func (v Value) New(args ...interface{}) Value {
350 res, ok := valueNew(v.ref, makeArgs(args))
351 if !ok {
352 if vType := v.Type(); vType != TypeFunction {
353 panic(&ValueError{"Value.Invoke", vType})
354 }
355 panic(Error{makeValue(res)})
356 }
357 return makeValue(res)
358 }
359
360 func valueNew(v ref, args []ref) (ref, bool)
361
362 func (v Value) isNumber() bool {
363 return v.ref == valueZero.ref ||
364 v.ref == valueNaN.ref ||
365 (v.ref != valueUndefined.ref && v.ref>>32&nanHead != nanHead)
366 }
367
368 func (v Value) float(method string) float64 {
369 if !v.isNumber() {
370 panic(&ValueError{method, v.Type()})
371 }
372 if v.ref == valueZero.ref {
373 return 0
374 }
375 return *(*float64)(unsafe.Pointer(&v.ref))
376 }
377
378
379
380 func (v Value) Float() float64 {
381 return v.float("Value.Float")
382 }
383
384
385
386 func (v Value) Int() int {
387 return int(v.float("Value.Int"))
388 }
389
390
391
392 func (v Value) Bool() bool {
393 switch v.ref {
394 case valueTrue.ref:
395 return true
396 case valueFalse.ref:
397 return false
398 default:
399 panic(&ValueError{"Value.Bool", v.Type()})
400 }
401 }
402
403
404
405
406 func (v Value) Truthy() bool {
407 switch v.Type() {
408 case TypeUndefined, TypeNull:
409 return false
410 case TypeBoolean:
411 return v.Bool()
412 case TypeNumber:
413 return v.ref != valueNaN.ref && v.ref != valueZero.ref
414 case TypeString:
415 return v.String() != ""
416 case TypeSymbol, TypeFunction, TypeObject:
417 return true
418 default:
419 panic("bad type")
420 }
421 }
422
423
424
425
426
427 func (v Value) String() string {
428 switch v.Type() {
429 case TypeString:
430 return jsString(v.ref)
431 case TypeUndefined:
432 return "<undefined>"
433 case TypeNull:
434 return "<null>"
435 case TypeBoolean:
436 return "<boolean: " + jsString(v.ref) + ">"
437 case TypeNumber:
438 return "<number: " + jsString(v.ref) + ">"
439 case TypeSymbol:
440 return "<symbol>"
441 case TypeObject:
442 return "<object>"
443 case TypeFunction:
444 return "<function>"
445 default:
446 panic("bad type")
447 }
448 }
449
450 func jsString(v ref) string {
451 str, length := valuePrepareString(v)
452 b := make([]byte, length)
453 valueLoadString(str, b)
454 return string(b)
455 }
456
457 func valuePrepareString(v ref) (ref, int)
458
459 func valueLoadString(v ref, b []byte)
460
461
462 func (v Value) InstanceOf(t Value) bool {
463 return valueInstanceOf(v.ref, t.ref)
464 }
465
466 func valueInstanceOf(v ref, t ref) bool
467
468
469
470
471 type ValueError struct {
472 Method string
473 Type Type
474 }
475
476 func (e *ValueError) Error() string {
477 return "syscall/js: call of " + e.Method + " on " + e.Type.String()
478 }
479
480
481
482
483 func CopyBytesToGo(dst []byte, src Value) int {
484 n, ok := copyBytesToGo(dst, src.ref)
485 if !ok {
486 panic("syscall/js: CopyBytesToGo: expected src to be an Uint8Array")
487 }
488 return n
489 }
490
491 func copyBytesToGo(dst []byte, src ref) (int, bool)
492
493
494
495
496 func CopyBytesToJS(dst Value, src []byte) int {
497 n, ok := copyBytesToJS(dst.ref, src)
498 if !ok {
499 panic("syscall/js: CopyBytesToJS: expected dst to be an Uint8Array")
500 }
501 return n
502 }
503
504 func copyBytesToJS(dst ref, src []byte) (int, bool)
505
View as plain text