1
0
mirror of https://github.com/robertkrimen/otto synced 2025-09-28 18:45:22 +08:00

Add a String.substr implementation

This will fix #6
This commit is contained in:
Robert Krimen 2012-10-19 13:26:22 -07:00
parent 512c48831e
commit f842eda638
4 changed files with 106 additions and 10 deletions

View File

@ -25,6 +25,7 @@ TEST := -v --run String_fromCharCode
TEST := -v --run ParseFailure
TEST := -v --run Lexer\|Parse
TEST := -v --run Lexer
TEST := -v --run String_
TEST := .
test: test-i

View File

@ -589,7 +589,7 @@ func builtinString_slice(call FunctionCall) Value {
target := toString(call.This)
length := uint(len(target))
start, end := sliceStartEnd(call.ArgumentList, length)
start, end := rangeStartEnd(call.ArgumentList, length)
if 0 >= end - start {
return toValue("")
}
@ -600,15 +600,40 @@ func builtinString_substring(call FunctionCall) Value {
checkObjectCoercible(call.This)
target := toString(call.This)
length := uint(len(target))
start := valueToArrayIndex(call.Argument(0), length, false)
end := valueToArrayIndex(call.Argument(1), length, false)
size := uint(len(target))
start := valueToArrayIndex(call.Argument(0), size, false)
end := valueToArrayIndex(call.Argument(1), size, false)
if start > end {
start, end = end, start
}
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 {
checkObjectCoercible(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)
}
func sliceStartEnd(source []Value, length uint) (start, end uint) {
start = valueToArrayIndex(valueOfArrayIndex(source, 0), length, true)
func rangeStartEnd(source []Value, size uint) (start, end uint) {
start = valueToArrayIndex(valueOfArrayIndex(source, 0), size, true)
if len(source) == 1 {
end = length
// If there is only the start argument, then end = size
end = size
return
}
end = length
// Assuming the argument is undefined...
end = size
endValue := valueOfArrayIndex(source, 1)
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
}
@ -884,7 +930,7 @@ func builtinArray_slice(call FunctionCall) Value {
thisObject := call.thisObject()
length := uint(toUI32(thisObject.Get("length")))
start, end := sliceStartEnd(call.ArgumentList, length)
start, end := rangeStartEnd(call.ArgumentList, length)
if start >= end {
// Always an empty array

View File

@ -16,3 +16,51 @@ func TestString_fromCharCode(t *testing.T) {
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")
}

View File

@ -237,6 +237,7 @@ func newContext() *_runtime {
"substring", 2, builtinString_substring,
"toLowerCase", 0, builtinString_toLowerCase,
"toUpperCase", 0, builtinString_toUpperCase,
"substr", 2, builtinString_substr,
)
// TODO Maybe streamline this redundancy?
self.Global.String.Define(