-
-
Notifications
You must be signed in to change notification settings - Fork 223
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Extend Value into the Object type (#74)
* basic return of an Object from value * implement object set property * get the global object and get object instance from template * Object Get methods and locking in the API for this PR * fix C++ failing issues * basic tests for the Object methods * value tests and iso fix * update changelog * address comments from review
- Loading branch information
Showing
12 changed files
with
441 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
// Copyright 2021 Roger Chapman and the v8go contributors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
package v8go | ||
|
||
// #include <stdlib.h> | ||
// #include "v8go.h" | ||
import "C" | ||
import ( | ||
"errors" | ||
"fmt" | ||
"math/big" | ||
"unsafe" | ||
) | ||
|
||
// Object is a JavaScript object (ECMA-262, 4.3.3) | ||
type Object struct { | ||
*Value | ||
} | ||
|
||
// Set will set a property on the Object to a given value. | ||
// Supports all value types, eg: Object, Array, Date, Set, Map etc | ||
// If the value passed is a Go supported primitive (string, int32, uint32, int64, uint64, float64, big.Int) | ||
// then a *Value will be created and set as the value property. | ||
func (o *Object) Set(key string, val interface{}) error { | ||
if len(key) == 0 { | ||
return errors.New("v8go: You must provide a valid property key") | ||
} | ||
return set(o, key, 0, val) | ||
} | ||
|
||
// Set will set a given index on the Object to a given value. | ||
// Supports all value types, eg: Object, Array, Date, Set, Map etc | ||
// If the value passed is a Go supported primitive (string, int32, uint32, int64, uint64, float64, big.Int) | ||
// then a *Value will be created and set as the value property. | ||
func (o *Object) SetIdx(idx uint32, val interface{}) error { | ||
return set(o, "", idx, val) | ||
} | ||
|
||
func set(o *Object, key string, idx uint32, val interface{}) error { | ||
var value *Value | ||
switch v := val.(type) { | ||
case string, int32, uint32, int64, uint64, float64, bool, *big.Int: | ||
// ignoring error as code cannot reach the error state as we are already | ||
// validating the new value types in this case statement | ||
value, _ = NewValue(o.ctx.iso, v) | ||
case Valuer: | ||
value = v.value() | ||
default: | ||
return fmt.Errorf("v8go: unsupported object property type `%T`", v) | ||
} | ||
|
||
if len(key) > 0 { | ||
ckey := C.CString(key) | ||
defer C.free(unsafe.Pointer(ckey)) | ||
C.ObjectSet(o.ptr, ckey, value.ptr) | ||
return nil | ||
} | ||
|
||
C.ObjectSetIdx(o.ptr, C.uint32_t(idx), value.ptr) | ||
return nil | ||
} | ||
|
||
// Get tries to get a Value for a given Object property key. | ||
func (o *Object) Get(key string) (*Value, error) { | ||
ckey := C.CString(key) | ||
defer C.free(unsafe.Pointer(ckey)) | ||
|
||
rtn := C.ObjectGet(o.ptr, ckey) | ||
return getValue(o.ctx, rtn), getError(rtn) | ||
} | ||
|
||
// GetIdx tries to get a Value at a give Object index. | ||
func (o *Object) GetIdx(idx uint32) (*Value, error) { | ||
rtn := C.ObjectGetIdx(o.ptr, C.uint32_t(idx)) | ||
return getValue(o.ctx, rtn), getError(rtn) | ||
} | ||
|
||
// Has calls the abstract operation HasProperty(O, P) described in ECMA-262, 7.3.10. | ||
// Returns true, if the object has the property, either own or on the prototype chain. | ||
func (o *Object) Has(key string) bool { | ||
ckey := C.CString(key) | ||
defer C.free(unsafe.Pointer(ckey)) | ||
return C.ObjectHas(o.ptr, ckey) != 0 | ||
} | ||
|
||
// HasIdx returns true if the object has a value at the given index. | ||
func (o *Object) HasIdx(idx uint32) bool { | ||
return C.ObjectHasIdx(o.ptr, C.uint32_t(idx)) != 0 | ||
} | ||
|
||
// Delete returns true if successful in deleting a named property on the object. | ||
func (o *Object) Delete(key string) bool { | ||
ckey := C.CString(key) | ||
defer C.free(unsafe.Pointer(ckey)) | ||
return C.ObjectDelete(o.ptr, ckey) != 0 | ||
} | ||
|
||
// DeleteIdx returns true if successful in deleting a value at a given index of the object. | ||
func (o *Object) DeleteIdx(idx uint32) bool { | ||
return C.ObjectDeleteIdx(o.ptr, C.uint32_t(idx)) != 0 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
// Copyright 2021 Roger Chapman and the v8go contributors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
package v8go_test | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
|
||
"rogchap.com/v8go" | ||
) | ||
|
||
func TestObjectSet(t *testing.T) { | ||
t.Parallel() | ||
|
||
ctx, _ := v8go.NewContext() | ||
val, _ := ctx.RunScript("const foo = {}; foo", "") | ||
obj, _ := val.AsObject() | ||
obj.Set("bar", "baz") | ||
baz, _ := ctx.RunScript("foo.bar", "") | ||
if baz.String() != "baz" { | ||
t.Errorf("unexpected value: %q", baz) | ||
} | ||
if err := obj.Set("", nil); err == nil { | ||
t.Error("expected error but got <nil>") | ||
} | ||
if err := obj.Set("a", 0); err == nil { | ||
t.Error("expected error but got <nil>") | ||
} | ||
obj.SetIdx(10, "ten") | ||
if ten, _ := ctx.RunScript("foo[10]", ""); ten.String() != "ten" { | ||
t.Errorf("unexpected value: %q", ten) | ||
} | ||
} | ||
|
||
func TestObjectGet(t *testing.T) { | ||
t.Parallel() | ||
|
||
ctx, _ := v8go.NewContext() | ||
val, _ := ctx.RunScript("const foo = { bar: 'baz'}; foo", "") | ||
obj, _ := val.AsObject() | ||
if bar, _ := obj.Get("bar"); bar.String() != "baz" { | ||
t.Errorf("unexpected value: %q", bar) | ||
} | ||
if baz, _ := obj.Get("baz"); !baz.IsUndefined() { | ||
t.Errorf("unexpected value: %q", baz) | ||
} | ||
ctx.RunScript("foo[5] = 5", "") | ||
if five, _ := obj.GetIdx(5); five.Integer() != 5 { | ||
t.Errorf("unexpected value: %q", five) | ||
} | ||
if u, _ := obj.GetIdx(55); !u.IsUndefined() { | ||
t.Errorf("unexpected value: %q", u) | ||
} | ||
} | ||
|
||
func TestObjectHas(t *testing.T) { | ||
t.Parallel() | ||
|
||
ctx, _ := v8go.NewContext() | ||
val, _ := ctx.RunScript("const foo = {a: 1, '2': 2}; foo", "") | ||
obj, _ := val.AsObject() | ||
if !obj.Has("a") { | ||
t.Error("expected true, got false") | ||
} | ||
if obj.Has("c") { | ||
t.Error("expected false, got true") | ||
} | ||
if !obj.HasIdx(2) { | ||
t.Error("expected true, got false") | ||
} | ||
if obj.HasIdx(1) { | ||
t.Error("expected false, got true") | ||
} | ||
} | ||
|
||
func TestObjectDelete(t *testing.T) { | ||
t.Parallel() | ||
|
||
ctx, _ := v8go.NewContext() | ||
val, _ := ctx.RunScript("const foo = { bar: 'baz', '2': 2}; foo", "") | ||
obj, _ := val.AsObject() | ||
if !obj.Has("bar") { | ||
t.Error("expected property to exist") | ||
} | ||
if !obj.Delete("bar") { | ||
t.Error("expected delete to return true, got false") | ||
} | ||
if obj.Has("bar") { | ||
t.Error("expected property to be deleted") | ||
} | ||
if !obj.DeleteIdx(2) { | ||
t.Error("expected delete to return true, got false") | ||
} | ||
|
||
} | ||
|
||
func ExampleObject_global() { | ||
iso, _ := v8go.NewIsolate() | ||
ctx, _ := v8go.NewContext(iso) | ||
global := ctx.Global() | ||
|
||
console, _ := v8go.NewObjectTemplate(iso) | ||
logfn, _ := v8go.NewFunctionTemplate(iso, func(info *v8go.FunctionCallbackInfo) *v8go.Value { | ||
fmt.Println(info.Args()[0]) | ||
return nil | ||
}) | ||
console.Set("log", logfn) | ||
consoleObj, _ := console.NewInstance(ctx) | ||
|
||
global.Set("console", consoleObj) | ||
ctx.RunScript("console.log('foo')", "") | ||
// Output: | ||
// foo | ||
} |
Oops, something went wrong.