forked from sloum/bombadillo
162 lines
2.8 KiB
Go
162 lines
2.8 KiB
Go
package cmdparse
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"io"
|
|
"strings"
|
|
)
|
|
|
|
//------------------------------------------------\\
|
|
// + + + T Y P E S + + + \\
|
|
//--------------------------------------------------\\
|
|
|
|
type Token struct {
|
|
kind tok
|
|
val string
|
|
}
|
|
|
|
type scanner struct {
|
|
r *bufio.Reader
|
|
}
|
|
|
|
type tok int
|
|
|
|
//------------------------------------------------\\
|
|
// + + + V A R I A B L E S + + + \\
|
|
//--------------------------------------------------\\
|
|
|
|
var eof rune = rune(0)
|
|
|
|
const (
|
|
Word tok = iota
|
|
Action
|
|
Value
|
|
End
|
|
Whitespace
|
|
|
|
illegal
|
|
)
|
|
|
|
//------------------------------------------------\\
|
|
// + + + R E C E I V E R S + + + \\
|
|
//--------------------------------------------------\\
|
|
|
|
func (s *scanner) read() rune {
|
|
ch, _, err := s.r.ReadRune()
|
|
if err != nil {
|
|
return eof
|
|
}
|
|
return ch
|
|
}
|
|
|
|
func (s *scanner) scanText() Token {
|
|
var buf bytes.Buffer
|
|
buf.WriteRune(s.read())
|
|
|
|
for {
|
|
if ch := s.read(); ch == eof {
|
|
s.unread()
|
|
break
|
|
} else if !isLetter(ch) && !isDigit(ch) {
|
|
s.unread()
|
|
break
|
|
} else {
|
|
_, _ = buf.WriteRune(ch)
|
|
}
|
|
}
|
|
|
|
capInput := strings.ToUpper(buf.String())
|
|
switch capInput {
|
|
case "D", "DELETE", "A", "ADD","W", "WRITE",
|
|
"S", "SET", "R", "RELOAD", "SEARCH",
|
|
"Q", "QUIT", "B", "BOOKMARKS", "H",
|
|
"HOME", "?", "HELP", "C", "CHECK",
|
|
"P", "PURGE":
|
|
return Token{Action, capInput}
|
|
}
|
|
|
|
return Token{Word, buf.String()}
|
|
}
|
|
|
|
func (s *scanner) scanWhitespace() Token {
|
|
var buf bytes.Buffer
|
|
buf.WriteRune(s.read())
|
|
|
|
for {
|
|
if ch := s.read(); ch == eof {
|
|
s.unread()
|
|
break
|
|
} else if !isWhitespace(ch) {
|
|
s.unread()
|
|
break
|
|
} else {
|
|
_, _ = buf.WriteRune(ch)
|
|
}
|
|
}
|
|
|
|
return Token{Whitespace, buf.String()}
|
|
|
|
}
|
|
|
|
func (s *scanner) scanNumber() Token {
|
|
var buf bytes.Buffer
|
|
buf.WriteRune(s.read())
|
|
|
|
for {
|
|
if ch := s.read(); ch == eof {
|
|
break
|
|
} else if !isDigit(ch) {
|
|
s.unread()
|
|
break
|
|
} else {
|
|
_, _ = buf.WriteRune(ch)
|
|
}
|
|
}
|
|
|
|
return Token{Value, buf.String()}
|
|
}
|
|
|
|
func (s *scanner) unread() { _ = s.r.UnreadRune() }
|
|
|
|
func (s *scanner) scan() Token {
|
|
char := s.read()
|
|
|
|
if isWhitespace(char) {
|
|
s.unread()
|
|
return s.scanWhitespace()
|
|
} else if isDigit(char) {
|
|
s.unread()
|
|
return s.scanNumber()
|
|
} else if isLetter(char) {
|
|
s.unread()
|
|
return s.scanText()
|
|
}
|
|
|
|
if char == eof {
|
|
return Token{End, ""}
|
|
}
|
|
|
|
return Token{illegal, string(char)}
|
|
}
|
|
|
|
//------------------------------------------------\\
|
|
// + + + F U N C T I O N S + + + \\
|
|
//--------------------------------------------------\\
|
|
|
|
func NewScanner(r io.Reader) *scanner {
|
|
return &scanner{r: bufio.NewReader(r)}
|
|
}
|
|
|
|
func isWhitespace(ch rune) bool {
|
|
return ch == ' ' || ch == '\t' || ch == '\n'
|
|
}
|
|
|
|
func isLetter(ch rune) bool {
|
|
return ch >= '!' && ch <= '~'
|
|
}
|
|
|
|
func isDigit(ch rune) bool {
|
|
return ch >= '0' && ch <= '9'
|
|
}
|