mirror of
				https://github.com/coredns/coredns.git
				synced 2025-10-30 17:53:21 -04:00 
			
		
		
		
	
		
			
	
	
		
			123 lines
		
	
	
		
			2.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
		
		
			
		
	
	
			123 lines
		
	
	
		
			2.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
|  | package parse
 | ||
|  | 
 | ||
|  | import (
 | ||
|  | 	"bufio"
 | ||
|  | 	"io"
 | ||
|  | 	"unicode"
 | ||
|  | )
 | ||
|  | 
 | ||
|  | type (
 | ||
|  | 	// lexer is a utility which can get values, token by
 | ||
|  | 	// token, from a Reader. A token is a word, and tokens
 | ||
|  | 	// are separated by whitespace. A word can be enclosed
 | ||
|  | 	// in quotes if it contains whitespace.
 | ||
|  | 	lexer struct {
 | ||
|  | 		reader *bufio.Reader
 | ||
|  | 		token  token
 | ||
|  | 		line   int
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	// token represents a single parsable unit.
 | ||
|  | 	token struct {
 | ||
|  | 		file string
 | ||
|  | 		line int
 | ||
|  | 		text string
 | ||
|  | 	}
 | ||
|  | )
 | ||
|  | 
 | ||
|  | // load prepares the lexer to scan an input for tokens.
 | ||
|  | func (l *lexer) load(input io.Reader) error {
 | ||
|  | 	l.reader = bufio.NewReader(input)
 | ||
|  | 	l.line = 1
 | ||
|  | 	return nil
 | ||
|  | }
 | ||
|  | 
 | ||
|  | // next loads the next token into the lexer.
 | ||
|  | // A token is delimited by whitespace, unless
 | ||
|  | // the token starts with a quotes character (")
 | ||
|  | // in which case the token goes until the closing
 | ||
|  | // quotes (the enclosing quotes are not included).
 | ||
|  | // Inside quoted strings, quotes may be escaped
 | ||
|  | // with a preceding \ character. No other chars
 | ||
|  | // may be escaped. The rest of the line is skipped
 | ||
|  | // if a "#" character is read in. Returns true if
 | ||
|  | // a token was loaded; false otherwise.
 | ||
|  | func (l *lexer) next() bool {
 | ||
|  | 	var val []rune
 | ||
|  | 	var comment, quoted, escaped bool
 | ||
|  | 
 | ||
|  | 	makeToken := func() bool {
 | ||
|  | 		l.token.text = string(val)
 | ||
|  | 		return true
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	for {
 | ||
|  | 		ch, _, err := l.reader.ReadRune()
 | ||
|  | 		if err != nil {
 | ||
|  | 			if len(val) > 0 {
 | ||
|  | 				return makeToken()
 | ||
|  | 			}
 | ||
|  | 			if err == io.EOF {
 | ||
|  | 				return false
 | ||
|  | 			}
 | ||
|  | 			panic(err)
 | ||
|  | 		}
 | ||
|  | 
 | ||
|  | 		if quoted {
 | ||
|  | 			if !escaped {
 | ||
|  | 				if ch == '\\' {
 | ||
|  | 					escaped = true
 | ||
|  | 					continue
 | ||
|  | 				} else if ch == '"' {
 | ||
|  | 					quoted = false
 | ||
|  | 					return makeToken()
 | ||
|  | 				}
 | ||
|  | 			}
 | ||
|  | 			if ch == '\n' {
 | ||
|  | 				l.line++
 | ||
|  | 			}
 | ||
|  | 			if escaped {
 | ||
|  | 				// only escape quotes
 | ||
|  | 				if ch != '"' {
 | ||
|  | 					val = append(val, '\\')
 | ||
|  | 				}
 | ||
|  | 			}
 | ||
|  | 			val = append(val, ch)
 | ||
|  | 			escaped = false
 | ||
|  | 			continue
 | ||
|  | 		}
 | ||
|  | 
 | ||
|  | 		if unicode.IsSpace(ch) {
 | ||
|  | 			if ch == '\r' {
 | ||
|  | 				continue
 | ||
|  | 			}
 | ||
|  | 			if ch == '\n' {
 | ||
|  | 				l.line++
 | ||
|  | 				comment = false
 | ||
|  | 			}
 | ||
|  | 			if len(val) > 0 {
 | ||
|  | 				return makeToken()
 | ||
|  | 			}
 | ||
|  | 			continue
 | ||
|  | 		}
 | ||
|  | 
 | ||
|  | 		if ch == '#' {
 | ||
|  | 			comment = true
 | ||
|  | 		}
 | ||
|  | 
 | ||
|  | 		if comment {
 | ||
|  | 			continue
 | ||
|  | 		}
 | ||
|  | 
 | ||
|  | 		if len(val) == 0 {
 | ||
|  | 			l.token = token{line: l.line}
 | ||
|  | 			if ch == '"' {
 | ||
|  | 				quoted = true
 | ||
|  | 				continue
 | ||
|  | 			}
 | ||
|  | 		}
 | ||
|  | 
 | ||
|  | 		val = append(val, ch)
 | ||
|  | 	}
 | ||
|  | }
 |