-
Notifications
You must be signed in to change notification settings - Fork 17
/
annotation.go
119 lines (114 loc) · 2.76 KB
/
annotation.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
package migu
import (
"bufio"
"bytes"
"fmt"
"go/ast"
"strconv"
"strings"
)
type annotation struct {
Table string
Option string
}
func parseAnnotation(g *ast.CommentGroup) (*annotation, error) {
for _, c := range g.List {
if !strings.HasPrefix(c.Text, commentPrefix) {
continue
}
s := strings.TrimSpace(c.Text[len(commentPrefix):])
if !strings.HasPrefix(s, marker) {
continue
}
if len(s) == len(marker) {
return &annotation{}, nil
}
if !isSpace(s[len(marker)]) {
continue
}
var a annotation
scanner := bufio.NewScanner(strings.NewReader(s[len(marker):]))
scanner.Split(splitAnnotationTags)
for scanner.Scan() {
ss := strings.SplitN(scanner.Text(), string(annotationSeparator), 2)
switch k, v := ss[0], ss[1]; k {
case "table":
s, err := parseString(v)
if err != nil {
return nil, fmt.Errorf("migu: BUG: %v", err)
}
a.Table = s
case "option":
s, err := parseString(v)
if err != nil {
return nil, fmt.Errorf("migu: BUG: %v", err)
}
a.Option = s
default:
return nil, fmt.Errorf("migu: unsupported annotation: %v", k)
}
}
if err := scanner.Err(); err != nil {
return nil, fmt.Errorf("%v: %v", err, c.Text)
}
return &a, nil
}
return nil, nil
}
func splitAnnotationTags(data []byte, atEOF bool) (advance int, token []byte, err error) {
if atEOF {
return 0, nil, nil
}
for ; advance < len(data); advance++ {
if !isSpace(data[advance]) {
break
}
}
i := bytes.IndexByte(data[advance:], annotationSeparator)
if i < 1 {
return 0, nil, fmt.Errorf("migu: invalid annotation")
}
advance += i + 1
if advance >= len(data) {
return 0, nil, fmt.Errorf("migu: invalid annotation")
}
switch quote := data[advance]; quote {
case '"':
for advance++; advance < len(data); advance++ {
i := bytes.IndexByte(data[advance:], quote)
if i < 0 {
break
}
advance += i
if data[advance-1] != '\\' {
return advance + 1, bytes.TrimSpace(data[:advance+1]), nil
}
}
return 0, nil, fmt.Errorf("migu: invalid annotation: string not terminated")
case '`':
for advance++; advance < len(data); advance++ {
i := bytes.IndexByte(data[advance:], quote)
if i < 0 {
break
}
advance += i
return advance + 1, bytes.TrimSpace(data[:advance+1]), nil
}
return 0, nil, fmt.Errorf("migu: invalid annotation: string not terminated")
}
if isSpace(data[advance]) {
return 0, nil, fmt.Errorf("migu: invalid annotation: value not given")
}
for advance++; advance < len(data); advance++ {
if isSpace(data[advance]) {
return advance, bytes.TrimSpace(data[:advance]), nil
}
}
return advance, bytes.TrimSpace(data[:advance]), nil
}
func parseString(s string) (string, error) {
if b := s[0]; b == '"' || b == '`' {
return strconv.Unquote(s)
}
return s, nil
}