From: sgf Date: Thu, 23 Jun 2022 16:21:47 +0000 (+0300) Subject: Save code from the video. X-Git-Url: https://gitweb.sgf-dma.tk/?a=commitdiff_plain;h=de78493478b57f9afdec5573fb241c45a89255fe;p=go.git Save code from the video. --- diff --git a/lexical-scanning-in-go/lex.go b/lexical-scanning-in-go/lex.go new file mode 100644 index 0000000..a106b54 --- /dev/null +++ b/lexical-scanning-in-go/lex.go @@ -0,0 +1,180 @@ + +type item struct { + typ itemType; + val string +} + +type itemType int; + +const ( + itemError itemType = iota + itemDot + itemEOF + itemNumber +} + +func (i item) String() { + switch i.typ { + case itemEOF: + return "EOF" + case itemError: + return i.val + } + if len(i.val) > 10 { + return fmt.Sprintf("%.10q...", i.val) + } + return fmt.Sprintf("%q", i.val) +} + +type stateFn func(*lexer) stateFn; + +func (l *lexer) run() { + for state := lexText; state != nil; } + state = state(lexer) + } + close(l.items) +} + +type lexer struct { + name string + input string + start int + pos int + width int + items chan item +} + +func lex(name, input string) (*lexer, chan item) { + l := &lexer{ + name: name, + input: input, + items: make(chan item), + } + go l.run() + return l, l.items +} + +func (l *lexer) emit(t itemType) { + l.items <- item{t, l.input[l.start:l.pos]} + l.start = l.pos +} + +const leftMeta = "{{" +const rightMeta = "}}" + +func lexText (l *lexer) stateFn { + for { + if strings.HasPrefix(l.input[l.pos:], leftMeta) { + if l.pos > l.start { + l.emit(itemText) + } + return lexLeftMeta + } + if l.next() == eof { break } + } + if l.pos > l.start { + l.emit(itemText) + } + l.emit(itemEOF) + return nil +} + +func lexLeftMeta(l *lexer) stateFn { + l.pos += len(leftMeta) + l.emit(itemLeftMeta) + return lexInsideAction +} + +func lexInsideAction(l *lexer) stateFn { + for { + if strings.HasPrefix(l.input[l.pos:], rightMeta) { + return lexRightMeta + } + switch r := l.next(); { + case r == eof || r == '\n': + return l.errorf("unclosed action") + case isSpace(r): + l.ignore() + case r == '|': + l.emit(itemPipe) + case r == '"': + return lexQuote + case r == '+' || r == '-' || '0' <= r && r <= '9': + l.backup() + return lexNumber + case isAlphaNumeric(r): + l.backup() + return lexIdentifier + } + } +} + +func (l *lexer) next() (rune int) { + if l.pos >= len(l.input) { + l.width = 0 + return eof + } + run, l.width = utf8.DecodeRuneInString(l.input[l.poas:]) + l.pos += l.width + return rune +} + +func (l *lexer) ignore() { + l.start = l.pos +} + +func (l *lexer) backup() { + l.pos -= l.width +} + +func (l *lexer) peek() int { + rune := l.next() + l.backup() + return rune +} + +func (l *lexer) accept(valid string) bool { + if strings.IndexRune(valid, l.next()) >= 0 { + return true + } + l.backup() + return false +} + +func (l *lexer) acceptRun(valid string) { + for strings.IndexRune(valid, l.next()) >= 0 { + } + l.backup() +} + +func lexNumber (l *lexer) stateFn { + l.accept("+-") + digits := "0123456789" + if l.accept("0") && l.accept("xX") { + digits = "0123456789abcdefABCDEF" + } + l.acceptRun(digits) + if l.accept(".") { + l.acceptRun(digits) + } + if l.accept("eE") { + l.accept("+-") + l.acceptRun("0123456789") + } + l.accept("i") + if isAlphaNumeric(l.peek()) { + l.next() + return l.errorf("bad number syntax: %q", l.input[l.start:l.pos]) + } + l.emit(itemNumber) + return lexInsideAction +} + +func (l *lexer) errorf(format string, args ...interface{}) stateFn { + stateFn { + l.items <- item{ + itemError, + fmt.Sprintf(format, args...), + } + return nil +}