protobuf-generate 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 78cf665e01a339bcdf515cee143af388685ef34a
4
+ data.tar.gz: 268a8fa0d167f93f8c86ec0f4f9ad304bb4650d2
5
+ SHA512:
6
+ metadata.gz: 30773411e397dbb87a547de33809646493fd3350c83c2fca83c6a2f9e4ed7a64a792780aa626ee60c7febea25d16d973da8550c5a6b4034196f8c46cbdd7c56f
7
+ data.tar.gz: ca1613fe95fa0e2a3a02c2616f2b23c19089e7d71a8bc63caed895907a7d6f4d3ba67cdc2f159e411ffb1728e3ccb02eee4b08e154c3ea8087aee45d35855a7c
data/.gitignore ADDED
@@ -0,0 +1,13 @@
1
+ # Junk
2
+ ._*
3
+ .DS_Store
4
+ *.swp
5
+ *.swo
6
+ gems/
7
+ tmp/
8
+ *.gem
9
+ .bundle
10
+ *.lock
11
+
12
+ bin/*
13
+ !bin/protobuf-generate
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,10 @@
1
+ NOTE: Fuck restrictive 'open' source licenses honestly. You can pretty much do whatever the fuck you want with my code under MIT but the C templates [ch].erb are probably considered derivative works because I stole them originally from from the Apache 2 (http://www.apache.org/licenses/LICENSE-2.0) licensed https://code.google.com/p/protobuf-embedded-c
2
+
3
+ Copyright (C) 2013 Shane Hanna
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
10
+
data/README.md ADDED
@@ -0,0 +1,56 @@
1
+ # protobuf-generate
2
+
3
+ [source](https://bitbucket.org/shanehanna/protobuf-generate)
4
+
5
+ ## Description
6
+
7
+ A multi-language concrete protobuf code generator in Ruby.
8
+
9
+ ## Synopsis
10
+
11
+ A simple PEG parser, AST and template based approach to code generation.
12
+
13
+ [protobuf-embedded-c](https://code.google.com/p/protobuf-embedded-c/) uses the same approach but requires a page of
14
+ rage inducing instructions to install obsolete Eclipse plugins and Java bullshit if you want to be able to develop
15
+ and customize any of the C it generates. Ruby and scripting languages in general are ideal for this sort of thing
16
+ so that's what I've done.
17
+
18
+ ## Install
19
+
20
+ ```
21
+ gem install protobuf-generate
22
+ ```
23
+
24
+ ## Usage
25
+
26
+ ```
27
+ protobuf-generate <language> <protofile>
28
+ ```
29
+
30
+ ## Languages
31
+
32
+ ### C - Embedded
33
+
34
+ C99+ suitable for embedded systems.
35
+
36
+ #### string and byte
37
+
38
+ A fixed size string and byte structure is generated using a required @size_max meta attribute to avoid dynamic
39
+ allocation. Strings sent from other protobuf implementations that are too long for the structure will be truncated and
40
+ null terminated to fit within the maximum size. Bytes will just be truncated.
41
+
42
+ ```
43
+ message Message {
44
+ required string name = 1; // @size_max = 32
45
+ }
46
+ ```
47
+
48
+ ```
49
+ typedef struct message_t {
50
+ struct {
51
+ uint8_t data[32];
52
+ site_t size;
53
+ } name;
54
+ } message_t;
55
+ ```
56
+
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env ruby
2
+ $: << File.join(File.dirname(__FILE__), '..', 'lib')
3
+ require 'protobuf-generate'
4
+
5
+ # Usage.
6
+ unless ARGV.size == 2
7
+ puts %q{
8
+ Generate native code from protobuf files.
9
+
10
+ usage: protobuf-generate <language> <proto>
11
+ language - Native language to generate.
12
+ proto - The protobuf file to generate from.
13
+ }
14
+ exit 0
15
+ end
16
+
17
+ unless generator = Protobuf::Generate::Language.find(ARGV[0])
18
+ puts 'ERROR: Unknown language "%s".' % ARGV[0]
19
+ exit -1
20
+ end
21
+
22
+ begin
23
+ proto = ARGV[1]
24
+ tree = Protobuf::Generate::Parser.new.parse(File.read(proto))
25
+ ast = Protobuf::Generate::Transform.new.apply(tree)
26
+ gen = generator.new(ast)
27
+
28
+ # TODO: Think about how best to have generator deal with multiple templates. e.g. *.c and *.h
29
+ gen.templates.each do |template|
30
+ # TODO: Each language should take care of file naming conventions as well.
31
+ postfix = File.basename(template).gsub(/\.erb$/, '') # c.erb, h.erb, demo.c.erb becomes .c, .h, demo.c
32
+ package = ast.find{|e| e.kind_of?(Protobuf::Generate::Ast::Package)}
33
+ package = package ? package.name : File.basename(proto).gsub(/\.proto$/)
34
+ package = package.gsub('.', '_').gsub(/([^A-Z_])([A-Z]+)/, '\1_\2').gsub(/_+/, '_').downcase
35
+ filename = File.join(File.dirname(proto), [package, postfix].join('.'))
36
+
37
+ File.open(filename, File::CREAT | File::TRUNC | File::WRONLY) do |fh|
38
+ fh.puts gen.generate(template, filename)
39
+ end
40
+ end
41
+ rescue Parslet::ParseFailed => error
42
+ puts error.cause.ascii_tree
43
+ end
44
+
@@ -0,0 +1,502 @@
1
+ #include "<%= filename.sub(/\.c$/, '.h') %>" <%# Hack job. %>
2
+
3
+ #include <stdbool.h>
4
+ #include <stdint.h>
5
+ #include <string.h>
6
+
7
+ static int write_raw_byte(uint8_t value, uint8_t *buffer, int offset) {
8
+ *(buffer + offset) = value;
9
+ return ++offset;
10
+ }
11
+
12
+ static int write_raw_little_endian32(uint32_t value, uint8_t *buffer, int offset) {
13
+ offset = write_raw_byte((uint8_t)((value ) & 0xFF), buffer, offset);
14
+ offset = write_raw_byte((uint8_t)((value >> 8) & 0xFF), buffer, offset);
15
+ offset = write_raw_byte((uint8_t)((value >> 16) & 0xFF), buffer, offset);
16
+ offset = write_raw_byte((uint8_t)((value >> 24) & 0xFF), buffer, offset);
17
+ return offset;
18
+ }
19
+
20
+ static int write_raw_little_endian64(uint64_t value, uint8_t *buffer, int offset) {
21
+ offset = write_raw_byte((uint8_t)((value ) & 0xFF), buffer, offset);
22
+ offset = write_raw_byte((uint8_t)((value >> 8) & 0xFF), buffer, offset);
23
+ offset = write_raw_byte((uint8_t)((value >> 16) & 0xFF), buffer, offset);
24
+ offset = write_raw_byte((uint8_t)((value >> 24) & 0xFF), buffer, offset);
25
+ offset = write_raw_byte((uint8_t)((value >> 32) & 0xFF), buffer, offset);
26
+ offset = write_raw_byte((uint8_t)((value >> 40) & 0xFF), buffer, offset);
27
+ offset = write_raw_byte((uint8_t)((value >> 48) & 0xFF), buffer, offset);
28
+ offset = write_raw_byte((uint8_t)((value >> 56) & 0xFF), buffer, offset);
29
+ return offset;
30
+ }
31
+
32
+ static int write_raw_varint32(uint32_t value, uint8_t *buffer, int offset) {
33
+ while (1) {
34
+ if ((value & ~0x7F) == 0) {
35
+ offset = write_raw_byte((uint8_t)value, buffer, offset);
36
+ return offset;
37
+ } else {
38
+ offset = write_raw_byte((uint8_t)((value & 0x7F) | 0x80), buffer, offset);
39
+ value = value >> 7;
40
+ }
41
+ }
42
+ return offset;
43
+ }
44
+
45
+ static int write_raw_varint64(uint64_t value, uint8_t *buffer, int offset) {
46
+ while (1) {
47
+ if ((value & ~0x7FL) == 0) {
48
+ offset = write_raw_byte((uint8_t)value, buffer, offset);
49
+ return offset;
50
+ } else {
51
+ offset = write_raw_byte((uint8_t)((value & 0x7F) | 0x80), buffer, offset);
52
+ value = value >> 7;
53
+ }
54
+ }
55
+ return offset;
56
+ }
57
+
58
+ static int write_raw_bytes(uint8_t *bytes, int bytes_size, uint8_t *buffer, int offset) {
59
+ for (int i = 0; i < bytes_size; ++i)
60
+ offset = write_raw_byte(*(bytes + i), buffer, offset);
61
+ return offset;
62
+ }
63
+
64
+ static inline uint32_t encode_zig_zag32(int32_t n) {
65
+ return (n << 1) ^ (n >> 31);
66
+ }
67
+
68
+ static inline uint64_t encode_zig_zag64(int64_t n) {
69
+ return (n << 1) ^ (n >> 63);
70
+ }
71
+
72
+ static inline int32_t decode_zig_zag32(uint32_t n) {
73
+ return (n >> 1) ^ -(n & 1);
74
+ }
75
+
76
+ static inline int64_t decode_zig_zag64(uint64_t n) {
77
+ return (n >> 1) ^ -(n & 1);
78
+ }
79
+
80
+ static inline int read_raw_byte(uint8_t *tag, const uint8_t *buffer, int offset) {
81
+ *tag = *(buffer + offset);
82
+ return ++offset;
83
+ }
84
+
85
+ static int read_raw_little_endian32(uint32_t *tag, const uint8_t *buffer, int offset) {
86
+ offset = read_raw_byte((uint8_t *)tag, buffer, offset);
87
+ uint8_t b1 = (uint8_t)*tag;
88
+ offset = read_raw_byte((uint8_t *)tag, buffer, offset);
89
+ uint8_t b2 = (uint8_t)*tag;
90
+ offset = read_raw_byte((uint8_t *)tag, buffer, offset);
91
+ uint8_t b3 = (uint8_t)*tag;
92
+ offset = read_raw_byte((uint8_t *)tag, buffer, offset);
93
+ uint8_t b4 = (uint8_t)*tag;
94
+
95
+ *tag = (((uint32_t)b1 & 0xff) ) |
96
+ (((uint32_t)b2 & 0xff) << 8) |
97
+ (((uint32_t)b3 & 0xff) << 16) |
98
+ (((uint32_t)b4 & 0xff) << 24);
99
+ return offset;
100
+ }
101
+
102
+ static int read_raw_little_endian64(uint64_t *tag, const uint8_t *buffer, int offset) {
103
+ offset = read_raw_byte((uint8_t *)tag, buffer, offset);
104
+ uint8_t b1 = (uint8_t)*tag;
105
+ offset = read_raw_byte((uint8_t *)tag, buffer, offset);
106
+ uint8_t b2 = (uint8_t)*tag;
107
+ offset = read_raw_byte((uint8_t *)tag, buffer, offset);
108
+ uint8_t b3 = (uint8_t)*tag;
109
+ offset = read_raw_byte((uint8_t *)tag, buffer, offset);
110
+ uint8_t b4 = (uint8_t)*tag;
111
+ offset = read_raw_byte((uint8_t *)tag, buffer, offset);
112
+ uint8_t b5 = (uint8_t)*tag;
113
+ offset = read_raw_byte((uint8_t *)tag, buffer, offset);
114
+ uint8_t b6 = (uint8_t)*tag;
115
+ offset = read_raw_byte((uint8_t *)tag, buffer, offset);
116
+ uint8_t b7 = (uint8_t)*tag;
117
+ offset = read_raw_byte((uint8_t *)tag, buffer, offset);
118
+ uint8_t b8 = (uint8_t)*tag;
119
+
120
+ *tag = (((uint64_t)b1 & 0xff) ) |
121
+ (((uint64_t)b2 & 0xff) << 8) |
122
+ (((uint64_t)b3 & 0xff) << 16) |
123
+ (((uint64_t)b4 & 0xff) << 24) |
124
+ (((uint64_t)b5 & 0xff) << 32) |
125
+ (((uint64_t)b6 & 0xff) << 40) |
126
+ (((uint64_t)b7 & 0xff) << 48) |
127
+ (((uint64_t)b8 & 0xff) << 56);
128
+
129
+ return offset;
130
+ }
131
+
132
+ static int read_raw_varint32(uint32_t *tag, const uint8_t *buffer, int offset) {
133
+ uint8_t result;
134
+
135
+ offset = read_raw_byte(&result, buffer, offset);
136
+ if (result >= 0) {
137
+ *tag = result;
138
+ return offset;
139
+ }
140
+ *tag = result & 0x7f;
141
+ offset = read_raw_byte(&result, buffer, offset);
142
+ if (result >= 0) {
143
+ *tag |= result << 7;
144
+ } else {
145
+ *tag |= (result & 0x7f) << 7;
146
+ offset = read_raw_byte(&result, buffer, offset);
147
+ if (result >= 0) {
148
+ *tag |= result << 14;
149
+ } else {
150
+ *tag |= (result & 0x7f) << 14;
151
+ offset = read_raw_byte(&result, buffer, offset);
152
+ if (result >= 0) {
153
+ *tag |= ((uint32_t)result) << 21;
154
+ } else {
155
+ *tag |= (((uint32_t)result) & 0x7f) << 21;
156
+ offset = read_raw_byte(&result, buffer, offset);
157
+ *tag |= ((uint32_t)result) << 28;
158
+ if (result < 0) {
159
+ /* Discard upper 32 bits. */
160
+ int i;
161
+ for (i = 0; i < 5; ++ i) {
162
+ offset = read_raw_byte(&result, buffer, offset);
163
+ if (result >= 0) {
164
+ return offset;
165
+ }
166
+ }
167
+ /* Invalid state. */
168
+ }
169
+ }
170
+ }
171
+ }
172
+ return offset;
173
+ }
174
+
175
+ static int read_raw_varint64(uint64_t *tag, uint8_t *buffer, int offset) {
176
+ short shift = 0;
177
+ uint8_t b;
178
+ *tag = 0;
179
+ while (shift < 64) {
180
+ offset = read_raw_byte(&b, buffer, offset);
181
+ *tag |= (uint64_t)(b & 0x7F) << shift;
182
+ if ((b & 0x80) == 0) {
183
+ return offset;
184
+ }
185
+ shift += 7;
186
+ }
187
+ /* return error code. */
188
+ return -1;
189
+ }
190
+
191
+ <% each do |exp| %>
192
+ <%
193
+ if exp.kind_of?(Protobuf::Generate::Ast::Package)
194
+ package exp.name
195
+ elsif exp.kind_of?(Protobuf::Generate::Ast::Enum)
196
+ %>
197
+ <% elsif exp.kind_of?(Protobuf::Generate::Ast::Message) %>
198
+
199
+ void <%= namespaced_function exp.name, 'clear' %>(<%= namespaced_type exp.name %> *pb) {
200
+ memset(pb, 0, sizeof(*pb));
201
+ }
202
+
203
+ void <%= namespaced_function exp.name, 'init', 'optional', 'attributes' %>(<%= namespaced_type exp.name %> *pb) {
204
+ <% exp.fields.each do |field| %>
205
+ <% if field.optional? %>
206
+ <% if type_message?(field.type) %>
207
+ <%= namespaced_function field.type, 'init', 'optional', 'attributes' %>(&pb-><%= field.name %>);
208
+ <% elsif type_enum?(field.type) %>
209
+ pb-><%= field.name %> = <%= namespaced_constant field.type, type_enum_default(field.type, field.options.fetch('default', nil)) %>;
210
+ <% elsif field.type =~ /bool/ %>
211
+ pb-><%= field.name %> = <%= field.options.fetch(:default, 'false') %>;
212
+ <% elsif field.type =~ /string/ %>
213
+ memcpy(pb-><%= field.name %>.data, <%= field.options.fetch('default', '""') %>, <%= size = (field.options.fetch('default', '').bytesize - 1); size > 0 ? size : 0 %>);
214
+ pb-><%= field.name %>.size = <%= field.options.fetch('default', '').bytesize %>;
215
+ <% elsif field.type =~ /bytes/ %>
216
+ memcpy(pb-><%= field.name %>.data, <%= field.options.fetch('default', '""') %>, <%= field.options.fetch('default', '').bytesize %>);
217
+ pb-><%= field.name %>.size = <%= field.options.fetch('default', '').bytesize %>;
218
+ <% else %>
219
+ pb-><%= field.name %> = <%= field.options.fetch('default', 0) %>;
220
+ <% end %>
221
+ <% end %>
222
+ <% end %>
223
+ return;
224
+ }
225
+
226
+ bool <%= namespaced_function exp.name, 'is', 'default', 'message' %>(const <%= namespaced_type exp.name %> *pb) {
227
+ return true
228
+ <% exp.fields.each do |field| %> // <%= field.name %>
229
+ <% if type_message?(field.type) %>
230
+ && <%= namespaced_function field.type, 'is', 'default', 'message' %>(&pb-><%= field.name %>)
231
+ <% elsif type_enum?(field.type) %>
232
+ && pb-><%= field.name %> == <%= namespaced_constant field.type, type_enum_default(field.type, field.options.fetch('default', nil)) %>
233
+ <% elsif field.type =~ /string|bytes/ %>
234
+ && memcmp(&pb-><%= field.name %>.data, <%= field.options.fetch('default', '""') %>, <%= field.meta.fetch('size_max', field.options.fetch('default', '').bytesize) %>) == 0
235
+ && pb-><%= field.name %>.size == <%= field.options.fetch('default', '').bytesize %>
236
+ <% else %>
237
+ && pb-><%= field.name %> == <%= field.options.fetch('default', 0) %>
238
+ <% end %>
239
+ <% end %>;
240
+ }
241
+
242
+ int <%= namespaced_function exp.name, 'write' %>(const <%= namespaced_type exp.name %> *pb, uint8_t *buffer, int offset) {
243
+ <% exp.fields.each do |field| %> // <%= field.name %>
244
+ <% if field.optional? %>
245
+ <% if type_message?(field.type) %>
246
+ if (!<%= namespaced_function field.type, 'is', 'default', 'message' %>(&pb-><%= field.name %>)) {
247
+ offset = <%= namespaced_function field.type, 'write', 'with', 'tag' %>(&pb-><%= field.name %>, buffer, offset, <%= field.tag %>);
248
+ }
249
+ <% elsif type_enum?(field.type) %>
250
+ if (pb-><%= field.name %> != <%= namespaced_constant field.type, type_enum_default(field.type, field.options.fetch('default', nil)) %>) {
251
+ offset = write_raw_varint32((<%= field.tag %><<3)+0, buffer, offset);
252
+ offset = write_raw_varint32(pb-><%= field.name %>, buffer, offset);
253
+ }
254
+ <% elsif field.type =~ /double/ %>
255
+ if (pb-><%= field.name %> != <%= field.options.fetch('default', 0) %>) {
256
+ offset = write_raw_varint32((<%= field.tag %><<3)+<%= type_wire field.type %>, buffer, offset);
257
+ offset = write_raw_little_endian64(*(uint64_t *)&pb-><%= field.name %>, buffer, offset);
258
+ }
259
+ <% elsif field.type =~ /float/ %>
260
+ if (pb-><%= field.name %> != <%= field.options.fetch('default', 0) %>) {
261
+ offset = write_raw_varint32((<%= field.tag %><<3)+<%= type_wire field.type %>, buffer, offset);
262
+ offset = write_raw_little_endian32(*(uint32_t *)&pb-><%= field.name %>, buffer, offset);
263
+ }
264
+ <% elsif field.type =~ /int32/%>
265
+ if (pb-><%= field.name %> != <%= field.options.fetch('default', 0) %>) {
266
+ offset = write_raw_varint32((<%= field.tag %><<3)+<%= type_wire field.type %>, buffer, offset);
267
+ if (pb-><%= field.name %> >= 0) offset = write_raw_varin32(pb-><%= field.name %>, buffer, offset);
268
+ else offset = write_raw_varint64(pb-><%= field.name %>, buffer, offset);
269
+ }
270
+ <% elsif field.type =~ /int64/ %>
271
+ if (pb-><%= field.name %> != <%= field.options.fetch('default', 0) %>) {
272
+ offset = write_raw_varint32((<%= field.tag %><<3)+<%= type_wire field.type %>, buffer, offset);
273
+ offset = write_raw_varint64(pb-><%= field.name %>, buffer, offset);
274
+ }
275
+ <% elsif field.type =~ /sint32/ %>
276
+ if (pb-><%= field.name %> != <%= field.options.fetch('default', 0) %>) {
277
+ offset = write_raw_varint32((<%= field.tag %><<3)+<%= type_wire field.type %>, buffer, offset);
278
+ offset = write_raw_varint32(encode_zig_zag32(pb-><%= field.name %>), buffer, offset);
279
+ }
280
+ <% elsif field.type =~ /sint62/ %>
281
+ if (pb-><%= field.name %> != <%= field.options.fetch('default', 0) %>) {
282
+ offset = write_raw_varint32((<%= field.tag %><<3)+<%= type_wire field.type %>, buffer, offset);
283
+ offset = write_raw_varint64(encode_zig_zag64(pb-><%= field.name %>), buffer, offset);
284
+ }
285
+ <% elsif field.type =~ /uint32/ %>
286
+ if (pb-><%= field.name %> != <%= field.options.fetch('default', 0) %>) {
287
+ offset = write_raw_varint32((<%= field.tag %><<3)+<%= type_wire field.type %>, buffer, offset);
288
+ offset = write_raw_varint32(pb-><%= field.name %>, buffer, offset);
289
+ }
290
+ <% elsif field.type =~ /uint64/ %>
291
+ if (pb-><%= field.name %> != <%= field.options.fetch('default', 0) %>) {
292
+ offset = write_raw_varint32((<%= field.tag %><<3)+<%= type_wire field.type %>, buffer, offset);
293
+ offset = write_raw_varint64(pb-><%= field.name %>, buffer, offset);
294
+ }
295
+ <% elsif field.type =~ /s?fixed32/ %>
296
+ if (pb-><%= field.name %> != <%= field.options.fetch('default', 0) %>) {
297
+ offset = write_raw_varint32((<%= field.tag %><<3)+<%= type_wire field.type %>, buffer, offset);
298
+ offset = write_raw_little_endian32(pb-><%= field.name %>, buffer, offset);
299
+ }
300
+ <% elsif field.type =~ /s?fixed64/ %>
301
+ if (pb-><%= field.name %> != <%= field.options.fetch('default', 0) %>) {
302
+ offset = write_raw_varint32((<%= field.tag %><<3)+<%= type_wire field.type %>, buffer, offset);
303
+ offset = write_raw_little_endian64(pb-><%= field.name %>, buffer, offset);
304
+ }
305
+ <% elsif field.type =~ /bool/ %>
306
+ if (pb-><%= field.name %> != <%= field.options.fetch('default', 'false') %>) {
307
+ offset = write_raw_varint32((<%= field.tag %><<3)+<%= type_wire field.type %>, buffer, offset);
308
+ offset = write_raw_byte(pb-><%= field.name %>, buffer, offset);
309
+ }
310
+ <% elsif field.type =~ /string/ %>
311
+ if (memcmp(&pb-><%= field.name %>.data, <%= field.options.fetch('default', '""') %>, <%= field.meta.fetch('size_max', field.options.fetch('default', '').bytesize) %>) != 0) {
312
+ offset = write_raw_varint32((<%= field.tag %><<3)+<%= type_wire field.type %>, buffer, offset);
313
+ offset = write_raw_varint32(pb-><%= field.name %>.size, buffer, offset);
314
+ offset = write_raw_bytes((uint8_t *)pb-><%= field.name %>.data, pb-><%= field.name %>.size, buffer, offset);
315
+ }
316
+ <% elsif field.type =~ /bytes/ %>
317
+ if (memcmp(&pb-><%= field.name %>.data, <%= field.options.fetch('default', '""') %>, <%= field.meta.fetch('size_max', field.options.fetch('default', '').bytesize) %>) != 0) {
318
+ offset = write_raw_varint32((<%= field.tag %><<3)+<%= type_wire field.type %>, buffer, offset);
319
+ offset = write_raw_varint32(pb-><%= field.name %>.size, buffer, offset);
320
+ offset = write_raw_bytes((uint8_t *)pb-><%= field.name %>.data, pb-><%= field.name %>.size, buffer, offset);
321
+ }
322
+ <% end %>
323
+ <% else %>
324
+ <% if type_message?(field.type) %>
325
+ offset = <%= namespaced_function field.type, 'write', 'with', 'tag' %>(&pb-><%= field.name %>, buffer, offset, <%= field.tag %>);
326
+ <% elsif type_enum?(field.type) %>
327
+ offset = write_raw_varint32((<%= field.tag %><<3)+0, buffer, offset);
328
+ offset = write_raw_varint32(pb-><%= field.name %>, buffer, offset);
329
+ <% elsif field.type =~ /double/ %>
330
+ offset = write_raw_varint32((<%= field.tag %><<3)+<%= type_wire field.type %>, buffer, offset);
331
+ offset = write_raw_little_endian64(*(uint64_t *)&pb-><%= field.name %>, buffer, offset);
332
+ <% elsif field.type =~ /float/ %>
333
+ offset = write_raw_varint32((<%= field.tag %><<3)+<%= type_wire field.type %>, buffer, offset);
334
+ offset = write_raw_little_endian32(*(uint32_t *)&pb-><%= field.name %>, buffer, offset);
335
+ <% elsif field.type =~ /int32/ %>
336
+ offset = write_raw_varint32((<%= field.tag %><<3)+<%= type_wire field.type %>, buffer, offset);
337
+ if (pb-><%= field.name %> >= 0) offset = write_raw_varin32(pb-><%= field.name %>, buffer, offset);
338
+ else offset = write_raw_varint64(pb-><%= field.name %>, buffer, offset);
339
+ <% elsif field.type =~ /int64/ %>
340
+ offset = write_raw_varint32((<%= field.tag %><<3)+<%= type_wire field.type %>, buffer, offset);
341
+ offset = write_raw_varint64(pb-><%= field.name %>, buffer, offset);
342
+ <% elsif field.type =~ /sint32/ %>
343
+ offset = write_raw_varint32((<%= field.tag %><<3)+<%= type_wire field.type %>, buffer, offset);
344
+ offset = write_raw_varint32(encode_zig_zag32(pb-><%= field.name %>), buffer, offset);
345
+ <% elsif field.type =~ /sint62/ %>
346
+ offset = write_raw_varint32((<%= field.tag %><<3)+<%= type_wire field.type %>, buffer, offset);
347
+ offset = write_raw_varint64(encode_zig_zag64(pb-><%= field.name %>), buffer, offset);
348
+ <% elsif field.type =~ /uint32/ %>
349
+ offset = write_raw_varint32((<%= field.tag %><<3)+<%= type_wire field.type %>, buffer, offset);
350
+ offset = write_raw_varint32(pb-><%= field.name %>, buffer, offset);
351
+ <% elsif field.type =~ /uint64/ %>
352
+ offset = write_raw_varint32((<%= field.tag %><<3)+<%= type_wire field.type %>, buffer, offset);
353
+ offset = write_raw_varint64(pb-><%= field.name %>, buffer, offset);
354
+ <% elsif field.type =~ /s?fixed32/ %>
355
+ offset = write_raw_varint32((<%= field.tag %><<3)+<%= type_wire field.type %>, buffer, offset);
356
+ offset = write_raw_little_endian32(pb-><%= field.name %>, buffer, offset);
357
+ <% elsif field.type =~ /s?fixed64/ %>
358
+ offset = write_raw_varint32((<%= field.tag %><<3)+<%= type_wire field.type %>, buffer, offset);
359
+ offset = write_raw_little_endian64(pb-><%= field.name %>, buffer, offset);
360
+ <% elsif field.type =~ /bool/ %>
361
+ offset = write_raw_varint32((<%= field.tag %><<3)+<%= type_wire field.type %>, buffer, offset);
362
+ offset = write_raw_byte(pb-><%= field.name %>, buffer, offset);
363
+ <% elsif field.type =~ /string/ %>
364
+ offset = write_raw_varint32((<%= field.tag %><<3)+<%= type_wire field.type %>, buffer, offset);
365
+ offset = write_raw_varint32(pb-><%= field.name %>.size, buffer, offset);
366
+ offset = write_raw_bytes((uint8_t *)pb-><%= field.name %>.data, pb-><%= field.name %>.size, buffer, offset);
367
+ <% elsif field.type =~ /bytes/ %>
368
+ offset = write_raw_varint32((<%= field.tag %><<3)+<%= type_wire field.type %>, buffer, offset);
369
+ offset = write_raw_varint32(pb-><%= field.name %>.size, buffer, offset);
370
+ offset = write_raw_bytes((uint8_t *)pb-><%= field.name %>.data, pb-><%= field.name %>.size, buffer, offset);
371
+ <% end %>
372
+ <% end %>
373
+ <% end %>
374
+ return offset;
375
+ }
376
+
377
+ int <%= namespaced_function exp.name, 'write', 'delimited', 'to' %>(const <%= namespaced_type exp.name %> *pb, uint8_t *buffer, int offset) {
378
+ int i, shift, new_offset, size;
379
+
380
+ new_offset = <%= namespaced_function exp.name, 'write' %>(pb, buffer, offset);
381
+ size = new_offset - offset;
382
+ shift = (size > 127) ? 2 : 1;
383
+ for (i = new_offset - 1; i >= offset; -- i)
384
+ *(buffer + i + shift) = *(buffer + i);
385
+
386
+ write_raw_varint32((uint32_t)size, buffer, offset);
387
+ return new_offset + shift;
388
+ }
389
+
390
+ int <%= namespaced_function exp.name, 'write', 'with', 'tag' %>(const <%= namespaced_type exp.name %> *pb, uint8_t *buffer, int offset, int tag) {
391
+ offset = write_raw_varint32((tag<<3)+2, buffer, offset);
392
+ offset = <%= namespaced_function exp.name, 'write', 'delimited', 'to' %>(pb, buffer, offset);
393
+ return offset;
394
+ }
395
+
396
+ int <%= namespaced_function exp.name, 'encode' %>(const <%= namespaced_type exp.name %> *pb, uint8_t *data, size_t data_size, size_t *encoded_size) {
397
+ *encoded_size = <%= namespaced_function exp.name, 'write', 'delimited', 'to' %>(pb, data, -1);
398
+ return 0; // TODO: Encoding errors.
399
+ }
400
+
401
+ int <%= namespaced_function exp.name, 'read', 'delimited', 'from' %>(<%= namespaced_type exp.name %> *pb, const uint8_t *buffer, int offset);
402
+
403
+ int <%= namespaced_function exp.name, 'read' %>(<%= namespaced_type exp.name %> *pb, const uint8_t *buffer, int offset, int limit) {
404
+ <%= namespaced_function exp.name, 'clear' %>(pb);
405
+ <%= namespaced_function exp.name, 'init', 'optional', 'attributes' %>(pb);
406
+
407
+ uint32_t tag = 0;
408
+ while (offset < limit) {
409
+ offset = read_raw_varint32(&tag, buffer, offset);
410
+ tag = tag>>3;
411
+ switch (tag) {
412
+ <% exp.fields.each do |field| %>
413
+ case <%= field.tag %>:
414
+ // <%= field.name %>
415
+ <% if type_message?(field.type) %>
416
+ offset = <%= namespaced_function field.type, 'read', 'delimited', 'from' %>(&pb-><%= field.name %>, buffer, offset);
417
+ <% elsif type_enum?(field.type) %>
418
+ offset = read_raw_varint32(&tag, buffer, offset);
419
+ pb-><%= field.name %> = tag;
420
+ <% elsif field.type =~ /float/ %>
421
+ offset = read_raw_little_endian32(&tag, buffer, offset);
422
+ pb-><%= field.name %> = *(float *)(&tag);
423
+ <% elsif field.type =~ /double/ %>
424
+ {
425
+ uint64_t value = 0;
426
+ offset = read_raw_little_endian64(&value, buffer, offset);
427
+ pb-><%= field.name %> = *(double *)(&value);
428
+ }
429
+ <% elsif field.type =~ /int32/ %>
430
+ offset = read_raw_varint32(&tag, buffer, offset);
431
+ pb-><%= field.name %> = (int32_t)tag;
432
+ <% elsif field.type =~ /int64/ %>
433
+ {
434
+ uint64_t value = 0;
435
+ offset = read_raw_varint64(&value, buffer, offset);
436
+ pb-><%= field.name %> = (int64_t)tag;
437
+ }
438
+ <% elsif field.type =~ /sint32/ %>
439
+ offset = read_raw_varint32(&tag, buffer, offset);
440
+ pb-><%= field.name %> = decode_zig_zag32(tag);
441
+ <% elsif field.type =~ /sint64/ %>
442
+ {
443
+ uint64_t value = 0;
444
+ offset = read_raw_varint64(&value, buffer, offset);
445
+ pb-><%= field.name %> = decode_zig_zag64(value);
446
+ }
447
+ <% elsif field.type =~ /uint32/ %>
448
+ offset = read_raw_varint32(&tag, buffer, offset);
449
+ pb-><%= field.name %> = tag;
450
+ <% elsif field.type =~ /uint64/ %>
451
+ {
452
+ uint64_t value = 0;
453
+ offset = read_raw_varint64(&value, buffer, offset);
454
+ pb-><%= field.name %> = value;
455
+ }
456
+ <% elsif field.type =~ /fixed32/ %>
457
+ offset = read_raw_little_endian32(&tag, buffer, offset);
458
+ pb-><%= field.name %> = tag;
459
+ <% elsif field.type =~ /fixed64/ %>
460
+ {
461
+ uint64_t value = 0;
462
+ offset = read_raw_little_endian64(&value, buffer, offset);
463
+ pb-><%= field.name %> = value;
464
+ }
465
+ <% elsif field.type =~ /sfixed32/ %>
466
+ offset = read_raw_little_endian32(&tag, buffer, offset);
467
+ pb-><%= field.name %> = (int32_t)tag;
468
+ <% elsif field.type =~ /sfixed64/ %>
469
+ {
470
+ uint64_t value = 0;
471
+ offset = read_raw_little_endian64(&value, buffer, offset);
472
+ pb-><%= field.name %> = (int64_t)value;
473
+ }
474
+ <% elsif field.type =~ /bool/ %>
475
+ offset = read_raw_varint32(&tag, buffer, offset);
476
+ pb-><%= field.name %> = tag & 1;
477
+ <% elsif field.type =~ /string|bytes/ %>
478
+ offset = read_raw_varint32(&tag, buffer, offset);
479
+ pb-><%= field.name %>.size = (size_t)tag;
480
+ for (size_t i = 0; i < (size_t)tag; ++i)
481
+ offset = read_raw_byte((pb-><%= field.name %>.data + i), buffer, offset);
482
+ <% end %>
483
+ break;
484
+ <% end %>
485
+ }
486
+ }
487
+ return offset;
488
+ }
489
+
490
+ int <%= namespaced_function exp.name, 'read', 'delimited', 'from' %>(<%= namespaced_type exp.name %> *pb, const uint8_t *buffer, int offset) {
491
+ uint32_t size;
492
+ offset = read_raw_varint32(&size, buffer, offset);
493
+ <%= namespaced_function exp.name, 'read' %>(pb, buffer, offset, size + offset);
494
+ return offset + size;
495
+ }
496
+
497
+ int <%= namespaced_function exp.name, 'decode' %>(<%= namespaced_type exp.name %> *pb, const uint8_t *data, size_t data_size, size_t *encoded_size) {
498
+ *encoded_size = <%= namespaced_function exp.name, 'read' %>(pb, data, 0, data_size);
499
+ return 0; // TODO: Decoding errors.
500
+ }
501
+ <% end %>
502
+ <% end %>
@@ -0,0 +1,71 @@
1
+ #pragma once
2
+
3
+ #include <stdbool.h>
4
+ #include <stddef.h>
5
+ #include <stdint.h>
6
+
7
+ #ifdef __cplusplus
8
+ extern "C" {
9
+ #endif
10
+ <%
11
+ each do |exp|
12
+ if exp.kind_of?(Protobuf::Generate::Ast::Package)
13
+ package exp.name
14
+ elsif exp.kind_of?(Protobuf::Generate::Ast::Enum)
15
+ %>
16
+
17
+ typedef enum {
18
+ <% exp.fields.each do |field| %>
19
+ <%= namespaced_constant exp.name, field.name %> = <%= field.tag %>,
20
+ <% end %>
21
+ } <%= namespaced_type exp.name %>;
22
+ <%
23
+ elsif exp.kind_of?(Protobuf::Generate::Ast::Message)
24
+ %>
25
+
26
+ typedef struct <%= namespaced_type exp.name %> {
27
+ <% exp.fields.each do |field| %>
28
+ <% if type_message?(field.type) %>
29
+ <%= namespaced_type field.type %> <%= field.name %>;
30
+ <% elsif type_enum?(field.type) %>
31
+ <%= namespaced_type field.type %> <%= field.name %>;
32
+ <% elsif field.type =~ /double/ %>
33
+ double <%= field.name %>;
34
+ <% elsif field.type =~ /float/ %>
35
+ float <%= field.name %>;
36
+ <% elsif field.type =~ /int32|sint32|sfixed32/ %>
37
+ int32_t <%= field.name %>;
38
+ <% elsif field.type =~ /int64|sint64|sfixed64/ %>
39
+ int64_t <%= field.name %>;
40
+ <% elsif field.type =~ /uint32|fixed32/ %>
41
+ uint32_t <%= field.name %>;
42
+ <% elsif field.type =~ /uint64|fixed64/ %>
43
+ uint64_t <%= field.name %>;
44
+ <% elsif field.type =~ /bool/ %>
45
+ bool <%= field.name %>;
46
+ <% elsif field.type =~ /string/ %>
47
+ struct {
48
+ uint8_t data[<%= field.meta["size_max"] %>];
49
+ size_t size;
50
+ } <%= field.name %>;
51
+ <% elsif field.type =~ /bytes/ %>
52
+ struct {
53
+ uint8_t data[<%= field.meta["size_max"] %>];
54
+ size_t size;
55
+ } <%= field.name %>;
56
+ <% end %>
57
+ <% end %>
58
+ } <%= namespaced_type exp.name %>;
59
+
60
+ // TODO: Replace int with an protobuf_(encode|decode)_t type.
61
+ // TODO: Move encode_size into result type.
62
+ int <%= namespaced_function exp.name, 'encode' %>(const <%= namespaced_type exp.name %> *pb, uint8_t *data, size_t data_size, size_t *encoded_size);
63
+ int <%= namespaced_function exp.name, 'decode' %>(<%= namespaced_type exp.name %> *pb, const uint8_t *data, size_t data_size, size_t *encoded_size);
64
+ <%
65
+ end
66
+ end
67
+ %>
68
+
69
+ #ifdef __cplusplus
70
+ }
71
+ #endif
@@ -0,0 +1,39 @@
1
+ require 'protobuf/generate/language'
2
+
3
+ module Protobuf
4
+ module Generate
5
+ class Language
6
+ class C < Language
7
+ match %r{^ (?:gnu|[Cc]) (?:99|11) $}x
8
+ templates Dir.glob(File.join(File.expand_path(File.dirname(__FILE__)), 'c', '*.erb'))
9
+
10
+ module Conventions
11
+ def package name = nil
12
+ @naming_namespace = name.to_s if name
13
+ (@naming_namespace ||= '').gsub('.', '_')
14
+ end
15
+
16
+ def type *name; snake_case *name, 't' end
17
+ def variable *name; snake_case *name end
18
+ def constant *name; snake_case(*name).upcase end
19
+ def function *name; snake_case *name end
20
+
21
+ def namespaced_type *name; type package, *name end
22
+ def namespaced_variable *name; variable package, *name end
23
+ def namespaced_constant *name; constant package, *name end
24
+ def namespaced_function *name; function package, *name end
25
+
26
+ protected
27
+ def snake_case *name
28
+ name.map(&:to_s).join('_').gsub(/([^A-Z_])([A-Z]+)/, '\1_\2').gsub(/_+/, '_').downcase
29
+ end
30
+ end # Conventions
31
+
32
+ def initialize ast, conventions = Conventions
33
+ ast.extend(conventions)
34
+ super ast
35
+ end
36
+ end # C
37
+ end # Langage
38
+ end # Generate
39
+ end # Protobuf
@@ -0,0 +1,64 @@
1
+ require 'erubis'
2
+
3
+ module Protobuf
4
+ module Generate
5
+ class Language
6
+ module Helpers
7
+ attr_accessor :template, :filename
8
+
9
+ def type_message? type
10
+ !!find{|e| e.kind_of?(Protobuf::Generate::Ast::Message) && e.name == type }
11
+ end
12
+
13
+ def type_enum? type
14
+ !!find{|e| e.kind_of?(Protobuf::Generate::Ast::Enum) && e.name == type }
15
+ end
16
+
17
+ def type_wire type
18
+ Hash[*%w{int32 0 int64 0 sint32 0 sint64 0 uint32 0 uint64 0 string 2 bool 0 float 5 double 1 fixed32 5 fixed64 1 sfixed32 5 sfixed64 1 bytes 2}][type]
19
+ end
20
+
21
+ def type_enum_default type, default
22
+ enum = find{|e| e.kind_of?(Protobuf::Generate::Ast::Enum) && e.name == type} # TODO: Or raise unknown type.
23
+ (enum.fields.find{|f| f.name == default.to_s} || enum.fields.first).name
24
+ end
25
+ end
26
+
27
+ def self.match language = nil
28
+ @language = language if language
29
+ @language
30
+ end
31
+
32
+ def self.templates templates = nil
33
+ @templates = templates if templates
34
+ @templates
35
+ end
36
+
37
+ def self.find language
38
+ @@languages.find{|l| l.match(language.to_s)}
39
+ end
40
+
41
+ def self.inherited klass
42
+ (@@languages ||= []) << klass
43
+ end
44
+
45
+ #--
46
+ # TODO: AST tree should include name of .proto that generated it.
47
+ def initialize ast
48
+ @ast = ast
49
+ end
50
+
51
+ def templates
52
+ self.class.templates
53
+ end
54
+
55
+ def generate template, filename
56
+ ast = @ast
57
+ ast.extend(Helpers)
58
+ ast.template = template
59
+ ast.filename = filename
60
+ Erubis::Eruby.new(File.read(template), filename: template).evaluate(ast)
61
+ end
62
+ end # Language
63
+ end # Generate
64
+ end # Protobuf
@@ -0,0 +1,92 @@
1
+ require 'parslet'
2
+
3
+ module Protobuf
4
+ module Generate
5
+ class Parser < Parslet::Parser
6
+ rule(:newline) { match('\n') }
7
+ rule(:whitespace) { match('\s').repeat(1) }
8
+ rule(:whitespace?) { whitespace.maybe }
9
+ rule(:space) { match('[\t ]').repeat(1) }
10
+ rule(:space?) { space.maybe }
11
+
12
+ rule(:comment_option) { str('@') >> identifier.as(:name) >> space? >> equals >> constant.as(:value) }
13
+ rule(:comment_option_list) { (comment_option.as(:option) >> space?).repeat(1) }
14
+ rule(:comment) { str('//') >> (newline.absent? >> (comment_option_list.as(:meta) | any)).repeat >> newline }
15
+ rule(:comment_list) { comment.repeat }
16
+
17
+ rule(:equals) { str('=') >> whitespace? }
18
+ rule(:bracket_open) { str('{') >> whitespace? }
19
+ rule(:bracket_close) { str('}') >> whitespace? }
20
+
21
+ rule(:digit) { match('[0-9]') }
22
+ rule(:integer) { str('-').maybe >> match('[1-9]') >> digit.repeat }
23
+ rule(:float) { str('-').maybe >> digit.repeat(1) >> str('.') >> digit.repeat(1) }
24
+
25
+ rule(:string_special) { match['\0\t\n\r"\\\\'] }
26
+ rule(:escaped_special) { str("\\") >> match['0tnr"\\\\'] }
27
+ rule(:string) { str('"') >> (escaped_special | string_special.absent? >> any).repeat >> str('"') }
28
+
29
+ rule(:identifier) { match('[a-zA-Z_]') >> match('[a-zA-Z0-9_]').repeat }
30
+ rule(:identifier_dot_list) { identifier >> (str('.') >> identifier).repeat }
31
+
32
+ rule(:constant) { identifier | integer | float | string }
33
+
34
+ rule(:field_option) { str('default').as(:name) >> whitespace? >> equals >> constant.as(:value) }
35
+ rule(:field_option_list) { (str('[') >> whitespace? >> (field_option.as(:option) >> whitespace?).repeat(1) >> whitespace? >> str(']') >> whitespace?) }
36
+ rule(:field_type) { identifier.as(:type) >> whitespace? }
37
+ rule(:field_label) { (str('required') | str('optional') | str('repeated')).as(:label) >> whitespace? }
38
+
39
+ rule(:message_field) { (field_label >> field_type >> identifier.as(:name) >> whitespace? >> equals >> integer.as(:tag) >> whitespace? >> field_option_list.maybe.as(:options) >> str(';') >> space? >> comment.maybe.as(:comment) ).as(:message_field) }
40
+ rule(:message_field_list) { (message_field >> whitespace?).repeat(1).as(:fields) }
41
+ rule(:message) { (comment_list.maybe.as(:comments) >> str('message') >> whitespace? >> identifier.as(:name) >> whitespace? >> bracket_open >> message_field_list.maybe >> bracket_close >> whitespace?).as(:message) }
42
+
43
+ rule(:enum_field) { (identifier.as(:name) >> whitespace? >> equals >> integer.as(:tag) >> whitespace? >> str(';')).as(:enum_field) }
44
+ rule(:enum_field_list) { (enum_field >> whitespace?).repeat(1).as(:fields) }
45
+ rule(:enum) { (str('enum') >> whitespace? >> identifier.as(:name) >> whitespace? >> bracket_open >> enum_field_list >> bracket_close >> whitespace?).as(:enum) }
46
+
47
+ rule(:package) { (str('package') >> whitespace? >> identifier_dot_list.as(:name) >> whitespace? >> str(';') >> whitespace?).as(:package) }
48
+
49
+ rule(:expression) { whitespace? >> (package | enum | message | comment | whitespace).repeat }
50
+ root(:expression)
51
+ end # Parser
52
+
53
+ class Ast
54
+ class Package < Struct.new(:name); end
55
+ class Message < Struct.new(:name, :meta, :fields)
56
+ def empty?; fields.nil? or fields.empty? end
57
+ end
58
+ class MessageField < Struct.new(:label, :type, :name, :tag, :meta, :options)
59
+ def required?; !!label.match(/required/) end
60
+ def optional?; !required? end
61
+ end
62
+ class Enum < Struct.new(:name, :fields); end
63
+ class EnumField < Struct.new(:name, :tag); end
64
+ end
65
+
66
+ class Transform < Parslet::Transform
67
+ rule(option: {name: simple(:name), value: simple(:value)}){ [name.to_s, value.to_s] }
68
+ rule(package: {name: simple(:name)}){ Ast::Package.new(name.to_s) }
69
+
70
+ rule(message_field: subtree(:f)) do
71
+ Ast::MessageField.new(
72
+ *f.values_at(:label, :type, :name, :tag).map(&:to_s),
73
+ f[:comment].kind_of?(Array) ? Hash[*f[:comment].map{|c| c[:meta]}.flatten.compact] : {},
74
+ f[:options].kind_of?(Array) ? Hash[*[f[:options]].flatten.compact] : {}
75
+ )
76
+ end
77
+
78
+ rule(message: subtree(:message)) do
79
+ Ast::Message.new(
80
+ message[:name].to_s,
81
+ # TODO: Parslet should return nil not "" when empty. Figure out what's going on.
82
+ message[:comments].kind_of?(Array) ? Hash[*message[:comments].map{|c| c[:meta]}.flatten.compact] : {},
83
+ [*message[:fields]].compact
84
+ )
85
+ end
86
+
87
+ rule(enum_field: {name: simple(:name), tag: simple(:tag)}){ Ast::EnumField.new(name.to_s, tag.to_s) }
88
+ rule(enum: subtree(:enum)){ Ast::Enum.new(enum[:name].to_s, enum[:fields]) }
89
+ end # Transform
90
+ end # Generate
91
+ end # Protobuf
92
+
@@ -0,0 +1,2 @@
1
+ require 'protobuf/generate/parser'
2
+ require 'protobuf/generate/language/c'
@@ -0,0 +1,22 @@
1
+ $:.unshift(File.join(File.dirname(__FILE__), 'lib'))
2
+
3
+ spec = Gem::Specification.new do |s|
4
+ s.name = 'protobuf-generate'
5
+ s.version = '0.0.1'
6
+ s.summary = 'A multi-language concrete protobuf code generator.'
7
+ s.description = 'A simple PEG parser, AST and template based approach to code generation.'
8
+ s.authors = ['Shane Hanna']
9
+ s.email = ['shane.hanna@gmail.com']
10
+ s.licenses = ['MIT']
11
+ s.homepage = 'https://bitbucket.org/shanehanna/protobuf-generate'
12
+
13
+ s.add_dependency('parslet')
14
+ s.add_dependency('erubis')
15
+
16
+ s.required_ruby_version = '>= 1.9.2'
17
+
18
+ s.files = `git ls-files`.split("\n")
19
+ s.test_files = `git ls-files -- test/*`.split("\n")
20
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
21
+ s.require_paths = ['lib']
22
+ end
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: protobuf-generate
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Shane Hanna
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-08-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: parslet
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: erubis
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: A simple PEG parser, AST and template based approach to code generation.
42
+ email:
43
+ - shane.hanna@gmail.com
44
+ executables:
45
+ - protobuf-generate
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - .gitignore
50
+ - Gemfile
51
+ - LICENSE
52
+ - README.md
53
+ - bin/protobuf-generate
54
+ - lib/protobuf-generate.rb
55
+ - lib/protobuf/generate/language.rb
56
+ - lib/protobuf/generate/language/c.rb
57
+ - lib/protobuf/generate/language/c/c.erb
58
+ - lib/protobuf/generate/language/c/h.erb
59
+ - lib/protobuf/generate/parser.rb
60
+ - protobuf-generate.gemspec
61
+ homepage: https://bitbucket.org/shanehanna/protobuf-generate
62
+ licenses:
63
+ - MIT
64
+ metadata: {}
65
+ post_install_message:
66
+ rdoc_options: []
67
+ require_paths:
68
+ - lib
69
+ required_ruby_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - '>='
72
+ - !ruby/object:Gem::Version
73
+ version: 1.9.2
74
+ required_rubygems_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ requirements: []
80
+ rubyforge_project:
81
+ rubygems_version: 2.0.3
82
+ signing_key:
83
+ specification_version: 4
84
+ summary: A multi-language concrete protobuf code generator.
85
+ test_files: []
86
+ has_rdoc: