blob: 7f057c6de5620f27e623b8343338f2eb066199c8 [file] [log] [blame]
// Copyright 2021 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 "tools/fidl/fidlc/src/consume_step.h"
#include <zircon/assert.h>
#include "tools/fidl/fidlc/src/attributes.h"
#include "tools/fidl/fidlc/src/compile_step.h"
#include "tools/fidl/fidlc/src/diagnostics.h"
#include "tools/fidl/fidlc/src/experimental_flags.h"
#include "tools/fidl/fidlc/src/flat_ast.h"
#include "tools/fidl/fidlc/src/raw_ast.h"
namespace fidlc {
ConsumeStep::ConsumeStep(Compiler* compiler, std::unique_ptr<File> file)
: Step(compiler),
file_(std::move(file)),
default_underlying_type_(
all_libraries()->root_library()->declarations.LookupBuiltin(Builtin::Identity::kUint32)),
framework_err_type_(all_libraries()->root_library()->declarations.LookupBuiltin(
Builtin::Identity::kFrameworkErr)) {}
void ConsumeStep::RunImpl() {
// All fidl files in a library should agree on the library name.
if (auto name = file_->library_decl->path->ToString(); library()->name.empty()) {
library()->name = std::move(name);
} else if (name != library()->name) {
reporter()->Fail(ErrFilesDisagreeOnLibraryName, file_->library_decl->path->span());
return;
}
library()->name_spans.emplace_back(file_->library_decl->path->span());
ConsumeAttributeList(std::move(file_->library_decl->attributes), &library()->attributes);
for (auto& using_directive : std::move(file_->using_list)) {
ConsumeUsing(std::move(using_directive));
}
for (auto& alias_declaration : std::move(file_->alias_list)) {
ConsumeAliasDeclaration(std::move(alias_declaration));
}
for (auto& const_declaration : std::move(file_->const_declaration_list)) {
ConsumeConstDeclaration(std::move(const_declaration));
}
for (auto& protocol_declaration : std::move(file_->protocol_declaration_list)) {
ConsumeProtocolDeclaration(std::move(protocol_declaration));
}
for (auto& resource_declaration : std::move(file_->resource_declaration_list)) {
ConsumeResourceDeclaration(std::move(resource_declaration));
}
for (auto& service_declaration : std::move(file_->service_declaration_list)) {
ConsumeServiceDeclaration(std::move(service_declaration));
}
for (auto& type_decl : std::move(file_->type_decls)) {
ConsumeTypeDeclaration(std::move(type_decl));
}
}
Decl* ConsumeStep::RegisterDecl(std::unique_ptr<Decl> decl) {
auto decl_ptr = library()->declarations.Insert(std::move(decl));
const Name& name = decl_ptr->name;
if (name.span()) {
if (library()->dependencies.Contains(name.span()->source_file().filename(),
{name.span()->data()})) {
reporter()->Fail(ErrDeclNameConflictsWithLibraryImport, name.span().value(), name);
} else if (auto canonical_decl_name = Canonicalize(name.decl_name());
library()->dependencies.Contains(name.span()->source_file().filename(),
{canonical_decl_name})) {
reporter()->Fail(ErrDeclNameConflictsWithLibraryImportCanonical, name.span().value(), name,
canonical_decl_name);
}
}
return decl_ptr;
}
void ConsumeStep::ConsumeAttributeList(std::unique_ptr<RawAttributeList> raw_attribute_list,
std::unique_ptr<AttributeList>* out_attribute_list) {
ZX_ASSERT_MSG(out_attribute_list, "must provide out parameter");
// Usually *out_attribute_list is null and we create the AttributeList here.
// For library declarations it's not, since we consume attributes from each
// file into the same library->attributes field.
if (*out_attribute_list == nullptr) {
*out_attribute_list = std::make_unique<AttributeList>();
}
if (!raw_attribute_list) {
return;
}
auto& out_attributes = (*out_attribute_list)->attributes;
for (auto& raw_attribute : raw_attribute_list->attributes)
ConsumeAttribute(std::move(raw_attribute), &out_attributes.emplace_back());
}
void ConsumeStep::ConsumeAttribute(std::unique_ptr<RawAttribute> raw_attribute,
std::unique_ptr<Attribute>* out_attribute) {
bool all_named = true;
std::vector<std::unique_ptr<AttributeArg>> args;
for (auto& raw_arg : raw_attribute->args) {
std::unique_ptr<Constant> constant;
if (!ConsumeConstant(std::move(raw_arg->value), &constant)) {
continue;
}
std::optional<SourceSpan> name;
if (raw_arg->maybe_name) {
name = raw_arg->maybe_name->span();
}
all_named = all_named && name.has_value();
args.emplace_back(std::make_unique<AttributeArg>(name, std::move(constant), raw_arg->span()));
}
ZX_ASSERT_MSG(all_named || args.size() == 1,
"parser should not allow an anonymous arg with other args");
SourceSpan name;
switch (raw_attribute->provenance) {
case RawAttribute::Provenance::kDefault:
name = raw_attribute->maybe_name->span();
break;
case RawAttribute::Provenance::kDocComment:
name = generated_source_file()->AddLine(Attribute::kDocCommentName);
break;
case RawAttribute::Provenance::kModifierAvailability:
name = generated_source_file()->AddLine(Attribute::kModifierAvailabilityName);
break;
}
*out_attribute = std::make_unique<Attribute>(name, std::move(args), raw_attribute->span());
all_libraries()->WarnOnAttributeTypo(out_attribute->get());
}
void ConsumeStep::ConsumeModifierList(std::unique_ptr<RawModifierList> raw_modifier_list,
std::unique_ptr<ModifierList>* out_modifier_list) {
ZX_ASSERT_MSG(out_modifier_list, "must provide out parameter");
*out_modifier_list = std::make_unique<ModifierList>();
if (!raw_modifier_list) {
return;
}
auto& out_modifiers = (*out_modifier_list)->modifiers;
for (auto& raw_modifier : raw_modifier_list->modifiers)
ConsumeModifier(std::move(raw_modifier), &out_modifiers.emplace_back());
}
void ConsumeStep::ConsumeModifier(std::unique_ptr<RawModifier> raw_modifier,
std::unique_ptr<Modifier>* out_modifier) {
std::vector<std::unique_ptr<Attribute>> attributes;
if (auto& attribute = raw_modifier->maybe_available_attribute)
ConsumeAttribute(std::move(attribute), &attributes.emplace_back());
*out_modifier = std::make_unique<Modifier>(std::make_unique<AttributeList>(std::move(attributes)),
raw_modifier->token.span(), raw_modifier->value);
}
bool ConsumeStep::ConsumeConstant(std::unique_ptr<RawConstant> raw_constant,
std::unique_ptr<Constant>* out_constant) {
switch (raw_constant->kind) {
case RawConstant::Kind::kIdentifier: {
auto identifier = static_cast<RawIdentifierConstant*>(raw_constant.get());
*out_constant = std::make_unique<IdentifierConstant>(Reference(*identifier->identifier),
identifier->span());
break;
}
case RawConstant::Kind::kLiteral: {
auto literal = static_cast<RawLiteralConstant*>(raw_constant.get());
std::unique_ptr<LiteralConstant> out;
ConsumeLiteralConstant(literal, &out);
*out_constant = std::unique_ptr<Constant>(out.release());
break;
}
case RawConstant::Kind::kBinaryOperator: {
auto binary_operator_constant = static_cast<RawBinaryOperatorConstant*>(raw_constant.get());
BinaryOperatorConstant::Operator op;
switch (binary_operator_constant->op) {
case RawBinaryOperatorConstant::Operator::kOr:
op = BinaryOperatorConstant::Operator::kOr;
break;
}
std::unique_ptr<Constant> left_operand;
if (!ConsumeConstant(std::move(binary_operator_constant->left_operand), &left_operand)) {
return false;
}
std::unique_ptr<Constant> right_operand;
if (!ConsumeConstant(std::move(binary_operator_constant->right_operand), &right_operand)) {
return false;
}
*out_constant = std::make_unique<BinaryOperatorConstant>(
std::move(left_operand), std::move(right_operand), op, binary_operator_constant->span());
break;
}
}
return true;
}
void ConsumeStep::ConsumeLiteralConstant(RawLiteralConstant* raw_constant,
std::unique_ptr<LiteralConstant>* out_constant) {
*out_constant =
std::make_unique<LiteralConstant>(ConsumeLiteral(std::move(raw_constant->literal)));
}
void ConsumeStep::ConsumeUsing(std::unique_ptr<RawUsing> using_directive) {
if (using_directive->attributes != nullptr) {
reporter()->Fail(ErrAttributesNotAllowedOnLibraryImport, using_directive->span());
return;
}
auto library_name = using_directive->using_path->ToString();
Library* dep_library = all_libraries()->Lookup(library_name);
if (!dep_library) {
reporter()->Fail(ErrUnknownLibrary, using_directive->using_path->span(), library_name);
return;
}
const auto filename = using_directive->span().source_file().filename();
const auto result = library()->dependencies.Register(
using_directive->using_path->span(), filename, dep_library, using_directive->maybe_alias);
switch (result) {
case Dependencies::RegisterResult::kSuccess:
break;
case Dependencies::RegisterResult::kDuplicate:
reporter()->Fail(ErrDuplicateLibraryImport, using_directive->span(), library_name);
return;
case Dependencies::RegisterResult::kCollision:
if (using_directive->maybe_alias) {
reporter()->Fail(ErrConflictingLibraryImportAlias, using_directive->span(), library_name,
using_directive->maybe_alias->span().data());
return;
}
reporter()->Fail(ErrConflictingLibraryImport, using_directive->span(), library_name);
return;
}
}
void ConsumeStep::ConsumeAliasDeclaration(std::unique_ptr<RawAliasDeclaration> alias_declaration) {
ZX_ASSERT(alias_declaration->alias && alias_declaration->type_ctor != nullptr);
std::unique_ptr<AttributeList> attributes;
ConsumeAttributeList(std::move(alias_declaration->attributes), &attributes);
auto alias_name = Name::CreateSourced(library(), alias_declaration->alias->span());
std::unique_ptr<TypeConstructor> type_ctor_;
if (!ConsumeTypeConstructor(std::move(alias_declaration->type_ctor),
NamingContext::Create(alias_name), &type_ctor_))
return;
RegisterDecl(
std::make_unique<Alias>(std::move(attributes), std::move(alias_name), std::move(type_ctor_)));
}
void ConsumeStep::ConsumeConstDeclaration(std::unique_ptr<RawConstDeclaration> const_declaration) {
auto span = const_declaration->identifier->span();
auto name = Name::CreateSourced(library(), span);
std::unique_ptr<AttributeList> attributes;
ConsumeAttributeList(std::move(const_declaration->attributes), &attributes);
std::unique_ptr<TypeConstructor> type_ctor;
if (!ConsumeTypeConstructor(std::move(const_declaration->type_ctor), NamingContext::Create(name),
&type_ctor))
return;
std::unique_ptr<Constant> constant;
if (!ConsumeConstant(std::move(const_declaration->constant), &constant))
return;
RegisterDecl(std::make_unique<Const>(std::move(attributes), std::move(name), std::move(type_ctor),
std::move(constant)));
}
// Create a type constructor pointing to an anonymous layout.
static std::unique_ptr<TypeConstructor> IdentifierTypeForDecl(Decl* decl) {
return std::make_unique<TypeConstructor>(SourceSpan(), Reference(Reference::Target(decl)),
std::make_unique<LayoutParameterList>(),
std::make_unique<TypeConstraints>());
}
bool ConsumeStep::NeedMethodResultUnion(const RawModifierList* raw_modifiers,
Protocol::Method::Kind kind, bool has_error) {
if (kind != Protocol::Method::Kind::kTwoWay)
return false;
if (has_error)
return true;
// This matches CompileStep::CompileModifierList which considers methods flexible by default.
if (!raw_modifiers)
return true;
if (raw_modifiers->modifiers.size() == 1 &&
!raw_modifiers->modifiers[0]->maybe_available_attribute) {
return std::get<Strictness>(raw_modifiers->modifiers[0]->value) == Strictness::kFlexible;
}
reporter()->Fail(ErrCannotChangeMethodStrictness, raw_modifiers->span());
return true;
}
void ConsumeStep::ConsumeMethodResultUnion(
const Name& protocol_name, std::string_view method_name, SourceSpan response_span,
const std::shared_ptr<NamingContext>& response_context,
std::unique_ptr<RawTypeConstructor> raw_success_type_ctor,
std::unique_ptr<RawTypeConstructor> raw_error_type_ctor, Union** out_union) {
// In protocol P, if method M is flexible or uses the error syntax, its
// response is the following compiler-generated union:
//
// type P_M_Result = strict union {
// 1: response @generated_name("P_M_Response") [user specified response type];
// // Only present for methods with error syntax.
// 2: err @generated_name("P_M_Error") [user specified error type];
// // Only present for flexible methods.
// 3: framework_err fidl.FrameworkErr;
// };
//
// This naming scheme is inconsistent with other compiler-generated names
// (e.g. PMRequest) because the error syntax predates anonymous layouts.
//
// Although the success variant is named P_M_Response, in fidlc we always use
// "response" to refer to the outermost type, in this case P_M_Result.
auto prefix = std::string(protocol_name.decl_name()) + "_" + std::string(method_name);
response_context->set_name_override(prefix + "_Result");
using Ordinal = Protocol::Method::ResultUnionOrdinal;
auto ordinal_source = SourceElement(Token(), Token());
std::vector<Union::Member> result_members;
auto success_name = generated_source_file()->AddLine("response");
auto success_context = response_context->EnterMember(success_name);
success_context->set_name_override(prefix + "_Response");
std::unique_ptr<TypeConstructor> success_type_ctor;
if (raw_success_type_ctor) {
ConsumeTypeConstructor(std::move(raw_success_type_ctor), success_context, &success_type_ctor);
} else {
auto empty_struct = std::make_unique<Struct>(
std::make_unique<AttributeList>(), std::make_unique<ModifierList>(),
Name::CreateAnonymous(library(), response_span, success_context,
Name::Provenance::kGeneratedEmptySuccessStruct),
std::vector<Struct::Member>());
success_type_ctor = IdentifierTypeForDecl(RegisterDecl(std::move(empty_struct)));
}
result_members.emplace_back(
ConsumeOrdinal(std::make_unique<RawOrdinal64>(ordinal_source, Ordinal::kSuccess)),
std::move(success_type_ctor), success_name, std::make_unique<AttributeList>());
if (raw_error_type_ctor) {
auto error_name = generated_source_file()->AddLine("err");
auto error_context = response_context->EnterMember(error_name);
error_context->set_name_override(prefix + "_Error");
std::unique_ptr<TypeConstructor> error_type_ctor;
ConsumeTypeConstructor(std::move(raw_error_type_ctor), error_context, &error_type_ctor);
result_members.emplace_back(
ConsumeOrdinal(std::make_unique<RawOrdinal64>(ordinal_source, Ordinal::kDomainError)),
std::move(error_type_ctor), error_name, std::make_unique<AttributeList>());
}
// In the ConsumeStep we don't know if the method is flexible, e.g. it could
// be `strict(removed=5) flexible(added=5)`. So we always add the framework
// error, and in the CompileStep we remove it if the method is strict.
auto framework_err_type_ctor = IdentifierTypeForDecl(framework_err_type_);
ZX_ASSERT_MSG(framework_err_type_ctor != nullptr, "missing framework_err type ctor");
result_members.emplace_back(
ConsumeOrdinal(std::make_unique<RawOrdinal64>(ordinal_source, Ordinal::kFrameworkError)),
std::move(framework_err_type_ctor), generated_source_file()->AddLine("framework_err"),
std::make_unique<AttributeList>());
std::vector<std::unique_ptr<Modifier>> union_modifiers;
union_modifiers.emplace_back(
std::make_unique<Modifier>(std::make_unique<AttributeList>(),
generated_source_file()->AddLine("strict"), Strictness::kStrict));
auto union_decl = std::make_unique<Union>(
std::make_unique<AttributeList>(), std::make_unique<ModifierList>(std::move(union_modifiers)),
Name::CreateAnonymous(library(), response_span, response_context,
Name::Provenance::kGeneratedResultUnion),
std::move(result_members));
*out_union = union_decl.get();
RegisterDecl(std::move(union_decl));
}
void ConsumeStep::ConsumeProtocolDeclaration(
std::unique_ptr<RawProtocolDeclaration> protocol_declaration) {
auto protocol_name = Name::CreateSourced(library(), protocol_declaration->identifier->span());
auto protocol_context = NamingContext::Create(protocol_name.span().value());
std::vector<Protocol::ComposedProtocol> composed_protocols;
for (auto& raw_composed : protocol_declaration->composed_protocols) {
std::unique_ptr<AttributeList> attributes;
ConsumeAttributeList(std::move(raw_composed->attributes), &attributes);
composed_protocols.emplace_back(std::move(attributes), Reference(*raw_composed->protocol_name));
}
std::vector<Protocol::Method> methods;
for (auto& method : protocol_declaration->methods) {
Protocol::Method::Kind kind;
if (method->maybe_request && method->maybe_response) {
kind = Protocol::Method::Kind::kTwoWay;
} else if (method->maybe_request) {
kind = Protocol::Method::Kind::kOneWay;
} else {
ZX_ASSERT(method->maybe_response);
kind = Protocol::Method::Kind::kEvent;
}
SourceSpan method_name = method->identifier->span();
bool has_error = method->maybe_error_ctor != nullptr;
// We have to call this before ConsumeModifierList because method->modifiers gets moved.
bool need_result_union = NeedMethodResultUnion(method->modifiers.get(), kind, has_error);
std::unique_ptr<AttributeList> attributes;
ConsumeAttributeList(std::move(method->attributes), &attributes);
std::unique_ptr<ModifierList> modifiers;
ConsumeModifierList(std::move(method->modifiers), &modifiers);
std::unique_ptr<TypeConstructor> maybe_request;
if (auto& params = method->maybe_request; params && params->type_ctor) {
ConsumeTypeConstructor(std::move(params->type_ctor),
protocol_context->EnterRequest(method_name), &maybe_request);
}
std::unique_ptr<TypeConstructor> maybe_response;
Union* maybe_result_union = nullptr;
if (need_result_union) {
ConsumeMethodResultUnion(protocol_name, method_name.data(), method->maybe_response->span(),
protocol_context->EnterResponse(method_name),
std::move(method->maybe_response->type_ctor),
std::move(method->maybe_error_ctor), &maybe_result_union);
maybe_response = IdentifierTypeForDecl(maybe_result_union);
} else if (auto& params = method->maybe_response; params && params->type_ctor) {
ConsumeTypeConstructor(std::move(params->type_ctor),
kind == Protocol::Method::Kind::kEvent
? protocol_context->EnterEvent(method_name)
: protocol_context->EnterResponse(method_name),
&maybe_response);
}
methods.emplace_back(std::move(attributes), std::move(modifiers), kind, method_name,
std::move(maybe_request), std::move(maybe_response), maybe_result_union,
has_error);
}
std::unique_ptr<AttributeList> attributes;
ConsumeAttributeList(std::move(protocol_declaration->attributes), &attributes);
std::unique_ptr<ModifierList> modifiers;
ConsumeModifierList(std::move(protocol_declaration->modifiers), &modifiers);
RegisterDecl(std::make_unique<Protocol>(std::move(attributes), std::move(modifiers),
std::move(protocol_name), std::move(composed_protocols),
std::move(methods)));
}
void ConsumeStep::ConsumeResourceDeclaration(
std::unique_ptr<RawResourceDeclaration> resource_declaration) {
auto name = Name::CreateSourced(library(), resource_declaration->identifier->span());
auto context = NamingContext::Create(name);
std::vector<Resource::Property> properties;
for (auto& property : resource_declaration->properties) {
std::unique_ptr<AttributeList> attributes;
ConsumeAttributeList(std::move(property->attributes), &attributes);
std::unique_ptr<TypeConstructor> type_ctor;
if (!ConsumeTypeConstructor(std::move(property->type_ctor),
context->EnterMember(property->identifier->span()), &type_ctor))
return;
properties.emplace_back(std::move(type_ctor), property->identifier->span(),
std::move(attributes));
}
std::unique_ptr<AttributeList> attributes;
ConsumeAttributeList(std::move(resource_declaration->attributes), &attributes);
std::unique_ptr<TypeConstructor> type_ctor;
if (resource_declaration->maybe_type_ctor != nullptr) {
if (!ConsumeTypeConstructor(std::move(resource_declaration->maybe_type_ctor), context,
&type_ctor))
return;
} else {
type_ctor = IdentifierTypeForDecl(default_underlying_type_);
}
RegisterDecl(std::make_unique<Resource>(std::move(attributes), std::move(name),
std::move(type_ctor), std::move(properties)));
}
void ConsumeStep::ConsumeServiceDeclaration(std::unique_ptr<RawServiceDeclaration> service_decl) {
auto name = Name::CreateSourced(library(), service_decl->identifier->span());
auto context = NamingContext::Create(name);
std::vector<Service::Member> members;
for (auto& member : service_decl->members) {
std::unique_ptr<AttributeList> attributes;
ConsumeAttributeList(std::move(member->attributes), &attributes);
std::unique_ptr<TypeConstructor> type_ctor;
if (!ConsumeTypeConstructor(std::move(member->type_ctor), context->EnterMember(member->span()),
&type_ctor))
return;
members.emplace_back(std::move(type_ctor), member->identifier->span(), std::move(attributes));
}
std::unique_ptr<AttributeList> attributes;
ConsumeAttributeList(std::move(service_decl->attributes), &attributes);
RegisterDecl(
std::make_unique<Service>(std::move(attributes), std::move(name), std::move(members)));
}
void ConsumeStep::MaybeOverrideName(AttributeList& attributes, NamingContext* context) {
auto attr = attributes.Get("generated_name");
if (attr == nullptr)
return;
CompileStep::CompileAttributeEarly(compiler(), attr);
const auto* arg = attr->GetArg(AttributeArg::kDefaultAnonymousName);
if (arg == nullptr || !arg->value->IsResolved()) {
return;
}
auto str = arg->value->Value().AsString().value();
if (IsValidIdentifierComponent(str)) {
context->set_name_override(std::string(str));
} else {
reporter()->Fail(ErrInvalidGeneratedName, arg->span);
}
}
template <typename T>
bool ConsumeStep::ConsumeValueLayout(std::unique_ptr<RawLayout> layout,
const std::shared_ptr<NamingContext>& context,
std::unique_ptr<RawAttributeList> raw_attribute_list,
Decl** out_decl) {
std::vector<typename T::Member> members;
for (auto& mem : layout->members) {
auto member = static_cast<RawValueLayoutMember*>(mem.get());
auto span = member->identifier->span();
std::unique_ptr<AttributeList> attributes;
ConsumeAttributeList(std::move(member->attributes), &attributes);
std::unique_ptr<Constant> value;
if (!ConsumeConstant(std::move(member->value), &value))
return false;
members.emplace_back(span, std::move(value), std::move(attributes));
}
std::unique_ptr<TypeConstructor> subtype_ctor;
if (layout->subtype_ctor != nullptr) {
if (!ConsumeTypeConstructor(std::move(layout->subtype_ctor), context, &subtype_ctor))
return false;
} else {
subtype_ctor = IdentifierTypeForDecl(default_underlying_type_);
}
std::unique_ptr<AttributeList> attributes;
ConsumeAttributeList(std::move(raw_attribute_list), &attributes);
MaybeOverrideName(*attributes, context.get());
std::unique_ptr<ModifierList> modifiers;
ConsumeModifierList(std::move(layout->modifiers), &modifiers);
Decl* decl = RegisterDecl(std::make_unique<T>(std::move(attributes), std::move(modifiers),
context->ToName(library(), layout->span()),
std::move(subtype_ctor), std::move(members)));
if (out_decl) {
*out_decl = decl;
}
return decl != nullptr;
}
template <typename T>
bool ConsumeStep::ConsumeOrdinaledLayout(std::unique_ptr<RawLayout> layout,
const std::shared_ptr<NamingContext>& context,
std::unique_ptr<RawAttributeList> raw_attribute_list,
Decl** out_decl) {
std::vector<typename T::Member> members;
for (auto& mem : layout->members) {
auto member = static_cast<RawOrdinaledLayoutMember*>(mem.get());
std::unique_ptr<AttributeList> attributes;
ConsumeAttributeList(std::move(member->attributes), &attributes);
std::unique_ptr<TypeConstructor> type_ctor;
if (!ConsumeTypeConstructor(std::move(member->type_ctor),
context->EnterMember(member->identifier->span()), &type_ctor))
return false;
members.emplace_back(ConsumeOrdinal(std::move(member->ordinal)), std::move(type_ctor),
member->identifier->span(), std::move(attributes));
}
std::unique_ptr<AttributeList> attributes;
ConsumeAttributeList(std::move(raw_attribute_list), &attributes);
MaybeOverrideName(*attributes, context.get());
std::unique_ptr<ModifierList> modifiers;
ConsumeModifierList(std::move(layout->modifiers), &modifiers);
Decl* decl = RegisterDecl(std::make_unique<T>(std::move(attributes), std::move(modifiers),
context->ToName(library(), layout->span()),
std::move(members)));
if (out_decl) {
*out_decl = decl;
}
return decl != nullptr;
}
bool ConsumeStep::ConsumeStructLayout(std::unique_ptr<RawLayout> layout,
const std::shared_ptr<NamingContext>& context,
std::unique_ptr<RawAttributeList> raw_attribute_list,
Decl** out_decl) {
std::vector<Struct::Member> members;
for (auto& mem : layout->members) {
auto member = static_cast<RawStructLayoutMember*>(mem.get());
std::unique_ptr<AttributeList> attributes;
ConsumeAttributeList(std::move(member->attributes), &attributes);
std::unique_ptr<TypeConstructor> type_ctor;
if (!ConsumeTypeConstructor(std::move(member->type_ctor),
context->EnterMember(member->identifier->span()), &type_ctor))
return false;
std::unique_ptr<Constant> default_value;
if (member->default_value != nullptr) {
ConsumeConstant(std::move(member->default_value), &default_value);
}
Attribute* allow_struct_defaults = attributes->Get("allow_deprecated_struct_defaults");
if (!allow_struct_defaults && default_value != nullptr) {
reporter()->Fail(ErrDeprecatedStructDefaults, mem->span());
}
members.emplace_back(std::move(type_ctor), member->identifier->span(), std::move(default_value),
std::move(attributes));
}
std::unique_ptr<AttributeList> attributes;
ConsumeAttributeList(std::move(raw_attribute_list), &attributes);
MaybeOverrideName(*attributes, context.get());
std::unique_ptr<ModifierList> modifiers;
ConsumeModifierList(std::move(layout->modifiers), &modifiers);
Decl* decl = RegisterDecl(std::make_unique<Struct>(std::move(attributes), std::move(modifiers),
context->ToName(library(), layout->span()),
std::move(members)));
if (out_decl) {
*out_decl = decl;
}
return decl != nullptr;
}
bool ConsumeStep::ConsumeLayout(std::unique_ptr<RawLayout> layout,
const std::shared_ptr<NamingContext>& context,
std::unique_ptr<RawAttributeList> raw_attribute_list,
Decl** out_decl) {
switch (layout->kind) {
case RawLayout::Kind::kBits: {
return ConsumeValueLayout<Bits>(std::move(layout), context, std::move(raw_attribute_list),
out_decl);
}
case RawLayout::Kind::kEnum: {
return ConsumeValueLayout<Enum>(std::move(layout), context, std::move(raw_attribute_list),
out_decl);
}
case RawLayout::Kind::kStruct: {
return ConsumeStructLayout(std::move(layout), context, std::move(raw_attribute_list),
out_decl);
}
case RawLayout::Kind::kTable: {
return ConsumeOrdinaledLayout<Table>(std::move(layout), context,
std::move(raw_attribute_list), out_decl);
}
case RawLayout::Kind::kUnion: {
return ConsumeOrdinaledLayout<Union>(std::move(layout), context,
std::move(raw_attribute_list), out_decl);
}
case RawLayout::Kind::kOverlay: {
return ConsumeOrdinaledLayout<Overlay>(std::move(layout), context,
std::move(raw_attribute_list), out_decl);
}
}
}
bool ConsumeStep::ConsumeTypeConstructor(std::unique_ptr<RawTypeConstructor> raw_type_ctor,
const std::shared_ptr<NamingContext>& context,
std::unique_ptr<TypeConstructor>* out_type_ctor) {
ZX_ASSERT_MSG(out_type_ctor, "must provide out parameter");
std::vector<std::unique_ptr<LayoutParameter>> params;
std::optional<SourceSpan> params_span;
if (raw_type_ctor->parameters) {
params_span = raw_type_ctor->parameters->span();
for (auto& p : raw_type_ctor->parameters->items) {
auto param = std::move(p);
auto span = param->span();
switch (param->kind) {
case RawLayoutParameter::Kind::kLiteral: {
auto literal_param = static_cast<RawLiteralLayoutParameter*>(param.get());
std::unique_ptr<LiteralConstant> constant;
ConsumeLiteralConstant(literal_param->literal.get(), &constant);
std::unique_ptr<LayoutParameter> consumed =
std::make_unique<LiteralLayoutParameter>(std::move(constant), span);
params.push_back(std::move(consumed));
break;
}
case RawLayoutParameter::Kind::kType: {
auto type_param = static_cast<RawTypeLayoutParameter*>(param.get());
std::unique_ptr<TypeConstructor> type_ctor;
if (!ConsumeTypeConstructor(std::move(type_param->type_ctor), context, &type_ctor))
return false;
std::unique_ptr<LayoutParameter> consumed =
std::make_unique<TypeLayoutParameter>(std::move(type_ctor), span);
params.push_back(std::move(consumed));
break;
}
case RawLayoutParameter::Kind::kIdentifier: {
auto id_param = static_cast<RawIdentifierLayoutParameter*>(param.get());
std::unique_ptr<LayoutParameter> consumed =
std::make_unique<IdentifierLayoutParameter>(Reference(*id_param->identifier), span);
params.push_back(std::move(consumed));
break;
}
}
}
}
std::vector<std::unique_ptr<Constant>> constraints;
std::optional<SourceSpan> constraints_span;
if (raw_type_ctor->constraints) {
constraints_span = raw_type_ctor->constraints->span();
for (auto& c : raw_type_ctor->constraints->items) {
std::unique_ptr<Constant> constraint;
if (!ConsumeConstant(std::move(c), &constraint))
return false;
constraints.push_back(std::move(constraint));
}
}
if (raw_type_ctor->layout_ref->kind == RawLayoutReference::Kind::kInline) {
auto inline_ref = static_cast<RawInlineLayoutReference*>(raw_type_ctor->layout_ref.get());
Decl* inline_decl;
if (!ConsumeLayout(std::move(inline_ref->layout), context, std::move(inline_ref->attributes),
&inline_decl))
return false;
*out_type_ctor = std::make_unique<TypeConstructor>(
raw_type_ctor->span(), Reference(Reference::Target(inline_decl)),
std::make_unique<LayoutParameterList>(std::move(params), params_span),
std::make_unique<TypeConstraints>(std::move(constraints), constraints_span));
return true;
}
auto named_ref = static_cast<RawNamedLayoutReference*>(raw_type_ctor->layout_ref.get());
*out_type_ctor = std::make_unique<TypeConstructor>(
raw_type_ctor->span(), Reference(*named_ref->identifier),
std::make_unique<LayoutParameterList>(std::move(params), params_span),
std::make_unique<TypeConstraints>(std::move(constraints), constraints_span));
return true;
}
void ConsumeStep::ConsumeTypeDeclaration(std::unique_ptr<RawTypeDeclaration> type_decl) {
auto name = Name::CreateSourced(library(), type_decl->identifier->span());
auto& layout_ref = type_decl->type_ctor->layout_ref;
if (layout_ref->kind == RawLayoutReference::Kind::kNamed) {
if (experimental_flags().IsEnabled(ExperimentalFlag::kAllowNewTypes)) {
ConsumeNewType(std::move(type_decl));
return;
}
auto named_ref = static_cast<RawNamedLayoutReference*>(layout_ref.get());
reporter()->Fail(ErrNewTypesNotAllowed, type_decl->span(), name, named_ref->span().data());
return;
}
std::unique_ptr<TypeConstructor> type_ctor;
ConsumeTypeConstructor(std::move(type_decl->type_ctor), NamingContext::Create(name), &type_ctor);
// TODO(https://fxbug.dev/42175339): Fail here if type_ctor has constraints.
Decl* decl = type_ctor->layout.raw_synthetic().target.element()->AsDecl();
ZX_ASSERT_MSG(decl->attributes->Empty(), "should have hit ErrAttributeInsideTypeDeclaration");
ConsumeAttributeList(std::move(type_decl->attributes), &decl->attributes);
}
void ConsumeStep::ConsumeNewType(std::unique_ptr<RawTypeDeclaration> type_decl) {
ZX_ASSERT(type_decl->type_ctor->layout_ref->kind == RawLayoutReference::Kind::kNamed);
ZX_ASSERT(experimental_flags().IsEnabled(ExperimentalFlag::kAllowNewTypes));
std::unique_ptr<AttributeList> attributes;
ConsumeAttributeList(std::move(type_decl->attributes), &attributes);
auto new_type_name = Name::CreateSourced(library(), type_decl->identifier->span());
std::unique_ptr<TypeConstructor> new_type_ctor;
if (!ConsumeTypeConstructor(std::move(type_decl->type_ctor), NamingContext::Create(new_type_name),
&new_type_ctor))
return;
RegisterDecl(std::make_unique<NewType>(std::move(attributes), std::move(new_type_name),
std::move(new_type_ctor)));
}
const RawLiteral* ConsumeStep::ConsumeLiteral(std::unique_ptr<RawLiteral> raw_literal) {
auto ptr = raw_literal.get();
library()->raw_literals.push_back(std::move(raw_literal));
return ptr;
}
const RawOrdinal64* ConsumeStep::ConsumeOrdinal(std::unique_ptr<RawOrdinal64> raw_ordinal) {
auto ptr = raw_ordinal.get();
library()->raw_ordinals.push_back(std::move(raw_ordinal));
return ptr;
}
} // namespace fidlc