blob: 34317b1fd94fb0c162f1ae85766185f5f3d9a57c [file] [log] [blame]
temporal40ee5512008-07-10 02:12:20 +00001// Protocol Buffers - Google's data interchange format
kenton@google.com24bf56f2008-09-24 20:31:01 +00002// Copyright 2008 Google Inc. All rights reserved.
temporal40ee5512008-07-10 02:12:20 +00003// http://code.google.com/p/protobuf/
4//
kenton@google.com24bf56f2008-09-24 20:31:01 +00005// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
temporal40ee5512008-07-10 02:12:20 +00008//
kenton@google.com24bf56f2008-09-24 20:31:01 +00009// * Redistributions of source code must retain the above copyright
10// notice, this list of conditions and the following disclaimer.
11// * Redistributions in binary form must reproduce the above
12// copyright notice, this list of conditions and the following disclaimer
13// in the documentation and/or other materials provided with the
14// distribution.
15// * Neither the name of Google Inc. nor the names of its
16// contributors may be used to endorse or promote products derived from
17// this software without specific prior written permission.
temporal40ee5512008-07-10 02:12:20 +000018//
kenton@google.com24bf56f2008-09-24 20:31:01 +000019// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
temporal40ee5512008-07-10 02:12:20 +000030
31// Author: kenton@google.com (Kenton Varda)
32// Based on original Protocol Buffers design by
33// Sanjay Ghemawat, Jeff Dean, and others.
34//
35// Recursive descent FTW.
36
temporal40ee5512008-07-10 02:12:20 +000037#include <float.h>
kenton@google.comfccb1462009-12-18 02:11:36 +000038#include <google/protobuf/stubs/hash.h>
39#include <limits>
temporal40ee5512008-07-10 02:12:20 +000040
41
42#include <google/protobuf/compiler/parser.h>
43#include <google/protobuf/descriptor.h>
44#include <google/protobuf/descriptor.pb.h>
45#include <google/protobuf/wire_format.h>
46#include <google/protobuf/io/tokenizer.h>
47#include <google/protobuf/stubs/common.h>
48#include <google/protobuf/stubs/strutil.h>
49#include <google/protobuf/stubs/map-util.h>
50
51namespace google {
52namespace protobuf {
53namespace compiler {
54
55using internal::WireFormat;
56
57namespace {
58
59typedef hash_map<string, FieldDescriptorProto::Type> TypeNameMap;
60
61TypeNameMap MakeTypeNameTable() {
62 TypeNameMap result;
63
64 result["double" ] = FieldDescriptorProto::TYPE_DOUBLE;
65 result["float" ] = FieldDescriptorProto::TYPE_FLOAT;
66 result["uint64" ] = FieldDescriptorProto::TYPE_UINT64;
67 result["fixed64" ] = FieldDescriptorProto::TYPE_FIXED64;
68 result["fixed32" ] = FieldDescriptorProto::TYPE_FIXED32;
69 result["bool" ] = FieldDescriptorProto::TYPE_BOOL;
70 result["string" ] = FieldDescriptorProto::TYPE_STRING;
71 result["group" ] = FieldDescriptorProto::TYPE_GROUP;
72
73 result["bytes" ] = FieldDescriptorProto::TYPE_BYTES;
74 result["uint32" ] = FieldDescriptorProto::TYPE_UINT32;
75 result["sfixed32"] = FieldDescriptorProto::TYPE_SFIXED32;
76 result["sfixed64"] = FieldDescriptorProto::TYPE_SFIXED64;
77 result["int32" ] = FieldDescriptorProto::TYPE_INT32;
78 result["int64" ] = FieldDescriptorProto::TYPE_INT64;
79 result["sint32" ] = FieldDescriptorProto::TYPE_SINT32;
80 result["sint64" ] = FieldDescriptorProto::TYPE_SINT64;
81
82 return result;
83}
84
85const TypeNameMap kTypeNames = MakeTypeNameTable();
86
87} // anonymous namespace
88
89// Makes code slightly more readable. The meaning of "DO(foo)" is
90// "Execute foo and fail if it fails.", where failure is indicated by
91// returning false.
92#define DO(STATEMENT) if (STATEMENT) {} else return false
93
94// ===================================================================
95
96Parser::Parser()
97 : input_(NULL),
98 error_collector_(NULL),
99 source_location_table_(NULL),
100 had_errors_(false),
kenton@google.comd37d46d2009-04-25 02:53:47 +0000101 require_syntax_identifier_(false),
102 stop_after_syntax_identifier_(false) {
temporal40ee5512008-07-10 02:12:20 +0000103}
104
105Parser::~Parser() {
106}
107
108// ===================================================================
109
110inline bool Parser::LookingAt(const char* text) {
111 return input_->current().text == text;
112}
113
114inline bool Parser::LookingAtType(io::Tokenizer::TokenType token_type) {
115 return input_->current().type == token_type;
116}
117
118inline bool Parser::AtEnd() {
119 return LookingAtType(io::Tokenizer::TYPE_END);
120}
121
122bool Parser::TryConsume(const char* text) {
123 if (LookingAt(text)) {
124 input_->Next();
125 return true;
126 } else {
127 return false;
128 }
129}
130
131bool Parser::Consume(const char* text, const char* error) {
132 if (TryConsume(text)) {
133 return true;
134 } else {
135 AddError(error);
136 return false;
137 }
138}
139
140bool Parser::Consume(const char* text) {
141 if (TryConsume(text)) {
142 return true;
143 } else {
144 AddError("Expected \"" + string(text) + "\".");
145 return false;
146 }
147}
148
149bool Parser::ConsumeIdentifier(string* output, const char* error) {
150 if (LookingAtType(io::Tokenizer::TYPE_IDENTIFIER)) {
151 *output = input_->current().text;
152 input_->Next();
153 return true;
154 } else {
155 AddError(error);
156 return false;
157 }
158}
159
160bool Parser::ConsumeInteger(int* output, const char* error) {
161 if (LookingAtType(io::Tokenizer::TYPE_INTEGER)) {
162 uint64 value = 0;
163 if (!io::Tokenizer::ParseInteger(input_->current().text,
164 kint32max, &value)) {
165 AddError("Integer out of range.");
166 // We still return true because we did, in fact, parse an integer.
167 }
168 *output = value;
169 input_->Next();
170 return true;
171 } else {
172 AddError(error);
173 return false;
174 }
175}
176
177bool Parser::ConsumeInteger64(uint64 max_value, uint64* output,
178 const char* error) {
179 if (LookingAtType(io::Tokenizer::TYPE_INTEGER)) {
180 if (!io::Tokenizer::ParseInteger(input_->current().text, max_value,
181 output)) {
182 AddError("Integer out of range.");
183 // We still return true because we did, in fact, parse an integer.
184 *output = 0;
185 }
186 input_->Next();
187 return true;
188 } else {
189 AddError(error);
190 return false;
191 }
192}
193
194bool Parser::ConsumeNumber(double* output, const char* error) {
195 if (LookingAtType(io::Tokenizer::TYPE_FLOAT)) {
196 *output = io::Tokenizer::ParseFloat(input_->current().text);
197 input_->Next();
198 return true;
199 } else if (LookingAtType(io::Tokenizer::TYPE_INTEGER)) {
200 // Also accept integers.
201 uint64 value = 0;
202 if (!io::Tokenizer::ParseInteger(input_->current().text,
203 kuint64max, &value)) {
204 AddError("Integer out of range.");
205 // We still return true because we did, in fact, parse a number.
206 }
207 *output = value;
208 input_->Next();
209 return true;
kenton@google.comfccb1462009-12-18 02:11:36 +0000210 } else if (LookingAt("inf")) {
211 *output = numeric_limits<double>::infinity();
212 input_->Next();
213 return true;
214 } else if (LookingAt("nan")) {
215 *output = numeric_limits<double>::quiet_NaN();
216 input_->Next();
217 return true;
temporal40ee5512008-07-10 02:12:20 +0000218 } else {
219 AddError(error);
220 return false;
221 }
222}
223
224bool Parser::ConsumeString(string* output, const char* error) {
225 if (LookingAtType(io::Tokenizer::TYPE_STRING)) {
226 io::Tokenizer::ParseString(input_->current().text, output);
227 input_->Next();
kenton@google.com26bd9ee2008-11-21 00:06:27 +0000228 // Allow C++ like concatenation of adjacent string tokens.
229 while (LookingAtType(io::Tokenizer::TYPE_STRING)) {
230 io::Tokenizer::ParseStringAppend(input_->current().text, output);
231 input_->Next();
232 }
temporal40ee5512008-07-10 02:12:20 +0000233 return true;
234 } else {
235 AddError(error);
236 return false;
237 }
238}
239
240// -------------------------------------------------------------------
241
242void Parser::AddError(int line, int column, const string& error) {
243 if (error_collector_ != NULL) {
244 error_collector_->AddError(line, column, error);
245 }
246 had_errors_ = true;
247}
248
249void Parser::AddError(const string& error) {
250 AddError(input_->current().line, input_->current().column, error);
251}
252
liujisi@google.com33165fe2010-11-02 13:14:58 +0000253// -------------------------------------------------------------------
254
255Parser::LocationRecorder::LocationRecorder(Parser* parser)
256 : parser_(parser),
257 location_(parser_->source_code_info_->add_location()) {
258 location_->add_span(parser_->input_->current().line);
259 location_->add_span(parser_->input_->current().column);
260}
261
262Parser::LocationRecorder::LocationRecorder(const LocationRecorder& parent) {
263 Init(parent);
264}
265
266Parser::LocationRecorder::LocationRecorder(const LocationRecorder& parent,
267 int path1) {
268 Init(parent);
269 AddPath(path1);
270}
271
272Parser::LocationRecorder::LocationRecorder(const LocationRecorder& parent,
273 int path1, int path2) {
274 Init(parent);
275 AddPath(path1);
276 AddPath(path2);
277}
278
279void Parser::LocationRecorder::Init(const LocationRecorder& parent) {
280 parser_ = parent.parser_;
281 location_ = parser_->source_code_info_->add_location();
282 location_->mutable_path()->CopyFrom(parent.location_->path());
283
284 location_->add_span(parser_->input_->current().line);
285 location_->add_span(parser_->input_->current().column);
286}
287
288Parser::LocationRecorder::~LocationRecorder() {
289 if (location_->span_size() <= 2) {
290 EndAt(parser_->input_->previous());
temporal40ee5512008-07-10 02:12:20 +0000291 }
292}
293
liujisi@google.com33165fe2010-11-02 13:14:58 +0000294void Parser::LocationRecorder::AddPath(int path_component) {
295 location_->add_path(path_component);
296}
297
298void Parser::LocationRecorder::StartAt(const io::Tokenizer::Token& token) {
299 location_->set_span(0, token.line);
300 location_->set_span(1, token.column);
301}
302
303void Parser::LocationRecorder::EndAt(const io::Tokenizer::Token& token) {
304 if (token.line != location_->span(0)) {
305 location_->add_span(token.line);
306 }
307 location_->add_span(token.end_column);
308}
309
310void Parser::LocationRecorder::RecordLegacyLocation(const Message* descriptor,
temporal40ee5512008-07-10 02:12:20 +0000311 DescriptorPool::ErrorCollector::ErrorLocation location) {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000312 if (parser_->source_location_table_ != NULL) {
313 parser_->source_location_table_->Add(
314 descriptor, location, location_->span(0), location_->span(1));
315 }
temporal40ee5512008-07-10 02:12:20 +0000316}
317
318// -------------------------------------------------------------------
319
320void Parser::SkipStatement() {
321 while (true) {
322 if (AtEnd()) {
323 return;
324 } else if (LookingAtType(io::Tokenizer::TYPE_SYMBOL)) {
325 if (TryConsume(";")) {
326 return;
327 } else if (TryConsume("{")) {
328 SkipRestOfBlock();
329 return;
330 } else if (LookingAt("}")) {
331 return;
332 }
333 }
334 input_->Next();
335 }
336}
337
338void Parser::SkipRestOfBlock() {
339 while (true) {
340 if (AtEnd()) {
341 return;
342 } else if (LookingAtType(io::Tokenizer::TYPE_SYMBOL)) {
343 if (TryConsume("}")) {
344 return;
345 } else if (TryConsume("{")) {
346 SkipRestOfBlock();
347 }
348 }
349 input_->Next();
350 }
351}
352
353// ===================================================================
354
355bool Parser::Parse(io::Tokenizer* input, FileDescriptorProto* file) {
356 input_ = input;
357 had_errors_ = false;
358 syntax_identifier_.clear();
359
liujisi@google.com33165fe2010-11-02 13:14:58 +0000360 // Note that |file| could be NULL at this point if
361 // stop_after_syntax_identifier_ is true. So, we conservatively allocate
362 // SourceCodeInfo on the stack, then swap it into the FileDescriptorProto
363 // later on.
364 SourceCodeInfo source_code_info;
365 source_code_info_ = &source_code_info;
366
temporal40ee5512008-07-10 02:12:20 +0000367 if (LookingAtType(io::Tokenizer::TYPE_START)) {
368 // Advance to first token.
369 input_->Next();
370 }
371
liujisi@google.com33165fe2010-11-02 13:14:58 +0000372 {
373 LocationRecorder root_location(this);
374
375 if (require_syntax_identifier_ || LookingAt("syntax")) {
376 if (!ParseSyntaxIdentifier()) {
377 // Don't attempt to parse the file if we didn't recognize the syntax
378 // identifier.
379 return false;
380 }
381 } else if (!stop_after_syntax_identifier_) {
382 syntax_identifier_ = "proto2";
temporal40ee5512008-07-10 02:12:20 +0000383 }
temporal40ee5512008-07-10 02:12:20 +0000384
liujisi@google.com33165fe2010-11-02 13:14:58 +0000385 if (stop_after_syntax_identifier_) return !had_errors_;
kenton@google.comd37d46d2009-04-25 02:53:47 +0000386
liujisi@google.com33165fe2010-11-02 13:14:58 +0000387 // Repeatedly parse statements until we reach the end of the file.
388 while (!AtEnd()) {
389 if (!ParseTopLevelStatement(file, root_location)) {
390 // This statement failed to parse. Skip it, but keep looping to parse
391 // other statements.
392 SkipStatement();
temporal40ee5512008-07-10 02:12:20 +0000393
liujisi@google.com33165fe2010-11-02 13:14:58 +0000394 if (LookingAt("}")) {
395 AddError("Unmatched \"}\".");
396 input_->Next();
397 }
temporal40ee5512008-07-10 02:12:20 +0000398 }
399 }
400 }
401
402 input_ = NULL;
liujisi@google.com33165fe2010-11-02 13:14:58 +0000403 source_code_info_ = NULL;
404 source_code_info.Swap(file->mutable_source_code_info());
temporal40ee5512008-07-10 02:12:20 +0000405 return !had_errors_;
406}
407
408bool Parser::ParseSyntaxIdentifier() {
409 DO(Consume("syntax", "File must begin with 'syntax = \"proto2\";'."));
410 DO(Consume("="));
411 io::Tokenizer::Token syntax_token = input_->current();
412 string syntax;
413 DO(ConsumeString(&syntax, "Expected syntax identifier."));
414 DO(Consume(";"));
415
416 syntax_identifier_ = syntax;
417
kenton@google.comd37d46d2009-04-25 02:53:47 +0000418 if (syntax != "proto2" && !stop_after_syntax_identifier_) {
temporal40ee5512008-07-10 02:12:20 +0000419 AddError(syntax_token.line, syntax_token.column,
420 "Unrecognized syntax identifier \"" + syntax + "\". This parser "
421 "only recognizes \"proto2\".");
422 return false;
423 }
424
425 return true;
426}
427
liujisi@google.com33165fe2010-11-02 13:14:58 +0000428bool Parser::ParseTopLevelStatement(FileDescriptorProto* file,
429 const LocationRecorder& root_location) {
temporal40ee5512008-07-10 02:12:20 +0000430 if (TryConsume(";")) {
431 // empty statement; ignore
432 return true;
433 } else if (LookingAt("message")) {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000434 LocationRecorder location(root_location,
435 FileDescriptorProto::kMessageTypeFieldNumber, file->message_type_size());
436 return ParseMessageDefinition(file->add_message_type(), location);
temporal40ee5512008-07-10 02:12:20 +0000437 } else if (LookingAt("enum")) {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000438 LocationRecorder location(root_location,
439 FileDescriptorProto::kEnumTypeFieldNumber, file->enum_type_size());
440 return ParseEnumDefinition(file->add_enum_type(), location);
temporal40ee5512008-07-10 02:12:20 +0000441 } else if (LookingAt("service")) {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000442 LocationRecorder location(root_location,
443 FileDescriptorProto::kServiceFieldNumber, file->service_size());
444 return ParseServiceDefinition(file->add_service(), location);
temporal40ee5512008-07-10 02:12:20 +0000445 } else if (LookingAt("extend")) {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000446 LocationRecorder location(root_location,
447 FileDescriptorProto::kExtensionFieldNumber);
temporal40ee5512008-07-10 02:12:20 +0000448 return ParseExtend(file->mutable_extension(),
liujisi@google.com33165fe2010-11-02 13:14:58 +0000449 file->mutable_message_type(),
450 root_location,
451 FileDescriptorProto::kMessageTypeFieldNumber,
452 location);
temporal40ee5512008-07-10 02:12:20 +0000453 } else if (LookingAt("import")) {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000454 int index = file->dependency_size();
455 return ParseImport(file->add_dependency(), root_location, index);
temporal40ee5512008-07-10 02:12:20 +0000456 } else if (LookingAt("package")) {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000457 return ParsePackage(file, root_location);
temporal40ee5512008-07-10 02:12:20 +0000458 } else if (LookingAt("option")) {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000459 LocationRecorder location(root_location,
460 FileDescriptorProto::kOptionsFieldNumber);
461 return ParseOption(file->mutable_options(), location);
temporal40ee5512008-07-10 02:12:20 +0000462 } else {
463 AddError("Expected top-level statement (e.g. \"message\").");
464 return false;
465 }
466}
467
468// -------------------------------------------------------------------
469// Messages
470
liujisi@google.com33165fe2010-11-02 13:14:58 +0000471bool Parser::ParseMessageDefinition(DescriptorProto* message,
472 const LocationRecorder& message_location) {
temporal40ee5512008-07-10 02:12:20 +0000473 DO(Consume("message"));
liujisi@google.com33165fe2010-11-02 13:14:58 +0000474 {
475 LocationRecorder location(message_location,
476 DescriptorProto::kNameFieldNumber);
477 location.RecordLegacyLocation(
478 message, DescriptorPool::ErrorCollector::NAME);
479 DO(ConsumeIdentifier(message->mutable_name(), "Expected message name."));
480 }
481 DO(ParseMessageBlock(message, message_location));
temporal40ee5512008-07-10 02:12:20 +0000482 return true;
483}
484
liujisi@google.com33165fe2010-11-02 13:14:58 +0000485bool Parser::ParseMessageBlock(DescriptorProto* message,
486 const LocationRecorder& message_location) {
temporal40ee5512008-07-10 02:12:20 +0000487 DO(Consume("{"));
488
489 while (!TryConsume("}")) {
490 if (AtEnd()) {
491 AddError("Reached end of input in message definition (missing '}').");
492 return false;
493 }
494
liujisi@google.com33165fe2010-11-02 13:14:58 +0000495 if (!ParseMessageStatement(message, message_location)) {
temporal40ee5512008-07-10 02:12:20 +0000496 // This statement failed to parse. Skip it, but keep looping to parse
497 // other statements.
498 SkipStatement();
499 }
500 }
501
502 return true;
503}
504
liujisi@google.com33165fe2010-11-02 13:14:58 +0000505bool Parser::ParseMessageStatement(DescriptorProto* message,
506 const LocationRecorder& message_location) {
temporal40ee5512008-07-10 02:12:20 +0000507 if (TryConsume(";")) {
508 // empty statement; ignore
509 return true;
510 } else if (LookingAt("message")) {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000511 LocationRecorder location(message_location,
512 DescriptorProto::kNestedTypeFieldNumber,
513 message->nested_type_size());
514 return ParseMessageDefinition(message->add_nested_type(), location);
temporal40ee5512008-07-10 02:12:20 +0000515 } else if (LookingAt("enum")) {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000516 LocationRecorder location(message_location,
517 DescriptorProto::kEnumTypeFieldNumber,
518 message->enum_type_size());
519 return ParseEnumDefinition(message->add_enum_type(), location);
temporal40ee5512008-07-10 02:12:20 +0000520 } else if (LookingAt("extensions")) {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000521 LocationRecorder location(message_location,
522 DescriptorProto::kExtensionRangeFieldNumber);
523 return ParseExtensions(message, location);
temporal40ee5512008-07-10 02:12:20 +0000524 } else if (LookingAt("extend")) {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000525 LocationRecorder location(message_location,
526 DescriptorProto::kExtensionFieldNumber);
temporal40ee5512008-07-10 02:12:20 +0000527 return ParseExtend(message->mutable_extension(),
liujisi@google.com33165fe2010-11-02 13:14:58 +0000528 message->mutable_nested_type(),
529 message_location,
530 DescriptorProto::kNestedTypeFieldNumber,
531 location);
temporal40ee5512008-07-10 02:12:20 +0000532 } else if (LookingAt("option")) {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000533 LocationRecorder location(message_location,
534 DescriptorProto::kOptionsFieldNumber);
535 return ParseOption(message->mutable_options(), location);
temporal40ee5512008-07-10 02:12:20 +0000536 } else {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000537 LocationRecorder location(message_location,
538 DescriptorProto::kFieldFieldNumber,
539 message->field_size());
temporal40ee5512008-07-10 02:12:20 +0000540 return ParseMessageField(message->add_field(),
liujisi@google.com33165fe2010-11-02 13:14:58 +0000541 message->mutable_nested_type(),
542 message_location,
543 DescriptorProto::kNestedTypeFieldNumber,
544 location);
temporal40ee5512008-07-10 02:12:20 +0000545 }
546}
547
548bool Parser::ParseMessageField(FieldDescriptorProto* field,
liujisi@google.com33165fe2010-11-02 13:14:58 +0000549 RepeatedPtrField<DescriptorProto>* messages,
550 const LocationRecorder& parent_location,
551 int location_field_number_for_nested_type,
552 const LocationRecorder& field_location) {
temporal40ee5512008-07-10 02:12:20 +0000553 // Parse label and type.
liujisi@google.com33165fe2010-11-02 13:14:58 +0000554 io::Tokenizer::Token label_token = input_->current();
555 {
556 LocationRecorder location(field_location,
557 FieldDescriptorProto::kLabelFieldNumber);
558 FieldDescriptorProto::Label label;
559 DO(ParseLabel(&label));
560 field->set_label(label);
561 }
temporal40ee5512008-07-10 02:12:20 +0000562
liujisi@google.com33165fe2010-11-02 13:14:58 +0000563 {
564 LocationRecorder location(field_location); // add path later
565 location.RecordLegacyLocation(field, DescriptorPool::ErrorCollector::TYPE);
566
567 FieldDescriptorProto::Type type = FieldDescriptorProto::TYPE_INT32;
568 string type_name;
569 DO(ParseType(&type, &type_name));
570 if (type_name.empty()) {
571 location.AddPath(FieldDescriptorProto::kTypeFieldNumber);
572 field->set_type(type);
573 } else {
574 location.AddPath(FieldDescriptorProto::kTypeNameFieldNumber);
575 field->set_type_name(type_name);
576 }
temporal40ee5512008-07-10 02:12:20 +0000577 }
578
579 // Parse name and '='.
temporal40ee5512008-07-10 02:12:20 +0000580 io::Tokenizer::Token name_token = input_->current();
liujisi@google.com33165fe2010-11-02 13:14:58 +0000581 {
582 LocationRecorder location(field_location,
583 FieldDescriptorProto::kNameFieldNumber);
584 location.RecordLegacyLocation(field, DescriptorPool::ErrorCollector::NAME);
585 DO(ConsumeIdentifier(field->mutable_name(), "Expected field name."));
586 }
temporal40ee5512008-07-10 02:12:20 +0000587 DO(Consume("=", "Missing field number."));
588
589 // Parse field number.
liujisi@google.com33165fe2010-11-02 13:14:58 +0000590 {
591 LocationRecorder location(field_location,
592 FieldDescriptorProto::kNumberFieldNumber);
593 location.RecordLegacyLocation(
594 field, DescriptorPool::ErrorCollector::NUMBER);
595 int number;
596 DO(ConsumeInteger(&number, "Expected field number."));
597 field->set_number(number);
598 }
temporal40ee5512008-07-10 02:12:20 +0000599
600 // Parse options.
liujisi@google.com33165fe2010-11-02 13:14:58 +0000601 DO(ParseFieldOptions(field, field_location));
temporal40ee5512008-07-10 02:12:20 +0000602
603 // Deal with groups.
liujisi@google.com33165fe2010-11-02 13:14:58 +0000604 if (field->has_type() && field->type() == FieldDescriptorProto::TYPE_GROUP) {
605 // Awkward: Since a group declares both a message type and a field, we
606 // have to create overlapping locations.
607 LocationRecorder group_location(parent_location);
608 group_location.StartAt(label_token);
609 group_location.AddPath(location_field_number_for_nested_type);
610 group_location.AddPath(messages->size());
611
temporal40ee5512008-07-10 02:12:20 +0000612 DescriptorProto* group = messages->Add();
613 group->set_name(field->name());
liujisi@google.com33165fe2010-11-02 13:14:58 +0000614
temporal40ee5512008-07-10 02:12:20 +0000615 // Record name location to match the field name's location.
liujisi@google.com33165fe2010-11-02 13:14:58 +0000616 {
617 LocationRecorder location(group_location,
618 DescriptorProto::kNameFieldNumber);
619 location.StartAt(name_token);
620 location.EndAt(name_token);
621 location.RecordLegacyLocation(
622 group, DescriptorPool::ErrorCollector::NAME);
623 }
624
625 // The field's type_name also comes from the name. Confusing!
626 {
627 LocationRecorder location(field_location,
628 FieldDescriptorProto::kTypeNameFieldNumber);
629 location.StartAt(name_token);
630 location.EndAt(name_token);
631 }
temporal40ee5512008-07-10 02:12:20 +0000632
633 // As a hack for backwards-compatibility, we force the group name to start
634 // with a capital letter and lower-case the field name. New code should
635 // not use groups; it should use nested messages.
636 if (group->name()[0] < 'A' || 'Z' < group->name()[0]) {
637 AddError(name_token.line, name_token.column,
638 "Group names must start with a capital letter.");
639 }
640 LowerString(field->mutable_name());
641
642 field->set_type_name(group->name());
643 if (LookingAt("{")) {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000644 DO(ParseMessageBlock(group, group_location));
temporal40ee5512008-07-10 02:12:20 +0000645 } else {
646 AddError("Missing group body.");
647 return false;
648 }
649 } else {
650 DO(Consume(";"));
651 }
652
653 return true;
654}
655
liujisi@google.com33165fe2010-11-02 13:14:58 +0000656bool Parser::ParseFieldOptions(FieldDescriptorProto* field,
657 const LocationRecorder& field_location) {
658 if (!LookingAt("[")) return true;
659
660 LocationRecorder location(field_location,
661 FieldDescriptorProto::kOptionsFieldNumber);
662
663 DO(Consume("["));
temporal40ee5512008-07-10 02:12:20 +0000664
665 // Parse field options.
666 do {
667 if (LookingAt("default")) {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000668 // We intentionally pass field_location rather than location here, since
669 // the default value is not actually an option.
670 DO(ParseDefaultAssignment(field, field_location));
temporal40ee5512008-07-10 02:12:20 +0000671 } else {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000672 DO(ParseOptionAssignment(field->mutable_options(), location));
temporal40ee5512008-07-10 02:12:20 +0000673 }
674 } while (TryConsume(","));
675
676 DO(Consume("]"));
677 return true;
678}
679
liujisi@google.com33165fe2010-11-02 13:14:58 +0000680bool Parser::ParseDefaultAssignment(FieldDescriptorProto* field,
681 const LocationRecorder& field_location) {
temporal40ee5512008-07-10 02:12:20 +0000682 if (field->has_default_value()) {
683 AddError("Already set option \"default\".");
684 field->clear_default_value();
685 }
686
687 DO(Consume("default"));
688 DO(Consume("="));
689
liujisi@google.com33165fe2010-11-02 13:14:58 +0000690 LocationRecorder location(field_location,
691 FieldDescriptorProto::kDefaultValueFieldNumber);
692 location.RecordLegacyLocation(
693 field, DescriptorPool::ErrorCollector::DEFAULT_VALUE);
temporal40ee5512008-07-10 02:12:20 +0000694 string* default_value = field->mutable_default_value();
695
696 if (!field->has_type()) {
697 // The field has a type name, but we don't know if it is a message or an
698 // enum yet. Assume an enum for now.
699 DO(ConsumeIdentifier(default_value, "Expected identifier."));
700 return true;
701 }
702
703 switch (field->type()) {
704 case FieldDescriptorProto::TYPE_INT32:
705 case FieldDescriptorProto::TYPE_INT64:
706 case FieldDescriptorProto::TYPE_SINT32:
707 case FieldDescriptorProto::TYPE_SINT64:
708 case FieldDescriptorProto::TYPE_SFIXED32:
709 case FieldDescriptorProto::TYPE_SFIXED64: {
710 uint64 max_value = kint64max;
711 if (field->type() == FieldDescriptorProto::TYPE_INT32 ||
712 field->type() == FieldDescriptorProto::TYPE_SINT32 ||
713 field->type() == FieldDescriptorProto::TYPE_SFIXED32) {
714 max_value = kint32max;
715 }
716
717 // These types can be negative.
718 if (TryConsume("-")) {
719 default_value->append("-");
720 // Two's complement always has one more negative value than positive.
721 ++max_value;
722 }
723 // Parse the integer to verify that it is not out-of-range.
724 uint64 value;
725 DO(ConsumeInteger64(max_value, &value, "Expected integer."));
726 // And stringify it again.
727 default_value->append(SimpleItoa(value));
728 break;
729 }
730
731 case FieldDescriptorProto::TYPE_UINT32:
732 case FieldDescriptorProto::TYPE_UINT64:
733 case FieldDescriptorProto::TYPE_FIXED32:
734 case FieldDescriptorProto::TYPE_FIXED64: {
735 uint64 max_value = kuint64max;
736 if (field->type() == FieldDescriptorProto::TYPE_UINT32 ||
737 field->type() == FieldDescriptorProto::TYPE_FIXED32) {
738 max_value = kuint32max;
739 }
740
741 // Numeric, not negative.
742 if (TryConsume("-")) {
743 AddError("Unsigned field can't have negative default value.");
744 }
745 // Parse the integer to verify that it is not out-of-range.
746 uint64 value;
747 DO(ConsumeInteger64(max_value, &value, "Expected integer."));
748 // And stringify it again.
749 default_value->append(SimpleItoa(value));
750 break;
751 }
752
753 case FieldDescriptorProto::TYPE_FLOAT:
754 case FieldDescriptorProto::TYPE_DOUBLE:
755 // These types can be negative.
756 if (TryConsume("-")) {
757 default_value->append("-");
758 }
759 // Parse the integer because we have to convert hex integers to decimal
760 // floats.
761 double value;
762 DO(ConsumeNumber(&value, "Expected number."));
763 // And stringify it again.
764 default_value->append(SimpleDtoa(value));
765 break;
766
767 case FieldDescriptorProto::TYPE_BOOL:
768 if (TryConsume("true")) {
769 default_value->assign("true");
770 } else if (TryConsume("false")) {
771 default_value->assign("false");
772 } else {
773 AddError("Expected \"true\" or \"false\".");
774 return false;
775 }
776 break;
777
778 case FieldDescriptorProto::TYPE_STRING:
779 DO(ConsumeString(default_value, "Expected string."));
780 break;
781
782 case FieldDescriptorProto::TYPE_BYTES:
783 DO(ConsumeString(default_value, "Expected string."));
784 *default_value = CEscape(*default_value);
785 break;
786
787 case FieldDescriptorProto::TYPE_ENUM:
788 DO(ConsumeIdentifier(default_value, "Expected identifier."));
789 break;
790
791 case FieldDescriptorProto::TYPE_MESSAGE:
792 case FieldDescriptorProto::TYPE_GROUP:
793 AddError("Messages can't have default values.");
794 return false;
795 }
796
797 return true;
798}
799
liujisi@google.com33165fe2010-11-02 13:14:58 +0000800bool Parser::ParseOptionNamePart(UninterpretedOption* uninterpreted_option,
801 const LocationRecorder& part_location) {
kenton@google.com24bf56f2008-09-24 20:31:01 +0000802 UninterpretedOption::NamePart* name = uninterpreted_option->add_name();
803 string identifier; // We parse identifiers into this string.
804 if (LookingAt("(")) { // This is an extension.
805 DO(Consume("("));
liujisi@google.com33165fe2010-11-02 13:14:58 +0000806
807 {
808 LocationRecorder location(
809 part_location, UninterpretedOption::NamePart::kNamePartFieldNumber);
810 // An extension name consists of dot-separated identifiers, and may begin
811 // with a dot.
812 if (LookingAtType(io::Tokenizer::TYPE_IDENTIFIER)) {
813 DO(ConsumeIdentifier(&identifier, "Expected identifier."));
814 name->mutable_name_part()->append(identifier);
815 }
816 while (LookingAt(".")) {
817 DO(Consume("."));
818 name->mutable_name_part()->append(".");
819 DO(ConsumeIdentifier(&identifier, "Expected identifier."));
820 name->mutable_name_part()->append(identifier);
821 }
temporal40ee5512008-07-10 02:12:20 +0000822 }
liujisi@google.com33165fe2010-11-02 13:14:58 +0000823
kenton@google.com24bf56f2008-09-24 20:31:01 +0000824 DO(Consume(")"));
825 name->set_is_extension(true);
826 } else { // This is a regular field.
liujisi@google.com33165fe2010-11-02 13:14:58 +0000827 LocationRecorder location(
828 part_location, UninterpretedOption::NamePart::kNamePartFieldNumber);
kenton@google.com24bf56f2008-09-24 20:31:01 +0000829 DO(ConsumeIdentifier(&identifier, "Expected identifier."));
830 name->mutable_name_part()->append(identifier);
831 name->set_is_extension(false);
832 }
833 return true;
834}
temporal40ee5512008-07-10 02:12:20 +0000835
liujisi@google.com33165fe2010-11-02 13:14:58 +0000836bool Parser::ParseUninterpretedBlock(string* value) {
837 // Note that enclosing braces are not added to *value.
838 DO(Consume("{"));
839 int brace_depth = 1;
840 while (!AtEnd()) {
841 if (LookingAt("{")) {
842 brace_depth++;
843 } else if (LookingAt("}")) {
844 brace_depth--;
845 if (brace_depth == 0) {
846 input_->Next();
847 return true;
848 }
849 }
850 // TODO(sanjay): Interpret line/column numbers to preserve formatting
851 if (!value->empty()) value->push_back(' ');
852 value->append(input_->current().text);
853 input_->Next();
854 }
855 AddError("Unexpected end of stream while parsing aggregate value.");
856 return false;
857}
858
kenton@google.com24bf56f2008-09-24 20:31:01 +0000859// We don't interpret the option here. Instead we store it in an
860// UninterpretedOption, to be interpreted later.
liujisi@google.com33165fe2010-11-02 13:14:58 +0000861bool Parser::ParseOptionAssignment(Message* options,
862 const LocationRecorder& options_location) {
kenton@google.com24bf56f2008-09-24 20:31:01 +0000863 // Create an entry in the uninterpreted_option field.
864 const FieldDescriptor* uninterpreted_option_field = options->GetDescriptor()->
865 FindFieldByName("uninterpreted_option");
866 GOOGLE_CHECK(uninterpreted_option_field != NULL)
867 << "No field named \"uninterpreted_option\" in the Options proto.";
868
liujisi@google.com33165fe2010-11-02 13:14:58 +0000869 const Reflection* reflection = options->GetReflection();
870
871 LocationRecorder location(
872 options_location, uninterpreted_option_field->number(),
873 reflection->FieldSize(*options, uninterpreted_option_field));
874
kenton@google.com80b1d622009-07-29 01:13:20 +0000875 UninterpretedOption* uninterpreted_option = down_cast<UninterpretedOption*>(
kenton@google.com24bf56f2008-09-24 20:31:01 +0000876 options->GetReflection()->AddMessage(options,
877 uninterpreted_option_field));
878
879 // Parse dot-separated name.
liujisi@google.com33165fe2010-11-02 13:14:58 +0000880 {
881 LocationRecorder name_location(location,
882 UninterpretedOption::kNameFieldNumber);
883 name_location.RecordLegacyLocation(
884 uninterpreted_option, DescriptorPool::ErrorCollector::OPTION_NAME);
kenton@google.com24bf56f2008-09-24 20:31:01 +0000885
liujisi@google.com33165fe2010-11-02 13:14:58 +0000886 {
887 LocationRecorder part_location(name_location,
888 uninterpreted_option->name_size());
889 DO(ParseOptionNamePart(uninterpreted_option, part_location));
890 }
kenton@google.com24bf56f2008-09-24 20:31:01 +0000891
liujisi@google.com33165fe2010-11-02 13:14:58 +0000892 while (LookingAt(".")) {
893 DO(Consume("."));
894 LocationRecorder part_location(name_location,
895 uninterpreted_option->name_size());
896 DO(ParseOptionNamePart(uninterpreted_option, part_location));
897 }
temporal40ee5512008-07-10 02:12:20 +0000898 }
899
900 DO(Consume("="));
901
liujisi@google.com33165fe2010-11-02 13:14:58 +0000902 LocationRecorder value_location(location);
903 value_location.RecordLegacyLocation(
904 uninterpreted_option, DescriptorPool::ErrorCollector::OPTION_VALUE);
kenton@google.com24bf56f2008-09-24 20:31:01 +0000905
906 // All values are a single token, except for negative numbers, which consist
907 // of a single '-' symbol, followed by a positive number.
908 bool is_negative = TryConsume("-");
909
910 switch (input_->current().type) {
911 case io::Tokenizer::TYPE_START:
912 GOOGLE_LOG(FATAL) << "Trying to read value before any tokens have been read.";
913 return false;
914
915 case io::Tokenizer::TYPE_END:
916 AddError("Unexpected end of stream while parsing option value.");
917 return false;
918
919 case io::Tokenizer::TYPE_IDENTIFIER: {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000920 value_location.AddPath(UninterpretedOption::kIdentifierValueFieldNumber);
kenton@google.com24bf56f2008-09-24 20:31:01 +0000921 if (is_negative) {
922 AddError("Invalid '-' symbol before identifier.");
923 return false;
924 }
925 string value;
926 DO(ConsumeIdentifier(&value, "Expected identifier."));
927 uninterpreted_option->set_identifier_value(value);
928 break;
929 }
930
931 case io::Tokenizer::TYPE_INTEGER: {
temporal40ee5512008-07-10 02:12:20 +0000932 uint64 value;
kenton@google.com24bf56f2008-09-24 20:31:01 +0000933 uint64 max_value =
934 is_negative ? static_cast<uint64>(kint64max) + 1 : kuint64max;
temporal40ee5512008-07-10 02:12:20 +0000935 DO(ConsumeInteger64(max_value, &value, "Expected integer."));
kenton@google.com24bf56f2008-09-24 20:31:01 +0000936 if (is_negative) {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000937 value_location.AddPath(
938 UninterpretedOption::kNegativeIntValueFieldNumber);
939 uninterpreted_option->set_negative_int_value(-static_cast<int64>(value));
temporal40ee5512008-07-10 02:12:20 +0000940 } else {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000941 value_location.AddPath(
942 UninterpretedOption::kPositiveIntValueFieldNumber);
kenton@google.com24bf56f2008-09-24 20:31:01 +0000943 uninterpreted_option->set_positive_int_value(value);
temporal40ee5512008-07-10 02:12:20 +0000944 }
945 break;
temporal40ee5512008-07-10 02:12:20 +0000946 }
947
kenton@google.com24bf56f2008-09-24 20:31:01 +0000948 case io::Tokenizer::TYPE_FLOAT: {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000949 value_location.AddPath(UninterpretedOption::kDoubleValueFieldNumber);
kenton@google.com24bf56f2008-09-24 20:31:01 +0000950 double value;
951 DO(ConsumeNumber(&value, "Expected number."));
952 uninterpreted_option->set_double_value(is_negative ? -value : value);
953 break;
954 }
955
956 case io::Tokenizer::TYPE_STRING: {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000957 value_location.AddPath(UninterpretedOption::kStringValueFieldNumber);
kenton@google.com24bf56f2008-09-24 20:31:01 +0000958 if (is_negative) {
959 AddError("Invalid '-' symbol before string.");
960 return false;
961 }
temporal40ee5512008-07-10 02:12:20 +0000962 string value;
963 DO(ConsumeString(&value, "Expected string."));
kenton@google.com24bf56f2008-09-24 20:31:01 +0000964 uninterpreted_option->set_string_value(value);
temporal40ee5512008-07-10 02:12:20 +0000965 break;
966 }
967
kenton@google.com24bf56f2008-09-24 20:31:01 +0000968 case io::Tokenizer::TYPE_SYMBOL:
liujisi@google.com33165fe2010-11-02 13:14:58 +0000969 if (LookingAt("{")) {
970 value_location.AddPath(UninterpretedOption::kAggregateValueFieldNumber);
971 DO(ParseUninterpretedBlock(
972 uninterpreted_option->mutable_aggregate_value()));
973 } else {
974 AddError("Expected option value.");
975 return false;
976 }
977 break;
temporal40ee5512008-07-10 02:12:20 +0000978 }
979
980 return true;
981}
982
liujisi@google.com33165fe2010-11-02 13:14:58 +0000983bool Parser::ParseExtensions(DescriptorProto* message,
984 const LocationRecorder& extensions_location) {
temporal40ee5512008-07-10 02:12:20 +0000985 // Parse the declaration.
986 DO(Consume("extensions"));
987
988 do {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000989 // Note that kExtensionRangeFieldNumber was already pushed by the parent.
990 LocationRecorder location(extensions_location,
991 message->extension_range_size());
992
temporal40ee5512008-07-10 02:12:20 +0000993 DescriptorProto::ExtensionRange* range = message->add_extension_range();
liujisi@google.com33165fe2010-11-02 13:14:58 +0000994 location.RecordLegacyLocation(
995 range, DescriptorPool::ErrorCollector::NUMBER);
temporal40ee5512008-07-10 02:12:20 +0000996
997 int start, end;
liujisi@google.com33165fe2010-11-02 13:14:58 +0000998 io::Tokenizer::Token start_token;
999
1000 {
1001 LocationRecorder start_location(
1002 location, DescriptorProto::ExtensionRange::kStartFieldNumber);
1003 start_token = input_->current();
1004 DO(ConsumeInteger(&start, "Expected field number range."));
1005 }
temporal40ee5512008-07-10 02:12:20 +00001006
1007 if (TryConsume("to")) {
liujisi@google.com33165fe2010-11-02 13:14:58 +00001008 LocationRecorder end_location(
1009 location, DescriptorProto::ExtensionRange::kEndFieldNumber);
temporal40ee5512008-07-10 02:12:20 +00001010 if (TryConsume("max")) {
1011 end = FieldDescriptor::kMaxNumber;
1012 } else {
1013 DO(ConsumeInteger(&end, "Expected integer."));
1014 }
1015 } else {
liujisi@google.com33165fe2010-11-02 13:14:58 +00001016 LocationRecorder end_location(
1017 location, DescriptorProto::ExtensionRange::kEndFieldNumber);
1018 end_location.StartAt(start_token);
1019 end_location.EndAt(start_token);
temporal40ee5512008-07-10 02:12:20 +00001020 end = start;
1021 }
1022
1023 // Users like to specify inclusive ranges, but in code we like the end
1024 // number to be exclusive.
1025 ++end;
1026
1027 range->set_start(start);
1028 range->set_end(end);
1029 } while (TryConsume(","));
1030
1031 DO(Consume(";"));
1032 return true;
1033}
1034
1035bool Parser::ParseExtend(RepeatedPtrField<FieldDescriptorProto>* extensions,
liujisi@google.com33165fe2010-11-02 13:14:58 +00001036 RepeatedPtrField<DescriptorProto>* messages,
1037 const LocationRecorder& parent_location,
1038 int location_field_number_for_nested_type,
1039 const LocationRecorder& extend_location) {
temporal40ee5512008-07-10 02:12:20 +00001040 DO(Consume("extend"));
1041
temporal40ee5512008-07-10 02:12:20 +00001042 // Parse the extendee type.
liujisi@google.com33165fe2010-11-02 13:14:58 +00001043 io::Tokenizer::Token extendee_start = input_->current();
1044 string extendee;
1045 DO(ParseUserDefinedType(&extendee));
1046 io::Tokenizer::Token extendee_end = input_->previous();
temporal40ee5512008-07-10 02:12:20 +00001047
1048 // Parse the block.
1049 DO(Consume("{"));
1050
1051 bool is_first = true;
1052
1053 do {
1054 if (AtEnd()) {
1055 AddError("Reached end of input in extend definition (missing '}').");
1056 return false;
1057 }
1058
liujisi@google.com33165fe2010-11-02 13:14:58 +00001059 // Note that kExtensionFieldNumber was already pushed by the parent.
1060 LocationRecorder location(extend_location, extensions->size());
1061
1062 FieldDescriptorProto* field = extensions->Add();
1063
1064 {
1065 LocationRecorder extendee_location(
1066 location, FieldDescriptorProto::kExtendeeFieldNumber);
1067 extendee_location.StartAt(extendee_start);
1068 extendee_location.EndAt(extendee_end);
1069
1070 if (is_first) {
1071 extendee_location.RecordLegacyLocation(
1072 field, DescriptorPool::ErrorCollector::EXTENDEE);
1073 is_first = false;
1074 }
temporal40ee5512008-07-10 02:12:20 +00001075 }
1076
liujisi@google.com33165fe2010-11-02 13:14:58 +00001077 field->set_extendee(extendee);
1078
1079 if (!ParseMessageField(field, messages, parent_location,
1080 location_field_number_for_nested_type,
1081 location)) {
temporal40ee5512008-07-10 02:12:20 +00001082 // This statement failed to parse. Skip it, but keep looping to parse
1083 // other statements.
1084 SkipStatement();
1085 }
1086 } while(!TryConsume("}"));
1087
1088 return true;
1089}
1090
1091// -------------------------------------------------------------------
1092// Enums
1093
liujisi@google.com33165fe2010-11-02 13:14:58 +00001094bool Parser::ParseEnumDefinition(EnumDescriptorProto* enum_type,
1095 const LocationRecorder& enum_location) {
temporal40ee5512008-07-10 02:12:20 +00001096 DO(Consume("enum"));
liujisi@google.com33165fe2010-11-02 13:14:58 +00001097
1098 {
1099 LocationRecorder location(enum_location,
1100 EnumDescriptorProto::kNameFieldNumber);
1101 location.RecordLegacyLocation(
1102 enum_type, DescriptorPool::ErrorCollector::NAME);
1103 DO(ConsumeIdentifier(enum_type->mutable_name(), "Expected enum name."));
1104 }
1105
1106 DO(ParseEnumBlock(enum_type, enum_location));
temporal40ee5512008-07-10 02:12:20 +00001107 return true;
1108}
1109
liujisi@google.com33165fe2010-11-02 13:14:58 +00001110bool Parser::ParseEnumBlock(EnumDescriptorProto* enum_type,
1111 const LocationRecorder& enum_location) {
temporal40ee5512008-07-10 02:12:20 +00001112 DO(Consume("{"));
1113
1114 while (!TryConsume("}")) {
1115 if (AtEnd()) {
1116 AddError("Reached end of input in enum definition (missing '}').");
1117 return false;
1118 }
1119
liujisi@google.com33165fe2010-11-02 13:14:58 +00001120 if (!ParseEnumStatement(enum_type, enum_location)) {
temporal40ee5512008-07-10 02:12:20 +00001121 // This statement failed to parse. Skip it, but keep looping to parse
1122 // other statements.
1123 SkipStatement();
1124 }
1125 }
1126
1127 return true;
1128}
1129
liujisi@google.com33165fe2010-11-02 13:14:58 +00001130bool Parser::ParseEnumStatement(EnumDescriptorProto* enum_type,
1131 const LocationRecorder& enum_location) {
temporal40ee5512008-07-10 02:12:20 +00001132 if (TryConsume(";")) {
1133 // empty statement; ignore
1134 return true;
1135 } else if (LookingAt("option")) {
liujisi@google.com33165fe2010-11-02 13:14:58 +00001136 LocationRecorder location(enum_location,
1137 EnumDescriptorProto::kOptionsFieldNumber);
1138 return ParseOption(enum_type->mutable_options(), location);
temporal40ee5512008-07-10 02:12:20 +00001139 } else {
liujisi@google.com33165fe2010-11-02 13:14:58 +00001140 LocationRecorder location(enum_location,
1141 EnumDescriptorProto::kValueFieldNumber, enum_type->value_size());
1142 return ParseEnumConstant(enum_type->add_value(), location);
temporal40ee5512008-07-10 02:12:20 +00001143 }
1144}
1145
liujisi@google.com33165fe2010-11-02 13:14:58 +00001146bool Parser::ParseEnumConstant(EnumValueDescriptorProto* enum_value,
1147 const LocationRecorder& enum_value_location) {
1148 // Parse name.
1149 {
1150 LocationRecorder location(enum_value_location,
1151 EnumValueDescriptorProto::kNameFieldNumber);
1152 location.RecordLegacyLocation(
1153 enum_value, DescriptorPool::ErrorCollector::NAME);
1154 DO(ConsumeIdentifier(enum_value->mutable_name(),
1155 "Expected enum constant name."));
1156 }
1157
temporal40ee5512008-07-10 02:12:20 +00001158 DO(Consume("=", "Missing numeric value for enum constant."));
1159
liujisi@google.com33165fe2010-11-02 13:14:58 +00001160 // Parse value.
1161 {
1162 LocationRecorder location(
1163 enum_value_location, EnumValueDescriptorProto::kNumberFieldNumber);
1164 location.RecordLegacyLocation(
1165 enum_value, DescriptorPool::ErrorCollector::NUMBER);
temporal40ee5512008-07-10 02:12:20 +00001166
liujisi@google.com33165fe2010-11-02 13:14:58 +00001167 bool is_negative = TryConsume("-");
1168 int number;
1169 DO(ConsumeInteger(&number, "Expected integer."));
1170 if (is_negative) number *= -1;
1171 enum_value->set_number(number);
1172 }
1173
1174 DO(ParseEnumConstantOptions(enum_value, enum_value_location));
temporal40ee5512008-07-10 02:12:20 +00001175
1176 DO(Consume(";"));
1177
1178 return true;
1179}
1180
liujisi@google.com33165fe2010-11-02 13:14:58 +00001181bool Parser::ParseEnumConstantOptions(
1182 EnumValueDescriptorProto* value,
1183 const LocationRecorder& enum_value_location) {
1184 if (!LookingAt("[")) return true;
1185
1186 LocationRecorder location(
1187 enum_value_location, EnumValueDescriptorProto::kOptionsFieldNumber);
1188
1189 DO(Consume("["));
kenton@google.com26bd9ee2008-11-21 00:06:27 +00001190
1191 do {
liujisi@google.com33165fe2010-11-02 13:14:58 +00001192 DO(ParseOptionAssignment(value->mutable_options(), location));
kenton@google.com26bd9ee2008-11-21 00:06:27 +00001193 } while (TryConsume(","));
1194
1195 DO(Consume("]"));
1196 return true;
1197}
1198
temporal40ee5512008-07-10 02:12:20 +00001199// -------------------------------------------------------------------
1200// Services
1201
liujisi@google.com33165fe2010-11-02 13:14:58 +00001202bool Parser::ParseServiceDefinition(ServiceDescriptorProto* service,
1203 const LocationRecorder& service_location) {
temporal40ee5512008-07-10 02:12:20 +00001204 DO(Consume("service"));
liujisi@google.com33165fe2010-11-02 13:14:58 +00001205
1206 {
1207 LocationRecorder location(service_location,
1208 ServiceDescriptorProto::kNameFieldNumber);
1209 location.RecordLegacyLocation(
1210 service, DescriptorPool::ErrorCollector::NAME);
1211 DO(ConsumeIdentifier(service->mutable_name(), "Expected service name."));
1212 }
1213
1214 DO(ParseServiceBlock(service, service_location));
temporal40ee5512008-07-10 02:12:20 +00001215 return true;
1216}
1217
liujisi@google.com33165fe2010-11-02 13:14:58 +00001218bool Parser::ParseServiceBlock(ServiceDescriptorProto* service,
1219 const LocationRecorder& service_location) {
temporal40ee5512008-07-10 02:12:20 +00001220 DO(Consume("{"));
1221
1222 while (!TryConsume("}")) {
1223 if (AtEnd()) {
1224 AddError("Reached end of input in service definition (missing '}').");
1225 return false;
1226 }
1227
liujisi@google.com33165fe2010-11-02 13:14:58 +00001228 if (!ParseServiceStatement(service, service_location)) {
temporal40ee5512008-07-10 02:12:20 +00001229 // This statement failed to parse. Skip it, but keep looping to parse
1230 // other statements.
1231 SkipStatement();
1232 }
1233 }
1234
1235 return true;
1236}
1237
liujisi@google.com33165fe2010-11-02 13:14:58 +00001238bool Parser::ParseServiceStatement(ServiceDescriptorProto* service,
1239 const LocationRecorder& service_location) {
temporal40ee5512008-07-10 02:12:20 +00001240 if (TryConsume(";")) {
1241 // empty statement; ignore
1242 return true;
1243 } else if (LookingAt("option")) {
liujisi@google.com33165fe2010-11-02 13:14:58 +00001244 LocationRecorder location(
1245 service_location, ServiceDescriptorProto::kOptionsFieldNumber);
1246 return ParseOption(service->mutable_options(), location);
temporal40ee5512008-07-10 02:12:20 +00001247 } else {
liujisi@google.com33165fe2010-11-02 13:14:58 +00001248 LocationRecorder location(service_location,
1249 ServiceDescriptorProto::kMethodFieldNumber, service->method_size());
1250 return ParseServiceMethod(service->add_method(), location);
temporal40ee5512008-07-10 02:12:20 +00001251 }
1252}
1253
liujisi@google.com33165fe2010-11-02 13:14:58 +00001254bool Parser::ParseServiceMethod(MethodDescriptorProto* method,
1255 const LocationRecorder& method_location) {
temporal40ee5512008-07-10 02:12:20 +00001256 DO(Consume("rpc"));
liujisi@google.com33165fe2010-11-02 13:14:58 +00001257
1258 {
1259 LocationRecorder location(method_location,
1260 MethodDescriptorProto::kNameFieldNumber);
1261 location.RecordLegacyLocation(
1262 method, DescriptorPool::ErrorCollector::NAME);
1263 DO(ConsumeIdentifier(method->mutable_name(), "Expected method name."));
1264 }
temporal40ee5512008-07-10 02:12:20 +00001265
1266 // Parse input type.
1267 DO(Consume("("));
liujisi@google.com33165fe2010-11-02 13:14:58 +00001268 {
1269 LocationRecorder location(method_location,
1270 MethodDescriptorProto::kInputTypeFieldNumber);
1271 location.RecordLegacyLocation(
1272 method, DescriptorPool::ErrorCollector::INPUT_TYPE);
1273 DO(ParseUserDefinedType(method->mutable_input_type()));
1274 }
temporal40ee5512008-07-10 02:12:20 +00001275 DO(Consume(")"));
1276
1277 // Parse output type.
1278 DO(Consume("returns"));
1279 DO(Consume("("));
liujisi@google.com33165fe2010-11-02 13:14:58 +00001280 {
1281 LocationRecorder location(method_location,
1282 MethodDescriptorProto::kOutputTypeFieldNumber);
1283 location.RecordLegacyLocation(
1284 method, DescriptorPool::ErrorCollector::OUTPUT_TYPE);
1285 DO(ParseUserDefinedType(method->mutable_output_type()));
1286 }
temporal40ee5512008-07-10 02:12:20 +00001287 DO(Consume(")"));
1288
1289 if (TryConsume("{")) {
1290 // Options!
1291 while (!TryConsume("}")) {
1292 if (AtEnd()) {
1293 AddError("Reached end of input in method options (missing '}').");
1294 return false;
1295 }
1296
1297 if (TryConsume(";")) {
1298 // empty statement; ignore
1299 } else {
liujisi@google.com33165fe2010-11-02 13:14:58 +00001300 LocationRecorder location(method_location,
1301 MethodDescriptorProto::kOptionsFieldNumber);
1302 if (!ParseOption(method->mutable_options(), location)) {
temporal40ee5512008-07-10 02:12:20 +00001303 // This statement failed to parse. Skip it, but keep looping to
1304 // parse other statements.
1305 SkipStatement();
1306 }
1307 }
1308 }
1309 } else {
1310 DO(Consume(";"));
1311 }
1312
1313 return true;
1314}
1315
1316// -------------------------------------------------------------------
1317
1318bool Parser::ParseLabel(FieldDescriptorProto::Label* label) {
1319 if (TryConsume("optional")) {
1320 *label = FieldDescriptorProto::LABEL_OPTIONAL;
1321 return true;
1322 } else if (TryConsume("repeated")) {
1323 *label = FieldDescriptorProto::LABEL_REPEATED;
1324 return true;
1325 } else if (TryConsume("required")) {
1326 *label = FieldDescriptorProto::LABEL_REQUIRED;
1327 return true;
1328 } else {
1329 AddError("Expected \"required\", \"optional\", or \"repeated\".");
1330 // We can actually reasonably recover here by just assuming the user
1331 // forgot the label altogether.
1332 *label = FieldDescriptorProto::LABEL_OPTIONAL;
1333 return true;
1334 }
1335}
1336
1337bool Parser::ParseType(FieldDescriptorProto::Type* type,
1338 string* type_name) {
1339 TypeNameMap::const_iterator iter = kTypeNames.find(input_->current().text);
1340 if (iter != kTypeNames.end()) {
1341 *type = iter->second;
1342 input_->Next();
1343 } else {
1344 DO(ParseUserDefinedType(type_name));
1345 }
1346 return true;
1347}
1348
1349bool Parser::ParseUserDefinedType(string* type_name) {
1350 type_name->clear();
1351
1352 TypeNameMap::const_iterator iter = kTypeNames.find(input_->current().text);
1353 if (iter != kTypeNames.end()) {
1354 // Note: The only place enum types are allowed is for field types, but
1355 // if we are parsing a field type then we would not get here because
1356 // primitives are allowed there as well. So this error message doesn't
1357 // need to account for enums.
1358 AddError("Expected message type.");
1359
1360 // Pretend to accept this type so that we can go on parsing.
1361 *type_name = input_->current().text;
1362 input_->Next();
1363 return true;
1364 }
1365
1366 // A leading "." means the name is fully-qualified.
1367 if (TryConsume(".")) type_name->append(".");
1368
1369 // Consume the first part of the name.
1370 string identifier;
1371 DO(ConsumeIdentifier(&identifier, "Expected type name."));
1372 type_name->append(identifier);
1373
1374 // Consume more parts.
1375 while (TryConsume(".")) {
1376 type_name->append(".");
1377 DO(ConsumeIdentifier(&identifier, "Expected identifier."));
1378 type_name->append(identifier);
1379 }
1380
1381 return true;
1382}
1383
1384// ===================================================================
1385
liujisi@google.com33165fe2010-11-02 13:14:58 +00001386bool Parser::ParsePackage(FileDescriptorProto* file,
1387 const LocationRecorder& root_location) {
temporal40ee5512008-07-10 02:12:20 +00001388 if (file->has_package()) {
1389 AddError("Multiple package definitions.");
temporalf2063512008-07-23 01:19:07 +00001390 // Don't append the new package to the old one. Just replace it. Not
1391 // that it really matters since this is an error anyway.
1392 file->clear_package();
temporal40ee5512008-07-10 02:12:20 +00001393 }
1394
1395 DO(Consume("package"));
1396
liujisi@google.com33165fe2010-11-02 13:14:58 +00001397 {
1398 LocationRecorder location(root_location,
1399 FileDescriptorProto::kPackageFieldNumber);
1400 location.RecordLegacyLocation(file, DescriptorPool::ErrorCollector::NAME);
temporal40ee5512008-07-10 02:12:20 +00001401
liujisi@google.com33165fe2010-11-02 13:14:58 +00001402 while (true) {
1403 string identifier;
1404 DO(ConsumeIdentifier(&identifier, "Expected identifier."));
1405 file->mutable_package()->append(identifier);
1406 if (!TryConsume(".")) break;
1407 file->mutable_package()->append(".");
1408 }
temporal40ee5512008-07-10 02:12:20 +00001409 }
1410
1411 DO(Consume(";"));
1412 return true;
1413}
1414
liujisi@google.com33165fe2010-11-02 13:14:58 +00001415bool Parser::ParseImport(string* import_filename,
1416 const LocationRecorder& root_location,
1417 int index) {
temporal40ee5512008-07-10 02:12:20 +00001418 DO(Consume("import"));
liujisi@google.com33165fe2010-11-02 13:14:58 +00001419 {
1420 LocationRecorder location(root_location,
1421 FileDescriptorProto::kDependencyFieldNumber,
1422 index);
1423 DO(ConsumeString(import_filename,
1424 "Expected a string naming the file to import."));
1425 }
temporal40ee5512008-07-10 02:12:20 +00001426 DO(Consume(";"));
1427 return true;
1428}
1429
liujisi@google.com33165fe2010-11-02 13:14:58 +00001430bool Parser::ParseOption(Message* options,
1431 const LocationRecorder& options_location) {
temporal40ee5512008-07-10 02:12:20 +00001432 DO(Consume("option"));
liujisi@google.com33165fe2010-11-02 13:14:58 +00001433 DO(ParseOptionAssignment(options, options_location));
temporal40ee5512008-07-10 02:12:20 +00001434 DO(Consume(";"));
1435 return true;
1436}
1437
1438// ===================================================================
1439
1440SourceLocationTable::SourceLocationTable() {}
1441SourceLocationTable::~SourceLocationTable() {}
1442
1443bool SourceLocationTable::Find(
1444 const Message* descriptor,
1445 DescriptorPool::ErrorCollector::ErrorLocation location,
1446 int* line, int* column) const {
1447 const pair<int, int>* result =
1448 FindOrNull(location_map_, make_pair(descriptor, location));
1449 if (result == NULL) {
1450 *line = -1;
1451 *column = 0;
1452 return false;
1453 } else {
1454 *line = result->first;
1455 *column = result->second;
1456 return true;
1457 }
1458}
1459
1460void SourceLocationTable::Add(
1461 const Message* descriptor,
1462 DescriptorPool::ErrorCollector::ErrorLocation location,
1463 int line, int column) {
1464 location_map_[make_pair(descriptor, location)] = make_pair(line, column);
1465}
1466
1467void SourceLocationTable::Clear() {
1468 location_map_.clear();
1469}
1470
1471} // namespace compiler
1472} // namespace protobuf
1473} // namespace google