12	s     string // Original casing.
 
13	lower string // Lower casing, for case-insensitive token consumption.
 
14	o     int    // Offset in s/lower.
 
17type parseError struct{ err error }
 
19func (e parseError) Error() string {
 
23func (e parseError) Unwrap() error {
 
27// toLower lower cases bytes that are A-Z. strings.ToLower does too much. and
 
28// would replace invalid bytes with unicode replacement characters, which would
 
29// break our requirement that offsets into the original and upper case strings
 
30// point to the same character.
 
31func toLower(s string) string {
 
34		if c >= 'A' && c <= 'Z' {
 
41func newParser(buf []byte) *parser {
 
43	return &parser{s, toLower(s), 0}
 
46// Turn panics of parseError into a descriptive ErrInvalidEncoding. Called with
 
47// defer by functions that parse.
 
48func (p *parser) recover(rerr *error) {
 
58	if errors.As(err, &xerr) {
 
62	*rerr = fmt.Errorf("%w: %s", ErrInvalidEncoding, err)
 
65func (p *parser) xerrorf(format string, args ...any) {
 
66	panic(parseError{fmt.Errorf(format, args...)})
 
69func (p *parser) xcheckf(err error, format string, args ...any) {
 
71		panic(parseError{fmt.Errorf("%s: %w", fmt.Sprintf(format, args...), err)})
 
75func (p *parser) xempty() {
 
77		p.xerrorf("leftover data")
 
81func (p *parser) xnonempty() {
 
83		p.xerrorf("unexpected end")
 
87func (p *parser) xbyte() byte {
 
94func (p *parser) peek(s string) bool {
 
95	return strings.HasPrefix(p.lower[p.o:], s)
 
98func (p *parser) take(s string) bool {
 
106func (p *parser) xtake(s string) {
 
108		p.xerrorf("expected %q", s)
 
112func (p *parser) xauthzid() string {
 
117func (p *parser) xusername() string {
 
122func (p *parser) xnonce() string {
 
125	for ; o < len(p.s); o++ {
 
127		if c <= ' ' || c >= 0x7f || c == ',' {
 
132		p.xerrorf("empty nonce")
 
139func (p *parser) xattrval() {
 
141	if !(c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z') {
 
142		p.xerrorf("expected alpha for attr-val")
 
148func (p *parser) xvalue() string {
 
149	for o, c := range p.s[p.o:] {
 
150		if c == 0 || c == ',' {
 
152				p.xerrorf("invalid empty value")
 
154			r := p.s[p.o : p.o+o]
 
165func (p *parser) xbase64() []byte {
 
167	for ; o < len(p.s); o++ {
 
169		if !(c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9' || c == '/' || c == '+' || c == '=') {
 
173	buf, err := base64.StdEncoding.DecodeString(p.s[p.o:o])
 
174	p.xcheckf(err, "decoding base64")
 
179func (p *parser) xsaslname() string {
 
183	for o, c := range p.s[p.o:] {
 
184		if c == 0 || c == ',' {
 
186				p.xerrorf("saslname unexpected end")
 
189				p.xerrorf("saslname cannot be empty")
 
205				p.xerrorf("bad escape %q in saslanem", esc)
 
217		p.xerrorf("saslname unexpected end")
 
220		p.xerrorf("saslname cannot be empty")
 
227func (p *parser) xcbname() string {
 
229	for ; o < len(p.s); o++ {
 
231		if c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9' || c == '.' || c == '-' {
 
237		p.xerrorf("empty channel binding name")
 
244func (p *parser) xchannelBinding() []byte {
 
249func (p *parser) xproof() []byte {
 
254func (p *parser) xsalt() []byte {
 
259func (p *parser) xtakefn1(fn func(rune, int) bool) string {
 
260	for o, c := range p.s[p.o:] {
 
263				p.xerrorf("non-empty match required")
 
265			r := p.s[p.o : p.o+o]
 
276func (p *parser) xiterations() int {
 
278	digits := p.xtakefn1(func(c rune, i int) bool {
 
279		return c >= '1' && c <= '9' || i > 0 && c == '0'
 
281	v, err := strconv.ParseInt(digits, 10, 32)
 
282	p.xcheckf(err, "parsing int")