| // Copyright 2017 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "fidl/parser.h" |
| |
| namespace fidl { |
| |
| #define TOKEN_PRIMITIVE_TYPE_CASES \ |
| case Token::Kind::kBool: \ |
| case Token::Kind::kStatus: \ |
| case Token::Kind::kInt8: \ |
| case Token::Kind::kInt16: \ |
| case Token::Kind::kInt32: \ |
| case Token::Kind::kInt64: \ |
| case Token::Kind::kUint8: \ |
| case Token::Kind::kUint16: \ |
| case Token::Kind::kUint32: \ |
| case Token::Kind::kUint64: \ |
| case Token::Kind::kFloat32: \ |
| case Token::Kind::kFloat64 |
| |
| #define TOKEN_TYPE_CASES \ |
| TOKEN_PRIMITIVE_TYPE_CASES: \ |
| case Token::Kind::kIdentifier: \ |
| case Token::Kind::kArray: \ |
| case Token::Kind::kVector: \ |
| case Token::Kind::kString: \ |
| case Token::Kind::kHandle: \ |
| case Token::Kind::kRequest |
| |
| #define TOKEN_LITERAL_CASES \ |
| case Token::Kind::kTrue: \ |
| case Token::Kind::kFalse: \ |
| case Token::Kind::kNumericLiteral: \ |
| case Token::Kind::kStringLiteral |
| |
| namespace { |
| enum { |
| More, |
| Done, |
| }; |
| } // namespace |
| |
| Parser::Parser(Lexer* lexer, ErrorReporter* error_reporter) |
| : lexer_(lexer), error_reporter_(error_reporter) { |
| handle_subtype_table_ = { |
| {"process", types::HandleSubtype::kProcess}, |
| {"thread", types::HandleSubtype::kThread}, |
| {"vmo", types::HandleSubtype::kVmo}, |
| {"channel", types::HandleSubtype::kChannel}, |
| {"event", types::HandleSubtype::kEvent}, |
| {"port", types::HandleSubtype::kPort}, |
| {"interrupt", types::HandleSubtype::kInterrupt}, |
| {"log", types::HandleSubtype::kLog}, |
| {"socket", types::HandleSubtype::kSocket}, |
| {"resource", types::HandleSubtype::kResource}, |
| {"eventpair", types::HandleSubtype::kEventpair}, |
| {"job", types::HandleSubtype::kJob}, |
| {"vmar", types::HandleSubtype::kVmar}, |
| {"fifo", types::HandleSubtype::kFifo}, |
| {"guest", types::HandleSubtype::kGuest}, |
| {"timer", types::HandleSubtype::kTimer}, |
| }; |
| |
| last_token_ = Lex(); |
| } |
| |
| bool Parser::LookupHandleSubtype(const raw::Identifier* identifier, |
| types::HandleSubtype* subtype_out) { |
| auto lookup = handle_subtype_table_.find(identifier->location.data()); |
| if (lookup == handle_subtype_table_.end()) { |
| return false; |
| } |
| *subtype_out = lookup->second; |
| return true; |
| } |
| |
| decltype(nullptr) Parser::Fail() { |
| if (ok_) { |
| auto token_location = last_token_.location(); |
| auto token_data = token_location.data(); |
| |
| SourceFile::Position position; |
| std::string surrounding_line = token_location.SourceLine(&position); |
| auto line_number = std::to_string(position.line); |
| auto column_number = std::to_string(position.column); |
| |
| std::string squiggle(position.column, ' '); |
| squiggle += "^"; |
| size_t squiggle_size = token_data.size(); |
| if (squiggle_size != 0u) { |
| --squiggle_size; |
| } |
| squiggle += std::string(squiggle_size, '~'); |
| // Some tokens (like string literals) can span multiple |
| // lines. Truncate the string to just one line at most. The |
| // containing line contains a newline, so drop it when |
| // comparing sizes. |
| size_t line_size = surrounding_line.size() - 1; |
| if (squiggle.size() > line_size) { |
| squiggle.resize(line_size); |
| } |
| |
| std::string error = "found unexpected token in file "; |
| error += token_location.source_file().filename(); |
| error += " on line " + line_number; |
| error += " column " + column_number + ":\n"; |
| error += surrounding_line; |
| error += squiggle + "\n"; |
| |
| error_reporter_->ReportError(std::move(error)); |
| ok_ = false; |
| } |
| return nullptr; |
| } |
| |
| std::unique_ptr<raw::Identifier> Parser::ParseIdentifier() { |
| auto identifier = ConsumeToken(Token::Kind::kIdentifier); |
| if (!Ok()) |
| return Fail(); |
| |
| return std::make_unique<raw::Identifier>(identifier.location()); |
| } |
| |
| std::unique_ptr<raw::CompoundIdentifier> Parser::ParseCompoundIdentifier() { |
| std::vector<std::unique_ptr<raw::Identifier>> components; |
| |
| components.emplace_back(ParseIdentifier()); |
| if (!Ok()) |
| return Fail(); |
| |
| auto parse_component = [&components, this]() { |
| switch (Peek()) { |
| default: |
| return Done; |
| |
| case Token::Kind::kDot: |
| ConsumeToken(Token::Kind::kDot); |
| if (Ok()) |
| components.emplace_back(ParseIdentifier()); |
| return More; |
| } |
| }; |
| |
| while (parse_component() == More) { |
| if (!Ok()) |
| return Fail(); |
| } |
| |
| return std::make_unique<raw::CompoundIdentifier>(std::move(components)); |
| } |
| |
| std::unique_ptr<raw::StringLiteral> Parser::ParseStringLiteral() { |
| auto string_literal = ConsumeToken(Token::Kind::kStringLiteral); |
| if (!Ok()) |
| return Fail(); |
| |
| return std::make_unique<raw::StringLiteral>(string_literal.location()); |
| } |
| |
| std::unique_ptr<raw::NumericLiteral> Parser::ParseNumericLiteral() { |
| auto numeric_literal = ConsumeToken(Token::Kind::kNumericLiteral); |
| if (!Ok()) |
| return Fail(); |
| |
| return std::make_unique<raw::NumericLiteral>(numeric_literal.location()); |
| } |
| |
| std::unique_ptr<raw::TrueLiteral> Parser::ParseTrueLiteral() { |
| ConsumeToken(Token::Kind::kTrue); |
| if (!Ok()) |
| return Fail(); |
| |
| return std::make_unique<raw::TrueLiteral>(); |
| } |
| |
| std::unique_ptr<raw::FalseLiteral> Parser::ParseFalseLiteral() { |
| ConsumeToken(Token::Kind::kFalse); |
| if (!Ok()) |
| return Fail(); |
| |
| return std::make_unique<raw::FalseLiteral>(); |
| } |
| |
| std::unique_ptr<raw::Literal> Parser::ParseLiteral() { |
| switch (Peek()) { |
| case Token::Kind::kStringLiteral: |
| return ParseStringLiteral(); |
| |
| case Token::Kind::kNumericLiteral: |
| return ParseNumericLiteral(); |
| |
| case Token::Kind::kTrue: |
| return ParseTrueLiteral(); |
| |
| case Token::Kind::kFalse: |
| return ParseFalseLiteral(); |
| |
| default: |
| return Fail(); |
| } |
| } |
| |
| std::unique_ptr<raw::Attribute> Parser::ParseAttribute() { |
| auto name = ParseIdentifier(); |
| if (!Ok()) |
| return Fail(); |
| std::unique_ptr<raw::StringLiteral> value; |
| if (MaybeConsumeToken(Token::Kind::kEqual)) { |
| value = ParseStringLiteral(); |
| if (!Ok()) |
| return Fail(); |
| } |
| return std::make_unique<raw::Attribute>(std::move(name), std::move(value)); |
| } |
| |
| std::unique_ptr<raw::AttributeList> Parser::ParseAttributeList() { |
| ConsumeToken(Token::Kind::kLeftSquare); |
| if (!Ok()) |
| return Fail(); |
| std::vector<std::unique_ptr<raw::Attribute>> attribute_list; |
| for (;;) { |
| attribute_list.emplace_back(ParseAttribute()); |
| if (!Ok()) |
| return Fail(); |
| if (!MaybeConsumeToken(Token::Kind::kComma)) |
| break; |
| } |
| ConsumeToken(Token::Kind::kRightSquare); |
| if (!Ok()) |
| return Fail(); |
| return std::make_unique<raw::AttributeList>(std::move(attribute_list)); |
| } |
| |
| std::unique_ptr<raw::AttributeList> Parser::MaybeParseAttributeList() { |
| if (Peek() == Token::Kind::kLeftSquare) |
| return ParseAttributeList(); |
| return nullptr; |
| } |
| |
| std::unique_ptr<raw::Constant> Parser::ParseConstant() { |
| switch (Peek()) { |
| case Token::Kind::kIdentifier: { |
| auto identifier = ParseCompoundIdentifier(); |
| if (!Ok()) |
| return Fail(); |
| return std::make_unique<raw::IdentifierConstant>(std::move(identifier)); |
| } |
| |
| TOKEN_LITERAL_CASES : { |
| auto literal = ParseLiteral(); |
| if (!Ok()) |
| return Fail(); |
| return std::make_unique<raw::LiteralConstant>(std::move(literal)); |
| } |
| |
| default: |
| return Fail(); |
| } |
| } |
| |
| std::unique_ptr<raw::Using> Parser::ParseUsing() { |
| ConsumeToken(Token::Kind::kUsing); |
| if (!Ok()) |
| return Fail(); |
| auto using_path = ParseCompoundIdentifier(); |
| if (!Ok()) |
| return Fail(); |
| |
| std::unique_ptr<raw::Identifier> maybe_alias; |
| if (MaybeConsumeToken(Token::Kind::kAs)) { |
| if (!Ok()) |
| return Fail(); |
| maybe_alias = ParseIdentifier(); |
| if (!Ok()) |
| return Fail(); |
| } |
| |
| return std::make_unique<raw::Using>(std::move(using_path), std::move(maybe_alias)); |
| } |
| |
| std::unique_ptr<raw::ArrayType> Parser::ParseArrayType() { |
| ConsumeToken(Token::Kind::kArray); |
| if (!Ok()) |
| return Fail(); |
| ConsumeToken(Token::Kind::kLeftAngle); |
| if (!Ok()) |
| return Fail(); |
| auto element_type = ParseType(); |
| if (!Ok()) |
| return Fail(); |
| ConsumeToken(Token::Kind::kRightAngle); |
| if (!Ok()) |
| return Fail(); |
| ConsumeToken(Token::Kind::kColon); |
| if (!Ok()) |
| return Fail(); |
| auto element_count = ParseConstant(); |
| if (!Ok()) |
| return Fail(); |
| |
| return std::make_unique<raw::ArrayType>(std::move(element_type), std::move(element_count)); |
| } |
| |
| std::unique_ptr<raw::VectorType> Parser::ParseVectorType() { |
| ConsumeToken(Token::Kind::kVector); |
| if (!Ok()) |
| return Fail(); |
| ConsumeToken(Token::Kind::kLeftAngle); |
| if (!Ok()) |
| return Fail(); |
| auto element_type = ParseType(); |
| if (!Ok()) |
| return Fail(); |
| ConsumeToken(Token::Kind::kRightAngle); |
| if (!Ok()) |
| return Fail(); |
| |
| std::unique_ptr<raw::Constant> maybe_element_count; |
| if (MaybeConsumeToken(Token::Kind::kColon)) { |
| if (!Ok()) |
| return Fail(); |
| maybe_element_count = ParseConstant(); |
| if (!Ok()) |
| return Fail(); |
| } |
| |
| auto nullability = types::Nullability::kNonnullable; |
| if (MaybeConsumeToken(Token::Kind::kQuestion)) { |
| nullability = types::Nullability::kNullable; |
| } |
| |
| return std::make_unique<raw::VectorType>(std::move(element_type), |
| std::move(maybe_element_count), nullability); |
| } |
| |
| std::unique_ptr<raw::StringType> Parser::ParseStringType() { |
| ConsumeToken(Token::Kind::kString); |
| if (!Ok()) |
| return Fail(); |
| |
| std::unique_ptr<raw::Constant> maybe_element_count; |
| if (MaybeConsumeToken(Token::Kind::kColon)) { |
| if (!Ok()) |
| return Fail(); |
| maybe_element_count = ParseConstant(); |
| if (!Ok()) |
| return Fail(); |
| } |
| |
| auto nullability = types::Nullability::kNonnullable; |
| if (MaybeConsumeToken(Token::Kind::kQuestion)) { |
| nullability = types::Nullability::kNullable; |
| } |
| |
| return std::make_unique<raw::StringType>(std::move(maybe_element_count), nullability); |
| } |
| |
| std::unique_ptr<raw::HandleType> Parser::ParseHandleType() { |
| ConsumeToken(Token::Kind::kHandle); |
| if (!Ok()) |
| return Fail(); |
| |
| auto subtype = types::HandleSubtype::kHandle; |
| if (MaybeConsumeToken(Token::Kind::kLeftAngle)) { |
| if (!Ok()) |
| return Fail(); |
| auto identifier = ParseIdentifier(); |
| if (!Ok()) |
| return Fail(); |
| if (!LookupHandleSubtype(identifier.get(), &subtype)) |
| return Fail(); |
| ConsumeToken(Token::Kind::kRightAngle); |
| if (!Ok()) |
| return Fail(); |
| } |
| |
| auto nullability = types::Nullability::kNonnullable; |
| if (MaybeConsumeToken(Token::Kind::kQuestion)) { |
| nullability = types::Nullability::kNullable; |
| } |
| |
| return std::make_unique<raw::HandleType>(subtype, nullability); |
| } |
| |
| std::unique_ptr<raw::PrimitiveType> Parser::ParsePrimitiveType() { |
| types::PrimitiveSubtype subtype; |
| |
| switch (Peek()) { |
| case Token::Kind::kBool: |
| subtype = types::PrimitiveSubtype::kBool; |
| break; |
| case Token::Kind::kStatus: |
| subtype = types::PrimitiveSubtype::kStatus; |
| break; |
| case Token::Kind::kInt8: |
| subtype = types::PrimitiveSubtype::kInt8; |
| break; |
| case Token::Kind::kInt16: |
| subtype = types::PrimitiveSubtype::kInt16; |
| break; |
| case Token::Kind::kInt32: |
| subtype = types::PrimitiveSubtype::kInt32; |
| break; |
| case Token::Kind::kInt64: |
| subtype = types::PrimitiveSubtype::kInt64; |
| break; |
| case Token::Kind::kUint8: |
| subtype = types::PrimitiveSubtype::kUint8; |
| break; |
| case Token::Kind::kUint16: |
| subtype = types::PrimitiveSubtype::kUint16; |
| break; |
| case Token::Kind::kUint32: |
| subtype = types::PrimitiveSubtype::kUint32; |
| break; |
| case Token::Kind::kUint64: |
| subtype = types::PrimitiveSubtype::kUint64; |
| break; |
| case Token::Kind::kFloat32: |
| subtype = types::PrimitiveSubtype::kFloat32; |
| break; |
| case Token::Kind::kFloat64: |
| subtype = types::PrimitiveSubtype::kFloat64; |
| break; |
| default: |
| return Fail(); |
| } |
| |
| ConsumeToken(Peek()); |
| if (!Ok()) |
| return Fail(); |
| return std::make_unique<raw::PrimitiveType>(subtype); |
| } |
| |
| std::unique_ptr<raw::RequestHandleType> Parser::ParseRequestHandleType() { |
| ConsumeToken(Token::Kind::kRequest); |
| if (!Ok()) |
| return Fail(); |
| ConsumeToken(Token::Kind::kLeftAngle); |
| if (!Ok()) |
| return Fail(); |
| auto identifier = ParseCompoundIdentifier(); |
| if (!Ok()) |
| return Fail(); |
| ConsumeToken(Token::Kind::kRightAngle); |
| if (!Ok()) |
| return Fail(); |
| |
| auto nullability = types::Nullability::kNonnullable; |
| if (MaybeConsumeToken(Token::Kind::kQuestion)) { |
| nullability = types::Nullability::kNullable; |
| } |
| |
| return std::make_unique<raw::RequestHandleType>(std::move(identifier), nullability); |
| } |
| |
| std::unique_ptr<raw::Type> Parser::ParseType() { |
| switch (Peek()) { |
| case Token::Kind::kIdentifier: { |
| auto identifier = ParseCompoundIdentifier(); |
| if (!Ok()) |
| return Fail(); |
| auto nullability = types::Nullability::kNonnullable; |
| if (MaybeConsumeToken(Token::Kind::kQuestion)) { |
| if (!Ok()) |
| return Fail(); |
| nullability = types::Nullability::kNullable; |
| } |
| return std::make_unique<raw::IdentifierType>(std::move(identifier), nullability); |
| } |
| |
| case Token::Kind::kArray: { |
| auto type = ParseArrayType(); |
| if (!Ok()) |
| return Fail(); |
| return type; |
| } |
| |
| case Token::Kind::kVector: { |
| auto type = ParseVectorType(); |
| if (!Ok()) |
| return Fail(); |
| return type; |
| } |
| |
| case Token::Kind::kString: { |
| auto type = ParseStringType(); |
| if (!Ok()) |
| return Fail(); |
| return type; |
| } |
| |
| case Token::Kind::kHandle: { |
| auto type = ParseHandleType(); |
| if (!Ok()) |
| return Fail(); |
| return type; |
| } |
| |
| case Token::Kind::kRequest: { |
| auto type = ParseRequestHandleType(); |
| if (!Ok()) |
| return Fail(); |
| return type; |
| } |
| |
| TOKEN_PRIMITIVE_TYPE_CASES : { |
| auto type = ParsePrimitiveType(); |
| if (!Ok()) |
| return Fail(); |
| return type; |
| } |
| |
| default: |
| return Fail(); |
| } |
| } |
| |
| std::unique_ptr<raw::ConstDeclaration> |
| Parser::ParseConstDeclaration(std::unique_ptr<raw::AttributeList> attributes) { |
| ConsumeToken(Token::Kind::kConst); |
| if (!Ok()) |
| return Fail(); |
| auto type = ParseType(); |
| if (!Ok()) |
| return Fail(); |
| auto identifier = ParseIdentifier(); |
| if (!Ok()) |
| return Fail(); |
| ConsumeToken(Token::Kind::kEqual); |
| if (!Ok()) |
| return Fail(); |
| auto constant = ParseConstant(); |
| if (!Ok()) |
| return Fail(); |
| |
| return std::make_unique<raw::ConstDeclaration>(std::move(attributes), std::move(type), |
| std::move(identifier), std::move(constant)); |
| } |
| |
| std::unique_ptr<raw::EnumMember> Parser::ParseEnumMember() { |
| auto identifier = ParseIdentifier(); |
| if (!Ok()) |
| return Fail(); |
| |
| ConsumeToken(Token::Kind::kEqual); |
| if (!Ok()) |
| return Fail(); |
| |
| auto member_value = ParseConstant(); |
| if (!Ok()) |
| return Fail(); |
| |
| return std::make_unique<raw::EnumMember>(std::move(identifier), std::move(member_value)); |
| } |
| |
| std::unique_ptr<raw::EnumDeclaration> |
| Parser::ParseEnumDeclaration(std::unique_ptr<raw::AttributeList> attributes) { |
| std::vector<std::unique_ptr<raw::EnumMember>> members; |
| |
| ConsumeToken(Token::Kind::kEnum); |
| if (!Ok()) |
| return Fail(); |
| auto identifier = ParseIdentifier(); |
| if (!Ok()) |
| return Fail(); |
| std::unique_ptr<raw::PrimitiveType> subtype; |
| if (MaybeConsumeToken(Token::Kind::kColon)) { |
| if (!Ok()) |
| return Fail(); |
| subtype = ParsePrimitiveType(); |
| if (!Ok()) |
| return Fail(); |
| } |
| ConsumeToken(Token::Kind::kLeftCurly); |
| if (!Ok()) |
| return Fail(); |
| |
| auto parse_member = [&members, this]() { |
| switch (Peek()) { |
| default: |
| ConsumeToken(Token::Kind::kRightCurly); |
| return Done; |
| |
| TOKEN_TYPE_CASES: |
| members.emplace_back(ParseEnumMember()); |
| return More; |
| } |
| }; |
| |
| while (parse_member() == More) { |
| if (!Ok()) |
| Fail(); |
| ConsumeToken(Token::Kind::kSemicolon); |
| if (!Ok()) |
| return Fail(); |
| } |
| if (!Ok()) |
| Fail(); |
| |
| if (members.empty()) |
| return Fail(); |
| |
| return std::make_unique<raw::EnumDeclaration>(std::move(attributes), std::move(identifier), |
| std::move(subtype), std::move(members)); |
| } |
| |
| std::unique_ptr<raw::Parameter> Parser::ParseParameter() { |
| auto type = ParseType(); |
| if (!Ok()) |
| return Fail(); |
| auto identifier = ParseIdentifier(); |
| if (!Ok()) |
| return Fail(); |
| |
| return std::make_unique<raw::Parameter>(std::move(type), std::move(identifier)); |
| } |
| |
| std::unique_ptr<raw::ParameterList> Parser::ParseParameterList() { |
| std::vector<std::unique_ptr<raw::Parameter>> parameter_list; |
| |
| switch (Peek()) { |
| default: |
| break; |
| |
| TOKEN_TYPE_CASES: |
| parameter_list.emplace_back(ParseParameter()); |
| if (!Ok()) |
| return Fail(); |
| while (Peek() == Token::Kind::kComma) { |
| ConsumeToken(Token::Kind::kComma); |
| if (!Ok()) |
| return Fail(); |
| switch (Peek()) { |
| TOKEN_TYPE_CASES: |
| parameter_list.emplace_back(ParseParameter()); |
| if (!Ok()) |
| return Fail(); |
| break; |
| |
| default: |
| return Fail(); |
| } |
| } |
| } |
| |
| return std::make_unique<raw::ParameterList>(std::move(parameter_list)); |
| } |
| |
| std::unique_ptr<raw::InterfaceMethod> Parser::ParseInterfaceMethod() { |
| auto ordinal = ParseNumericLiteral(); |
| if (!Ok()) |
| return Fail(); |
| ConsumeToken(Token::Kind::kColon); |
| if (!Ok()) |
| return Fail(); |
| |
| std::unique_ptr<raw::Identifier> method_name; |
| std::unique_ptr<raw::ParameterList> maybe_request; |
| std::unique_ptr<raw::ParameterList> maybe_response; |
| |
| auto parse_params = [this](std::unique_ptr<raw::ParameterList>* params_out) { |
| ConsumeToken(Token::Kind::kLeftParen); |
| if (!Ok()) |
| return false; |
| *params_out = ParseParameterList(); |
| if (!Ok()) |
| return false; |
| ConsumeToken(Token::Kind::kRightParen); |
| if (!Ok()) |
| return false; |
| return true; |
| }; |
| |
| if (MaybeConsumeToken(Token::Kind::kArrow)) { |
| method_name = ParseIdentifier(); |
| if (!Ok()) |
| return Fail(); |
| if (!parse_params(&maybe_response)) |
| return Fail(); |
| } else { |
| method_name = ParseIdentifier(); |
| if (!Ok()) |
| return Fail(); |
| if (!parse_params(&maybe_request)) |
| return Fail(); |
| |
| if (MaybeConsumeToken(Token::Kind::kArrow)) { |
| if (!Ok()) |
| return Fail(); |
| if (!parse_params(&maybe_response)) |
| return Fail(); |
| } |
| } |
| |
| assert(method_name); |
| assert(maybe_request || maybe_response); |
| |
| return std::make_unique<raw::InterfaceMethod>(std::move(ordinal), std::move(method_name), |
| std::move(maybe_request), |
| std::move(maybe_response)); |
| } |
| |
| std::unique_ptr<raw::InterfaceDeclaration> |
| Parser::ParseInterfaceDeclaration(std::unique_ptr<raw::AttributeList> attributes) { |
| std::vector<std::unique_ptr<raw::CompoundIdentifier>> superinterfaces; |
| std::vector<std::unique_ptr<raw::InterfaceMethod>> methods; |
| |
| ConsumeToken(Token::Kind::kInterface); |
| if (!Ok()) |
| return Fail(); |
| |
| auto identifier = ParseIdentifier(); |
| if (!Ok()) |
| return Fail(); |
| |
| if (MaybeConsumeToken(Token::Kind::kColon)) { |
| for (;;) { |
| superinterfaces.emplace_back(ParseCompoundIdentifier()); |
| if (!Ok()) |
| return Fail(); |
| if (!MaybeConsumeToken(Token::Kind::kComma)) |
| break; |
| } |
| } |
| |
| ConsumeToken(Token::Kind::kLeftCurly); |
| if (!Ok()) |
| return Fail(); |
| |
| auto parse_member = [&methods, this]() { |
| std::unique_ptr<raw::AttributeList> attributes = MaybeParseAttributeList(); |
| if (!Ok()) |
| return More; |
| |
| switch (Peek()) { |
| default: |
| ConsumeToken(Token::Kind::kRightCurly); |
| return Done; |
| |
| case Token::Kind::kNumericLiteral: |
| methods.emplace_back(ParseInterfaceMethod()); |
| return More; |
| } |
| }; |
| |
| while (parse_member() == More) { |
| if (!Ok()) |
| Fail(); |
| ConsumeToken(Token::Kind::kSemicolon); |
| if (!Ok()) |
| return Fail(); |
| } |
| if (!Ok()) |
| Fail(); |
| |
| return std::make_unique<raw::InterfaceDeclaration>(std::move(attributes), std::move(identifier), |
| std::move(superinterfaces), |
| std::move(methods)); |
| } |
| |
| std::unique_ptr<raw::StructMember> Parser::ParseStructMember() { |
| auto type = ParseType(); |
| if (!Ok()) |
| return Fail(); |
| auto identifier = ParseIdentifier(); |
| if (!Ok()) |
| return Fail(); |
| |
| std::unique_ptr<raw::Constant> maybe_default_value; |
| if (MaybeConsumeToken(Token::Kind::kEqual)) { |
| if (!Ok()) |
| return Fail(); |
| maybe_default_value = ParseConstant(); |
| if (!Ok()) |
| return Fail(); |
| } |
| |
| return std::make_unique<raw::StructMember>(std::move(type), std::move(identifier), |
| std::move(maybe_default_value)); |
| } |
| |
| std::unique_ptr<raw::StructDeclaration> |
| Parser::ParseStructDeclaration(std::unique_ptr<raw::AttributeList> attributes) { |
| std::vector<std::unique_ptr<raw::StructMember>> members; |
| |
| ConsumeToken(Token::Kind::kStruct); |
| if (!Ok()) |
| return Fail(); |
| auto identifier = ParseIdentifier(); |
| if (!Ok()) |
| return Fail(); |
| ConsumeToken(Token::Kind::kLeftCurly); |
| if (!Ok()) |
| return Fail(); |
| |
| auto parse_member = [&members, this]() { |
| std::unique_ptr<raw::AttributeList> attributes = MaybeParseAttributeList(); |
| if (!Ok()) |
| return More; |
| |
| switch (Peek()) { |
| default: |
| ConsumeToken(Token::Kind::kRightCurly); |
| return Done; |
| |
| TOKEN_TYPE_CASES: |
| members.emplace_back(ParseStructMember()); |
| return More; |
| } |
| }; |
| |
| while (parse_member() == More) { |
| if (!Ok()) |
| Fail(); |
| ConsumeToken(Token::Kind::kSemicolon); |
| if (!Ok()) |
| return Fail(); |
| } |
| if (!Ok()) |
| Fail(); |
| |
| if (members.empty()) |
| return Fail(); |
| |
| return std::make_unique<raw::StructDeclaration>(std::move(attributes), std::move(identifier), |
| std::move(members)); |
| } |
| |
| std::unique_ptr<raw::UnionMember> Parser::ParseUnionMember() { |
| auto type = ParseType(); |
| if (!Ok()) |
| return Fail(); |
| auto identifier = ParseIdentifier(); |
| if (!Ok()) |
| return Fail(); |
| |
| return std::make_unique<raw::UnionMember>(std::move(type), std::move(identifier)); |
| } |
| |
| std::unique_ptr<raw::UnionDeclaration> |
| Parser::ParseUnionDeclaration(std::unique_ptr<raw::AttributeList> attributes) { |
| std::vector<std::unique_ptr<raw::UnionMember>> members; |
| |
| ConsumeToken(Token::Kind::kUnion); |
| if (!Ok()) |
| return Fail(); |
| auto identifier = ParseIdentifier(); |
| if (!Ok()) |
| return Fail(); |
| ConsumeToken(Token::Kind::kLeftCurly); |
| if (!Ok()) |
| return Fail(); |
| |
| auto parse_member = [&members, this]() { |
| std::unique_ptr<raw::AttributeList> attributes = MaybeParseAttributeList(); |
| if (!Ok()) |
| return More; |
| |
| switch (Peek()) { |
| default: |
| ConsumeToken(Token::Kind::kRightCurly); |
| return Done; |
| |
| TOKEN_TYPE_CASES: |
| members.emplace_back(ParseUnionMember()); |
| return More; |
| } |
| }; |
| |
| while (parse_member() == More) { |
| if (!Ok()) |
| Fail(); |
| ConsumeToken(Token::Kind::kSemicolon); |
| if (!Ok()) |
| return Fail(); |
| } |
| if (!Ok()) |
| Fail(); |
| |
| if (members.empty()) |
| Fail(); |
| |
| return std::make_unique<raw::UnionDeclaration>(std::move(attributes), std::move(identifier), |
| std::move(members)); |
| } |
| |
| std::unique_ptr<raw::File> Parser::ParseFile() { |
| std::vector<std::unique_ptr<raw::Using>> using_list; |
| std::vector<std::unique_ptr<raw::ConstDeclaration>> const_declaration_list; |
| std::vector<std::unique_ptr<raw::EnumDeclaration>> enum_declaration_list; |
| std::vector<std::unique_ptr<raw::InterfaceDeclaration>> interface_declaration_list; |
| std::vector<std::unique_ptr<raw::StructDeclaration>> struct_declaration_list; |
| std::vector<std::unique_ptr<raw::UnionDeclaration>> union_declaration_list; |
| |
| ConsumeToken(Token::Kind::kLibrary); |
| if (!Ok()) |
| return Fail(); |
| auto library_name = ParseCompoundIdentifier(); |
| if (!Ok()) |
| return Fail(); |
| ConsumeToken(Token::Kind::kSemicolon); |
| if (!Ok()) |
| return Fail(); |
| |
| auto parse_using = [&using_list, this]() { |
| switch (Peek()) { |
| default: |
| return Done; |
| |
| case Token::Kind::kUsing: |
| using_list.emplace_back(ParseUsing()); |
| return More; |
| } |
| }; |
| |
| while (parse_using() == More) { |
| if (!Ok()) |
| return Fail(); |
| ConsumeToken(Token::Kind::kSemicolon); |
| if (!Ok()) |
| return Fail(); |
| } |
| |
| auto parse_declaration = [&const_declaration_list, &enum_declaration_list, |
| &interface_declaration_list, &struct_declaration_list, |
| &union_declaration_list, this]() { |
| std::unique_ptr<raw::AttributeList> attributes = MaybeParseAttributeList(); |
| if (!Ok()) |
| return More; |
| |
| switch (Peek()) { |
| default: |
| return Done; |
| |
| case Token::Kind::kConst: |
| const_declaration_list.emplace_back(ParseConstDeclaration(std::move(attributes))); |
| return More; |
| |
| case Token::Kind::kEnum: |
| enum_declaration_list.emplace_back(ParseEnumDeclaration(std::move(attributes))); |
| return More; |
| |
| case Token::Kind::kInterface: |
| interface_declaration_list.emplace_back( |
| ParseInterfaceDeclaration(std::move(attributes))); |
| return More; |
| |
| case Token::Kind::kStruct: |
| struct_declaration_list.emplace_back(ParseStructDeclaration(std::move(attributes))); |
| return More; |
| |
| case Token::Kind::kUnion: |
| union_declaration_list.emplace_back(ParseUnionDeclaration(std::move(attributes))); |
| return More; |
| } |
| }; |
| |
| while (parse_declaration() == More) { |
| if (!Ok()) |
| return Fail(); |
| ConsumeToken(Token::Kind::kSemicolon); |
| if (!Ok()) |
| return Fail(); |
| } |
| |
| ConsumeToken(Token::Kind::kEndOfFile); |
| if (!Ok()) |
| return Fail(); |
| |
| return std::make_unique<raw::File>( |
| std::move(library_name), std::move(using_list), std::move(const_declaration_list), |
| std::move(enum_declaration_list), std::move(interface_declaration_list), |
| std::move(struct_declaration_list), std::move(union_declaration_list)); |
| } |
| |
| } // namespace fidl |