diff options
author | Rob Pike <r@golang.org> | 2011-06-29 15:02:04 +1000 |
---|---|---|
committer | Rob Pike <r@golang.org> | 2011-06-29 15:02:04 +1000 |
commit | c756a1954c4d07a2a4da07e6e0a7f024f42dc04a (patch) | |
tree | 4763bc4831edcd0e68919c23b894021045077f04 | |
parent | 7e1a3e9f209d33eff36eb6876e0505a300be9ba6 (diff) | |
download | go-c756a1954c4d07a2a4da07e6e0a7f024f42dc04a.tar.gz go-c756a1954c4d07a2a4da07e6e0a7f024f42dc04a.zip |
exp/template: boolean constants
R=rsc
CC=golang-dev
https://golang.org/cl/4628073
-rw-r--r-- | src/pkg/exp/template/exec.go | 13 | ||||
-rw-r--r-- | src/pkg/exp/template/exec_test.go | 19 | ||||
-rw-r--r-- | src/pkg/exp/template/lex.go | 4 | ||||
-rw-r--r-- | src/pkg/exp/template/lex_test.go | 7 | ||||
-rw-r--r-- | src/pkg/exp/template/parse.go | 19 | ||||
-rw-r--r-- | src/pkg/exp/template/parse_test.go | 2 |
6 files changed, 55 insertions, 9 deletions
diff --git a/src/pkg/exp/template/exec.go b/src/pkg/exp/template/exec.go index c097c20a87..27c1b096ec 100644 --- a/src/pkg/exp/template/exec.go +++ b/src/pkg/exp/template/exec.go @@ -224,7 +224,8 @@ func (s *state) evalArg(data reflect.Value, typ reflect.Type, n node) reflect.Va 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: @@ -240,6 +241,16 @@ func (s *state) evalArg(data reflect.Value, typ reflect.Type, n node) reflect.Va 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() diff --git a/src/pkg/exp/template/exec_test.go b/src/pkg/exp/template/exec_test.go index 10348da7b6..bd21125ef4 100644 --- a/src/pkg/exp/template/exec_test.go +++ b/src/pkg/exp/template/exec_test.go @@ -24,6 +24,7 @@ type T struct { // Slices SI []int SEmpty []int + SB []bool // Maps MSI map[string]int MSIEmpty map[string]int @@ -63,11 +64,11 @@ func (t *T) MSort(m map[string]int) []string { } // 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 { @@ -80,6 +81,7 @@ var tVal = &T{ X: "x", U: &U{"v"}, SI: []int{3, 4, 5}, + SB: []bool{true, false}, MSI: map[string]int{"one": 1, "two": 2, "three": 3}, } @@ -106,13 +108,14 @@ var execTests = []execTest{ {"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) { @@ -147,7 +150,7 @@ 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) } @@ -155,6 +158,6 @@ func TestExecuteError(t *testing.T) { 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) } } diff --git a/src/pkg/exp/template/lex.go b/src/pkg/exp/template/lex.go index 51baa6e71e..1919cf4715 100644 --- a/src/pkg/exp/template/lex.go +++ b/src/pkg/exp/template/lex.go @@ -35,6 +35,7 @@ type itemType int const ( itemError itemType = iota // error occurred; value is text of error + itemBool // boolean constant itemDot // the cursor, spelled '.'. itemEOF itemElse // else keyword @@ -55,6 +56,7 @@ const ( // Make the types prettyprint. var itemName = map[itemType]string{ itemError: "error", + itemBool: "bool", itemDot: ".", itemEOF: "EOF", itemElse: "else", @@ -284,6 +286,8 @@ Loop: l.emit(key[word]) case word[0] == '.': l.emit(itemField) + case word == "true", word == "false": + l.emit(itemBool) default: l.emit(itemIdentifier) } diff --git a/src/pkg/exp/template/lex_test.go b/src/pkg/exp/template/lex_test.go index beca41baa5..62bce6daa0 100644 --- a/src/pkg/exp/template/lex_test.go +++ b/src/pkg/exp/template/lex_test.go @@ -46,6 +46,13 @@ var lexTests = []lexTest{ tRight, tEOF, }}, + {"bools", "{{true false}}", []item{ + tLeft, + {itemBool, "true"}, + {itemBool, "false"}, + tRight, + tEOF, + }}, {"dot", "{{.}}", []item{ tLeft, {itemDot, "."}, diff --git a/src/pkg/exp/template/parse.go b/src/pkg/exp/template/parse.go index cfe180631e..f1695557f4 100644 --- a/src/pkg/exp/template/parse.go +++ b/src/pkg/exp/template/parse.go @@ -198,6 +198,23 @@ func (f *fieldNode) String() string { 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. @@ -534,6 +551,8 @@ Loop: 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) diff --git a/src/pkg/exp/template/parse_test.go b/src/pkg/exp/template/parse_test.go index e194c5e5d4..b1da989cf2 100644 --- a/src/pkg/exp/template/parse_test.go +++ b/src/pkg/exp/template/parse_test.go @@ -151,6 +151,8 @@ var parseTests = []parseTest{ `[({{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, ""}, |