Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(1246)

Side by Side Diff: src/pkg/text/template/funcs.go

Issue 13091045: code review 13091045: text/template: implement comparison of basic types (Closed)
Patch Set: Created 10 years, 7 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2011 The Go Authors. All rights reserved. 1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style 2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file. 3 // license that can be found in the LICENSE file.
4 4
5 package template 5 package template
6 6
7 import ( 7 import (
8 "bytes" 8 "bytes"
9 "errors"
9 "fmt" 10 "fmt"
10 "io" 11 "io"
11 "net/url" 12 "net/url"
12 "reflect" 13 "reflect"
13 "strings" 14 "strings"
14 "unicode" 15 "unicode"
15 "unicode/utf8" 16 "unicode/utf8"
16 ) 17 )
17 18
18 // FuncMap is the type of the map defining the mapping from names to functions. 19 // FuncMap is the type of the map defining the mapping from names to functions.
19 // Each function must have either a single return value, or two return values of 20 // Each function must have either a single return value, or two return values of
20 // which the second has type error. In that case, if the second (error) 21 // which the second has type error. In that case, if the second (error)
21 // return value evaluates to non-nil during execution, execution terminates and 22 // return value evaluates to non-nil during execution, execution terminates and
22 // Execute returns that error. 23 // Execute returns that error.
23 type FuncMap map[string]interface{} 24 type FuncMap map[string]interface{}
24 25
25 var builtins = FuncMap{ 26 var builtins = FuncMap{
26 "and": and, 27 "and": and,
27 "call": call, 28 "call": call,
28 "html": HTMLEscaper, 29 "html": HTMLEscaper,
29 "index": index, 30 "index": index,
30 "js": JSEscaper, 31 "js": JSEscaper,
31 "len": length, 32 "len": length,
32 "not": not, 33 "not": not,
33 "or": or, 34 "or": or,
34 "print": fmt.Sprint, 35 "print": fmt.Sprint,
35 "printf": fmt.Sprintf, 36 "printf": fmt.Sprintf,
36 "println": fmt.Sprintln, 37 "println": fmt.Sprintln,
37 "urlquery": URLQueryEscaper, 38 "urlquery": URLQueryEscaper,
39
40 // Comparisons
41 "eq": eq, // ==
42 "ge": ge, // >=
43 "gt": gt, // >
44 "le": le, // <=
45 "lt": lt, // <
46 "ne": ne, // !=
38 } 47 }
39 48
40 var builtinFuncs = createValueFuncs(builtins) 49 var builtinFuncs = createValueFuncs(builtins)
41 50
42 // createValueFuncs turns a FuncMap into a map[string]reflect.Value 51 // createValueFuncs turns a FuncMap into a map[string]reflect.Value
43 func createValueFuncs(funcMap FuncMap) map[string]reflect.Value { 52 func createValueFuncs(funcMap FuncMap) map[string]reflect.Value {
44 m := make(map[string]reflect.Value) 53 m := make(map[string]reflect.Value)
45 addValueFuncs(m, funcMap) 54 addValueFuncs(m, funcMap)
46 return m 55 return m
47 } 56 }
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after
241 } 250 }
242 return arg0 251 return arg0
243 } 252 }
244 253
245 // not returns the Boolean negation of its argument. 254 // not returns the Boolean negation of its argument.
246 func not(arg interface{}) (truth bool) { 255 func not(arg interface{}) (truth bool) {
247 truth, _ = isTrue(reflect.ValueOf(arg)) 256 truth, _ = isTrue(reflect.ValueOf(arg))
248 return !truth 257 return !truth
249 } 258 }
250 259
260 // Comparison.
261
262 var (
263 errBadComparisonType = errors.New("invalid type for comparison")
264 errBadComparison = errors.New("incompatible types for comparison")
265 )
266
267 type kind int
268
269 const (
270 invalidKind kind = iota
271 boolKind
272 complexKind
273 intKind
274 floatKind
275 integerKind
276 stringKind
277 uintKind
278 )
279
280 func basicKind(v reflect.Value) (kind, error) {
281 switch v.Kind() {
282 case reflect.Bool:
283 return boolKind, nil
284 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.In t64:
285 return intKind, nil
286 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflec t.Uint64, reflect.Uintptr:
adg 2013/08/21 01:16:53 add a TODO to consider comparisons between int and
287 return uintKind, nil
288 case reflect.Float32, reflect.Float64:
289 return floatKind, nil
290 case reflect.Complex64, reflect.Complex128:
291 return complexKind, nil
292 case reflect.String:
293 return stringKind, nil
294 }
295 return invalidKind, errBadComparisonType
296 }
297
298 // eq evaluates the comparison a == b.
299 func eq(arg1, arg2 interface{}) (bool, error) {
300 v1 := reflect.ValueOf(arg1)
301 k1, err := basicKind(v1)
302 if err != nil {
303 return false, err
304 }
305 v2 := reflect.ValueOf(arg2)
306 k2, err := basicKind(v2)
307 if err != nil {
308 return false, err
309 }
310 if k1 != k2 {
311 return false, errBadComparison
312 }
313 truth := false
314 switch k1 {
315 case boolKind:
316 truth = v1.Bool() == v2.Bool()
317 case complexKind:
318 truth = v1.Complex() == v2.Complex()
319 case floatKind:
320 truth = v1.Float() == v2.Float()
321 case intKind:
322 truth = v1.Int() == v2.Int()
323 case stringKind:
324 truth = v1.String() == v2.String()
325 case uintKind:
326 truth = v1.Uint() == v2.Uint()
327 default:
328 panic("invalid kind")
329 }
330 return truth, nil
331 }
332
333 // ne evaluates the comparison a != b.
334 func ne(arg1, arg2 interface{}) (bool, error) {
335 equal, err := eq(arg1, arg2)
336 return !equal, err
337 }
338
339 // lt evaluates the comparison a < b.
340 func lt(arg1, arg2 interface{}) (bool, error) {
341 v1 := reflect.ValueOf(arg1)
342 v2 := reflect.ValueOf(arg2)
343 k1, err := basicKind(v1)
344 if err != nil {
345 return false, err
346 }
347 k2, err := basicKind(v2)
348 if err != nil {
349 return false, err
350 }
351 if k1 != k2 {
352 return false, errBadComparison
353 }
354 truth := false
355 switch k1 {
356 case boolKind, complexKind:
357 return false, errBadComparisonType
358 case floatKind:
359 truth = v1.Float() < v2.Float()
360 case intKind:
361 truth = v1.Int() < v2.Int()
362 case stringKind:
363 truth = v1.String() < v2.String()
364 case uintKind:
365 truth = v1.Uint() < v2.Uint()
366 default:
367 panic("invalid kind")
368 }
369 return truth, nil
370 }
371
372 // le evaluates the comparison <= b.
373 func le(arg1, arg2 interface{}) (bool, error) {
374 lessThan, err := lt(arg1, arg2)
375 if lessThan || err != nil {
376 return lessThan, err
377 }
378 return eq(arg1, arg2)
379 }
380
381 // gt evaluates the comparison a > b.
382 func gt(arg1, arg2 interface{}) (bool, error) {
383 lessThan, err := lt(arg1, arg2)
384 if err != nil {
385 return false, err
386 }
387 return !lessThan, nil
388 }
389
390 // ge evaluates the comparison a >= b.
391 func ge(arg1, arg2 interface{}) (bool, error) {
392 lessThan, err := lt(arg1, arg2)
393 if err != nil {
394 return false, err
395 }
396 if !lessThan {
397 return true, nil
398 }
399 return eq(arg1, arg2)
400 }
401
251 // HTML escaping. 402 // HTML escaping.
252 403
253 var ( 404 var (
254 htmlQuot = []byte("&#34;") // shorter than "&quot;" 405 htmlQuot = []byte("&#34;") // shorter than "&quot;"
255 htmlApos = []byte("&#39;") // shorter than "&apos;" and apos was not in HTML until HTML5 406 htmlApos = []byte("&#39;") // shorter than "&apos;" and apos was not in HTML until HTML5
256 htmlAmp = []byte("&amp;") 407 htmlAmp = []byte("&amp;")
257 htmlLt = []byte("&lt;") 408 htmlLt = []byte("&lt;")
258 htmlGt = []byte("&gt;") 409 htmlGt = []byte("&gt;")
259 ) 410 )
260 411
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after
407 func URLQueryEscaper(args ...interface{}) string { 558 func URLQueryEscaper(args ...interface{}) string {
408 s, ok := "", false 559 s, ok := "", false
409 if len(args) == 1 { 560 if len(args) == 1 {
410 s, ok = args[0].(string) 561 s, ok = args[0].(string)
411 } 562 }
412 if !ok { 563 if !ok {
413 s = fmt.Sprint(args...) 564 s = fmt.Sprint(args...)
414 } 565 }
415 return url.QueryEscape(s) 566 return url.QueryEscape(s)
416 } 567 }
OLDNEW
« src/pkg/text/template/exec_test.go ('K') | « src/pkg/text/template/exec_test.go ('k') | no next file » | no next file with comments »

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b