| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221 |
- package pattern
- import (
- "fmt"
- "go/token"
- "unicode"
- "unicode/utf8"
- )
- type lexer struct {
- f *token.File
- input string
- start int
- pos int
- width int
- items chan item
- }
- type itemType int
- const eof = -1
- const (
- itemError itemType = iota
- itemLeftParen
- itemRightParen
- itemLeftBracket
- itemRightBracket
- itemTypeName
- itemVariable
- itemAt
- itemColon
- itemBlank
- itemString
- itemEOF
- )
- func (typ itemType) String() string {
- switch typ {
- case itemError:
- return "ERROR"
- case itemLeftParen:
- return "("
- case itemRightParen:
- return ")"
- case itemLeftBracket:
- return "["
- case itemRightBracket:
- return "]"
- case itemTypeName:
- return "TYPE"
- case itemVariable:
- return "VAR"
- case itemAt:
- return "@"
- case itemColon:
- return ":"
- case itemBlank:
- return "_"
- case itemString:
- return "STRING"
- case itemEOF:
- return "EOF"
- default:
- return fmt.Sprintf("itemType(%d)", typ)
- }
- }
- type item struct {
- typ itemType
- val string
- pos int
- }
- type stateFn func(*lexer) stateFn
- func (l *lexer) run() {
- for state := lexStart; state != nil; {
- state = state(l)
- }
- close(l.items)
- }
- func (l *lexer) emitValue(t itemType, value string) {
- l.items <- item{t, value, l.start}
- l.start = l.pos
- }
- func (l *lexer) emit(t itemType) {
- l.items <- item{t, l.input[l.start:l.pos], l.start}
- l.start = l.pos
- }
- func lexStart(l *lexer) stateFn {
- switch r := l.next(); {
- case r == eof:
- l.emit(itemEOF)
- return nil
- case unicode.IsSpace(r):
- l.ignore()
- case r == '(':
- l.emit(itemLeftParen)
- case r == ')':
- l.emit(itemRightParen)
- case r == '[':
- l.emit(itemLeftBracket)
- case r == ']':
- l.emit(itemRightBracket)
- case r == '@':
- l.emit(itemAt)
- case r == ':':
- l.emit(itemColon)
- case r == '_':
- l.emit(itemBlank)
- case r == '"':
- l.backup()
- return lexString
- case unicode.IsUpper(r):
- l.backup()
- return lexType
- case unicode.IsLower(r):
- l.backup()
- return lexVariable
- default:
- return l.errorf("unexpected character %c", r)
- }
- return lexStart
- }
- func (l *lexer) next() (r rune) {
- if l.pos >= len(l.input) {
- l.width = 0
- return eof
- }
- r, l.width = utf8.DecodeRuneInString(l.input[l.pos:])
- if r == '\n' {
- l.f.AddLine(l.pos)
- }
- l.pos += l.width
- return r
- }
- func (l *lexer) ignore() {
- l.start = l.pos
- }
- func (l *lexer) backup() {
- l.pos -= l.width
- }
- func (l *lexer) errorf(format string, args ...interface{}) stateFn {
- // TODO(dh): emit position information in errors
- l.items <- item{
- itemError,
- fmt.Sprintf(format, args...),
- l.start,
- }
- return nil
- }
- func isAlphaNumeric(r rune) bool {
- return r >= '0' && r <= '9' ||
- r >= 'a' && r <= 'z' ||
- r >= 'A' && r <= 'Z'
- }
- func lexString(l *lexer) stateFn {
- l.next() // skip quote
- escape := false
- var runes []rune
- for {
- switch r := l.next(); r {
- case eof:
- return l.errorf("unterminated string")
- case '"':
- if !escape {
- l.emitValue(itemString, string(runes))
- return lexStart
- } else {
- runes = append(runes, '"')
- escape = false
- }
- case '\\':
- if escape {
- runes = append(runes, '\\')
- escape = false
- } else {
- escape = true
- }
- default:
- runes = append(runes, r)
- }
- }
- }
- func lexType(l *lexer) stateFn {
- l.next()
- for {
- if !isAlphaNumeric(l.next()) {
- l.backup()
- l.emit(itemTypeName)
- return lexStart
- }
- }
- }
- func lexVariable(l *lexer) stateFn {
- l.next()
- for {
- if !isAlphaNumeric(l.next()) {
- l.backup()
- l.emit(itemVariable)
- return lexStart
- }
- }
- }
|