Save code from the video.
authorsgf <sgf.dma@gmail.com>
Thu, 23 Jun 2022 16:21:47 +0000 (19:21 +0300)
committersgf <sgf.dma@gmail.com>
Thu, 23 Jun 2022 16:21:47 +0000 (19:21 +0300)
lexical-scanning-in-go/lex.go [new file with mode: 0644]

diff --git a/lexical-scanning-in-go/lex.go b/lexical-scanning-in-go/lex.go
new file mode 100644 (file)
index 0000000..a106b54
--- /dev/null
@@ -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
+}