package parser import ( "bufio" "bytes" "io" ) type Token struct { kind int val string } type scanner struct { r *bufio.Reader } var eof rune = rune(0) const ( Number int = iota + 1 Text Opperator Whitespace Comment Newline Separator End Illegal ) // - ~ + - ~ + // // Receivers // // - ~ + - ~ + // 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() Token { for { char := s.read() if isWhitespace(char) { s.unread() s.scanWhitespace() } else if isLetter(char) { s.unread() return s.scanText() } else if isNumber(char) { s.unread() return s.scanNumber() } else if char == '#' { s.unread() s.scanComment() } else if isOpperator(char) { return Token{Opperator, string(char)} } else if char == '\n' { return Token{Newline,"New Line"} } else if char == ':' { return Token{Separator,":"} } else if char == eof { return Token{End, "eof"} } else { return Token{Illegal, string(char)} } } } 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 { s.unread() break } else if !isNumber(ch) { s.unread() break } else { _, _ = buf.WriteRune(ch) } } return Token{Number, buf.String()} } 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) && !isNumber(ch) { s.unread() break } else { _, _ = buf.WriteRune(ch) } } return Token{Text, buf.String()} } func (s *scanner) scanComment() Token { var buf bytes.Buffer buf.WriteRune(s.read()) for { if ch := s.read(); ch == eof || ch == '\n' { s.unread() break } else { _, _ = buf.WriteRune(ch) } } return Token{Comment, buf.String()} } // - ~ + - ~ + // // Functions // // - ~ + - ~ + // func isWhitespace(ch rune) bool { return ch == ' ' || ch == '\t' || ch == '\r' } func isLetter(ch rune) bool { return ch >= 'A' && ch <= 'Z' || ch >= 'a' && ch <= 'z' } func isNumber(ch rune) bool { return ch >= '0' && ch <= '9' } func isOpperator(ch rune) bool { return ch == '=' || ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '^' || ch == '%' } func NewScanner(r io.Reader) *scanner { return &scanner{r: bufio.NewReader(r)} }