Imported Upstream version 4.8.1
[platform/upstream/gcc48.git] / libgo / go / html / template / context.go
1 // Copyright 2011 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.
4
5 package template
6
7 import (
8         "fmt"
9 )
10
11 // context describes the state an HTML parser must be in when it reaches the
12 // portion of HTML produced by evaluating a particular template node.
13 //
14 // The zero value of type context is the start context for a template that
15 // produces an HTML fragment as defined at
16 // http://www.w3.org/TR/html5/the-end.html#parsing-html-fragments
17 // where the context element is null.
18 type context struct {
19         state   state
20         delim   delim
21         urlPart urlPart
22         jsCtx   jsCtx
23         attr    attr
24         element element
25         err     *Error
26 }
27
28 func (c context) String() string {
29         return fmt.Sprintf("{%v %v %v %v %v %v %v}", c.state, c.delim, c.urlPart, c.jsCtx, c.attr, c.element, c.err)
30 }
31
32 // eq returns whether two contexts are equal.
33 func (c context) eq(d context) bool {
34         return c.state == d.state &&
35                 c.delim == d.delim &&
36                 c.urlPart == d.urlPart &&
37                 c.jsCtx == d.jsCtx &&
38                 c.attr == d.attr &&
39                 c.element == d.element &&
40                 c.err == d.err
41 }
42
43 // mangle produces an identifier that includes a suffix that distinguishes it
44 // from template names mangled with different contexts.
45 func (c context) mangle(templateName string) string {
46         // The mangled name for the default context is the input templateName.
47         if c.state == stateText {
48                 return templateName
49         }
50         s := templateName + "$htmltemplate_" + c.state.String()
51         if c.delim != 0 {
52                 s += "_" + c.delim.String()
53         }
54         if c.urlPart != 0 {
55                 s += "_" + c.urlPart.String()
56         }
57         if c.jsCtx != 0 {
58                 s += "_" + c.jsCtx.String()
59         }
60         if c.attr != 0 {
61                 s += "_" + c.attr.String()
62         }
63         if c.element != 0 {
64                 s += "_" + c.element.String()
65         }
66         return s
67 }
68
69 // state describes a high-level HTML parser state.
70 //
71 // It bounds the top of the element stack, and by extension the HTML insertion
72 // mode, but also contains state that does not correspond to anything in the
73 // HTML5 parsing algorithm because a single token production in the HTML
74 // grammar may contain embedded actions in a template. For instance, the quoted
75 // HTML attribute produced by
76 //     <div title="Hello {{.World}}">
77 // is a single token in HTML's grammar but in a template spans several nodes.
78 type state uint8
79
80 const (
81         // stateText is parsed character data. An HTML parser is in
82         // this state when its parse position is outside an HTML tag,
83         // directive, comment, and special element body.
84         stateText state = iota
85         // stateTag occurs before an HTML attribute or the end of a tag.
86         stateTag
87         // stateAttrName occurs inside an attribute name.
88         // It occurs between the ^'s in ` ^name^ = value`.
89         stateAttrName
90         // stateAfterName occurs after an attr name has ended but before any
91         // equals sign. It occurs between the ^'s in ` name^ ^= value`.
92         stateAfterName
93         // stateBeforeValue occurs after the equals sign but before the value.
94         // It occurs between the ^'s in ` name =^ ^value`.
95         stateBeforeValue
96         // stateHTMLCmt occurs inside an <!-- HTML comment -->.
97         stateHTMLCmt
98         // stateRCDATA occurs inside an RCDATA element (<textarea> or <title>)
99         // as described at http://dev.w3.org/html5/spec/syntax.html#elements-0
100         stateRCDATA
101         // stateAttr occurs inside an HTML attribute whose content is text.
102         stateAttr
103         // stateURL occurs inside an HTML attribute whose content is a URL.
104         stateURL
105         // stateJS occurs inside an event handler or script element.
106         stateJS
107         // stateJSDqStr occurs inside a JavaScript double quoted string.
108         stateJSDqStr
109         // stateJSSqStr occurs inside a JavaScript single quoted string.
110         stateJSSqStr
111         // stateJSRegexp occurs inside a JavaScript regexp literal.
112         stateJSRegexp
113         // stateJSBlockCmt occurs inside a JavaScript /* block comment */.
114         stateJSBlockCmt
115         // stateJSLineCmt occurs inside a JavaScript // line comment.
116         stateJSLineCmt
117         // stateCSS occurs inside a <style> element or style attribute.
118         stateCSS
119         // stateCSSDqStr occurs inside a CSS double quoted string.
120         stateCSSDqStr
121         // stateCSSSqStr occurs inside a CSS single quoted string.
122         stateCSSSqStr
123         // stateCSSDqURL occurs inside a CSS double quoted url("...").
124         stateCSSDqURL
125         // stateCSSSqURL occurs inside a CSS single quoted url('...').
126         stateCSSSqURL
127         // stateCSSURL occurs inside a CSS unquoted url(...).
128         stateCSSURL
129         // stateCSSBlockCmt occurs inside a CSS /* block comment */.
130         stateCSSBlockCmt
131         // stateCSSLineCmt occurs inside a CSS // line comment.
132         stateCSSLineCmt
133         // stateError is an infectious error state outside any valid
134         // HTML/CSS/JS construct.
135         stateError
136 )
137
138 var stateNames = [...]string{
139         stateText:        "stateText",
140         stateTag:         "stateTag",
141         stateAttrName:    "stateAttrName",
142         stateAfterName:   "stateAfterName",
143         stateBeforeValue: "stateBeforeValue",
144         stateHTMLCmt:     "stateHTMLCmt",
145         stateRCDATA:      "stateRCDATA",
146         stateAttr:        "stateAttr",
147         stateURL:         "stateURL",
148         stateJS:          "stateJS",
149         stateJSDqStr:     "stateJSDqStr",
150         stateJSSqStr:     "stateJSSqStr",
151         stateJSRegexp:    "stateJSRegexp",
152         stateJSBlockCmt:  "stateJSBlockCmt",
153         stateJSLineCmt:   "stateJSLineCmt",
154         stateCSS:         "stateCSS",
155         stateCSSDqStr:    "stateCSSDqStr",
156         stateCSSSqStr:    "stateCSSSqStr",
157         stateCSSDqURL:    "stateCSSDqURL",
158         stateCSSSqURL:    "stateCSSSqURL",
159         stateCSSURL:      "stateCSSURL",
160         stateCSSBlockCmt: "stateCSSBlockCmt",
161         stateCSSLineCmt:  "stateCSSLineCmt",
162         stateError:       "stateError",
163 }
164
165 func (s state) String() string {
166         if int(s) < len(stateNames) {
167                 return stateNames[s]
168         }
169         return fmt.Sprintf("illegal state %d", int(s))
170 }
171
172 // isComment is true for any state that contains content meant for template
173 // authors & maintainers, not for end-users or machines.
174 func isComment(s state) bool {
175         switch s {
176         case stateHTMLCmt, stateJSBlockCmt, stateJSLineCmt, stateCSSBlockCmt, stateCSSLineCmt:
177                 return true
178         }
179         return false
180 }
181
182 // isInTag return whether s occurs solely inside an HTML tag.
183 func isInTag(s state) bool {
184         switch s {
185         case stateTag, stateAttrName, stateAfterName, stateBeforeValue, stateAttr:
186                 return true
187         }
188         return false
189 }
190
191 // delim is the delimiter that will end the current HTML attribute.
192 type delim uint8
193
194 const (
195         // delimNone occurs outside any attribute.
196         delimNone delim = iota
197         // delimDoubleQuote occurs when a double quote (") closes the attribute.
198         delimDoubleQuote
199         // delimSingleQuote occurs when a single quote (') closes the attribute.
200         delimSingleQuote
201         // delimSpaceOrTagEnd occurs when a space or right angle bracket (>)
202         // closes the attribute.
203         delimSpaceOrTagEnd
204 )
205
206 var delimNames = [...]string{
207         delimNone:          "delimNone",
208         delimDoubleQuote:   "delimDoubleQuote",
209         delimSingleQuote:   "delimSingleQuote",
210         delimSpaceOrTagEnd: "delimSpaceOrTagEnd",
211 }
212
213 func (d delim) String() string {
214         if int(d) < len(delimNames) {
215                 return delimNames[d]
216         }
217         return fmt.Sprintf("illegal delim %d", int(d))
218 }
219
220 // urlPart identifies a part in an RFC 3986 hierarchical URL to allow different
221 // encoding strategies.
222 type urlPart uint8
223
224 const (
225         // urlPartNone occurs when not in a URL, or possibly at the start:
226         // ^ in "^http://auth/path?k=v#frag".
227         urlPartNone urlPart = iota
228         // urlPartPreQuery occurs in the scheme, authority, or path; between the
229         // ^s in "h^ttp://auth/path^?k=v#frag".
230         urlPartPreQuery
231         // urlPartQueryOrFrag occurs in the query portion between the ^s in
232         // "http://auth/path?^k=v#frag^".
233         urlPartQueryOrFrag
234         // urlPartUnknown occurs due to joining of contexts both before and
235         // after the query separator.
236         urlPartUnknown
237 )
238
239 var urlPartNames = [...]string{
240         urlPartNone:        "urlPartNone",
241         urlPartPreQuery:    "urlPartPreQuery",
242         urlPartQueryOrFrag: "urlPartQueryOrFrag",
243         urlPartUnknown:     "urlPartUnknown",
244 }
245
246 func (u urlPart) String() string {
247         if int(u) < len(urlPartNames) {
248                 return urlPartNames[u]
249         }
250         return fmt.Sprintf("illegal urlPart %d", int(u))
251 }
252
253 // jsCtx determines whether a '/' starts a regular expression literal or a
254 // division operator.
255 type jsCtx uint8
256
257 const (
258         // jsCtxRegexp occurs where a '/' would start a regexp literal.
259         jsCtxRegexp jsCtx = iota
260         // jsCtxDivOp occurs where a '/' would start a division operator.
261         jsCtxDivOp
262         // jsCtxUnknown occurs where a '/' is ambiguous due to context joining.
263         jsCtxUnknown
264 )
265
266 func (c jsCtx) String() string {
267         switch c {
268         case jsCtxRegexp:
269                 return "jsCtxRegexp"
270         case jsCtxDivOp:
271                 return "jsCtxDivOp"
272         case jsCtxUnknown:
273                 return "jsCtxUnknown"
274         }
275         return fmt.Sprintf("illegal jsCtx %d", int(c))
276 }
277
278 // element identifies the HTML element when inside a start tag or special body.
279 // Certain HTML element (for example <script> and <style>) have bodies that are
280 // treated differently from stateText so the element type is necessary to
281 // transition into the correct context at the end of a tag and to identify the
282 // end delimiter for the body.
283 type element uint8
284
285 const (
286         // elementNone occurs outside a special tag or special element body.
287         elementNone element = iota
288         // elementScript corresponds to the raw text <script> element.
289         elementScript
290         // elementStyle corresponds to the raw text <style> element.
291         elementStyle
292         // elementTextarea corresponds to the RCDATA <textarea> element.
293         elementTextarea
294         // elementTitle corresponds to the RCDATA <title> element.
295         elementTitle
296 )
297
298 var elementNames = [...]string{
299         elementNone:     "elementNone",
300         elementScript:   "elementScript",
301         elementStyle:    "elementStyle",
302         elementTextarea: "elementTextarea",
303         elementTitle:    "elementTitle",
304 }
305
306 func (e element) String() string {
307         if int(e) < len(elementNames) {
308                 return elementNames[e]
309         }
310         return fmt.Sprintf("illegal element %d", int(e))
311 }
312
313 // attr identifies the most recent HTML attribute when inside a start tag.
314 type attr uint8
315
316 const (
317         // attrNone corresponds to a normal attribute or no attribute.
318         attrNone attr = iota
319         // attrScript corresponds to an event handler attribute.
320         attrScript
321         // attrStyle corresponds to the style attribute whose value is CSS.
322         attrStyle
323         // attrURL corresponds to an attribute whose value is a URL.
324         attrURL
325 )
326
327 var attrNames = [...]string{
328         attrNone:   "attrNone",
329         attrScript: "attrScript",
330         attrStyle:  "attrStyle",
331         attrURL:    "attrURL",
332 }
333
334 func (a attr) String() string {
335         if int(a) < len(attrNames) {
336                 return attrNames[a]
337         }
338         return fmt.Sprintf("illegal attr %d", int(a))
339 }