]> Cypherpunks repositories - gostls13.git/commitdiff
exp/template: boolean constants
authorRob Pike <r@golang.org>
Wed, 29 Jun 2011 05:02:04 +0000 (15:02 +1000)
committerRob Pike <r@golang.org>
Wed, 29 Jun 2011 05:02:04 +0000 (15:02 +1000)
R=rsc
CC=golang-dev
https://golang.org/cl/4628073

src/pkg/exp/template/exec.go
src/pkg/exp/template/exec_test.go
src/pkg/exp/template/lex.go
src/pkg/exp/template/lex_test.go
src/pkg/exp/template/parse.go
src/pkg/exp/template/parse_test.go

index c097c20a87907456abda8be8ed9ee3a67fbb16e9..27c1b096ec667e72417460e6113b1f124a4337a8 100644 (file)
@@ -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()
index 10348da7b6369d3f72d1f201893f271fb7734f60..bd21125ef4197295864d4d06e26a9c197b092c2b 100644 (file)
@@ -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)
        }
 }
index 51baa6e71e9daeff48d361a20c6298501a1684c9..1919cf4715ad0272760e3102b556c5a58738fef9 100644 (file)
@@ -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)
                        }
index beca41baa55dd621e91c8e445b993f9f50499a95..62bce6daa01dfc680854264a30bacef5e38eff3f 100644 (file)
@@ -46,6 +46,13 @@ var lexTests = []lexTest{
                tRight,
                tEOF,
        }},
+       {"bools", "{{true false}}", []item{
+               tLeft,
+               {itemBool, "true"},
+               {itemBool, "false"},
+               tRight,
+               tEOF,
+       }},
        {"dot", "{{.}}", []item{
                tLeft,
                {itemDot, "."},
index cfe180631ecd499f118c235e9fdf7bd384dfe093..f1695557f4f6cffa1911dc5d3f4b81b75e877fae 100644 (file)
@@ -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)
index e194c5e5d445827cd8e5fb69400f53e5e3c7ae5d..b1da989cf25aa148aa28d156ecfd39fd3432e56d 100644 (file)
@@ -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, ""},