Commit 53406932 authored by YOU's avatar YOU Committed by Dylan Trotter

Fix IndexError to TypeError (#155)

parent 93543941
......@@ -487,21 +487,26 @@ func Index(f *Frame, o *Object) (*Object, *BaseException) {
// IndexInt returns the value of o converted to a Go int according to o's
// __index__ slot.
// It raises a TypeError if o doesn't have an __index__ method.
// If the returned value doesn't fit into an int, it raises an OverflowError.
func IndexInt(f *Frame, o *Object) (int, *BaseException) {
i, raised := Index(f, o)
if raised != nil {
return 0, raised
}
if i != nil {
if i.isInstance(IntType) {
return toIntUnsafe(i).Value(), nil
func IndexInt(f *Frame, o *Object) (i int, raised *BaseException) {
if index := o.typ.slots.Index; index != nil {
// Unwrap __index__ slot and fall through.
o, raised = index.Fn(f, o)
if raised != nil {
return 0, raised
}
if l := toLongUnsafe(i).Value(); numInIntRange(l) {
return int(l.Int64()), nil
}
if o.isInstance(IntType) {
return toIntUnsafe(o).Value(), nil
}
if o.isInstance(LongType) {
l := toLongUnsafe(o).Value()
// Anything bigger than maxIntBig will treat as maxIntBig.
if !numInIntRange(l) {
l = maxIntBig
}
return int(l.Int64()), nil
}
return 0, f.RaiseType(IndexErrorType, fmt.Sprintf("cannot fit '%s' into an index-sized integer", o.typ))
return 0, f.RaiseType(TypeErrorType, errBadSliceIndex)
}
// Invoke calls the given callable with the positional arguments given by args
......
......@@ -221,13 +221,13 @@ func strFind(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) {
s := toStrUnsafe(args[0]).Value()
l := len(s)
start, end := 0, l
if argc >= 3 {
if argc >= 3 && args[2] != None {
start, raised = IndexInt(f, args[2])
if raised != nil {
return nil, raised
}
}
if argc == 4 {
if argc == 4 && args[3] != None {
end, raised = IndexInt(f, args[3])
if raised != nil {
return nil, raised
......@@ -236,7 +236,7 @@ func strFind(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) {
if start > l {
return NewInt(-1).ToObject(), nil
}
start, end = adjustIndex(start, l), adjustIndex(end, l)
start, end = adjustIndex(start, end, l)
if start > end {
return NewInt(-1).ToObject(), nil
}
......@@ -750,16 +750,22 @@ func strRepeatCount(f *Frame, numChars int, mult *Object) (int, bool, *BaseExcep
return n, true, nil
}
func adjustIndex(i, l int) int {
switch {
case i <= -l:
i = 0
case i < 0:
i += l
case i > l:
i = l
func adjustIndex(start, end, length int) (int, int) {
if end > length {
end = length
} else if end < 0 {
end += length
if end < 0 {
end = 0
}
}
if start < 0 {
start += length
if start < 0 {
start = 0
}
}
return i
return start, end
}
func strStartsEndsWith(f *Frame, method string, args Args) (*Object, *BaseException) {
......@@ -801,11 +807,12 @@ func strStartsEndsWith(f *Frame, method string, args Args) (*Object, *BaseExcept
l := len(s)
start, end := 0, l
if argc >= 3 {
start = adjustIndex(toIntUnsafe(args[2]).Value(), l)
start = toIntUnsafe(args[2]).Value()
}
if argc == 4 {
end = adjustIndex(toIntUnsafe(args[3]).Value(), l)
end = toIntUnsafe(args[3]).Value()
}
start, end = adjustIndex(start, end, l)
if start > end {
// start == end may still return true when matching ''.
return False.ToObject(), nil
......
......@@ -247,6 +247,17 @@ func TestStrRepr(t *testing.T) {
}
func TestStrMethods(t *testing.T) {
fooType := newTestClass("Foo", []*Type{ObjectType}, newStringDict(map[string]*Object{"bar": None}))
intIndexType := newTestClass("IntIndex", []*Type{ObjectType}, newStringDict(map[string]*Object{
"__index__": newBuiltinFunction("__index__", func(f *Frame, _ Args, _ KWArgs) (*Object, *BaseException) {
return NewInt(2).ToObject(), nil
}).ToObject(),
}))
longIndexType := newTestClass("LongIndex", []*Type{ObjectType}, newStringDict(map[string]*Object{
"__index__": newBuiltinFunction("__index__", func(f *Frame, _ Args, _ KWArgs) (*Object, *BaseException) {
return NewLong(big.NewInt(2)).ToObject(), nil
}).ToObject(),
}))
cases := []struct {
methodName string
args Args
......@@ -254,7 +265,7 @@ func TestStrMethods(t *testing.T) {
wantExc *BaseException
}{
{"endswith", wrapArgs("", ""), True.ToObject(), nil},
{"endswith", wrapArgs("", "", 1), True.ToObject(), nil},
{"endswith", wrapArgs("", "", 1), False.ToObject(), nil},
{"endswith", wrapArgs("foobar", "bar"), True.ToObject(), nil},
{"endswith", wrapArgs("foobar", "bar", 0, -2), False.ToObject(), nil},
{"endswith", wrapArgs("foobar", "foo", 0, 3), True.ToObject(), nil},
......@@ -266,12 +277,22 @@ func TestStrMethods(t *testing.T) {
{"endswith", wrapArgs("foo", newTestTuple(123).ToObject()), nil, mustCreateException(TypeErrorType, "expected a str")},
{"find", wrapArgs("", ""), NewInt(0).ToObject(), nil},
{"find", wrapArgs("", "", 1), NewInt(-1).ToObject(), nil},
{"find", wrapArgs("", "", -1), NewInt(0).ToObject(), nil},
{"find", wrapArgs("", "", None, -1), NewInt(0).ToObject(), nil},
{"find", wrapArgs("foobar", "bar"), NewInt(3).ToObject(), nil},
{"find", wrapArgs("foobar", "bar", fooType), nil, mustCreateException(TypeErrorType, "slice indices must be integers or None or have an __index__ method")},
{"find", wrapArgs("foobar", "bar", NewInt(MaxInt)), NewInt(-1).ToObject(), nil},
{"find", wrapArgs("foobar", "bar", None, NewInt(MaxInt)), NewInt(3).ToObject(), nil},
{"find", wrapArgs("foobar", "bar", newObject(intIndexType)), NewInt(3).ToObject(), nil},
{"find", wrapArgs("foobar", "bar", None, newObject(intIndexType)), NewInt(-1).ToObject(), nil},
{"find", wrapArgs("foobar", "bar", newObject(longIndexType)), NewInt(3).ToObject(), nil},
{"find", wrapArgs("foobar", "bar", None, newObject(longIndexType)), NewInt(-1).ToObject(), nil},
// TODO: Support unicode substring.
{"find", wrapArgs("foobar", NewUnicode("bar")), nil, mustCreateException(TypeErrorType, "'find/index' requires a 'str' object but received a 'unicode'")},
{"find", wrapArgs("foobar", "bar", "baz"), nil, mustCreateException(IndexErrorType, "cannot fit '<type 'str'>' into an index-sized integer")},
{"find", wrapArgs("foobar", "bar", 0, "baz"), nil, mustCreateException(IndexErrorType, "cannot fit '<type 'str'>' into an index-sized integer")},
{"find", wrapArgs("foobar", "bar", "baz"), nil, mustCreateException(TypeErrorType, "slice indices must be integers or None or have an __index__ method")},
{"find", wrapArgs("foobar", "bar", 0, "baz"), nil, mustCreateException(TypeErrorType, "slice indices must be integers or None or have an __index__ method")},
{"find", wrapArgs("foobar", "bar", None), NewInt(3).ToObject(), nil},
{"find", wrapArgs("foobar", "bar", 0, None), NewInt(3).ToObject(), nil},
{"find", wrapArgs("foobar", "bar", 0, -2), NewInt(-1).ToObject(), nil},
{"find", wrapArgs("foobar", "foo", 0, 3), NewInt(0).ToObject(), nil},
{"find", wrapArgs("foobar", "foo", 10), NewInt(-1).ToObject(), nil},
......@@ -321,7 +342,7 @@ func TestStrMethods(t *testing.T) {
{"split", wrapArgs("foo", 1), nil, mustCreateException(TypeErrorType, "expected a str separator")},
{"split", wrapArgs("foo", ""), nil, mustCreateException(ValueErrorType, "empty separator")},
{"startswith", wrapArgs("", ""), True.ToObject(), nil},
{"startswith", wrapArgs("", "", 1), True.ToObject(), nil},
{"startswith", wrapArgs("", "", 1), False.ToObject(), nil},
{"startswith", wrapArgs("foobar", "foo"), True.ToObject(), nil},
{"startswith", wrapArgs("foobar", "foo", 2), False.ToObject(), nil},
{"startswith", wrapArgs("foobar", "bar", 3), True.ToObject(), nil},
......
......@@ -24,11 +24,15 @@ assert "baz" + "" == "baz"
# Test find
assert "".find("") == 0
assert "".find("", 1) == -1
assert "".find("", -1) == 0
assert "".find("", None, -1) == 0
assert "foobar".find("bar") == 3
assert "foobar".find("bar", 0, -2) == -1
assert "foobar".find("foo", 0, 3) == 0
assert "foobar".find("bar", 3, 5) == -1
assert "foobar".find("bar", 5, 3) == -1
assert 'foobar'.find("bar", None) == 3
assert 'foobar'.find("bar", 0, None) == 3
assert "bar".find("foobar") == -1
assert "bar".find("a", 0, -1) == 1
assert 'abcdefghiabc'.find('abc') == 0
......@@ -42,18 +46,17 @@ assert 'abc'.find('', 4) == -1
assert 'rrarrrrrrrrra'.find('a') == 2
assert 'rrarrrrrrrrra'.find('a', 4) == 12
assert 'rrarrrrrrrrra'.find('a', 4, 6) == -1
assert 'rrarrrrrrrrra'.find('a', 4, None) == 12
assert 'rrarrrrrrrrra'.find('a', None, 6) == 2
assert ''.find('') == 0
assert ''.find('', 1, 1) == -1
assert ''.find('', sys.maxint, 0) == -1
assert ''.find('xx') == -1
assert ''.find('xx', 1, 1) == -1
assert ''.find('xx', sys.maxint, 0) == -1
assert 'ab'.find('xxx', sys.maxsize + 1, 0) == -1
# TODO: Support unicode substring.
# assert "foobar".find(u"bar") == 3
# TODO: Support None.
# assert 'rrarrrrrrrrra'.find('a', 4, None) == 12
# assert 'rrarrrrrrrrra'.find('a', None, 6) == 2
class Foo(object):
......@@ -61,8 +64,6 @@ class Foo(object):
return 3
assert 'abcd'.find('a', Foo()) == -1
# TODO: This raises IndexError under Grumpy but returns -1 for CPython.
# 'ab'.find('xxx', sys.maxsize + 1, 0)
try:
"foo".find(123)
......@@ -82,19 +83,17 @@ try:
except TypeError:
pass
# TODO: Both of these test cases raise TypeError under CPython but raise
# IndexError under Grumpy.
#try:
# 'foobar'.find("bar", "baz")
# raise AssertionError
#except TypeError:
# pass
#try:
# 'foobar'.find("bar", 0, "baz")
# raise AssertionError
#except TypeError:
# pass
try:
'foobar'.find("bar", "baz")
raise AssertionError
except TypeError:
pass
try:
'foobar'.find("bar", 0, "baz")
raise AssertionError
except TypeError:
pass
# Test Mod
assert "%s" % 42 == "42"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment