func isDigit(ch rune) bool {
	return (ch >= '0' && ch <= '9')
}
isDigit returns true if the rune is a digit.
package vdf
import (
	"bufio"
	"bytes"
	"io"
)
type Scanner struct {
	r *bufio.Reader
}
func NewScanner(r io.Reader) *Scanner {
	return &Scanner{r: bufio.NewReader(r)}
}
func (s *Scanner) read() rune {
	ch, _, err := s.r.ReadRune()
	if err != nil {
		return eof
	}
	return ch
}
func (s *Scanner) unread() {
	_ = s.r.UnreadRune()
}
func (s *Scanner) Scan(respectWhitespace bool) (tok Token, lit string) {
	ch := s.read()
	if !respectWhitespace && (isWhitespace(ch) || isLineEnding(ch)) {
		s.unread()
		return s.scanWhitespace()
	} else if respectWhitespace && isWhitespace(ch) {
		return WS, string(ch)
	} else if respectWhitespace && isLineEnding(ch) {
		return EOL, string(ch)
	} else if isLetter(ch) || isDigit(ch) {
		s.unread()
		return s.scanIdent()
	} else if isComment(ch, s) {
		return CommentDoubleSlash, string(ch) + string(ch)
	}
	switch ch {
	case eof:
		return EOF, ""
	case '\\':
		return EscapeSequence, string(ch)
	case '{':
		return CurlyBraceOpen, string(ch)
	case '}':
		return CurlyBraceClose, string(ch)
	case '"':
		return QuotationMark, string(ch)
	}
	return Illegal, string(ch)
}
func (s *Scanner) scanWhitespace() (Token, string) {
	var buf bytes.Buffer
	buf.WriteRune(s.read())
	for {
		if ch := s.read(); ch == eof {
			break
		} else if !isWhitespace(ch) {
			s.unread()
			break
		} else {
			buf.WriteRune(ch)
		}
	}
	return WS, buf.String()
}
func (s *Scanner) scanIdent() (tok Token, lit string) {
	var buf bytes.Buffer
	buf.WriteRune(s.read())
	for {
		if ch := s.read(); ch == eof {
			break
		} else if !isLetter(ch) && !isDigit(ch) && ch != '_' {
			s.unread()
			break
		} else {
			_, _ = buf.WriteRune(ch)
		}
	}
	return Ident, buf.String()
}
func isWhitespace(ch rune) bool {
	return ch == ' ' || ch == '\t'
}
func isLineEnding(ch rune) bool {
	return ch == '\n' || ch == '\r'
}
func isLetter(ch rune) bool {
	return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
}