func (i *inputBytes) context(pos int) syntax.EmptyOp { r1, r2 := endOfText, endOfText if pos > 0 && pos <= len(i.str) { r1, _ = utf8.DecodeLastRune(i.str[:pos]) } if pos < len(i.str) { r2, _ = utf8.DecodeRune(i.str[pos:]) } return syntax.EmptyOpContext(r1, r2) }
// lastIndexFunc is the same as LastIndexFunc except that if // truth==false, the sense of the predicate function is // inverted. func lastIndexFunc(s []byte, f func(r int) bool, truth bool) int { for i := len(s); i > 0; { rune, size := utf8.DecodeLastRune(s[0:i]) i -= size if f(rune) == truth { return i } } return -1 }
// UnreadRune unreads the last rune returned by ReadRune. // If the most recent read or write operation on the buffer was // not a ReadRune, UnreadRune returns an error. (In this regard // it is stricter than UnreadByte, which will unread the last byte // from any read operation.) func (b *Buffer) UnreadRune() error { if b.lastRead != opReadRune { return errors.New("bytes.Buffer: UnreadRune: previous operation was not ReadRune") } b.lastRead = opInvalid if b.off > 0 { _, n := utf8.DecodeLastRune(b.buf[0:b.off]) b.off -= n } return nil }
// LastIndexAny interprets s as a sequence of UTF-8-encoded Unicode code // points. It returns the byte index of the last occurrence in s of any of // the Unicode code points in chars. It returns -1 if chars is empty or if // there is no code point in common. func LastIndexAny(s []byte, chars string) int { if len(chars) > 0 { for i := len(s); i > 0; { rune, size := utf8.DecodeLastRune(s[0:i]) i -= size for _, m := range chars { if rune == m { return i } } } } return -1 }
// endsWithCSSKeyword returns whether b ends with an ident that // case-insensitively matches the lower-case kw. func endsWithCSSKeyword(b []byte, kw string) bool { i := len(b) - len(kw) if i < 0 { // Too short. return false } if i != 0 { r, _ := utf8.DecodeLastRune(b[:i]) if isCSSNmchar(r) { // Too long. return false } } // Many CSS keywords, such as "!important" can have characters encoded, // but the URI production does not allow that according to // http://www.w3.org/TR/css3-syntax/#TOK-URI // This does not attempt to recognize encoded keywords. For example, // given "\75\72\6c" and "url" this return false. return string(bytes.ToLower(b[i:])) == kw }
// jsValEscaper escapes its inputs to a JS Expression (section 11.14) that has // nether side-effects nor free variables outside (NaN, Infinity). func jsValEscaper(args ...interface{}) string { var a interface{} if len(args) == 1 { a = args[0] switch t := a.(type) { case JS: return string(t) case JSStr: // TODO: normalize quotes. return `"` + string(t) + `"` case json.Marshaler: // Do not treat as a Stringer. case fmt.Stringer: a = t.String() } } else { a = fmt.Sprint(args...) } // TODO: detect cycles before calling Marshal which loops infinitely on // cyclic data. This may be an unnacceptable DoS risk. b, err := json.Marshal(a) if err != nil { // Put a space before comment so that if it is flush against // a division operator it is not turned into a line comment: // x/{{y}} // turning into // x//* error marshalling y: // second line of error message */null return fmt.Sprintf(" /* %s */null ", strings.Replace(err.Error(), "*/", "* /", -1)) } // TODO: maybe post-process output to prevent it from containing // "<!--", "-->", "<![CDATA[", "]]>", or "</script" // in case custom marshallers produce output containing those. // TODO: Maybe abbreviate \u00ab to \xab to produce more compact output. if len(b) == 0 { // In, `x=y/{{.}}*z` a json.Marshaler that produces "" should // not cause the output `x=y/*z`. return " null " } first, _ := utf8.DecodeRune(b) last, _ := utf8.DecodeLastRune(b) var buf bytes.Buffer // Prevent IdentifierNames and NumericLiterals from running into // keywords: in, instanceof, typeof, void pad := isJSIdentPart(first) || isJSIdentPart(last) if pad { buf.WriteByte(' ') } written := 0 // Make sure that json.Marshal escapes codepoints U+2028 & U+2029 // so it falls within the subset of JSON which is valid JS. for i := 0; i < len(b); { rune, n := utf8.DecodeRune(b[i:]) repl := "" if rune == 0x2028 { repl = `\u2028` } else if rune == 0x2029 { repl = `\u2029` } if repl != "" { buf.Write(b[written:i]) buf.WriteString(repl) written = i + n } i += n } if buf.Len() != 0 { buf.Write(b[written:]) if pad { buf.WriteByte(' ') } b = buf.Bytes() } return string(b) }