Commit 0ba7ffe2 authored by Rob Pike's avatar Rob Pike

text/template: allow eq to take more than two arguments

Based on an old suggestion by rsc, it compares the second
and following arguments to the first.

Unfortunately the code cannot be as pretty as rsc's original
because it doesn't require identical types.

R=golang-dev, dsymonds, adg
CC=golang-dev
https://golang.org/cl/13509046
parent 54b2a83d
......@@ -326,13 +326,22 @@ functions:
ge
Returns the boolean truth of arg1 >= arg2
These functions work on basic types only (or named basic types,
such as "type Celsius float32"). They implement the Go rules for
comparison of values, except that size and exact type are ignored,
so any integer value may be compared with any other integer value,
any unsigned integer value may be compared with any other unsigned
integer value, and so on. However, as usual, one may not compare
an int with a float32 and so on.
For simpler multi-way equality tests, eq (only) accepts two or more
arguments and compares the second and subsequent to the first,
returning in effect
arg1==arg2 || arg1==arg3 || arg1==arg4 ...
(Unlike with || in Go, however, eq is a function call and all the
arguments will be evaluated.)
The comparison functions work on basic types only (or named basic
types, such as "type Celsius float32"). They implement the Go rules
for comparison of values, except that size and exact type are
ignored, so any integer value may be compared with any other integer
value, any unsigned integer value may be compared with any other
unsigned integer value, and so on. However, as usual, one may not
compare an int with a float32 and so on.
Associated templates
......
......@@ -891,6 +891,8 @@ var cmpTests = []cmpTest{
{"eq `xy` `xyz`", "false", true},
{"eq .Xuint .Xuint", "true", true},
{"eq .Xuint .Yuint", "false", true},
{"eq 3 4 5 6 3", "true", true},
{"eq 3 4 5 6 7", "false", true},
{"ne true true", "false", true},
{"ne true false", "true", true},
{"ne 1+2i 1+2i", "false", true},
......@@ -946,7 +948,6 @@ var cmpTests = []cmpTest{
{"ge .Xuint .Yuint", "false", true},
{"ge .Yuint .Xuint", "true", true},
// Errors
{"eq 3 4 5", "", false}, // Too many arguments.
{"eq `xy` 1", "", false}, // Different types.
{"lt true true", "", false}, // Unordered types.
{"lt 1+0i 1+0i", "", false}, // Unordered types.
......@@ -970,7 +971,7 @@ func TestComparison(t *testing.T) {
continue
}
if !test.ok && err == nil {
t.Errorf("%s did not error")
t.Errorf("%s did not error", test.expr)
continue
}
if b.String() != test.truth {
......
......@@ -264,6 +264,7 @@ func not(arg interface{}) (truth bool) {
var (
errBadComparisonType = errors.New("invalid type for comparison")
errBadComparison = errors.New("incompatible types for comparison")
errNoComparison = errors.New("missing argument for comparison")
)
type kind int
......@@ -297,39 +298,47 @@ func basicKind(v reflect.Value) (kind, error) {
return invalidKind, errBadComparisonType
}
// eq evaluates the comparison a == b.
func eq(arg1, arg2 interface{}) (bool, error) {
// eq evaluates the comparison a == b || a == c || ...
func eq(arg1 interface{}, arg2 ...interface{}) (bool, error) {
v1 := reflect.ValueOf(arg1)
k1, err := basicKind(v1)
if err != nil {
return false, err
}
v2 := reflect.ValueOf(arg2)
k2, err := basicKind(v2)
if err != nil {
return false, err
if len(arg2) == 0 {
return false, errNoComparison
}
if k1 != k2 {
return false, errBadComparison
}
truth := false
switch k1 {
case boolKind:
truth = v1.Bool() == v2.Bool()
case complexKind:
truth = v1.Complex() == v2.Complex()
case floatKind:
truth = v1.Float() == v2.Float()
case intKind:
truth = v1.Int() == v2.Int()
case stringKind:
truth = v1.String() == v2.String()
case uintKind:
truth = v1.Uint() == v2.Uint()
default:
panic("invalid kind")
for _, arg := range arg2 {
v2 := reflect.ValueOf(arg)
k2, err := basicKind(v2)
if err != nil {
return false, err
}
if k1 != k2 {
return false, errBadComparison
}
truth := false
switch k1 {
case boolKind:
truth = v1.Bool() == v2.Bool()
case complexKind:
truth = v1.Complex() == v2.Complex()
case floatKind:
truth = v1.Float() == v2.Float()
case intKind:
truth = v1.Int() == v2.Int()
case stringKind:
truth = v1.String() == v2.String()
case uintKind:
truth = v1.Uint() == v2.Uint()
default:
panic("invalid kind")
}
if truth {
return true, nil
}
}
return truth, nil
return false, nil
}
// ne evaluates the comparison a != b.
......
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