1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // Code to parse a template.
21 // Errors returned during parsing and execution. Users may extract the information and reformat
28 func (e *Error) String() string { return fmt.Sprintf("line %d: %s", e.Line, e.Msg) }
30 // checkError is a deferred function to turn a panic with type *Error into a plain error return.
31 // Other panics are unexpected and so are re-enabled.
32 func checkError(error *os.Error) {
33 if v := recover(); v != nil {
34 if e, ok := v.(*Error); ok {
37 // runtime errors should crash
43 // Most of the literals are aces.
44 var lbrace = []byte{'{'}
45 var rbrace = []byte{'}'}
46 var space = []byte{' '}
47 var tab = []byte{'\t'}
49 // The various types of "tokens", which are plain text or (usually) brace-delimited descriptors
62 // FormatterMap is the type describing the mapping from formatter
63 // names to the functions that implement them.
64 type FormatterMap map[string]func(io.Writer, string, ...interface{})
66 // Built-in formatters.
67 var builtins = FormatterMap{
68 "html": HTMLFormatter,
69 "str": StringFormatter,
73 // The parsed state of a template is a vector of xxxElement structs.
74 // Sections have line numbers so errors can be reported better during execution.
77 type textElement struct {
81 // A literal such as .meta-left or .meta-right
82 type literalElement struct {
86 // A variable invocation to be evaluated
87 type variableElement struct {
89 args []interface{} // The fields and literals in the invocation.
90 fmts []string // Names of formatters to apply. len(fmts) > 0
93 // A variableElement arg to be evaluated as a field name
96 // A .section block, possibly with a .or
97 type sectionElement struct {
98 linenum int // of .section itself
99 field string // cursor field for this block
100 start int // first element
101 or int // first element of .or block
102 end int // one beyond last element
105 // A .repeated block, possibly with a .or and a .alternates
106 type repeatedElement struct {
107 sectionElement // It has the same structure...
108 altstart int // ... except for alternates
112 // Template is the type that represents a template definition.
113 // It is unchanged after parsing.
114 type Template struct {
115 fmap FormatterMap // formatters for variables
116 // Used during parsing:
117 ldelim, rdelim []byte // delimiters; default {}
118 buf []byte // input text to process
119 p int // position in buf
120 linenum int // position in input
125 // New creates a new template with the specified formatter map (which
126 // may be nil) to define auxiliary functions for formatting variables.
127 func New(fmap FormatterMap) *Template {
132 t.elems = make([]interface{}, 0, 16)
136 // Report error and stop executing. The line number must be provided explicitly.
137 func (t *Template) execError(st *state, line int, err string, args ...interface{}) {
138 panic(&Error{line, fmt.Sprintf(err, args...)})
141 // Report error, panic to terminate parsing.
142 // The line number comes from the template state.
143 func (t *Template) parseError(err string, args ...interface{}) {
144 panic(&Error{t.linenum, fmt.Sprintf(err, args...)})
147 // Is this an exported - upper case - name?
148 func isExported(name string) bool {
149 rune, _ := utf8.DecodeRuneInString(name)
150 return unicode.IsUpper(rune)
153 // -- Lexical analysis
155 // Is c a space character?
156 func isSpace(c uint8) bool { return c == ' ' || c == '\t' || c == '\r' || c == '\n' }
158 // Safely, does s[n:n+len(t)] == t?
159 func equal(s []byte, n int, t []byte) bool {
161 if len(t) > len(b) { // not enough space left for a match.
164 for i, c := range t {
172 // isQuote returns true if c is a string- or character-delimiting quote character.
173 func isQuote(c byte) bool {
174 return c == '"' || c == '`' || c == '\''
177 // endQuote returns the end quote index for the quoted string that
178 // starts at n, or -1 if no matching end quote is found before the end
180 func endQuote(s []byte, n int) int {
182 for n++; n < len(s); n++ {
185 if quote == '"' || quote == '\'' {
197 // nextItem returns the next item from the input buffer. If the returned
198 // item is empty, we are at EOF. The item will be either a
199 // delimited string or a non-empty string between delimited
200 // strings. Tokens stop at (but include, if plain text) a newline.
201 // Action tokens on a line by themselves drop any space on
202 // either side, up to and including the newline.
203 func (t *Template) nextItem() []byte {
204 startOfLine := t.p == 0 || t.buf[t.p-1] == '\n'
211 // Leading space up to but not including newline
212 for i = start; i < len(t.buf); i++ {
213 if t.buf[i] == '\n' || !isSpace(t.buf[i]) {
217 leadingSpace := i > start
218 // What's left is nothing, newline, delimited string, or plain text
220 case i == len(t.buf):
221 // EOF; nothing to do
222 case t.buf[i] == '\n':
224 case equal(t.buf, i, t.ldelim):
225 left := i // Start of left delimiter.
226 right := -1 // Will be (immediately after) right delimiter.
227 haveText := false // Delimiters contain text.
229 // Find the end of the action.
230 for ; i < len(t.buf); i++ {
231 if t.buf[i] == '\n' {
234 if isQuote(t.buf[i]) {
235 i = endQuote(t.buf, i)
237 t.parseError("unmatched quote")
242 if equal(t.buf, i, t.rdelim) {
250 t.parseError("unmatched opening delimiter")
253 // Is this a special action (starts with '.' or '#') and the only thing on the line?
254 if startOfLine && haveText {
255 firstChar := t.buf[left+len(t.ldelim)]
256 if firstChar == '.' || firstChar == '#' {
257 // It's special and the first thing on the line. Is it the last?
258 for j := right; j < len(t.buf) && isSpace(t.buf[j]); j++ {
259 if t.buf[j] == '\n' {
260 // Yes it is. Drop the surrounding space and return the {.foo}
263 return t.buf[left:right]
268 // No it's not. If there's leading space, return that.
270 // not trimming space: return leading space if there is some.
272 return t.buf[start:left]
274 // Return the word, leave the trailing space.
278 for ; i < len(t.buf); i++ {
279 if t.buf[i] == '\n' {
283 if equal(t.buf, i, t.ldelim) {
288 item := t.buf[start:i]
293 // Turn a byte array into a space-split array of strings,
294 // taking into account quoted strings.
295 func words(buf []byte) []string {
296 s := make([]string, 0, 5)
297 for i := 0; i < len(buf); {
299 for i < len(buf) && isSpace(buf[i]) {
315 // Even with quotes, break on space only. This handles input
316 // such as {""|} and catches quoting mistakes.
317 for i < len(buf) && !isSpace(buf[i]) {
320 s = append(s, string(buf[start:i]))
325 // Analyze an item and return its token type and, if it's an action item, an array of
326 // its constituent words.
327 func (t *Template) analyze(item []byte) (tok int, w []string) {
328 // item is known to be non-empty
329 if !equal(item, 0, t.ldelim) { // doesn't start with left delimiter
333 if !equal(item, len(item)-len(t.rdelim), t.rdelim) { // doesn't end with right delimiter
334 t.parseError("internal error: unmatched opening delimiter") // lexing should prevent this
337 if len(item) <= len(t.ldelim)+len(t.rdelim) { // no contents
338 t.parseError("empty directive")
342 if item[len(t.ldelim)] == '#' {
347 w = words(item[len(t.ldelim) : len(item)-len(t.rdelim)]) // drop final delimiter
349 t.parseError("empty directive")
357 if len(first) > 1 && first[1] >= '0' && first[1] <= '9' {
363 case ".meta-left", ".meta-right", ".space", ".tab":
374 t.parseError("incorrect fields for .section: %s", item)
380 if len(w) != 3 || w[1] != "section" {
381 t.parseError("incorrect fields for .repeated: %s", item)
387 if len(w) != 2 || w[1] != "with" {
388 t.parseError("incorrect fields for .alternates: %s", item)
394 t.parseError("bad directive: %s", item)
398 // formatter returns the Formatter with the given name in the Template, or nil if none exists.
399 func (t *Template) formatter(name string) func(io.Writer, string, ...interface{}) {
401 if fn := t.fmap[name]; fn != nil {
405 return builtins[name]
410 // newVariable allocates a new variable-evaluation element.
411 func (t *Template) newVariable(words []string) *variableElement {
412 formatters := extractFormatters(words)
413 args := make([]interface{}, len(words))
415 // Build argument list, processing any literals
416 for i, word := range words {
420 v, err := strconv.Unquote(word)
421 if err == nil && word[0] == '\'' {
422 args[i] = []int(v)[0]
424 args[i], lerr = v, err
427 case '.', '+', '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
428 v, err := strconv.Btoi64(word, 0)
432 v, err := strconv.Atof64(word)
433 args[i], lerr = v, err
437 args[i] = fieldName(word)
440 t.parseError("invalid literal: %q: %s", word, lerr)
444 // We could remember the function address here and avoid the lookup later,
445 // but it's more dynamic to let the user change the map contents underfoot.
446 // We do require the name to be present, though.
448 // Is it in user-supplied map?
449 for _, f := range formatters {
450 if t.formatter(f) == nil {
451 t.parseError("unknown formatter: %q", f)
455 return &variableElement{t.linenum, args, formatters}
458 // extractFormatters extracts a list of formatters from words.
459 // After the final space-separated argument in a variable, formatters may be
460 // specified separated by pipe symbols. For example: {a b c|d|e}
461 // The words parameter still has the formatters joined by '|' in the last word.
462 // extractFormatters splits formatters, replaces the last word with the content
463 // found before the first '|' within it, and returns the formatters obtained.
464 // If no formatters are found in words, the default formatter is returned.
465 func extractFormatters(words []string) (formatters []string) {
466 // "" is the default formatter.
467 formatters = []string{""}
472 lastWord := words[len(words)-1]
473 if isQuote(lastWord[0]) {
474 end := endQuote([]byte(lastWord), 0)
475 if end < 0 || end+1 == len(lastWord) || lastWord[end+1] != '|' {
480 bar = strings.IndexRune(lastWord, '|')
485 words[len(words)-1] = lastWord[0:bar]
486 formatters = strings.Split(lastWord[bar+1:], "|")
490 // Grab the next item. If it's simple, just append it to the template.
491 // Otherwise return its details.
492 func (t *Template) parseSimple(item []byte) (done bool, tok int, w []string) {
493 tok, w = t.analyze(item)
494 done = true // assume for simplicity
499 t.elems = append(t.elems, &textElement{item})
504 t.elems = append(t.elems, &literalElement{t.ldelim})
506 t.elems = append(t.elems, &literalElement{t.rdelim})
508 t.elems = append(t.elems, &literalElement{space})
510 t.elems = append(t.elems, &literalElement{tab})
512 t.parseError("internal error: unknown literal: %s", w[0])
516 t.elems = append(t.elems, t.newVariable(w))
522 // parseRepeated and parseSection are mutually recursive
524 func (t *Template) parseRepeated(words []string) *repeatedElement {
525 r := new(repeatedElement)
526 t.elems = append(t.elems, r)
527 r.linenum = t.linenum
529 // Scan section, collecting true and false (.or) blocks.
530 r.start = len(t.elems)
538 t.parseError("missing .end for .repeated section")
541 done, tok, w := t.parseSimple(item)
550 t.parseError("extra .or in .repeated section")
553 r.altend = len(t.elems)
561 t.parseError("extra .alternates in .repeated section")
565 t.parseError(".alternates inside .or block in .repeated section")
568 r.altstart = len(t.elems)
570 t.parseError("internal error: unknown repeated section item: %s", item)
575 r.altend = len(t.elems)
581 func (t *Template) parseSection(words []string) *sectionElement {
582 s := new(sectionElement)
583 t.elems = append(t.elems, s)
584 s.linenum = t.linenum
586 // Scan section, collecting true and false (.or) blocks.
587 s.start = len(t.elems)
593 t.parseError("missing .end for .section")
596 done, tok, w := t.parseSimple(item)
605 t.parseError("extra .or in .section")
614 t.parseError(".alternates not in .repeated")
616 t.parseError("internal error: unknown section item: %s", item)
623 func (t *Template) parse() {
629 done, tok, w := t.parseSimple(item)
634 case tokOr, tokEnd, tokAlternates:
635 t.parseError("unexpected %s", w[0])
641 t.parseError("internal error: bad directive in parse: %s", item)
648 // -- Public interface
650 // Parse initializes a Template by parsing its definition. The string
651 // s contains the template text. If any errors occur, Parse returns
653 func (t *Template) Parse(s string) (err os.Error) {
655 return &Error{1, "template not allocated with New"}
657 if !validDelim(t.ldelim) || !validDelim(t.rdelim) {
658 return &Error{1, fmt.Sprintf("bad delimiter strings %q %q", t.ldelim, t.rdelim)}
660 defer checkError(&err)
668 // ParseFile is like Parse but reads the template definition from the
670 func (t *Template) ParseFile(filename string) (err os.Error) {
671 b, err := ioutil.ReadFile(filename)
675 return t.Parse(string(b))
678 // Execute applies a parsed template to the specified data object,
679 // generating output to wr.
680 func (t *Template) Execute(wr io.Writer, data interface{}) (err os.Error) {
681 // Extract the driver data.
682 val := reflect.ValueOf(data)
683 defer checkError(&err)
685 t.execute(0, len(t.elems), &state{parent: nil, data: val, wr: wr})
689 // SetDelims sets the left and right delimiters for operations in the
690 // template. They are validated during parsing. They could be
691 // validated here but it's better to keep the routine simple. The
692 // delimiters are very rarely invalid and Parse has the necessary
693 // error-handling interface already.
694 func (t *Template) SetDelims(left, right string) {
695 t.ldelim = []byte(left)
696 t.rdelim = []byte(right)
699 // Parse creates a Template with default parameters (such as {} for
700 // metacharacters). The string s contains the template text while
701 // the formatter map fmap, which may be nil, defines auxiliary functions
702 // for formatting variables. The template is returned. If any errors
703 // occur, err will be non-nil.
704 func Parse(s string, fmap FormatterMap) (t *Template, err os.Error) {
713 // ParseFile is a wrapper function that creates a Template with default
714 // parameters (such as {} for metacharacters). The filename identifies
715 // a file containing the template text, while the formatter map fmap, which
716 // may be nil, defines auxiliary functions for formatting variables.
717 // The template is returned. If any errors occur, err will be non-nil.
718 func ParseFile(filename string, fmap FormatterMap) (t *Template, err os.Error) {
719 b, err := ioutil.ReadFile(filename)
723 return Parse(string(b), fmap)
726 // MustParse is like Parse but panics if the template cannot be parsed.
727 func MustParse(s string, fmap FormatterMap) *Template {
728 t, err := Parse(s, fmap)
730 panic("template.MustParse error: " + err.String())
735 // MustParseFile is like ParseFile but panics if the file cannot be read
736 // or the template cannot be parsed.
737 func MustParseFile(filename string, fmap FormatterMap) *Template {
738 b, err := ioutil.ReadFile(filename)
740 panic("template.MustParseFile error: " + err.String())
742 return MustParse(string(b), fmap)