github.com/hugelgupf/u-root@v0.0.0-20191023214958-4807c632154c/cmds/core/elvish/parse/parser.go (about) 1 package parse 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "strings" 8 "unicode/utf8" 9 10 "github.com/u-root/u-root/cmds/core/elvish/util" 11 ) 12 13 // Parser maintains some mutable states of parsing. 14 // 15 // NOTE: The str member is assumed to be valid UF-8. 16 type Parser struct { 17 srcName string 18 src string 19 pos int 20 overEOF int 21 cutsets []map[rune]int 22 errors Error 23 } 24 25 // NewParser creates a new parser from a piece of source text and its name. 26 func NewParser(srcname, src string) *Parser { 27 return &Parser{srcname, src, 0, 0, []map[rune]int{{}}, Error{}} 28 } 29 30 // Done tells the parser that parsing has completed. 31 func (ps *Parser) Done() { 32 if ps.pos != len(ps.src) { 33 r, _ := utf8.DecodeRuneInString(ps.src[ps.pos:]) 34 ps.error(fmt.Errorf("unexpected rune %q", r)) 35 } 36 } 37 38 // Errors gets the parsing errors after calling one of the parse* functions. If 39 // the return value is not nil, it is always of type Error. 40 func (ps *Parser) Errors() error { 41 if len(ps.errors.Entries) > 0 { 42 return &ps.errors 43 } 44 return nil 45 } 46 47 // Source returns the source code that is being parsed. 48 func (ps *Parser) Source() string { 49 return ps.src 50 } 51 52 const eof rune = -1 53 54 func (ps *Parser) peek() rune { 55 if ps.pos == len(ps.src) { 56 return eof 57 } 58 r, _ := utf8.DecodeRuneInString(ps.src[ps.pos:]) 59 return r 60 } 61 62 func (ps *Parser) hasPrefix(prefix string) bool { 63 return strings.HasPrefix(ps.src[ps.pos:], prefix) 64 } 65 66 func (ps *Parser) next() rune { 67 if ps.pos == len(ps.src) { 68 ps.overEOF++ 69 return eof 70 } 71 r, s := utf8.DecodeRuneInString(ps.src[ps.pos:]) 72 ps.pos += s 73 return r 74 } 75 76 func (ps *Parser) backup() { 77 if ps.overEOF > 0 { 78 ps.overEOF-- 79 return 80 } 81 _, s := utf8.DecodeLastRuneInString(ps.src[:ps.pos]) 82 ps.pos -= s 83 } 84 85 func (ps *Parser) errorp(begin, end int, e error) { 86 ps.errors.Add(e.Error(), util.NewSourceRange(ps.srcName, ps.src, begin, end)) 87 } 88 89 func (ps *Parser) error(e error) { 90 end := ps.pos 91 if end < len(ps.src) { 92 end++ 93 } 94 ps.errorp(ps.pos, end, e) 95 } 96 97 func newError(text string, shouldbe ...string) error { 98 if len(shouldbe) == 0 { 99 return errors.New(text) 100 } 101 var buf bytes.Buffer 102 if len(text) > 0 { 103 buf.WriteString(text + ", ") 104 } 105 buf.WriteString("should be " + shouldbe[0]) 106 for i, opt := range shouldbe[1:] { 107 if i == len(shouldbe)-2 { 108 buf.WriteString(" or ") 109 } else { 110 buf.WriteString(", ") 111 } 112 buf.WriteString(opt) 113 } 114 return errors.New(buf.String()) 115 }