-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathscanner.go
127 lines (102 loc) · 2.03 KB
/
scanner.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
package toml
import (
"unicode/utf8"
)
const (
EOF = 0xF8
RuneError = 0xFFFD
)
type Scanner interface {
Fetch(skip bool) string
Rune() rune
Next() rune
Eof() bool
LastLine() (int, int, string)
}
type scanner struct {
buf []byte
pos int
offset int // for Get()
size int
line int
first int // offset to first char of line
col int
r rune
}
// first scanner
func NewScanner(source []byte) Scanner {
p := scanner{}
p.buf = source
r := p.Next()
if r == BOM {
p.Fetch(true)
p.Next()
}
p.line = 1
p.first = 0
if r == RuneError {
p.buf = nil
}
return &p
}
func (p *scanner) Eof() bool {
return p.r == EOF
}
func (p *scanner) Rune() rune {
return p.r
}
// Fetch returns last char, at string(buffer[:Scan.offset - sizeOfLastChar]).
// Fetch 返回未被取出的字符串. skip 表示是否包含 pos 处的字符
func (p *scanner) Fetch(last bool) (str string) {
e := p.pos
if !last && p.r != EOF {
e -= p.size
}
str = string(p.buf[p.offset:e])
p.offset = e
return
}
func (p *scanner) LastLine() (int, int, string) {
s := p.first
e := p.pos - p.size
if p.col == 1 && s > 0 {
s--
}
r := p.buf[s]
for s > 0 && r != '\n' && r != '\r' && r != 0x1E {
s--
r = p.buf[s]
}
r = p.buf[e]
for e < len(p.buf) && r != '\n' && r != '\r' && r != 0x1E {
r = p.buf[e]
e++
}
return p.line, p.col, string(p.buf[s:e])
}
// Next returns read char frome the buffer.
// b is byte(char) when size of char equal 1, otherwise it is const MultiBytes.
// r is rune value of char,If the encoding is invalid, it is RuneError.
// if end of buffer or encoding is invalid, char is error string, b equal const EOF, r equal const RuneError.
func (p *scanner) Next() rune {
if p.r == EOF {
return p.r
}
if p.pos >= len(p.buf) {
p.r = EOF
return p.r
}
r := p.r
p.r, p.size = utf8.DecodeRune(p.buf[p.pos:])
n := p.r
p.col++
if n == '\n' || n == '\r' || n == 0x1E {
if n == r || n != r && r != '\n' && r != '\r' {
p.col = 1
p.line++
p.first = p.pos
}
}
p.pos += p.size
return p.r
}