package circuit import ( "bufio" "bytes" "io" ) // OperatorSymbol is ... type OperatorSymbol int // Token is ... type Token int // Tokens const ( ILLEGAL Token = iota WS EOF IDENT // val VAR // var CONST // const value EQ // = PLUS // + MINUS // - MULTIPLY // * DIVIDE // / EXP // ^ OUT ) var eof = rune(0) func isWhitespace(ch rune) bool { return ch == ' ' || ch == '\t' || ch == '\n' } func isLetter(ch rune) bool { return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') } func isDigit(ch rune) bool { return (ch >= '0' && ch <= '9') } // Scanner holds the bufio.Reader type Scanner struct { r *bufio.Reader } // NewScanner creates a new Scanner with the given io.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() } // Scan returns the Token and literal string of the current value func (s *Scanner) scan() (tok Token, lit string) { ch := s.read() if isWhitespace(ch) { // space s.unread() return s.scanWhitespace() } else if isLetter(ch) { // letter s.unread() return s.scanIndent() } else if isDigit(ch) { s.unread() return s.scanIndent() } switch ch { case eof: return EOF, "" case '=': return EQ, "=" case '+': return PLUS, "+" case '-': return MINUS, "-" case '*': return MULTIPLY, "*" case '/': return DIVIDE, "/" case '^': return EXP, "^" } return ILLEGAL, string(ch) } func (s *Scanner) scanWhitespace() (token Token, lit 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) scanIndent() (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) { s.unread() break } else { _, _ = buf.WriteRune(ch) } } switch buf.String() { case "var": return VAR, buf.String() } if len(buf.String()) == 1 { return Token(rune(buf.String()[0])), buf.String() } if buf.String() == "out" { return OUT, buf.String() } return IDENT, buf.String() }