blob: 9bed931194f0913d438ec5917ed8fe378c454dd3 [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 "fidl/names.h"
namespace fidl {
namespace {
constexpr auto kIndent = " ";
std::ostream& operator<<(std::ostream& stream, StringView view) {
stream.rdbuf()->sputn(view.data(), view.size());
return stream;
}
void Emit(std::ostream* file, StringView 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, uint32_t value) {
*file << value;
}
void Emit(std::ostream* file, types::HandleSubtype handle_subtype) {
Emit(file, NameHandleZXObjType(handle_subtype));
}
void Emit(std::ostream* file, types::Nullability nullability) {
switch (nullability) {
case types::Nullability::kNullable:
Emit(file, "::fidl::kNullable");
break;
case types::Nullability::kNonnullable:
Emit(file, "::fidl::kNonnullable");
break;
}
}
} // namespace
void TablesGenerator::GenerateInclude(StringView filename) {
Emit(&tables_file_, "#include ");
Emit(&tables_file_, filename);
Emit(&tables_file_, "\n");
}
void TablesGenerator::GenerateFilePreamble() {
Emit(&tables_file_, "// WARNING: This file is machine generated by fidlc.\n\n");
GenerateInclude("<lib/fidl/internal.h>");
Emit(&tables_file_, "\nextern \"C\" {\n");
Emit(&tables_file_, "\n");
}
void TablesGenerator::GenerateFilePostamble() {
Emit(&tables_file_, "} // extern \"C\"\n");
}
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::StructType& struct_type) {
Emit(&tables_file_, "static const ::fidl::FidlStructField ");
Emit(&tables_file_, NameFields(struct_type.coded_name));
Emit(&tables_file_, "[] = ");
GenerateArray(struct_type.fields);
Emit(&tables_file_, ";\n");
Emit(&tables_file_, "const fidl_type_t ");
Emit(&tables_file_, NameTable(struct_type.coded_name));
Emit(&tables_file_, " = fidl_type_t(::fidl::FidlCodedStruct(");
Emit(&tables_file_, NameFields(struct_type.coded_name));
Emit(&tables_file_, ", ");
Emit(&tables_file_, static_cast<uint32_t>(struct_type.fields.size()));
Emit(&tables_file_, ", ");
Emit(&tables_file_, struct_type.size);
Emit(&tables_file_, ", \"");
Emit(&tables_file_, struct_type.qname);
Emit(&tables_file_, "\"));\n\n");
}
void TablesGenerator::Generate(const coded::TableType& table_type) {
Emit(&tables_file_, "static const ::fidl::FidlTableField ");
Emit(&tables_file_, NameFields(table_type.coded_name));
Emit(&tables_file_, "[] = ");
GenerateArray(table_type.fields);
Emit(&tables_file_, ";\n");
Emit(&tables_file_, "const fidl_type_t ");
Emit(&tables_file_, NameTable(table_type.coded_name));
Emit(&tables_file_, " = fidl_type_t(::fidl::FidlCodedTable(");
Emit(&tables_file_, NameFields(table_type.coded_name));
Emit(&tables_file_, ", ");
Emit(&tables_file_, static_cast<uint32_t>(table_type.fields.size()));
Emit(&tables_file_, ", \"");
Emit(&tables_file_, table_type.qname);
Emit(&tables_file_, "\"));\n\n");
}
void TablesGenerator::Generate(const coded::UnionType& union_type) {
Emit(&tables_file_, "static const fidl_type_t* ");
Emit(&tables_file_, NameMembers(union_type.coded_name));
Emit(&tables_file_, "[] = ");
GenerateArray(union_type.types);
Emit(&tables_file_, ";\n");
Emit(&tables_file_, "const fidl_type_t ");
Emit(&tables_file_, NameTable(union_type.coded_name));
Emit(&tables_file_, " = fidl_type_t(::fidl::FidlCodedUnion(");
Emit(&tables_file_, NameMembers(union_type.coded_name));
Emit(&tables_file_, ", ");
Emit(&tables_file_, static_cast<uint32_t>(union_type.types.size()));
Emit(&tables_file_, ", ");
Emit(&tables_file_, union_type.data_offset);
Emit(&tables_file_, ", ");
Emit(&tables_file_, union_type.size);
Emit(&tables_file_, ", \"");
Emit(&tables_file_, union_type.qname);
Emit(&tables_file_, "\"));\n\n");
}
void TablesGenerator::Generate(const coded::XUnionType& xunion_type) {
Emit(&tables_file_, "static const ::fidl::FidlXUnionField ");
Emit(&tables_file_, NameFields(xunion_type.coded_name));
Emit(&tables_file_, "[] = ");
GenerateArray(xunion_type.fields);
Emit(&tables_file_, ";\n");
Emit(&tables_file_, "const fidl_type_t ");
Emit(&tables_file_, NameTable(xunion_type.coded_name));
Emit(&tables_file_, " = fidl_type_t(::fidl::FidlCodedXUnion(");
Emit(&tables_file_, static_cast<uint32_t>(xunion_type.fields.size()));
Emit(&tables_file_, ", ");
Emit(&tables_file_, NameFields(xunion_type.coded_name));
Emit(&tables_file_, ", \"");
Emit(&tables_file_, xunion_type.qname);
Emit(&tables_file_, "\"));\n\n");
}
void TablesGenerator::Generate(const coded::MessageType& message_type) {
Emit(&tables_file_, "extern const fidl_type_t ");
Emit(&tables_file_, NameTable(message_type.coded_name));
Emit(&tables_file_, ";\n");
Emit(&tables_file_, "static const ::fidl::FidlStructField ");
Emit(&tables_file_, NameFields(message_type.coded_name));
Emit(&tables_file_, "[] = ");
GenerateArray(message_type.fields);
Emit(&tables_file_, ";\n");
Emit(&tables_file_, "const fidl_type_t ");
Emit(&tables_file_, NameTable(message_type.coded_name));
Emit(&tables_file_, " = fidl_type_t(::fidl::FidlCodedStruct(");
Emit(&tables_file_, NameFields(message_type.coded_name));
Emit(&tables_file_, ", ");
Emit(&tables_file_, static_cast<uint32_t>(message_type.fields.size()));
Emit(&tables_file_, ", ");
Emit(&tables_file_, message_type.size);
Emit(&tables_file_, ", \"");
Emit(&tables_file_, message_type.qname);
Emit(&tables_file_, "\"));\n\n");
}
void TablesGenerator::Generate(const coded::HandleType& handle_type) {
Emit(&tables_file_, "static const fidl_type_t ");
Emit(&tables_file_, NameTable(handle_type.coded_name));
Emit(&tables_file_, " = fidl_type_t(::fidl::FidlCodedHandle(");
Emit(&tables_file_, handle_type.subtype);
Emit(&tables_file_, ", ");
Emit(&tables_file_, handle_type.nullability);
Emit(&tables_file_, "));\n\n");
}
void TablesGenerator::Generate(const coded::RequestHandleType& request_type) {
Emit(&tables_file_, "static const fidl_type_t ");
Emit(&tables_file_, NameTable(request_type.coded_name));
Emit(&tables_file_, " = fidl_type_t(::fidl::FidlCodedHandle(");
Emit(&tables_file_, types::HandleSubtype::kChannel);
Emit(&tables_file_, ", ");
Emit(&tables_file_, request_type.nullability);
Emit(&tables_file_, "));\n\n");
}
void TablesGenerator::Generate(const coded::InterfaceHandleType& interface_type) {
Emit(&tables_file_, "static const fidl_type_t ");
Emit(&tables_file_, NameTable(interface_type.coded_name));
Emit(&tables_file_, " = fidl_type_t(::fidl::FidlCodedHandle(");
Emit(&tables_file_, types::HandleSubtype::kChannel);
Emit(&tables_file_, ", ");
Emit(&tables_file_, interface_type.nullability);
Emit(&tables_file_, "));\n\n");
}
void TablesGenerator::Generate(const coded::ArrayType& array_type) {
Emit(&tables_file_, "static const fidl_type_t ");
Emit(&tables_file_, NameTable(array_type.coded_name));
Emit(&tables_file_, " = fidl_type_t(::fidl::FidlCodedArray(&");
Emit(&tables_file_, NameTable(array_type.element_type->coded_name));
Emit(&tables_file_, ", ");
Emit(&tables_file_, array_type.size);
Emit(&tables_file_, ", ");
Emit(&tables_file_, array_type.element_size);
Emit(&tables_file_, "));\n\n");
}
void TablesGenerator::Generate(const coded::StringType& string_type) {
Emit(&tables_file_, "static const fidl_type_t ");
Emit(&tables_file_, NameTable(string_type.coded_name));
Emit(&tables_file_, " = fidl_type_t(::fidl::FidlCodedString(");
Emit(&tables_file_, string_type.max_size);
Emit(&tables_file_, ", ");
Emit(&tables_file_, string_type.nullability);
Emit(&tables_file_, "));\n\n");
}
void TablesGenerator::Generate(const coded::VectorType& vector_type) {
Emit(&tables_file_, "static const fidl_type_t ");
Emit(&tables_file_, NameTable(vector_type.coded_name));
Emit(&tables_file_, " = fidl_type_t(::fidl::FidlCodedVector(");
if (vector_type.element_type->coding_needed == coded::CodingNeeded::kNeeded) {
Emit(&tables_file_, "&");
Emit(&tables_file_, NameTable(vector_type.element_type->coded_name));
} else {
Emit(&tables_file_, "nullptr");
}
Emit(&tables_file_, ", ");
Emit(&tables_file_, vector_type.max_count);
Emit(&tables_file_, ", ");
Emit(&tables_file_, vector_type.element_size);
Emit(&tables_file_, ", ");
Emit(&tables_file_, vector_type.nullability);
Emit(&tables_file_, "));\n\n");
}
void TablesGenerator::Generate(const coded::Type* type) {
if (type) {
Emit(&tables_file_, "&");
Emit(&tables_file_, NameTable(type->coded_name));
} else {
Emit(&tables_file_, "nullptr");
}
}
void TablesGenerator::Generate(const coded::StructField& field) {
Emit(&tables_file_, "::fidl::FidlStructField(&");
Emit(&tables_file_, NameTable(field.type->coded_name));
Emit(&tables_file_, ", ");
Emit(&tables_file_, field.offset);
Emit(&tables_file_, ")");
}
void TablesGenerator::Generate(const coded::TableField& field) {
Emit(&tables_file_, "::fidl::FidlTableField(&");
Emit(&tables_file_, NameTable(field.type->coded_name));
Emit(&tables_file_, ",");
Emit(&tables_file_, field.ordinal);
Emit(&tables_file_, ")");
}
void TablesGenerator::Generate(const coded::XUnionField& field) {
Emit(&tables_file_, "::fidl::FidlXUnionField(&");
Emit(&tables_file_, NameTable(field.type->coded_name));
Emit(&tables_file_, ",");
Emit(&tables_file_, field.ordinal);
Emit(&tables_file_, ")");
}
void TablesGenerator::GeneratePointerIfNeeded(const coded::StructType& struct_type) {
if (struct_type.referenced_by_pointer) {
Emit(&tables_file_, "static const fidl_type_t ");
Emit(&tables_file_, NameTable(struct_type.pointer_name));
Emit(&tables_file_, " = fidl_type_t(::fidl::FidlCodedStructPointer(&");
Emit(&tables_file_, NameTable(struct_type.coded_name));
Emit(&tables_file_, ".coded_struct));\n");
}
}
void TablesGenerator::GeneratePointerIfNeeded(const coded::TableType& table_type) {
if (table_type.referenced_by_pointer) {
Emit(&tables_file_, "static const fidl_type_t ");
Emit(&tables_file_, NameTable(table_type.pointer_name));
Emit(&tables_file_, " = fidl_type_t(::fidl::FidlCodedTablePointer(&");
Emit(&tables_file_, NameTable(table_type.coded_name));
Emit(&tables_file_, ".coded_table));\n");
}
}
void TablesGenerator::GeneratePointerIfNeeded(const coded::UnionType& union_type) {
if (union_type.referenced_by_pointer) {
Emit(&tables_file_, "static const fidl_type_t ");
Emit(&tables_file_, NameTable(union_type.pointer_name));
Emit(&tables_file_, " = fidl_type_t(::fidl::FidlCodedUnionPointer(&");
Emit(&tables_file_, NameTable(union_type.coded_name));
Emit(&tables_file_, ".coded_union));\n");
}
}
void TablesGenerator::GeneratePointerIfNeeded(const coded::XUnionType& xunion_type) {
if (xunion_type.referenced_by_pointer) {
Emit(&tables_file_, "static const fidl_type_t ");
Emit(&tables_file_, NameTable(xunion_type.pointer_name));
Emit(&tables_file_, " = fidl_type_t(::fidl::FidlCodedXUnionPointer(&");
Emit(&tables_file_, NameTable(xunion_type.coded_name));
Emit(&tables_file_, ".coded_xunion));\n");
}
}
void TablesGenerator::GenerateForward(const coded::StructType& struct_type) {
Emit(&tables_file_, "extern const fidl_type_t ");
Emit(&tables_file_, NameTable(struct_type.coded_name));
Emit(&tables_file_, ";\n");
}
void TablesGenerator::GenerateForward(const coded::TableType& table_type) {
Emit(&tables_file_, "extern const fidl_type_t ");
Emit(&tables_file_, NameTable(table_type.coded_name));
Emit(&tables_file_, ";\n");
}
void TablesGenerator::GenerateForward(const coded::UnionType& union_type) {
Emit(&tables_file_, "extern const fidl_type_t ");
Emit(&tables_file_, NameTable(union_type.coded_name));
Emit(&tables_file_, ";\n");
}
void TablesGenerator::GenerateForward(const coded::XUnionType& xunion_type) {
Emit(&tables_file_, "extern const fidl_type_t ");
Emit(&tables_file_, NameTable(xunion_type.coded_name));
Emit(&tables_file_, ";\n");
}
const coded::Type* TablesGenerator::CompileType(const flat::Type* type) {
switch (type->kind) {
case flat::Type::Kind::kArray: {
auto array_type = static_cast<const flat::ArrayType*>(type);
auto iter = array_type_map_.find(array_type);
if (iter != array_type_map_.end())
return iter->second;
auto coded_element_type = CompileType(array_type->element_type.get());
uint32_t array_size = array_type->size;
uint32_t element_size = array_type->element_type->size;
auto name = NameCodedArray(coded_element_type->coded_name, array_size);
auto coded_array_type = std::make_unique<coded::ArrayType>(
std::move(name), coded_element_type, array_size, element_size);
array_type_map_[array_type] = coded_array_type.get();
coded_types_.push_back(std::move(coded_array_type));
return coded_types_.back().get();
}
case flat::Type::Kind::kVector: {
auto vector_type = static_cast<const flat::VectorType*>(type);
auto iter = vector_type_map_.find(vector_type);
if (iter != vector_type_map_.end())
return iter->second;
auto coded_element_type = CompileType(vector_type->element_type.get());
uint32_t max_count =
static_cast<const flat::Size&>(vector_type->element_count->Value()).value;
uint32_t element_size = coded_element_type->size;
StringView element_name = coded_element_type->coded_name;
auto name = NameCodedVector(element_name, max_count, vector_type->nullability);
auto coded_vector_type = std::make_unique<coded::VectorType>(
std::move(name), coded_element_type, max_count, element_size, vector_type->nullability);
vector_type_map_[vector_type] = coded_vector_type.get();
coded_types_.push_back(std::move(coded_vector_type));
return coded_types_.back().get();
}
case flat::Type::Kind::kString: {
auto string_type = static_cast<const flat::StringType*>(type);
auto iter = string_type_map_.find(string_type);
if (iter != string_type_map_.end())
return iter->second;
uint32_t max_size =
static_cast<const flat::Size&>(string_type->max_size->Value()).value;
auto name = NameCodedString(max_size, string_type->nullability);
auto coded_string_type = std::make_unique<coded::StringType>(std::move(name), max_size,
string_type->nullability);
string_type_map_[string_type] = coded_string_type.get();
coded_types_.push_back(std::move(coded_string_type));
return coded_types_.back().get();
}
case flat::Type::Kind::kHandle: {
auto handle_type = static_cast<const flat::HandleType*>(type);
auto iter = handle_type_map_.find(handle_type);
if (iter != handle_type_map_.end())
return iter->second;
auto name = NameCodedHandle(handle_type->subtype, handle_type->nullability);
auto coded_handle_type = std::make_unique<coded::HandleType>(
std::move(name), handle_type->subtype, handle_type->nullability);
handle_type_map_[handle_type] = coded_handle_type.get();
coded_types_.push_back(std::move(coded_handle_type));
return coded_types_.back().get();
}
case flat::Type::Kind::kRequestHandle: {
auto request_type = static_cast<const flat::RequestHandleType*>(type);
auto iter = request_type_map_.find(request_type);
if (iter != request_type_map_.end())
return iter->second;
auto name = NameCodedRequestHandle(NameName(request_type->name, "_", "_"), request_type->nullability);
auto coded_request_type =
std::make_unique<coded::RequestHandleType>(std::move(name), request_type->nullability);
request_type_map_[request_type] = coded_request_type.get();
coded_types_.push_back(std::move(coded_request_type));
return coded_types_.back().get();
}
case flat::Type::Kind::kPrimitive: {
auto primitive_type = static_cast<const flat::PrimitiveType*>(type);
auto iter = primitive_type_map_.find(primitive_type);
if (iter != primitive_type_map_.end())
return iter->second;
auto name = NamePrimitiveSubtype(primitive_type->subtype);
auto coded_primitive_type = std::make_unique<coded::PrimitiveType>(
std::move(name), primitive_type->subtype,
flat::PrimitiveType::SubtypeSize(primitive_type->subtype));
primitive_type_map_[primitive_type] = coded_primitive_type.get();
coded_types_.push_back(std::move(coded_primitive_type));
return coded_types_.back().get();
}
case flat::Type::Kind::kIdentifier: {
auto identifier_type = static_cast<const flat::IdentifierType*>(type);
auto iter = named_coded_types_.find(&identifier_type->name);
if (iter == named_coded_types_.end()) {
assert(false && "unknown type in named type map!");
}
// We may need to set the emit-pointer bit on structs, unions, and xunions now.
auto coded_type = iter->second.get();
switch (coded_type->kind) {
case coded::Type::Kind::kStruct: {
// Structs were compiled as part of decl compilation,
// but we may now need to generate the StructPointer.
if (identifier_type->nullability != types::Nullability::kNullable)
break;
auto coded_struct_type = static_cast<coded::StructType*>(coded_type);
coded_struct_type->referenced_by_pointer = true;
coded_types_.push_back(std::make_unique<coded::StructPointerType>(
coded_struct_type->pointer_name, coded_struct_type));
return coded_types_.back().get();
}
case coded::Type::Kind::kTable: {
// Tables were compiled as part of decl compilation,
// but we may now need to generate the TablePointer.
if (identifier_type->nullability != types::Nullability::kNullable)
break;
auto coded_table_type = static_cast<coded::TableType*>(coded_type);
coded_table_type->referenced_by_pointer = true;
coded_types_.push_back(std::make_unique<coded::TablePointerType>(
coded_table_type->pointer_name, coded_table_type));
return coded_types_.back().get();
}
case coded::Type::Kind::kUnion: {
// Unions were compiled as part of decl compilation,
// but we may now need to generate the UnionPointer.
if (identifier_type->nullability != types::Nullability::kNullable)
break;
auto coded_union_type = static_cast<coded::UnionType*>(coded_type);
coded_union_type->referenced_by_pointer = true;
coded_types_.push_back(std::make_unique<coded::UnionPointerType>(
coded_union_type->pointer_name, coded_union_type));
return coded_types_.back().get();
}
case coded::Type::Kind::kXUnion: {
// XUnions were compiled as part of decl compilation,
// but we may now need to generate the XUnionPointer.
if (identifier_type->nullability != types::Nullability::kNullable)
break;
auto coded_xunion_type = static_cast<coded::XUnionType*>(coded_type);
coded_xunion_type->referenced_by_pointer = true;
coded_types_.push_back(std::make_unique<coded::XUnionPointerType>(
coded_xunion_type->pointer_name, coded_xunion_type));
return coded_types_.back().get();
}
case coded::Type::Kind::kInterface: {
auto iter = interface_type_map_.find(identifier_type);
if (iter != interface_type_map_.end())
return iter->second;
auto name = NameCodedInterfaceHandle(NameName(identifier_type->name, "_", "_"),
identifier_type->nullability);
auto coded_interface_type = std::make_unique<coded::InterfaceHandleType>(
std::move(name), identifier_type->nullability);
interface_type_map_[identifier_type] = coded_interface_type.get();
coded_types_.push_back(std::move(coded_interface_type));
return coded_types_.back().get();
}
case coded::Type::Kind::kPrimitive:
// These are from enums. We don't need to do anything with them.
break;
case coded::Type::Kind::kInterfaceHandle:
case coded::Type::Kind::kStructPointer:
case coded::Type::Kind::kTablePointer:
case coded::Type::Kind::kUnionPointer:
case coded::Type::Kind::kXUnionPointer:
case coded::Type::Kind::kMessage:
case coded::Type::Kind::kRequestHandle:
case coded::Type::Kind::kHandle:
case coded::Type::Kind::kArray:
case coded::Type::Kind::kVector:
case coded::Type::Kind::kString:
assert(false && "anonymous type in named type map!");
break;
}
return coded_type;
}
}
}
void TablesGenerator::CompileFields(const flat::Decl* decl) {
switch (decl->kind) {
case flat::Decl::Kind::kInterface: {
auto interface_decl = static_cast<const flat::Interface*>(decl);
coded::InterfaceType* coded_interface =
static_cast<coded::InterfaceType*>(named_coded_types_[&decl->name].get());
size_t i = 0;
for (const auto& method_pointer : interface_decl->all_methods) {
assert(method_pointer != nullptr);
const auto& method = *method_pointer;
auto CompileMessage = [&](const flat::Struct& message) -> void {
std::unique_ptr<coded::MessageType>& coded_message = coded_interface->messages[i++];
std::vector<coded::StructField>& request_fields = coded_message->fields;
for (const auto& parameter : message.members) {
std::string parameter_name =
coded_message->coded_name + "_" + std::string(parameter.name.data());
auto coded_parameter_type = CompileType(parameter.type.get());
if (coded_parameter_type->coding_needed == coded::CodingNeeded::kNeeded)
request_fields.emplace_back(coded_parameter_type,
parameter.fieldshape.Offset());
}
// We move the coded_message to coded_types_ so that we'll generate tables for the
// message
// in the proper order.
coded_types_.push_back(std::move(coded_message));
};
if (method.maybe_request) {
CompileMessage(*method.maybe_request);
}
if (method.maybe_response) {
CompileMessage(*method.maybe_response);
}
}
break;
}
case flat::Decl::Kind::kStruct: {
auto struct_decl = static_cast<const flat::Struct*>(decl);
if (struct_decl->anonymous)
break;
coded::StructType* coded_struct =
static_cast<coded::StructType*>(named_coded_types_[&decl->name].get());
std::vector<coded::StructField>& struct_fields = coded_struct->fields;
for (const auto& member : struct_decl->members) {
std::string member_name =
coded_struct->coded_name + "_" + std::string(member.name.data());
auto coded_member_type = CompileType(member.type.get());
if (coded_member_type->coding_needed == coded::CodingNeeded::kNeeded)
struct_fields.emplace_back(coded_member_type, member.fieldshape.Offset());
}
break;
}
case flat::Decl::Kind::kUnion: {
auto union_decl = static_cast<const flat::Union*>(decl);
coded::UnionType* union_struct =
static_cast<coded::UnionType*>(named_coded_types_[&decl->name].get());
std::vector<const coded::Type*>& union_members = union_struct->types;
for (const auto& member : union_decl->members) {
std::string member_name =
union_struct->coded_name + "_" + std::string(member.name.data());
auto coded_member_type = CompileType(member.type.get());
if (coded_member_type->coding_needed == coded::CodingNeeded::kNeeded) {
union_members.push_back(coded_member_type);
} else {
// We need union_members.size() to match union_decl->members.size() because
// the coding tables will use the union |tag| to index into the member array.
union_members.push_back(nullptr);
}
}
break;
}
case flat::Decl::Kind::kXUnion: {
auto xunion_decl = static_cast<const flat::XUnion*>(decl);
auto coded_xunion =
static_cast<coded::XUnionType*>(named_coded_types_[&decl->name].get());
std::map<uint32_t, const flat::XUnion::Member*> members;
for (const auto& member : xunion_decl->members) {
if (!members.emplace(member.ordinal->value, &member).second) {
assert(false && "Duplicate ordinal found in table generation");
}
}
for (const auto& member_pair : members) {
const auto& member = *member_pair.second;
auto coded_member_type = CompileType(member.type.get());
if (coded_member_type->coding_needed == coded::CodingNeeded::kNeeded) {
coded_xunion->fields.emplace_back(coded_member_type, member.ordinal->value);
}
}
break;
}
case flat::Decl::Kind::kTable: {
auto table_decl = static_cast<const flat::Table*>(decl);
coded::TableType* coded_table =
static_cast<coded::TableType*>(named_coded_types_[&decl->name].get());
std::vector<coded::TableField>& table_fields = coded_table->fields;
std::map<uint32_t, const flat::Table::Member*> members;
for (const auto& member : table_decl->members) {
if (!members.emplace(member.ordinal->value, &member).second) {
assert(false && "Duplicate ordinal found in table generation");
}
}
for (const auto& member_pair : members) {
const auto& member = *member_pair.second;
if (!member.maybe_used)
continue;
std::string member_name =
coded_table->coded_name + "_" + std::string(member.maybe_used->name.data());
auto coded_member_type = CompileType(member.maybe_used->type.get());
if (coded_member_type->coding_needed == coded::CodingNeeded::kNeeded)
table_fields.emplace_back(coded_member_type, member.ordinal->value);
}
break;
}
default: {
break;
}
}
}
void TablesGenerator::Compile(const flat::Decl* decl) {
switch (decl->kind) {
case flat::Decl::Kind::kConst:
// Nothing to do for const declarations.
break;
case flat::Decl::Kind::kEnum: {
auto enum_decl = static_cast<const flat::Enum*>(decl);
std::string enum_name = NameName(enum_decl->name, "_", "_");
named_coded_types_.emplace(&enum_decl->name,
std::make_unique<coded::PrimitiveType>(
std::move(enum_name), enum_decl->type->subtype,
flat::PrimitiveType::SubtypeSize(enum_decl->type->subtype)));
break;
}
case flat::Decl::Kind::kInterface: {
auto interface_decl = static_cast<const flat::Interface*>(decl);
std::string interface_name = NameInterface(*interface_decl);
std::string interface_qname = NameName(interface_decl->name, ".", "/");
std::vector<std::unique_ptr<coded::MessageType>> interface_messages;
for (const auto& method_pointer : interface_decl->all_methods) {
assert(method_pointer != nullptr);
const auto& method = *method_pointer;
std::string method_name = NameMethod(interface_name, method);
std::string method_qname = NameMethod(interface_qname, method);
auto CreateMessage = [&](const flat::Struct& message,
types::MessageKind kind) -> void {
std::string message_name = NameMessage(method_name, kind);
std::string message_qname = NameMessage(method_qname, kind);
interface_messages.push_back(std::make_unique<coded::MessageType>(
std::move(message_name), std::vector<coded::StructField>(),
message.typeshape.Size(), std::move(message_qname)));
};
if (method.maybe_request) {
CreateMessage(*method.maybe_request, types::MessageKind::kRequest);
}
if (method.maybe_response) {
auto kind = method.maybe_request ? types::MessageKind::kResponse
: types::MessageKind::kEvent;
CreateMessage(*method.maybe_response, kind);
}
}
named_coded_types_.emplace(
&decl->name, std::make_unique<coded::InterfaceType>(std::move(interface_messages)));
break;
}
case flat::Decl::Kind::kTable: {
auto table_decl = static_cast<const flat::Table*>(decl);
std::string table_name = NameCodedTable(table_decl);
std::string pointer_name = NamePointer(table_name);
named_coded_types_.emplace(
&decl->name,
std::make_unique<coded::TableType>(std::move(table_name), std::vector<coded::TableField>(),
table_decl->typeshape.Size(),
std::move(pointer_name), NameName(table_decl->name, ".", "/")));
break;
}
case flat::Decl::Kind::kStruct: {
auto struct_decl = static_cast<const flat::Struct*>(decl);
if (struct_decl->anonymous)
break;
std::string struct_name = NameCodedStruct(struct_decl);
std::string pointer_name = NamePointer(struct_name);
named_coded_types_.emplace(
&decl->name,
std::make_unique<coded::StructType>(std::move(struct_name), std::vector<coded::StructField>(),
struct_decl->typeshape.Size(),
std::move(pointer_name), NameName(struct_decl->name, ".", "/")));
break;
}
case flat::Decl::Kind::kUnion: {
auto union_decl = static_cast<const flat::Union*>(decl);
std::string union_name = NameCodedUnion(union_decl);
std::string pointer_name = NamePointer(union_name);
named_coded_types_.emplace(
&decl->name, std::make_unique<coded::UnionType>(
std::move(union_name), std::vector<const coded::Type*>(),
union_decl->membershape.Offset(), union_decl->typeshape.Size(),
std::move(pointer_name), NameName(union_decl->name, ".", "/")));
break;
}
case flat::Decl::Kind::kXUnion: {
auto xunion_decl = static_cast<const flat::XUnion*>(decl);
std::string xunion_name = NameCodedXUnion(xunion_decl);
std::string pointer_name = NamePointer(xunion_name);
named_coded_types_.emplace(
&decl->name, std::make_unique<coded::XUnionType>(
std::move(xunion_name), std::vector<coded::XUnionField>(),
std::move(pointer_name), NameName(xunion_decl->name, ".", "/")));
break;
}
}
}
std::ostringstream TablesGenerator::Produce() {
GenerateFilePreamble();
for (const auto& decl : library_->declaration_order_) {
Compile(decl);
}
for (const auto& decl : library_->declaration_order_) {
if (decl->name.library() != library_)
continue;
CompileFields(decl);
}
for (const auto& decl : library_->declaration_order_) {
coded::Type* coded_type = named_coded_types_[&decl->name].get();
if (!coded_type)
continue;
switch (coded_type->kind) {
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::kUnion:
GenerateForward(*static_cast<const coded::UnionType*>(coded_type));
break;
case coded::Type::Kind::kXUnion:
GenerateForward(*static_cast<const coded::XUnionType*>(coded_type));
break;
default:
break;
}
}
Emit(&tables_file_, "\n");
for (const auto& decl : library_->declaration_order_) {
coded::Type* coded_type = named_coded_types_[&decl->name].get();
if (!coded_type)
continue;
switch (coded_type->kind) {
case coded::Type::Kind::kStruct:
GeneratePointerIfNeeded(*static_cast<const coded::StructType*>(coded_type));
break;
case coded::Type::Kind::kTable:
GeneratePointerIfNeeded(*static_cast<const coded::TableType*>(coded_type));
break;
case coded::Type::Kind::kUnion:
GeneratePointerIfNeeded(*static_cast<const coded::UnionType*>(coded_type));
break;
case coded::Type::Kind::kXUnion:
GeneratePointerIfNeeded(*static_cast<const coded::XUnionType*>(coded_type));
break;
default:
break;
}
}
Emit(&tables_file_, "\n");
for (const auto& coded_type : coded_types_) {
if (coded_type->coding_needed == coded::CodingNeeded::kNotNeeded)
continue;
switch (coded_type->kind) {
case coded::Type::Kind::kStruct:
case coded::Type::Kind::kStructPointer:
case coded::Type::Kind::kTable:
case coded::Type::Kind::kTablePointer:
case coded::Type::Kind::kUnion:
case coded::Type::Kind::kUnionPointer:
case coded::Type::Kind::kXUnion:
case coded::Type::Kind::kXUnionPointer:
// These are generated in the next phase.
break;
case coded::Type::Kind::kInterface:
// Nothing to generate for interfaces. We've already moved the
// messages from the interface into coded_types_ directly.
break;
case coded::Type::Kind::kMessage:
Generate(*static_cast<const coded::MessageType*>(coded_type.get()));
break;
case coded::Type::Kind::kHandle:
Generate(*static_cast<const coded::HandleType*>(coded_type.get()));
break;
case coded::Type::Kind::kInterfaceHandle:
Generate(*static_cast<const coded::InterfaceHandleType*>(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:
// These are only around to provide size information to
// vectors. There's never anything to generate, and this
// should not be reached.
assert(false && "Primitive types should never need coding tables");
break;
}
}
for (const auto& decl : library_->declaration_order_) {
if (decl->name.library() != library_)
continue;
coded::Type* coded_type = named_coded_types_[&decl->name].get();
if (!coded_type)
continue;
switch (coded_type->kind) {
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::kUnion:
Generate(*static_cast<const coded::UnionType*>(coded_type));
break;
case coded::Type::Kind::kXUnion:
Generate(*static_cast<const coded::XUnionType*>(coded_type));
break;
default:
continue;
}
}
GenerateFilePostamble();
return std::move(tables_file_);
}
} // namespace fidl