mirror of
https://github.com/golang/go
synced 2024-11-19 16:44:43 -07:00
exp/template: boolean constants
R=rsc CC=golang-dev https://golang.org/cl/4628073
This commit is contained in:
parent
7e1a3e9f20
commit
c756a1954c
@ -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()
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -46,6 +46,13 @@ var lexTests = []lexTest{
|
||||
tRight,
|
||||
tEOF,
|
||||
}},
|
||||
{"bools", "{{true false}}", []item{
|
||||
tLeft,
|
||||
{itemBool, "true"},
|
||||
{itemBool, "false"},
|
||||
tRight,
|
||||
tEOF,
|
||||
}},
|
||||
{"dot", "{{.}}", []item{
|
||||
tLeft,
|
||||
{itemDot, "."},
|
||||
|
@ -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)
|
||||
|
@ -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, ""},
|
||||
|
Loading…
Reference in New Issue
Block a user