ruby_protobuf 0.3.2 → 0.3.3
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 +7 -2
- data/Manifest.txt +74 -0
- data/README.txt +1 -1
- data/Rakefile +5 -5
- data/bin/rprotoc +25 -10
- data/{test/proto → examples}/addressbook.pb.rb +1 -14
- 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/compiler/compiler.rb +9 -11
- data/lib/protobuf/compiler/nodes.rb +15 -7
- data/lib/protobuf/compiler/proto.y +56 -36
- data/lib/protobuf/compiler/proto_parser.rb +373 -236
- data/lib/protobuf/compiler/visitors.rb +5 -1
- data/lib/protobuf/descriptor/enum_descriptor.rb +1 -1
- data/lib/protobuf/message/decoder.rb +12 -19
- data/lib/protobuf/message/encoder.rb +5 -2
- data/lib/protobuf/message/enum.rb +1 -1
- data/lib/protobuf/message/field.rb +302 -298
- data/lib/protobuf/message/message.rb +63 -35
- data/lib/ruby_protobuf.rb +1 -1
- data/{bin → script}/mk_parser +0 -0
- data/test/merge.rb +1 -1
- data/test/proto/types.proto +20 -0
- data/test/test_addressbook.rb +1 -0
- data/test/test_compiler.rb +21 -7
- data/test/test_message.rb +19 -0
- data/test/test_optional_field.rb +80 -0
- data/test/test_repeated_types.rb +106 -0
- data/test/test_serialize.rb +34 -0
- data/test/test_standard_message.rb +10 -0
- data/test/test_types.rb +49 -4
- data/test/types.rb +23 -2
- metadata +22 -20
- data/lib/protobuf/compiler/compiler_old.rb +0 -123
- data/test/proto/addressbook.rb +0 -69
- data/test/proto/bool_default.pb.rb +0 -16
- data/test/proto/bool_default.proto +0 -3
- data/test/proto/float_default.proto +0 -2
data/History.txt
CHANGED
@@ -1,6 +1,11 @@
|
|
1
|
-
=== 0.3.
|
1
|
+
=== 0.3.3 / 2009-07-10
|
2
2
|
|
3
|
-
* 0.3.
|
3
|
+
* 0.3.3 (rev.218)
|
4
|
+
* Support C-like comment.
|
5
|
+
* Optimize for speed.
|
6
|
+
* Bug fixes.
|
7
|
+
* 0.3.2 (rev.185)
|
8
|
+
* Bug fixes.
|
4
9
|
* 0.3.1 fixed bugs concerning RPC (rev.146)
|
5
10
|
* 0.3.0 RPC is available (rev.124)
|
6
11
|
* RPC is available
|
data/Manifest.txt
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
History.txt
|
2
|
+
Manifest.txt
|
3
|
+
README.txt
|
4
|
+
Rakefile
|
5
|
+
script/mk_parser
|
6
|
+
bin/rprotoc
|
7
|
+
examples/addressbook.proto
|
8
|
+
examples/addressbook.pb.rb
|
9
|
+
examples/reading_a_message.rb
|
10
|
+
examples/writing_a_message.rb
|
11
|
+
lib/protobuf/common/wire_type.rb
|
12
|
+
lib/protobuf/compiler/compiler.rb
|
13
|
+
lib/protobuf/compiler/nodes.rb
|
14
|
+
lib/protobuf/compiler/proto.y
|
15
|
+
lib/protobuf/compiler/proto2.ebnf
|
16
|
+
lib/protobuf/compiler/proto_parser.rb
|
17
|
+
lib/protobuf/compiler/template/rpc_bin.erb
|
18
|
+
lib/protobuf/compiler/template/rpc_client.erb
|
19
|
+
lib/protobuf/compiler/template/rpc_service.erb
|
20
|
+
lib/protobuf/compiler/visitors.rb
|
21
|
+
lib/protobuf/descriptor/descriptor.proto
|
22
|
+
lib/protobuf/descriptor/descriptor.rb
|
23
|
+
lib/protobuf/descriptor/descriptor_builder.rb
|
24
|
+
lib/protobuf/descriptor/descriptor_proto.rb
|
25
|
+
lib/protobuf/descriptor/enum_descriptor.rb
|
26
|
+
lib/protobuf/descriptor/field_descriptor.rb
|
27
|
+
lib/protobuf/descriptor/file_descriptor.rb
|
28
|
+
lib/protobuf/message/decoder.rb
|
29
|
+
lib/protobuf/message/encoder.rb
|
30
|
+
lib/protobuf/message/enum.rb
|
31
|
+
lib/protobuf/message/extend.rb
|
32
|
+
lib/protobuf/message/field.rb
|
33
|
+
lib/protobuf/message/message.rb
|
34
|
+
lib/protobuf/message/protoable.rb
|
35
|
+
lib/protobuf/message/service.rb
|
36
|
+
lib/protobuf/rpc/client.rb
|
37
|
+
lib/protobuf/rpc/handler.rb
|
38
|
+
lib/protobuf/rpc/server.rb
|
39
|
+
lib/ruby_protobuf.rb
|
40
|
+
test/addressbook.rb
|
41
|
+
test/addressbook_base.rb
|
42
|
+
test/addressbook_ext.rb
|
43
|
+
test/check_unbuild.rb
|
44
|
+
test/collision.rb
|
45
|
+
test/data/data.bin
|
46
|
+
test/data/data_source.py
|
47
|
+
test/data/types.bin
|
48
|
+
test/data/types_source.py
|
49
|
+
test/data/unk.png
|
50
|
+
test/ext_collision.rb
|
51
|
+
test/ext_range.rb
|
52
|
+
test/merge.rb
|
53
|
+
test/nested.rb
|
54
|
+
test/proto/addressbook.proto
|
55
|
+
test/proto/addressbook_base.proto
|
56
|
+
test/proto/addressbook_ext.proto
|
57
|
+
test/proto/collision.proto
|
58
|
+
test/proto/ext_collision.proto
|
59
|
+
test/proto/ext_range.proto
|
60
|
+
test/proto/merge.proto
|
61
|
+
test/proto/nested.proto
|
62
|
+
test/proto/rpc.proto
|
63
|
+
test/proto/types.proto
|
64
|
+
test/test_addressbook.rb
|
65
|
+
test/test_compiler.rb
|
66
|
+
test/test_descriptor.rb
|
67
|
+
test/test_extension.rb
|
68
|
+
test/test_message.rb
|
69
|
+
test/test_parse.rb
|
70
|
+
test/test_ruby_protobuf.rb
|
71
|
+
test/test_serialize.rb
|
72
|
+
test/test_standard_message.rb
|
73
|
+
test/test_types.rb
|
74
|
+
test/types.rb
|
data/README.txt
CHANGED
data/Rakefile
CHANGED
@@ -5,14 +5,14 @@ require 'rubygems'
|
|
5
5
|
require 'hoe'
|
6
6
|
require 'ruby_protobuf'
|
7
7
|
|
8
|
-
Hoe.
|
8
|
+
Hoe.spec('ruby_protobuf') do |p|
|
9
|
+
p.version = RubyProtobuf::VERSION
|
9
10
|
p.rubyforge_name = 'ruby-protobuf'
|
10
|
-
p.
|
11
|
-
p.email = 'andyjpn@gmail.com'
|
11
|
+
p.developer('MATSUYAMA Kengo', 'macksx@gmail.com')
|
12
12
|
p.summary = 'Protocol Buffers for Ruby'
|
13
13
|
p.description = p.paragraphs_of('README.txt', 2..5).join("\n\n")
|
14
|
-
p.url =
|
14
|
+
p.url = 'http://code.google.com/p/ruby-protobuf'
|
15
15
|
p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
|
16
16
|
end
|
17
17
|
|
18
|
-
# vim: syntax=
|
18
|
+
# vim: syntax=ruby
|
data/bin/rprotoc
CHANGED
@@ -1,21 +1,36 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
$: << "#{File.dirname(__FILE__)}/../lib"
|
3
2
|
require 'optparse'
|
3
|
+
if File.exist? "#{File.dirname(__FILE__)}/../lib"
|
4
|
+
$: << "#{File.dirname(__FILE__)}/../lib"
|
5
|
+
else
|
6
|
+
require 'rubygems'
|
7
|
+
gem 'ruby_protobuf'
|
8
|
+
end
|
4
9
|
require 'ruby_protobuf'
|
5
|
-
#require 'protobuf/compiler/compiler_old'
|
6
10
|
require 'protobuf/compiler/compiler'
|
7
11
|
|
8
12
|
|
9
|
-
|
10
|
-
|
11
|
-
opts =
|
12
|
-
opts.on('-
|
13
|
-
opts.on('-o', '--out <OUT_DIR>', 'Specify the directory in which Ruby source file is generated. The current directory is default.'){|v| OPT[:out] = v}
|
13
|
+
options = {}
|
14
|
+
opts = OptionParser.new("#{$0} [OPTIONS] PROTO_FILE")
|
15
|
+
opts.on('-p', '--proto_path <PATH>', 'Specify the directory in which to search for imports. The current directory is default.'){|v| options[:proto_path] = v}
|
16
|
+
opts.on('-o', '--out <OUT_DIR>', 'Specify the directory in which Ruby source file is generated. The current directory is default.'){|v| options[:out] = v}
|
14
17
|
opts.on_tail('-v', '--version', 'Show version.'){puts(opts.ver); exit}
|
15
18
|
opts.on_tail('-h', '--help', 'Show this message.'){puts(opts.help); exit}
|
16
19
|
|
17
20
|
::Version = RubyProtobuf::VERSION
|
18
|
-
opts.order! ARGV
|
19
|
-
PROTO_FILE = ARGV.shift
|
20
21
|
|
21
|
-
|
22
|
+
begin
|
23
|
+
opts.order! ARGV
|
24
|
+
rescue OptionParser::ParseError
|
25
|
+
$stderr.puts $!.to_s
|
26
|
+
exit 1
|
27
|
+
end
|
28
|
+
|
29
|
+
proto_file = ARGV.shift
|
30
|
+
|
31
|
+
unless proto_file
|
32
|
+
puts opts
|
33
|
+
exit
|
34
|
+
end
|
35
|
+
|
36
|
+
Protobuf::Compiler.compile(proto_file, (options[:proto_path] or '.'), (options[:out] or '.'))
|
@@ -1,5 +1,5 @@
|
|
1
1
|
### Generated by rprotoc. DO NOT EDIT!
|
2
|
-
### <proto file:
|
2
|
+
### <proto file: examples/addressbook.proto>
|
3
3
|
# package tutorial;
|
4
4
|
#
|
5
5
|
# message Person {
|
@@ -19,13 +19,6 @@
|
|
19
19
|
# }
|
20
20
|
#
|
21
21
|
# repeated PhoneNumber phone = 4;
|
22
|
-
# optional uint32 age = 5 [default = 20];
|
23
|
-
#
|
24
|
-
# extensions 100 to 200;
|
25
|
-
# }
|
26
|
-
#
|
27
|
-
# extend Person {
|
28
|
-
# optional int32 age = 100;
|
29
22
|
# }
|
30
23
|
#
|
31
24
|
# message AddressBook {
|
@@ -55,12 +48,6 @@ module Tutorial
|
|
55
48
|
optional :PhoneType, :type, 2, :default => :HOME
|
56
49
|
end
|
57
50
|
repeated :PhoneNumber, :phone, 4
|
58
|
-
optional :uint32, :age, 5, :default => 20
|
59
|
-
extensions 100..200
|
60
|
-
end
|
61
|
-
class Person < ::Protobuf::Message
|
62
|
-
defined_in __FILE__
|
63
|
-
optional :int32, :age, 100, :extension => true
|
64
51
|
end
|
65
52
|
class AddressBook < ::Protobuf::Message
|
66
53
|
defined_in __FILE__
|
@@ -0,0 +1,24 @@
|
|
1
|
+
package tutorial;
|
2
|
+
|
3
|
+
message Person {
|
4
|
+
required string name = 1;
|
5
|
+
required int32 id = 2;
|
6
|
+
optional string email = 3;
|
7
|
+
|
8
|
+
enum PhoneType {
|
9
|
+
MOBILE = 0;
|
10
|
+
HOME = 1;
|
11
|
+
WORK = 2;
|
12
|
+
}
|
13
|
+
|
14
|
+
message PhoneNumber {
|
15
|
+
required string number = 1;
|
16
|
+
optional PhoneType type = 2 [default = HOME];
|
17
|
+
}
|
18
|
+
|
19
|
+
repeated PhoneNumber phone = 4;
|
20
|
+
}
|
21
|
+
|
22
|
+
message AddressBook {
|
23
|
+
repeated Person person = 1;
|
24
|
+
}
|
@@ -0,0 +1,32 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'addressbook.pb'
|
4
|
+
|
5
|
+
def list_people(address_book)
|
6
|
+
address_book.person.each do |person|
|
7
|
+
puts "Person ID: #{person.id}"
|
8
|
+
puts " Name: #{person.name}"
|
9
|
+
puts " E-mail: #{person.email}" unless person.email.empty?
|
10
|
+
person.phone.each do |phone_number|
|
11
|
+
print(case phone_number.type
|
12
|
+
when Tutorial::Person::PhoneType::MOBILE
|
13
|
+
' Mobile phone #: '
|
14
|
+
when Tutorial::Person::PhoneType::HOME
|
15
|
+
' Home phone #: '
|
16
|
+
when Tutorial::Person::PhoneType::WORK
|
17
|
+
' Work phone #: '
|
18
|
+
end)
|
19
|
+
puts phone_number.number
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
unless ARGV.size == 1
|
25
|
+
puts "Usage: #{$0} ADDRESS_BOOK_FILE"
|
26
|
+
exit
|
27
|
+
end
|
28
|
+
|
29
|
+
address_book = Tutorial::AddressBook.new
|
30
|
+
address_book.parse_from_file ARGV[0]
|
31
|
+
|
32
|
+
list_people address_book
|
@@ -0,0 +1,46 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'addressbook.pb'
|
4
|
+
|
5
|
+
def prompt_for_address(person)
|
6
|
+
print 'Enter person ID number: '
|
7
|
+
person.id = STDIN.gets.strip.to_i
|
8
|
+
print 'Enter name: '
|
9
|
+
person.name = STDIN.gets.strip
|
10
|
+
print 'Enter email address (blank for none): '
|
11
|
+
email = STDIN.gets.strip
|
12
|
+
person.email = email unless email.empty?
|
13
|
+
|
14
|
+
loop do
|
15
|
+
print 'Enter a phone number (or leave blank to finish): '
|
16
|
+
break if (number = STDIN.gets.strip).empty?
|
17
|
+
|
18
|
+
person.phone << Tutorial::Person::PhoneNumber.new
|
19
|
+
person.phone.last.number = number
|
20
|
+
|
21
|
+
print 'Is this a mobile, home, or work phone? '
|
22
|
+
person.phone.last.type =
|
23
|
+
case type = STDIN.gets.strip
|
24
|
+
when 'mobile'
|
25
|
+
Tutorial::Person::PhoneType::MOBILE
|
26
|
+
when 'home'
|
27
|
+
Tutorial::Person::PhoneType::HOME
|
28
|
+
when 'work'
|
29
|
+
Tutorial::Person::PhoneType::WORK
|
30
|
+
else
|
31
|
+
puts 'Unknown phone type; leaving as default value.'
|
32
|
+
nil
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
unless ARGV.size == 1
|
38
|
+
puts "Usage: #{$0} ADDRESS_BOOK_FILE"
|
39
|
+
exit
|
40
|
+
end
|
41
|
+
|
42
|
+
address_book = Tutorial::AddressBook.new
|
43
|
+
address_book.parse_from_file ARGV[0] if File.exist? ARGV[0]
|
44
|
+
address_book.person << Tutorial::Person.new
|
45
|
+
prompt_for_address address_book.person.last
|
46
|
+
address_book.serialize_to_file ARGV[0]
|
@@ -15,12 +15,7 @@ module Protobuf
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def create_message(proto_file, proto_dir='.', out_dir='.', file_create=true)
|
18
|
-
out_dir.sub
|
19
|
-
proto_dir.sub! %r{/$}, ''
|
20
|
-
rb_file =
|
21
|
-
if proto_file =~ %r{^/}
|
22
|
-
then "#{out_dir}/#{proto_file.split('/').last.sub(/\.proto$/, '.pb.rb')}"
|
23
|
-
else "#{out_dir}/#{proto_file.sub(/\.proto$/, '.pb.rb')}" end
|
18
|
+
rb_file = File.join(out_dir, File.basename(proto_file).sub(/\.[^\0]*\z/, '') + '.pb.rb')
|
24
19
|
proto_path = validate_existence proto_file, proto_dir
|
25
20
|
|
26
21
|
message_visitor = Protobuf::Visitor::CreateMessageVisitor.new proto_file, proto_dir, out_dir
|
@@ -31,8 +26,7 @@ module Protobuf
|
|
31
26
|
end
|
32
27
|
|
33
28
|
def create_rpc(proto_file, proto_dir='.', out_dir='.', file_create=true)
|
34
|
-
message_file =
|
35
|
-
out_dir = "#{out_dir}/#{File.dirname proto_file}"
|
29
|
+
message_file = File.join(out_dir, File.basename(proto_file).sub(/\.[^\0]*\z/, '') + '.pb.rb')
|
36
30
|
proto_path = validate_existence proto_file, proto_dir
|
37
31
|
|
38
32
|
rpc_visitor = Protobuf::Visitor::CreateRpcVisitor.new
|
@@ -44,11 +38,15 @@ module Protobuf
|
|
44
38
|
|
45
39
|
def validate_existence(path, base_dir)
|
46
40
|
if File.exist? path
|
47
|
-
|
41
|
+
path
|
48
42
|
else
|
49
|
-
|
43
|
+
newpath = File.join(base_dir, path)
|
44
|
+
if File.exist? newpath
|
45
|
+
newpath
|
46
|
+
else
|
47
|
+
raise ArgumentError.new("File does not exist: #{path}")
|
48
|
+
end
|
50
49
|
end
|
51
|
-
path
|
52
50
|
end
|
53
51
|
end
|
54
52
|
end
|
@@ -106,10 +106,14 @@ require 'protobuf/message/extend'
|
|
106
106
|
end
|
107
107
|
|
108
108
|
def accept_message_visitor(visitor)
|
109
|
-
|
109
|
+
class_name = @name.to_s
|
110
|
+
class_name.gsub!(/\A[a-z]/) {|c| c.upcase}
|
111
|
+
visitor.write "class #{class_name} < ::Protobuf::Message"
|
110
112
|
visitor.in_context self.class do
|
111
113
|
define_in_the_file visitor
|
112
|
-
|
114
|
+
#@children.each {|child| child.accept_message_visitor visitor}
|
115
|
+
@children.each {|child| next if child == ';'; child.accept_message_visitor visitor}
|
116
|
+
# TODO: `next if child == ';';' is a monky patching. There must be a parser error.
|
113
117
|
end
|
114
118
|
visitor.write "end"
|
115
119
|
end
|
@@ -129,7 +133,8 @@ require 'protobuf/message/extend'
|
|
129
133
|
end
|
130
134
|
|
131
135
|
def accept_message_visitor(visitor)
|
132
|
-
|
136
|
+
name = @name.is_a?(Array) ? @name.join : name.to_s
|
137
|
+
visitor.write "class #{name} < ::Protobuf::Message"
|
133
138
|
visitor.in_context self.class do
|
134
139
|
define_in_the_file visitor
|
135
140
|
@children.each {|child| child.accept_message_visitor visitor}
|
@@ -246,7 +251,10 @@ require 'protobuf/message/extend'
|
|
246
251
|
if visitor.context.first == Protobuf::Node::ExtendNode
|
247
252
|
opts += ', :extension => true'
|
248
253
|
end
|
249
|
-
type =
|
254
|
+
type = if @type.is_a?(Array)
|
255
|
+
then (@type.size > 1) ? "'#{@type.join '::'}'" : @type[0]
|
256
|
+
else @type
|
257
|
+
end
|
250
258
|
visitor.write "#{@label} :#{type}, :#{@name}, #{@value}#{opts}"
|
251
259
|
end
|
252
260
|
|
@@ -254,7 +262,7 @@ require 'protobuf/message/extend'
|
|
254
262
|
descriptor = Google::Protobuf::FieldDescriptorProto.new :name => @name.to_s, :number => @value
|
255
263
|
descriptor.label = Google::Protobuf::FieldDescriptorProto::Label.const_get "LABEL_#{@label.to_s.upcase}"
|
256
264
|
descriptor.type = Google::Protobuf::FieldDescriptorProto::Type.const_get "TYPE_#{@type.to_s.upcase}" if predefined_type?
|
257
|
-
descriptor.type_name = @type.to_s
|
265
|
+
descriptor.type_name = @type.is_a?(Array) ? @type.join : @type.to_s
|
258
266
|
@opts.each do |key, val|
|
259
267
|
case key.to_sym
|
260
268
|
when :default
|
@@ -275,7 +283,7 @@ require 'protobuf/message/extend'
|
|
275
283
|
end
|
276
284
|
|
277
285
|
def accept_message_visitor(visitor)
|
278
|
-
visitor.write "extensions #{@range.to_s}"
|
286
|
+
visitor.write "extensions #{@range.first.to_s}"
|
279
287
|
end
|
280
288
|
|
281
289
|
def accept_descriptor_visitor(visitor)
|
@@ -303,7 +311,7 @@ require 'protobuf/message/extend'
|
|
303
311
|
if @high.nil?
|
304
312
|
@low.to_s
|
305
313
|
elsif @high == :max
|
306
|
-
"#{@low}
|
314
|
+
"#{@low}..::Protobuf::Extend::MAX"
|
307
315
|
else
|
308
316
|
"#{@low}..#{@high}"
|
309
317
|
end
|
@@ -1,5 +1,4 @@
|
|
1
1
|
class Protobuf::ProtoParser
|
2
|
-
#options no_result_var
|
3
2
|
rule
|
4
3
|
proto : proto_item
|
5
4
|
{ result = Protobuf::Node::ProtoNode.new val }
|
@@ -105,11 +104,13 @@ rule
|
|
105
104
|
group : label 'group' CAMEL_IDENT '=' integer_literal message_body
|
106
105
|
{ result = Protobuf::Node::GroupNode.new val[0], val[2], val[4], val[5] }
|
107
106
|
|
108
|
-
field : label type
|
107
|
+
field : label type field_name '=' integer_literal ';'
|
109
108
|
{ result = Protobuf::Node::FieldNode.new val[0], val[1], val[2], val[4] }
|
110
|
-
| label type
|
109
|
+
| label type field_name '=' integer_literal '[' field_option_list ']' ';'
|
111
110
|
{ result = Protobuf::Node::FieldNode.new val[0], val[1], val[2], val[4], val[6] }
|
112
111
|
|
112
|
+
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"
|
113
|
+
|
113
114
|
field_option_list : field_option
|
114
115
|
{ result = val }
|
115
116
|
| field_option_list ',' field_option
|
@@ -160,42 +161,61 @@ end
|
|
160
161
|
|
161
162
|
---- inner
|
162
163
|
|
164
|
+
require 'strscan'
|
165
|
+
|
163
166
|
def parse(f)
|
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
|
-
|
167
|
+
@scanner = StringScanner.new(f.read)
|
168
|
+
yyparse(self, :scan)
|
169
|
+
end
|
170
|
+
|
171
|
+
def scan_debug
|
172
|
+
scan do |token, value|
|
173
|
+
p [token, value]
|
174
|
+
yield [token, value]
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
def scan
|
179
|
+
until @scanner.eos?
|
180
|
+
case
|
181
|
+
when match(/\s+/, /\/\/.*/)
|
182
|
+
# skip
|
183
|
+
when match(/\/\*/)
|
184
|
+
# C-like comment
|
185
|
+
raise 'EOF inside block comment' until @scanner.scan_until(/\*\//)
|
186
|
+
when match(/(?: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/)
|
187
|
+
yield [@token, @token.to_sym]
|
188
|
+
when match(/[+-]?\d*\.\d+([Ee][\+-]?\d+)?/)
|
189
|
+
yield [:FLOAT_LITERAL, @token.to_f]
|
190
|
+
when match(/[+-]?[1-9]\d*(?!\.)/, /0(?![.xX0-9])/)
|
191
|
+
yield [:DEC_INTEGER, @token.to_i]
|
192
|
+
when match(/0[xX]([A-Fa-f0-9])+/)
|
193
|
+
yield [:HEX_INTEGER, @token.to_i(0)]
|
194
|
+
when match(/0[0-7]+/)
|
195
|
+
yield [:OCT_INTEGER, @token.to_i(0)]
|
196
|
+
when match(/(true|false)\b/)
|
197
|
+
yield [:BOOLEAN_LITERAL, @token == 'true']
|
198
|
+
when match(/"(?:[^"\\]+|\\.)*"/, /'(?:[^'\\]+|\\.)*'/)
|
199
|
+
yield [:STRING_LITERAL, eval(@token)]
|
200
|
+
when match(/[a-zA-Z_][\w_]*/)
|
201
|
+
yield [:IDENT, @token.to_sym]
|
202
|
+
when match(/[A-Z][\w_]*/)
|
203
|
+
yield [:CAMEL_IDENT, @token.to_sym]
|
204
|
+
when match(/./)
|
205
|
+
yield [@token, @token]
|
206
|
+
else
|
207
|
+
raise "parse error around #{@scanner.string[@scanner.pos, 32].inspect}"
|
194
208
|
end
|
195
209
|
end
|
196
|
-
|
210
|
+
yield [false, nil]
|
197
211
|
end
|
198
212
|
|
199
|
-
def
|
200
|
-
|
213
|
+
def match(*regular_expressions)
|
214
|
+
regular_expressions.each do |re|
|
215
|
+
if @scanner.scan(re)
|
216
|
+
@token = @scanner[0]
|
217
|
+
return true
|
218
|
+
end
|
219
|
+
end
|
220
|
+
false
|
201
221
|
end
|