-
Notifications
You must be signed in to change notification settings - Fork 0
/
lexer_utils.go
95 lines (78 loc) · 2.27 KB
/
lexer_utils.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
package dibbi
import (
"strings"
)
// Finds string Tokens delimited by delimiter
func lexCharacterDelimited(source string, initialCursor Cursor, delimiter byte) (*token, Cursor, bool) {
finalCursor := initialCursor
if len(source[finalCursor.Pointer:]) == 0 {
return nil, initialCursor, false
}
// Source must start with delimiter
if source[finalCursor.Pointer] != delimiter {
return nil, initialCursor, false
}
finalCursor.location.column++
finalCursor.Pointer++
var value []byte
for ; finalCursor.Pointer < uint(len(source)); finalCursor.Pointer++ {
char := source[finalCursor.Pointer]
if char == delimiter {
if finalCursor.Pointer+1 >= uint(len(source)) || // if Cursor is at end of source
source[finalCursor.Pointer+1] != delimiter { // or next char is not a delimiter
// the full value was read
finalCursor.Pointer++
finalCursor.location.column++
return &token{
value: string(value),
location: initialCursor.location,
tokenType: StringType,
}, finalCursor, true
} else {
// next char is a delimiter. In SQL a double delimiter is an escape
value = append(value, delimiter)
finalCursor.Pointer++
finalCursor.location.column++
}
} else {
value = append(value, char)
finalCursor.location.column++
}
}
return nil, initialCursor, false
}
// given a source, Cursor and an array of possible matches, returns the longest match found
func findLongestStringMatch(source string, initialCursor Cursor, options []string) string {
var value []byte
var skipList []int
var match string
finalCursor := initialCursor
for finalCursor.Pointer < uint(len(source)) {
value = append(value, strings.ToLower(string(source[finalCursor.Pointer]))...)
finalCursor.Pointer++
match:
for i, option := range options {
for _, skip := range skipList {
if i == skip {
continue match
}
}
if option == string(value) {
skipList = append(skipList, i)
if len(option) > len(match) {
match = option
}
continue
}
sharesPrefix := string(value) == option[:finalCursor.Pointer-initialCursor.Pointer]
tooLong := len(value) > len(option)
if tooLong || !sharesPrefix {
skipList = append(skipList, i)
}
}
if len(skipList) == len(options) {
break
}
}
return match
}