-
Notifications
You must be signed in to change notification settings - Fork 12
/
private.go
151 lines (129 loc) · 3.62 KB
/
private.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
142
143
144
145
146
147
148
149
150
151
package lexer
import (
"bufio"
"io"
"unicode/utf8"
)
import (
"github.com/iNamik/go_container/queue"
"github.com/iNamik/go_pkg/bufio/bleeder"
)
const defaultBufSize = 1024 //4096
// lexer holds the state of the scanner.
type lexer struct {
ioReader io.Reader // the original reader passed into New()
reader *bufio.Reader // reader buffer
autoExpand bool // should we auto-expand buffered reader?
bufLen int // reader buffer len
line int // current line in steram
column int // current column within current line
peekBytes []byte // cache of bufio.Reader.Peek()
peekPos int
tokenLen int
runes queue.Interface // rune buffer
pos int
sequence int // Incremented after each emit/ignore - used to validate markers
state StateFn // the next lexing function to enter
tokens chan *Token // channel of scanned tokens.
eofToken *Token
eof bool
}
// newLexer
func newLexer(startState StateFn, reader io.Reader, readerBufLen int, autoExpand bool, channelCap int) Lexer {
r := bufio.NewReaderSize(reader, readerBufLen)
l := &lexer{
ioReader: reader,
reader: r,
bufLen: readerBufLen,
autoExpand: autoExpand,
runes: queue.New(4), // 4 is just a nice number that seems appropriate
state: startState,
tokens: make(chan *Token, channelCap),
line: 1,
column: 0,
eofToken: nil,
eof: false,
}
l.updatePeekBytes()
return l
}
// ensureRuneLen
func (l *lexer) ensureRuneLen(n int) bool {
for l.runes.Len() < n {
// If auto-expand is enabled and
// If our peek buffer is full (suggesting we are likely not at eof) and
// If we don't have enough bytes left to safely decode a rune,
if l.autoExpand == true && len(l.peekBytes) == l.bufLen && (len(l.peekBytes)-l.peekPos) < utf8.UTFMax {
l.bufLen *= 2
bl := bleeder.New(l.reader, l.ioReader)
l.reader = bufio.NewReaderSize(bl, l.bufLen)
l.updatePeekBytes()
}
rune, size := utf8.DecodeRune(l.peekBytes[l.peekPos:])
if utf8.RuneError == rune {
return false
}
l.runes.Add(rune)
l.peekPos += size
}
return l.runes.Len() >= n
}
// emit
func (l *lexer) emit(t TokenType, emitBytes bool) {
if T_EOF == t {
if l.eof {
panic("illegal state: EmitEOF() already called")
}
l.consume(false)
l.eofToken = &Token{typ: T_EOF, bytes: nil, line: l.line, column: l.column + 1}
l.eof = true
l.tokens <- l.eofToken
} else {
line := l.line
column := l.column - (l.tokenLen - 1)
b := l.consume(emitBytes)
l.tokens <- &Token{typ: t, bytes: b, line: line, column: column}
}
}
// emitErr
func (l *lexer) emitErr(err string) {
line := l.line
column := l.column - (l.tokenLen - 1)
l.consume(false)
l.tokens <- &Token{typ: T_LEX_ERR, bytes: []byte(err), line: line, column: column}
}
// consume
func (l *lexer) consume(keepBytes bool) []byte {
var b []byte
if keepBytes {
b = make([]byte, l.tokenLen)
n, err := l.reader.Read(b)
if err != nil || n != l.tokenLen {
panic("Unexpected problem in bufio.Reader.Read(): " + err.Error())
}
} else {
// May be better to just grab string and ignore, or always emit bytes
for ; l.tokenLen > 0; l.tokenLen-- {
_, err := l.reader.ReadByte()
if err != nil {
panic("Unexpected problem in bufio.Reader.ReadByte(): " + err.Error())
}
}
b = nil
}
l.sequence++
l.pos = 0
l.tokenLen = 0
l.peekPos = 0
l.runes.Clear()
l.updatePeekBytes()
return b
}
// updatePeekBytes
func (l *lexer) updatePeekBytes() {
var err error
l.peekBytes, err = l.reader.Peek(l.bufLen)
if err != nil && err != bufio.ErrBufferFull && err != io.EOF {
panic(err)
}
}