blob: c50cdf54a8ce4fcb64e73e383fd8bc5d6eefa009 [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.
Feng Xiaoe4288622014-10-01 16:26:23 -07003// https://developers.google.com/protocol-buffers/
temporal40ee5512008-07-10 02:12:20 +00004//
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>
jieluo@google.com4de8f552014-07-18 00:47:59 +000049#include <google/protobuf/stubs/map_util.h>
temporal40ee5512008-07-10 02:12:20 +000050
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
Feng Xiao6ef984a2014-11-10 17:34:54 -080087// Camel-case the field name and append "Entry" for generated map entry name.
88// e.g. map<KeyType, ValueType> foo_map => FooMapEntry
89string MapEntryName(const string& field_name) {
90 string result;
91 static const char kSuffix[] = "Entry";
92 result.reserve(field_name.size() + sizeof(kSuffix));
93 bool cap_next = true;
94 for (int i = 0; i < field_name.size(); ++i) {
95 if (field_name[i] == '_') {
96 cap_next = true;
97 } else if (cap_next) {
98 // Note: Do not use ctype.h due to locales.
99 if ('a' <= field_name[i] && field_name[i] <= 'z') {
100 result.push_back(field_name[i] - 'a' + 'A');
101 } else {
102 result.push_back(field_name[i]);
103 }
104 cap_next = false;
105 } else {
106 result.push_back(field_name[i]);
107 }
108 }
109 result.append(kSuffix);
110 return result;
111}
112
temporal40ee5512008-07-10 02:12:20 +0000113} // anonymous namespace
114
115// Makes code slightly more readable. The meaning of "DO(foo)" is
116// "Execute foo and fail if it fails.", where failure is indicated by
117// returning false.
118#define DO(STATEMENT) if (STATEMENT) {} else return false
119
120// ===================================================================
121
122Parser::Parser()
123 : input_(NULL),
124 error_collector_(NULL),
125 source_location_table_(NULL),
126 had_errors_(false),
kenton@google.comd37d46d2009-04-25 02:53:47 +0000127 require_syntax_identifier_(false),
128 stop_after_syntax_identifier_(false) {
temporal40ee5512008-07-10 02:12:20 +0000129}
130
131Parser::~Parser() {
132}
133
134// ===================================================================
135
136inline bool Parser::LookingAt(const char* text) {
137 return input_->current().text == text;
138}
139
140inline bool Parser::LookingAtType(io::Tokenizer::TokenType token_type) {
141 return input_->current().type == token_type;
142}
143
144inline bool Parser::AtEnd() {
145 return LookingAtType(io::Tokenizer::TYPE_END);
146}
147
148bool Parser::TryConsume(const char* text) {
149 if (LookingAt(text)) {
150 input_->Next();
151 return true;
152 } else {
153 return false;
154 }
155}
156
157bool Parser::Consume(const char* text, const char* error) {
158 if (TryConsume(text)) {
159 return true;
160 } else {
161 AddError(error);
162 return false;
163 }
164}
165
166bool Parser::Consume(const char* text) {
167 if (TryConsume(text)) {
168 return true;
169 } else {
170 AddError("Expected \"" + string(text) + "\".");
171 return false;
172 }
173}
174
175bool Parser::ConsumeIdentifier(string* output, const char* error) {
176 if (LookingAtType(io::Tokenizer::TYPE_IDENTIFIER)) {
177 *output = input_->current().text;
178 input_->Next();
179 return true;
180 } else {
181 AddError(error);
182 return false;
183 }
184}
185
186bool Parser::ConsumeInteger(int* output, const char* error) {
187 if (LookingAtType(io::Tokenizer::TYPE_INTEGER)) {
188 uint64 value = 0;
189 if (!io::Tokenizer::ParseInteger(input_->current().text,
190 kint32max, &value)) {
191 AddError("Integer out of range.");
192 // We still return true because we did, in fact, parse an integer.
193 }
194 *output = value;
195 input_->Next();
196 return true;
197 } else {
198 AddError(error);
199 return false;
200 }
201}
202
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000203bool Parser::ConsumeSignedInteger(int* output, const char* error) {
204 bool is_negative = false;
205 uint64 max_value = kint32max;
206 if (TryConsume("-")) {
207 is_negative = true;
208 max_value += 1;
209 }
210 uint64 value = 0;
211 DO(ConsumeInteger64(max_value, &value, error));
212 if (is_negative) value *= -1;
213 *output = value;
214 return true;
215}
216
temporal40ee5512008-07-10 02:12:20 +0000217bool Parser::ConsumeInteger64(uint64 max_value, uint64* output,
218 const char* error) {
219 if (LookingAtType(io::Tokenizer::TYPE_INTEGER)) {
220 if (!io::Tokenizer::ParseInteger(input_->current().text, max_value,
221 output)) {
222 AddError("Integer out of range.");
223 // We still return true because we did, in fact, parse an integer.
224 *output = 0;
225 }
226 input_->Next();
227 return true;
228 } else {
229 AddError(error);
230 return false;
231 }
232}
233
234bool Parser::ConsumeNumber(double* output, const char* error) {
235 if (LookingAtType(io::Tokenizer::TYPE_FLOAT)) {
236 *output = io::Tokenizer::ParseFloat(input_->current().text);
237 input_->Next();
238 return true;
239 } else if (LookingAtType(io::Tokenizer::TYPE_INTEGER)) {
240 // Also accept integers.
241 uint64 value = 0;
242 if (!io::Tokenizer::ParseInteger(input_->current().text,
243 kuint64max, &value)) {
244 AddError("Integer out of range.");
245 // We still return true because we did, in fact, parse a number.
246 }
247 *output = value;
248 input_->Next();
249 return true;
kenton@google.comfccb1462009-12-18 02:11:36 +0000250 } else if (LookingAt("inf")) {
251 *output = numeric_limits<double>::infinity();
252 input_->Next();
253 return true;
254 } else if (LookingAt("nan")) {
255 *output = numeric_limits<double>::quiet_NaN();
256 input_->Next();
257 return true;
temporal40ee5512008-07-10 02:12:20 +0000258 } else {
259 AddError(error);
260 return false;
261 }
262}
263
264bool Parser::ConsumeString(string* output, const char* error) {
265 if (LookingAtType(io::Tokenizer::TYPE_STRING)) {
266 io::Tokenizer::ParseString(input_->current().text, output);
267 input_->Next();
kenton@google.com26bd9ee2008-11-21 00:06:27 +0000268 // Allow C++ like concatenation of adjacent string tokens.
269 while (LookingAtType(io::Tokenizer::TYPE_STRING)) {
270 io::Tokenizer::ParseStringAppend(input_->current().text, output);
271 input_->Next();
272 }
temporal40ee5512008-07-10 02:12:20 +0000273 return true;
274 } else {
275 AddError(error);
276 return false;
277 }
278}
279
Jisi Liu885b6122015-02-28 14:51:22 -0800280bool Parser::TryConsumeEndOfDeclaration(
281 const char* text, const LocationRecorder* location) {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000282 if (LookingAt(text)) {
283 string leading, trailing;
Jisi Liu885b6122015-02-28 14:51:22 -0800284 vector<string> detached;
285 input_->NextWithComments(&trailing, &detached, &leading);
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000286
287 // Save the leading comments for next time, and recall the leading comments
288 // from last time.
289 leading.swap(upcoming_doc_comments_);
290
291 if (location != NULL) {
Jisi Liu885b6122015-02-28 14:51:22 -0800292 upcoming_detached_comments_.swap(detached);
293 location->AttachComments(&leading, &trailing, &detached);
294 } else if (strcmp(text, "}") == 0) {
295 // If the current location is null and we are finishing the current scope,
296 // drop pending upcoming detached comments.
297 upcoming_detached_comments_.swap(detached);
298 } else {
299 // Otherwise, append the new detached comments to the existing upcoming
300 // detached comments.
301 upcoming_detached_comments_.insert(upcoming_detached_comments_.end(),
302 detached.begin(), detached.end());
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000303 }
Jisi Liu885b6122015-02-28 14:51:22 -0800304
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000305 return true;
306 } else {
307 return false;
308 }
309}
310
Jisi Liu885b6122015-02-28 14:51:22 -0800311bool Parser::ConsumeEndOfDeclaration(
312 const char* text, const LocationRecorder* location) {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000313 if (TryConsumeEndOfDeclaration(text, location)) {
314 return true;
315 } else {
316 AddError("Expected \"" + string(text) + "\".");
317 return false;
318 }
319}
320
temporal40ee5512008-07-10 02:12:20 +0000321// -------------------------------------------------------------------
322
323void Parser::AddError(int line, int column, const string& error) {
324 if (error_collector_ != NULL) {
325 error_collector_->AddError(line, column, error);
326 }
327 had_errors_ = true;
328}
329
330void Parser::AddError(const string& error) {
331 AddError(input_->current().line, input_->current().column, error);
332}
333
liujisi@google.com33165fe2010-11-02 13:14:58 +0000334// -------------------------------------------------------------------
335
336Parser::LocationRecorder::LocationRecorder(Parser* parser)
337 : parser_(parser),
338 location_(parser_->source_code_info_->add_location()) {
339 location_->add_span(parser_->input_->current().line);
340 location_->add_span(parser_->input_->current().column);
341}
342
343Parser::LocationRecorder::LocationRecorder(const LocationRecorder& parent) {
344 Init(parent);
345}
346
347Parser::LocationRecorder::LocationRecorder(const LocationRecorder& parent,
348 int path1) {
349 Init(parent);
350 AddPath(path1);
351}
352
353Parser::LocationRecorder::LocationRecorder(const LocationRecorder& parent,
354 int path1, int path2) {
355 Init(parent);
356 AddPath(path1);
357 AddPath(path2);
358}
359
360void Parser::LocationRecorder::Init(const LocationRecorder& parent) {
361 parser_ = parent.parser_;
362 location_ = parser_->source_code_info_->add_location();
363 location_->mutable_path()->CopyFrom(parent.location_->path());
364
365 location_->add_span(parser_->input_->current().line);
366 location_->add_span(parser_->input_->current().column);
367}
368
369Parser::LocationRecorder::~LocationRecorder() {
370 if (location_->span_size() <= 2) {
371 EndAt(parser_->input_->previous());
temporal40ee5512008-07-10 02:12:20 +0000372 }
373}
374
liujisi@google.com33165fe2010-11-02 13:14:58 +0000375void Parser::LocationRecorder::AddPath(int path_component) {
376 location_->add_path(path_component);
377}
378
379void Parser::LocationRecorder::StartAt(const io::Tokenizer::Token& token) {
380 location_->set_span(0, token.line);
381 location_->set_span(1, token.column);
382}
383
jieluo@google.com4de8f552014-07-18 00:47:59 +0000384void Parser::LocationRecorder::StartAt(const LocationRecorder& other) {
385 location_->set_span(0, other.location_->span(0));
386 location_->set_span(1, other.location_->span(1));
387}
388
liujisi@google.com33165fe2010-11-02 13:14:58 +0000389void Parser::LocationRecorder::EndAt(const io::Tokenizer::Token& token) {
390 if (token.line != location_->span(0)) {
391 location_->add_span(token.line);
392 }
393 location_->add_span(token.end_column);
394}
395
396void Parser::LocationRecorder::RecordLegacyLocation(const Message* descriptor,
temporal40ee5512008-07-10 02:12:20 +0000397 DescriptorPool::ErrorCollector::ErrorLocation location) {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000398 if (parser_->source_location_table_ != NULL) {
399 parser_->source_location_table_->Add(
400 descriptor, location, location_->span(0), location_->span(1));
401 }
temporal40ee5512008-07-10 02:12:20 +0000402}
403
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000404void Parser::LocationRecorder::AttachComments(
Jisi Liu885b6122015-02-28 14:51:22 -0800405 string* leading, string* trailing,
406 vector<string>* detached_comments) const {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000407 GOOGLE_CHECK(!location_->has_leading_comments());
408 GOOGLE_CHECK(!location_->has_trailing_comments());
409
410 if (!leading->empty()) {
411 location_->mutable_leading_comments()->swap(*leading);
412 }
413 if (!trailing->empty()) {
414 location_->mutable_trailing_comments()->swap(*trailing);
415 }
Jisi Liu885b6122015-02-28 14:51:22 -0800416 for (int i = 0; i < detached_comments->size(); ++i) {
417 location_->add_leading_detached_comments()->swap(
418 (*detached_comments)[i]);
419 }
420 detached_comments->clear();
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000421}
422
temporal40ee5512008-07-10 02:12:20 +0000423// -------------------------------------------------------------------
424
425void Parser::SkipStatement() {
426 while (true) {
427 if (AtEnd()) {
428 return;
429 } else if (LookingAtType(io::Tokenizer::TYPE_SYMBOL)) {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000430 if (TryConsumeEndOfDeclaration(";", NULL)) {
temporal40ee5512008-07-10 02:12:20 +0000431 return;
432 } else if (TryConsume("{")) {
433 SkipRestOfBlock();
434 return;
435 } else if (LookingAt("}")) {
436 return;
437 }
438 }
439 input_->Next();
440 }
441}
442
443void Parser::SkipRestOfBlock() {
444 while (true) {
445 if (AtEnd()) {
446 return;
447 } else if (LookingAtType(io::Tokenizer::TYPE_SYMBOL)) {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000448 if (TryConsumeEndOfDeclaration("}", NULL)) {
temporal40ee5512008-07-10 02:12:20 +0000449 return;
450 } else if (TryConsume("{")) {
451 SkipRestOfBlock();
452 }
453 }
454 input_->Next();
455 }
456}
457
458// ===================================================================
459
460bool Parser::Parse(io::Tokenizer* input, FileDescriptorProto* file) {
461 input_ = input;
462 had_errors_ = false;
463 syntax_identifier_.clear();
464
liujisi@google.com33165fe2010-11-02 13:14:58 +0000465 // Note that |file| could be NULL at this point if
466 // stop_after_syntax_identifier_ is true. So, we conservatively allocate
467 // SourceCodeInfo on the stack, then swap it into the FileDescriptorProto
468 // later on.
469 SourceCodeInfo source_code_info;
470 source_code_info_ = &source_code_info;
471
Jisi Liu885b6122015-02-28 14:51:22 -0800472 vector<string> top_doc_comments;
temporal40ee5512008-07-10 02:12:20 +0000473 if (LookingAtType(io::Tokenizer::TYPE_START)) {
474 // Advance to first token.
Jisi Liu885b6122015-02-28 14:51:22 -0800475 input_->NextWithComments(NULL, &upcoming_detached_comments_,
476 &upcoming_doc_comments_);
temporal40ee5512008-07-10 02:12:20 +0000477 }
478
liujisi@google.com33165fe2010-11-02 13:14:58 +0000479 {
480 LocationRecorder root_location(this);
481
482 if (require_syntax_identifier_ || LookingAt("syntax")) {
Jisi Liu885b6122015-02-28 14:51:22 -0800483 if (!ParseSyntaxIdentifier(root_location)) {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000484 // Don't attempt to parse the file if we didn't recognize the syntax
485 // identifier.
486 return false;
487 }
Feng Xiao6ef984a2014-11-10 17:34:54 -0800488 // Store the syntax into the file.
489 if (file != NULL) file->set_syntax(syntax_identifier_);
liujisi@google.com33165fe2010-11-02 13:14:58 +0000490 } else if (!stop_after_syntax_identifier_) {
Feng Xiao3eb55df2014-11-14 12:41:10 -0800491 GOOGLE_LOG(WARNING) << "No syntax specified for the proto file. "
Jisi Liu885b6122015-02-28 14:51:22 -0800492 << "Please use 'syntax = \"proto2\";' or "
493 << "'syntax = \"proto3\";' to specify a syntax "
494 << "version. (Defaulted to proto2 syntax.)";
liujisi@google.com33165fe2010-11-02 13:14:58 +0000495 syntax_identifier_ = "proto2";
temporal40ee5512008-07-10 02:12:20 +0000496 }
temporal40ee5512008-07-10 02:12:20 +0000497
liujisi@google.com33165fe2010-11-02 13:14:58 +0000498 if (stop_after_syntax_identifier_) return !had_errors_;
kenton@google.comd37d46d2009-04-25 02:53:47 +0000499
liujisi@google.com33165fe2010-11-02 13:14:58 +0000500 // Repeatedly parse statements until we reach the end of the file.
501 while (!AtEnd()) {
502 if (!ParseTopLevelStatement(file, root_location)) {
503 // This statement failed to parse. Skip it, but keep looping to parse
504 // other statements.
505 SkipStatement();
temporal40ee5512008-07-10 02:12:20 +0000506
liujisi@google.com33165fe2010-11-02 13:14:58 +0000507 if (LookingAt("}")) {
508 AddError("Unmatched \"}\".");
Jisi Liu885b6122015-02-28 14:51:22 -0800509 input_->NextWithComments(NULL, &upcoming_detached_comments_,
510 &upcoming_doc_comments_);
liujisi@google.com33165fe2010-11-02 13:14:58 +0000511 }
temporal40ee5512008-07-10 02:12:20 +0000512 }
513 }
514 }
515
516 input_ = NULL;
liujisi@google.com33165fe2010-11-02 13:14:58 +0000517 source_code_info_ = NULL;
518 source_code_info.Swap(file->mutable_source_code_info());
temporal40ee5512008-07-10 02:12:20 +0000519 return !had_errors_;
520}
521
Jisi Liu885b6122015-02-28 14:51:22 -0800522bool Parser::ParseSyntaxIdentifier(const LocationRecorder& parent) {
523 LocationRecorder syntax_location(parent,
524 FileDescriptorProto::kSyntaxFieldNumber);
Feng Xiao6ef984a2014-11-10 17:34:54 -0800525 DO(Consume(
526 "syntax",
527 "File must begin with a syntax statement, e.g. 'syntax = \"proto2\";'."));
temporal40ee5512008-07-10 02:12:20 +0000528 DO(Consume("="));
529 io::Tokenizer::Token syntax_token = input_->current();
530 string syntax;
531 DO(ConsumeString(&syntax, "Expected syntax identifier."));
Jisi Liu885b6122015-02-28 14:51:22 -0800532 DO(ConsumeEndOfDeclaration(";", &syntax_location));
temporal40ee5512008-07-10 02:12:20 +0000533
534 syntax_identifier_ = syntax;
535
Feng Xiao6ef984a2014-11-10 17:34:54 -0800536 if (syntax != "proto2" && syntax != "proto3" &&
537 !stop_after_syntax_identifier_) {
temporal40ee5512008-07-10 02:12:20 +0000538 AddError(syntax_token.line, syntax_token.column,
539 "Unrecognized syntax identifier \"" + syntax + "\". This parser "
Feng Xiao6ef984a2014-11-10 17:34:54 -0800540 "only recognizes \"proto2\" and \"proto3\".");
temporal40ee5512008-07-10 02:12:20 +0000541 return false;
542 }
543
544 return true;
545}
546
liujisi@google.com33165fe2010-11-02 13:14:58 +0000547bool Parser::ParseTopLevelStatement(FileDescriptorProto* file,
548 const LocationRecorder& root_location) {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000549 if (TryConsumeEndOfDeclaration(";", NULL)) {
temporal40ee5512008-07-10 02:12:20 +0000550 // empty statement; ignore
551 return true;
552 } else if (LookingAt("message")) {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000553 LocationRecorder location(root_location,
554 FileDescriptorProto::kMessageTypeFieldNumber, file->message_type_size());
jieluo@google.com4de8f552014-07-18 00:47:59 +0000555 return ParseMessageDefinition(file->add_message_type(), location, file);
temporal40ee5512008-07-10 02:12:20 +0000556 } else if (LookingAt("enum")) {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000557 LocationRecorder location(root_location,
558 FileDescriptorProto::kEnumTypeFieldNumber, file->enum_type_size());
jieluo@google.com4de8f552014-07-18 00:47:59 +0000559 return ParseEnumDefinition(file->add_enum_type(), location, file);
temporal40ee5512008-07-10 02:12:20 +0000560 } else if (LookingAt("service")) {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000561 LocationRecorder location(root_location,
562 FileDescriptorProto::kServiceFieldNumber, file->service_size());
jieluo@google.com4de8f552014-07-18 00:47:59 +0000563 return ParseServiceDefinition(file->add_service(), location, file);
temporal40ee5512008-07-10 02:12:20 +0000564 } else if (LookingAt("extend")) {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000565 LocationRecorder location(root_location,
566 FileDescriptorProto::kExtensionFieldNumber);
temporal40ee5512008-07-10 02:12:20 +0000567 return ParseExtend(file->mutable_extension(),
liujisi@google.com33165fe2010-11-02 13:14:58 +0000568 file->mutable_message_type(),
569 root_location,
570 FileDescriptorProto::kMessageTypeFieldNumber,
jieluo@google.com4de8f552014-07-18 00:47:59 +0000571 location, file);
temporal40ee5512008-07-10 02:12:20 +0000572 } else if (LookingAt("import")) {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000573 return ParseImport(file->mutable_dependency(),
574 file->mutable_public_dependency(),
575 file->mutable_weak_dependency(),
jieluo@google.com4de8f552014-07-18 00:47:59 +0000576 root_location, file);
temporal40ee5512008-07-10 02:12:20 +0000577 } else if (LookingAt("package")) {
jieluo@google.com4de8f552014-07-18 00:47:59 +0000578 return ParsePackage(file, root_location, file);
temporal40ee5512008-07-10 02:12:20 +0000579 } else if (LookingAt("option")) {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000580 LocationRecorder location(root_location,
581 FileDescriptorProto::kOptionsFieldNumber);
jieluo@google.com4de8f552014-07-18 00:47:59 +0000582 return ParseOption(file->mutable_options(), location, file,
583 OPTION_STATEMENT);
temporal40ee5512008-07-10 02:12:20 +0000584 } else {
585 AddError("Expected top-level statement (e.g. \"message\").");
586 return false;
587 }
588}
589
590// -------------------------------------------------------------------
591// Messages
592
jieluo@google.com4de8f552014-07-18 00:47:59 +0000593bool Parser::ParseMessageDefinition(
594 DescriptorProto* message,
595 const LocationRecorder& message_location,
596 const FileDescriptorProto* containing_file) {
temporal40ee5512008-07-10 02:12:20 +0000597 DO(Consume("message"));
liujisi@google.com33165fe2010-11-02 13:14:58 +0000598 {
599 LocationRecorder location(message_location,
600 DescriptorProto::kNameFieldNumber);
601 location.RecordLegacyLocation(
602 message, DescriptorPool::ErrorCollector::NAME);
603 DO(ConsumeIdentifier(message->mutable_name(), "Expected message name."));
604 }
jieluo@google.com4de8f552014-07-18 00:47:59 +0000605 DO(ParseMessageBlock(message, message_location, containing_file));
temporal40ee5512008-07-10 02:12:20 +0000606 return true;
607}
608
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000609namespace {
610
611const int kMaxExtensionRangeSentinel = -1;
612
613bool IsMessageSetWireFormatMessage(const DescriptorProto& message) {
614 const MessageOptions& options = message.options();
615 for (int i = 0; i < options.uninterpreted_option_size(); ++i) {
616 const UninterpretedOption& uninterpreted = options.uninterpreted_option(i);
617 if (uninterpreted.name_size() == 1 &&
618 uninterpreted.name(0).name_part() == "message_set_wire_format" &&
619 uninterpreted.identifier_value() == "true") {
620 return true;
621 }
622 }
623 return false;
624}
625
626// Modifies any extension ranges that specified 'max' as the end of the
627// extension range, and sets them to the type-specific maximum. The actual max
628// tag number can only be determined after all options have been parsed.
629void AdjustExtensionRangesWithMaxEndNumber(DescriptorProto* message) {
630 const bool is_message_set = IsMessageSetWireFormatMessage(*message);
631 const int max_extension_number = is_message_set ?
632 kint32max :
633 FieldDescriptor::kMaxNumber + 1;
634 for (int i = 0; i < message->extension_range_size(); ++i) {
635 if (message->extension_range(i).end() == kMaxExtensionRangeSentinel) {
636 message->mutable_extension_range(i)->set_end(max_extension_number);
637 }
638 }
639}
640
641} // namespace
642
liujisi@google.com33165fe2010-11-02 13:14:58 +0000643bool Parser::ParseMessageBlock(DescriptorProto* message,
jieluo@google.com4de8f552014-07-18 00:47:59 +0000644 const LocationRecorder& message_location,
645 const FileDescriptorProto* containing_file) {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000646 DO(ConsumeEndOfDeclaration("{", &message_location));
temporal40ee5512008-07-10 02:12:20 +0000647
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000648 while (!TryConsumeEndOfDeclaration("}", NULL)) {
temporal40ee5512008-07-10 02:12:20 +0000649 if (AtEnd()) {
650 AddError("Reached end of input in message definition (missing '}').");
651 return false;
652 }
653
jieluo@google.com4de8f552014-07-18 00:47:59 +0000654 if (!ParseMessageStatement(message, message_location, containing_file)) {
temporal40ee5512008-07-10 02:12:20 +0000655 // This statement failed to parse. Skip it, but keep looping to parse
656 // other statements.
657 SkipStatement();
658 }
659 }
660
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000661 if (message->extension_range_size() > 0) {
662 AdjustExtensionRangesWithMaxEndNumber(message);
663 }
temporal40ee5512008-07-10 02:12:20 +0000664 return true;
665}
666
liujisi@google.com33165fe2010-11-02 13:14:58 +0000667bool Parser::ParseMessageStatement(DescriptorProto* message,
jieluo@google.com4de8f552014-07-18 00:47:59 +0000668 const LocationRecorder& message_location,
669 const FileDescriptorProto* containing_file) {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000670 if (TryConsumeEndOfDeclaration(";", NULL)) {
temporal40ee5512008-07-10 02:12:20 +0000671 // empty statement; ignore
672 return true;
673 } else if (LookingAt("message")) {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000674 LocationRecorder location(message_location,
675 DescriptorProto::kNestedTypeFieldNumber,
676 message->nested_type_size());
jieluo@google.com4de8f552014-07-18 00:47:59 +0000677 return ParseMessageDefinition(message->add_nested_type(), location,
678 containing_file);
temporal40ee5512008-07-10 02:12:20 +0000679 } else if (LookingAt("enum")) {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000680 LocationRecorder location(message_location,
681 DescriptorProto::kEnumTypeFieldNumber,
682 message->enum_type_size());
jieluo@google.com4de8f552014-07-18 00:47:59 +0000683 return ParseEnumDefinition(message->add_enum_type(), location,
684 containing_file);
temporal40ee5512008-07-10 02:12:20 +0000685 } else if (LookingAt("extensions")) {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000686 LocationRecorder location(message_location,
687 DescriptorProto::kExtensionRangeFieldNumber);
jieluo@google.com4de8f552014-07-18 00:47:59 +0000688 return ParseExtensions(message, location, containing_file);
temporal40ee5512008-07-10 02:12:20 +0000689 } else if (LookingAt("extend")) {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000690 LocationRecorder location(message_location,
691 DescriptorProto::kExtensionFieldNumber);
temporal40ee5512008-07-10 02:12:20 +0000692 return ParseExtend(message->mutable_extension(),
liujisi@google.com33165fe2010-11-02 13:14:58 +0000693 message->mutable_nested_type(),
694 message_location,
695 DescriptorProto::kNestedTypeFieldNumber,
jieluo@google.com4de8f552014-07-18 00:47:59 +0000696 location, containing_file);
temporal40ee5512008-07-10 02:12:20 +0000697 } else if (LookingAt("option")) {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000698 LocationRecorder location(message_location,
699 DescriptorProto::kOptionsFieldNumber);
jieluo@google.com4de8f552014-07-18 00:47:59 +0000700 return ParseOption(message->mutable_options(), location,
701 containing_file, OPTION_STATEMENT);
702 } else if (LookingAt("oneof")) {
703 int oneof_index = message->oneof_decl_size();
704 LocationRecorder oneof_location(message_location,
705 DescriptorProto::kOneofDeclFieldNumber,
706 oneof_index);
707
708 return ParseOneof(message->add_oneof_decl(), message,
709 oneof_index, oneof_location, message_location,
710 containing_file);
temporal40ee5512008-07-10 02:12:20 +0000711 } else {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000712 LocationRecorder location(message_location,
713 DescriptorProto::kFieldFieldNumber,
714 message->field_size());
temporal40ee5512008-07-10 02:12:20 +0000715 return ParseMessageField(message->add_field(),
liujisi@google.com33165fe2010-11-02 13:14:58 +0000716 message->mutable_nested_type(),
717 message_location,
718 DescriptorProto::kNestedTypeFieldNumber,
jieluo@google.com4de8f552014-07-18 00:47:59 +0000719 location,
720 containing_file);
temporal40ee5512008-07-10 02:12:20 +0000721 }
722}
723
724bool Parser::ParseMessageField(FieldDescriptorProto* field,
liujisi@google.com33165fe2010-11-02 13:14:58 +0000725 RepeatedPtrField<DescriptorProto>* messages,
726 const LocationRecorder& parent_location,
727 int location_field_number_for_nested_type,
jieluo@google.com4de8f552014-07-18 00:47:59 +0000728 const LocationRecorder& field_location,
729 const FileDescriptorProto* containing_file) {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000730 {
731 LocationRecorder location(field_location,
732 FieldDescriptorProto::kLabelFieldNumber);
733 FieldDescriptorProto::Label label;
Feng Xiao6ef984a2014-11-10 17:34:54 -0800734 if (ParseLabel(&label, containing_file)) {
735 field->set_label(label);
736 }
liujisi@google.com33165fe2010-11-02 13:14:58 +0000737 }
temporal40ee5512008-07-10 02:12:20 +0000738
jieluo@google.com4de8f552014-07-18 00:47:59 +0000739 return ParseMessageFieldNoLabel(field, messages, parent_location,
740 location_field_number_for_nested_type,
741 field_location,
742 containing_file);
743}
744
745bool Parser::ParseMessageFieldNoLabel(
746 FieldDescriptorProto* field,
747 RepeatedPtrField<DescriptorProto>* messages,
748 const LocationRecorder& parent_location,
749 int location_field_number_for_nested_type,
750 const LocationRecorder& field_location,
751 const FileDescriptorProto* containing_file) {
Feng Xiao6ef984a2014-11-10 17:34:54 -0800752 MapField map_field;
jieluo@google.com4de8f552014-07-18 00:47:59 +0000753 // Parse type.
liujisi@google.com33165fe2010-11-02 13:14:58 +0000754 {
755 LocationRecorder location(field_location); // add path later
756 location.RecordLegacyLocation(field, DescriptorPool::ErrorCollector::TYPE);
757
Feng Xiao6ef984a2014-11-10 17:34:54 -0800758 bool type_parsed = false;
liujisi@google.com33165fe2010-11-02 13:14:58 +0000759 FieldDescriptorProto::Type type = FieldDescriptorProto::TYPE_INT32;
760 string type_name;
Feng Xiao6ef984a2014-11-10 17:34:54 -0800761
762 // Special case map field. We only treat the field as a map field if the
763 // field type name starts with the word "map" with a following "<".
764 if (TryConsume("map")) {
765 if (LookingAt("<")) {
766 map_field.is_map_field = true;
767 } else {
768 // False positive
769 type_parsed = true;
770 type_name = "map";
771 }
772 }
773 if (map_field.is_map_field) {
774 if (field->has_oneof_index()) {
775 AddError("Map fields are not allowed in oneofs.");
776 return false;
777 }
778 if (field->has_label()) {
779 AddError(
780 "Field labels (required/optional/repeated) are not allowed on "
781 "map fields.");
782 return false;
783 }
784 if (field->has_extendee()) {
785 AddError("Map fields are not allowed to be extensions.");
786 return false;
787 }
788 field->set_label(FieldDescriptorProto::LABEL_REPEATED);
789 DO(Consume("<"));
790 DO(ParseType(&map_field.key_type, &map_field.key_type_name));
791 DO(Consume(","));
792 DO(ParseType(&map_field.value_type, &map_field.value_type_name));
793 DO(Consume(">"));
794 // Defer setting of the type name of the map field until the
795 // field name is parsed. Add the source location though.
liujisi@google.com33165fe2010-11-02 13:14:58 +0000796 location.AddPath(FieldDescriptorProto::kTypeNameFieldNumber);
Feng Xiao6ef984a2014-11-10 17:34:54 -0800797 } else {
798 // Handle the case where no explicit label is given for a non-map field.
799 if (!field->has_label() && DefaultToOptionalFields()) {
800 field->set_label(FieldDescriptorProto::LABEL_OPTIONAL);
801 }
802 if (!field->has_label()) {
803 AddError("Expected \"required\", \"optional\", or \"repeated\".");
804 // We can actually reasonably recover here by just assuming the user
805 // forgot the label altogether.
806 field->set_label(FieldDescriptorProto::LABEL_OPTIONAL);
807 }
808
809 // Handle the case where the actual type is a message or enum named "map",
810 // which we already consumed in the code above.
811 if (!type_parsed) {
812 DO(ParseType(&type, &type_name));
813 }
814 if (type_name.empty()) {
815 location.AddPath(FieldDescriptorProto::kTypeFieldNumber);
816 field->set_type(type);
817 } else {
818 location.AddPath(FieldDescriptorProto::kTypeNameFieldNumber);
819 field->set_type_name(type_name);
820 }
liujisi@google.com33165fe2010-11-02 13:14:58 +0000821 }
temporal40ee5512008-07-10 02:12:20 +0000822 }
823
824 // Parse name and '='.
temporal40ee5512008-07-10 02:12:20 +0000825 io::Tokenizer::Token name_token = input_->current();
liujisi@google.com33165fe2010-11-02 13:14:58 +0000826 {
827 LocationRecorder location(field_location,
828 FieldDescriptorProto::kNameFieldNumber);
829 location.RecordLegacyLocation(field, DescriptorPool::ErrorCollector::NAME);
830 DO(ConsumeIdentifier(field->mutable_name(), "Expected field name."));
831 }
temporal40ee5512008-07-10 02:12:20 +0000832 DO(Consume("=", "Missing field number."));
833
834 // Parse field number.
liujisi@google.com33165fe2010-11-02 13:14:58 +0000835 {
836 LocationRecorder location(field_location,
837 FieldDescriptorProto::kNumberFieldNumber);
838 location.RecordLegacyLocation(
839 field, DescriptorPool::ErrorCollector::NUMBER);
840 int number;
841 DO(ConsumeInteger(&number, "Expected field number."));
842 field->set_number(number);
843 }
temporal40ee5512008-07-10 02:12:20 +0000844
845 // Parse options.
jieluo@google.com4de8f552014-07-18 00:47:59 +0000846 DO(ParseFieldOptions(field, field_location, containing_file));
temporal40ee5512008-07-10 02:12:20 +0000847
848 // Deal with groups.
liujisi@google.com33165fe2010-11-02 13:14:58 +0000849 if (field->has_type() && field->type() == FieldDescriptorProto::TYPE_GROUP) {
850 // Awkward: Since a group declares both a message type and a field, we
851 // have to create overlapping locations.
852 LocationRecorder group_location(parent_location);
jieluo@google.com4de8f552014-07-18 00:47:59 +0000853 group_location.StartAt(field_location);
liujisi@google.com33165fe2010-11-02 13:14:58 +0000854 group_location.AddPath(location_field_number_for_nested_type);
855 group_location.AddPath(messages->size());
856
temporal40ee5512008-07-10 02:12:20 +0000857 DescriptorProto* group = messages->Add();
858 group->set_name(field->name());
liujisi@google.com33165fe2010-11-02 13:14:58 +0000859
temporal40ee5512008-07-10 02:12:20 +0000860 // Record name location to match the field name's location.
liujisi@google.com33165fe2010-11-02 13:14:58 +0000861 {
862 LocationRecorder location(group_location,
863 DescriptorProto::kNameFieldNumber);
864 location.StartAt(name_token);
865 location.EndAt(name_token);
866 location.RecordLegacyLocation(
867 group, DescriptorPool::ErrorCollector::NAME);
868 }
869
870 // The field's type_name also comes from the name. Confusing!
871 {
872 LocationRecorder location(field_location,
873 FieldDescriptorProto::kTypeNameFieldNumber);
874 location.StartAt(name_token);
875 location.EndAt(name_token);
876 }
temporal40ee5512008-07-10 02:12:20 +0000877
878 // As a hack for backwards-compatibility, we force the group name to start
879 // with a capital letter and lower-case the field name. New code should
880 // not use groups; it should use nested messages.
881 if (group->name()[0] < 'A' || 'Z' < group->name()[0]) {
882 AddError(name_token.line, name_token.column,
883 "Group names must start with a capital letter.");
884 }
885 LowerString(field->mutable_name());
886
887 field->set_type_name(group->name());
888 if (LookingAt("{")) {
jieluo@google.com4de8f552014-07-18 00:47:59 +0000889 DO(ParseMessageBlock(group, group_location, containing_file));
temporal40ee5512008-07-10 02:12:20 +0000890 } else {
891 AddError("Missing group body.");
892 return false;
893 }
894 } else {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000895 DO(ConsumeEndOfDeclaration(";", &field_location));
temporal40ee5512008-07-10 02:12:20 +0000896 }
897
Feng Xiao6ef984a2014-11-10 17:34:54 -0800898 // Create a map entry type if this is a map field.
899 if (map_field.is_map_field) {
900 GenerateMapEntry(map_field, field, messages);
901 }
902
temporal40ee5512008-07-10 02:12:20 +0000903 return true;
904}
905
Feng Xiao6ef984a2014-11-10 17:34:54 -0800906void Parser::GenerateMapEntry(const MapField& map_field,
907 FieldDescriptorProto* field,
908 RepeatedPtrField<DescriptorProto>* messages) {
909 DescriptorProto* entry = messages->Add();
910 string entry_name = MapEntryName(field->name());
911 field->set_type_name(entry_name);
912 entry->set_name(entry_name);
913 entry->mutable_options()->set_map_entry(true);
914 FieldDescriptorProto* key_field = entry->add_field();
915 key_field->set_name("key");
916 key_field->set_label(FieldDescriptorProto::LABEL_OPTIONAL);
917 key_field->set_number(1);
918 if (map_field.key_type_name.empty()) {
919 key_field->set_type(map_field.key_type);
920 } else {
921 key_field->set_type_name(map_field.key_type_name);
922 }
923 FieldDescriptorProto* value_field = entry->add_field();
924 value_field->set_name("value");
925 value_field->set_label(FieldDescriptorProto::LABEL_OPTIONAL);
926 value_field->set_number(2);
927 if (map_field.value_type_name.empty()) {
928 value_field->set_type(map_field.value_type);
929 } else {
930 value_field->set_type_name(map_field.value_type_name);
931 }
932}
933
liujisi@google.com33165fe2010-11-02 13:14:58 +0000934bool Parser::ParseFieldOptions(FieldDescriptorProto* field,
jieluo@google.com4de8f552014-07-18 00:47:59 +0000935 const LocationRecorder& field_location,
936 const FileDescriptorProto* containing_file) {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000937 if (!LookingAt("[")) return true;
938
939 LocationRecorder location(field_location,
940 FieldDescriptorProto::kOptionsFieldNumber);
941
942 DO(Consume("["));
temporal40ee5512008-07-10 02:12:20 +0000943
944 // Parse field options.
945 do {
946 if (LookingAt("default")) {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000947 // We intentionally pass field_location rather than location here, since
948 // the default value is not actually an option.
jieluo@google.com4de8f552014-07-18 00:47:59 +0000949 DO(ParseDefaultAssignment(field, field_location, containing_file));
temporal40ee5512008-07-10 02:12:20 +0000950 } else {
jieluo@google.com4de8f552014-07-18 00:47:59 +0000951 DO(ParseOption(field->mutable_options(), location,
952 containing_file, OPTION_ASSIGNMENT));
temporal40ee5512008-07-10 02:12:20 +0000953 }
954 } while (TryConsume(","));
955
956 DO(Consume("]"));
957 return true;
958}
959
jieluo@google.com4de8f552014-07-18 00:47:59 +0000960bool Parser::ParseDefaultAssignment(
961 FieldDescriptorProto* field,
962 const LocationRecorder& field_location,
963 const FileDescriptorProto* containing_file) {
temporal40ee5512008-07-10 02:12:20 +0000964 if (field->has_default_value()) {
965 AddError("Already set option \"default\".");
966 field->clear_default_value();
967 }
968
969 DO(Consume("default"));
970 DO(Consume("="));
971
liujisi@google.com33165fe2010-11-02 13:14:58 +0000972 LocationRecorder location(field_location,
973 FieldDescriptorProto::kDefaultValueFieldNumber);
974 location.RecordLegacyLocation(
975 field, DescriptorPool::ErrorCollector::DEFAULT_VALUE);
temporal40ee5512008-07-10 02:12:20 +0000976 string* default_value = field->mutable_default_value();
977
978 if (!field->has_type()) {
979 // The field has a type name, but we don't know if it is a message or an
jieluo@google.com4de8f552014-07-18 00:47:59 +0000980 // enum yet. (If it were a primitive type, |field| would have a type set
981 // already.) In this case, simply take the current string as the default
982 // value; we will catch the error later if it is not a valid enum value.
983 // (N.B. that we do not check whether the current token is an identifier:
984 // doing so throws strange errors when the user mistypes a primitive
985 // typename and we assume it's an enum. E.g.: "optional int foo = 1 [default
986 // = 42]". In such a case the fundamental error is really that "int" is not
987 // a type, not that "42" is not an identifier. See b/12533582.)
988 *default_value = input_->current().text;
989 input_->Next();
temporal40ee5512008-07-10 02:12:20 +0000990 return true;
991 }
992
993 switch (field->type()) {
994 case FieldDescriptorProto::TYPE_INT32:
995 case FieldDescriptorProto::TYPE_INT64:
996 case FieldDescriptorProto::TYPE_SINT32:
997 case FieldDescriptorProto::TYPE_SINT64:
998 case FieldDescriptorProto::TYPE_SFIXED32:
999 case FieldDescriptorProto::TYPE_SFIXED64: {
1000 uint64 max_value = kint64max;
1001 if (field->type() == FieldDescriptorProto::TYPE_INT32 ||
1002 field->type() == FieldDescriptorProto::TYPE_SINT32 ||
1003 field->type() == FieldDescriptorProto::TYPE_SFIXED32) {
1004 max_value = kint32max;
1005 }
1006
1007 // These types can be negative.
1008 if (TryConsume("-")) {
1009 default_value->append("-");
1010 // Two's complement always has one more negative value than positive.
1011 ++max_value;
1012 }
1013 // Parse the integer to verify that it is not out-of-range.
1014 uint64 value;
jieluo@google.com4de8f552014-07-18 00:47:59 +00001015 DO(ConsumeInteger64(max_value, &value,
1016 "Expected integer for field default value."));
temporal40ee5512008-07-10 02:12:20 +00001017 // And stringify it again.
1018 default_value->append(SimpleItoa(value));
1019 break;
1020 }
1021
1022 case FieldDescriptorProto::TYPE_UINT32:
1023 case FieldDescriptorProto::TYPE_UINT64:
1024 case FieldDescriptorProto::TYPE_FIXED32:
1025 case FieldDescriptorProto::TYPE_FIXED64: {
1026 uint64 max_value = kuint64max;
1027 if (field->type() == FieldDescriptorProto::TYPE_UINT32 ||
1028 field->type() == FieldDescriptorProto::TYPE_FIXED32) {
1029 max_value = kuint32max;
1030 }
1031
1032 // Numeric, not negative.
1033 if (TryConsume("-")) {
1034 AddError("Unsigned field can't have negative default value.");
1035 }
1036 // Parse the integer to verify that it is not out-of-range.
1037 uint64 value;
jieluo@google.com4de8f552014-07-18 00:47:59 +00001038 DO(ConsumeInteger64(max_value, &value,
1039 "Expected integer for field default value."));
temporal40ee5512008-07-10 02:12:20 +00001040 // And stringify it again.
1041 default_value->append(SimpleItoa(value));
1042 break;
1043 }
1044
1045 case FieldDescriptorProto::TYPE_FLOAT:
1046 case FieldDescriptorProto::TYPE_DOUBLE:
1047 // These types can be negative.
1048 if (TryConsume("-")) {
1049 default_value->append("-");
1050 }
1051 // Parse the integer because we have to convert hex integers to decimal
1052 // floats.
1053 double value;
1054 DO(ConsumeNumber(&value, "Expected number."));
1055 // And stringify it again.
1056 default_value->append(SimpleDtoa(value));
1057 break;
1058
1059 case FieldDescriptorProto::TYPE_BOOL:
1060 if (TryConsume("true")) {
1061 default_value->assign("true");
1062 } else if (TryConsume("false")) {
1063 default_value->assign("false");
1064 } else {
1065 AddError("Expected \"true\" or \"false\".");
1066 return false;
1067 }
1068 break;
1069
1070 case FieldDescriptorProto::TYPE_STRING:
jieluo@google.com4de8f552014-07-18 00:47:59 +00001071 // Note: When file opton java_string_check_utf8 is true, if a
1072 // non-string representation (eg byte[]) is later supported, it must
1073 // be checked for UTF-8-ness.
1074 DO(ConsumeString(default_value, "Expected string for field default "
1075 "value."));
temporal40ee5512008-07-10 02:12:20 +00001076 break;
1077
1078 case FieldDescriptorProto::TYPE_BYTES:
1079 DO(ConsumeString(default_value, "Expected string."));
1080 *default_value = CEscape(*default_value);
1081 break;
1082
1083 case FieldDescriptorProto::TYPE_ENUM:
jieluo@google.com4de8f552014-07-18 00:47:59 +00001084 DO(ConsumeIdentifier(default_value, "Expected enum identifier for field "
1085 "default value."));
temporal40ee5512008-07-10 02:12:20 +00001086 break;
1087
1088 case FieldDescriptorProto::TYPE_MESSAGE:
1089 case FieldDescriptorProto::TYPE_GROUP:
1090 AddError("Messages can't have default values.");
1091 return false;
1092 }
1093
1094 return true;
1095}
1096
liujisi@google.com33165fe2010-11-02 13:14:58 +00001097bool Parser::ParseOptionNamePart(UninterpretedOption* uninterpreted_option,
jieluo@google.com4de8f552014-07-18 00:47:59 +00001098 const LocationRecorder& part_location,
1099 const FileDescriptorProto* containing_file) {
kenton@google.com24bf56f2008-09-24 20:31:01 +00001100 UninterpretedOption::NamePart* name = uninterpreted_option->add_name();
1101 string identifier; // We parse identifiers into this string.
1102 if (LookingAt("(")) { // This is an extension.
1103 DO(Consume("("));
liujisi@google.com33165fe2010-11-02 13:14:58 +00001104
1105 {
1106 LocationRecorder location(
1107 part_location, UninterpretedOption::NamePart::kNamePartFieldNumber);
1108 // An extension name consists of dot-separated identifiers, and may begin
1109 // with a dot.
1110 if (LookingAtType(io::Tokenizer::TYPE_IDENTIFIER)) {
1111 DO(ConsumeIdentifier(&identifier, "Expected identifier."));
1112 name->mutable_name_part()->append(identifier);
1113 }
1114 while (LookingAt(".")) {
1115 DO(Consume("."));
1116 name->mutable_name_part()->append(".");
1117 DO(ConsumeIdentifier(&identifier, "Expected identifier."));
1118 name->mutable_name_part()->append(identifier);
1119 }
temporal40ee5512008-07-10 02:12:20 +00001120 }
liujisi@google.com33165fe2010-11-02 13:14:58 +00001121
kenton@google.com24bf56f2008-09-24 20:31:01 +00001122 DO(Consume(")"));
1123 name->set_is_extension(true);
1124 } else { // This is a regular field.
liujisi@google.com33165fe2010-11-02 13:14:58 +00001125 LocationRecorder location(
1126 part_location, UninterpretedOption::NamePart::kNamePartFieldNumber);
kenton@google.com24bf56f2008-09-24 20:31:01 +00001127 DO(ConsumeIdentifier(&identifier, "Expected identifier."));
1128 name->mutable_name_part()->append(identifier);
1129 name->set_is_extension(false);
1130 }
1131 return true;
1132}
temporal40ee5512008-07-10 02:12:20 +00001133
liujisi@google.com33165fe2010-11-02 13:14:58 +00001134bool Parser::ParseUninterpretedBlock(string* value) {
1135 // Note that enclosing braces are not added to *value.
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001136 // We do NOT use ConsumeEndOfStatement for this brace because it's delimiting
1137 // an expression, not a block of statements.
liujisi@google.com33165fe2010-11-02 13:14:58 +00001138 DO(Consume("{"));
1139 int brace_depth = 1;
1140 while (!AtEnd()) {
1141 if (LookingAt("{")) {
1142 brace_depth++;
1143 } else if (LookingAt("}")) {
1144 brace_depth--;
1145 if (brace_depth == 0) {
1146 input_->Next();
1147 return true;
1148 }
1149 }
1150 // TODO(sanjay): Interpret line/column numbers to preserve formatting
1151 if (!value->empty()) value->push_back(' ');
1152 value->append(input_->current().text);
1153 input_->Next();
1154 }
1155 AddError("Unexpected end of stream while parsing aggregate value.");
1156 return false;
1157}
1158
kenton@google.com24bf56f2008-09-24 20:31:01 +00001159// We don't interpret the option here. Instead we store it in an
1160// UninterpretedOption, to be interpreted later.
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001161bool Parser::ParseOption(Message* options,
1162 const LocationRecorder& options_location,
jieluo@google.com4de8f552014-07-18 00:47:59 +00001163 const FileDescriptorProto* containing_file,
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001164 OptionStyle style) {
kenton@google.com24bf56f2008-09-24 20:31:01 +00001165 // Create an entry in the uninterpreted_option field.
1166 const FieldDescriptor* uninterpreted_option_field = options->GetDescriptor()->
1167 FindFieldByName("uninterpreted_option");
1168 GOOGLE_CHECK(uninterpreted_option_field != NULL)
1169 << "No field named \"uninterpreted_option\" in the Options proto.";
1170
liujisi@google.com33165fe2010-11-02 13:14:58 +00001171 const Reflection* reflection = options->GetReflection();
1172
1173 LocationRecorder location(
1174 options_location, uninterpreted_option_field->number(),
1175 reflection->FieldSize(*options, uninterpreted_option_field));
1176
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001177 if (style == OPTION_STATEMENT) {
1178 DO(Consume("option"));
1179 }
1180
kenton@google.com80b1d622009-07-29 01:13:20 +00001181 UninterpretedOption* uninterpreted_option = down_cast<UninterpretedOption*>(
kenton@google.com24bf56f2008-09-24 20:31:01 +00001182 options->GetReflection()->AddMessage(options,
1183 uninterpreted_option_field));
1184
1185 // Parse dot-separated name.
liujisi@google.com33165fe2010-11-02 13:14:58 +00001186 {
1187 LocationRecorder name_location(location,
1188 UninterpretedOption::kNameFieldNumber);
1189 name_location.RecordLegacyLocation(
1190 uninterpreted_option, DescriptorPool::ErrorCollector::OPTION_NAME);
kenton@google.com24bf56f2008-09-24 20:31:01 +00001191
liujisi@google.com33165fe2010-11-02 13:14:58 +00001192 {
1193 LocationRecorder part_location(name_location,
1194 uninterpreted_option->name_size());
jieluo@google.com4de8f552014-07-18 00:47:59 +00001195 DO(ParseOptionNamePart(uninterpreted_option, part_location,
1196 containing_file));
liujisi@google.com33165fe2010-11-02 13:14:58 +00001197 }
kenton@google.com24bf56f2008-09-24 20:31:01 +00001198
liujisi@google.com33165fe2010-11-02 13:14:58 +00001199 while (LookingAt(".")) {
1200 DO(Consume("."));
1201 LocationRecorder part_location(name_location,
1202 uninterpreted_option->name_size());
jieluo@google.com4de8f552014-07-18 00:47:59 +00001203 DO(ParseOptionNamePart(uninterpreted_option, part_location,
1204 containing_file));
liujisi@google.com33165fe2010-11-02 13:14:58 +00001205 }
temporal40ee5512008-07-10 02:12:20 +00001206 }
1207
1208 DO(Consume("="));
1209
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001210 {
1211 LocationRecorder value_location(location);
1212 value_location.RecordLegacyLocation(
1213 uninterpreted_option, DescriptorPool::ErrorCollector::OPTION_VALUE);
kenton@google.com24bf56f2008-09-24 20:31:01 +00001214
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001215 // All values are a single token, except for negative numbers, which consist
1216 // of a single '-' symbol, followed by a positive number.
1217 bool is_negative = TryConsume("-");
kenton@google.com24bf56f2008-09-24 20:31:01 +00001218
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001219 switch (input_->current().type) {
1220 case io::Tokenizer::TYPE_START:
1221 GOOGLE_LOG(FATAL) << "Trying to read value before any tokens have been read.";
kenton@google.com24bf56f2008-09-24 20:31:01 +00001222 return false;
kenton@google.com24bf56f2008-09-24 20:31:01 +00001223
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001224 case io::Tokenizer::TYPE_END:
1225 AddError("Unexpected end of stream while parsing option value.");
1226 return false;
1227
1228 case io::Tokenizer::TYPE_IDENTIFIER: {
liujisi@google.com33165fe2010-11-02 13:14:58 +00001229 value_location.AddPath(
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001230 UninterpretedOption::kIdentifierValueFieldNumber);
1231 if (is_negative) {
1232 AddError("Invalid '-' symbol before identifier.");
1233 return false;
1234 }
1235 string value;
1236 DO(ConsumeIdentifier(&value, "Expected identifier."));
1237 uninterpreted_option->set_identifier_value(value);
1238 break;
temporal40ee5512008-07-10 02:12:20 +00001239 }
temporal40ee5512008-07-10 02:12:20 +00001240
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001241 case io::Tokenizer::TYPE_INTEGER: {
1242 uint64 value;
1243 uint64 max_value =
1244 is_negative ? static_cast<uint64>(kint64max) + 1 : kuint64max;
1245 DO(ConsumeInteger64(max_value, &value, "Expected integer."));
1246 if (is_negative) {
1247 value_location.AddPath(
1248 UninterpretedOption::kNegativeIntValueFieldNumber);
1249 uninterpreted_option->set_negative_int_value(
1250 -static_cast<int64>(value));
1251 } else {
1252 value_location.AddPath(
1253 UninterpretedOption::kPositiveIntValueFieldNumber);
1254 uninterpreted_option->set_positive_int_value(value);
1255 }
1256 break;
kenton@google.com24bf56f2008-09-24 20:31:01 +00001257 }
temporal40ee5512008-07-10 02:12:20 +00001258
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001259 case io::Tokenizer::TYPE_FLOAT: {
1260 value_location.AddPath(UninterpretedOption::kDoubleValueFieldNumber);
1261 double value;
1262 DO(ConsumeNumber(&value, "Expected number."));
1263 uninterpreted_option->set_double_value(is_negative ? -value : value);
1264 break;
liujisi@google.com33165fe2010-11-02 13:14:58 +00001265 }
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001266
1267 case io::Tokenizer::TYPE_STRING: {
1268 value_location.AddPath(UninterpretedOption::kStringValueFieldNumber);
1269 if (is_negative) {
1270 AddError("Invalid '-' symbol before string.");
1271 return false;
1272 }
1273 string value;
1274 DO(ConsumeString(&value, "Expected string."));
1275 uninterpreted_option->set_string_value(value);
1276 break;
1277 }
1278
1279 case io::Tokenizer::TYPE_SYMBOL:
1280 if (LookingAt("{")) {
1281 value_location.AddPath(
1282 UninterpretedOption::kAggregateValueFieldNumber);
1283 DO(ParseUninterpretedBlock(
1284 uninterpreted_option->mutable_aggregate_value()));
1285 } else {
1286 AddError("Expected option value.");
1287 return false;
1288 }
1289 break;
1290 }
1291 }
1292
1293 if (style == OPTION_STATEMENT) {
1294 DO(ConsumeEndOfDeclaration(";", &location));
temporal40ee5512008-07-10 02:12:20 +00001295 }
1296
1297 return true;
1298}
1299
liujisi@google.com33165fe2010-11-02 13:14:58 +00001300bool Parser::ParseExtensions(DescriptorProto* message,
jieluo@google.com4de8f552014-07-18 00:47:59 +00001301 const LocationRecorder& extensions_location,
1302 const FileDescriptorProto* containing_file) {
temporal40ee5512008-07-10 02:12:20 +00001303 // Parse the declaration.
1304 DO(Consume("extensions"));
1305
1306 do {
liujisi@google.com33165fe2010-11-02 13:14:58 +00001307 // Note that kExtensionRangeFieldNumber was already pushed by the parent.
1308 LocationRecorder location(extensions_location,
1309 message->extension_range_size());
1310
temporal40ee5512008-07-10 02:12:20 +00001311 DescriptorProto::ExtensionRange* range = message->add_extension_range();
liujisi@google.com33165fe2010-11-02 13:14:58 +00001312 location.RecordLegacyLocation(
1313 range, DescriptorPool::ErrorCollector::NUMBER);
temporal40ee5512008-07-10 02:12:20 +00001314
1315 int start, end;
liujisi@google.com33165fe2010-11-02 13:14:58 +00001316 io::Tokenizer::Token start_token;
1317
1318 {
1319 LocationRecorder start_location(
1320 location, DescriptorProto::ExtensionRange::kStartFieldNumber);
1321 start_token = input_->current();
1322 DO(ConsumeInteger(&start, "Expected field number range."));
1323 }
temporal40ee5512008-07-10 02:12:20 +00001324
1325 if (TryConsume("to")) {
liujisi@google.com33165fe2010-11-02 13:14:58 +00001326 LocationRecorder end_location(
1327 location, DescriptorProto::ExtensionRange::kEndFieldNumber);
temporal40ee5512008-07-10 02:12:20 +00001328 if (TryConsume("max")) {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001329 // Set to the sentinel value - 1 since we increment the value below.
1330 // The actual value of the end of the range should be set with
1331 // AdjustExtensionRangesWithMaxEndNumber.
1332 end = kMaxExtensionRangeSentinel - 1;
temporal40ee5512008-07-10 02:12:20 +00001333 } else {
1334 DO(ConsumeInteger(&end, "Expected integer."));
1335 }
1336 } else {
liujisi@google.com33165fe2010-11-02 13:14:58 +00001337 LocationRecorder end_location(
1338 location, DescriptorProto::ExtensionRange::kEndFieldNumber);
1339 end_location.StartAt(start_token);
1340 end_location.EndAt(start_token);
temporal40ee5512008-07-10 02:12:20 +00001341 end = start;
1342 }
1343
1344 // Users like to specify inclusive ranges, but in code we like the end
1345 // number to be exclusive.
1346 ++end;
1347
1348 range->set_start(start);
1349 range->set_end(end);
1350 } while (TryConsume(","));
1351
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001352 DO(ConsumeEndOfDeclaration(";", &extensions_location));
temporal40ee5512008-07-10 02:12:20 +00001353 return true;
1354}
1355
1356bool Parser::ParseExtend(RepeatedPtrField<FieldDescriptorProto>* extensions,
liujisi@google.com33165fe2010-11-02 13:14:58 +00001357 RepeatedPtrField<DescriptorProto>* messages,
1358 const LocationRecorder& parent_location,
1359 int location_field_number_for_nested_type,
jieluo@google.com4de8f552014-07-18 00:47:59 +00001360 const LocationRecorder& extend_location,
1361 const FileDescriptorProto* containing_file) {
temporal40ee5512008-07-10 02:12:20 +00001362 DO(Consume("extend"));
1363
temporal40ee5512008-07-10 02:12:20 +00001364 // Parse the extendee type.
liujisi@google.com33165fe2010-11-02 13:14:58 +00001365 io::Tokenizer::Token extendee_start = input_->current();
1366 string extendee;
1367 DO(ParseUserDefinedType(&extendee));
1368 io::Tokenizer::Token extendee_end = input_->previous();
temporal40ee5512008-07-10 02:12:20 +00001369
1370 // Parse the block.
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001371 DO(ConsumeEndOfDeclaration("{", &extend_location));
temporal40ee5512008-07-10 02:12:20 +00001372
1373 bool is_first = true;
1374
1375 do {
1376 if (AtEnd()) {
1377 AddError("Reached end of input in extend definition (missing '}').");
1378 return false;
1379 }
1380
liujisi@google.com33165fe2010-11-02 13:14:58 +00001381 // Note that kExtensionFieldNumber was already pushed by the parent.
1382 LocationRecorder location(extend_location, extensions->size());
1383
1384 FieldDescriptorProto* field = extensions->Add();
1385
1386 {
1387 LocationRecorder extendee_location(
1388 location, FieldDescriptorProto::kExtendeeFieldNumber);
1389 extendee_location.StartAt(extendee_start);
1390 extendee_location.EndAt(extendee_end);
1391
1392 if (is_first) {
1393 extendee_location.RecordLegacyLocation(
1394 field, DescriptorPool::ErrorCollector::EXTENDEE);
1395 is_first = false;
1396 }
temporal40ee5512008-07-10 02:12:20 +00001397 }
1398
liujisi@google.com33165fe2010-11-02 13:14:58 +00001399 field->set_extendee(extendee);
1400
1401 if (!ParseMessageField(field, messages, parent_location,
1402 location_field_number_for_nested_type,
jieluo@google.com4de8f552014-07-18 00:47:59 +00001403 location,
1404 containing_file)) {
1405 // This statement failed to parse. Skip it, but keep looping to parse
1406 // other statements.
1407 SkipStatement();
1408 }
1409 } while (!TryConsumeEndOfDeclaration("}", NULL));
1410
1411 return true;
1412}
1413
1414bool Parser::ParseOneof(OneofDescriptorProto* oneof_decl,
1415 DescriptorProto* containing_type,
1416 int oneof_index,
1417 const LocationRecorder& oneof_location,
1418 const LocationRecorder& containing_type_location,
1419 const FileDescriptorProto* containing_file) {
1420 DO(Consume("oneof"));
1421
1422 {
1423 LocationRecorder name_location(oneof_location,
1424 OneofDescriptorProto::kNameFieldNumber);
1425 DO(ConsumeIdentifier(oneof_decl->mutable_name(), "Expected oneof name."));
1426 }
1427
1428 DO(ConsumeEndOfDeclaration("{", &oneof_location));
1429
1430 do {
1431 if (AtEnd()) {
1432 AddError("Reached end of input in oneof definition (missing '}').");
1433 return false;
1434 }
1435
1436 // Print a nice error if the user accidentally tries to place a label
1437 // on an individual member of a oneof.
1438 if (LookingAt("required") ||
1439 LookingAt("optional") ||
1440 LookingAt("repeated")) {
1441 AddError("Fields in oneofs must not have labels (required / optional "
1442 "/ repeated).");
1443 // We can continue parsing here because we understand what the user
1444 // meant. The error report will still make parsing fail overall.
1445 input_->Next();
1446 }
1447
1448 LocationRecorder field_location(containing_type_location,
1449 DescriptorProto::kFieldFieldNumber,
1450 containing_type->field_size());
1451
1452 FieldDescriptorProto* field = containing_type->add_field();
1453 field->set_label(FieldDescriptorProto::LABEL_OPTIONAL);
1454 field->set_oneof_index(oneof_index);
1455
1456 if (!ParseMessageFieldNoLabel(field,
1457 containing_type->mutable_nested_type(),
1458 containing_type_location,
1459 DescriptorProto::kNestedTypeFieldNumber,
1460 field_location,
1461 containing_file)) {
temporal40ee5512008-07-10 02:12:20 +00001462 // This statement failed to parse. Skip it, but keep looping to parse
1463 // other statements.
1464 SkipStatement();
1465 }
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001466 } while (!TryConsumeEndOfDeclaration("}", NULL));
temporal40ee5512008-07-10 02:12:20 +00001467
1468 return true;
1469}
1470
1471// -------------------------------------------------------------------
1472// Enums
1473
liujisi@google.com33165fe2010-11-02 13:14:58 +00001474bool Parser::ParseEnumDefinition(EnumDescriptorProto* enum_type,
jieluo@google.com4de8f552014-07-18 00:47:59 +00001475 const LocationRecorder& enum_location,
1476 const FileDescriptorProto* containing_file) {
temporal40ee5512008-07-10 02:12:20 +00001477 DO(Consume("enum"));
liujisi@google.com33165fe2010-11-02 13:14:58 +00001478
1479 {
1480 LocationRecorder location(enum_location,
1481 EnumDescriptorProto::kNameFieldNumber);
1482 location.RecordLegacyLocation(
1483 enum_type, DescriptorPool::ErrorCollector::NAME);
1484 DO(ConsumeIdentifier(enum_type->mutable_name(), "Expected enum name."));
1485 }
1486
jieluo@google.com4de8f552014-07-18 00:47:59 +00001487 DO(ParseEnumBlock(enum_type, enum_location, containing_file));
temporal40ee5512008-07-10 02:12:20 +00001488 return true;
1489}
1490
liujisi@google.com33165fe2010-11-02 13:14:58 +00001491bool Parser::ParseEnumBlock(EnumDescriptorProto* enum_type,
jieluo@google.com4de8f552014-07-18 00:47:59 +00001492 const LocationRecorder& enum_location,
1493 const FileDescriptorProto* containing_file) {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001494 DO(ConsumeEndOfDeclaration("{", &enum_location));
temporal40ee5512008-07-10 02:12:20 +00001495
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001496 while (!TryConsumeEndOfDeclaration("}", NULL)) {
temporal40ee5512008-07-10 02:12:20 +00001497 if (AtEnd()) {
1498 AddError("Reached end of input in enum definition (missing '}').");
1499 return false;
1500 }
1501
jieluo@google.com4de8f552014-07-18 00:47:59 +00001502 if (!ParseEnumStatement(enum_type, enum_location, containing_file)) {
temporal40ee5512008-07-10 02:12:20 +00001503 // This statement failed to parse. Skip it, but keep looping to parse
1504 // other statements.
1505 SkipStatement();
1506 }
1507 }
1508
1509 return true;
1510}
1511
liujisi@google.com33165fe2010-11-02 13:14:58 +00001512bool Parser::ParseEnumStatement(EnumDescriptorProto* enum_type,
jieluo@google.com4de8f552014-07-18 00:47:59 +00001513 const LocationRecorder& enum_location,
1514 const FileDescriptorProto* containing_file) {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001515 if (TryConsumeEndOfDeclaration(";", NULL)) {
temporal40ee5512008-07-10 02:12:20 +00001516 // empty statement; ignore
1517 return true;
1518 } else if (LookingAt("option")) {
liujisi@google.com33165fe2010-11-02 13:14:58 +00001519 LocationRecorder location(enum_location,
1520 EnumDescriptorProto::kOptionsFieldNumber);
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001521 return ParseOption(enum_type->mutable_options(), location,
jieluo@google.com4de8f552014-07-18 00:47:59 +00001522 containing_file, OPTION_STATEMENT);
temporal40ee5512008-07-10 02:12:20 +00001523 } else {
liujisi@google.com33165fe2010-11-02 13:14:58 +00001524 LocationRecorder location(enum_location,
1525 EnumDescriptorProto::kValueFieldNumber, enum_type->value_size());
jieluo@google.com4de8f552014-07-18 00:47:59 +00001526 return ParseEnumConstant(enum_type->add_value(), location, containing_file);
temporal40ee5512008-07-10 02:12:20 +00001527 }
1528}
1529
liujisi@google.com33165fe2010-11-02 13:14:58 +00001530bool Parser::ParseEnumConstant(EnumValueDescriptorProto* enum_value,
jieluo@google.com4de8f552014-07-18 00:47:59 +00001531 const LocationRecorder& enum_value_location,
1532 const FileDescriptorProto* containing_file) {
liujisi@google.com33165fe2010-11-02 13:14:58 +00001533 // Parse name.
1534 {
1535 LocationRecorder location(enum_value_location,
1536 EnumValueDescriptorProto::kNameFieldNumber);
1537 location.RecordLegacyLocation(
1538 enum_value, DescriptorPool::ErrorCollector::NAME);
1539 DO(ConsumeIdentifier(enum_value->mutable_name(),
1540 "Expected enum constant name."));
1541 }
1542
temporal40ee5512008-07-10 02:12:20 +00001543 DO(Consume("=", "Missing numeric value for enum constant."));
1544
liujisi@google.com33165fe2010-11-02 13:14:58 +00001545 // Parse value.
1546 {
1547 LocationRecorder location(
1548 enum_value_location, EnumValueDescriptorProto::kNumberFieldNumber);
1549 location.RecordLegacyLocation(
1550 enum_value, DescriptorPool::ErrorCollector::NUMBER);
temporal40ee5512008-07-10 02:12:20 +00001551
liujisi@google.com33165fe2010-11-02 13:14:58 +00001552 int number;
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001553 DO(ConsumeSignedInteger(&number, "Expected integer."));
liujisi@google.com33165fe2010-11-02 13:14:58 +00001554 enum_value->set_number(number);
1555 }
1556
jieluo@google.com4de8f552014-07-18 00:47:59 +00001557 DO(ParseEnumConstantOptions(enum_value, enum_value_location,
1558 containing_file));
temporal40ee5512008-07-10 02:12:20 +00001559
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001560 DO(ConsumeEndOfDeclaration(";", &enum_value_location));
temporal40ee5512008-07-10 02:12:20 +00001561
1562 return true;
1563}
1564
liujisi@google.com33165fe2010-11-02 13:14:58 +00001565bool Parser::ParseEnumConstantOptions(
1566 EnumValueDescriptorProto* value,
jieluo@google.com4de8f552014-07-18 00:47:59 +00001567 const LocationRecorder& enum_value_location,
1568 const FileDescriptorProto* containing_file) {
liujisi@google.com33165fe2010-11-02 13:14:58 +00001569 if (!LookingAt("[")) return true;
1570
1571 LocationRecorder location(
1572 enum_value_location, EnumValueDescriptorProto::kOptionsFieldNumber);
1573
1574 DO(Consume("["));
kenton@google.com26bd9ee2008-11-21 00:06:27 +00001575
1576 do {
jieluo@google.com4de8f552014-07-18 00:47:59 +00001577 DO(ParseOption(value->mutable_options(), location,
1578 containing_file, OPTION_ASSIGNMENT));
kenton@google.com26bd9ee2008-11-21 00:06:27 +00001579 } while (TryConsume(","));
1580
1581 DO(Consume("]"));
1582 return true;
1583}
1584
temporal40ee5512008-07-10 02:12:20 +00001585// -------------------------------------------------------------------
1586// Services
1587
jieluo@google.com4de8f552014-07-18 00:47:59 +00001588bool Parser::ParseServiceDefinition(
1589 ServiceDescriptorProto* service,
1590 const LocationRecorder& service_location,
1591 const FileDescriptorProto* containing_file) {
temporal40ee5512008-07-10 02:12:20 +00001592 DO(Consume("service"));
liujisi@google.com33165fe2010-11-02 13:14:58 +00001593
1594 {
1595 LocationRecorder location(service_location,
1596 ServiceDescriptorProto::kNameFieldNumber);
1597 location.RecordLegacyLocation(
1598 service, DescriptorPool::ErrorCollector::NAME);
1599 DO(ConsumeIdentifier(service->mutable_name(), "Expected service name."));
1600 }
1601
jieluo@google.com4de8f552014-07-18 00:47:59 +00001602 DO(ParseServiceBlock(service, service_location, containing_file));
temporal40ee5512008-07-10 02:12:20 +00001603 return true;
1604}
1605
liujisi@google.com33165fe2010-11-02 13:14:58 +00001606bool Parser::ParseServiceBlock(ServiceDescriptorProto* service,
jieluo@google.com4de8f552014-07-18 00:47:59 +00001607 const LocationRecorder& service_location,
1608 const FileDescriptorProto* containing_file) {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001609 DO(ConsumeEndOfDeclaration("{", &service_location));
temporal40ee5512008-07-10 02:12:20 +00001610
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001611 while (!TryConsumeEndOfDeclaration("}", NULL)) {
temporal40ee5512008-07-10 02:12:20 +00001612 if (AtEnd()) {
1613 AddError("Reached end of input in service definition (missing '}').");
1614 return false;
1615 }
1616
jieluo@google.com4de8f552014-07-18 00:47:59 +00001617 if (!ParseServiceStatement(service, service_location, containing_file)) {
temporal40ee5512008-07-10 02:12:20 +00001618 // This statement failed to parse. Skip it, but keep looping to parse
1619 // other statements.
1620 SkipStatement();
1621 }
1622 }
1623
1624 return true;
1625}
1626
liujisi@google.com33165fe2010-11-02 13:14:58 +00001627bool Parser::ParseServiceStatement(ServiceDescriptorProto* service,
jieluo@google.com4de8f552014-07-18 00:47:59 +00001628 const LocationRecorder& service_location,
1629 const FileDescriptorProto* containing_file) {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001630 if (TryConsumeEndOfDeclaration(";", NULL)) {
temporal40ee5512008-07-10 02:12:20 +00001631 // empty statement; ignore
1632 return true;
1633 } else if (LookingAt("option")) {
liujisi@google.com33165fe2010-11-02 13:14:58 +00001634 LocationRecorder location(
1635 service_location, ServiceDescriptorProto::kOptionsFieldNumber);
jieluo@google.com4de8f552014-07-18 00:47:59 +00001636 return ParseOption(service->mutable_options(), location,
1637 containing_file, OPTION_STATEMENT);
temporal40ee5512008-07-10 02:12:20 +00001638 } else {
liujisi@google.com33165fe2010-11-02 13:14:58 +00001639 LocationRecorder location(service_location,
1640 ServiceDescriptorProto::kMethodFieldNumber, service->method_size());
jieluo@google.com4de8f552014-07-18 00:47:59 +00001641 return ParseServiceMethod(service->add_method(), location, containing_file);
temporal40ee5512008-07-10 02:12:20 +00001642 }
1643}
1644
liujisi@google.com33165fe2010-11-02 13:14:58 +00001645bool Parser::ParseServiceMethod(MethodDescriptorProto* method,
jieluo@google.com4de8f552014-07-18 00:47:59 +00001646 const LocationRecorder& method_location,
1647 const FileDescriptorProto* containing_file) {
temporal40ee5512008-07-10 02:12:20 +00001648 DO(Consume("rpc"));
liujisi@google.com33165fe2010-11-02 13:14:58 +00001649
1650 {
1651 LocationRecorder location(method_location,
1652 MethodDescriptorProto::kNameFieldNumber);
1653 location.RecordLegacyLocation(
1654 method, DescriptorPool::ErrorCollector::NAME);
1655 DO(ConsumeIdentifier(method->mutable_name(), "Expected method name."));
1656 }
temporal40ee5512008-07-10 02:12:20 +00001657
1658 // Parse input type.
1659 DO(Consume("("));
liujisi@google.com33165fe2010-11-02 13:14:58 +00001660 {
Jisi Liu885b6122015-02-28 14:51:22 -08001661 if (LookingAt("stream")) {
1662 LocationRecorder location(
1663 method_location, MethodDescriptorProto::kClientStreamingFieldNumber);
1664 location.RecordLegacyLocation(
1665 method, DescriptorPool::ErrorCollector::OTHER);
Feng Xiao99aa0f92014-11-20 16:18:53 -08001666 method->set_client_streaming(true);
Jisi Liu885b6122015-02-28 14:51:22 -08001667 DO(Consume("stream"));
1668
Feng Xiao99aa0f92014-11-20 16:18:53 -08001669 }
liujisi@google.com33165fe2010-11-02 13:14:58 +00001670 LocationRecorder location(method_location,
1671 MethodDescriptorProto::kInputTypeFieldNumber);
1672 location.RecordLegacyLocation(
1673 method, DescriptorPool::ErrorCollector::INPUT_TYPE);
1674 DO(ParseUserDefinedType(method->mutable_input_type()));
1675 }
temporal40ee5512008-07-10 02:12:20 +00001676 DO(Consume(")"));
1677
1678 // Parse output type.
1679 DO(Consume("returns"));
1680 DO(Consume("("));
liujisi@google.com33165fe2010-11-02 13:14:58 +00001681 {
Jisi Liu885b6122015-02-28 14:51:22 -08001682 if (LookingAt("stream")) {
1683 LocationRecorder location(
1684 method_location, MethodDescriptorProto::kServerStreamingFieldNumber);
1685 location.RecordLegacyLocation(
1686 method, DescriptorPool::ErrorCollector::OTHER);
1687 DO(Consume("stream"));
Feng Xiao99aa0f92014-11-20 16:18:53 -08001688 method->set_server_streaming(true);
Jisi Liu885b6122015-02-28 14:51:22 -08001689
Feng Xiao99aa0f92014-11-20 16:18:53 -08001690 }
liujisi@google.com33165fe2010-11-02 13:14:58 +00001691 LocationRecorder location(method_location,
1692 MethodDescriptorProto::kOutputTypeFieldNumber);
1693 location.RecordLegacyLocation(
1694 method, DescriptorPool::ErrorCollector::OUTPUT_TYPE);
1695 DO(ParseUserDefinedType(method->mutable_output_type()));
1696 }
temporal40ee5512008-07-10 02:12:20 +00001697 DO(Consume(")"));
1698
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001699 if (LookingAt("{")) {
temporal40ee5512008-07-10 02:12:20 +00001700 // Options!
Jisi Liu885b6122015-02-28 14:51:22 -08001701 DO(ParseMethodOptions(method_location, containing_file,
1702 MethodDescriptorProto::kOptionsFieldNumber,
1703 method->mutable_options()));
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001704 } else {
1705 DO(ConsumeEndOfDeclaration(";", &method_location));
1706 }
temporal40ee5512008-07-10 02:12:20 +00001707
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001708 return true;
1709}
1710
1711
Jisi Liu885b6122015-02-28 14:51:22 -08001712bool Parser::ParseMethodOptions(const LocationRecorder& parent_location,
1713 const FileDescriptorProto* containing_file,
1714 const int optionsFieldNumber,
1715 Message* mutable_options) {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001716 // Options!
1717 ConsumeEndOfDeclaration("{", &parent_location);
1718 while (!TryConsumeEndOfDeclaration("}", NULL)) {
1719 if (AtEnd()) {
1720 AddError("Reached end of input in method options (missing '}').");
1721 return false;
1722 }
1723
1724 if (TryConsumeEndOfDeclaration(";", NULL)) {
1725 // empty statement; ignore
1726 } else {
1727 LocationRecorder location(parent_location,
1728 optionsFieldNumber);
Jisi Liu885b6122015-02-28 14:51:22 -08001729 if (!ParseOption(mutable_options, location,
1730 containing_file, OPTION_STATEMENT)) {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001731 // This statement failed to parse. Skip it, but keep looping to
1732 // parse other statements.
1733 SkipStatement();
temporal40ee5512008-07-10 02:12:20 +00001734 }
1735 }
temporal40ee5512008-07-10 02:12:20 +00001736 }
1737
1738 return true;
1739}
1740
1741// -------------------------------------------------------------------
1742
jieluo@google.com4de8f552014-07-18 00:47:59 +00001743bool Parser::ParseLabel(FieldDescriptorProto::Label* label,
1744 const FileDescriptorProto* containing_file) {
temporal40ee5512008-07-10 02:12:20 +00001745 if (TryConsume("optional")) {
1746 *label = FieldDescriptorProto::LABEL_OPTIONAL;
1747 return true;
1748 } else if (TryConsume("repeated")) {
1749 *label = FieldDescriptorProto::LABEL_REPEATED;
1750 return true;
1751 } else if (TryConsume("required")) {
1752 *label = FieldDescriptorProto::LABEL_REQUIRED;
1753 return true;
temporal40ee5512008-07-10 02:12:20 +00001754 }
Feng Xiao6ef984a2014-11-10 17:34:54 -08001755 return false;
temporal40ee5512008-07-10 02:12:20 +00001756}
1757
1758bool Parser::ParseType(FieldDescriptorProto::Type* type,
1759 string* type_name) {
1760 TypeNameMap::const_iterator iter = kTypeNames.find(input_->current().text);
1761 if (iter != kTypeNames.end()) {
1762 *type = iter->second;
1763 input_->Next();
1764 } else {
1765 DO(ParseUserDefinedType(type_name));
1766 }
1767 return true;
1768}
1769
1770bool Parser::ParseUserDefinedType(string* type_name) {
1771 type_name->clear();
1772
1773 TypeNameMap::const_iterator iter = kTypeNames.find(input_->current().text);
1774 if (iter != kTypeNames.end()) {
1775 // Note: The only place enum types are allowed is for field types, but
1776 // if we are parsing a field type then we would not get here because
1777 // primitives are allowed there as well. So this error message doesn't
1778 // need to account for enums.
1779 AddError("Expected message type.");
1780
1781 // Pretend to accept this type so that we can go on parsing.
1782 *type_name = input_->current().text;
1783 input_->Next();
1784 return true;
1785 }
1786
1787 // A leading "." means the name is fully-qualified.
1788 if (TryConsume(".")) type_name->append(".");
1789
1790 // Consume the first part of the name.
1791 string identifier;
1792 DO(ConsumeIdentifier(&identifier, "Expected type name."));
1793 type_name->append(identifier);
1794
1795 // Consume more parts.
1796 while (TryConsume(".")) {
1797 type_name->append(".");
1798 DO(ConsumeIdentifier(&identifier, "Expected identifier."));
1799 type_name->append(identifier);
1800 }
1801
1802 return true;
1803}
1804
1805// ===================================================================
1806
liujisi@google.com33165fe2010-11-02 13:14:58 +00001807bool Parser::ParsePackage(FileDescriptorProto* file,
jieluo@google.com4de8f552014-07-18 00:47:59 +00001808 const LocationRecorder& root_location,
1809 const FileDescriptorProto* containing_file) {
temporal40ee5512008-07-10 02:12:20 +00001810 if (file->has_package()) {
1811 AddError("Multiple package definitions.");
temporalf2063512008-07-23 01:19:07 +00001812 // Don't append the new package to the old one. Just replace it. Not
1813 // that it really matters since this is an error anyway.
1814 file->clear_package();
temporal40ee5512008-07-10 02:12:20 +00001815 }
1816
1817 DO(Consume("package"));
1818
liujisi@google.com33165fe2010-11-02 13:14:58 +00001819 {
1820 LocationRecorder location(root_location,
1821 FileDescriptorProto::kPackageFieldNumber);
1822 location.RecordLegacyLocation(file, DescriptorPool::ErrorCollector::NAME);
temporal40ee5512008-07-10 02:12:20 +00001823
liujisi@google.com33165fe2010-11-02 13:14:58 +00001824 while (true) {
1825 string identifier;
1826 DO(ConsumeIdentifier(&identifier, "Expected identifier."));
1827 file->mutable_package()->append(identifier);
1828 if (!TryConsume(".")) break;
1829 file->mutable_package()->append(".");
1830 }
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001831
1832 location.EndAt(input_->previous());
1833
1834 DO(ConsumeEndOfDeclaration(";", &location));
temporal40ee5512008-07-10 02:12:20 +00001835 }
1836
temporal40ee5512008-07-10 02:12:20 +00001837 return true;
1838}
1839
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001840bool Parser::ParseImport(RepeatedPtrField<string>* dependency,
1841 RepeatedField<int32>* public_dependency,
1842 RepeatedField<int32>* weak_dependency,
jieluo@google.com4de8f552014-07-18 00:47:59 +00001843 const LocationRecorder& root_location,
1844 const FileDescriptorProto* containing_file) {
temporal40ee5512008-07-10 02:12:20 +00001845 DO(Consume("import"));
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001846 if (LookingAt("public")) {
1847 LocationRecorder location(
1848 root_location, FileDescriptorProto::kPublicDependencyFieldNumber,
1849 public_dependency->size());
1850 DO(Consume("public"));
1851 *public_dependency->Add() = dependency->size();
1852 } else if (LookingAt("weak")) {
1853 LocationRecorder location(
1854 root_location, FileDescriptorProto::kWeakDependencyFieldNumber,
1855 weak_dependency->size());
1856 DO(Consume("weak"));
1857 *weak_dependency->Add() = dependency->size();
1858 }
liujisi@google.com33165fe2010-11-02 13:14:58 +00001859 {
1860 LocationRecorder location(root_location,
1861 FileDescriptorProto::kDependencyFieldNumber,
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001862 dependency->size());
1863 DO(ConsumeString(dependency->Add(),
liujisi@google.com33165fe2010-11-02 13:14:58 +00001864 "Expected a string naming the file to import."));
temporal40ee5512008-07-10 02:12:20 +00001865
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001866 location.EndAt(input_->previous());
1867
1868 DO(ConsumeEndOfDeclaration(";", &location));
1869 }
temporal40ee5512008-07-10 02:12:20 +00001870 return true;
1871}
1872
1873// ===================================================================
1874
1875SourceLocationTable::SourceLocationTable() {}
1876SourceLocationTable::~SourceLocationTable() {}
1877
1878bool SourceLocationTable::Find(
1879 const Message* descriptor,
1880 DescriptorPool::ErrorCollector::ErrorLocation location,
1881 int* line, int* column) const {
1882 const pair<int, int>* result =
Jisi Liu885b6122015-02-28 14:51:22 -08001883 FindOrNull(location_map_, std::make_pair(descriptor, location));
temporal40ee5512008-07-10 02:12:20 +00001884 if (result == NULL) {
1885 *line = -1;
1886 *column = 0;
1887 return false;
1888 } else {
1889 *line = result->first;
1890 *column = result->second;
1891 return true;
1892 }
1893}
1894
1895void SourceLocationTable::Add(
1896 const Message* descriptor,
1897 DescriptorPool::ErrorCollector::ErrorLocation location,
1898 int line, int column) {
Jisi Liu885b6122015-02-28 14:51:22 -08001899 location_map_[std::make_pair(descriptor, location)] =
1900 std::make_pair(line, column);
temporal40ee5512008-07-10 02:12:20 +00001901}
1902
1903void SourceLocationTable::Clear() {
1904 location_map_.clear();
1905}
1906
1907} // namespace compiler
1908} // namespace protobuf
1909} // namespace google