Skip to content

Commit

Permalink
feat: support push to go slices
Browse files Browse the repository at this point in the history
Add support for direct use of push to go slices without converting to
array using .slice().

Fixes #357

Also:
* Add classGoSlice and use it, to make it clear the type when debugging.
  • Loading branch information
stevenh committed Nov 27, 2022
1 parent a3b51c6 commit 751ea08
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 11 deletions.
1 change: 1 addition & 0 deletions consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const (
// Common classes.
classString = "String"
classGoArray = "GoArray"
classGoSlice = "GoSlice"
classNumber = "Number"
classDate = "Date"
classArray = "Array"
Expand Down
20 changes: 20 additions & 0 deletions issue_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -942,3 +942,23 @@ func Test_issue383(t *testing.T) {
`)
require.NoError(t, err)
}

func Test_issue357(t *testing.T) {
vm := New()
arr := []string{"wow", "hey"}
err := vm.Set("arr", arr)
require.NoError(t, err)

val, err := vm.Run(`
arr.push('another', 'more');
arr;
`)
require.NoError(t, err)
iface, err := val.Export()
require.NoError(t, err)

slice, ok := iface.([]string)
require.True(t, ok)

require.Equal(t, []string{"wow", "hey", "another", "more"}, slice)
}
5 changes: 3 additions & 2 deletions runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,8 @@ func (self *_runtime) convertCallParameter(v Value, t reflect.Type) (reflect.Val

tt := t.Elem()

if o.class == classArray {
switch o.class {
case classArray:
for i := int64(0); i < l; i++ {
p, ok := o.property[strconv.FormatInt(i, 10)]
if !ok {
Expand All @@ -450,7 +451,7 @@ func (self *_runtime) convertCallParameter(v Value, t reflect.Type) (reflect.Val

s.Index(int(i)).Set(ev)
}
} else if o.class == classGoArray {
case classGoArray, classGoSlice:
var gslice bool
switch o.value.(type) {
case *_goSliceObject:
Expand Down
13 changes: 11 additions & 2 deletions type_array.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,16 @@ func (runtime *_runtime) newArrayObject(length uint32) *_object {
}

func isArray(object *_object) bool {
return object != nil && (object.class == classArray || object.class == classGoArray)
if object == nil {
return false
}

switch object.class {
case classArray, classGoArray, classGoSlice:
return true
default:
return false
}
}

func objectLength(object *_object) uint32 {
Expand All @@ -25,7 +34,7 @@ func objectLength(object *_object) uint32 {
return object.get(propertyLength).value.(uint32)
case classString:
return uint32(object.get(propertyLength).value.(int))
case classGoArray:
case classGoArray, classGoSlice:
return uint32(object.get(propertyLength).value.(int))
}
return 0
Expand Down
43 changes: 36 additions & 7 deletions type_go_slice.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (

func (runtime *_runtime) newGoSliceObject(value reflect.Value) *_object {
self := runtime.newObject()
self.class = classGoArray // TODO GoSlice?
self.class = classGoSlice
self.objectClass = _classGoSlice
self.value = _newGoSliceObject(value)
return self
Expand All @@ -31,15 +31,43 @@ func (self _goSliceObject) getValue(index int64) (reflect.Value, bool) {
return reflect.Value{}, false
}

func (self _goSliceObject) setValue(index int64, value Value) bool {
indexValue, exists := self.getValue(index)
if !exists {
return false
func (self *_goSliceObject) setLength(value Value) {
want, err := value.ToInteger()
if err != nil {
panic(err)
}

wantInt := int(want)
switch {
case wantInt == self.value.Len():
// No change needed.
case wantInt < self.value.Cap():
// Fits in current capacity.
self.value.SetLen(wantInt)
default:
// Needs expanding.
newSlice := reflect.MakeSlice(self.value.Type(), wantInt, wantInt)
reflect.Copy(newSlice, self.value)
self.value = newSlice
}
}

func (self *_goSliceObject) setValue(index int64, value Value) bool {
reflectValue, err := value.toReflectValue(self.value.Type().Elem().Kind())
if err != nil {
panic(err)
}

indexValue, exists := self.getValue(index)
if !exists {
if int64(self.value.Len()) == index {
// Trying to append e.g. slice.push(...), allow it.
self.value = reflect.Append(self.value, reflectValue)
return true
}
return false
}

indexValue.Set(reflectValue)
return true
}
Expand All @@ -49,7 +77,7 @@ func goSliceGetOwnProperty(self *_object, name string) *_property {
if name == propertyLength {
return &_property{
value: toValue(self.value.(*_goSliceObject).value.Len()),
mode: 0,
mode: 0110,
}
}

Expand Down Expand Up @@ -93,7 +121,8 @@ func goSliceEnumerate(self *_object, all bool, each func(string) bool) {

func goSliceDefineOwnProperty(self *_object, name string, descriptor _property, throw bool) bool {
if name == propertyLength {
return self.runtime.typeErrorResult(throw)
self.value.(*_goSliceObject).setLength(descriptor.value.(Value))
return true
} else if index := stringToArrayIndex(name); index >= 0 {
if self.value.(*_goSliceObject).setValue(index, descriptor.value.(Value)) {
return true
Expand Down

0 comments on commit 751ea08

Please sign in to comment.