OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [go/] [html/] [template/] [js.go] - Blame information for rev 747

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 747 jeremybenn
// 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
        "bytes"
9
        "encoding/json"
10
        "fmt"
11
        "reflect"
12
        "strings"
13
        "unicode/utf8"
14
)
15
 
16
// nextJSCtx returns the context that determines whether a slash after the
17
// given run of tokens tokens starts a regular expression instead of a division
18
// operator: / or /=.
19
//
20
// This assumes that the token run does not include any string tokens, comment
21
// tokens, regular expression literal tokens, or division operators.
22
//
23
// This fails on some valid but nonsensical JavaScript programs like
24
// "x = ++/foo/i" which is quite different than "x++/foo/i", but is not known to
25
// fail on any known useful programs. It is based on the draft
26
// JavaScript 2.0 lexical grammar and requires one token of lookbehind:
27
// http://www.mozilla.org/js/language/js20-2000-07/rationale/syntax.html
28
func nextJSCtx(s []byte, preceding jsCtx) jsCtx {
29
        s = bytes.TrimRight(s, "\t\n\f\r \u2028\u2029")
30
        if len(s) == 0 {
31
                return preceding
32
        }
33
 
34
        // All cases below are in the single-byte UTF-8 group.
35
        switch c, n := s[len(s)-1], len(s); c {
36
        case '+', '-':
37
                // ++ and -- are not regexp preceders, but + and - are whether
38
                // they are used as infix or prefix operators.
39
                start := n - 1
40
                // Count the number of adjacent dashes or pluses.
41
                for start > 0 && s[start-1] == c {
42
                        start--
43
                }
44
                if (n-start)&1 == 1 {
45
                        // Reached for trailing minus signs since "---" is the
46
                        // same as "-- -".
47
                        return jsCtxRegexp
48
                }
49
                return jsCtxDivOp
50
        case '.':
51
                // Handle "42."
52
                if n != 1 && '0' <= s[n-2] && s[n-2] <= '9' {
53
                        return jsCtxDivOp
54
                }
55
                return jsCtxRegexp
56
        // Suffixes for all punctuators from section 7.7 of the language spec
57
        // that only end binary operators not handled above.
58
        case ',', '<', '>', '=', '*', '%', '&', '|', '^', '?':
59
                return jsCtxRegexp
60
        // Suffixes for all punctuators from section 7.7 of the language spec
61
        // that are prefix operators not handled above.
62
        case '!', '~':
63
                return jsCtxRegexp
64
        // Matches all the punctuators from section 7.7 of the language spec
65
        // that are open brackets not handled above.
66
        case '(', '[':
67
                return jsCtxRegexp
68
        // Matches all the punctuators from section 7.7 of the language spec
69
        // that precede expression starts.
70
        case ':', ';', '{':
71
                return jsCtxRegexp
72
        // CAVEAT: the close punctuators ('}', ']', ')') precede div ops and
73
        // are handled in the default except for '}' which can precede a
74
        // division op as in
75
        //    ({ valueOf: function () { return 42 } } / 2
76
        // which is valid, but, in practice, developers don't divide object
77
        // literals, so our heuristic works well for code like
78
        //    function () { ... }  /foo/.test(x) && sideEffect();
79
        // The ')' punctuator can precede a regular expression as in
80
        //     if (b) /foo/.test(x) && ...
81
        // but this is much less likely than
82
        //     (a + b) / c
83
        case '}':
84
                return jsCtxRegexp
85
        default:
86
                // Look for an IdentifierName and see if it is a keyword that
87
                // can precede a regular expression.
88
                j := n
89
                for j > 0 && isJSIdentPart(rune(s[j-1])) {
90
                        j--
91
                }
92
                if regexpPrecederKeywords[string(s[j:])] {
93
                        return jsCtxRegexp
94
                }
95
        }
96
        // Otherwise is a punctuator not listed above, or
97
        // a string which precedes a div op, or an identifier
98
        // which precedes a div op.
99
        return jsCtxDivOp
100
}
101
 
102
// regexPrecederKeywords is a set of reserved JS keywords that can precede a
103
// regular expression in JS source.
104
var regexpPrecederKeywords = map[string]bool{
105
        "break":      true,
106
        "case":       true,
107
        "continue":   true,
108
        "delete":     true,
109
        "do":         true,
110
        "else":       true,
111
        "finally":    true,
112
        "in":         true,
113
        "instanceof": true,
114
        "return":     true,
115
        "throw":      true,
116
        "try":        true,
117
        "typeof":     true,
118
        "void":       true,
119
}
120
 
121
var jsonMarshalType = reflect.TypeOf((*json.Marshaler)(nil)).Elem()
122
 
123
// indirectToJSONMarshaler returns the value, after dereferencing as many times
124
// as necessary to reach the base type (or nil) or an implementation of json.Marshal.
125
func indirectToJSONMarshaler(a interface{}) interface{} {
126
        v := reflect.ValueOf(a)
127
        for !v.Type().Implements(jsonMarshalType) && v.Kind() == reflect.Ptr && !v.IsNil() {
128
                v = v.Elem()
129
        }
130
        return v.Interface()
131
}
132
 
133
// jsValEscaper escapes its inputs to a JS Expression (section 11.14) that has
134
// neither side-effects nor free variables outside (NaN, Infinity).
135
func jsValEscaper(args ...interface{}) string {
136
        var a interface{}
137
        if len(args) == 1 {
138
                a = indirectToJSONMarshaler(args[0])
139
                switch t := a.(type) {
140
                case JS:
141
                        return string(t)
142
                case JSStr:
143
                        // TODO: normalize quotes.
144
                        return `"` + string(t) + `"`
145
                case json.Marshaler:
146
                        // Do not treat as a Stringer.
147
                case fmt.Stringer:
148
                        a = t.String()
149
                }
150
        } else {
151
                for i, arg := range args {
152
                        args[i] = indirectToJSONMarshaler(arg)
153
                }
154
                a = fmt.Sprint(args...)
155
        }
156
        // TODO: detect cycles before calling Marshal which loops infinitely on
157
        // cyclic data. This may be an unacceptable DoS risk.
158
 
159
        b, err := json.Marshal(a)
160
        if err != nil {
161
                // Put a space before comment so that if it is flush against
162
                // a division operator it is not turned into a line comment:
163
                //     x/{{y}}
164
                // turning into
165
                //     x//* error marshalling y:
166
                //          second line of error message */null
167
                return fmt.Sprintf(" /* %s */null ", strings.Replace(err.Error(), "*/", "* /", -1))
168
        }
169
 
170
        // TODO: maybe post-process output to prevent it from containing
171
        // "", "", or "
172
        // in case custom marshallers produce output containing those.
173
 
174
        // TODO: Maybe abbreviate \u00ab to \xab to produce more compact output.
175
        if len(b) == 0 {
176
                // In, `x=y/{{.}}*z` a json.Marshaler that produces "" should
177
                // not cause the output `x=y/*z`.
178
                return " null "
179
        }
180
        first, _ := utf8.DecodeRune(b)
181
        last, _ := utf8.DecodeLastRune(b)
182
        var buf bytes.Buffer
183
        // Prevent IdentifierNames and NumericLiterals from running into
184
        // keywords: in, instanceof, typeof, void
185
        pad := isJSIdentPart(first) || isJSIdentPart(last)
186
        if pad {
187
                buf.WriteByte(' ')
188
        }
189
        written := 0
190
        // Make sure that json.Marshal escapes codepoints U+2028 & U+2029
191
        // so it falls within the subset of JSON which is valid JS.
192
        for i := 0; i < len(b); {
193
                rune, n := utf8.DecodeRune(b[i:])
194
                repl := ""
195
                if rune == 0x2028 {
196
                        repl = `\u2028`
197
                } else if rune == 0x2029 {
198
                        repl = `\u2029`
199
                }
200
                if repl != "" {
201
                        buf.Write(b[written:i])
202
                        buf.WriteString(repl)
203
                        written = i + n
204
                }
205
                i += n
206
        }
207
        if buf.Len() != 0 {
208
                buf.Write(b[written:])
209
                if pad {
210
                        buf.WriteByte(' ')
211
                }
212
                b = buf.Bytes()
213
        }
214
        return string(b)
215
}
216
 
217
// jsStrEscaper produces a string that can be included between quotes in
218
// JavaScript source, in JavaScript embedded in an HTML5 



powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.