Skip to content

Commit

Permalink
Merge d1e5c65 into ef4f2a0
Browse files Browse the repository at this point in the history
  • Loading branch information
zyxkad committed Mar 7, 2024
2 parents ef4f2a0 + d1e5c65 commit 8344913
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 2 deletions.
20 changes: 20 additions & 0 deletions misc/wasm/wasm_exec.js
Expand Up @@ -334,6 +334,26 @@
Reflect.deleteProperty(loadValue(sp + 8), loadString(sp + 16));
},

// func valueGetRef(v ref, s ref) ref
"syscall/js.valueGetRef": (sp) => {
sp >>>= 0;
const result = Reflect.get(loadValue(sp + 8), loadValue(sp + 16));
sp = this._inst.exports.getsp() >>> 0; // see comment above
storeValue(sp + 24, result);
},

// func valueSetRef(v ref, s ref, x ref)
"syscall/js.valueSetRef": (sp) => {
sp >>>= 0;
Reflect.set(loadValue(sp + 8), loadValue(sp + 16), loadValue(sp + 24));
},

// func valueDeleteRef(v ref, s ref)
"syscall/js.valueDeleteRef": (sp) => {
sp >>>= 0;
Reflect.deleteProperty(loadValue(sp + 8), loadValue(sp + 16));
},

// func valueIndex(v ref, i int) ref
"syscall/js.valueIndex": (sp) => {
sp >>>= 0;
Expand Down
57 changes: 56 additions & 1 deletion src/syscall/js/js.go
Expand Up @@ -325,6 +325,60 @@ func (v Value) Delete(p string) {
//go:wasmimport gojs syscall/js.valueDelete
func valueDelete(v ref, p string)

// GetSymbol returns the JavaScript symbol s of value v.
// It panics if v is not a JavaScript object or s is not a JavaScript symbol.
func (v Value) GetSymbol(s Value) Value {
if vType := v.Type(); !vType.isObject() {
panic(&ValueError{"Value.GetSymbol", vType})
}
if sType := s.Type(); sType != TypeSymbol {
panic("syscall/js: Value.GetSymbol: argument 1 is not a symbol, got " + sType.String())
}
r := makeValue(valueGetRef(v.ref, s.ref))
runtime.KeepAlive(v)
runtime.KeepAlive(s)
return r
}

//go:wasmimport gojs syscall/js.valueGetRef
func valueGetRef(v ref, s ref) ref

// SetSymbol sets the JavaScript symbol s of value v to ValueOf(x).
// It panics if v is not a JavaScript object or s is not a JavaScript symbol.
func (v Value) SetSymbol(s Value, x any) {
if vType := v.Type(); !vType.isObject() {
panic(&ValueError{"Value.SetSymbol", vType})
}
if sType := s.Type(); sType != TypeSymbol {
panic("syscall/js: Value.SetSymbol: argument 1 is not a symbol, got " + sType.String())
}
xv := ValueOf(x)
valueSetRef(v.ref, s.ref, xv.ref)
runtime.KeepAlive(v)
runtime.KeepAlive(s)
runtime.KeepAlive(xv)
}

//go:wasmimport gojs syscall/js.valueSetRef
func valueSetRef(v ref, s ref, x ref)

// DeleteSymbol deletes the JavaScript symbol s of value v.
// It panics if v is not a JavaScript object or s is not a JavaScript symbol.
func (v Value) DeleteSymbol(s Value) {
if vType := v.Type(); !vType.isObject() {
panic(&ValueError{"Value.DeleteSymbol", vType})
}
if sType := s.Type(); sType != TypeSymbol {
panic("syscall/js: Value.DeleteSymbol: argument 1 is not a symbol, got " + sType.String())
}
valueDeleteRef(v.ref, s.ref)
runtime.KeepAlive(v)
runtime.KeepAlive(s)
}

//go:wasmimport gojs syscall/js.valueDeleteRef
func valueDeleteRef(v ref, s ref)

// Index returns JavaScript index i of value v.
// It panics if v is not a JavaScript object.
func (v Value) Index(i int) Value {
Expand Down Expand Up @@ -521,7 +575,8 @@ func (v Value) String() string {
case TypeNumber:
return "<number: " + jsString(v) + ">"
case TypeSymbol:
return "<symbol>"
// It's better to print out the symbol name here so we can debug easier
return "<symbol: " + jsString(v) + ">"
case TypeObject:
return "<object>"
case TypeFunction:
Expand Down
56 changes: 55 additions & 1 deletion src/syscall/js/js_test.go
Expand Up @@ -30,6 +30,8 @@ var dummys = js.Global().Call("eval", `({
someFloat: 42.123,
someArray: [41, 42, 43],
someDate: new Date(),
someSymbol: Symbol.iterator,
someSymbolFor: Symbol.for("someSymbolFor"),
add: function(a, b) {
return a + b;
},
Expand Down Expand Up @@ -97,7 +99,7 @@ func TestString(t *testing.T) {
if got, want := js.ValueOf(42.5).String(), "<number: 42.5>"; got != want {
t.Errorf("got %#v, want %#v", got, want)
}
if got, want := js.Global().Call("Symbol").String(), "<symbol>"; got != want {
if got, want := js.Global().Call("Symbol").String(), "<symbol: Symbol()>"; got != want {
t.Errorf("got %#v, want %#v", got, want)
}
if got, want := js.Global().String(), "<object>"; got != want {
Expand Down Expand Up @@ -159,6 +161,58 @@ func TestFloat(t *testing.T) {
}
}

func TestSymbol(t *testing.T) {
if got, want := dummys.Get("someSymbol"), js.Global().Get("Symbol").Get("iterator"); !got.Equal(want) {
t.Errorf("got %#v, want %#v", got, want)
}
if !dummys.Get("someSymbol").Equal(dummys.Get("someSymbol")) {
t.Errorf("same value not equal")
}
if got, want := dummys.Get("someSymbolFor"), js.Global().Get("Symbol").Call("for", "someSymbolFor"); !got.Equal(want) {
t.Errorf("got %#v, want %#v", got, want)
}
if !dummys.Get("someSymbolFor").Equal(dummys.Get("someSymbolFor")) {
t.Errorf("same value not equal")
}

if js.Global().Call("Symbol").Equal(js.Global().Call("Symbol")) {
t.Errorf("different Symbol instances are equal")
}

if iterSym := js.Global().Get("Symbol").Get("iterator"); iterSym.IsUndefined() {
t.Errorf("Symbol.iterator is undefined")
} else {
o := js.Global().Get("Object").New()
i := 0
o.Set("next", js.FuncOf(func(this js.Value, args []js.Value) any {
if i > 3 {
return object{"done": true, "value": nil}
}
i++
return object{"done": false, "value": 10 - i}
}))
o.SetSymbol(iterSym, js.FuncOf(func(this js.Value, args []js.Value) any {
return o
}))
r := js.Global().Call("eval", `(function(o){
if (typeof o[Symbol.iterator] !== "function") {
return "object is not iterable"
}
let i = 0
for (let got of o) {
i++
let want = 10 - i
if (got !== want) {
return "got " + got + " at iteration #" + i + ", want " + want
}
}
})`).Invoke(o)
if !r.IsUndefined() {
t.Error(r.String())
}
}
}

func TestObject(t *testing.T) {
if !dummys.Get("someArray").Equal(dummys.Get("someArray")) {
t.Errorf("same value not equal")
Expand Down

0 comments on commit 8344913

Please sign in to comment.