-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathprotodata.go
198 lines (154 loc) · 4.68 KB
/
protodata.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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
package protostub
import (
"io"
"strings"
"github.com/emicklei/proto"
)
// ProtoData is the main visitor, which passes off to the other ones.
// I try to have a visitor per "major" type - message, service, enum, etc.
// This base Visitor handles the basic stuff.
type ProtoData struct {
Types []ProtoType
// why not set? please?
imports map[string]bool
// depth is incremented for each class definition
r io.Reader
depth int
}
// New creates a new protodata object. It takes a reader to the proto file
func New(r io.Reader) *ProtoData {
return &ProtoData{
Types: make([]ProtoType, 0),
depth: 0,
imports: make(map[string]bool),
r: r,
}
}
// Parse will parse the proto file, and dispatch to all the visitors. Error is
// returned on failure
func (v *ProtoData) Parse() error {
p := proto.NewParser(v.r)
pr, err := p.Parse()
if err != nil {
return err
}
for _, i := range pr.Elements {
i.Accept(v)
}
return nil
}
// TODO: make sure everything is here
var typeMap = map[string]string{
"int32": "int",
"int64": "int",
"double": "float",
"uint32": "int",
"uint64": "int",
"sint32": "int",
"sint64": "int",
"fixed32": "int",
"fixed64": "int",
"sfixed32": "int",
"sfixed64": "int",
"bytes": "str",
}
// TranslateType takes in a protobuf type and translates it to a Python primitive
// type. If there is no translation needed, the input is returned unaltered.
func TranslateType(t string) string {
if val, ok := typeMap[t]; ok {
return val
}
split := strings.Split(t, ".")
return split[len(split)-1]
}
// VisitMessage will create a MessageVisitor, and dispatch it. The message type
// is included in protodata.
func (v *ProtoData) VisitMessage(m *proto.Message) {
if m.Comment == nil {
m.Comment = &proto.Comment{Lines: make([]string, 0)}
}
mv := NewMessageVisitor(m.Name, m.IsExtend, m.Comment)
for _, i := range m.Elements {
i.Accept(mv)
}
v.Types = append(v.Types, mv.message)
mv.message.Types = mv.Types
}
// VisitSyntax presently does nothing.
func (v *ProtoData) VisitSyntax(s *proto.Syntax) {
}
// VisitPackage presently does nothing.
func (v *ProtoData) VisitPackage(p *proto.Package) {
}
// VisitOption presently does nothing.
func (v *ProtoData) VisitOption(o *proto.Option) {
}
// VisitImport will try to translate a proto import to a python one. Currently it
// is a bit of a hack.
func (v *ProtoData) VisitImport(i *proto.Import) {
// a bit of a hack, yet perhaps it will work?
// then remove the specific file, so we just have the path of the package
split := strings.Split(i.Filename, "/")
// the path is all but the last
path := strings.Join(split[:len(split)-1], ".")
// because we can't figure out the class we are importing by the import
// path, import it all.
// if it already exists, don't bother continuing.
if _, ok := v.imports[path]; ok {
return
}
v.imports[path] = true
}
// VisitNormalField does nothing here, and is implemented in the message visitor.
func (v *ProtoData) VisitNormalField(n *proto.NormalField) {
}
// VisitEnumField will panic when called here, as enum fields should be inside
// enums.
func (v *ProtoData) VisitEnumField(e *proto.EnumField) {
panic("Cannot visit enum field")
}
// VisitEnum will create a new Enum visitor and dispatch it.
func (v *ProtoData) VisitEnum(e *proto.Enum) {
ev := NewEnumVisitor()
e.Accept(ev)
v.Types = append(v.Types, &ev.Enum)
}
// VisitComment currently does nothing, comments are only handled when attached
// to messages and their fields.
func (v *ProtoData) VisitComment(c *proto.Comment) {
}
// VisitOneof will panic when called from here.
func (v *ProtoData) VisitOneof(o *proto.Oneof) {
panic("Cannot visit oneof")
}
// VisitOneofField will panic when called from here.
func (v *ProtoData) VisitOneofField(o *proto.OneOfField) {
panic("Cannot visit oneof field")
}
// VisitReserved is currently not implemented.
func (v *ProtoData) VisitReserved(r *proto.Reserved) {
}
// VisitService will create a new service visitor, and dispatch it.
func (v *ProtoData) VisitService(r *proto.Service) {
if r.Comment == nil {
r.Comment = &proto.Comment{Lines: make([]string, 0)}
}
sv := NewServiceVisitor(r.Name, r.Comment)
for _, i := range r.Elements {
i.Accept(sv)
}
v.Types = append(v.Types, sv.service)
sv.service.Types = sv.Types
}
// VisitRPC will currently do nothing, as RPC should be inside a service.
func (v *ProtoData) VisitRPC(r *proto.RPC) {
}
// VisitMapField is currently not implemented
func (v *ProtoData) VisitMapField(m *proto.MapField) {
}
// VisitGroup is currently not implemented
func (v *ProtoData) VisitGroup(g *proto.Group) {
}
// VisitExtensions is currently not implemented
func (v *ProtoData) VisitExtensions(e *proto.Extensions) {
}