blob: 64c02f78f33dc3b93bd3125e169fe23a5f726672 [file] [log] [blame]
// Copyright 2018 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/tables_generator.h"
#include <zircon/assert.h>
#include "fidl/coded_ast.h"
#include "fidl/names.h"
namespace fidl {
namespace {
std::string PrimitiveSubtypeToString(fidl::types::PrimitiveSubtype subtype) {
using fidl::types::PrimitiveSubtype;
switch (subtype) {
case PrimitiveSubtype::kBool:
return "Bool";
case PrimitiveSubtype::kInt8:
return "Int8";
case PrimitiveSubtype::kInt16:
return "Int16";
case PrimitiveSubtype::kInt32:
return "Int32";
case PrimitiveSubtype::kInt64:
return "Int64";
case PrimitiveSubtype::kUint8:
return "Uint8";
case PrimitiveSubtype::kUint16:
return "Uint16";
case PrimitiveSubtype::kUint32:
return "Uint32";
case PrimitiveSubtype::kUint64:
return "Uint64";
case PrimitiveSubtype::kFloat32:
return "Float32";
case PrimitiveSubtype::kFloat64:
return "Float64";
}
}
// When generating coding tables for containers employing envelopes (xunions & tables),
// we need to reference coding tables for primitives, in addition to types that need coding.
// This function handles naming coding tables for both cases.
std::string CodedNameForEnvelope(const fidl::coded::Type* type) {
switch (type->kind) {
case coded::Type::Kind::kPrimitive: {
using fidl::types::PrimitiveSubtype;
// To save space, all primitive types of the same underlying subtype
// share the same table.
std::string suffix =
PrimitiveSubtypeToString(static_cast<const coded::PrimitiveType*>(type)->subtype);
return "fidl_internal_k" + suffix;
}
default:
return type->coded_name;
}
}
template <typename Type>
std::string TableTypeName([[maybe_unused]] const Type& type) {
using T = std::decay_t<Type>;
if constexpr (std::is_same_v<T, fidl::coded::PrimitiveType>)
return "FidlCodedPrimitive";
if constexpr (std::is_same_v<T, fidl::coded::BitsType>)
return "FidlCodedBits";
if constexpr (std::is_same_v<T, fidl::coded::EnumType>)
return "FidlCodedEnum";
if constexpr (std::is_same_v<T, fidl::coded::HandleType>)
return "FidlCodedHandle";
if constexpr (std::is_same_v<T, fidl::coded::RequestHandleType>)
return "FidlCodedHandle";
if constexpr (std::is_same_v<T, fidl::coded::ProtocolHandleType>)
return "FidlCodedHandle";
if constexpr (std::is_same_v<T, fidl::coded::ArrayType>)
return "FidlCodedArray";
if constexpr (std::is_same_v<T, fidl::coded::VectorType>)
return "FidlCodedVector";
if constexpr (std::is_same_v<T, fidl::coded::StructType>)
return "FidlCodedStruct";
if constexpr (std::is_same_v<T, fidl::coded::StructPointerType>)
return "FidlCodedStructPointer";
if constexpr (std::is_same_v<T, fidl::coded::TableType>)
return "FidlCodedTable";
if constexpr (std::is_same_v<T, fidl::coded::XUnionType>)
return "FidlCodedXUnion";
}
constexpr auto kIndent = " ";
void Emit(std::ostream* file, std::string_view data) { *file << data; }
void EmitNewlineAndIndent(std::ostream* file, size_t indent_level) {
*file << "\n";
while (indent_level--)
*file << kIndent;
}
void EmitArrayBegin(std::ostream* file) { *file << "{"; }
void EmitArraySeparator(std::ostream* file, size_t indent_level) {
*file << ",";
EmitNewlineAndIndent(file, indent_level);
}
void EmitArrayEnd(std::ostream* file) { *file << "}"; }
void Emit(std::ostream* file, uint16_t value) { *file << value << "u"; }
void Emit(std::ostream* file, uint32_t value) { *file << value << "u"; }
void Emit(std::ostream* file, uint64_t value) { *file << value << "ul"; }
void Emit(std::ostream* file, types::Nullability nullability) {
switch (nullability) {
case types::Nullability::kNullable:
Emit(file, "kFidlNullability_Nullable");
break;
case types::Nullability::kNonnullable:
Emit(file, "kFidlNullability_Nonnullable");
break;
}
}
void Emit(std::ostream* file, types::Strictness strictness) {
switch (strictness) {
case types::Strictness::kFlexible:
Emit(file, "kFidlStrictness_Flexible");
break;
case types::Strictness::kStrict:
Emit(file, "kFidlStrictness_Strict");
break;
}
}
void Emit(std::ostream* file, types::Resourceness resourceness) {
switch (resourceness) {
case types::Resourceness::kResource:
Emit(file, "kFidlIsResource_Resource");
break;
case types::Resourceness::kValue:
Emit(file, "kFidlIsResource_NotResource");
break;
}
}
void Emit(std::ostream* file, coded::MemcpyCompatibility element_memcpy_compatibility) {
switch (element_memcpy_compatibility) {
case coded::MemcpyCompatibility::kCannotMemcpy:
Emit(file, "kFidlMemcpyCompatibility_CannotMemcpy");
break;
case coded::MemcpyCompatibility::kCanMemcpy:
Emit(file, "kFidlMemcpyCompatibility_CanMemcpy");
break;
}
}
} // namespace
template <typename Collection>
void TablesGenerator::GenerateArray(const Collection& collection) {
EmitArrayBegin(&tables_file_);
if (!collection.empty())
EmitNewlineAndIndent(&tables_file_, ++indent_level_);
for (size_t i = 0; i < collection.size(); ++i) {
if (i)
EmitArraySeparator(&tables_file_, indent_level_);
Generate(collection[i]);
}
if (!collection.empty())
EmitNewlineAndIndent(&tables_file_, --indent_level_);
EmitArrayEnd(&tables_file_);
}
void TablesGenerator::Generate(const coded::EnumType& enum_type) {
std::string validator_func_ref;
if (enum_type.strictness == types::Strictness::kStrict) {
std::string validator_func =
std::string("EnumValidatorFor_") + std::string(enum_type.coded_name);
validator_func_ref = "&" + validator_func;
Emit(&tables_file_, "static bool ");
Emit(&tables_file_, validator_func);
Emit(&tables_file_, "(uint64_t v) {\n switch (v) {\n");
for (const auto& member : enum_type.members) {
Emit(&tables_file_, " case ");
Emit(&tables_file_, member);
Emit(&tables_file_, ":\n");
}
Emit(&tables_file_, " return true;\n");
Emit(&tables_file_, " default:\n return false;\n");
Emit(&tables_file_, " }\n}\n\n");
} else {
validator_func_ref = "NULL";
}
Emit(&tables_file_, "const struct FidlCodedEnum ");
Emit(&tables_file_, NameTable(enum_type.coded_name));
Emit(&tables_file_, " = {.tag=kFidlTypeEnum, .underlying_type=kFidlCodedPrimitiveSubtype_");
Emit(&tables_file_, PrimitiveSubtypeToString(enum_type.subtype));
Emit(&tables_file_, ", .strictness=");
Emit(&tables_file_, enum_type.strictness);
Emit(&tables_file_, ", .validate=" + validator_func_ref + ", .name=\"");
Emit(&tables_file_, enum_type.qname);
Emit(&tables_file_, "\"};\n\n");
}
void TablesGenerator::Generate(const coded::BitsType& bits_type) {
Emit(&tables_file_, "const struct FidlCodedBits ");
Emit(&tables_file_, NameTable(bits_type.coded_name));
Emit(&tables_file_, " = {.tag=kFidlTypeBits, .underlying_type=kFidlCodedPrimitiveSubtype_");
Emit(&tables_file_, PrimitiveSubtypeToString(bits_type.subtype));
Emit(&tables_file_, ", .strictness=");
Emit(&tables_file_, bits_type.strictness);
Emit(&tables_file_, ", .mask=");
Emit(&tables_file_, bits_type.mask);
Emit(&tables_file_, ", .name=\"");
Emit(&tables_file_, bits_type.qname);
Emit(&tables_file_, "\"};\n\n");
}
// TODO(fxbug.dev/56727) Consider filtering out structs that are not used because they are
// only referenced by channel transports.
void TablesGenerator::Generate(const coded::StructType& struct_type) {
std::string fields_array_name = NameFields(struct_type.coded_name);
if (!struct_type.elements.empty()) {
Emit(&tables_file_, "static const struct FidlStructElement ");
Emit(&tables_file_, fields_array_name);
Emit(&tables_file_, "[] = ");
GenerateArray(struct_type.elements);
Emit(&tables_file_, ";\n");
}
Emit(&tables_file_, "const struct FidlCodedStruct ");
Emit(&tables_file_, NameTable(struct_type.coded_name));
Emit(&tables_file_, " = {.tag=kFidlTypeStruct, .contains_envelope=");
Emit(&tables_file_, struct_type.contains_envelope
? "kFidlContainsEnvelope_ContainsEnvelope"
: "kFidlContainsEnvelope_DoesNotContainEnvelope");
Emit(&tables_file_, ", .is_empty=");
Emit(&tables_file_, struct_type.is_empty ? "kFidlEmpty_IsEmpty" : "kFidlEmpty_IsNotEmpty");
Emit(&tables_file_, ", .elements=");
Emit(&tables_file_, struct_type.elements.empty() ? "NULL" : fields_array_name);
Emit(&tables_file_, ", .element_count=");
Emit(&tables_file_, static_cast<uint32_t>(struct_type.elements.size()));
Emit(&tables_file_, ", .size_v2=");
Emit(&tables_file_, struct_type.size_v2);
Emit(&tables_file_, ", .name=\"");
Emit(&tables_file_, struct_type.qname);
Emit(&tables_file_, "\"};\n\n");
}
void TablesGenerator::Generate(const coded::TableType& table_type) {
std::string fields_array_name = NameFields(table_type.coded_name);
if (!table_type.fields.empty()) {
Emit(&tables_file_, "static const struct FidlTableField ");
Emit(&tables_file_, NameFields(table_type.coded_name));
Emit(&tables_file_, "[] = ");
GenerateArray(table_type.fields);
Emit(&tables_file_, ";\n");
}
Emit(&tables_file_, "const struct FidlCodedTable ");
Emit(&tables_file_, NameTable(table_type.coded_name));
Emit(&tables_file_, " = {.tag=kFidlTypeTable, .fields=");
Emit(&tables_file_, table_type.fields.empty() ? "NULL" : fields_array_name);
Emit(&tables_file_, ", .field_count=");
Emit(&tables_file_, static_cast<uint32_t>(table_type.fields.size()));
Emit(&tables_file_, ", .is_resource=");
Emit(&tables_file_, table_type.resourceness);
Emit(&tables_file_, ", .name=\"");
Emit(&tables_file_, table_type.qname);
Emit(&tables_file_, "\"};\n\n");
}
void TablesGenerator::Generate(const coded::XUnionType& xunion_type) {
std::string fields_array_name = NameFields(xunion_type.coded_name);
if (!xunion_type.fields.empty()) {
Emit(&tables_file_, "static const struct FidlXUnionField ");
Emit(&tables_file_, NameFields(xunion_type.coded_name));
Emit(&tables_file_, "[] = ");
GenerateArray(xunion_type.fields);
Emit(&tables_file_, ";\n");
}
Emit(&tables_file_, "const struct FidlCodedXUnion ");
Emit(&tables_file_, NameTable(xunion_type.coded_name));
Emit(&tables_file_, " = {.tag=kFidlTypeXUnion, .field_count=");
Emit(&tables_file_, static_cast<uint32_t>(xunion_type.fields.size()));
Emit(&tables_file_, ", .fields=");
Emit(&tables_file_, xunion_type.fields.empty() ? "NULL" : fields_array_name);
Emit(&tables_file_, ", .nullable=");
Emit(&tables_file_, xunion_type.nullability);
Emit(&tables_file_, ", .name=\"");
Emit(&tables_file_, xunion_type.qname);
Emit(&tables_file_, "\", .strictness=");
Emit(&tables_file_, xunion_type.strictness);
Emit(&tables_file_, ", .is_resource=");
Emit(&tables_file_, xunion_type.resourceness);
Emit(&tables_file_, "};\n");
}
void TablesGenerator::Generate(const coded::StructPointerType& pointer) {
Emit(&tables_file_, "static const struct FidlCodedStructPointer ");
Emit(&tables_file_, NameTable(pointer.coded_name));
Emit(&tables_file_, " = {.tag=kFidlTypeStructPointer, .struct_type=");
Generate(pointer.element_type, CastToFidlType::kNoCast);
Emit(&tables_file_, "};\n");
}
void TablesGenerator::Generate(const coded::HandleType& handle_type) {
Emit(&tables_file_, "static const struct FidlCodedHandle ");
Emit(&tables_file_, NameTable(handle_type.coded_name));
Emit(&tables_file_, " = {.tag=kFidlTypeHandle, .handle_subtype=");
Emit(&tables_file_, NameHandleZXObjType(handle_type.subtype));
Emit(&tables_file_, ", .handle_rights=");
Emit(&tables_file_, handle_type.rights);
Emit(&tables_file_, ", .nullable=");
Emit(&tables_file_, handle_type.nullability);
Emit(&tables_file_, "};\n\n");
}
void TablesGenerator::Generate(const coded::RequestHandleType& request_type) {
Emit(&tables_file_, "static const struct FidlCodedHandle ");
Emit(&tables_file_, NameTable(request_type.coded_name));
Emit(&tables_file_,
" = {.tag=kFidlTypeHandle, .handle_subtype=ZX_OBJ_TYPE_CHANNEL, "
".handle_rights=ZX_DEFAULT_CHANNEL_RIGHTS, "
".nullable=");
Emit(&tables_file_, request_type.nullability);
Emit(&tables_file_, "};\n\n");
}
void TablesGenerator::Generate(const coded::ProtocolHandleType& protocol_type) {
Emit(&tables_file_, "static const struct FidlCodedHandle ");
Emit(&tables_file_, NameTable(protocol_type.coded_name));
Emit(&tables_file_,
" = {.tag=kFidlTypeHandle, .handle_subtype=ZX_OBJ_TYPE_CHANNEL, "
".handle_rights=ZX_DEFAULT_CHANNEL_RIGHTS, "
".nullable=");
Emit(&tables_file_, protocol_type.nullability);
Emit(&tables_file_, "};\n\n");
}
void TablesGenerator::Generate(const coded::ArrayType& array_type) {
Emit(&tables_file_, "static const struct FidlCodedArray ");
Emit(&tables_file_, NameTable(array_type.coded_name));
// Array defs can be unused when they only appear in structs where the field is optimized out.
Emit(&tables_file_, " __attribute__((unused)) = {.tag=kFidlTypeArray, .element=");
Generate(array_type.element_type);
Emit(&tables_file_, ", .array_size_v2=");
Emit(&tables_file_, array_type.size_v2);
Emit(&tables_file_, ", .element_size_v2=");
Emit(&tables_file_, array_type.element_size_v2);
Emit(&tables_file_, "};\n\n");
}
void TablesGenerator::Generate(const coded::StringType& string_type) {
Emit(&tables_file_, "static const struct FidlCodedString ");
Emit(&tables_file_, NameTable(string_type.coded_name));
Emit(&tables_file_, " = {.tag=kFidlTypeString, .max_size=");
Emit(&tables_file_, string_type.max_size);
Emit(&tables_file_, ", .nullable=");
Emit(&tables_file_, string_type.nullability);
Emit(&tables_file_, "};\n\n");
}
void TablesGenerator::Generate(const coded::VectorType& vector_type) {
Emit(&tables_file_, "static const struct FidlCodedVector ");
Emit(&tables_file_, NameTable(vector_type.coded_name));
Emit(&tables_file_, " = {.tag=kFidlTypeVector, .element=");
Generate(vector_type.element_type);
Emit(&tables_file_, ", .max_count=");
Emit(&tables_file_, vector_type.max_count);
Emit(&tables_file_, ", .element_size_v2=");
Emit(&tables_file_, vector_type.element_size_v2);
Emit(&tables_file_, ", .nullable=");
Emit(&tables_file_, vector_type.nullability);
Emit(&tables_file_, ", .element_memcpy_compatibility=");
Emit(&tables_file_, vector_type.element_memcpy_compatibility);
Emit(&tables_file_, "};\n\n");
}
void TablesGenerator::Generate(const coded::Type* type, CastToFidlType cast_to_fidl_type) {
if (type && type->is_coding_needed) {
if (cast_to_fidl_type == CastToFidlType::kCast) {
Emit(&tables_file_, "(fidl_type_t*)(&");
} else {
Emit(&tables_file_, "&");
}
Emit(&tables_file_, NameTable(CodedNameForEnvelope(type)));
if (cast_to_fidl_type == CastToFidlType::kCast) {
Emit(&tables_file_, ")");
}
} else {
Emit(&tables_file_, "NULL");
}
}
void TablesGenerator::Generate(const coded::StructField& field) {
Emit(&tables_file_, "/*FidlStructField*/{.header=");
Emit(&tables_file_, "/*FidlStructElementHeader*/{.element_type=");
Emit(&tables_file_, "kFidlStructElementType_Field");
Emit(&tables_file_, ", ");
Emit(&tables_file_, ".is_resource=");
Emit(&tables_file_, field.resourceness);
Emit(&tables_file_, "},");
Emit(&tables_file_, ".offset_v2=");
Emit(&tables_file_, field.offset_v2);
Emit(&tables_file_, ", ");
Emit(&tables_file_, ".field_type=");
Generate(field.type);
Emit(&tables_file_, "}");
}
void TablesGenerator::Generate(const coded::StructPadding& padding) {
Emit(&tables_file_, "/*FidlStructPadding*/{.offset_v2=");
Emit(&tables_file_, padding.offset_v2);
Emit(&tables_file_, ", .header=/*FidlStructElementHeader*/{");
if (std::holds_alternative<uint64_t>(padding.mask)) {
Emit(&tables_file_, ".element_type=");
Emit(&tables_file_, "kFidlStructElementType_Padding64");
Emit(&tables_file_, ",.is_resource=kFidlIsResource_NotResource},");
Emit(&tables_file_, ".mask_64=");
Emit(&tables_file_, std::get<uint64_t>(padding.mask));
} else if (std::holds_alternative<uint32_t>(padding.mask)) {
Emit(&tables_file_, ".element_type=");
Emit(&tables_file_, "kFidlStructElementType_Padding32");
Emit(&tables_file_, ",.is_resource=kFidlIsResource_NotResource},");
Emit(&tables_file_, ".mask_32=");
Emit(&tables_file_, std::get<uint32_t>(padding.mask));
} else if (std::holds_alternative<uint16_t>(padding.mask)) {
Emit(&tables_file_, ".element_type=");
Emit(&tables_file_, "kFidlStructElementType_Padding16");
Emit(&tables_file_, ",.is_resource=kFidlIsResource_NotResource},");
Emit(&tables_file_, ".mask_16=");
Emit(&tables_file_, std::get<uint16_t>(padding.mask));
} else {
ZX_PANIC("invalid mask variant");
}
Emit(&tables_file_, "}");
}
void TablesGenerator::Generate(const coded::StructElement& element) {
if (std::holds_alternative<const coded::StructField>(element)) {
Emit(&tables_file_, "/*FidlStructPadding*/{.field=");
Generate(std::get<const coded::StructField>(element));
Emit(&tables_file_, "}");
} else if (std::holds_alternative<const coded::StructPadding>(element)) {
Emit(&tables_file_, "/*FidlStructPadding*/{.padding=");
Generate(std::get<const coded::StructPadding>(element));
Emit(&tables_file_, "}");
} else {
ZX_PANIC("invalid StructElement variant");
}
}
void TablesGenerator::Generate(const coded::TableField& field) {
Emit(&tables_file_, "/*FidlTableField*/{.type=");
Generate(field.type);
Emit(&tables_file_, ", .ordinal=");
Emit(&tables_file_, field.ordinal);
Emit(&tables_file_, "}");
}
void TablesGenerator::Generate(const coded::XUnionField& field) {
Emit(&tables_file_, "/*FidlXUnionField*/{.type=");
Generate(field.type);
Emit(&tables_file_, "}");
}
template <class T>
std::string ForwardDecls(const T& t) {
// Since we always generate nullable xunions they may be unused
return "__LOCAL extern const struct " + TableTypeName(t) + " " + NameTable(t.coded_name) + ";\n";
}
void TablesGenerator::GenerateForward(const coded::EnumType& enum_type) {
Emit(&tables_file_, ForwardDecls(enum_type));
}
void TablesGenerator::GenerateForward(const coded::BitsType& bits_type) {
Emit(&tables_file_, ForwardDecls(bits_type));
}
void TablesGenerator::GenerateForward(const coded::StructType& struct_type) {
Emit(&tables_file_, ForwardDecls(struct_type));
}
void TablesGenerator::GenerateForward(const coded::TableType& table_type) {
Emit(&tables_file_, ForwardDecls(table_type));
}
void TablesGenerator::GenerateForward(const coded::XUnionType& xunion_type) {
Emit(&tables_file_, ForwardDecls(xunion_type));
}
void TablesGenerator::Produce(CodedTypesGenerator* coded_types_generator) {
// Generate forward declarations of coding tables for named declarations.
for (const auto& decl : compilation_->all_libraries_declaration_order) {
auto coded_type = coded_types_generator->CodedTypeFor(decl->name);
if (!coded_type)
continue;
switch (coded_type->kind) {
case coded::Type::Kind::kEnum:
GenerateForward(*static_cast<const coded::EnumType*>(coded_type));
break;
case coded::Type::Kind::kBits:
GenerateForward(*static_cast<const coded::BitsType*>(coded_type));
break;
case coded::Type::Kind::kStruct:
GenerateForward(*static_cast<const coded::StructType*>(coded_type));
break;
case coded::Type::Kind::kTable:
GenerateForward(*static_cast<const coded::TableType*>(coded_type));
break;
case coded::Type::Kind::kXUnion: {
// Generate forward declarations for both the non-nullable and nullable variants
const auto& xunion_type = *static_cast<const coded::XUnionType*>(coded_type);
GenerateForward(xunion_type);
if (xunion_type.maybe_reference_type)
GenerateForward(*xunion_type.maybe_reference_type);
break;
}
case coded::Type::Kind::kProtocol: {
const auto* protocol_coded_type = static_cast<const coded::ProtocolType*>(coded_type);
for (const auto* message : protocol_coded_type->messages_after_compile) {
switch (message->kind) {
case coded::Type::Kind::kStruct: {
GenerateForward(*static_cast<const coded::StructType*>(message));
break;
}
case coded::Type::Kind::kTable: {
GenerateForward(*static_cast<const coded::TableType*>(message));
break;
}
case coded::Type::Kind::kXUnion: {
GenerateForward(*static_cast<const coded::XUnionType*>(message));
break;
}
default: {
ZX_PANIC("only structs, tables, and unions may be used as message payloads");
}
}
}
break;
}
default:
break;
}
}
Emit(&tables_file_, "\n");
// Generate pointer coding tables necessary for nullable types.
for (const auto& decl : compilation_->all_libraries_declaration_order) {
auto coded_type = coded_types_generator->CodedTypeFor(decl->name);
if (!coded_type)
continue;
switch (coded_type->kind) {
case coded::Type::Kind::kStruct: {
const auto& struct_type = *static_cast<const coded::StructType*>(coded_type);
if (auto pointer_type = struct_type.maybe_reference_type; pointer_type) {
Generate(*pointer_type);
}
break;
}
case coded::Type::Kind::kXUnion: {
// Nullable xunions have the same wire representation as non-nullable ones,
// hence have the same fields and dependencies in their coding tables.
// As such, we will generate them in the next phase, to maintain the correct
// declaration order.
break;
}
default:
break;
}
}
Emit(&tables_file_, "\n");
// Generate coding table definitions for unnamed declarations.
// These are composed in an ad-hoc way in FIDL source, hence we generate "static" coding tables
// local to the translation unit.
for (const auto& coded_type : coded_types_generator->coded_types()) {
if (!coded_type->is_coding_needed)
continue;
switch (coded_type->kind) {
case coded::Type::Kind::kEnum:
case coded::Type::Kind::kBits:
case coded::Type::Kind::kStruct:
case coded::Type::Kind::kTable:
case coded::Type::Kind::kStructPointer:
case coded::Type::Kind::kXUnion:
// These are generated in the next phase.
break;
case coded::Type::Kind::kProtocol:
// Nothing to generate for protocols. We've already moved the
// messages from the protocol into coded_types_ directly.
break;
case coded::Type::Kind::kHandle:
Generate(*static_cast<const coded::HandleType*>(coded_type.get()));
break;
case coded::Type::Kind::kProtocolHandle:
Generate(*static_cast<const coded::ProtocolHandleType*>(coded_type.get()));
break;
case coded::Type::Kind::kRequestHandle:
Generate(*static_cast<const coded::RequestHandleType*>(coded_type.get()));
break;
case coded::Type::Kind::kArray:
Generate(*static_cast<const coded::ArrayType*>(coded_type.get()));
break;
case coded::Type::Kind::kString:
Generate(*static_cast<const coded::StringType*>(coded_type.get()));
break;
case coded::Type::Kind::kVector:
Generate(*static_cast<const coded::VectorType*>(coded_type.get()));
break;
case coded::Type::Kind::kPrimitive:
// Nothing to generate for primitives. We intern all primitive
// coding tables, and therefore directly reference them.
break;
}
}
Emit(&tables_file_, "\n");
// Generate coding table definitions for named declarations.
for (const auto& decl : compilation_->declaration_order) {
const coded::Type* coded_type = coded_types_generator->CodedTypeFor(decl->name);
if (!coded_type)
continue;
switch (coded_type->kind) {
case coded::Type::Kind::kEnum:
Generate(*static_cast<const coded::EnumType*>(coded_type));
break;
case coded::Type::Kind::kBits:
Generate(*static_cast<const coded::BitsType*>(coded_type));
break;
case coded::Type::Kind::kStruct:
Generate(*static_cast<const coded::StructType*>(coded_type));
break;
case coded::Type::Kind::kTable:
Generate(*static_cast<const coded::TableType*>(coded_type));
break;
case coded::Type::Kind::kXUnion: {
const auto& xunion_type = *static_cast<const coded::XUnionType*>(coded_type);
Generate(xunion_type);
if (xunion_type.maybe_reference_type)
Generate(*xunion_type.maybe_reference_type);
break;
}
case coded::Type::Kind::kProtocol: {
const auto* protocol_coded_type = static_cast<const coded::ProtocolType*>(coded_type);
for (const auto* message : protocol_coded_type->messages_after_compile) {
switch (message->kind) {
case coded::Type::Kind::kStruct: {
Generate(*static_cast<const coded::StructType*>(message));
break;
}
case coded::Type::Kind::kTable: {
Generate(*static_cast<const coded::TableType*>(message));
break;
}
case coded::Type::Kind::kXUnion: {
Generate(*static_cast<const coded::XUnionType*>(message));
break;
}
default: {
ZX_PANIC("only structs, tables, and unions may be used as message payloads");
}
}
}
break;
}
default:
break;
}
}
}
std::ostringstream TablesGenerator::Produce() {
CodedTypesGenerator ctg_v1(compilation_);
ctg_v1.CompileCodedTypes();
Produce(&ctg_v1);
std::ostringstream result;
Emit(&result, "// WARNING: This file is machine generated by fidlc.\n\n");
Emit(&result, "#include <lib/fidl/internal.h>\n\n");
result << std::move(forward_decls_).str();
result << "\n";
result << std::move(tables_file_).str();
return result;
}
} // namespace fidl