Skip to content

Commit 19bf589

Browse files
committed
More docs; arrays and slices now covered
1 parent c842484 commit 19bf589

File tree

3 files changed

+227
-18
lines changed

3 files changed

+227
-18
lines changed

compiler/prelude/jsmapping.go

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ var $internalize = function(v, t, recv) {
194194
var timePkg = $packages["time"];
195195
if (timePkg !== undefined && t === timePkg.Time) {
196196
if (v === null || v === undefined) {
197-
return new timePkg.Time.ptr(new $Uint64(0, 0), new $Int64(0, 0), $ptrType(timePkg.Location).nil)
197+
return new timePkg.Time.ptr(new $Uint64(0, 0), new $Int64(0, 0), $ptrType(timePkg.Location).nil)
198198
}
199199
if (v.constructor !== Date) {
200200
$throwRuntimeError("internalize time.Time, invalid value of type " + typeof v + "; must be Date");
@@ -304,8 +304,14 @@ var $internalize = function(v, t, recv) {
304304
305305
return v.valueOf();
306306
case $kindArray:
307+
if (v === undefined || v === null) {
308+
return t.zero();
309+
}
310+
if (!$validArrayType(v.constructor, t.elem)) {
311+
$throwRuntimeError("internalize " + t.string + ", invalid value of type " + $typeof(v));
312+
}
307313
if (v.length !== t.len) {
308-
$throwRuntimeError("got array with wrong size from JavaScript native");
314+
$throwRuntimeError("internalize " + t.string + ", wrong size from Javascript native " + $typeof(v));
309315
}
310316
return $mapArray(v, function(e) { return $internalize(e, t.elem); });
311317
case $kindFunc:
@@ -386,6 +392,9 @@ var $internalize = function(v, t, recv) {
386392
return new mapType($internalize(v, mapType));
387393
}
388394
case $kindMap:
395+
if (v === undefined || v === null) {
396+
return t.zero();
397+
}
389398
var m = {};
390399
var keys = $keys(v);
391400
for (var i = 0; i < keys.length; i++) {
@@ -398,6 +407,12 @@ var $internalize = function(v, t, recv) {
398407
return $internalize(v, t.elem);
399408
}
400409
case $kindSlice:
410+
if (v === undefined || v === null) {
411+
return t.zero();
412+
}
413+
if (!$validArrayType(v.constructor, t.elem)) {
414+
$throwRuntimeError("internalize " + t.string + ", invalid value of type " + $typeof(v));
415+
}
401416
return new t($mapArray(v, function(e) { return $internalize(e, t.elem); }));
402417
case $kindString:
403418
if (v === undefined || v === null) {
@@ -458,6 +473,36 @@ var $internalize = function(v, t, recv) {
458473
$throwRuntimeError("cannot internalize " + t.string);
459474
};
460475
476+
var $validArrayType = function(c, t) {
477+
if (c === Array) {
478+
return true;
479+
}
480+
481+
switch (t.kind) {
482+
case $kindInt8:
483+
return c === Int8Array;
484+
case $kindUint8:
485+
return c === Uint8Array || c === Uint8ClampedArray;
486+
case $kindInt16:
487+
return c === Int16Array;
488+
case $kindUint16:
489+
return c === Uint16Array;
490+
case $kindInt:
491+
case $kindInt32:
492+
return c === Int32Array;
493+
case $kindUint:
494+
case $kindUint32:
495+
case $kindUintptr:
496+
return c === Uint32Array;
497+
case $kindFloat32:
498+
return c === Float32Array;
499+
case $kindFloat64:
500+
return c === Float64Array;
501+
}
502+
503+
return false;
504+
};
505+
461506
var $typeof = function(v) {
462507
if (v === undefined) {
463508
return "undefined";

js/js.go

Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,30 +9,65 @@
99
// When values pass from Javascript to Go, a process known as internalization,
1010
// the following conversion table is applied:
1111
//
12-
// |----------------+---------------+-------------------------+--------|
13-
// | Go target type | Translation | Javascript source value | Result |
14-
// |----------------+---------------+-------------------------+--------|
15-
// | string | UTF16 -> UTF8 | null | "" |
16-
// | | | undefined | "" |
17-
// | | | "" | "" |
18-
// | | | new String("") | "" |
19-
// | | | "ok" † | "ok" |
20-
// | | | new String("ok") † | "ok" |
21-
// |----------------+---------------+-------------------------+--------|
22-
// | bool | none | null | false |
23-
// | | | undefined | false |
24-
// | | | false † | false |
25-
// | | | new Boolean(false) † | false |
26-
// |----------------+---------------+-------------------------+--------|
12+
// |-------------------+---------------+----------------------------------+---------------------------------------------|
13+
// | Go target type | Translation | Javascript source value | Result |
14+
// |-------------------+---------------+----------------------------------+---------------------------------------------|
15+
// | string | UTF16 -> UTF8 | null | "" |
16+
// | | | undefined | "" |
17+
// | | | "" | "" |
18+
// | | | new String("") | "" |
19+
// | | | "ok" † | "ok" |
20+
// | | | new String("ok") † | "ok" |
21+
// |-------------------+---------------+----------------------------------+---------------------------------------------|
22+
// | bool | none | null | false |
23+
// | | | undefined | false |
24+
// | | | false † | false |
25+
// | | | new Boolean(false) † | false |
26+
// |-------------------+---------------+----------------------------------+---------------------------------------------|
27+
// | time.Time | none | null | zero val of time.Time |
28+
// | | | undefined | zero val of time.Time |
29+
// | | | new Date(Date.UTC(2017, 0, 1)) † | time.Date(2017, 1, 1, 0, 0, 0, 0, time.UTC) |
30+
// |-------------------+---------------+----------------------------------+---------------------------------------------|
31+
// | int, int8, | none | null | 0 |
32+
// | int16, int32, | | undefined | 0 |
33+
// | int64 | | 1 † | 1 |
34+
// | | | new Number(1) † | 1 |
35+
// |-------------------+---------------+----------------------------------+---------------------------------------------|
36+
// | uint, uint8, | none | null | 0 |
37+
// | uint16, uint32, | | undefined | 0 |
38+
// | uint64 | | 1 † | 1 |
39+
// | | | new Number(1) † | 1 |
40+
// |-------------------+---------------+----------------------------------+---------------------------------------------|
41+
// | float32, float64 | none | null | 0 |
42+
// | | | undefined | 0 |
43+
// | | | 1 † | 1 |
44+
// | | | new Number(1) † | 1 |
45+
// |-------------------+---------------+----------------------------------+---------------------------------------------|
46+
// | [n]X - array type | none | null | zero val of [n]X |
47+
// | length n and | | undefined | zero val of [n]X |
48+
// | element type X | | new Array(n) | zero val of [n]X |
49+
// | | | new Array(x1, x2, ... xn) | [n]X{x1, x2, ... xn} |
50+
// | | | new TypedArray(n) ‡ | zero val of [n]X |
51+
// |-------------------+---------------+----------------------------------+---------------------------------------------|
52+
// | []X - slice type | none | null | ([]X)(nil) |
53+
// | element type X | | undefined | ([]X)(nil) |
54+
// | | | new Array(n) | ([]X)(nil) |
55+
// | | | new Array(x1, x2, ... xn) | [n]X{x1, x2, ... xn} |
56+
// | | | new TypedArray(n) ‡ | ([]X)(nil) |
57+
// |-------------------+---------------+----------------------------------+---------------------------------------------|
2758
//
2859
// Any source values not listed in this table cause a runtime panic for a given
2960
// target type if a conversion is attempted, e.g. a Javascript number value
3061
// being assigned to a string type Go variable.
3162
//
32-
// Source values annotated with † are generally applicable to all valid
63+
// † - Source values annotated with † are generally applicable to all valid
3364
// values of the target type. e.g. for target type string, "ok" represents
3465
// all valid string primitive values.
3566
//
67+
// ‡ - TypedArray types, Int8Array etc., can be used in place of Array values
68+
// where the type corresponds to the Go target type, e.g. Int8Array is valid
69+
// for target types [n]int8 or []int8.
70+
//
3671
// Externalization
3772
//
3873
// When values pass from Go to Javascript, a process known as externalization,

js/js_test.go

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -631,6 +631,135 @@ func TestInternalizeTime(t *testing.T) {
631631
}
632632
}
633633

634+
func TestInternalizeArray(t *testing.T) {
635+
type Internalize struct {
636+
*js.Object
637+
638+
array [2]int `js:"array"`
639+
}
640+
641+
testVals := []struct {
642+
source string
643+
target [2]int
644+
error string
645+
}{
646+
{
647+
source: `undefined`,
648+
},
649+
{
650+
source: `null`,
651+
},
652+
{
653+
source: `new Array(1,2)`,
654+
target: [2]int{1, 2},
655+
},
656+
{
657+
source: `Int32Array.from("12")`,
658+
target: [2]int{1, 2},
659+
},
660+
{
661+
source: `new Array(1)`,
662+
error: `runtime error: internalize [2]int, wrong size from Javascript native object/Array`,
663+
},
664+
}
665+
666+
for _, v := range testVals {
667+
o := js.Global.Get("Object").New()
668+
o.Set("array", js.Global.Call("eval", v.source))
669+
i := &Internalize{Object: o}
670+
671+
if v.error == "" {
672+
if v.target != i.array {
673+
t.Fatalf("expected %q to give %v; got %v", v.source, v.target, i.array)
674+
}
675+
} else {
676+
func() {
677+
defer func() {
678+
err, ok := recover().(error)
679+
if !ok {
680+
t.Fatalf("expected to have had to handle panic; we didn't see a panic")
681+
}
682+
683+
if err.Error() != v.error {
684+
t.Fatalf("expected error %q, got %q", v.error, err)
685+
}
686+
}()
687+
688+
_ = i.array
689+
}()
690+
}
691+
}
692+
}
693+
694+
func TestInternalizeSlice(t *testing.T) {
695+
type Internalize struct {
696+
*js.Object
697+
698+
slice []int `js:"slice"`
699+
}
700+
701+
testVals := []struct {
702+
source string
703+
target []int
704+
error string
705+
}{
706+
{
707+
source: `undefined`,
708+
},
709+
{
710+
source: `null`,
711+
},
712+
{
713+
source: `new Array(1,2)`,
714+
target: []int{1, 2},
715+
},
716+
{
717+
source: `Int32Array.from("12")`,
718+
target: []int{1, 2},
719+
},
720+
{
721+
source: `new Array()`,
722+
target: ([]int)(nil),
723+
},
724+
{
725+
source: `new Array("ok")`,
726+
error: "runtime error: internalize int, invalid value of type string/String",
727+
},
728+
}
729+
730+
for _, v := range testVals {
731+
o := js.Global.Get("Object").New()
732+
o.Set("slice", js.Global.Call("eval", v.source))
733+
i := &Internalize{Object: o}
734+
735+
if v.error == "" {
736+
if len(v.target) != len(i.slice) {
737+
t.Fatalf("expected %q to give len(i.slice) %v; got %v", v.source, len(v.target), len(i.slice))
738+
}
739+
for j := range v.target {
740+
if v.target[j] != i.slice[j] {
741+
t.Fatalf("expected %q to give i.slice[%v] %v; got %v", v.source, j, v.target[j], i.slice[j])
742+
}
743+
}
744+
} else {
745+
func() {
746+
defer func() {
747+
err, ok := recover().(error)
748+
if !ok {
749+
t.Fatalf("expected to have had to handle panic; we didn't see a panic")
750+
}
751+
752+
if err.Error() != v.error {
753+
t.Fatalf("expected error %q, got %q", v.error, err)
754+
}
755+
}()
756+
757+
_ = i.slice
758+
}()
759+
}
760+
}
761+
}
762+
634763
func jsval(v string) *js.Object {
635764
return js.Global.Call("eval", v)
636765
}

0 commit comments

Comments
 (0)