3 Star 1 Fork 0

Gitee 极速下载/otto

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
此仓库是为了提升国内下载速度的镜像仓库,每日同步一次。 原始仓库: https://github.com/robertkrimen/otto
克隆/下载
builtin_array.go 19.44 KB
一键复制 编辑 原始数据 按行查看 历史
Steven Hartland 提交于 2024-04-13 17:05 . chore: update ci versions (#519)
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683
package otto
import (
"strconv"
"strings"
)
// Array
func builtinArray(call FunctionCall) Value {
return objectValue(builtinNewArrayNative(call.runtime, call.ArgumentList))
}
func builtinNewArray(obj *object, argumentList []Value) Value {
return objectValue(builtinNewArrayNative(obj.runtime, argumentList))
}
func builtinNewArrayNative(rt *runtime, argumentList []Value) *object {
if len(argumentList) == 1 {
firstArgument := argumentList[0]
if firstArgument.IsNumber() {
return rt.newArray(arrayUint32(rt, firstArgument))
}
}
return rt.newArrayOf(argumentList)
}
func builtinArrayToString(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 builtinObjectToString(call)
}
func builtinArrayToLocaleString(call FunctionCall) Value {
separator := ","
thisObject := call.thisObject()
length := int64(toUint32(thisObject.get(propertyLength)))
if length == 0 {
return stringValue("")
}
stringList := make([]string, 0, length)
for index := int64(0); index < length; index++ {
value := thisObject.get(arrayIndexToString(index))
stringValue := ""
switch value.kind {
case valueEmpty, valueUndefined, valueNull:
default:
obj := call.runtime.toObject(value)
toLocaleString := obj.get("toLocaleString")
if !toLocaleString.isCallable() {
panic(call.runtime.panicTypeError("Array.toLocaleString index[%d] %q is not callable", index, toLocaleString))
}
stringValue = toLocaleString.call(call.runtime, objectValue(obj)).string()
}
stringList = append(stringList, stringValue)
}
return stringValue(strings.Join(stringList, separator))
}
func builtinArrayConcat(call FunctionCall) Value {
thisObject := call.thisObject()
valueArray := []Value{}
source := append([]Value{objectValue(thisObject)}, call.ArgumentList...)
for _, item := range source {
switch item.kind {
case valueObject:
obj := item.object()
if isArray(obj) {
length := obj.get(propertyLength).number().int64
for index := int64(0); index < length; index++ {
name := strconv.FormatInt(index, 10)
if obj.hasProperty(name) {
valueArray = append(valueArray, obj.get(name))
} else {
valueArray = append(valueArray, Value{})
}
}
continue
}
fallthrough
default:
valueArray = append(valueArray, item)
}
}
return objectValue(call.runtime.newArrayOf(valueArray))
}
func builtinArrayShift(call FunctionCall) Value {
thisObject := call.thisObject()
length := int64(toUint32(thisObject.get(propertyLength)))
if length == 0 {
thisObject.put(propertyLength, int64Value(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(propertyLength, int64Value(length-1), true)
return first
}
func builtinArrayPush(call FunctionCall) Value {
thisObject := call.thisObject()
itemList := call.ArgumentList
index := int64(toUint32(thisObject.get(propertyLength)))
for len(itemList) > 0 {
thisObject.put(arrayIndexToString(index), itemList[0], true)
itemList = itemList[1:]
index++
}
length := int64Value(index)
thisObject.put(propertyLength, length, true)
return length
}
func builtinArrayPop(call FunctionCall) Value {
thisObject := call.thisObject()
length := int64(toUint32(thisObject.get(propertyLength)))
if length == 0 {
thisObject.put(propertyLength, uint32Value(0), true)
return Value{}
}
last := thisObject.get(arrayIndexToString(length - 1))
thisObject.delete(arrayIndexToString(length-1), true)
thisObject.put(propertyLength, int64Value(length-1), true)
return last
}
func builtinArrayJoin(call FunctionCall) Value {
separator := ","
argument := call.Argument(0)
if argument.IsDefined() {
separator = argument.string()
}
thisObject := call.thisObject()
length := int64(toUint32(thisObject.get(propertyLength)))
if length == 0 {
return stringValue("")
}
stringList := make([]string, 0, length)
for index := int64(0); index < length; index++ {
value := thisObject.get(arrayIndexToString(index))
stringValue := ""
switch value.kind {
case valueEmpty, valueUndefined, valueNull:
default:
stringValue = value.string()
}
stringList = append(stringList, stringValue)
}
return stringValue(strings.Join(stringList, separator))
}
func builtinArraySplice(call FunctionCall) Value {
thisObject := call.thisObject()
length := int64(toUint32(thisObject.get(propertyLength)))
start := valueToRangeIndex(call.Argument(0), length, false)
deleteCount := length - start
if arg, ok := call.getArgument(1); ok {
deleteCount = valueToRangeIndex(arg, length-start, true)
}
valueArray := make([]Value, deleteCount)
for index := int64(0); index < deleteCount; index++ {
indexString := arrayIndexToString(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 := 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 := 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 := 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(propertyLength, int64Value(length+itemCount-deleteCount), true)
return objectValue(call.runtime.newArrayOf(valueArray))
}
func builtinArraySlice(call FunctionCall) Value {
thisObject := call.thisObject()
length := int64(toUint32(thisObject.get(propertyLength)))
start, end := rangeStartEnd(call.ArgumentList, length, false)
if start >= end {
// Always an empty array
return objectValue(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 objectValue(call.runtime.newArrayOf(sliceValueArray))
}
func builtinArrayUnshift(call FunctionCall) Value {
thisObject := call.thisObject()
length := int64(toUint32(thisObject.get(propertyLength)))
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 := int64Value(length + itemCount)
thisObject.put(propertyLength, newLength, true)
return newLength
}
func builtinArrayReverse(call FunctionCall) Value {
thisObject := call.thisObject()
length := int64(toUint32(thisObject.get(propertyLength)))
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)
switch {
case 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)
case !lower.exists && upper.exists:
value := thisObject.get(upper.name)
thisObject.delete(upper.name, true)
thisObject.put(lower.name, value, true)
case lower.exists && !upper.exists:
value := thisObject.get(lower.name)
thisObject.delete(lower.name, true)
thisObject.put(upper.name, value, true)
}
lower.index++
}
return call.This
}
func sortCompare(thisObject *object, index0, index1 uint, compare *object) int {
j := struct {
name string
value string
exists bool
defined 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)
switch {
case !j.exists && !k.exists:
return 0
case !j.exists:
return 1
case !k.exists:
return -1
}
x := thisObject.get(j.name)
y := thisObject.get(k.name)
j.defined = x.IsDefined()
k.defined = y.IsDefined()
switch {
case !j.defined && !k.defined:
return 0
case !j.defined:
return 1
case !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 toIntSign(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)
switch {
case j.exists && k.exists:
jv := thisObject.get(j.name)
kv := thisObject.get(k.name)
thisObject.put(j.name, kv, true)
thisObject.put(k.name, jv, true)
case !j.exists && k.exists:
value := thisObject.get(k.name)
thisObject.delete(k.name, true)
thisObject.put(j.name, value, true)
case j.exists && !k.exists:
value := thisObject.get(j.name)
thisObject.delete(j.name, true)
thisObject.put(k.name, value, true)
}
}
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++
cursor2++
} else if comparison == 0 {
arraySortSwap(thisObject, index, cursor2)
cursor2++
}
}
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 builtinArraySort(call FunctionCall) Value {
thisObject := call.thisObject()
length := uint(toUint32(thisObject.get(propertyLength)))
compareValue := call.Argument(0)
compare := compareValue.object()
if compareValue.IsUndefined() {
} else if !compareValue.isCallable() {
panic(call.runtime.panicTypeError("Array.sort value %q is not callable", compareValue))
}
if length > 1 {
arraySortQuickSort(thisObject, 0, length-1, compare)
}
return call.This
}
func builtinArrayIsArray(call FunctionCall) Value {
return boolValue(isArray(call.Argument(0).object()))
}
func builtinArrayIndexOf(call FunctionCall) Value {
thisObject, matchValue := call.thisObject(), call.Argument(0)
if length := int64(toUint32(thisObject.get(propertyLength))); 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(index)
if !thisObject.hasProperty(name) {
continue
}
value := thisObject.get(name)
if strictEqualityComparison(matchValue, value) {
return uint32Value(uint32(index))
}
}
}
return intValue(-1)
}
func builtinArrayLastIndexOf(call FunctionCall) Value {
thisObject, matchValue := call.thisObject(), call.Argument(0)
length := int64(toUint32(thisObject.get(propertyLength)))
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 intValue(-1)
}
for ; index >= 0; index-- {
name := arrayIndexToString(index)
if !thisObject.hasProperty(name) {
continue
}
value := thisObject.get(name)
if strictEqualityComparison(matchValue, value) {
return uint32Value(uint32(index))
}
}
return intValue(-1)
}
func builtinArrayEvery(call FunctionCall) Value {
thisObject := call.thisObject()
this := objectValue(thisObject)
if iterator := call.Argument(0); iterator.isCallable() {
length := int64(toUint32(thisObject.get(propertyLength)))
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, int64Value(index), this).bool() {
continue
}
return falseValue
}
}
return trueValue
}
panic(call.runtime.panicTypeError("Array.every argument %q is not callable", call.Argument(0)))
}
func builtinArraySome(call FunctionCall) Value {
thisObject := call.thisObject()
this := objectValue(thisObject)
if iterator := call.Argument(0); iterator.isCallable() {
length := int64(toUint32(thisObject.get(propertyLength)))
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, int64Value(index), this).bool() {
return trueValue
}
}
}
return falseValue
}
panic(call.runtime.panicTypeError("Array.some %q if not callable", call.Argument(0)))
}
func builtinArrayForEach(call FunctionCall) Value {
thisObject := call.thisObject()
this := objectValue(thisObject)
if iterator := call.Argument(0); iterator.isCallable() {
length := int64(toUint32(thisObject.get(propertyLength)))
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), int64Value(index), this)
}
}
return Value{}
}
panic(call.runtime.panicTypeError("Array.foreach %q if not callable", call.Argument(0)))
}
func builtinArrayMap(call FunctionCall) Value {
thisObject := call.thisObject()
this := objectValue(thisObject)
if iterator := call.Argument(0); iterator.isCallable() {
length := int64(toUint32(thisObject.get(propertyLength)))
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 objectValue(call.runtime.newArrayOf(values))
}
panic(call.runtime.panicTypeError("Array.foreach %q if not callable", call.Argument(0)))
}
func builtinArrayFilter(call FunctionCall) Value {
thisObject := call.thisObject()
this := objectValue(thisObject)
if iterator := call.Argument(0); iterator.isCallable() {
length := int64(toUint32(thisObject.get(propertyLength)))
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 objectValue(call.runtime.newArrayOf(values))
}
panic(call.runtime.panicTypeError("Array.filter %q if not callable", call.Argument(0)))
}
func builtinArrayReduce(call FunctionCall) Value {
thisObject := call.thisObject()
this := objectValue(thisObject)
if iterator := call.Argument(0); iterator.isCallable() {
initial := len(call.ArgumentList) > 1
start := call.Argument(1)
length := int64(toUint32(thisObject.get(propertyLength)))
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), index, this)
}
}
return accumulator
}
}
panic(call.runtime.panicTypeError("Array.reduce %q if not callable", call.Argument(0)))
}
func builtinArrayReduceRight(call FunctionCall) Value {
thisObject := call.thisObject()
this := objectValue(thisObject)
if iterator := call.Argument(0); iterator.isCallable() {
initial := len(call.ArgumentList) > 1
start := call.Argument(1)
length := int64(toUint32(thisObject.get(propertyLength)))
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("Array.reduceRight %q if not callable", call.Argument(0)))
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/mirrors/otto.git
git@gitee.com:mirrors/otto.git
mirrors
otto
otto
master

搜索帮助

0d507c66 1850385 C8b1a773 1850385