Index: third_party/protobuf/src/google/protobuf/compiler/parser.cc |
=================================================================== |
--- third_party/protobuf/src/google/protobuf/compiler/parser.cc (revision 216642) |
+++ third_party/protobuf/src/google/protobuf/compiler/parser.cc (working copy) |
@@ -174,6 +174,20 @@ |
} |
} |
+bool Parser::ConsumeSignedInteger(int* output, const char* error) { |
+ bool is_negative = false; |
+ uint64 max_value = kint32max; |
+ if (TryConsume("-")) { |
+ is_negative = true; |
+ max_value += 1; |
+ } |
+ uint64 value = 0; |
+ DO(ConsumeInteger64(max_value, &value, error)); |
+ if (is_negative) value *= -1; |
+ *output = value; |
+ return true; |
+} |
+ |
bool Parser::ConsumeInteger64(uint64 max_value, uint64* output, |
const char* error) { |
if (LookingAtType(io::Tokenizer::TYPE_INTEGER)) { |
@@ -237,6 +251,35 @@ |
} |
} |
+bool Parser::TryConsumeEndOfDeclaration(const char* text, |
+ const LocationRecorder* location) { |
+ if (LookingAt(text)) { |
+ string leading, trailing; |
+ input_->NextWithComments(&trailing, NULL, &leading); |
+ |
+ // Save the leading comments for next time, and recall the leading comments |
+ // from last time. |
+ leading.swap(upcoming_doc_comments_); |
+ |
+ if (location != NULL) { |
+ location->AttachComments(&leading, &trailing); |
+ } |
+ return true; |
+ } else { |
+ return false; |
+ } |
+} |
+ |
+bool Parser::ConsumeEndOfDeclaration(const char* text, |
+ const LocationRecorder* location) { |
+ if (TryConsumeEndOfDeclaration(text, location)) { |
+ return true; |
+ } else { |
+ AddError("Expected \"" + string(text) + "\"."); |
+ return false; |
+ } |
+} |
+ |
// ------------------------------------------------------------------- |
void Parser::AddError(int line, int column, const string& error) { |
@@ -315,6 +358,19 @@ |
} |
} |
+void Parser::LocationRecorder::AttachComments( |
+ string* leading, string* trailing) const { |
+ GOOGLE_CHECK(!location_->has_leading_comments()); |
+ GOOGLE_CHECK(!location_->has_trailing_comments()); |
+ |
+ if (!leading->empty()) { |
+ location_->mutable_leading_comments()->swap(*leading); |
+ } |
+ if (!trailing->empty()) { |
+ location_->mutable_trailing_comments()->swap(*trailing); |
+ } |
+} |
+ |
// ------------------------------------------------------------------- |
void Parser::SkipStatement() { |
@@ -322,7 +378,7 @@ |
if (AtEnd()) { |
return; |
} else if (LookingAtType(io::Tokenizer::TYPE_SYMBOL)) { |
- if (TryConsume(";")) { |
+ if (TryConsumeEndOfDeclaration(";", NULL)) { |
return; |
} else if (TryConsume("{")) { |
SkipRestOfBlock(); |
@@ -340,7 +396,7 @@ |
if (AtEnd()) { |
return; |
} else if (LookingAtType(io::Tokenizer::TYPE_SYMBOL)) { |
- if (TryConsume("}")) { |
+ if (TryConsumeEndOfDeclaration("}", NULL)) { |
return; |
} else if (TryConsume("{")) { |
SkipRestOfBlock(); |
@@ -366,7 +422,7 @@ |
if (LookingAtType(io::Tokenizer::TYPE_START)) { |
// Advance to first token. |
- input_->Next(); |
+ input_->NextWithComments(NULL, NULL, &upcoming_doc_comments_); |
} |
{ |
@@ -393,7 +449,7 @@ |
if (LookingAt("}")) { |
AddError("Unmatched \"}\"."); |
- input_->Next(); |
+ input_->NextWithComments(NULL, NULL, &upcoming_doc_comments_); |
} |
} |
} |
@@ -411,7 +467,7 @@ |
io::Tokenizer::Token syntax_token = input_->current(); |
string syntax; |
DO(ConsumeString(&syntax, "Expected syntax identifier.")); |
- DO(Consume(";")); |
+ DO(ConsumeEndOfDeclaration(";", NULL)); |
syntax_identifier_ = syntax; |
@@ -427,7 +483,7 @@ |
bool Parser::ParseTopLevelStatement(FileDescriptorProto* file, |
const LocationRecorder& root_location) { |
- if (TryConsume(";")) { |
+ if (TryConsumeEndOfDeclaration(";", NULL)) { |
// empty statement; ignore |
return true; |
} else if (LookingAt("message")) { |
@@ -451,14 +507,16 @@ |
FileDescriptorProto::kMessageTypeFieldNumber, |
location); |
} else if (LookingAt("import")) { |
- int index = file->dependency_size(); |
- return ParseImport(file->add_dependency(), root_location, index); |
+ return ParseImport(file->mutable_dependency(), |
+ file->mutable_public_dependency(), |
+ file->mutable_weak_dependency(), |
+ root_location); |
} else if (LookingAt("package")) { |
return ParsePackage(file, root_location); |
} else if (LookingAt("option")) { |
LocationRecorder location(root_location, |
FileDescriptorProto::kOptionsFieldNumber); |
- return ParseOption(file->mutable_options(), location); |
+ return ParseOption(file->mutable_options(), location, OPTION_STATEMENT); |
} else { |
AddError("Expected top-level statement (e.g. \"message\")."); |
return false; |
@@ -482,11 +540,45 @@ |
return true; |
} |
+namespace { |
+ |
+const int kMaxExtensionRangeSentinel = -1; |
+ |
+bool IsMessageSetWireFormatMessage(const DescriptorProto& message) { |
+ const MessageOptions& options = message.options(); |
+ for (int i = 0; i < options.uninterpreted_option_size(); ++i) { |
+ const UninterpretedOption& uninterpreted = options.uninterpreted_option(i); |
+ if (uninterpreted.name_size() == 1 && |
+ uninterpreted.name(0).name_part() == "message_set_wire_format" && |
+ uninterpreted.identifier_value() == "true") { |
+ return true; |
+ } |
+ } |
+ return false; |
+} |
+ |
+// Modifies any extension ranges that specified 'max' as the end of the |
+// extension range, and sets them to the type-specific maximum. The actual max |
+// tag number can only be determined after all options have been parsed. |
+void AdjustExtensionRangesWithMaxEndNumber(DescriptorProto* message) { |
+ const bool is_message_set = IsMessageSetWireFormatMessage(*message); |
+ const int max_extension_number = is_message_set ? |
+ kint32max : |
+ FieldDescriptor::kMaxNumber + 1; |
+ for (int i = 0; i < message->extension_range_size(); ++i) { |
+ if (message->extension_range(i).end() == kMaxExtensionRangeSentinel) { |
+ message->mutable_extension_range(i)->set_end(max_extension_number); |
+ } |
+ } |
+} |
+ |
+} // namespace |
+ |
bool Parser::ParseMessageBlock(DescriptorProto* message, |
const LocationRecorder& message_location) { |
- DO(Consume("{")); |
+ DO(ConsumeEndOfDeclaration("{", &message_location)); |
- while (!TryConsume("}")) { |
+ while (!TryConsumeEndOfDeclaration("}", NULL)) { |
if (AtEnd()) { |
AddError("Reached end of input in message definition (missing '}')."); |
return false; |
@@ -499,12 +591,15 @@ |
} |
} |
+ if (message->extension_range_size() > 0) { |
+ AdjustExtensionRangesWithMaxEndNumber(message); |
+ } |
return true; |
} |
bool Parser::ParseMessageStatement(DescriptorProto* message, |
const LocationRecorder& message_location) { |
- if (TryConsume(";")) { |
+ if (TryConsumeEndOfDeclaration(";", NULL)) { |
// empty statement; ignore |
return true; |
} else if (LookingAt("message")) { |
@@ -532,7 +627,7 @@ |
} else if (LookingAt("option")) { |
LocationRecorder location(message_location, |
DescriptorProto::kOptionsFieldNumber); |
- return ParseOption(message->mutable_options(), location); |
+ return ParseOption(message->mutable_options(), location, OPTION_STATEMENT); |
} else { |
LocationRecorder location(message_location, |
DescriptorProto::kFieldFieldNumber, |
@@ -647,7 +742,7 @@ |
return false; |
} |
} else { |
- DO(Consume(";")); |
+ DO(ConsumeEndOfDeclaration(";", &field_location)); |
} |
return true; |
@@ -669,7 +764,7 @@ |
// the default value is not actually an option. |
DO(ParseDefaultAssignment(field, field_location)); |
} else { |
- DO(ParseOptionAssignment(field->mutable_options(), location)); |
+ DO(ParseOption(field->mutable_options(), location, OPTION_ASSIGNMENT)); |
} |
} while (TryConsume(",")); |
@@ -835,6 +930,8 @@ |
bool Parser::ParseUninterpretedBlock(string* value) { |
// Note that enclosing braces are not added to *value. |
+ // We do NOT use ConsumeEndOfStatement for this brace because it's delimiting |
+ // an expression, not a block of statements. |
DO(Consume("{")); |
int brace_depth = 1; |
while (!AtEnd()) { |
@@ -858,8 +955,9 @@ |
// We don't interpret the option here. Instead we store it in an |
// UninterpretedOption, to be interpreted later. |
-bool Parser::ParseOptionAssignment(Message* options, |
- const LocationRecorder& options_location) { |
+bool Parser::ParseOption(Message* options, |
+ const LocationRecorder& options_location, |
+ OptionStyle style) { |
// Create an entry in the uninterpreted_option field. |
const FieldDescriptor* uninterpreted_option_field = options->GetDescriptor()-> |
FindFieldByName("uninterpreted_option"); |
@@ -872,6 +970,10 @@ |
options_location, uninterpreted_option_field->number(), |
reflection->FieldSize(*options, uninterpreted_option_field)); |
+ if (style == OPTION_STATEMENT) { |
+ DO(Consume("option")); |
+ } |
+ |
UninterpretedOption* uninterpreted_option = down_cast<UninterpretedOption*>( |
options->GetReflection()->AddMessage(options, |
uninterpreted_option_field)); |
@@ -899,84 +1001,93 @@ |
DO(Consume("=")); |
- LocationRecorder value_location(location); |
- value_location.RecordLegacyLocation( |
- uninterpreted_option, DescriptorPool::ErrorCollector::OPTION_VALUE); |
+ { |
+ LocationRecorder value_location(location); |
+ value_location.RecordLegacyLocation( |
+ uninterpreted_option, DescriptorPool::ErrorCollector::OPTION_VALUE); |
- // All values are a single token, except for negative numbers, which consist |
- // of a single '-' symbol, followed by a positive number. |
- bool is_negative = TryConsume("-"); |
+ // All values are a single token, except for negative numbers, which consist |
+ // of a single '-' symbol, followed by a positive number. |
+ bool is_negative = TryConsume("-"); |
- switch (input_->current().type) { |
- case io::Tokenizer::TYPE_START: |
- GOOGLE_LOG(FATAL) << "Trying to read value before any tokens have been read."; |
- return false; |
+ switch (input_->current().type) { |
+ case io::Tokenizer::TYPE_START: |
+ GOOGLE_LOG(FATAL) << "Trying to read value before any tokens have been read."; |
+ return false; |
- case io::Tokenizer::TYPE_END: |
- AddError("Unexpected end of stream while parsing option value."); |
- return false; |
- |
- case io::Tokenizer::TYPE_IDENTIFIER: { |
- value_location.AddPath(UninterpretedOption::kIdentifierValueFieldNumber); |
- if (is_negative) { |
- AddError("Invalid '-' symbol before identifier."); |
+ case io::Tokenizer::TYPE_END: |
+ AddError("Unexpected end of stream while parsing option value."); |
return false; |
- } |
- string value; |
- DO(ConsumeIdentifier(&value, "Expected identifier.")); |
- uninterpreted_option->set_identifier_value(value); |
- break; |
- } |
- case io::Tokenizer::TYPE_INTEGER: { |
- uint64 value; |
- uint64 max_value = |
- is_negative ? static_cast<uint64>(kint64max) + 1 : kuint64max; |
- DO(ConsumeInteger64(max_value, &value, "Expected integer.")); |
- if (is_negative) { |
+ case io::Tokenizer::TYPE_IDENTIFIER: { |
value_location.AddPath( |
- UninterpretedOption::kNegativeIntValueFieldNumber); |
- uninterpreted_option->set_negative_int_value(-static_cast<int64>(value)); |
- } else { |
- value_location.AddPath( |
- UninterpretedOption::kPositiveIntValueFieldNumber); |
- uninterpreted_option->set_positive_int_value(value); |
+ UninterpretedOption::kIdentifierValueFieldNumber); |
+ if (is_negative) { |
+ AddError("Invalid '-' symbol before identifier."); |
+ return false; |
+ } |
+ string value; |
+ DO(ConsumeIdentifier(&value, "Expected identifier.")); |
+ uninterpreted_option->set_identifier_value(value); |
+ break; |
} |
- break; |
- } |
- case io::Tokenizer::TYPE_FLOAT: { |
- value_location.AddPath(UninterpretedOption::kDoubleValueFieldNumber); |
- double value; |
- DO(ConsumeNumber(&value, "Expected number.")); |
- uninterpreted_option->set_double_value(is_negative ? -value : value); |
- break; |
- } |
+ case io::Tokenizer::TYPE_INTEGER: { |
+ uint64 value; |
+ uint64 max_value = |
+ is_negative ? static_cast<uint64>(kint64max) + 1 : kuint64max; |
+ DO(ConsumeInteger64(max_value, &value, "Expected integer.")); |
+ if (is_negative) { |
+ value_location.AddPath( |
+ UninterpretedOption::kNegativeIntValueFieldNumber); |
+ uninterpreted_option->set_negative_int_value( |
+ -static_cast<int64>(value)); |
+ } else { |
+ value_location.AddPath( |
+ UninterpretedOption::kPositiveIntValueFieldNumber); |
+ uninterpreted_option->set_positive_int_value(value); |
+ } |
+ break; |
+ } |
- case io::Tokenizer::TYPE_STRING: { |
- value_location.AddPath(UninterpretedOption::kStringValueFieldNumber); |
- if (is_negative) { |
- AddError("Invalid '-' symbol before string."); |
- return false; |
+ case io::Tokenizer::TYPE_FLOAT: { |
+ value_location.AddPath(UninterpretedOption::kDoubleValueFieldNumber); |
+ double value; |
+ DO(ConsumeNumber(&value, "Expected number.")); |
+ uninterpreted_option->set_double_value(is_negative ? -value : value); |
+ break; |
} |
- string value; |
- DO(ConsumeString(&value, "Expected string.")); |
- uninterpreted_option->set_string_value(value); |
- break; |
- } |
- case io::Tokenizer::TYPE_SYMBOL: |
- if (LookingAt("{")) { |
- value_location.AddPath(UninterpretedOption::kAggregateValueFieldNumber); |
- DO(ParseUninterpretedBlock( |
- uninterpreted_option->mutable_aggregate_value())); |
- } else { |
- AddError("Expected option value."); |
- return false; |
+ case io::Tokenizer::TYPE_STRING: { |
+ value_location.AddPath(UninterpretedOption::kStringValueFieldNumber); |
+ if (is_negative) { |
+ AddError("Invalid '-' symbol before string."); |
+ return false; |
+ } |
+ string value; |
+ DO(ConsumeString(&value, "Expected string.")); |
+ uninterpreted_option->set_string_value(value); |
+ break; |
} |
- break; |
+ |
+ case io::Tokenizer::TYPE_SYMBOL: |
+ if (LookingAt("{")) { |
+ value_location.AddPath( |
+ UninterpretedOption::kAggregateValueFieldNumber); |
+ DO(ParseUninterpretedBlock( |
+ uninterpreted_option->mutable_aggregate_value())); |
+ } else { |
+ AddError("Expected option value."); |
+ return false; |
+ } |
+ break; |
+ } |
} |
+ if (style == OPTION_STATEMENT) { |
+ DO(ConsumeEndOfDeclaration(";", &location)); |
+ } |
+ |
return true; |
} |
@@ -1008,7 +1119,10 @@ |
LocationRecorder end_location( |
location, DescriptorProto::ExtensionRange::kEndFieldNumber); |
if (TryConsume("max")) { |
- end = FieldDescriptor::kMaxNumber; |
+ // Set to the sentinel value - 1 since we increment the value below. |
+ // The actual value of the end of the range should be set with |
+ // AdjustExtensionRangesWithMaxEndNumber. |
+ end = kMaxExtensionRangeSentinel - 1; |
} else { |
DO(ConsumeInteger(&end, "Expected integer.")); |
} |
@@ -1028,7 +1142,7 @@ |
range->set_end(end); |
} while (TryConsume(",")); |
- DO(Consume(";")); |
+ DO(ConsumeEndOfDeclaration(";", &extensions_location)); |
return true; |
} |
@@ -1046,7 +1160,7 @@ |
io::Tokenizer::Token extendee_end = input_->previous(); |
// Parse the block. |
- DO(Consume("{")); |
+ DO(ConsumeEndOfDeclaration("{", &extend_location)); |
bool is_first = true; |
@@ -1083,7 +1197,7 @@ |
// other statements. |
SkipStatement(); |
} |
- } while(!TryConsume("}")); |
+ } while (!TryConsumeEndOfDeclaration("}", NULL)); |
return true; |
} |
@@ -1109,9 +1223,9 @@ |
bool Parser::ParseEnumBlock(EnumDescriptorProto* enum_type, |
const LocationRecorder& enum_location) { |
- DO(Consume("{")); |
+ DO(ConsumeEndOfDeclaration("{", &enum_location)); |
- while (!TryConsume("}")) { |
+ while (!TryConsumeEndOfDeclaration("}", NULL)) { |
if (AtEnd()) { |
AddError("Reached end of input in enum definition (missing '}')."); |
return false; |
@@ -1129,13 +1243,14 @@ |
bool Parser::ParseEnumStatement(EnumDescriptorProto* enum_type, |
const LocationRecorder& enum_location) { |
- if (TryConsume(";")) { |
+ if (TryConsumeEndOfDeclaration(";", NULL)) { |
// empty statement; ignore |
return true; |
} else if (LookingAt("option")) { |
LocationRecorder location(enum_location, |
EnumDescriptorProto::kOptionsFieldNumber); |
- return ParseOption(enum_type->mutable_options(), location); |
+ return ParseOption(enum_type->mutable_options(), location, |
+ OPTION_STATEMENT); |
} else { |
LocationRecorder location(enum_location, |
EnumDescriptorProto::kValueFieldNumber, enum_type->value_size()); |
@@ -1164,16 +1279,14 @@ |
location.RecordLegacyLocation( |
enum_value, DescriptorPool::ErrorCollector::NUMBER); |
- bool is_negative = TryConsume("-"); |
int number; |
- DO(ConsumeInteger(&number, "Expected integer.")); |
- if (is_negative) number *= -1; |
+ DO(ConsumeSignedInteger(&number, "Expected integer.")); |
enum_value->set_number(number); |
} |
DO(ParseEnumConstantOptions(enum_value, enum_value_location)); |
- DO(Consume(";")); |
+ DO(ConsumeEndOfDeclaration(";", &enum_value_location)); |
return true; |
} |
@@ -1189,7 +1302,7 @@ |
DO(Consume("[")); |
do { |
- DO(ParseOptionAssignment(value->mutable_options(), location)); |
+ DO(ParseOption(value->mutable_options(), location, OPTION_ASSIGNMENT)); |
} while (TryConsume(",")); |
DO(Consume("]")); |
@@ -1217,9 +1330,9 @@ |
bool Parser::ParseServiceBlock(ServiceDescriptorProto* service, |
const LocationRecorder& service_location) { |
- DO(Consume("{")); |
+ DO(ConsumeEndOfDeclaration("{", &service_location)); |
- while (!TryConsume("}")) { |
+ while (!TryConsumeEndOfDeclaration("}", NULL)) { |
if (AtEnd()) { |
AddError("Reached end of input in service definition (missing '}')."); |
return false; |
@@ -1237,13 +1350,13 @@ |
bool Parser::ParseServiceStatement(ServiceDescriptorProto* service, |
const LocationRecorder& service_location) { |
- if (TryConsume(";")) { |
+ if (TryConsumeEndOfDeclaration(";", NULL)) { |
// empty statement; ignore |
return true; |
} else if (LookingAt("option")) { |
LocationRecorder location( |
service_location, ServiceDescriptorProto::kOptionsFieldNumber); |
- return ParseOption(service->mutable_options(), location); |
+ return ParseOption(service->mutable_options(), location, OPTION_STATEMENT); |
} else { |
LocationRecorder location(service_location, |
ServiceDescriptorProto::kMethodFieldNumber, service->method_size()); |
@@ -1286,28 +1399,41 @@ |
} |
DO(Consume(")")); |
- if (TryConsume("{")) { |
+ if (LookingAt("{")) { |
// Options! |
- while (!TryConsume("}")) { |
- if (AtEnd()) { |
- AddError("Reached end of input in method options (missing '}')."); |
- return false; |
- } |
+ DO(ParseOptions(method_location, |
+ MethodDescriptorProto::kOptionsFieldNumber, |
+ method->mutable_options())); |
+ } else { |
+ DO(ConsumeEndOfDeclaration(";", &method_location)); |
+ } |
- if (TryConsume(";")) { |
- // empty statement; ignore |
- } else { |
- LocationRecorder location(method_location, |
- MethodDescriptorProto::kOptionsFieldNumber); |
- if (!ParseOption(method->mutable_options(), location)) { |
- // This statement failed to parse. Skip it, but keep looping to |
- // parse other statements. |
- SkipStatement(); |
- } |
+ return true; |
+} |
+ |
+ |
+bool Parser::ParseOptions(const LocationRecorder& parent_location, |
+ const int optionsFieldNumber, |
+ Message* mutable_options) { |
+ // Options! |
+ ConsumeEndOfDeclaration("{", &parent_location); |
+ while (!TryConsumeEndOfDeclaration("}", NULL)) { |
+ if (AtEnd()) { |
+ AddError("Reached end of input in method options (missing '}')."); |
+ return false; |
+ } |
+ |
+ if (TryConsumeEndOfDeclaration(";", NULL)) { |
+ // empty statement; ignore |
+ } else { |
+ LocationRecorder location(parent_location, |
+ optionsFieldNumber); |
+ if (!ParseOption(mutable_options, location, OPTION_STATEMENT)) { |
+ // This statement failed to parse. Skip it, but keep looping to |
+ // parse other statements. |
+ SkipStatement(); |
} |
} |
- } else { |
- DO(Consume(";")); |
} |
return true; |
@@ -1406,35 +1532,47 @@ |
if (!TryConsume(".")) break; |
file->mutable_package()->append("."); |
} |
+ |
+ location.EndAt(input_->previous()); |
+ |
+ DO(ConsumeEndOfDeclaration(";", &location)); |
} |
- DO(Consume(";")); |
return true; |
} |
-bool Parser::ParseImport(string* import_filename, |
- const LocationRecorder& root_location, |
- int index) { |
+bool Parser::ParseImport(RepeatedPtrField<string>* dependency, |
+ RepeatedField<int32>* public_dependency, |
+ RepeatedField<int32>* weak_dependency, |
+ const LocationRecorder& root_location) { |
DO(Consume("import")); |
+ if (LookingAt("public")) { |
+ LocationRecorder location( |
+ root_location, FileDescriptorProto::kPublicDependencyFieldNumber, |
+ public_dependency->size()); |
+ DO(Consume("public")); |
+ *public_dependency->Add() = dependency->size(); |
+ } else if (LookingAt("weak")) { |
+ LocationRecorder location( |
+ root_location, FileDescriptorProto::kWeakDependencyFieldNumber, |
+ weak_dependency->size()); |
+ DO(Consume("weak")); |
+ *weak_dependency->Add() = dependency->size(); |
+ } |
{ |
LocationRecorder location(root_location, |
FileDescriptorProto::kDependencyFieldNumber, |
- index); |
- DO(ConsumeString(import_filename, |
+ dependency->size()); |
+ DO(ConsumeString(dependency->Add(), |
"Expected a string naming the file to import.")); |
+ |
+ location.EndAt(input_->previous()); |
+ |
+ DO(ConsumeEndOfDeclaration(";", &location)); |
} |
- DO(Consume(";")); |
return true; |
} |
-bool Parser::ParseOption(Message* options, |
- const LocationRecorder& options_location) { |
- DO(Consume("option")); |
- DO(ParseOptionAssignment(options, options_location)); |
- DO(Consume(";")); |
- return true; |
-} |
- |
// =================================================================== |
SourceLocationTable::SourceLocationTable() {} |