-
Notifications
You must be signed in to change notification settings - Fork 2
/
scanner.go
104 lines (94 loc) · 2.04 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
package main
import (
"bufio"
"bytes"
"errors"
"fmt"
"io"
"strings"
)
type scanner struct {
buf bytes.Buffer
comment bool
e error
line int
q *query
quote byte
reader *bufio.Reader
stringLiteral bool
}
func newScanner(r io.Reader) *scanner {
return &scanner{reader: bufio.NewReader(r)}
}
func (s *scanner) scan() bool {
if s.e != nil {
return false
}
line := s.line
for {
str, err := s.reader.ReadString('\n')
if err == io.EOF && s.buf.Len() != 0 {
s.e = errors.New("unexpected EOF")
return false
}
if err != nil {
s.e = err
return false
}
s.line++
if !s.comment && s.quote == 0 && (strings.HasPrefix(str, "--") || str == "\n") {
continue
}
var i int
for {
j := strings.IndexAny(str[i:], "/*`\"'\\;")
if j == -1 {
s.buf.WriteString(str)
break
} else if !s.comment && s.quote == 0 && strings.HasPrefix(str[i+j:], "/*!") {
s.comment = true
i += j + 3
} else if s.comment && s.quote == 0 && strings.HasPrefix(str[i+j:], "*/") {
s.comment = false
i += j + 2
} else if s.quote == 0 && strings.IndexByte("`\"'", str[i+j]) != -1 {
s.quote = str[i+j]
s.stringLiteral = str[i+j] == '\''
i += j + 1
} else if s.quote != 0 && str[i+j] == s.quote {
if !s.stringLiteral && len(str) > i+j+1 && str[i+j+1] == s.quote {
i += j + 2
} else {
s.quote = 0
s.stringLiteral = false
i += j + 1
}
} else if s.stringLiteral && str[i+j] == '\\' {
i += j + 2
} else if !s.comment && s.quote == 0 && str[i+j] == ';' {
if len(str) != i+j+2 || str[i+j+1] != '\n' {
s.e = fmt.Errorf("newline is expected after ';'. line=%d", s.line)
return false
}
s.buf.WriteString(str[:i+j+1])
s.q = &query{line: line + 1, s: s.buf.String()}
s.buf.Reset()
return true
} else {
i += j + 1
}
}
}
}
func (s *scanner) err() error {
if s.e == io.EOF {
return nil
}
return s.e
}
func (s *scanner) query() *query {
if s.e != nil {
return nil
}
return s.q
}