2015-10-03 14:08:09 +00:00
|
|
|
package parser
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bufio"
|
2015-10-03 16:45:57 +00:00
|
|
|
"bytes"
|
2015-10-03 14:08:09 +00:00
|
|
|
"io"
|
|
|
|
"unicode"
|
|
|
|
)
|
|
|
|
|
|
|
|
// eof represents a marker rune for the end of the reader.
|
|
|
|
const eof = rune(0)
|
|
|
|
|
|
|
|
// Lexer defines a lexical scanner
|
|
|
|
type Lexer struct {
|
2015-10-03 16:45:57 +00:00
|
|
|
src *bufio.Reader // input
|
|
|
|
ch rune // current character
|
2015-10-03 14:08:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewLexer returns a new instance of Lexer.
|
2015-10-03 16:45:57 +00:00
|
|
|
func NewLexer(src io.Reader) *Lexer {
|
2015-10-03 14:08:09 +00:00
|
|
|
return &Lexer{
|
2015-10-03 16:45:57 +00:00
|
|
|
src: bufio.NewReader(src),
|
2015-10-03 14:08:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-03 17:32:27 +00:00
|
|
|
// next reads the next rune from the bufferred reader. Returns the rune(0) if
|
2015-10-03 14:08:09 +00:00
|
|
|
// an error occurs (or io.EOF is returned).
|
|
|
|
func (l *Lexer) next() rune {
|
2015-10-03 16:45:57 +00:00
|
|
|
var err error
|
|
|
|
l.ch, _, err = l.src.ReadRune()
|
2015-10-03 14:08:09 +00:00
|
|
|
if err != nil {
|
|
|
|
return eof
|
|
|
|
}
|
2015-10-03 17:32:27 +00:00
|
|
|
|
2015-10-03 16:45:57 +00:00
|
|
|
return l.ch
|
2015-10-03 14:08:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// unread places the previously read rune back on the reader.
|
2015-10-03 17:32:27 +00:00
|
|
|
func (l *Lexer) unread() { _ = l.src.UnreadRune() }
|
2015-10-03 14:08:09 +00:00
|
|
|
|
|
|
|
// Scan scans the next token and returns the token and it's literal string.
|
|
|
|
func (l *Lexer) Scan() (tok Token, lit string) {
|
|
|
|
ch := l.next()
|
|
|
|
|
2015-10-03 16:45:57 +00:00
|
|
|
// skip white space
|
|
|
|
for isWhitespace(ch) {
|
2015-10-03 14:08:09 +00:00
|
|
|
ch = l.next()
|
|
|
|
}
|
|
|
|
|
2015-10-03 16:45:57 +00:00
|
|
|
// identifier
|
|
|
|
if isLetter(ch) {
|
|
|
|
return l.scanIdentifier()
|
|
|
|
}
|
|
|
|
|
|
|
|
switch ch {
|
|
|
|
case eof:
|
|
|
|
return EOF, ""
|
|
|
|
}
|
|
|
|
|
2015-10-03 14:08:09 +00:00
|
|
|
return 0, ""
|
|
|
|
}
|
|
|
|
|
2015-10-03 16:45:57 +00:00
|
|
|
func (l *Lexer) scanIdentifier() (Token, string) {
|
|
|
|
// Create a buffer and read the current character into it.
|
|
|
|
var buf bytes.Buffer
|
|
|
|
|
|
|
|
// write current character before we move to the next
|
|
|
|
buf.WriteRune(l.ch)
|
|
|
|
|
|
|
|
return 0, ""
|
2015-10-03 14:08:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Pos returns the position of the character immediately after the character or
|
|
|
|
// token returned by the last call to Next or Scan.
|
|
|
|
func (l *Lexer) Pos() Position {
|
|
|
|
return Position{}
|
|
|
|
}
|
|
|
|
|
|
|
|
// isSpace reports whether r is a space character.
|
|
|
|
func isSpace(r rune) bool {
|
|
|
|
return r == ' ' || r == '\t'
|
|
|
|
}
|
|
|
|
|
|
|
|
// isEndOfLine reports whether r is an end-of-line character.
|
|
|
|
func isEndOfLine(r rune) bool {
|
|
|
|
return r == '\r' || r == '\n'
|
|
|
|
}
|
|
|
|
|
|
|
|
func isLetter(ch rune) bool {
|
|
|
|
return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= 0x80 && unicode.IsLetter(ch)
|
|
|
|
}
|
|
|
|
|
|
|
|
func isDigit(ch rune) bool {
|
|
|
|
return '0' <= ch && ch <= '9' || ch >= 0x80 && unicode.IsDigit(ch)
|
|
|
|
}
|
|
|
|
|
|
|
|
// isWhitespace returns true if the rune is a space, tab, newline or carriage return
|
|
|
|
func isWhitespace(ch rune) bool {
|
|
|
|
return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r'
|
|
|
|
}
|