Commit 92c85b5b authored by YOU's avatar YOU Committed by Dylan Trotter

Start implement string slicing (#83)

* Start implement string slicing
* implement unicode slicing
parent dfc59c29
......@@ -201,20 +201,37 @@ func strGE(f *Frame, v, w *Object) (*Object, *BaseException) {
return strCompare(v, w, False, True, True), nil
}
// strGetItem returns a slice of string depending on whether index is an integer
// or a slice. If index is neither of those types then a TypeError is returned.
func strGetItem(f *Frame, o, key *Object) (*Object, *BaseException) {
s := toStrUnsafe(o).Value()
if key.typ.slots.Index == nil {
return nil, f.RaiseType(TypeErrorType, fmt.Sprintf("string indices must be integers, not %s", key.typ.Name()))
}
index, raised := IndexInt(f, key)
if raised != nil {
return nil, raised
}
index, raised = seqCheckedIndex(f, len(s), index)
if raised != nil {
return nil, raised
switch {
case key.typ.slots.Index != nil:
index, raised := IndexInt(f, key)
if raised != nil {
return nil, raised
}
index, raised = seqCheckedIndex(f, len(s), index)
if raised != nil {
return nil, raised
}
return NewStr(s[index : index+1]).ToObject(), nil
case key.isInstance(SliceType):
slice := toSliceUnsafe(key)
start, stop, step, sliceLen, raised := slice.calcSlice(f, len(s))
if raised != nil {
return nil, raised
}
if step == 1 {
return NewStr(s[start:stop]).ToObject(), nil
}
result := make([]byte, 0, sliceLen)
for j := start; j < stop; j += step {
result = append(result, s[j])
}
return NewStr(string(result)).ToObject(), nil
}
return NewStr(s[index : index+1]).ToObject(), nil
return nil, f.RaiseType(TypeErrorType, fmt.Sprintf("string indices must be integers or slice, not %s", key.typ.Name()))
}
func strGetNewArgs(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) {
......
......@@ -159,7 +159,7 @@ func TestStrGetItem(t *testing.T) {
}))
cases := []invokeTestCase{
{args: wrapArgs("bar", 1), want: NewStr("a").ToObject()},
{args: wrapArgs("foo", 3.14), wantExc: mustCreateException(TypeErrorType, "string indices must be integers, not float")},
{args: wrapArgs("foo", 3.14), wantExc: mustCreateException(TypeErrorType, "string indices must be integers or slice, not float")},
{args: wrapArgs("bar", big.NewInt(1)), want: NewStr("a").ToObject()},
{args: wrapArgs("baz", -1), want: NewStr("z").ToObject()},
{args: wrapArgs("baz", newObject(intIndexType)), want: NewStr("z").ToObject()},
......@@ -167,6 +167,11 @@ func TestStrGetItem(t *testing.T) {
{args: wrapArgs("baz", -4), wantExc: mustCreateException(IndexErrorType, "index out of range")},
{args: wrapArgs("", 0), wantExc: mustCreateException(IndexErrorType, "index out of range")},
{args: wrapArgs("foo", 3), wantExc: mustCreateException(IndexErrorType, "index out of range")},
{args: wrapArgs("bar", newTestSlice(None, 2)), want: NewStr("ba").ToObject()},
{args: wrapArgs("bar", newTestSlice(1, 3)), want: NewStr("ar").ToObject()},
{args: wrapArgs("bar", newTestSlice(1, None)), want: NewStr("ar").ToObject()},
{args: wrapArgs("foobarbaz", newTestSlice(1, 8, 2)), want: NewStr("obra").ToObject()},
{args: wrapArgs("bar", newTestSlice(1, 2, 0)), wantExc: mustCreateException(ValueErrorType, "slice step cannot be zero")},
}
for _, cas := range cases {
if err := runInvokeMethodTestCase(StrType, "__getitem__", &cas); err != "" {
......
......@@ -156,16 +156,34 @@ func unicodeGE(f *Frame, v, w *Object) (*Object, *BaseException) {
return unicodeCompare(f, toUnicodeUnsafe(v), w, False, True, True)
}
// unicodeGetItem returns a slice of string depending on whether index is an
// integer or a slice. If index is neither of those types then a TypeError is
// returned.
func unicodeGetItem(f *Frame, o, key *Object) (*Object, *BaseException) {
s := toUnicodeUnsafe(o).Value()
if !key.isInstance(IntType) {
return nil, f.RaiseType(TypeErrorType, "string index out of range")
}
index, raised := seqCheckedIndex(f, len(s), toIntUnsafe(key).Value())
if raised != nil {
return nil, raised
switch {
case key.typ.slots.Index != nil:
index, raised := seqCheckedIndex(f, len(s), toIntUnsafe(key).Value())
if raised != nil {
return nil, raised
}
return NewUnicodeFromRunes([]rune{s[index]}).ToObject(), nil
case key.isInstance(SliceType):
slice := toSliceUnsafe(key)
start, stop, step, sliceLen, raised := slice.calcSlice(f, len(s))
if raised != nil {
return nil, raised
}
if step == 1 {
return NewUnicodeFromRunes(s[start:stop]).ToObject(), nil
}
result := make([]rune, 0, sliceLen)
for j := start; j < stop; j += step {
result = append(result, s[j])
}
return NewUnicodeFromRunes([]rune(result)).ToObject(), nil
}
return NewUnicodeFromRunes([]rune{s[index]}).ToObject(), nil
return nil, f.RaiseType(TypeErrorType, fmt.Sprintf("unicode indices must be integers or slice, not %s", key.typ.Name()))
}
func unicodeGetNewArgs(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) {
......
......@@ -128,11 +128,16 @@ func TestUnicodeEncode(t *testing.T) {
func TestUnicodeGetItem(t *testing.T) {
cases := []invokeTestCase{
{args: wrapArgs(NewUnicode("bar"), 1), want: NewUnicode("a").ToObject()},
{args: wrapArgs(NewUnicode("foo"), 3.14), wantExc: mustCreateException(TypeErrorType, "string index out of range")},
{args: wrapArgs(NewUnicode("foo"), 3.14), wantExc: mustCreateException(TypeErrorType, "unicode indices must be integers or slice, not float")},
{args: wrapArgs(NewUnicode("baz"), -1), want: NewUnicode("z").ToObject()},
{args: wrapArgs(NewUnicode("baz"), -4), wantExc: mustCreateException(IndexErrorType, "index out of range")},
{args: wrapArgs(NewUnicode(""), 0), wantExc: mustCreateException(IndexErrorType, "index out of range")},
{args: wrapArgs(NewUnicode("foo"), 3), wantExc: mustCreateException(IndexErrorType, "index out of range")},
{args: wrapArgs(NewUnicode("bar"), newTestSlice(None, 2)), want: NewStr("ba").ToObject()},
{args: wrapArgs(NewUnicode("bar"), newTestSlice(1, 3)), want: NewStr("ar").ToObject()},
{args: wrapArgs(NewUnicode("bar"), newTestSlice(1, None)), want: NewStr("ar").ToObject()},
{args: wrapArgs(NewUnicode("foobarbaz"), newTestSlice(1, 8, 2)), want: NewStr("obra").ToObject()},
{args: wrapArgs(NewUnicode("bar"), newTestSlice(1, 2, 0)), wantExc: mustCreateException(ValueErrorType, "slice step cannot be zero")},
}
for _, cas := range cases {
if err := runInvokeMethodTestCase(UnicodeType, "__getitem__", &cas); err != "" {
......
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