Skip to content

Commit

Permalink
eval/vals: Support float64 when indexing lists or strings.
Browse files Browse the repository at this point in the history
This addresses #816.
  • Loading branch information
xiaq committed Apr 27, 2019
1 parent 726ce88 commit 6c4b737
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 32 deletions.
6 changes: 1 addition & 5 deletions eval/vals/assoc.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,7 @@ func assocString(s string, k, v interface{}) (interface{}, error) {
}

func assocList(l List, k, v interface{}) (interface{}, error) {
kstring, ok := k.(string)
if !ok {
return nil, errIndexMustBeString
}
index, err := ConvertListIndex(kstring, l.Len())
index, err := ConvertListIndex(k, l.Len())
if err != nil {
return nil, err
}
Expand Down
6 changes: 4 additions & 2 deletions eval/vals/assoc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@ var assocTests = tt.Table{
Args("0123", "0", "foo").Rets("foo123", nil),
Args("0123", "1:3", "bar").Rets("0bar3", nil),
Args("0123", "1:3", 12).Rets(nil, errReplacementMustBeString),
Args("0123", "x", "y").Rets(nil, errIndexMustBeNumber),
Args("0123", "x", "y").Rets(nil, errIndexMustBeInteger),

Args(MakeList("0", "1", "2", "3"), "0", "foo").Rets(
eq(MakeList("foo", "1", "2", "3")), nil),
Args(MakeList("0"), MakeList("0"), "1").Rets(nil, errIndexMustBeString),
Args(MakeList("0", "1", "2", "3"), 0.0, "foo").Rets(
eq(MakeList("foo", "1", "2", "3")), nil),
Args(MakeList("0"), MakeList("0"), "1").Rets(nil, errIndexMustBeInteger),
Args(MakeList("0"), "1", "x").Rets(nil, errIndexOutOfRange),
// TODO: Support list assoc with slice
Args(MakeList("0", "1", "2", "3"), "1:3", MakeList("foo")).Rets(
Expand Down
59 changes: 34 additions & 25 deletions eval/vals/index_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@ import (
)

var (
errIndexMustBeString = errors.New("index must be string")
errIndexMustBeNumber = errors.New("index or slice component must be number")
errIndexOutOfRange = errors.New("index out of range")
errIndexMustBeInteger = errors.New("index must must be integer")
errIndexOutOfRange = errors.New("index out of range")
)

func indexList(l List, rawIndex interface{}) (interface{}, error) {
Expand All @@ -35,30 +34,40 @@ type ListIndex struct {
// ConvertListIndex parses a list index, check whether it is valid, and returns
// the converted structure.
func ConvertListIndex(rawIndex interface{}, n int) (*ListIndex, error) {
s, ok := rawIndex.(string)
if !ok {
return nil, errIndexMustBeString
}
slice, i, j, err := parseListIndex(s, n)
if err != nil {
return nil, err
}
if i < 0 {
i += n
}
if j < 0 {
j += n
}
if slice {
if !(0 <= i && i <= j && j <= n) {
return nil, errIndexOutOfRange
switch rawIndex := rawIndex.(type) {
case float64:
index := int(rawIndex)
if rawIndex != float64(index) {
return nil, errIndexMustBeInteger
}
} else {
if !(0 <= i && i < n) {
return nil, errIndexOutOfRange
if index < 0 {
index += n
}
return &ListIndex{false, index, 0}, nil
case string:
slice, i, j, err := parseListIndex(rawIndex, n)
if err != nil {
return nil, err
}
if i < 0 {
i += n
}
if j < 0 {
j += n
}
if slice {
if !(0 <= i && i <= j && j <= n) {
return nil, errIndexOutOfRange
}
} else {
if !(0 <= i && i < n) {
return nil, errIndexOutOfRange
}
}
return &ListIndex{slice, i, j}, nil
default:
return nil, errIndexMustBeInteger
}
return &ListIndex{slice, i, j}, nil
}

// ListIndex = Number |
Expand Down Expand Up @@ -101,7 +110,7 @@ func atoi(a string) (int, error) {
if err.(*strconv.NumError).Err == strconv.ErrRange {
return 0, errIndexOutOfRange
}
return 0, errIndexMustBeNumber
return 0, errIndexMustBeInteger
}
return i, nil
}
7 changes: 7 additions & 0 deletions eval/vals/index_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ var (
var indexTests = tt.Table{
// String indicies
Args("abc", "0").Rets("a", nil),
Args("abc", 0.0).Rets("a", nil),
Args("你好", "0").Rets("你", nil),
Args("你好", "3").Rets("好", nil),
Args("你好", "2").Rets(any, errIndexNotAtRuneBoundary),
Expand All @@ -40,6 +41,12 @@ var indexTests = tt.Table{
// Decimal indicies are not allowed even if the value is an integer.
Args(li4, "0.0").Rets(any, anyError),

// Float64 indicies are allowed as long as they are integers.
Args(li4, 0.0).Rets("foo", nil),
Args(li4, 3.0).Rets("ipsum", nil),
Args(li4, -1.0).Rets("ipsum", nil),
Args(li4, 0.5).Rets(any, anyError),

// Slice indicies: 0 <= i <= j <= n.
Args(li4, "1:3").Rets(eq(MakeList("bar", "lorem")), nil),
Args(li4, "3:4").Rets(eq(MakeList("ipsum")), nil),
Expand Down

0 comments on commit 6c4b737

Please sign in to comment.