| // 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::Bool: \ |
| case Token::Kind::Status: \ |
| case Token::Kind::Int8: \ |
| case Token::Kind::Int16: \ |
| case Token::Kind::Int32: \ |
| case Token::Kind::Int64: \ |
| case Token::Kind::Uint8: \ |
| case Token::Kind::Uint16: \ |
| case Token::Kind::Uint32: \ |
| case Token::Kind::Uint64: \ |
| case Token::Kind::Float32: \ |
| case Token::Kind::Float64 |
| |
| #define TOKEN_TYPE_CASES \ |
| TOKEN_PRIMITIVE_TYPE_CASES: \ |
| case Token::Kind::Identifier: \ |
| case Token::Kind::Array: \ |
| case Token::Kind::Vector: \ |
| case Token::Kind::String: \ |
| case Token::Kind::Handle: \ |
| case Token::Kind::Request |
| |
| #define TOKEN_LITERAL_CASES \ |
| case Token::Kind::Default: \ |
| case Token::Kind::True: \ |
| case Token::Kind::False: \ |
| case Token::Kind::NumericLiteral: \ |
| case Token::Kind::StringLiteral |
| |
| namespace { |
| enum { |
| More, |
| Done, |
| }; |
| } // namespace |
| |
| Parser::Parser(Lexer* lexer, ErrorReporter* error_reporter) |
| : lexer_(lexer) |
| , error_reporter_(error_reporter) { |
| handle_subtype_table_ = { |
| { "process", types::HandleSubtype::Process }, |
| { "thread", types::HandleSubtype::Thread }, |
| { "vmo", types::HandleSubtype::Vmo }, |
| { "channel", types::HandleSubtype::Channel }, |
| { "event", types::HandleSubtype::Event }, |
| { "port", types::HandleSubtype::Port }, |
| { "interrupt", types::HandleSubtype::Interrupt }, |
| { "iomap", types::HandleSubtype::Iomap }, |
| { "pci", types::HandleSubtype::Pci }, |
| { "log", types::HandleSubtype::Log }, |
| { "socket", types::HandleSubtype::Socket }, |
| { "resource", types::HandleSubtype::Resource }, |
| { "eventpair", types::HandleSubtype::Eventpair }, |
| { "job", types::HandleSubtype::Job }, |
| { "vmar", types::HandleSubtype::Vmar }, |
| { "fifo", types::HandleSubtype::Fifo }, |
| { "hypervisor", types::HandleSubtype::Hypervisor }, |
| { "guest", types::HandleSubtype::Guest }, |
| { "timer", types::HandleSubtype::Timer }, |
| }; |
| |
| last_token_ = Lex(); |
| } |
| |
| bool Parser::LookupHandleSubtype(const ast::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_) { |
| int line_number; |
| auto surrounding_line = last_token_.location().SourceLine(&line_number); |
| |
| std::string error = "found unexpected token: "; |
| error += last_token_.data(); |
| error += "\n"; |
| error += "on line #" + std::to_string(line_number) + ":\n\n"; |
| error += surrounding_line; |
| error += "\n"; |
| |
| error_reporter_->ReportError(error); |
| ok_ = false; |
| } |
| return nullptr; |
| } |
| |
| std::unique_ptr<ast::Identifier> Parser::ParseIdentifier() { |
| auto identifier = ConsumeToken(Token::Kind::Identifier); |
| if (!Ok()) |
| return Fail(); |
| |
| return std::make_unique<ast::Identifier>(identifier.location()); |
| } |
| |
| std::unique_ptr<ast::CompoundIdentifier> Parser::ParseCompoundIdentifier() { |
| std::vector<std::unique_ptr<ast::Identifier>> components; |
| |
| components.emplace_back(ParseIdentifier()); |
| if (!Ok()) |
| return Fail(); |
| |
| auto parse_component = [&components, this]() { |
| switch (Peek()) { |
| default: |
| return Done; |
| |
| case Token::Kind::Dot: |
| ConsumeToken(Token::Kind::Dot); |
| if (Ok()) |
| components.emplace_back(ParseIdentifier()); |
| return More; |
| } |
| }; |
| |
| while (parse_component() == More) { |
| if (!Ok()) |
| return Fail(); |
| } |
| |
| return std::make_unique<ast::CompoundIdentifier>(std::move(components)); |
| } |
| |
| std::unique_ptr<ast::StringLiteral> Parser::ParseStringLiteral() { |
| auto string_literal = ConsumeToken(Token::Kind::StringLiteral); |
| if (!Ok()) |
| return Fail(); |
| |
| return std::make_unique<ast::StringLiteral>(string_literal.location()); |
| } |
| |
| std::unique_ptr<ast::NumericLiteral> Parser::ParseNumericLiteral() { |
| auto numeric_literal = ConsumeToken(Token::Kind::NumericLiteral); |
| if (!Ok()) |
| return Fail(); |
| |
| return std::make_unique<ast::NumericLiteral>(numeric_literal.location()); |
| } |
| |
| std::unique_ptr<ast::TrueLiteral> Parser::ParseTrueLiteral() { |
| ConsumeToken(Token::Kind::True); |
| if (!Ok()) |
| return Fail(); |
| |
| return std::make_unique<ast::TrueLiteral>(); |
| } |
| |
| std::unique_ptr<ast::FalseLiteral> Parser::ParseFalseLiteral() { |
| ConsumeToken(Token::Kind::False); |
| if (!Ok()) |
| return Fail(); |
| |
| return std::make_unique<ast::FalseLiteral>(); |
| } |
| |
| std::unique_ptr<ast::DefaultLiteral> Parser::ParseDefaultLiteral() { |
| ConsumeToken(Token::Kind::Default); |
| if (!Ok()) |
| return Fail(); |
| |
| return std::make_unique<ast::DefaultLiteral>(); |
| } |
| |
| std::unique_ptr<ast::Literal> Parser::ParseLiteral() { |
| switch (Peek()) { |
| case Token::Kind::StringLiteral: |
| return ParseStringLiteral(); |
| |
| case Token::Kind::NumericLiteral: |
| return ParseNumericLiteral(); |
| |
| case Token::Kind::True: |
| return ParseTrueLiteral(); |
| |
| case Token::Kind::False: |
| return ParseFalseLiteral(); |
| |
| case Token::Kind::Default: |
| return ParseDefaultLiteral(); |
| |
| default: |
| return Fail(); |
| } |
| } |
| |
| std::unique_ptr<ast::Constant> Parser::ParseConstant() { |
| switch (Peek()) { |
| case Token::Kind::Identifier: { |
| auto identifier = ParseCompoundIdentifier(); |
| if (!Ok()) |
| return Fail(); |
| return std::make_unique<ast::IdentifierConstant>(std::move(identifier)); |
| } |
| |
| TOKEN_LITERAL_CASES : { |
| auto literal = ParseLiteral(); |
| if (!Ok()) |
| return Fail(); |
| return std::make_unique<ast::LiteralConstant>(std::move(literal)); |
| } |
| |
| default: |
| return Fail(); |
| } |
| } |
| |
| std::unique_ptr<ast::Using> Parser::ParseUsing() { |
| ConsumeToken(Token::Kind::Using); |
| if (!Ok()) |
| return Fail(); |
| auto using_path = ParseCompoundIdentifier(); |
| if (!Ok()) |
| return Fail(); |
| |
| std::unique_ptr<ast::Identifier> maybe_alias; |
| if (MaybeConsumeToken(Token::Kind::As)) { |
| if (!Ok()) |
| return Fail(); |
| maybe_alias = ParseIdentifier(); |
| if (!Ok()) |
| return Fail(); |
| } |
| |
| return std::make_unique<ast::Using>(std::move(using_path), std::move(maybe_alias)); |
| } |
| |
| std::unique_ptr<ast::ArrayType> Parser::ParseArrayType() { |
| ConsumeToken(Token::Kind::Array); |
| if (!Ok()) |
| return Fail(); |
| ConsumeToken(Token::Kind::LeftAngle); |
| if (!Ok()) |
| return Fail(); |
| auto element_type = ParseType(); |
| if (!Ok()) |
| return Fail(); |
| ConsumeToken(Token::Kind::RightAngle); |
| if (!Ok()) |
| return Fail(); |
| ConsumeToken(Token::Kind::Colon); |
| if (!Ok()) |
| return Fail(); |
| auto element_count = ParseConstant(); |
| if (!Ok()) |
| return Fail(); |
| |
| return std::make_unique<ast::ArrayType>(std::move(element_type), std::move(element_count)); |
| } |
| |
| std::unique_ptr<ast::VectorType> Parser::ParseVectorType() { |
| ConsumeToken(Token::Kind::Vector); |
| if (!Ok()) |
| return Fail(); |
| ConsumeToken(Token::Kind::LeftAngle); |
| if (!Ok()) |
| return Fail(); |
| auto element_type = ParseType(); |
| if (!Ok()) |
| return Fail(); |
| ConsumeToken(Token::Kind::RightAngle); |
| if (!Ok()) |
| return Fail(); |
| |
| std::unique_ptr<ast::Constant> maybe_element_count; |
| if (MaybeConsumeToken(Token::Kind::Colon)) { |
| if (!Ok()) |
| return Fail(); |
| maybe_element_count = ParseConstant(); |
| if (!Ok()) |
| return Fail(); |
| } |
| |
| auto nullability = types::Nullability::Nonnullable; |
| if (MaybeConsumeToken(Token::Kind::Question)) { |
| nullability = types::Nullability::Nullable; |
| } |
| |
| return std::make_unique<ast::VectorType>(std::move(element_type), |
| std::move(maybe_element_count), nullability); |
| } |
| |
| std::unique_ptr<ast::StringType> Parser::ParseStringType() { |
| ConsumeToken(Token::Kind::String); |
| if (!Ok()) |
| return Fail(); |
| |
| std::unique_ptr<ast::Constant> maybe_element_count; |
| if (MaybeConsumeToken(Token::Kind::Colon)) { |
| if (!Ok()) |
| return Fail(); |
| maybe_element_count = ParseConstant(); |
| if (!Ok()) |
| return Fail(); |
| } |
| |
| auto nullability = types::Nullability::Nonnullable; |
| if (MaybeConsumeToken(Token::Kind::Question)) { |
| nullability = types::Nullability::Nullable; |
| } |
| |
| return std::make_unique<ast::StringType>(std::move(maybe_element_count), nullability); |
| } |
| |
| std::unique_ptr<ast::HandleType> Parser::ParseHandleType() { |
| ConsumeToken(Token::Kind::Handle); |
| if (!Ok()) |
| return Fail(); |
| |
| auto subtype = types::HandleSubtype::Handle; |
| if (MaybeConsumeToken(Token::Kind::LeftAngle)) { |
| if (!Ok()) |
| return Fail(); |
| auto identifier = ParseIdentifier(); |
| if (!Ok()) |
| return Fail(); |
| if (!LookupHandleSubtype(identifier.get(), &subtype)) |
| return Fail(); |
| ConsumeToken(Token::Kind::RightAngle); |
| if (!Ok()) |
| return Fail(); |
| } |
| |
| auto nullability = types::Nullability::Nonnullable; |
| if (MaybeConsumeToken(Token::Kind::Question)) { |
| nullability = types::Nullability::Nullable; |
| } |
| |
| return std::make_unique<ast::HandleType>(subtype, nullability); |
| } |
| |
| std::unique_ptr<ast::PrimitiveType> Parser::ParsePrimitiveType() { |
| types::PrimitiveSubtype subtype; |
| |
| switch (Peek()) { |
| case Token::Kind::Bool: |
| subtype = types::PrimitiveSubtype::Bool; |
| break; |
| case Token::Kind::Status: |
| subtype = types::PrimitiveSubtype::Status; |
| break; |
| case Token::Kind::Int8: |
| subtype = types::PrimitiveSubtype::Int8; |
| break; |
| case Token::Kind::Int16: |
| subtype = types::PrimitiveSubtype::Int16; |
| break; |
| case Token::Kind::Int32: |
| subtype = types::PrimitiveSubtype::Int32; |
| break; |
| case Token::Kind::Int64: |
| subtype = types::PrimitiveSubtype::Int64; |
| break; |
| case Token::Kind::Uint8: |
| subtype = types::PrimitiveSubtype::Uint8; |
| break; |
| case Token::Kind::Uint16: |
| subtype = types::PrimitiveSubtype::Uint16; |
| break; |
| case Token::Kind::Uint32: |
| subtype = types::PrimitiveSubtype::Uint32; |
| break; |
| case Token::Kind::Uint64: |
| subtype = types::PrimitiveSubtype::Uint64; |
| break; |
| case Token::Kind::Float32: |
| subtype = types::PrimitiveSubtype::Float32; |
| break; |
| case Token::Kind::Float64: |
| subtype = types::PrimitiveSubtype::Float64; |
| break; |
| default: |
| return Fail(); |
| } |
| |
| ConsumeToken(Peek()); |
| if (!Ok()) |
| return Fail(); |
| return std::make_unique<ast::PrimitiveType>(subtype); |
| } |
| |
| std::unique_ptr<ast::RequestType> Parser::ParseRequestType() { |
| ConsumeToken(Token::Kind::Request); |
| if (!Ok()) |
| return Fail(); |
| ConsumeToken(Token::Kind::LeftAngle); |
| if (!Ok()) |
| return Fail(); |
| auto identifier = ParseCompoundIdentifier(); |
| if (!Ok()) |
| return Fail(); |
| ConsumeToken(Token::Kind::RightAngle); |
| if (!Ok()) |
| return Fail(); |
| |
| auto nullability = types::Nullability::Nonnullable; |
| if (MaybeConsumeToken(Token::Kind::Question)) { |
| nullability = types::Nullability::Nullable; |
| } |
| |
| return std::make_unique<ast::RequestType>(std::move(identifier), nullability); |
| } |
| |
| std::unique_ptr<ast::Type> Parser::ParseType() { |
| switch (Peek()) { |
| case Token::Kind::Identifier: { |
| auto identifier = ParseCompoundIdentifier(); |
| if (!Ok()) |
| return Fail(); |
| auto nullability = types::Nullability::Nonnullable; |
| if (MaybeConsumeToken(Token::Kind::Question)) { |
| if (!Ok()) |
| return Fail(); |
| nullability = types::Nullability::Nullable; |
| } |
| return std::make_unique<ast::IdentifierType>(std::move(identifier), nullability); |
| } |
| |
| case Token::Kind::Array: { |
| auto type = ParseArrayType(); |
| if (!Ok()) |
| return Fail(); |
| return type; |
| } |
| |
| case Token::Kind::Vector: { |
| auto type = ParseVectorType(); |
| if (!Ok()) |
| return Fail(); |
| return type; |
| } |
| |
| case Token::Kind::String: { |
| auto type = ParseStringType(); |
| if (!Ok()) |
| return Fail(); |
| return type; |
| } |
| |
| case Token::Kind::Handle: { |
| auto type = ParseHandleType(); |
| if (!Ok()) |
| return Fail(); |
| return type; |
| } |
| |
| case Token::Kind::Request: { |
| auto type = ParseRequestType(); |
| 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<ast::ConstDeclaration> Parser::ParseConstDeclaration() { |
| ConsumeToken(Token::Kind::Const); |
| if (!Ok()) |
| return Fail(); |
| auto type = ParseType(); |
| if (!Ok()) |
| return Fail(); |
| auto identifier = ParseIdentifier(); |
| if (!Ok()) |
| return Fail(); |
| ConsumeToken(Token::Kind::Equal); |
| if (!Ok()) |
| return Fail(); |
| auto constant = ParseConstant(); |
| if (!Ok()) |
| return Fail(); |
| |
| return std::make_unique<ast::ConstDeclaration>(std::move(type), std::move(identifier), |
| std::move(constant)); |
| } |
| |
| std::unique_ptr<ast::EnumMember> Parser::ParseEnumMember() { |
| auto identifier = ParseIdentifier(); |
| if (!Ok()) |
| return Fail(); |
| |
| ConsumeToken(Token::Kind::Equal); |
| if (!Ok()) |
| return Fail(); |
| |
| auto member_value = ParseConstant(); |
| if (!Ok()) |
| return Fail(); |
| |
| return std::make_unique<ast::EnumMember>(std::move(identifier), std::move(member_value)); |
| } |
| |
| std::unique_ptr<ast::EnumDeclaration> Parser::ParseEnumDeclaration() { |
| std::vector<std::unique_ptr<ast::EnumMember>> members; |
| |
| ConsumeToken(Token::Kind::Enum); |
| if (!Ok()) |
| return Fail(); |
| auto identifier = ParseIdentifier(); |
| if (!Ok()) |
| return Fail(); |
| std::unique_ptr<ast::PrimitiveType> subtype; |
| if (MaybeConsumeToken(Token::Kind::Colon)) { |
| if (!Ok()) |
| return Fail(); |
| subtype = ParsePrimitiveType(); |
| if (!Ok()) |
| return Fail(); |
| } |
| ConsumeToken(Token::Kind::LeftCurly); |
| if (!Ok()) |
| return Fail(); |
| |
| auto parse_member = [&members, this]() { |
| switch (Peek()) { |
| default: |
| ConsumeToken(Token::Kind::RightCurly); |
| return Done; |
| |
| TOKEN_TYPE_CASES: |
| members.emplace_back(ParseEnumMember()); |
| return More; |
| } |
| }; |
| |
| while (parse_member() == More) { |
| if (!Ok()) |
| Fail(); |
| ConsumeToken(Token::Kind::Semicolon); |
| if (!Ok()) |
| return Fail(); |
| } |
| if (!Ok()) |
| Fail(); |
| |
| return std::make_unique<ast::EnumDeclaration>(std::move(identifier), std::move(subtype), |
| std::move(members)); |
| } |
| |
| std::unique_ptr<ast::Parameter> Parser::ParseParameter() { |
| auto type = ParseType(); |
| if (!Ok()) |
| return Fail(); |
| auto identifier = ParseIdentifier(); |
| if (!Ok()) |
| return Fail(); |
| |
| return std::make_unique<ast::Parameter>(std::move(type), std::move(identifier)); |
| } |
| |
| std::unique_ptr<ast::ParameterList> Parser::ParseParameterList() { |
| std::vector<std::unique_ptr<ast::Parameter>> parameter_list; |
| |
| switch (Peek()) { |
| default: |
| break; |
| |
| TOKEN_TYPE_CASES: |
| parameter_list.emplace_back(ParseParameter()); |
| if (!Ok()) |
| return Fail(); |
| while (Peek() == Token::Kind::Comma) { |
| ConsumeToken(Token::Kind::Comma); |
| 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<ast::ParameterList>(std::move(parameter_list)); |
| } |
| |
| std::unique_ptr<ast::InterfaceMemberMethod> Parser::ParseInterfaceMemberMethod() { |
| auto ordinal = ParseNumericLiteral(); |
| if (!Ok()) |
| return Fail(); |
| ConsumeToken(Token::Kind::Colon); |
| if (!Ok()) |
| return Fail(); |
| |
| std::unique_ptr<ast::Identifier> method_name; |
| std::unique_ptr<ast::ParameterList> maybe_request; |
| std::unique_ptr<ast::ParameterList> maybe_response; |
| |
| auto parse_params = [this](std::unique_ptr<ast::ParameterList>* params_out) { |
| ConsumeToken(Token::Kind::LeftParen); |
| if (!Ok()) |
| return false; |
| *params_out = ParseParameterList(); |
| if (!Ok()) |
| return false; |
| ConsumeToken(Token::Kind::RightParen); |
| if (!Ok()) |
| return false; |
| return true; |
| }; |
| |
| if (MaybeConsumeToken(Token::Kind::Arrow)) { |
| 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::Arrow)) { |
| if (!Ok()) |
| return Fail(); |
| if (!parse_params(&maybe_response)) |
| return Fail(); |
| } |
| } |
| |
| assert(method_name); |
| assert(maybe_request || maybe_response); |
| |
| return std::make_unique<ast::InterfaceMemberMethod>(std::move(ordinal), |
| std::move(method_name), |
| std::move(maybe_request), |
| std::move(maybe_response)); |
| } |
| |
| std::unique_ptr<ast::InterfaceDeclaration> Parser::ParseInterfaceDeclaration() { |
| std::vector<std::unique_ptr<ast::CompoundIdentifier>> superinterfaces; |
| std::vector<std::unique_ptr<ast::ConstDeclaration>> const_members; |
| std::vector<std::unique_ptr<ast::EnumDeclaration>> enum_members; |
| std::vector<std::unique_ptr<ast::InterfaceMemberMethod>> method_members; |
| |
| ConsumeToken(Token::Kind::Interface); |
| if (!Ok()) |
| return Fail(); |
| |
| auto identifier = ParseIdentifier(); |
| if (!Ok()) |
| return Fail(); |
| |
| if (MaybeConsumeToken(Token::Kind::Colon)) { |
| for (;;) { |
| superinterfaces.emplace_back(ParseCompoundIdentifier()); |
| if (!Ok()) |
| return Fail(); |
| if (!MaybeConsumeToken(Token::Kind::Comma)) |
| break; |
| } |
| } |
| |
| ConsumeToken(Token::Kind::LeftCurly); |
| if (!Ok()) |
| return Fail(); |
| |
| auto parse_member = [&const_members, &enum_members, &method_members, this]() { |
| switch (Peek()) { |
| default: |
| ConsumeToken(Token::Kind::RightCurly); |
| return Done; |
| |
| case Token::Kind::Const: |
| const_members.emplace_back(ParseConstDeclaration()); |
| return More; |
| |
| case Token::Kind::Enum: |
| enum_members.emplace_back(ParseEnumDeclaration()); |
| return More; |
| |
| case Token::Kind::NumericLiteral: |
| method_members.emplace_back(ParseInterfaceMemberMethod()); |
| return More; |
| } |
| }; |
| |
| while (parse_member() == More) { |
| if (!Ok()) |
| Fail(); |
| ConsumeToken(Token::Kind::Semicolon); |
| if (!Ok()) |
| return Fail(); |
| } |
| if (!Ok()) |
| Fail(); |
| |
| return std::make_unique<ast::InterfaceDeclaration>(std::move(identifier), std::move(superinterfaces), |
| std::move(const_members), std::move(enum_members), |
| std::move(method_members)); |
| } |
| |
| std::unique_ptr<ast::StructMember> Parser::ParseStructMember() { |
| auto type = ParseType(); |
| if (!Ok()) |
| return Fail(); |
| auto identifier = ParseIdentifier(); |
| if (!Ok()) |
| return Fail(); |
| |
| std::unique_ptr<ast::Constant> maybe_default_value; |
| if (MaybeConsumeToken(Token::Kind::Equal)) { |
| if (!Ok()) |
| return Fail(); |
| maybe_default_value = ParseConstant(); |
| if (!Ok()) |
| return Fail(); |
| } |
| |
| return std::make_unique<ast::StructMember>(std::move(type), std::move(identifier), |
| std::move(maybe_default_value)); |
| } |
| |
| std::unique_ptr<ast::StructDeclaration> Parser::ParseStructDeclaration() { |
| std::vector<std::unique_ptr<ast::ConstDeclaration>> const_members; |
| std::vector<std::unique_ptr<ast::EnumDeclaration>> enum_members; |
| std::vector<std::unique_ptr<ast::StructMember>> members; |
| |
| ConsumeToken(Token::Kind::Struct); |
| if (!Ok()) |
| return Fail(); |
| auto identifier = ParseIdentifier(); |
| if (!Ok()) |
| return Fail(); |
| ConsumeToken(Token::Kind::LeftCurly); |
| if (!Ok()) |
| return Fail(); |
| |
| auto parse_member = [&const_members, &enum_members, &members, this]() { |
| switch (Peek()) { |
| default: |
| ConsumeToken(Token::Kind::RightCurly); |
| return Done; |
| |
| case Token::Kind::Const: |
| const_members.emplace_back(ParseConstDeclaration()); |
| return More; |
| |
| case Token::Kind::Enum: |
| enum_members.emplace_back(ParseEnumDeclaration()); |
| return More; |
| |
| TOKEN_TYPE_CASES: |
| members.emplace_back(ParseStructMember()); |
| return More; |
| } |
| }; |
| |
| while (parse_member() == More) { |
| if (!Ok()) |
| Fail(); |
| ConsumeToken(Token::Kind::Semicolon); |
| if (!Ok()) |
| return Fail(); |
| } |
| if (!Ok()) |
| Fail(); |
| |
| return std::make_unique<ast::StructDeclaration>(std::move(identifier), std::move(const_members), |
| std::move(enum_members), std::move(members)); |
| } |
| |
| std::unique_ptr<ast::UnionMember> Parser::ParseUnionMember() { |
| auto type = ParseType(); |
| if (!Ok()) |
| return Fail(); |
| auto identifier = ParseIdentifier(); |
| if (!Ok()) |
| return Fail(); |
| |
| return std::make_unique<ast::UnionMember>(std::move(type), std::move(identifier)); |
| } |
| |
| std::unique_ptr<ast::UnionDeclaration> Parser::ParseUnionDeclaration() { |
| std::vector<std::unique_ptr<ast::ConstDeclaration>> const_members; |
| std::vector<std::unique_ptr<ast::EnumDeclaration>> enum_members; |
| std::vector<std::unique_ptr<ast::UnionMember>> members; |
| |
| ConsumeToken(Token::Kind::Union); |
| if (!Ok()) |
| return Fail(); |
| auto identifier = ParseIdentifier(); |
| if (!Ok()) |
| return Fail(); |
| ConsumeToken(Token::Kind::LeftCurly); |
| if (!Ok()) |
| return Fail(); |
| |
| auto parse_member = [&const_members, &enum_members, &members, this]() { |
| switch (Peek()) { |
| default: |
| ConsumeToken(Token::Kind::RightCurly); |
| return Done; |
| |
| case Token::Kind::Const: |
| const_members.emplace_back(ParseConstDeclaration()); |
| return More; |
| |
| case Token::Kind::Enum: |
| enum_members.emplace_back(ParseEnumDeclaration()); |
| return More; |
| |
| TOKEN_TYPE_CASES: |
| members.emplace_back(ParseUnionMember()); |
| return More; |
| } |
| }; |
| |
| while (parse_member() == More) { |
| if (!Ok()) |
| Fail(); |
| ConsumeToken(Token::Kind::Semicolon); |
| if (!Ok()) |
| return Fail(); |
| } |
| if (!Ok()) |
| Fail(); |
| |
| if (members.empty()) |
| Fail(); |
| |
| return std::make_unique<ast::UnionDeclaration>(std::move(identifier), std::move(const_members), |
| std::move(enum_members), std::move(members)); |
| } |
| |
| std::unique_ptr<ast::File> Parser::ParseFile() { |
| std::vector<std::unique_ptr<ast::Using>> using_list; |
| std::vector<std::unique_ptr<ast::ConstDeclaration>> const_declaration_list; |
| std::vector<std::unique_ptr<ast::EnumDeclaration>> enum_declaration_list; |
| std::vector<std::unique_ptr<ast::InterfaceDeclaration>> interface_declaration_list; |
| std::vector<std::unique_ptr<ast::StructDeclaration>> struct_declaration_list; |
| std::vector<std::unique_ptr<ast::UnionDeclaration>> union_declaration_list; |
| |
| ConsumeToken(Token::Kind::Library); |
| if (!Ok()) |
| return Fail(); |
| auto identifier = ParseCompoundIdentifier(); |
| if (!Ok()) |
| return Fail(); |
| ConsumeToken(Token::Kind::Semicolon); |
| if (!Ok()) |
| return Fail(); |
| |
| auto parse_using = [&using_list, this]() { |
| switch (Peek()) { |
| default: |
| return Done; |
| |
| case Token::Kind::Using: |
| using_list.emplace_back(ParseUsing()); |
| return More; |
| } |
| }; |
| |
| while (parse_using() == More) { |
| if (!Ok()) |
| return Fail(); |
| ConsumeToken(Token::Kind::Semicolon); |
| if (!Ok()) |
| return Fail(); |
| } |
| |
| auto parse_declaration = [&const_declaration_list, &enum_declaration_list, |
| &interface_declaration_list, &struct_declaration_list, |
| &union_declaration_list, this]() { |
| switch (Peek()) { |
| default: |
| return Done; |
| |
| case Token::Kind::Const: |
| const_declaration_list.emplace_back(ParseConstDeclaration()); |
| return More; |
| |
| case Token::Kind::Enum: |
| enum_declaration_list.emplace_back(ParseEnumDeclaration()); |
| return More; |
| |
| case Token::Kind::Interface: |
| interface_declaration_list.emplace_back(ParseInterfaceDeclaration()); |
| return More; |
| |
| case Token::Kind::Struct: |
| struct_declaration_list.emplace_back(ParseStructDeclaration()); |
| return More; |
| |
| case Token::Kind::Union: |
| union_declaration_list.emplace_back(ParseUnionDeclaration()); |
| return More; |
| } |
| }; |
| |
| while (parse_declaration() == More) { |
| if (!Ok()) |
| return Fail(); |
| ConsumeToken(Token::Kind::Semicolon); |
| if (!Ok()) |
| return Fail(); |
| } |
| |
| ConsumeToken(Token::Kind::EndOfFile); |
| if (!Ok()) |
| return Fail(); |
| |
| return std::make_unique<ast::File>( |
| std::move(identifier), 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 |