Import of https://github.com/ciena/voltctl at commit 40d61fbf3f910ed4017cf67c9c79e8e1f82a33a5
Change-Id: I8464c59e60d76cb8612891db3303878975b5416c
diff --git a/vendor/github.com/jhump/protoreflect/desc/protoparse/lexer.go b/vendor/github.com/jhump/protoreflect/desc/protoparse/lexer.go
new file mode 100644
index 0000000..c685e56
--- /dev/null
+++ b/vendor/github.com/jhump/protoreflect/desc/protoparse/lexer.go
@@ -0,0 +1,766 @@
+package protoparse
+
+import (
+ "bufio"
+ "bytes"
+ "errors"
+ "fmt"
+ "io"
+ "strconv"
+ "strings"
+ "unicode/utf8"
+)
+
+type runeReader struct {
+ rr *bufio.Reader
+ unread []rune
+ err error
+}
+
+func (rr *runeReader) readRune() (r rune, size int, err error) {
+ if rr.err != nil {
+ return 0, 0, rr.err
+ }
+ if len(rr.unread) > 0 {
+ r := rr.unread[len(rr.unread)-1]
+ rr.unread = rr.unread[:len(rr.unread)-1]
+ return r, utf8.RuneLen(r), nil
+ }
+ r, sz, err := rr.rr.ReadRune()
+ if err != nil {
+ rr.err = err
+ }
+ return r, sz, err
+}
+
+func (rr *runeReader) unreadRune(r rune) {
+ rr.unread = append(rr.unread, r)
+}
+
+func lexError(l protoLexer, pos *SourcePos, err string) {
+ pl := l.(*protoLex)
+ if pl.err == nil {
+ pl.err = ErrorWithSourcePos{Underlying: errors.New(err), Pos: pos}
+ }
+}
+
+type protoLex struct {
+ filename string
+ input *runeReader
+ err error
+ res *fileNode
+
+ lineNo int
+ colNo int
+ offset int
+
+ prevSym terminalNode
+}
+
+func newLexer(in io.Reader) *protoLex {
+ return &protoLex{input: &runeReader{rr: bufio.NewReader(in)}}
+}
+
+var keywords = map[string]int{
+ "syntax": _SYNTAX,
+ "import": _IMPORT,
+ "weak": _WEAK,
+ "public": _PUBLIC,
+ "package": _PACKAGE,
+ "option": _OPTION,
+ "true": _TRUE,
+ "false": _FALSE,
+ "inf": _INF,
+ "nan": _NAN,
+ "repeated": _REPEATED,
+ "optional": _OPTIONAL,
+ "required": _REQUIRED,
+ "double": _DOUBLE,
+ "float": _FLOAT,
+ "int32": _INT32,
+ "int64": _INT64,
+ "uint32": _UINT32,
+ "uint64": _UINT64,
+ "sint32": _SINT32,
+ "sint64": _SINT64,
+ "fixed32": _FIXED32,
+ "fixed64": _FIXED64,
+ "sfixed32": _SFIXED32,
+ "sfixed64": _SFIXED64,
+ "bool": _BOOL,
+ "string": _STRING,
+ "bytes": _BYTES,
+ "group": _GROUP,
+ "oneof": _ONEOF,
+ "map": _MAP,
+ "extensions": _EXTENSIONS,
+ "to": _TO,
+ "max": _MAX,
+ "reserved": _RESERVED,
+ "enum": _ENUM,
+ "message": _MESSAGE,
+ "extend": _EXTEND,
+ "service": _SERVICE,
+ "rpc": _RPC,
+ "stream": _STREAM,
+ "returns": _RETURNS,
+}
+
+func (l *protoLex) cur() *SourcePos {
+ return &SourcePos{
+ Filename: l.filename,
+ Offset: l.offset,
+ Line: l.lineNo + 1,
+ Col: l.colNo + 1,
+ }
+}
+
+func (l *protoLex) prev() *SourcePos {
+ if l.prevSym == nil {
+ return &SourcePos{
+ Filename: l.filename,
+ Offset: 0,
+ Line: 1,
+ Col: 1,
+ }
+ }
+ return l.prevSym.start()
+}
+
+func (l *protoLex) Lex(lval *protoSymType) int {
+ if l.err != nil {
+ // if we are already in a failed state, bail
+ lval.err = l.err
+ return _ERROR
+ }
+
+ prevLineNo := l.lineNo
+ prevColNo := l.colNo
+ prevOffset := l.offset
+ var comments []*comment
+
+ pos := func() posRange {
+ return posRange{
+ start: &SourcePos{
+ Filename: l.filename,
+ Offset: prevOffset,
+ Line: prevLineNo + 1,
+ Col: prevColNo + 1,
+ },
+ end: l.cur(),
+ }
+ }
+ basic := func() basicNode {
+ return basicNode{
+ posRange: pos(),
+ leading: comments,
+ }
+ }
+ setPrev := func(n terminalNode) {
+ nStart := n.start().Line
+ if _, ok := n.(*basicNode); ok {
+ // if the node is a simple rune, don't attribute comments to it
+ // HACK: adjusting the start line makes leading comments appear
+ // detached so logic below will naturally associated trailing
+ // comment to previous symbol
+ nStart += 2
+ }
+ if l.prevSym != nil && len(n.leadingComments()) > 0 && l.prevSym.end().Line < nStart {
+ // we may need to re-attribute the first comment to
+ // instead be previous node's trailing comment
+ prevEnd := l.prevSym.end().Line
+ comments := n.leadingComments()
+ c := comments[0]
+ commentStart := c.start.Line
+ if commentStart == prevEnd {
+ // comment is on same line as previous symbol
+ n.popLeadingComment()
+ l.prevSym.pushTrailingComment(c)
+ } else if commentStart == prevEnd+1 {
+ // comment is right after previous symbol; see if it is detached
+ // and if so re-attribute
+ singleLineStyle := strings.HasPrefix(c.text, "//")
+ line := c.end.Line
+ groupEnd := -1
+ for i := 1; i < len(comments); i++ {
+ c := comments[i]
+ newGroup := false
+ if !singleLineStyle || c.start.Line > line+1 {
+ // we've found a gap between comments, which means the
+ // previous comments were detached
+ newGroup = true
+ } else {
+ line = c.end.Line
+ singleLineStyle = strings.HasPrefix(comments[i].text, "//")
+ if !singleLineStyle {
+ // we've found a switch from // comments to /*
+ // consider that a new group which means the
+ // previous comments were detached
+ newGroup = true
+ }
+ }
+ if newGroup {
+ groupEnd = i
+ break
+ }
+ }
+
+ if groupEnd == -1 {
+ // just one group of comments; we'll mark it as a trailing
+ // comment if it immediately follows previous symbol and is
+ // detached from current symbol
+ c1 := comments[0]
+ c2 := comments[len(comments)-1]
+ if c1.start.Line <= prevEnd+1 && c2.end.Line < nStart-1 {
+ groupEnd = len(comments)
+ }
+ }
+
+ for i := 0; i < groupEnd; i++ {
+ l.prevSym.pushTrailingComment(n.popLeadingComment())
+ }
+ }
+ }
+
+ l.prevSym = n
+ }
+ setString := func(val string) {
+ b := basic()
+ lval.str = &stringLiteralNode{val: val}
+ lval.str.setRange(&b, &b)
+ setPrev(lval.str)
+ }
+ setIdent := func(val string, kind identKind) {
+ lval.id = &identNode{basicNode: basic(), val: val, kind: kind}
+ setPrev(lval.id)
+ }
+ setInt := func(val uint64) {
+ lval.ui = &intLiteralNode{basicNode: basic(), val: val}
+ setPrev(lval.ui)
+ }
+ setFloat := func(val float64) {
+ b := basic()
+ lval.f = &floatLiteralNode{val: val}
+ lval.f.setRange(&b, &b)
+ setPrev(lval.f)
+ }
+ setRune := func() {
+ b := basic()
+ lval.b = &b
+ setPrev(lval.b)
+ }
+ setError := func(err error) {
+ lval.err = err
+ l.err = err
+ }
+
+ for {
+ c, n, err := l.input.readRune()
+ if err == io.EOF {
+ // we're not actually returning a rune, but this will associate
+ // accumulated comments as a trailing comment on last symbol
+ // (if appropriate)
+ setRune()
+ return 0
+ } else if err != nil {
+ setError(err)
+ return _ERROR
+ }
+
+ prevLineNo = l.lineNo
+ prevColNo = l.colNo
+ prevOffset = l.offset
+
+ l.offset += n
+ if c == '\n' {
+ l.colNo = 0
+ l.lineNo++
+ continue
+ } else if c == '\r' {
+ continue
+ }
+ l.colNo++
+ if c == ' ' || c == '\t' {
+ continue
+ }
+
+ if c == '.' {
+ // tokens that start with a dot include type names and decimal literals
+ cn, _, err := l.input.readRune()
+ if err != nil {
+ setRune()
+ return int(c)
+ }
+ if cn == '_' || (cn >= 'a' && cn <= 'z') || (cn >= 'A' && cn <= 'Z') {
+ l.colNo++
+ token := []rune{c, cn}
+ token = l.readIdentifier(token)
+ setIdent(string(token), identTypeName)
+ return _TYPENAME
+ }
+ if cn >= '0' && cn <= '9' {
+ l.colNo++
+ token := []rune{c, cn}
+ token = l.readNumber(token, false, true)
+ f, err := strconv.ParseFloat(string(token), 64)
+ if err != nil {
+ setError(err)
+ return _ERROR
+ }
+ setFloat(f)
+ return _FLOAT_LIT
+ }
+ l.input.unreadRune(cn)
+ setRune()
+ return int(c)
+ }
+
+ if c == '_' || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') {
+ // identifier
+ token := []rune{c}
+ token = l.readIdentifier(token)
+ str := string(token)
+ if strings.Contains(str, ".") {
+ setIdent(str, identQualified)
+ return _FQNAME
+ }
+ if t, ok := keywords[str]; ok {
+ setIdent(str, identSimpleName)
+ return t
+ }
+ setIdent(str, identSimpleName)
+ return _NAME
+ }
+
+ if c >= '0' && c <= '9' {
+ // integer or float literal
+ if c == '0' {
+ cn, _, err := l.input.readRune()
+ if err != nil {
+ setInt(0)
+ return _INT_LIT
+ }
+ if cn == 'x' || cn == 'X' {
+ cnn, _, err := l.input.readRune()
+ if err != nil {
+ l.input.unreadRune(cn)
+ setInt(0)
+ return _INT_LIT
+ }
+ if (cnn >= '0' && cnn <= '9') || (cnn >= 'a' && cnn <= 'f') || (cnn >= 'A' && cnn <= 'F') {
+ // hexadecimal!
+ l.colNo += 2
+ token := []rune{cnn}
+ token = l.readHexNumber(token)
+ ui, err := strconv.ParseUint(string(token), 16, 64)
+ if err != nil {
+ setError(err)
+ return _ERROR
+ }
+ setInt(ui)
+ return _INT_LIT
+ }
+ l.input.unreadRune(cnn)
+ l.input.unreadRune(cn)
+ setInt(0)
+ return _INT_LIT
+ } else {
+ l.input.unreadRune(cn)
+ }
+ }
+ token := []rune{c}
+ token = l.readNumber(token, true, true)
+ numstr := string(token)
+ if strings.Contains(numstr, ".") || strings.Contains(numstr, "e") || strings.Contains(numstr, "E") {
+ // floating point!
+ f, err := strconv.ParseFloat(numstr, 64)
+ if err != nil {
+ setError(err)
+ return _ERROR
+ }
+ setFloat(f)
+ return _FLOAT_LIT
+ }
+ // integer! (decimal or octal)
+ ui, err := strconv.ParseUint(numstr, 0, 64)
+ if err != nil {
+ setError(err)
+ return _ERROR
+ }
+ setInt(ui)
+ return _INT_LIT
+ }
+
+ if c == '\'' || c == '"' {
+ // string literal
+ str, err := l.readStringLiteral(c)
+ if err != nil {
+ setError(err)
+ return _ERROR
+ }
+ setString(str)
+ return _STRING_LIT
+ }
+
+ if c == '/' {
+ // comment
+ cn, _, err := l.input.readRune()
+ if err != nil {
+ setRune()
+ return int(c)
+ }
+ if cn == '/' {
+ l.colNo++
+ hitNewline, txt := l.skipToEndOfLineComment()
+ commentPos := pos()
+ commentPos.end.Col++
+ if hitNewline {
+ l.colNo = 0
+ l.lineNo++
+ }
+ comments = append(comments, &comment{posRange: commentPos, text: txt})
+ continue
+ }
+ if cn == '*' {
+ l.colNo++
+ if txt, ok := l.skipToEndOfBlockComment(); !ok {
+ setError(errors.New("block comment never terminates, unexpected EOF"))
+ return _ERROR
+ } else {
+ comments = append(comments, &comment{posRange: pos(), text: txt})
+ }
+ continue
+ }
+ l.input.unreadRune(cn)
+ }
+
+ setRune()
+ return int(c)
+ }
+}
+
+func (l *protoLex) readNumber(sofar []rune, allowDot bool, allowExp bool) []rune {
+ token := sofar
+ for {
+ c, _, err := l.input.readRune()
+ if err != nil {
+ break
+ }
+ if c == '.' {
+ if !allowDot {
+ l.input.unreadRune(c)
+ break
+ }
+ allowDot = false
+ cn, _, err := l.input.readRune()
+ if err != nil {
+ l.input.unreadRune(c)
+ break
+ }
+ if cn < '0' || cn > '9' {
+ l.input.unreadRune(cn)
+ l.input.unreadRune(c)
+ break
+ }
+ l.colNo++
+ token = append(token, c)
+ c = cn
+ } else if c == 'e' || c == 'E' {
+ if !allowExp {
+ l.input.unreadRune(c)
+ break
+ }
+ allowExp = false
+ cn, _, err := l.input.readRune()
+ if err != nil {
+ l.input.unreadRune(c)
+ break
+ }
+ if cn == '-' || cn == '+' {
+ cnn, _, err := l.input.readRune()
+ if err != nil {
+ l.input.unreadRune(cn)
+ l.input.unreadRune(c)
+ break
+ }
+ if cnn < '0' || cnn > '9' {
+ l.input.unreadRune(cnn)
+ l.input.unreadRune(cn)
+ l.input.unreadRune(c)
+ break
+ }
+ l.colNo++
+ token = append(token, c)
+ c = cn
+ cn = cnn
+ } else if cn < '0' || cn > '9' {
+ l.input.unreadRune(cn)
+ l.input.unreadRune(c)
+ break
+ }
+ l.colNo++
+ token = append(token, c)
+ c = cn
+ } else if c < '0' || c > '9' {
+ l.input.unreadRune(c)
+ break
+ }
+ l.colNo++
+ token = append(token, c)
+ }
+ return token
+}
+
+func (l *protoLex) readHexNumber(sofar []rune) []rune {
+ token := sofar
+ for {
+ c, _, err := l.input.readRune()
+ if err != nil {
+ break
+ }
+ if (c < 'a' || c > 'f') && (c < 'A' || c > 'F') && (c < '0' || c > '9') {
+ l.input.unreadRune(c)
+ break
+ }
+ l.colNo++
+ token = append(token, c)
+ }
+ return token
+}
+
+func (l *protoLex) readIdentifier(sofar []rune) []rune {
+ token := sofar
+ for {
+ c, _, err := l.input.readRune()
+ if err != nil {
+ break
+ }
+ if c == '.' {
+ cn, _, err := l.input.readRune()
+ if err != nil {
+ l.input.unreadRune(c)
+ break
+ }
+ if cn != '_' && (cn < 'a' || cn > 'z') && (cn < 'A' || cn > 'Z') {
+ l.input.unreadRune(cn)
+ l.input.unreadRune(c)
+ break
+ }
+ l.colNo++
+ token = append(token, c)
+ c = cn
+ } else if c != '_' && (c < 'a' || c > 'z') && (c < 'A' || c > 'Z') && (c < '0' || c > '9') {
+ l.input.unreadRune(c)
+ break
+ }
+ l.colNo++
+ token = append(token, c)
+ }
+ return token
+}
+
+func (l *protoLex) readStringLiteral(quote rune) (string, error) {
+ var buf bytes.Buffer
+ for {
+ c, _, err := l.input.readRune()
+ if err != nil {
+ if err == io.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ return "", err
+ }
+ if c == '\n' {
+ l.colNo = 0
+ l.lineNo++
+ return "", errors.New("encountered end-of-line before end of string literal")
+ }
+ l.colNo++
+ if c == quote {
+ break
+ }
+ if c == 0 {
+ return "", errors.New("null character ('\\0') not allowed in string literal")
+ }
+ if c == '\\' {
+ // escape sequence
+ c, _, err = l.input.readRune()
+ if err != nil {
+ return "", err
+ }
+ l.colNo++
+ if c == 'x' || c == 'X' {
+ // hex escape
+ c, _, err := l.input.readRune()
+ if err != nil {
+ return "", err
+ }
+ l.colNo++
+ c2, _, err := l.input.readRune()
+ if err != nil {
+ return "", err
+ }
+ var hex string
+ if (c2 < '0' || c2 > '9') && (c2 < 'a' || c2 > 'f') && (c2 < 'A' || c2 > 'F') {
+ l.input.unreadRune(c2)
+ hex = string(c)
+ } else {
+ l.colNo++
+ hex = string([]rune{c, c2})
+ }
+ i, err := strconv.ParseInt(hex, 16, 32)
+ if err != nil {
+ return "", fmt.Errorf("invalid hex escape: \\x%q", hex)
+ }
+ buf.WriteByte(byte(i))
+
+ } else if c >= '0' && c <= '7' {
+ // octal escape
+ c2, _, err := l.input.readRune()
+ if err != nil {
+ return "", err
+ }
+ var octal string
+ if c2 < '0' || c2 > '7' {
+ l.input.unreadRune(c2)
+ octal = string(c)
+ } else {
+ l.colNo++
+ c3, _, err := l.input.readRune()
+ if err != nil {
+ return "", err
+ }
+ if c3 < '0' || c3 > '7' {
+ l.input.unreadRune(c3)
+ octal = string([]rune{c, c2})
+ } else {
+ l.colNo++
+ octal = string([]rune{c, c2, c3})
+ }
+ }
+ i, err := strconv.ParseInt(octal, 8, 32)
+ if err != nil {
+ return "", fmt.Errorf("invalid octal escape: \\%q", octal)
+ }
+ if i > 0xff {
+ return "", fmt.Errorf("octal escape is out range, must be between 0 and 377: \\%q", octal)
+ }
+ buf.WriteByte(byte(i))
+
+ } else if c == 'u' {
+ // short unicode escape
+ u := make([]rune, 4)
+ for i := range u {
+ c, _, err := l.input.readRune()
+ if err != nil {
+ return "", err
+ }
+ l.colNo++
+ u[i] = c
+ }
+ i, err := strconv.ParseInt(string(u), 16, 32)
+ if err != nil {
+ return "", fmt.Errorf("invalid unicode escape: \\u%q", string(u))
+ }
+ buf.WriteRune(rune(i))
+
+ } else if c == 'U' {
+ // long unicode escape
+ u := make([]rune, 8)
+ for i := range u {
+ c, _, err := l.input.readRune()
+ if err != nil {
+ return "", err
+ }
+ l.colNo++
+ u[i] = c
+ }
+ i, err := strconv.ParseInt(string(u), 16, 32)
+ if err != nil {
+ return "", fmt.Errorf("invalid unicode escape: \\U%q", string(u))
+ }
+ if i > 0x10ffff || i < 0 {
+ return "", fmt.Errorf("unicode escape is out of range, must be between 0 and 0x10ffff: \\U%q", string(u))
+ }
+ buf.WriteRune(rune(i))
+
+ } else if c == 'a' {
+ buf.WriteByte('\a')
+ } else if c == 'b' {
+ buf.WriteByte('\b')
+ } else if c == 'f' {
+ buf.WriteByte('\f')
+ } else if c == 'n' {
+ buf.WriteByte('\n')
+ } else if c == 'r' {
+ buf.WriteByte('\r')
+ } else if c == 't' {
+ buf.WriteByte('\t')
+ } else if c == 'v' {
+ buf.WriteByte('\v')
+ } else if c == '\\' {
+ buf.WriteByte('\\')
+ } else if c == '\'' {
+ buf.WriteByte('\'')
+ } else if c == '"' {
+ buf.WriteByte('"')
+ } else if c == '?' {
+ buf.WriteByte('?')
+ } else {
+ return "", fmt.Errorf("invalid escape sequence: %q", "\\"+string(c))
+ }
+ } else {
+ buf.WriteRune(c)
+ }
+ }
+ return buf.String(), nil
+}
+
+func (l *protoLex) skipToEndOfLineComment() (bool, string) {
+ txt := []rune{'/', '/'}
+ for {
+ c, _, err := l.input.readRune()
+ if err != nil {
+ return false, string(txt)
+ }
+ if c == '\n' {
+ return true, string(txt)
+ }
+ l.colNo++
+ txt = append(txt, c)
+ }
+}
+
+func (l *protoLex) skipToEndOfBlockComment() (string, bool) {
+ txt := []rune{'/', '*'}
+ for {
+ c, _, err := l.input.readRune()
+ if err != nil {
+ return "", false
+ }
+ if c == '\n' {
+ l.colNo = 0
+ l.lineNo++
+ } else {
+ l.colNo++
+ }
+ txt = append(txt, c)
+ if c == '*' {
+ c, _, err := l.input.readRune()
+ if err != nil {
+ return "", false
+ }
+ if c == '/' {
+ l.colNo++
+ txt = append(txt, c)
+ return string(txt), true
+ }
+ l.input.unreadRune(c)
+ }
+ }
+}
+
+func (l *protoLex) Error(s string) {
+ if l.err == nil {
+ l.err = ErrorWithSourcePos{Underlying: errors.New(s), Pos: l.prevSym.start()}
+ }
+}