-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlex.go
141 lines (125 loc) · 2.6 KB
/
lex.go
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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package mathxf
import (
"fmt"
"strings"
"unicode/utf8"
)
const eof = -1
// lexer holds the state of the scanner.
type lexer struct {
input string // the string being scanned
replaceKeywords map[string]string // todo replace keywords
lastTokenType tokenType // last Token type
tokens chan Token // channel of scanned tokens
start int
pos int
line int
col int
width int
}
func lex(input string) *lexer {
l := &lexer{
input: input,
line: 1,
col: 0,
tokens: make(chan Token),
}
return l
}
// run runs the state machine for the lexer.
func (l *lexer) run() {
go func() {
state := baseStateFn
for state != nil {
state = state(l)
}
l.emit(TokenEOF)
close(l.tokens)
}()
}
func (l *lexer) nextToken() Token {
item := <-l.tokens
return item
}
// next returns the next rune in the input.
func (l *lexer) next() rune {
if l.pos >= len(l.input) {
l.width = 0
return eof
}
r, w := utf8.DecodeRuneInString(l.input[l.pos:])
l.width = w
l.pos += l.width
l.col += l.width
return r
}
func (l *lexer) backup() {
l.pos -= l.width
l.col -= l.width
}
func (l *lexer) peek() rune {
r := l.next()
l.backup()
return r
}
// accept consumes the next rune if it'name from the valid set.
func (l *lexer) accept(valid string) bool {
if strings.IndexRune(valid, l.next()) >= 0 {
return true
}
l.backup()
return false
}
// acceptRun consumes a run of runes from the valid set.
func (l *lexer) acceptRun(valid string) {
for strings.IndexRune(valid, l.next()) >= 0 {
}
l.backup()
}
// ignore skips over the pending input before this point.
func (l *lexer) ignore() {
l.start = l.pos
//l.startLine = l.line
//l.startCol = l.col
}
func (l *lexer) value() string {
return l.input[l.start:l.pos]
}
// emit passes an item back to the client.
func (l *lexer) emit(t tokenType) {
l.lastTokenType = t
l.tokens <- Token{t, l.line, l.col, l.value()}
l.start = l.pos
}
func (l *lexer) emitError(format string, args ...interface{}) stateFn {
l.tokens <- Token{TokenError, l.line, l.col, fmt.Sprintf(format, args...)}
return nil
}
func (l *lexer) scanNumber() (bool, bool) {
// Is it hex?
digits := "0123456789"
if l.accept("0") && l.accept("xX") {
digits = "0123456789abcdefABCDEF"
}
l.acceptRun(digits)
if l.accept(".") {
pos := l.pos
l.acceptRun(digits)
if pos == l.pos {
l.next()
return false, false
}
}
if l.accept("eE") {
l.accept("+-")
l.acceptRun("0123456789")
}
//Is it imaginary?
isComplex := l.accept("i")
//Next thing mustn't be alphanumeric.
if isAlphaNumeric(l.peek()) {
l.next()
return false, false
}
return true, isComplex
}