1 package parser 2 3 import "io" 4 5 // PhraseType represnts the type of phrase being read. 6 // 7 // Negative values are reserved for this package. 8 type PhraseType int 9 10 // Constants PhraseError (-2) and PhraseDone (-1) 11 const ( 12 PhraseDone PhraseType = -1 - iota 13 PhraseError 14 ) 15 16 // PhraseFunc is the type that the worker types implement in order to be used 17 // by the Phraser 18 type PhraseFunc func(*Parser) (Phrase, PhraseFunc) 19 20 // Phrase represents a collection of tokens that have meaning together 21 type Phrase struct { 22 Type PhraseType 23 Data []Token 24 } 25 26 // Parser is a type used to get tokens or phrases (collection of token) from an 27 // an input 28 type Parser struct { 29 Tokeniser 30 state PhraseFunc 31 tokens []Token 32 peekedToken bool 33 } 34 35 // GetPhrase runs the state machine and retrieves a single Phrase and possibly 36 // an error 37 func (p *Parser) GetPhrase() (Phrase, error) { 38 if p.Err == io.EOF { 39 return Phrase{ 40 Type: PhraseDone, 41 Data: make([]Token, 0), 42 }, io.EOF 43 } 44 if p.state == nil { 45 p.Err = ErrNoState 46 p.state = (*Parser).Error 47 } 48 var ph Phrase 49 ph, p.state = p.state(p) 50 if ph.Type == PhraseError { 51 if p.Err == io.EOF { 52 p.Err = io.ErrUnexpectedEOF 53 } 54 return ph, p.Err 55 } 56 return ph, nil 57 } 58 59 // GetToken runs the state machine and retrieves a single Token and possibly 60 // an error. 61 // 62 // If a Token has already been 'peek'ed, that token will be returned without 63 // running the state machine 64 func (p *Parser) GetToken() (Token, error) { 65 tk := p.get() 66 if tk.Type == TokenError { 67 return tk, p.Err 68 } 69 return tk, nil 70 } 71 72 // PhraserState allows the internal state of the Phraser to be set. 73 func (p *Parser) PhraserState(pf PhraseFunc) { 74 p.state = pf 75 } 76 77 func (p *Parser) get() Token { 78 if p.peekedToken { 79 p.peekedToken = false 80 return p.tokens[len(p.tokens)-1] 81 } else if len(p.tokens) > 0 && p.tokens[len(p.tokens)-1].Type < 0 { 82 return p.tokens[len(p.tokens)-1] 83 } 84 tk := p.Tokeniser.get() 85 p.tokens = append(p.tokens, tk) 86 return tk 87 } 88 89 func (p *Parser) backup() { 90 p.peekedToken = true 91 } 92 93 // Accept will accept a token with one of the given types, returning true if 94 // one is read and false otherwise. 95 func (p *Parser) Accept(types ...TokenType) bool { 96 tk := p.get() 97 for _, t := range types { 98 if tk.Type == t { 99 return true 100 } 101 } 102 p.backup() 103 return false 104 } 105 106 // Peek takes a look at the upcoming Token and returns it. 107 func (p *Parser) Peek() Token { 108 tk := p.get() 109 p.backup() 110 return tk 111 } 112 113 // Get retrieves a slice of the Tokens that have been read so far. 114 func (p *Parser) Get() []Token { 115 var toRet []Token 116 if p.peekedToken { 117 tk := p.tokens[len(p.tokens)-1] 118 toRet = make([]Token, len(p.tokens)-1) 119 copy(toRet, p.tokens) 120 p.tokens[0] = tk 121 p.tokens = p.tokens[:1] 122 } else { 123 toRet = make([]Token, len(p.tokens)) 124 copy(toRet, p.tokens) 125 p.tokens = p.tokens[:0] 126 } 127 return toRet 128 } 129 130 // Len returns how many tokens have been read. 131 func (p *Parser) Len() int { 132 l := len(p.tokens) 133 if p.peekedToken { 134 l-- 135 } 136 return l 137 } 138 139 // AcceptRun will keep Accepting tokens as long as they match one of the 140 // given types. 141 // 142 // It will return the type of the token that made it stop. 143 func (p *Parser) AcceptRun(types ...TokenType) TokenType { 144 Loop: 145 for { 146 tk := p.get() 147 for _, t := range types { 148 if tk.Type == t { 149 continue Loop 150 } 151 } 152 p.backup() 153 return tk.Type 154 } 155 } 156 157 // AcceptToken will accept a token matching one of the ones provided exactly, 158 // returning true if one is read and false otherwise. 159 func (p *Parser) AcceptToken(tokens ...Token) bool { 160 tk := p.get() 161 for _, ttk := range tokens { 162 if ttk == tk { 163 return true 164 } 165 } 166 p.backup() 167 return false 168 } 169 170 // Except will Accept a token that is not one of the types given. Returns true 171 // if it Accepted a token. 172 func (p *Parser) Except(types ...TokenType) bool { 173 tk := p.get() 174 for _, t := range types { 175 if tk.Type == t { 176 p.backup() 177 return false 178 } 179 } 180 return true 181 } 182 183 // ExceptRun will keep Accepting tokens as long as they do not match one of the 184 // given types. 185 // 186 // It will return the type of the token that made it stop. 187 func (p *Parser) ExceptRun(types ...TokenType) TokenType { 188 for { 189 tk := p.get() 190 for _, t := range types { 191 if tk.Type == t || tk.Type < 0 { 192 p.backup() 193 return tk.Type 194 } 195 } 196 } 197 } 198 199 // Done is a PhraseFunc that is used to indicate that there are no more phrases 200 // to parse. 201 func (p *Parser) Done() (Phrase, PhraseFunc) { 202 p.Err = io.EOF 203 return Phrase{ 204 Type: PhraseDone, 205 Data: make([]Token, 0), 206 }, (*Parser).Done 207 } 208 209 // Error represents an error state for the phraser. 210 // 211 // The error value should be set in Parser.Err and then this func should be 212 // called. 213 func (p *Parser) Error() (Phrase, PhraseFunc) { 214 if p.Err == nil { 215 p.Err = ErrUnknownError 216 } 217 return Phrase{ 218 Type: PhraseError, 219 Data: []Token{ 220 {Type: TokenError, Data: p.Err.Error()}, 221 }, 222 }, (*Parser).Error 223 }