go-ethereum/vendor/github.com/robertkrimen/otto/builtin_array.go
Péter Szilágyi 289b30715d Godeps, vendor: convert dependency management to trash (#3198)
This commit converts the dependency management from Godeps to the vendor
folder, also switching the tool from godep to trash. Since the upstream tool
lacks a few features proposed via a few PRs, until those PRs are merged in
(if), use github.com/karalabe/trash.

You can update dependencies via trash --update.

All dependencies have been updated to their latest version.

Parts of the build system are reworked to drop old notions of Godeps and
invocation of the go vet command so that it doesn't run against the vendor
folder, as that will just blow up during vetting.

The conversion drops OpenCL (and hence GPU mining support) from ethash and our
codebase. The short reasoning is that there's noone to maintain and having
opencl libs in our deps messes up builds as go install ./... tries to build
them, failing with unsatisfied link errors for the C OpenCL deps.

golang.org/x/net/context is not vendored in. We expect it to be fetched by the
user (i.e. using go get). To keep ci.go builds reproducible the package is
"vendored" in build/_vendor.
2016-10-28 19:05:01 +02:00

682 lines
19 KiB
Go

package otto
import (
"strconv"
"strings"
)
// Array
func builtinArray(call FunctionCall) Value {
return toValue_object(builtinNewArrayNative(call.runtime, call.ArgumentList))
}
func builtinNewArray(self *_object, argumentList []Value) Value {
return toValue_object(builtinNewArrayNative(self.runtime, argumentList))
}
func builtinNewArrayNative(runtime *_runtime, argumentList []Value) *_object {
if len(argumentList) == 1 {
firstArgument := argumentList[0]
if firstArgument.IsNumber() {
return runtime.newArray(arrayUint32(runtime, firstArgument))
}
}
return runtime.newArrayOf(argumentList)
}
func builtinArray_toString(call FunctionCall) Value {
thisObject := call.thisObject()
join := thisObject.get("join")
if join.isCallable() {
join := join._object()
return join.call(call.This, call.ArgumentList, false, nativeFrame)
}
return builtinObject_toString(call)
}
func builtinArray_toLocaleString(call FunctionCall) Value {
separator := ","
thisObject := call.thisObject()
length := int64(toUint32(thisObject.get("length")))
if length == 0 {
return toValue_string("")
}
stringList := make([]string, 0, length)
for index := int64(0); index < length; index += 1 {
value := thisObject.get(arrayIndexToString(index))
stringValue := ""
switch value.kind {
case valueEmpty, valueUndefined, valueNull:
default:
object := call.runtime.toObject(value)
toLocaleString := object.get("toLocaleString")
if !toLocaleString.isCallable() {
panic(call.runtime.panicTypeError())
}
stringValue = toLocaleString.call(call.runtime, toValue_object(object)).string()
}
stringList = append(stringList, stringValue)
}
return toValue_string(strings.Join(stringList, separator))
}
func builtinArray_concat(call FunctionCall) Value {
thisObject := call.thisObject()
valueArray := []Value{}
source := append([]Value{toValue_object(thisObject)}, call.ArgumentList...)
for _, item := range source {
switch item.kind {
case valueObject:
object := item._object()
if isArray(object) {
length := object.get("length").number().int64
for index := int64(0); index < length; index += 1 {
name := strconv.FormatInt(index, 10)
if object.hasProperty(name) {
valueArray = append(valueArray, object.get(name))
} else {
valueArray = append(valueArray, Value{})
}
}
continue
}
fallthrough
default:
valueArray = append(valueArray, item)
}
}
return toValue_object(call.runtime.newArrayOf(valueArray))
}
func builtinArray_shift(call FunctionCall) Value {
thisObject := call.thisObject()
length := int64(toUint32(thisObject.get("length")))
if 0 == length {
thisObject.put("length", toValue_int64(0), true)
return Value{}
}
first := thisObject.get("0")
for index := int64(1); index < length; index++ {
from := arrayIndexToString(index)
to := arrayIndexToString(index - 1)
if thisObject.hasProperty(from) {
thisObject.put(to, thisObject.get(from), true)
} else {
thisObject.delete(to, true)
}
}
thisObject.delete(arrayIndexToString(length-1), true)
thisObject.put("length", toValue_int64(length-1), true)
return first
}
func builtinArray_push(call FunctionCall) Value {
thisObject := call.thisObject()
itemList := call.ArgumentList
index := int64(toUint32(thisObject.get("length")))
for len(itemList) > 0 {
thisObject.put(arrayIndexToString(index), itemList[0], true)
itemList = itemList[1:]
index += 1
}
length := toValue_int64(index)
thisObject.put("length", length, true)
return length
}
func builtinArray_pop(call FunctionCall) Value {
thisObject := call.thisObject()
length := int64(toUint32(thisObject.get("length")))
if 0 == length {
thisObject.put("length", toValue_uint32(0), true)
return Value{}
}
last := thisObject.get(arrayIndexToString(length - 1))
thisObject.delete(arrayIndexToString(length-1), true)
thisObject.put("length", toValue_int64(length-1), true)
return last
}
func builtinArray_join(call FunctionCall) Value {
separator := ","
{
argument := call.Argument(0)
if argument.IsDefined() {
separator = argument.string()
}
}
thisObject := call.thisObject()
length := int64(toUint32(thisObject.get("length")))
if length == 0 {
return toValue_string("")
}
stringList := make([]string, 0, length)
for index := int64(0); index < length; index += 1 {
value := thisObject.get(arrayIndexToString(index))
stringValue := ""
switch value.kind {
case valueEmpty, valueUndefined, valueNull:
default:
stringValue = value.string()
}
stringList = append(stringList, stringValue)
}
return toValue_string(strings.Join(stringList, separator))
}
func builtinArray_splice(call FunctionCall) Value {
thisObject := call.thisObject()
length := int64(toUint32(thisObject.get("length")))
start := valueToRangeIndex(call.Argument(0), length, false)
deleteCount := valueToRangeIndex(call.Argument(1), int64(length)-start, true)
valueArray := make([]Value, deleteCount)
for index := int64(0); index < deleteCount; index++ {
indexString := arrayIndexToString(int64(start + index))
if thisObject.hasProperty(indexString) {
valueArray[index] = thisObject.get(indexString)
}
}
// 0, <1, 2, 3, 4>, 5, 6, 7
// a, b
// length 8 - delete 4 @ start 1
itemList := []Value{}
itemCount := int64(len(call.ArgumentList))
if itemCount > 2 {
itemCount -= 2 // Less the first two arguments
itemList = call.ArgumentList[2:]
} else {
itemCount = 0
}
if itemCount < deleteCount {
// The Object/Array is shrinking
stop := int64(length) - deleteCount
// The new length of the Object/Array before
// appending the itemList remainder
// Stopping at the lower bound of the insertion:
// Move an item from the after the deleted portion
// to a position after the inserted portion
for index := start; index < stop; index++ {
from := arrayIndexToString(index + deleteCount) // Position just after deletion
to := arrayIndexToString(index + itemCount) // Position just after splice (insertion)
if thisObject.hasProperty(from) {
thisObject.put(to, thisObject.get(from), true)
} else {
thisObject.delete(to, true)
}
}
// Delete off the end
// We don't bother to delete below <stop + itemCount> (if any) since those
// will be overwritten anyway
for index := int64(length); index > (stop + itemCount); index-- {
thisObject.delete(arrayIndexToString(index-1), true)
}
} else if itemCount > deleteCount {
// The Object/Array is growing
// The itemCount is greater than the deleteCount, so we do
// not have to worry about overwriting what we should be moving
// ---
// Starting from the upper bound of the deletion:
// Move an item from the after the deleted portion
// to a position after the inserted portion
for index := int64(length) - deleteCount; index > start; index-- {
from := arrayIndexToString(index + deleteCount - 1)
to := arrayIndexToString(index + itemCount - 1)
if thisObject.hasProperty(from) {
thisObject.put(to, thisObject.get(from), true)
} else {
thisObject.delete(to, true)
}
}
}
for index := int64(0); index < itemCount; index++ {
thisObject.put(arrayIndexToString(index+start), itemList[index], true)
}
thisObject.put("length", toValue_int64(int64(length)+itemCount-deleteCount), true)
return toValue_object(call.runtime.newArrayOf(valueArray))
}
func builtinArray_slice(call FunctionCall) Value {
thisObject := call.thisObject()
length := int64(toUint32(thisObject.get("length")))
start, end := rangeStartEnd(call.ArgumentList, length, false)
if start >= end {
// Always an empty array
return toValue_object(call.runtime.newArray(0))
}
sliceLength := end - start
sliceValueArray := make([]Value, sliceLength)
for index := int64(0); index < sliceLength; index++ {
from := arrayIndexToString(index + start)
if thisObject.hasProperty(from) {
sliceValueArray[index] = thisObject.get(from)
}
}
return toValue_object(call.runtime.newArrayOf(sliceValueArray))
}
func builtinArray_unshift(call FunctionCall) Value {
thisObject := call.thisObject()
length := int64(toUint32(thisObject.get("length")))
itemList := call.ArgumentList
itemCount := int64(len(itemList))
for index := length; index > 0; index-- {
from := arrayIndexToString(index - 1)
to := arrayIndexToString(index + itemCount - 1)
if thisObject.hasProperty(from) {
thisObject.put(to, thisObject.get(from), true)
} else {
thisObject.delete(to, true)
}
}
for index := int64(0); index < itemCount; index++ {
thisObject.put(arrayIndexToString(index), itemList[index], true)
}
newLength := toValue_int64(length + itemCount)
thisObject.put("length", newLength, true)
return newLength
}
func builtinArray_reverse(call FunctionCall) Value {
thisObject := call.thisObject()
length := int64(toUint32(thisObject.get("length")))
lower := struct {
name string
index int64
exists bool
}{}
upper := lower
lower.index = 0
middle := length / 2 // Division will floor
for lower.index != middle {
lower.name = arrayIndexToString(lower.index)
upper.index = length - lower.index - 1
upper.name = arrayIndexToString(upper.index)
lower.exists = thisObject.hasProperty(lower.name)
upper.exists = thisObject.hasProperty(upper.name)
if lower.exists && upper.exists {
lowerValue := thisObject.get(lower.name)
upperValue := thisObject.get(upper.name)
thisObject.put(lower.name, upperValue, true)
thisObject.put(upper.name, lowerValue, true)
} else if !lower.exists && upper.exists {
value := thisObject.get(upper.name)
thisObject.delete(upper.name, true)
thisObject.put(lower.name, value, true)
} else if lower.exists && !upper.exists {
value := thisObject.get(lower.name)
thisObject.delete(lower.name, true)
thisObject.put(upper.name, value, true)
} else {
// Nothing happens.
}
lower.index += 1
}
return call.This
}
func sortCompare(thisObject *_object, index0, index1 uint, compare *_object) int {
j := struct {
name string
exists bool
defined bool
value string
}{}
k := j
j.name = arrayIndexToString(int64(index0))
j.exists = thisObject.hasProperty(j.name)
k.name = arrayIndexToString(int64(index1))
k.exists = thisObject.hasProperty(k.name)
if !j.exists && !k.exists {
return 0
} else if !j.exists {
return 1
} else if !k.exists {
return -1
}
x := thisObject.get(j.name)
y := thisObject.get(k.name)
j.defined = x.IsDefined()
k.defined = y.IsDefined()
if !j.defined && !k.defined {
return 0
} else if !j.defined {
return 1
} else if !k.defined {
return -1
}
if compare == nil {
j.value = x.string()
k.value = y.string()
if j.value == k.value {
return 0
} else if j.value < k.value {
return -1
}
return 1
}
return int(toInt32(compare.call(Value{}, []Value{x, y}, false, nativeFrame)))
}
func arraySortSwap(thisObject *_object, index0, index1 uint) {
j := struct {
name string
exists bool
}{}
k := j
j.name = arrayIndexToString(int64(index0))
j.exists = thisObject.hasProperty(j.name)
k.name = arrayIndexToString(int64(index1))
k.exists = thisObject.hasProperty(k.name)
if j.exists && k.exists {
jValue := thisObject.get(j.name)
kValue := thisObject.get(k.name)
thisObject.put(j.name, kValue, true)
thisObject.put(k.name, jValue, true)
} else if !j.exists && k.exists {
value := thisObject.get(k.name)
thisObject.delete(k.name, true)
thisObject.put(j.name, value, true)
} else if j.exists && !k.exists {
value := thisObject.get(j.name)
thisObject.delete(j.name, true)
thisObject.put(k.name, value, true)
} else {
// Nothing happens.
}
}
func arraySortQuickPartition(thisObject *_object, left, right, pivot uint, compare *_object) (uint, uint) {
arraySortSwap(thisObject, pivot, right) // Right is now the pivot value
cursor := left
cursor2 := left
for index := left; index < right; index++ {
comparison := sortCompare(thisObject, index, right, compare) // Compare to the pivot value
if comparison < 0 {
arraySortSwap(thisObject, index, cursor)
if cursor < cursor2 {
arraySortSwap(thisObject, index, cursor2)
}
cursor += 1
cursor2 += 1
} else if comparison == 0 {
arraySortSwap(thisObject, index, cursor2)
cursor2 += 1
}
}
arraySortSwap(thisObject, cursor2, right)
return cursor, cursor2
}
func arraySortQuickSort(thisObject *_object, left, right uint, compare *_object) {
if left < right {
middle := left + (right-left)/2
pivot, pivot2 := arraySortQuickPartition(thisObject, left, right, middle, compare)
if pivot > 0 {
arraySortQuickSort(thisObject, left, pivot-1, compare)
}
arraySortQuickSort(thisObject, pivot2+1, right, compare)
}
}
func builtinArray_sort(call FunctionCall) Value {
thisObject := call.thisObject()
length := uint(toUint32(thisObject.get("length")))
compareValue := call.Argument(0)
compare := compareValue._object()
if compareValue.IsUndefined() {
} else if !compareValue.isCallable() {
panic(call.runtime.panicTypeError())
}
if length > 1 {
arraySortQuickSort(thisObject, 0, length-1, compare)
}
return call.This
}
func builtinArray_isArray(call FunctionCall) Value {
return toValue_bool(isArray(call.Argument(0)._object()))
}
func builtinArray_indexOf(call FunctionCall) Value {
thisObject, matchValue := call.thisObject(), call.Argument(0)
if length := int64(toUint32(thisObject.get("length"))); length > 0 {
index := int64(0)
if len(call.ArgumentList) > 1 {
index = call.Argument(1).number().int64
}
if index < 0 {
if index += length; index < 0 {
index = 0
}
} else if index >= length {
index = -1
}
for ; index >= 0 && index < length; index++ {
name := arrayIndexToString(int64(index))
if !thisObject.hasProperty(name) {
continue
}
value := thisObject.get(name)
if strictEqualityComparison(matchValue, value) {
return toValue_uint32(uint32(index))
}
}
}
return toValue_int(-1)
}
func builtinArray_lastIndexOf(call FunctionCall) Value {
thisObject, matchValue := call.thisObject(), call.Argument(0)
length := int64(toUint32(thisObject.get("length")))
index := length - 1
if len(call.ArgumentList) > 1 {
index = call.Argument(1).number().int64
}
if 0 > index {
index += length
}
if index > length {
index = length - 1
} else if 0 > index {
return toValue_int(-1)
}
for ; index >= 0; index-- {
name := arrayIndexToString(int64(index))
if !thisObject.hasProperty(name) {
continue
}
value := thisObject.get(name)
if strictEqualityComparison(matchValue, value) {
return toValue_uint32(uint32(index))
}
}
return toValue_int(-1)
}
func builtinArray_every(call FunctionCall) Value {
thisObject := call.thisObject()
this := toValue_object(thisObject)
if iterator := call.Argument(0); iterator.isCallable() {
length := int64(toUint32(thisObject.get("length")))
callThis := call.Argument(1)
for index := int64(0); index < length; index++ {
if key := arrayIndexToString(index); thisObject.hasProperty(key) {
if value := thisObject.get(key); iterator.call(call.runtime, callThis, value, toValue_int64(index), this).bool() {
continue
}
return falseValue
}
}
return trueValue
}
panic(call.runtime.panicTypeError())
}
func builtinArray_some(call FunctionCall) Value {
thisObject := call.thisObject()
this := toValue_object(thisObject)
if iterator := call.Argument(0); iterator.isCallable() {
length := int64(toUint32(thisObject.get("length")))
callThis := call.Argument(1)
for index := int64(0); index < length; index++ {
if key := arrayIndexToString(index); thisObject.hasProperty(key) {
if value := thisObject.get(key); iterator.call(call.runtime, callThis, value, toValue_int64(index), this).bool() {
return trueValue
}
}
}
return falseValue
}
panic(call.runtime.panicTypeError())
}
func builtinArray_forEach(call FunctionCall) Value {
thisObject := call.thisObject()
this := toValue_object(thisObject)
if iterator := call.Argument(0); iterator.isCallable() {
length := int64(toUint32(thisObject.get("length")))
callThis := call.Argument(1)
for index := int64(0); index < length; index++ {
if key := arrayIndexToString(index); thisObject.hasProperty(key) {
iterator.call(call.runtime, callThis, thisObject.get(key), toValue_int64(index), this)
}
}
return Value{}
}
panic(call.runtime.panicTypeError())
}
func builtinArray_map(call FunctionCall) Value {
thisObject := call.thisObject()
this := toValue_object(thisObject)
if iterator := call.Argument(0); iterator.isCallable() {
length := int64(toUint32(thisObject.get("length")))
callThis := call.Argument(1)
values := make([]Value, length)
for index := int64(0); index < length; index++ {
if key := arrayIndexToString(index); thisObject.hasProperty(key) {
values[index] = iterator.call(call.runtime, callThis, thisObject.get(key), index, this)
} else {
values[index] = Value{}
}
}
return toValue_object(call.runtime.newArrayOf(values))
}
panic(call.runtime.panicTypeError())
}
func builtinArray_filter(call FunctionCall) Value {
thisObject := call.thisObject()
this := toValue_object(thisObject)
if iterator := call.Argument(0); iterator.isCallable() {
length := int64(toUint32(thisObject.get("length")))
callThis := call.Argument(1)
values := make([]Value, 0)
for index := int64(0); index < length; index++ {
if key := arrayIndexToString(index); thisObject.hasProperty(key) {
value := thisObject.get(key)
if iterator.call(call.runtime, callThis, value, index, this).bool() {
values = append(values, value)
}
}
}
return toValue_object(call.runtime.newArrayOf(values))
}
panic(call.runtime.panicTypeError())
}
func builtinArray_reduce(call FunctionCall) Value {
thisObject := call.thisObject()
this := toValue_object(thisObject)
if iterator := call.Argument(0); iterator.isCallable() {
initial := len(call.ArgumentList) > 1
start := call.Argument(1)
length := int64(toUint32(thisObject.get("length")))
index := int64(0)
if length > 0 || initial {
var accumulator Value
if !initial {
for ; index < length; index++ {
if key := arrayIndexToString(index); thisObject.hasProperty(key) {
accumulator = thisObject.get(key)
index++
break
}
}
} else {
accumulator = start
}
for ; index < length; index++ {
if key := arrayIndexToString(index); thisObject.hasProperty(key) {
accumulator = iterator.call(call.runtime, Value{}, accumulator, thisObject.get(key), key, this)
}
}
return accumulator
}
}
panic(call.runtime.panicTypeError())
}
func builtinArray_reduceRight(call FunctionCall) Value {
thisObject := call.thisObject()
this := toValue_object(thisObject)
if iterator := call.Argument(0); iterator.isCallable() {
initial := len(call.ArgumentList) > 1
start := call.Argument(1)
length := int64(toUint32(thisObject.get("length")))
if length > 0 || initial {
index := length - 1
var accumulator Value
if !initial {
for ; index >= 0; index-- {
if key := arrayIndexToString(index); thisObject.hasProperty(key) {
accumulator = thisObject.get(key)
index--
break
}
}
} else {
accumulator = start
}
for ; index >= 0; index-- {
if key := arrayIndexToString(index); thisObject.hasProperty(key) {
accumulator = iterator.call(call.runtime, Value{}, accumulator, thisObject.get(key), key, this)
}
}
return accumulator
}
}
panic(call.runtime.panicTypeError())
}