return value
}
switch typ.Kind() {
- // TODO: boolean
+ case reflect.Bool:
+ return s.evalBool(data, typ, n)
case reflect.String:
return s.evalString(data, typ, n)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
panic("not reached")
}
+func (s *state) evalBool(v reflect.Value, typ reflect.Type, n node) reflect.Value {
+ if n, ok := n.(*boolNode); ok {
+ value := reflect.New(typ).Elem()
+ value.SetBool(n.true)
+ return value
+ }
+ s.errorf("expected bool; found %s", n)
+ panic("not reached")
+}
+
func (s *state) evalString(v reflect.Value, typ reflect.Type, n node) reflect.Value {
if n, ok := n.(*stringNode); ok {
value := reflect.New(typ).Elem()
// Slices
SI []int
SEmpty []int
+ SB []bool
// Maps
MSI map[string]int
MSIEmpty map[string]int
}
// EPERM returns a value and an os.Error according to its argument.
-func (t *T) EPERM(a int) (int, os.Error) {
- if a == 0 {
- return 0, os.EPERM
+func (t *T) EPERM(error bool) (bool, os.Error) {
+ if error {
+ return true, os.EPERM
}
- return a, nil
+ return false, nil
}
type U struct {
X: "x",
U: &U{"v"},
SI: []int{3, 4, 5},
+ SB: []bool{true, false},
MSI: map[string]int{"one": 1, "two": 2, "three": 3},
}
{"range empty no else", "{{range .SEmpty}}-{{.}}-{{end}}", "", tVal, true},
{"range []int else", "{{range .SI}}-{{.}}-{{else}}EMPTY{{end}}", "-3--4--5-", tVal, true},
{"range empty else", "{{range .SEmpty}}-{{.}}-{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
+ {"range []bool", "{{range .SB}}-{{.}}-{{end}}", "-true--false-", tVal, true},
{"range []int method", "{{range .SI | .MAdd .I}}-{{.}}-{{end}}", "-20--21--22-", tVal, true},
{"range map", "{{range .MSI | .MSort}}-{{.}}-{{end}}", "-one--three--two-", tVal, true},
{"range empty map no else", "{{range .MSIEmpty}}-{{.}}-{{end}}", "", tVal, true},
{"range map else", "{{range .MSI | .MSort}}-{{.}}-{{else}}EMPTY{{end}}", "-one--three--two-", tVal, true},
{"range empty map else", "{{range .MSIEmpty}}-{{.}}-{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
- {"error method, no error", "{{.EPERM 1}}", "1", tVal, true},
- {"error method, error", "{{.EPERM 0}}", "1", tVal, false},
+ {"error method, error", "{{.EPERM true}}", "", tVal, false},
+ {"error method, no error", "{{.EPERM false}}", "false", tVal, true},
}
func TestExecute(t *testing.T) {
func TestExecuteError(t *testing.T) {
b := new(bytes.Buffer)
tmpl := New("error")
- err := tmpl.Parse("{{.EPERM 0}}")
+ err := tmpl.Parse("{{.EPERM true}}")
if err != nil {
t.Fatalf("parse error: %s", err)
}
if err == nil {
t.Errorf("expected error; got none")
} else if !strings.Contains(err.String(), os.EPERM.String()) {
- t.Errorf("expected os.EPERM; got %s %s", err)
+ t.Errorf("expected os.EPERM; got %s", err)
}
}
return fmt.Sprintf("F=%s", f.ident)
}
+// boolNode holds a boolean constant.
+type boolNode struct {
+ nodeType
+ true bool
+}
+
+func newBool(true bool) *boolNode {
+ return &boolNode{nodeType: nodeString, true: true}
+}
+
+func (b *boolNode) String() string {
+ if b.true {
+ return fmt.Sprintf("B=true")
+ }
+ return fmt.Sprintf("B=false")
+}
+
// numberNode holds a number, signed or unsigned, integer, floating, or imaginary.
// The value is parsed and stored under all the types that can represent the value.
// This simulates in a small amount of code the behavior of Go's ideal constants.
cmd.append(newDot())
case itemField:
cmd.append(newField(token.val))
+ case itemBool:
+ cmd.append(newBool(token.val == "true"))
case itemNumber:
if len(cmd.args) == 0 {
t.errorf("command cannot be %q", token.val)
`[({{range [(command: [F=[X]]) (command: [F=[M]])]}} [(text: "true")] {{else}} [(text: "false")])]`},
{"range []int", "{{range .SI}}{{.}}{{end}}", noError,
`[({{range [(command: [F=[SI]])]}} [(action: [(command: [{{<.>}}])])])]`},
+ {"constants", "{{range .SI 1 -3.2i true false }}{{end}}", noError,
+ `[({{range [(command: [F=[SI] N=1 N=-3.2i B=true B=false])]}} [])]`},
// Errors.
{"unclosed action", "hello{{range", hasError, ""},
{"missing end", "hello{{range .x}}", hasError, ""},