1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
|
// Package lex представляет собой достаточно простой лексер произвольных выражений.
// Практически полностью аналогичен лексеру от Роба Пайка.
package lex
import (
"strings"
"unicode/utf8"
)
func Do(initState StateFunc, input string) <-chan Token {
t := &Lexer{
pos: 0,
input: input,
start: 0,
ch: make(chan Token),
}
go func() {
defer close(t.ch)
for state := initState; state != nil; {
state = state(t)
}
}()
return t.ch
}
type Lexer struct {
pos int
start int
input string
width int
ch chan Token
}
func (l *Lexer) Next() (ch rune) {
if l.pos >= len(l.input) {
l.width = 0
return 0
}
ch, l.width = utf8.DecodeRuneInString(l.input[l.pos:])
l.pos += l.width
return ch
}
func (l *Lexer) Peek() rune {
ch := l.Next()
l.Back()
return ch
}
func (l *Lexer) Back() {
l.pos -= l.width
}
func (l *Lexer) Skip() {
l.start = l.pos
}
func (l *Lexer) EmitToken(typ Typ) {
value := ""
if l.pos > l.start {
value = l.input[l.start:l.pos]
}
l.ch <- Token{
Typ: typ,
Value: value,
Pos: l.pos,
}
l.start = l.pos
}
func (l *Lexer) EmitError(err error) {
value := ""
if l.pos > l.start {
value = l.input[l.start:l.pos]
}
l.ch <- Token{
Value: value,
Pos: l.pos,
Error: err,
}
}
func (l *Lexer) Accept(valid string) bool {
if strings.ContainsRune(valid, l.Next()) {
return true
}
l.Back()
return false
}
func (l *Lexer) AcceptRun(valid string) {
for strings.ContainsRune(valid, l.Next()) {
}
l.Back()
}
func (l *Lexer) AcceptNotRun(invalid string, greedy bool) {
for ch := l.Next(); !strings.ContainsRune(invalid, ch) && ch != 0; ch = l.Next() {
}
if !greedy {
l.Back()
}
}
|