mirror of
https://github.com/robertkrimen/otto
synced 2025-09-28 18:45:22 +08:00
parent
512c48831e
commit
f842eda638
1
Makefile
1
Makefile
|
@ -25,6 +25,7 @@ TEST := -v --run String_fromCharCode
|
||||||
TEST := -v --run ParseFailure
|
TEST := -v --run ParseFailure
|
||||||
TEST := -v --run Lexer\|Parse
|
TEST := -v --run Lexer\|Parse
|
||||||
TEST := -v --run Lexer
|
TEST := -v --run Lexer
|
||||||
|
TEST := -v --run String_
|
||||||
TEST := .
|
TEST := .
|
||||||
|
|
||||||
test: test-i
|
test: test-i
|
||||||
|
|
66
builtin.go
66
builtin.go
|
@ -589,7 +589,7 @@ func builtinString_slice(call FunctionCall) Value {
|
||||||
target := toString(call.This)
|
target := toString(call.This)
|
||||||
|
|
||||||
length := uint(len(target))
|
length := uint(len(target))
|
||||||
start, end := sliceStartEnd(call.ArgumentList, length)
|
start, end := rangeStartEnd(call.ArgumentList, length)
|
||||||
if 0 >= end - start {
|
if 0 >= end - start {
|
||||||
return toValue("")
|
return toValue("")
|
||||||
}
|
}
|
||||||
|
@ -600,15 +600,40 @@ func builtinString_substring(call FunctionCall) Value {
|
||||||
checkObjectCoercible(call.This)
|
checkObjectCoercible(call.This)
|
||||||
target := toString(call.This)
|
target := toString(call.This)
|
||||||
|
|
||||||
length := uint(len(target))
|
size := uint(len(target))
|
||||||
start := valueToArrayIndex(call.Argument(0), length, false)
|
start := valueToArrayIndex(call.Argument(0), size, false)
|
||||||
end := valueToArrayIndex(call.Argument(1), length, false)
|
end := valueToArrayIndex(call.Argument(1), size, false)
|
||||||
if start > end {
|
if start > end {
|
||||||
start, end = end, start
|
start, end = end, start
|
||||||
}
|
}
|
||||||
return toValue(target[start:end])
|
return toValue(target[start:end])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func builtinString_substr(call FunctionCall) Value {
|
||||||
|
target := toString(call.This)
|
||||||
|
|
||||||
|
size := int64(len(target))
|
||||||
|
start, length := rangeStartLength(call.ArgumentList, uint(size))
|
||||||
|
|
||||||
|
if start >= size {
|
||||||
|
return toValue("")
|
||||||
|
}
|
||||||
|
|
||||||
|
if length <= 0 {
|
||||||
|
return toValue("")
|
||||||
|
}
|
||||||
|
|
||||||
|
if start + length >= size {
|
||||||
|
// Cap length to be to the end of the string
|
||||||
|
// start = 3, length = 5, size = 4 [0, 1, 2, 3]
|
||||||
|
// 4 - 3 = 1
|
||||||
|
// target[3:4]
|
||||||
|
length = size - start
|
||||||
|
}
|
||||||
|
|
||||||
|
return toValue(target[start:start+length])
|
||||||
|
}
|
||||||
|
|
||||||
func builtinString_toLowerCase(call FunctionCall) Value {
|
func builtinString_toLowerCase(call FunctionCall) Value {
|
||||||
checkObjectCoercible(call.This)
|
checkObjectCoercible(call.This)
|
||||||
return toValue(strings.ToLower(toString(call.This)))
|
return toValue(strings.ToLower(toString(call.This)))
|
||||||
|
@ -789,17 +814,38 @@ func builtinArray_joinNative(valueArray []Value, separator string) string {
|
||||||
return strings.Join(stringList, separator)
|
return strings.Join(stringList, separator)
|
||||||
}
|
}
|
||||||
|
|
||||||
func sliceStartEnd(source []Value, length uint) (start, end uint) {
|
func rangeStartEnd(source []Value, size uint) (start, end uint) {
|
||||||
start = valueToArrayIndex(valueOfArrayIndex(source, 0), length, true)
|
start = valueToArrayIndex(valueOfArrayIndex(source, 0), size, true)
|
||||||
if len(source) == 1 {
|
if len(source) == 1 {
|
||||||
end = length
|
// If there is only the start argument, then end = size
|
||||||
|
end = size
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
end = length
|
// Assuming the argument is undefined...
|
||||||
|
end = size
|
||||||
endValue := valueOfArrayIndex(source, 1)
|
endValue := valueOfArrayIndex(source, 1)
|
||||||
if !endValue.IsUndefined() {
|
if !endValue.IsUndefined() {
|
||||||
end = valueToArrayIndex(endValue, length, true)
|
// Which it is not, so get the value as an array index
|
||||||
|
end = valueToArrayIndex(endValue, size, true)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func rangeStartLength(source []Value, size uint) (start, length int64) {
|
||||||
|
start = int64(valueToArrayIndex(valueOfArrayIndex(source, 0), size, true))
|
||||||
|
|
||||||
|
// Assume the second argument is missing or undefined
|
||||||
|
length = int64(size)
|
||||||
|
if len(source) == 1 {
|
||||||
|
// If there is only the start argument, then length = size
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
lengthValue := valueOfArrayIndex(source, 1)
|
||||||
|
if !lengthValue.IsUndefined() {
|
||||||
|
// Which it is not, so get the value as an array index
|
||||||
|
length = toInteger(lengthValue)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -884,7 +930,7 @@ func builtinArray_slice(call FunctionCall) Value {
|
||||||
thisObject := call.thisObject()
|
thisObject := call.thisObject()
|
||||||
|
|
||||||
length := uint(toUI32(thisObject.Get("length")))
|
length := uint(toUI32(thisObject.Get("length")))
|
||||||
start, end := sliceStartEnd(call.ArgumentList, length)
|
start, end := rangeStartEnd(call.ArgumentList, length)
|
||||||
|
|
||||||
if start >= end {
|
if start >= end {
|
||||||
// Always an empty array
|
// Always an empty array
|
||||||
|
|
|
@ -16,3 +16,51 @@ func TestString_fromCharCode(t *testing.T) {
|
||||||
test(`String.fromCharCode("0x21")`, "!")
|
test(`String.fromCharCode("0x21")`, "!")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestString_substr(t *testing.T) {
|
||||||
|
Terst(t)
|
||||||
|
|
||||||
|
test := runTest()
|
||||||
|
test(`"abc".substr(0,1)`, "a")
|
||||||
|
test(`"abc".substr(0,2)`, "ab")
|
||||||
|
test(`"abc".substr(0,3)`, "abc")
|
||||||
|
test(`"abc".substr(0,4)`, "abc")
|
||||||
|
test(`"abc".substr(0,9)`, "abc")
|
||||||
|
|
||||||
|
test(`"abc".substr(1,1)`, "b")
|
||||||
|
test(`"abc".substr(1,2)`, "bc")
|
||||||
|
test(`"abc".substr(1,3)`, "bc")
|
||||||
|
test(`"abc".substr(1,4)`, "bc")
|
||||||
|
test(`"abc".substr(1,9)`, "bc")
|
||||||
|
|
||||||
|
test(`"abc".substr(2,1)`, "c")
|
||||||
|
test(`"abc".substr(2,2)`, "c")
|
||||||
|
test(`"abc".substr(2,3)`, "c")
|
||||||
|
test(`"abc".substr(2,4)`, "c")
|
||||||
|
test(`"abc".substr(2,9)`, "c")
|
||||||
|
|
||||||
|
test(`"abc".substr(3,1)`, "")
|
||||||
|
test(`"abc".substr(3,2)`, "")
|
||||||
|
test(`"abc".substr(3,3)`, "")
|
||||||
|
test(`"abc".substr(3,4)`, "")
|
||||||
|
test(`"abc".substr(3,9)`, "")
|
||||||
|
|
||||||
|
test(`"abc".substr(0)`, "abc")
|
||||||
|
test(`"abc".substr(1)`, "bc")
|
||||||
|
test(`"abc".substr(2)`, "c")
|
||||||
|
test(`"abc".substr(3)`, "")
|
||||||
|
test(`"abc".substr(9)`, "")
|
||||||
|
|
||||||
|
test(`"abc".substr(-9)`, "abc")
|
||||||
|
test(`"abc".substr(-3)`, "abc")
|
||||||
|
test(`"abc".substr(-2)`, "bc")
|
||||||
|
test(`"abc".substr(-1)`, "c")
|
||||||
|
|
||||||
|
test(`"abc".substr(-9, 1)`, "a")
|
||||||
|
test(`"abc".substr(-3, 1)`, "a")
|
||||||
|
test(`"abc".substr(-2, 1)`, "b")
|
||||||
|
test(`"abc".substr(-1, 1)`, "c")
|
||||||
|
test(`"abc".substr(-1, 2)`, "c")
|
||||||
|
|
||||||
|
test(`"abcd".substr(3, 5)`, "d")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -237,6 +237,7 @@ func newContext() *_runtime {
|
||||||
"substring", 2, builtinString_substring,
|
"substring", 2, builtinString_substring,
|
||||||
"toLowerCase", 0, builtinString_toLowerCase,
|
"toLowerCase", 0, builtinString_toLowerCase,
|
||||||
"toUpperCase", 0, builtinString_toUpperCase,
|
"toUpperCase", 0, builtinString_toUpperCase,
|
||||||
|
"substr", 2, builtinString_substr,
|
||||||
)
|
)
|
||||||
// TODO Maybe streamline this redundancy?
|
// TODO Maybe streamline this redundancy?
|
||||||
self.Global.String.Define(
|
self.Global.String.Define(
|
||||||
|
|
Loading…
Reference in New Issue
Block a user