func (p *Parser) parseColonSlash() (Revisioner, error) {
	var tok, nextTok token
	var lit string
	var re string
	var negate bool
	var err error
	for {
		tok, lit, err = p.scan()
		if err != nil {
			return nil, err
		}
		nextTok, _, err = p.scan()
		if err != nil {
			return nil, err
		}
		switch {
		case tok == emark && nextTok == emark:
			re += lit
		case re == "" && tok == emark && nextTok == minus:
			negate = true
		case re == "" && tok == emark:
			return nil, &ErrInvalidRevision{fmt.Sprintf(`revision suffix brace component sequences starting with "/!" others than those defined are reserved`)}
		case tok == eof:
			p.unscan()
			reg, err := regexp.Compile(re)
			if err != nil {
				return ColonReg{}, &ErrInvalidRevision{fmt.Sprintf(`revision suffix brace component, %s`, err.Error())}
			}
			return ColonReg{reg, negate}, nil
		default:
			p.unscan()
			re += lit
		}
	}
}
parseColonSlash extract :/<data> statements
package revision
import (
	"bytes"
	"fmt"
	"io"
	"regexp"
	"strconv"
	"time"
)
type ErrInvalidRevision struct {
	s string
}
func (e *ErrInvalidRevision) Error() string {
	return "Revision invalid : " + e.s
}
type Revisioner interface {
}
type Ref string
type TildePath struct {
	Depth int
}
type CaretPath struct {
	Depth int
}
type CaretReg struct {
	Regexp *regexp.Regexp
	Negate bool
}
type CaretType struct {
	ObjectType string
}
type AtReflog struct {
	Depth int
}
type AtCheckout struct {
	Depth int
}
type AtUpstream struct {
	BranchName string
}
type AtPush struct {
	BranchName string
}
type AtDate struct {
	Date time.Time
}
type ColonReg struct {
	Regexp *regexp.Regexp
	Negate bool
}
type ColonPath struct {
	Path string
}
type ColonStagePath struct {
	Path  string
	Stage int
}
type Parser struct {
	s                 *scanner
	currentParsedChar struct {
		tok token
		lit string
	}
	unreadLastChar bool
}
func NewParserFromString(s string) *Parser {
	return NewParser(bytes.NewBufferString(s))
}
func NewParser(r io.Reader) *Parser {
	return &Parser{s: newScanner(r)}
}
func (p *Parser) scan() (token, string, error) {
	if p.unreadLastChar {
		p.unreadLastChar = false
		return p.currentParsedChar.tok, p.currentParsedChar.lit, nil
	}
	tok, lit, err := p.s.scan()
	p.currentParsedChar.tok, p.currentParsedChar.lit = tok, lit
	return tok, lit, err
}
func (p *Parser) unscan() { p.unreadLastChar = true }
func (p *Parser) Parse() ([]Revisioner, error) {
	var rev Revisioner
	var revs []Revisioner
	var tok token
	var err error
	for {
		tok, _, err = p.scan()
		if err != nil {
			return nil, err
		}
		switch tok {
		case at:
			rev, err = p.parseAt()
		case tilde:
			rev, err = p.parseTilde()
		case caret:
			rev, err = p.parseCaret()
		case colon:
			rev, err = p.parseColon()
		case eof:
			err = p.validateFullRevision(&revs)
			if err != nil {
				return []Revisioner{}, err
			}
			return revs, nil
		default:
			p.unscan()
			rev, err = p.parseRef()
		}
		if err != nil {
			return []Revisioner{}, err
		}
		revs = append(revs, rev)
	}
}
func (p *Parser) validateFullRevision(chunks *[]Revisioner) error {
	var hasReference bool
	for i, chunk := range *chunks {
		switch chunk.(type) {
		case Ref:
			if i == 0 {
				hasReference = true
			} else {
				return &ErrInvalidRevision{`reference must be defined once at the beginning`}
			}
		case AtDate:
			if len(*chunks) == 1 || hasReference && len(*chunks) == 2 {
				return nil
			}
			return &ErrInvalidRevision{`"@" statement is not valid, could be : <refname>@{<ISO-8601 date>}, @{<ISO-8601 date>}`}
		case AtReflog:
			if len(*chunks) == 1 || hasReference && len(*chunks) == 2 {
				return nil
			}
			return &ErrInvalidRevision{`"@" statement is not valid, could be : <refname>@{<n>}, @{<n>}`}
		case AtCheckout:
			if len(*chunks) == 1 {
				return nil
			}
			return &ErrInvalidRevision{`"@" statement is not valid, could be : @{-<n>}`}
		case AtUpstream:
			if len(*chunks) == 1 || hasReference && len(*chunks) == 2 {
				return nil
			}
			return &ErrInvalidRevision{`"@" statement is not valid, could be : <refname>@{upstream}, @{upstream}, <refname>@{u}, @{u}`}
		case AtPush:
			if len(*chunks) == 1 || hasReference && len(*chunks) == 2 {
				return nil
			}
			return &ErrInvalidRevision{`"@" statement is not valid, could be : <refname>@{push}, @{push}`}
		case TildePath, CaretPath, CaretReg:
			if !hasReference {
				return &ErrInvalidRevision{`"~" or "^" statement must have a reference defined at the beginning`}
			}
		case ColonReg:
			if len(*chunks) == 1 {
				return nil
			}
			return &ErrInvalidRevision{`":" statement is not valid, could be : :/<regexp>`}
		case ColonPath:
			if i == len(*chunks)-1 && hasReference || len(*chunks) == 1 {
				return nil
			}
			return &ErrInvalidRevision{`":" statement is not valid, could be : <revision>:<path>`}
		case ColonStagePath:
			if len(*chunks) == 1 {
				return nil
			}
			return &ErrInvalidRevision{`":" statement is not valid, could be : :<n>:<path>`}
		}
	}
	return nil
}
func (p *Parser) parseAt() (Revisioner, error) {
	var tok, nextTok token
	var lit, nextLit string
	var err error
	tok, _, err = p.scan()
	if err != nil {
		return nil, err
	}
	if tok != obrace {
		p.unscan()
		return Ref("HEAD"), nil
	}
	tok, lit, err = p.scan()
	if err != nil {
		return nil, err
	}
	nextTok, nextLit, err = p.scan()
	if err != nil {
		return nil, err
	}
	switch {
	case tok == word && (lit == "u" || lit == "upstream") && nextTok == cbrace:
		return AtUpstream{}, nil
	case tok == word && lit == "push" && nextTok == cbrace:
		return AtPush{}, nil
	case tok == number && nextTok == cbrace:
		n, _ := strconv.Atoi(lit)
		return AtReflog{n}, nil
	case tok == minus && nextTok == number:
		n, _ := strconv.Atoi(nextLit)
		t, _, err := p.scan()
		if err != nil {
			return nil, err
		}
		if t != cbrace {
			return nil, &ErrInvalidRevision{fmt.Sprintf(`missing "}" in @{-n} structure`)}
		}
		return AtCheckout{n}, nil
	default:
		p.unscan()
		date := lit
		for {
			tok, lit, err = p.scan()
			if err != nil {
				return nil, err
			}
			switch {
			case tok == cbrace:
				t, err := time.Parse("2006-01-02T15:04:05Z", date)
				if err != nil {
					return nil, &ErrInvalidRevision{fmt.Sprintf(`wrong date "%s" must fit ISO-8601 format : 2006-01-02T15:04:05Z`, date)}
				}
				return AtDate{t}, nil
			default:
				date += lit
			}
		}
	}
}
func (p *Parser) parseTilde() (Revisioner, error) {
	var tok token
	var lit string
	var err error
	tok, lit, err = p.scan()
	if err != nil {
		return nil, err
	}
	switch {
	case tok == number:
		n, _ := strconv.Atoi(lit)
		return TildePath{n}, nil
	default:
		p.unscan()
		return TildePath{1}, nil
	}
}
func (p *Parser) parseCaret() (Revisioner, error) {
	var tok token
	var lit string
	var err error
	tok, lit, err = p.scan()
	if err != nil {
		return nil, err
	}
	switch {
	case tok == obrace:
		r, err := p.parseCaretBraces()
		if err != nil {
			return nil, err
		}
		return r, nil
	case tok == number:
		n, _ := strconv.Atoi(lit)
		if n > 2 {
			return nil, &ErrInvalidRevision{fmt.Sprintf(`"%s" found must be 0, 1 or 2 after "^"`, lit)}
		}
		return CaretPath{n}, nil
	default:
		p.unscan()
		return CaretPath{1}, nil
	}
}
func (p *Parser) parseCaretBraces() (Revisioner, error) {
	var tok, nextTok token
	var lit, _ string
	start := true
	var re string
	var negate bool
	var err error
	for {
		tok, lit, err = p.scan()
		if err != nil {
			return nil, err
		}
		nextTok, _, err = p.scan()
		if err != nil {
			return nil, err
		}
		switch {
		case tok == word && nextTok == cbrace && (lit == "commit" || lit == "tree" || lit == "blob" || lit == "tag" || lit == "object"):
			return CaretType{lit}, nil
		case re == "" && tok == cbrace:
			return CaretType{"tag"}, nil
		case re == "" && tok == emark && nextTok == emark:
			re += lit
		case re == "" && tok == emark && nextTok == minus:
			negate = true
		case re == "" && tok == emark:
			return nil, &ErrInvalidRevision{fmt.Sprintf(`revision suffix brace component sequences starting with "/!" others than those defined are reserved`)}
		case re == "" && tok == slash:
			p.unscan()
		case tok != slash && start:
			return nil, &ErrInvalidRevision{fmt.Sprintf(`"%s" is not a valid revision suffix brace component`, lit)}
		case tok != cbrace:
			p.unscan()
			re += lit
		case tok == cbrace:
			p.unscan()
			reg, err := regexp.Compile(re)
			if err != nil {
				return CaretReg{}, &ErrInvalidRevision{fmt.Sprintf(`revision suffix brace component, %s`, err.Error())}
			}
			return CaretReg{reg, negate}, nil
		}
		start = false
	}
}
func (p *Parser) parseColon() (Revisioner, error) {
	var tok token
	var err error
	tok, _, err = p.scan()
	if err != nil {
		return nil, err
	}
	switch tok {
	case slash:
		return p.parseColonSlash()
	default:
		p.unscan()
		return p.parseColonDefault()
	}
}