// Package lex представляет собой достаточно простой лексер произвольных выражений. // Практически полностью аналогичен лексеру от Роба Пайка. package lex import ( "bufio" "strings" ) func Do(initState StateFunc, input *bufio.Reader) <-chan Token { t := &Lexer{ input: input, ch: make(chan Token), buf: []rune{}, } go func() { defer close(t.ch) for state := initState; state != nil; { state = state(t) } }() return t.ch } type Lexer struct { input *bufio.Reader width int ch chan Token buf []rune pos int } func (l *Lexer) Next() (ch rune, err error) { ch, l.width, err = l.input.ReadRune() if err != nil { return 0, err } l.buf = append(l.buf, ch) return ch, nil } func (l *Lexer) Peek() (rune, error) { ch, err := l.Next() if err != nil { return 0, err } return ch, l.input.UnreadRune() } func (l *Lexer) Back() error { if len(l.buf) == 0 { return nil } l.pos -= l.width l.buf = l.buf[:len(l.buf)-1] return l.input.UnreadRune() } func (l *Lexer) Skip() { l.buf = l.buf[:] } func (l *Lexer) EmitToken(typ Typ) { l.ch <- Token{ Typ: typ, Value: string(l.buf), Pos: l.pos, } l.buf = l.buf[:] } func (l *Lexer) EmitError(err error) { l.ch <- Token{ Error: err, Value: string(l.buf), Pos: l.pos, } l.buf = l.buf[:] } func (l *Lexer) Accept(valid string) bool { ch, err := l.Next() if err != nil { l.Back() return false } if strings.ContainsRune(valid, ch) { return true } l.Back() return false } func (l *Lexer) AcceptRun(valid string) bool { ok := false for l.Accept(valid) { ok = true } return ok } func (l *Lexer) AcceptNotRun(invalid string, greedy bool) bool { ok := false for { ch, err := l.Next() if err != nil { return ok } if strings.ContainsRune(invalid, ch) { if !greedy { l.Back() } return ok } ok = true } } func (l *Lexer) AcceptAlph() bool { ch, err := l.Next() if err != nil { l.Back() return false } if 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' { return true } l.Back() return false } func (l *Lexer) AcceptDigit() bool { ch, err := l.Next() if err != nil { l.Back() return false } if '0' <= ch && ch <= '9' { return true } l.Back() return false } func (l *Lexer) AcceptSpace() bool { return l.Accept(" \r\n\t") } func (l *Lexer) Empty() bool { return len(l.buf) == 0 }