github.com/markusbkk/elvish@v0.0.0-20231204143114-91dc52438621/pkg/parse/parser.go (about) 1 package parse 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "io" 8 "reflect" 9 "strings" 10 "unicode/utf8" 11 12 "github.com/markusbkk/elvish/pkg/diag" 13 ) 14 15 // parser maintains some mutable states of parsing. 16 // 17 // NOTE: The str member is assumed to be valid UF-8. 18 type parser struct { 19 srcName string 20 src string 21 pos int 22 overEOF int 23 errors Error 24 warn io.Writer 25 } 26 27 func (ps *parser) parse(n Node) parsed { 28 begin := ps.pos 29 n.n().From = begin 30 n.parse(ps) 31 n.n().To = ps.pos 32 n.n().sourceText = ps.src[begin:ps.pos] 33 return parsed{n} 34 } 35 36 type parserState struct { 37 pos int 38 overEOF int 39 errors Error 40 } 41 42 func (ps *parser) save() parserState { 43 return parserState{ps.pos, ps.overEOF, ps.errors} 44 } 45 46 func (ps *parser) restore(s parserState) { 47 ps.pos, ps.overEOF, ps.errors = s.pos, s.overEOF, s.errors 48 } 49 50 var nodeType = reflect.TypeOf((*Node)(nil)).Elem() 51 52 type parsed struct { 53 n Node 54 } 55 56 func (p parsed) addAs(ptr interface{}, parent Node) { 57 dst := reflect.ValueOf(ptr).Elem() 58 dst.Set(reflect.ValueOf(p.n)) // *ptr = p.n 59 addChild(parent, p.n) 60 } 61 62 func (p parsed) addTo(ptr interface{}, parent Node) { 63 dst := reflect.ValueOf(ptr).Elem() 64 dst.Set(reflect.Append(dst, reflect.ValueOf(p.n))) // *ptr = append(*ptr, n) 65 addChild(parent, p.n) 66 } 67 68 // Tells the parser that parsing is done. 69 func (ps *parser) done() { 70 if ps.pos != len(ps.src) { 71 r, _ := utf8.DecodeRuneInString(ps.src[ps.pos:]) 72 ps.error(fmt.Errorf("unexpected rune %q", r)) 73 } 74 } 75 76 // Assembles all parsing errors as one, or returns nil if there were no errors. 77 func (ps *parser) assembleError() error { 78 if len(ps.errors.Entries) > 0 { 79 return &ps.errors 80 } 81 return nil 82 } 83 84 const eof rune = -1 85 86 func (ps *parser) peek() rune { 87 if ps.pos == len(ps.src) { 88 return eof 89 } 90 r, _ := utf8.DecodeRuneInString(ps.src[ps.pos:]) 91 return r 92 } 93 94 func (ps *parser) hasPrefix(prefix string) bool { 95 return strings.HasPrefix(ps.src[ps.pos:], prefix) 96 } 97 98 func (ps *parser) next() rune { 99 if ps.pos == len(ps.src) { 100 ps.overEOF++ 101 return eof 102 } 103 r, s := utf8.DecodeRuneInString(ps.src[ps.pos:]) 104 ps.pos += s 105 return r 106 } 107 108 func (ps *parser) backup() { 109 if ps.overEOF > 0 { 110 ps.overEOF-- 111 return 112 } 113 _, s := utf8.DecodeLastRuneInString(ps.src[:ps.pos]) 114 ps.pos -= s 115 } 116 117 func (ps *parser) errorp(r diag.Ranger, e error) { 118 ps.errors.add(e.Error(), diag.NewContext(ps.srcName, ps.src, r)) 119 } 120 121 func (ps *parser) error(e error) { 122 end := ps.pos 123 if end < len(ps.src) { 124 end++ 125 } 126 ps.errorp(diag.Ranging{From: ps.pos, To: end}, e) 127 } 128 129 func newError(text string, shouldbe ...string) error { 130 if len(shouldbe) == 0 { 131 return errors.New(text) 132 } 133 var buf bytes.Buffer 134 if len(text) > 0 { 135 buf.WriteString(text + ", ") 136 } 137 buf.WriteString("should be " + shouldbe[0]) 138 for i, opt := range shouldbe[1:] { 139 if i == len(shouldbe)-2 { 140 buf.WriteString(" or ") 141 } else { 142 buf.WriteString(", ") 143 } 144 buf.WriteString(opt) 145 } 146 return errors.New(buf.String()) 147 }