macks-ruby_protobuf 0.3.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +14 -0
- data/Manifest.txt +74 -0
- data/README.txt +58 -0
- data/Rakefile +18 -0
- data/bin/mk_parser +2 -0
- data/bin/rprotoc +36 -0
- data/examples/addressbook.pb.rb +56 -0
- data/examples/addressbook.proto +24 -0
- data/examples/reading_a_message.rb +32 -0
- data/examples/writing_a_message.rb +46 -0
- data/lib/protobuf/common/wire_type.rb +10 -0
- data/lib/protobuf/compiler/compiler.rb +54 -0
- data/lib/protobuf/compiler/nodes.rb +319 -0
- data/lib/protobuf/compiler/proto.y +203 -0
- data/lib/protobuf/compiler/proto2.ebnf +79 -0
- data/lib/protobuf/compiler/proto_parser.rb +1394 -0
- data/lib/protobuf/compiler/template/rpc_bin.erb +4 -0
- data/lib/protobuf/compiler/template/rpc_client.erb +18 -0
- data/lib/protobuf/compiler/template/rpc_service.erb +25 -0
- data/lib/protobuf/compiler/visitors.rb +288 -0
- data/lib/protobuf/descriptor/descriptor.proto +286 -0
- data/lib/protobuf/descriptor/descriptor.rb +54 -0
- data/lib/protobuf/descriptor/descriptor_builder.rb +144 -0
- data/lib/protobuf/descriptor/descriptor_proto.rb +119 -0
- data/lib/protobuf/descriptor/enum_descriptor.rb +33 -0
- data/lib/protobuf/descriptor/field_descriptor.rb +50 -0
- data/lib/protobuf/descriptor/file_descriptor.rb +38 -0
- data/lib/protobuf/message/decoder.rb +93 -0
- data/lib/protobuf/message/encoder.rb +37 -0
- data/lib/protobuf/message/enum.rb +28 -0
- data/lib/protobuf/message/extend.rb +8 -0
- data/lib/protobuf/message/field.rb +654 -0
- data/lib/protobuf/message/message.rb +308 -0
- data/lib/protobuf/message/protoable.rb +37 -0
- data/lib/protobuf/message/service.rb +9 -0
- data/lib/protobuf/rpc/client.rb +19 -0
- data/lib/protobuf/rpc/handler.rb +17 -0
- data/lib/protobuf/rpc/server.rb +39 -0
- data/lib/ruby_protobuf.rb +3 -0
- data/test/addressbook.rb +98 -0
- data/test/addressbook_base.rb +62 -0
- data/test/addressbook_ext.rb +12 -0
- data/test/check_unbuild.rb +30 -0
- data/test/collision.rb +18 -0
- data/test/data/data.bin +3 -0
- data/test/data/data_source.py +14 -0
- data/test/data/types.bin +0 -0
- data/test/data/types_source.py +22 -0
- data/test/data/unk.png +0 -0
- data/test/ext_collision.rb +25 -0
- data/test/ext_range.rb +23 -0
- data/test/merge.rb +40 -0
- data/test/nested.rb +25 -0
- data/test/proto/addressbook.proto +31 -0
- data/test/proto/addressbook_base.proto +26 -0
- data/test/proto/addressbook_ext.proto +6 -0
- data/test/proto/collision.proto +5 -0
- data/test/proto/ext_collision.proto +8 -0
- data/test/proto/ext_range.proto +7 -0
- data/test/proto/merge.proto +15 -0
- data/test/proto/nested.proto +7 -0
- data/test/proto/rpc.proto +6 -0
- data/test/proto/types.proto +17 -0
- data/test/test_addressbook.rb +43 -0
- data/test/test_compiler.rb +313 -0
- data/test/test_descriptor.rb +122 -0
- data/test/test_extension.rb +40 -0
- data/test/test_message.rb +106 -0
- data/test/test_optional_field.rb +68 -0
- data/test/test_parse.rb +15 -0
- data/test/test_ruby_protobuf.rb +1 -0
- data/test/test_serialize.rb +42 -0
- data/test/test_standard_message.rb +96 -0
- data/test/test_types.rb +181 -0
- data/test/types.rb +22 -0
- metadata +150 -0
@@ -0,0 +1,319 @@
|
|
1
|
+
require 'protobuf/descriptor/descriptor_proto'
|
2
|
+
|
3
|
+
module Protobuf
|
4
|
+
module Node
|
5
|
+
class Base
|
6
|
+
def define_in_the_file(visitor)
|
7
|
+
visitor.write "defined_in __FILE__" if visitor.attach_proto?
|
8
|
+
end
|
9
|
+
|
10
|
+
def accept_message_visitor(visitor)
|
11
|
+
end
|
12
|
+
|
13
|
+
def accept_rpc_visitor(vistor)
|
14
|
+
end
|
15
|
+
|
16
|
+
def accept_descriptor_visitor(visitor)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class ProtoNode < Base
|
21
|
+
attr_reader :children
|
22
|
+
|
23
|
+
def initialize(children)
|
24
|
+
@children = children
|
25
|
+
end
|
26
|
+
|
27
|
+
def accept_message_visitor(visitor)
|
28
|
+
visitor.write '### Generated by rprotoc. DO NOT EDIT!'
|
29
|
+
visitor.write "### <proto file: #{visitor.proto_file}>" if visitor.attach_proto?
|
30
|
+
visitor.write visitor.commented_proto_contents if visitor.attach_proto?
|
31
|
+
visitor.write <<-eos
|
32
|
+
require 'protobuf/message/message'
|
33
|
+
require 'protobuf/message/enum'
|
34
|
+
require 'protobuf/message/service'
|
35
|
+
require 'protobuf/message/extend'
|
36
|
+
eos
|
37
|
+
@children.map{|child| child.accept_message_visitor visitor}
|
38
|
+
visitor.close_ruby
|
39
|
+
end
|
40
|
+
|
41
|
+
def accept_rpc_visitor(visitor)
|
42
|
+
@children.map{|child| child.accept_rpc_visitor visitor}
|
43
|
+
end
|
44
|
+
|
45
|
+
def accept_descriptor_visitor(visitor)
|
46
|
+
descriptor = Google::Protobuf::FileDescriptorProto.new :name => visitor.filename
|
47
|
+
visitor.file_descriptor = descriptor
|
48
|
+
visitor.in_context descriptor do
|
49
|
+
@children.map{|child| child.accept_descriptor_visitor visitor}
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
class ImportNode < Base
|
55
|
+
def initialize(path)
|
56
|
+
@path = path
|
57
|
+
end
|
58
|
+
|
59
|
+
def accept_message_visitor(visitor)
|
60
|
+
visitor.write "require '#{visitor.required_message_from_proto @path}'"
|
61
|
+
end
|
62
|
+
|
63
|
+
def accept_descriptor_visitor(visitor)
|
64
|
+
visitor.current_descriptor.dependency << @path
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
class PackageNode < Base
|
69
|
+
def initialize(path_list)
|
70
|
+
@path_list = path_list
|
71
|
+
end
|
72
|
+
|
73
|
+
def accept_message_visitor(visitor)
|
74
|
+
@path_list.each do |path|
|
75
|
+
visitor.write "module #{path.to_s.capitalize}"
|
76
|
+
visitor.increment
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def accept_rpc_visitor(visitor)
|
81
|
+
visitor.package = @path_list.dup
|
82
|
+
end
|
83
|
+
|
84
|
+
def accept_descriptor_visitor(visitor)
|
85
|
+
visitor.current_descriptor.package = @path_list.join '.'
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
class OptionNode < Base
|
90
|
+
def initialize(name_list, value)
|
91
|
+
@name_list, @value = name_list, value
|
92
|
+
end
|
93
|
+
|
94
|
+
def accept_message_visitor(visitor)
|
95
|
+
visitor.write "::Protobuf::OPTIONS[:#{@name_list.join('.').inspect}] = #{@value.inspect}"
|
96
|
+
end
|
97
|
+
|
98
|
+
def accept_descriptor_visitor(visitor)
|
99
|
+
visitor.add_option @name_list.join('.'), @value
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
class MessageNode < Base
|
104
|
+
def initialize(name, children)
|
105
|
+
@name, @children = name, children
|
106
|
+
end
|
107
|
+
|
108
|
+
def accept_message_visitor(visitor)
|
109
|
+
visitor.write "class #{@name} < ::Protobuf::Message"
|
110
|
+
visitor.in_context self.class do
|
111
|
+
define_in_the_file visitor
|
112
|
+
#@children.each {|child| child.accept_message_visitor visitor}
|
113
|
+
@children.each {|child| next if child == ';'; child.accept_message_visitor visitor}
|
114
|
+
# TODO: `next if child == ';';' is a monky patching. There must be a parser error.
|
115
|
+
end
|
116
|
+
visitor.write "end"
|
117
|
+
end
|
118
|
+
|
119
|
+
def accept_descriptor_visitor(visitor)
|
120
|
+
descriptor = Google::Protobuf::DescriptorProto.new :name => @name.to_s
|
121
|
+
visitor.descriptor = descriptor
|
122
|
+
visitor.in_context descriptor do
|
123
|
+
@children.each {|child| child.accept_descriptor_visitor visitor}
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
class ExtendNode < Base
|
129
|
+
def initialize(name, children)
|
130
|
+
@name, @children = name, children
|
131
|
+
end
|
132
|
+
|
133
|
+
def accept_message_visitor(visitor)
|
134
|
+
name = @name.is_a?(Array) ? @name.join : name.to_s
|
135
|
+
visitor.write "class #{name} < ::Protobuf::Message"
|
136
|
+
visitor.in_context self.class do
|
137
|
+
define_in_the_file visitor
|
138
|
+
@children.each {|child| child.accept_message_visitor visitor}
|
139
|
+
end
|
140
|
+
visitor.write "end"
|
141
|
+
end
|
142
|
+
|
143
|
+
def accept_descriptor_visitor(visitor)
|
144
|
+
# TODO: how should i handle this?
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
class EnumNode < Base
|
149
|
+
def initialize(name, children)
|
150
|
+
@name, @children = name, children
|
151
|
+
end
|
152
|
+
|
153
|
+
def accept_message_visitor(visitor)
|
154
|
+
visitor.write "class #{@name} < ::Protobuf::Enum"
|
155
|
+
visitor.in_context self.class do
|
156
|
+
define_in_the_file visitor
|
157
|
+
@children.each {|child| child.accept_message_visitor visitor}
|
158
|
+
end
|
159
|
+
visitor.write "end"
|
160
|
+
end
|
161
|
+
|
162
|
+
def accept_descriptor_visitor(visitor)
|
163
|
+
descriptor = Google::Protobuf::EnumDescriptorProto.new :name => @name.to_s
|
164
|
+
visitor.enum_descriptor = descriptor
|
165
|
+
visitor.in_context descriptor do
|
166
|
+
@children.each {|child| child.accept_descriptor_visitor visitor}
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
class EnumFieldNode < Base
|
172
|
+
def initialize(name, value)
|
173
|
+
@name, @value = name, value
|
174
|
+
end
|
175
|
+
|
176
|
+
def accept_message_visitor(visitor)
|
177
|
+
visitor.write "#{@name} = #{@value}"
|
178
|
+
end
|
179
|
+
|
180
|
+
def accept_descriptor_visitor(visitor)
|
181
|
+
descriptor = Google::Protobuf::EnumValueDescriptorProto.new :name => @name.to_s, :number => @value
|
182
|
+
visitor.enum_value_descriptor = descriptor
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
class ServiceNode < Base
|
187
|
+
def initialize(name, children)
|
188
|
+
@name, @children = name, children
|
189
|
+
end
|
190
|
+
|
191
|
+
def accept_message_visitor(visitor)
|
192
|
+
# do nothing
|
193
|
+
end
|
194
|
+
|
195
|
+
def accept_rpc_visitor(visitor)
|
196
|
+
visitor.current_service = @name
|
197
|
+
@children.each {|child| child.accept_rpc_visitor visitor}
|
198
|
+
end
|
199
|
+
|
200
|
+
def accept_descriptor_visitor(visitor)
|
201
|
+
descriptor = Google::Protobuf::ServiceDescriptorProto.new :name => @name.to_s
|
202
|
+
visitor.service_descriptor = descriptor
|
203
|
+
visitor.in_context descriptor do
|
204
|
+
@children.each {|child| child.accept_descriptor_visitor visitor}
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
class RpcNode < Base
|
210
|
+
def initialize(name, request, response)
|
211
|
+
@name, @request, @response = name, request, response
|
212
|
+
end
|
213
|
+
|
214
|
+
def accept_message_visitor(visitor)
|
215
|
+
# do nothing
|
216
|
+
end
|
217
|
+
|
218
|
+
def accept_rpc_visitor(visitor)
|
219
|
+
visitor.add_rpc @name, @request, @response
|
220
|
+
end
|
221
|
+
|
222
|
+
def accept_descriptor_visitor(visitor)
|
223
|
+
descriptor = Google::Protobuf::MethodDescriptorProto.new :name => @name.to_s, :input_type => @request.to_s, :output_type => @response.to_s
|
224
|
+
visitor.method_descriptor = descriptor
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
class GroupNode < Base
|
229
|
+
def initialize(label, name, value, children)
|
230
|
+
@label, @name, @value, @children = label, name, value, children
|
231
|
+
end
|
232
|
+
|
233
|
+
def accept_message_visitor(visitor)
|
234
|
+
raise NotImplementedError.new
|
235
|
+
end
|
236
|
+
|
237
|
+
def accept_descriptor_visitor(visitor)
|
238
|
+
raise NotImplementedError.new
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
class FieldNode < Base
|
243
|
+
def initialize(label, type, name, value, opts={})
|
244
|
+
@label, @type, @name, @value, @opts = label, type, name, value, opts
|
245
|
+
end
|
246
|
+
|
247
|
+
def accept_message_visitor(visitor)
|
248
|
+
opts = @opts.empty? ? '' : ", #{@opts.map{|k, v| ":#{k} => #{v.inspect}" }.join(', ')}"
|
249
|
+
if visitor.context.first == Protobuf::Node::ExtendNode
|
250
|
+
opts += ', :extension => true'
|
251
|
+
end
|
252
|
+
type = if @type.is_a?(Array)
|
253
|
+
then (@type.size > 1) ? "'#{@type.join '::'}'" : @type[0]
|
254
|
+
else @type
|
255
|
+
end
|
256
|
+
visitor.write "#{@label} :#{type}, :#{@name}, #{@value}#{opts}"
|
257
|
+
end
|
258
|
+
|
259
|
+
def accept_descriptor_visitor(visitor)
|
260
|
+
descriptor = Google::Protobuf::FieldDescriptorProto.new :name => @name.to_s, :number => @value
|
261
|
+
descriptor.label = Google::Protobuf::FieldDescriptorProto::Label.const_get "LABEL_#{@label.to_s.upcase}"
|
262
|
+
descriptor.type = Google::Protobuf::FieldDescriptorProto::Type.const_get "TYPE_#{@type.to_s.upcase}" if predefined_type?
|
263
|
+
descriptor.type_name = @type.is_a?(Array) ? @type.join : @type.to_s
|
264
|
+
@opts.each do |key, val|
|
265
|
+
case key.to_sym
|
266
|
+
when :default
|
267
|
+
descriptor.default_value = val.to_s
|
268
|
+
end
|
269
|
+
end
|
270
|
+
visitor.field_descriptor = descriptor
|
271
|
+
end
|
272
|
+
|
273
|
+
def predefined_type?
|
274
|
+
%w{double float int64 uint64 int32 fixed64 fixed32 bool string group message bytes uint32 enum sfixed32 sfixed64 sint32 sint64}.include? @type.to_s
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
class ExtensionsNode < Base
|
279
|
+
def initialize(range)
|
280
|
+
@range = range
|
281
|
+
end
|
282
|
+
|
283
|
+
def accept_message_visitor(visitor)
|
284
|
+
visitor.write "extensions #{@range.first.to_s}"
|
285
|
+
end
|
286
|
+
|
287
|
+
def accept_descriptor_visitor(visitor)
|
288
|
+
descriptor = Google::Protobuf::DescriptorProto::ExtensionRange.new :start => @range.first.low
|
289
|
+
case @range.first.high
|
290
|
+
when NilClass; # ignore
|
291
|
+
when :max; descriptor.end = 1
|
292
|
+
else; descriptor.end = @range.first.high
|
293
|
+
end
|
294
|
+
visitor.extension_range_descriptor = descriptor
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
class ExtensionRangeNode < Base
|
299
|
+
attr_reader :low, :high
|
300
|
+
|
301
|
+
def initialize(low, high=nil)
|
302
|
+
@low, @high = low, high
|
303
|
+
end
|
304
|
+
|
305
|
+
#def accept_message_visitor(visitor)
|
306
|
+
#end
|
307
|
+
|
308
|
+
def to_s
|
309
|
+
if @high.nil?
|
310
|
+
@low.to_s
|
311
|
+
elsif @high == :max
|
312
|
+
"#{@low}..::Protobuf::Extend::MAX"
|
313
|
+
else
|
314
|
+
"#{@low}..#{@high}"
|
315
|
+
end
|
316
|
+
end
|
317
|
+
end
|
318
|
+
end
|
319
|
+
end
|
@@ -0,0 +1,203 @@
|
|
1
|
+
class Protobuf::ProtoParser
|
2
|
+
#options no_result_var
|
3
|
+
rule
|
4
|
+
proto : proto_item
|
5
|
+
{ result = Protobuf::Node::ProtoNode.new val }
|
6
|
+
| proto proto_item
|
7
|
+
{ result.children << val[1] }
|
8
|
+
|
9
|
+
proto_item : message
|
10
|
+
| extend
|
11
|
+
| enum
|
12
|
+
| import
|
13
|
+
| package
|
14
|
+
| option
|
15
|
+
| service
|
16
|
+
| ';'
|
17
|
+
{ }
|
18
|
+
|
19
|
+
import : 'import' STRING_LITERAL ';'
|
20
|
+
{ result = Protobuf::Node::ImportNode.new val[1] }
|
21
|
+
|
22
|
+
package : 'package' IDENT dot_ident_list ';'
|
23
|
+
{ result = Protobuf::Node::PackageNode.new val[2].unshift(val[1]) }
|
24
|
+
|
25
|
+
dot_ident_list :
|
26
|
+
{ result = [] }
|
27
|
+
| dot_ident_list '.' IDENT
|
28
|
+
{ result << val[2] }
|
29
|
+
|
30
|
+
option : 'option' option_body ';'
|
31
|
+
{ result = Protobuf::Node::OptionNode.new(*val[1]) }
|
32
|
+
|
33
|
+
option_body : IDENT dot_ident_list '=' constant
|
34
|
+
{ result = [val[1].unshift(val[0]), val[3]] }
|
35
|
+
|
36
|
+
message : 'message' IDENT message_body
|
37
|
+
{ result = Protobuf::Node::MessageNode.new val[1], val[2] }
|
38
|
+
|
39
|
+
extend : 'extend' user_type '{' extend_body_list '}'
|
40
|
+
{ result = Protobuf::Node::ExtendNode.new val[1], val[3] }
|
41
|
+
|
42
|
+
extend_body_list :
|
43
|
+
{ result = [] }
|
44
|
+
| extend_body_list extend_body
|
45
|
+
{ result << val[1] }
|
46
|
+
|
47
|
+
extend_body : field
|
48
|
+
| group
|
49
|
+
| ';'
|
50
|
+
{ }
|
51
|
+
|
52
|
+
enum : 'enum' IDENT '{' enum_body_list '}'
|
53
|
+
{ result = Protobuf::Node::EnumNode.new val[1], val[3] }
|
54
|
+
|
55
|
+
enum_body_list :
|
56
|
+
{ result = [] }
|
57
|
+
| enum_body_list enum_body
|
58
|
+
{ result << val[1] }
|
59
|
+
|
60
|
+
enum_body : option
|
61
|
+
| enum_field
|
62
|
+
| ';'
|
63
|
+
{ }
|
64
|
+
|
65
|
+
enum_field : IDENT '=' integer_literal ';'
|
66
|
+
{ result = Protobuf::Node::EnumFieldNode.new val[0], val[2] }
|
67
|
+
|
68
|
+
service : 'service' IDENT '{' service_body_list '}'
|
69
|
+
{ result = Protobuf::Node::ServiceNode.new val[1], val[3] }
|
70
|
+
|
71
|
+
service_body_list :
|
72
|
+
{ result = [] }
|
73
|
+
| service_body_list service_body
|
74
|
+
{ result << val[1] }
|
75
|
+
|
76
|
+
service_body : option
|
77
|
+
| rpc
|
78
|
+
| ';'
|
79
|
+
{ }
|
80
|
+
|
81
|
+
rpc : 'rpc' IDENT '(' rpc_arg ')' 'returns' '(' rpc_arg ')' ';'
|
82
|
+
{ result = Protobuf::Node::RpcNode.new val[1], val[3], val[7] }
|
83
|
+
|
84
|
+
rpc_arg :
|
85
|
+
| user_type
|
86
|
+
|
87
|
+
message_body : '{' message_body_body_list '}'
|
88
|
+
{ result = val[1] }
|
89
|
+
|
90
|
+
message_body_body_list :
|
91
|
+
{ result = [] }
|
92
|
+
| message_body_body_list message_body_body
|
93
|
+
{ result << val[1] }
|
94
|
+
|
95
|
+
message_body_body : field
|
96
|
+
| enum
|
97
|
+
| message
|
98
|
+
| extend
|
99
|
+
| extensions
|
100
|
+
| group
|
101
|
+
| option
|
102
|
+
| ';'
|
103
|
+
{ }
|
104
|
+
|
105
|
+
group : label 'group' CAMEL_IDENT '=' integer_literal message_body
|
106
|
+
{ result = Protobuf::Node::GroupNode.new val[0], val[2], val[4], val[5] }
|
107
|
+
|
108
|
+
field : label type field_name '=' integer_literal ';'
|
109
|
+
{ result = Protobuf::Node::FieldNode.new val[0], val[1], val[2], val[4] }
|
110
|
+
| label type field_name '=' integer_literal '[' field_option_list ']' ';'
|
111
|
+
{ result = Protobuf::Node::FieldNode.new val[0], val[1], val[2], val[4], val[6] }
|
112
|
+
|
113
|
+
field_name : IDENT | "required" | "optional" | "repeated" | "import" | "package" | "option" | "message" | "extend" | "enum" | "service" | "rpc" | "returns" | "group" | "default" | "extensions" | "to" | "max" | "double" | "float" | "int32" | "int64" | "uint32" | "uint64" | "sint32" | "sint64" | "fixed32" | "fixed64" | "sfixed32" | "sfixed64" | "bool" | "string" | "bytes"
|
114
|
+
|
115
|
+
field_option_list : field_option
|
116
|
+
{ result = val }
|
117
|
+
| field_option_list ',' field_option
|
118
|
+
{ result << val[2] }
|
119
|
+
|
120
|
+
field_option : option_body
|
121
|
+
| 'default' '=' constant
|
122
|
+
{ result = [:default, val[2]] }
|
123
|
+
|
124
|
+
extensions : 'extensions' extension comma_extension_list ';'
|
125
|
+
{ result = Protobuf::Node::ExtensionsNode.new val[2].unshift(val[1]) }
|
126
|
+
|
127
|
+
comma_extension_list :
|
128
|
+
{ result = [] }
|
129
|
+
| ',' extension
|
130
|
+
{ result << val[1] }
|
131
|
+
|
132
|
+
extension : integer_literal
|
133
|
+
{ result = Protobuf::Node::ExtensionRangeNode.new val[0] }
|
134
|
+
| integer_literal 'to' integer_literal
|
135
|
+
{ result = Protobuf::Node::ExtensionRangeNode.new val[0], val[2] }
|
136
|
+
| integer_literal 'to' 'max'
|
137
|
+
{ result = Protobuf::Node::ExtensionRangeNode.new val[0], :max }
|
138
|
+
|
139
|
+
label : 'required'
|
140
|
+
| 'optional'
|
141
|
+
| 'repeated'
|
142
|
+
|
143
|
+
type : 'double' | 'float' | 'int32' | 'int64' | 'uint32' | 'uint64'
|
144
|
+
| 'sint32' | 'sint64' | 'fixed32' | 'fixed64' | 'sfixed32' | 'sfixed64'
|
145
|
+
| 'bool' | 'string' | 'bytes' | user_type
|
146
|
+
|
147
|
+
user_type : IDENT dot_ident_list
|
148
|
+
{ result = val[1].unshift(val[0]) }
|
149
|
+
| '.' IDENT dot_ident_list
|
150
|
+
{ result = val[1].unshift(val[0]) }
|
151
|
+
|
152
|
+
constant : IDENT
|
153
|
+
| integer_literal
|
154
|
+
| FLOAT_LITERAL
|
155
|
+
| STRING_LITERAL
|
156
|
+
| BOOLEAN_LITERAL
|
157
|
+
|
158
|
+
integer_literal : DEC_INTEGER
|
159
|
+
| HEX_INTEGER
|
160
|
+
| OCT_INTEGER
|
161
|
+
end
|
162
|
+
|
163
|
+
---- inner
|
164
|
+
|
165
|
+
def parse(f)
|
166
|
+
@q = []
|
167
|
+
f.each do |line|
|
168
|
+
until line.empty? do
|
169
|
+
case line
|
170
|
+
when /\A\s+/, /\A\/\/.*/
|
171
|
+
;
|
172
|
+
when /\A(required|optional|repeated|import|package|option|message|extend|enum|service|rpc|returns|group|default|extensions|to|max|double|float|int32|int64|uint32|uint64|sint32|sint64|fixed32|fixed64|sfixed32|sfixed64|bool|string|bytes)\b/
|
173
|
+
@q.push [$&, $&.to_sym]
|
174
|
+
when /\A[1-9]\d*(?!\.)/, /\A0(?![.xX0-9])/
|
175
|
+
@q.push [:DEC_INTEGER, $&.to_i]
|
176
|
+
when /\A0[xX]([A-Fa-f0-9])+/
|
177
|
+
@q.push [:HEX_INTEGER, $&.to_i(0)]
|
178
|
+
when /\A0[0-7]+/
|
179
|
+
@q.push [:OCT_INTEGER, $&.to_i(0)]
|
180
|
+
when /\A\d+(\.\d+)?([Ee][\+-]?\d+)?/
|
181
|
+
@q.push [:FLOAT_LITERAL, $&.to_f]
|
182
|
+
when /\A(true|false)/
|
183
|
+
@q.push [:BOOLEAN_LITERAL, $& == 'true']
|
184
|
+
when /\A"(?:[^"\\]+|\\.)*"/, /\A'(?:[^'\\]+|\\.)*'/
|
185
|
+
@q.push [:STRING_LITERAL, eval($&)]
|
186
|
+
when /\A[a-zA-Z_][\w_]*/
|
187
|
+
@q.push [:IDENT, $&.to_sym]
|
188
|
+
when /\A[A-Z][\w_]*/
|
189
|
+
@q.push [:CAMEL_IDENT, $&.to_sym]
|
190
|
+
when /\A./
|
191
|
+
@q.push [$&, $&]
|
192
|
+
else
|
193
|
+
raise ArgumentError.new(line)
|
194
|
+
end
|
195
|
+
line = $'
|
196
|
+
end
|
197
|
+
end
|
198
|
+
do_parse
|
199
|
+
end
|
200
|
+
|
201
|
+
def next_token
|
202
|
+
@q.shift
|
203
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# See: http://groups.google.com/group/protobuf/browse_thread/thread/1cccfc624cd612da
|
2
|
+
|
3
|
+
proto ::= ( message | extend | enum | import | package | option | ";" )*
|
4
|
+
|
5
|
+
import ::= "import" strLit ";"
|
6
|
+
|
7
|
+
package ::= "package" ident ( "." ident )* ";"
|
8
|
+
|
9
|
+
option ::= "option" optionBody ";"
|
10
|
+
|
11
|
+
optionBody ::= ident ( "." ident )* "=" constant
|
12
|
+
|
13
|
+
message ::= "message" ident messageBody
|
14
|
+
|
15
|
+
extend ::= "extend" userType "{" ( field | group | ";" )* "}"
|
16
|
+
|
17
|
+
enum ::= "enum" ident "{" ( option | enumField | ";" )* "}"
|
18
|
+
|
19
|
+
enumField ::= ident "=" intLit ";"
|
20
|
+
|
21
|
+
service ::= "service" ident "{" ( option | rpc | ";" )* "}"
|
22
|
+
|
23
|
+
rpc ::= "rpc" ident "(" userType ")" "returns" "(" userType ")" ";"
|
24
|
+
|
25
|
+
messageBody ::= "{" ( field | enum | message | extend | extensions | group | option | ":" )* "}"
|
26
|
+
|
27
|
+
group ::= label "group" camelIdent "=" intLit messageBody
|
28
|
+
|
29
|
+
field ::= label type ident "=" intLit ( "[" fieldOption ( "," fieldOption )* "]" )? ";"
|
30
|
+
# tag number must be 2^29-1 or lower, not 0, and not 19000-19999 (reserved)
|
31
|
+
|
32
|
+
fieldOption ::= optionBody | "default" "=" constant
|
33
|
+
|
34
|
+
# extension numbers must not overlap with field or other extension numbers
|
35
|
+
extensions ::= "extensions" extension ( "," extension )* ";"
|
36
|
+
|
37
|
+
extension ::= intLit ( "to" ( intLit | "max" ) )?
|
38
|
+
|
39
|
+
label ::= "required" | "optional" | "repeated"
|
40
|
+
|
41
|
+
type ::= "double" | "float" | "int32" | "int64" | "uint32" | "uint64"
|
42
|
+
| "sint32" | "sint64" | "fixed32" | "fixed64" | "sfixed32" | "sfixed64"
|
43
|
+
| "bool" | "string" | "bytes" | userType
|
44
|
+
|
45
|
+
# leading dot for identifiers means they're fully qualified
|
46
|
+
userType ::= "."? ident ( "." ident )*
|
47
|
+
|
48
|
+
constant ::= ident | intLit | floatLit | strLit | boolLit
|
49
|
+
|
50
|
+
ident ::= /[A-Za-z_][\w_]*/
|
51
|
+
|
52
|
+
# according to parser.cc, group names must start with a capital letter as a
|
53
|
+
# hack for backwards-compatibility
|
54
|
+
camelIdent ::= /[A-Z][\w_]*/
|
55
|
+
|
56
|
+
intLit ::= decInt | hexInt | octInt
|
57
|
+
|
58
|
+
decInt ::= /[1-9]\d*/
|
59
|
+
|
60
|
+
hexInt ::= /0[xX]([A-Fa-f0-9])+/
|
61
|
+
|
62
|
+
octInt ::= /0[0-7]+/
|
63
|
+
|
64
|
+
# allow_f_after_float_ is disabled by default in tokenizer.cc
|
65
|
+
floatLit ::= /\d+(\.\d+)?([Ee][\+-]?\d+)?/
|
66
|
+
|
67
|
+
boolLit ::= "true" | "false"
|
68
|
+
|
69
|
+
# contents must not contain unescaped quote character
|
70
|
+
strLit ::= quote ( hexEscape | octEscape | charEscape | /[^\0\n]/ )* quote
|
71
|
+
|
72
|
+
quote ::= /["']/
|
73
|
+
|
74
|
+
hexEscape ::= /\\[Xx][A-Fa-f0-9]{1,2}/
|
75
|
+
|
76
|
+
octEscape ::= /\\0?[0-7]{1,3}/
|
77
|
+
|
78
|
+
charEscape ::= /\\[abfnrtv\\\?'"]/
|
79
|
+
|