blob: 38d222b136995a93b668e607594989d1f2771b41 [file] [log] [blame]
# Copyright 2013 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Generates C++ source files from a mojom.Module."""
import mojom.generate.generator as generator
import mojom.generate.module as mojom
import mojom.generate.pack as pack
from mojom.generate.template_expander import UseJinja
_kind_to_cpp_type = {
mojom.BOOL: "bool",
mojom.INT8: "int8_t",
mojom.UINT8: "uint8_t",
mojom.INT16: "int16_t",
mojom.UINT16: "uint16_t",
mojom.INT32: "int32_t",
mojom.UINT32: "uint32_t",
mojom.FLOAT: "float",
mojom.INT64: "int64_t",
mojom.UINT64: "uint64_t",
mojom.DOUBLE: "double",
}
_kind_to_cpp_literal_suffix = {
mojom.UINT8: "U",
mojom.UINT16: "U",
mojom.UINT32: "U",
mojom.FLOAT: "f",
mojom.UINT64: "ULL",
}
# TODO(rockot): Get rid of these globals. This requires some refactoring of the
# generator library code so that filters can use the generator as context.
_current_typemap = {}
_for_blink = False
# TODO(rockot, yzshen): The variant handling is kind of a hack currently. Make
# it right.
_variant = None
_export_attribute = None
class _NameFormatter(object):
"""A formatter for the names of kinds or values."""
def __init__(self, token, variant):
self._token = token
self._variant = variant
def Format(self, separator, prefixed=False, internal=False,
include_variant=False, add_same_module_namespaces=False,
flatten_nested_kind=False):
"""Formats the name according to the given configuration.
Args:
separator: Separator between different parts of the name.
prefixed: Whether a leading separator should be added.
internal: Returns the name in the "internal" namespace.
include_variant: Whether to include variant as namespace. If |internal| is
True, then this flag is ignored and variant is not included.
add_same_module_namespaces: Includes all namespaces even if the token is
from the same module as the current mojom file.
flatten_nested_kind: It is allowed to define enums inside structs and
interfaces. If this flag is set to True, this method concatenates the
parent kind and the nested kind with '_', instead of treating the
parent kind as a scope."""
parts = []
if self._ShouldIncludeNamespace(add_same_module_namespaces):
if prefixed:
parts.append("")
parts.extend(self._GetNamespace())
if include_variant and self._variant and not internal:
parts.append(self._variant)
parts.extend(self._GetName(internal, flatten_nested_kind))
return separator.join(parts)
def FormatForCpp(self, add_same_module_namespaces=False, internal=False,
flatten_nested_kind=False):
return self.Format(
"::", prefixed=True,
add_same_module_namespaces=add_same_module_namespaces,
internal=internal, include_variant=True,
flatten_nested_kind=flatten_nested_kind)
def FormatForMojom(self):
return self.Format(".", add_same_module_namespaces=True)
def _MapKindName(self, token, internal):
if not internal:
return token.name
if (mojom.IsStructKind(token) or mojom.IsUnionKind(token) or
mojom.IsEnumKind(token)):
return token.name + "_Data"
return token.name
def _GetName(self, internal, flatten_nested_kind):
if isinstance(self._token, mojom.EnumValue):
name_parts = _NameFormatter(self._token.enum, self._variant)._GetName(
internal, flatten_nested_kind)
name_parts.append(self._token.name)
return name_parts
name_parts = []
if internal:
name_parts.append("internal")
if (flatten_nested_kind and mojom.IsEnumKind(self._token) and
self._token.parent_kind):
name = "%s_%s" % (self._token.parent_kind.name,
self._MapKindName(self._token, internal))
name_parts.append(name)
return name_parts
if self._token.parent_kind:
name_parts.append(self._MapKindName(self._token.parent_kind, internal))
name_parts.append(self._MapKindName(self._token, internal))
return name_parts
def _ShouldIncludeNamespace(self, add_same_module_namespaces):
return add_same_module_namespaces or self._token.imported_from
def _GetNamespace(self):
if self._token.imported_from:
return NamespaceToArray(self._token.imported_from["namespace"])
elif hasattr(self._token, "module"):
return NamespaceToArray(self._token.module.namespace)
return []
def ConstantValue(constant):
return ExpressionToText(constant.value, kind=constant.kind)
# TODO(yzshen): Revisit the default value feature. It was designed prior to
# custom type mapping.
def DefaultValue(field):
if field.default:
if mojom.IsStructKind(field.kind):
assert field.default == "default"
if not IsTypemappedKind(field.kind):
return "%s::New()" % GetNameForKind(field.kind)
return ExpressionToText(field.default, kind=field.kind)
return ""
def NamespaceToArray(namespace):
return namespace.split(".") if namespace else []
def GetNameForKind(kind, internal=False, flatten_nested_kind=False,
add_same_module_namespaces=False):
return _NameFormatter(kind, _variant).FormatForCpp(
internal=internal, flatten_nested_kind=flatten_nested_kind,
add_same_module_namespaces=add_same_module_namespaces)
def GetQualifiedNameForKind(kind, internal=False, flatten_nested_kind=False,
include_variant=True):
return _NameFormatter(
kind, _variant if include_variant else None).FormatForCpp(
internal=internal, add_same_module_namespaces=True,
flatten_nested_kind=flatten_nested_kind)
def GetWtfHashFnNameForEnum(enum):
return _NameFormatter(
enum, None).Format("_", internal=True, add_same_module_namespaces=True,
flatten_nested_kind=True) + "HashFn"
def GetFullMojomNameForKind(kind):
return _NameFormatter(kind, _variant).FormatForMojom()
def IsTypemappedKind(kind):
return hasattr(kind, "name") and \
GetFullMojomNameForKind(kind) in _current_typemap
def IsNativeOnlyKind(kind):
return (mojom.IsStructKind(kind) or mojom.IsEnumKind(kind)) and \
kind.native_only
def IsHashableKind(kind):
"""Check if the kind can be hashed.
Args:
kind: {Kind} The kind to check.
Returns:
{bool} True if a value of this kind can be hashed.
"""
checked = set()
def Check(kind):
if kind.spec in checked:
return True
checked.add(kind.spec)
if mojom.IsNullableKind(kind):
return False
elif mojom.IsStructKind(kind):
if (IsTypemappedKind(kind) and
not _current_typemap[GetFullMojomNameForKind(kind)]["hashable"]):
return False
return all(Check(field.kind) for field in kind.fields)
elif mojom.IsEnumKind(kind):
return not IsTypemappedKind(kind) or _current_typemap[
GetFullMojomNameForKind(kind)]["hashable"]
elif mojom.IsUnionKind(kind):
return all(Check(field.kind) for field in kind.fields)
elif mojom.IsAnyHandleKind(kind):
return False
elif mojom.IsAnyInterfaceKind(kind):
return False
# TODO(tibell): Arrays and maps could be made hashable. We just don't have a
# use case yet.
elif mojom.IsArrayKind(kind):
return False
elif mojom.IsMapKind(kind):
return False
else:
return True
return Check(kind)
def AllEnumValues(enum):
"""Return all enum values associated with an enum.
Args:
enum: {mojom.Enum} The enum type.
Returns:
{Set[int]} The values.
"""
return set(field.numeric_value for field in enum.fields)
def GetNativeTypeName(typemapped_kind):
return _current_typemap[GetFullMojomNameForKind(typemapped_kind)]["typename"]
def GetCppPodType(kind):
return _kind_to_cpp_type[kind]
def FormatConstantDeclaration(constant, nested=False):
if mojom.IsStringKind(constant.kind):
if nested:
return "const char %s[]" % constant.name
return "%sextern const char %s[]" % \
((_export_attribute + " ") if _export_attribute else "", constant.name)
return "constexpr %s %s = %s" % (GetCppPodType(constant.kind), constant.name,
ConstantValue(constant))
def GetCppWrapperType(kind, add_same_module_namespaces=False):
def _AddOptional(type_name):
pattern = "WTF::Optional<%s>" if _for_blink else "base::Optional<%s>"
return pattern % type_name
if IsTypemappedKind(kind):
type_name = GetNativeTypeName(kind)
if (mojom.IsNullableKind(kind) and
not _current_typemap[GetFullMojomNameForKind(kind)][
"nullable_is_same_type"]):
type_name = _AddOptional(type_name)
return type_name
if mojom.IsEnumKind(kind):
return GetNameForKind(
kind, add_same_module_namespaces=add_same_module_namespaces)
if mojom.IsStructKind(kind) or mojom.IsUnionKind(kind):
return "%sPtr" % GetNameForKind(
kind, add_same_module_namespaces=add_same_module_namespaces)
if mojom.IsArrayKind(kind):
pattern = "WTF::Vector<%s>" if _for_blink else "std::vector<%s>"
if mojom.IsNullableKind(kind):
pattern = _AddOptional(pattern)
return pattern % GetCppWrapperType(
kind.kind, add_same_module_namespaces=add_same_module_namespaces)
if mojom.IsMapKind(kind):
pattern = ("WTF::HashMap<%s, %s>" if _for_blink else
"std::unordered_map<%s, %s>")
if mojom.IsNullableKind(kind):
pattern = _AddOptional(pattern)
return pattern % (
GetCppWrapperType(
kind.key_kind,
add_same_module_namespaces=add_same_module_namespaces),
GetCppWrapperType(
kind.value_kind,
add_same_module_namespaces=add_same_module_namespaces))
if mojom.IsInterfaceKind(kind):
return "%sPtr" % GetNameForKind(
kind, add_same_module_namespaces=add_same_module_namespaces)
if mojom.IsInterfaceRequestKind(kind):
return "%sRequest" % GetNameForKind(
kind.kind, add_same_module_namespaces=add_same_module_namespaces)
if mojom.IsAssociatedInterfaceKind(kind):
return "%sAssociatedPtrInfo" % GetNameForKind(
kind.kind, add_same_module_namespaces=add_same_module_namespaces)
if mojom.IsAssociatedInterfaceRequestKind(kind):
return "%sAssociatedRequest" % GetNameForKind(
kind.kind, add_same_module_namespaces=add_same_module_namespaces)
if mojom.IsStringKind(kind):
if _for_blink:
return "WTF::String"
type_name = "std::string"
return _AddOptional(type_name) if mojom.IsNullableKind(kind) else type_name
if mojom.IsGenericHandleKind(kind):
return "mojo::ScopedHandle"
if mojom.IsDataPipeConsumerKind(kind):
return "mojo::ScopedDataPipeConsumerHandle"
if mojom.IsDataPipeProducerKind(kind):
return "mojo::ScopedDataPipeProducerHandle"
if mojom.IsMessagePipeKind(kind):
return "mojo::ScopedMessagePipeHandle"
if mojom.IsSharedBufferKind(kind):
return "mojo::ScopedSharedBufferHandle"
if not kind in _kind_to_cpp_type:
raise Exception("Unrecognized kind %s" % kind.spec)
return _kind_to_cpp_type[kind]
def IsMoveOnlyKind(kind):
if IsTypemappedKind(kind):
if mojom.IsEnumKind(kind):
return False
return _current_typemap[GetFullMojomNameForKind(kind)]["move_only"]
if mojom.IsStructKind(kind) or mojom.IsUnionKind(kind):
return True
if mojom.IsArrayKind(kind):
return IsMoveOnlyKind(kind.kind)
if mojom.IsMapKind(kind):
return IsMoveOnlyKind(kind.value_kind)
if mojom.IsAnyHandleOrInterfaceKind(kind):
return True
return False
def IsCopyablePassByValue(kind):
if not IsTypemappedKind(kind):
return False
return _current_typemap[GetFullMojomNameForKind(kind)][
"copyable_pass_by_value"]
def ShouldPassParamByValue(kind):
return ((not mojom.IsReferenceKind(kind)) or IsMoveOnlyKind(kind) or
IsCopyablePassByValue(kind))
def GetCppWrapperParamType(kind):
cpp_wrapper_type = GetCppWrapperType(kind)
return (cpp_wrapper_type if ShouldPassParamByValue(kind)
else "const %s&" % cpp_wrapper_type)
def GetCppFieldType(kind):
if mojom.IsStructKind(kind):
return ("mojo::internal::Pointer<%s>" %
GetNameForKind(kind, internal=True))
if mojom.IsUnionKind(kind):
return "%s" % GetNameForKind(kind, internal=True)
if mojom.IsArrayKind(kind):
return ("mojo::internal::Pointer<mojo::internal::Array_Data<%s>>" %
GetCppFieldType(kind.kind))
if mojom.IsMapKind(kind):
return ("mojo::internal::Pointer<mojo::internal::Map_Data<%s, %s>>" %
(GetCppFieldType(kind.key_kind), GetCppFieldType(kind.value_kind)))
if mojom.IsInterfaceKind(kind):
return "mojo::internal::Interface_Data"
if mojom.IsInterfaceRequestKind(kind):
return "mojo::internal::Handle_Data"
if mojom.IsAssociatedInterfaceKind(kind):
return "mojo::internal::AssociatedInterface_Data"
if mojom.IsAssociatedInterfaceRequestKind(kind):
return "mojo::internal::AssociatedEndpointHandle_Data"
if mojom.IsEnumKind(kind):
return "int32_t"
if mojom.IsStringKind(kind):
return "mojo::internal::Pointer<mojo::internal::String_Data>"
if mojom.IsAnyHandleKind(kind):
return "mojo::internal::Handle_Data"
return _kind_to_cpp_type[kind]
def GetCppUnionFieldType(kind):
if mojom.IsUnionKind(kind):
return ("mojo::internal::Pointer<%s>" % GetNameForKind(kind, internal=True))
return GetCppFieldType(kind)
def GetUnionGetterReturnType(kind):
if mojom.IsReferenceKind(kind):
return "%s&" % GetCppWrapperType(kind)
return GetCppWrapperType(kind)
def GetUnionTraitGetterReturnType(kind):
"""Get field type used in UnionTraits template specialization.
The type may be qualified as UnionTraits specializations live outside the
namespace where e.g. structs are defined.
Args:
kind: {Kind} The type of the field.
Returns:
{str} The C++ type to use for the field.
"""
if mojom.IsReferenceKind(kind):
return "%s&" % GetCppWrapperType(kind, add_same_module_namespaces=True)
return GetCppWrapperType(kind, add_same_module_namespaces=True)
def GetCppDataViewType(kind, qualified=False):
def _GetName(input_kind):
return _NameFormatter(input_kind, None).FormatForCpp(
add_same_module_namespaces=qualified, flatten_nested_kind=True)
if mojom.IsEnumKind(kind):
return _GetName(kind)
if mojom.IsStructKind(kind) or mojom.IsUnionKind(kind):
return "%sDataView" % _GetName(kind)
if mojom.IsArrayKind(kind):
return "mojo::ArrayDataView<%s>" % GetCppDataViewType(kind.kind, qualified)
if mojom.IsMapKind(kind):
return ("mojo::MapDataView<%s, %s>" % (
GetCppDataViewType(kind.key_kind, qualified),
GetCppDataViewType(kind.value_kind, qualified)))
if mojom.IsStringKind(kind):
return "mojo::StringDataView"
if mojom.IsInterfaceKind(kind):
return "%sPtrDataView" % _GetName(kind)
if mojom.IsInterfaceRequestKind(kind):
return "%sRequestDataView" % _GetName(kind.kind)
if mojom.IsAssociatedInterfaceKind(kind):
return "%sAssociatedPtrInfoDataView" % _GetName(kind.kind)
if mojom.IsAssociatedInterfaceRequestKind(kind):
return "%sAssociatedRequestDataView" % _GetName(kind.kind)
if mojom.IsGenericHandleKind(kind):
return "mojo::ScopedHandle"
if mojom.IsDataPipeConsumerKind(kind):
return "mojo::ScopedDataPipeConsumerHandle"
if mojom.IsDataPipeProducerKind(kind):
return "mojo::ScopedDataPipeProducerHandle"
if mojom.IsMessagePipeKind(kind):
return "mojo::ScopedMessagePipeHandle"
if mojom.IsSharedBufferKind(kind):
return "mojo::ScopedSharedBufferHandle"
return _kind_to_cpp_type[kind]
def GetUnmappedTypeForSerializer(kind):
return GetCppDataViewType(kind, qualified=True)
def TranslateConstants(token, kind):
if isinstance(token, mojom.NamedValue):
return GetNameForKind(token, flatten_nested_kind=True)
if isinstance(token, mojom.BuiltinValue):
if token.value == "double.INFINITY":
return "std::numeric_limits<double>::infinity()"
if token.value == "float.INFINITY":
return "std::numeric_limits<float>::infinity()"
if token.value == "double.NEGATIVE_INFINITY":
return "-std::numeric_limits<double>::infinity()"
if token.value == "float.NEGATIVE_INFINITY":
return "-std::numeric_limits<float>::infinity()"
if token.value == "double.NAN":
return "std::numeric_limits<double>::quiet_NaN()"
if token.value == "float.NAN":
return "std::numeric_limits<float>::quiet_NaN()"
if (kind is not None and mojom.IsFloatKind(kind)):
return token if token.isdigit() else token + "f";
# Per C++11, 2.14.2, the type of an integer literal is the first of the
# corresponding list in Table 6 in which its value can be represented. In this
# case, the list for decimal constants with no suffix is:
# int, long int, long long int
# The standard considers a program ill-formed if it contains an integer
# literal that cannot be represented by any of the allowed types.
#
# As it turns out, MSVC doesn't bother trying to fall back to long long int,
# so the integral constant -2147483648 causes it grief: it decides to
# represent 2147483648 as an unsigned integer, and then warns that the unary
# minus operator doesn't make sense on unsigned types. Doh!
if kind == mojom.INT32 and token == "-2147483648":
return "(-%d - 1) /* %s */" % (
2**31 - 1, "Workaround for MSVC bug; see https://crbug.com/445618")
return "%s%s" % (token, _kind_to_cpp_literal_suffix.get(kind, ""))
def ExpressionToText(value, kind=None):
return TranslateConstants(value, kind)
def RequiresContextForDataView(kind):
for field in kind.fields:
if mojom.IsReferenceKind(field.kind):
return True
return False
def ShouldInlineStruct(struct):
# TODO(darin): Base this on the size of the wrapper class.
if len(struct.fields) > 4:
return False
for field in struct.fields:
if mojom.IsReferenceKind(field.kind) and not mojom.IsStringKind(field.kind):
return False
return True
def ContainsMoveOnlyMembers(struct):
for field in struct.fields:
if IsMoveOnlyKind(field.kind):
return True
return False
def ShouldInlineUnion(union):
return not any(
mojom.IsReferenceKind(field.kind) and not mojom.IsStringKind(field.kind)
for field in union.fields)
class StructConstructor(object):
"""Represents a constructor for a generated struct.
Fields:
fields: {[Field]} All struct fields in order.
params: {[Field]} The fields that are passed as params.
"""
def __init__(self, fields, params):
self._fields = fields
self._params = set(params)
@property
def params(self):
return [field for field in self._fields if field in self._params]
@property
def fields(self):
for field in self._fields:
yield (field, field in self._params)
def GetStructConstructors(struct):
"""Returns a list of constructors for a struct.
Params:
struct: {Struct} The struct to return constructors for.
Returns:
{[StructConstructor]} A list of StructConstructors that should be generated
for |struct|.
"""
if not mojom.IsStructKind(struct):
raise TypeError
# Types that are neither copyable nor movable can't be passed to a struct
# constructor so only generate a default constructor.
if any(IsTypemappedKind(field.kind) and _current_typemap[
GetFullMojomNameForKind(field.kind)]["non_copyable_non_movable"]
for field in struct.fields):
return [StructConstructor(struct.fields, [])]
param_counts = [0]
for version in struct.versions:
if param_counts[-1] != version.num_fields:
param_counts.append(version.num_fields)
ordinal_fields = sorted(struct.fields, key=lambda field: field.ordinal)
return (StructConstructor(struct.fields, ordinal_fields[:param_count])
for param_count in param_counts)
def GetContainerValidateParamsCtorArgs(kind):
if mojom.IsStringKind(kind):
expected_num_elements = 0
element_is_nullable = False
key_validate_params = "nullptr"
element_validate_params = "nullptr"
enum_validate_func = "nullptr"
elif mojom.IsMapKind(kind):
expected_num_elements = 0
element_is_nullable = False
key_validate_params = GetNewContainerValidateParams(mojom.Array(
kind=kind.key_kind))
element_validate_params = GetNewContainerValidateParams(mojom.Array(
kind=kind.value_kind))
enum_validate_func = "nullptr"
else: # mojom.IsArrayKind(kind)
expected_num_elements = generator.ExpectedArraySize(kind) or 0
element_is_nullable = mojom.IsNullableKind(kind.kind)
key_validate_params = "nullptr"
element_validate_params = GetNewContainerValidateParams(kind.kind)
if mojom.IsEnumKind(kind.kind):
enum_validate_func = ("%s::Validate" %
GetQualifiedNameForKind(kind.kind, internal=True,
flatten_nested_kind=True))
else:
enum_validate_func = "nullptr"
if enum_validate_func == "nullptr":
if key_validate_params == "nullptr":
return "%d, %s, %s" % (expected_num_elements,
"true" if element_is_nullable else "false",
element_validate_params)
else:
return "%s, %s" % (key_validate_params, element_validate_params)
else:
return "%d, %s" % (expected_num_elements, enum_validate_func)
def GetNewContainerValidateParams(kind):
if (not mojom.IsArrayKind(kind) and not mojom.IsMapKind(kind) and
not mojom.IsStringKind(kind)):
return "nullptr"
return "new mojo::internal::ContainerValidateParams(%s)" % (
GetContainerValidateParamsCtorArgs(kind))
class Generator(generator.Generator):
cpp_filters = {
"all_enum_values": AllEnumValues,
"constant_value": ConstantValue,
"contains_handles_or_interfaces": mojom.ContainsHandlesOrInterfaces,
"contains_move_only_members": ContainsMoveOnlyMembers,
"cpp_wrapper_param_type": GetCppWrapperParamType,
"cpp_data_view_type": GetCppDataViewType,
"cpp_field_type": GetCppFieldType,
"cpp_union_field_type": GetCppUnionFieldType,
"cpp_pod_type": GetCppPodType,
"cpp_union_getter_return_type": GetUnionGetterReturnType,
"cpp_union_trait_getter_return_type": GetUnionTraitGetterReturnType,
"cpp_wrapper_type": GetCppWrapperType,
"default_value": DefaultValue,
"expression_to_text": ExpressionToText,
"format_constant_declaration": FormatConstantDeclaration,
"get_container_validate_params_ctor_args":
GetContainerValidateParamsCtorArgs,
"get_name_for_kind": GetNameForKind,
"get_pad": pack.GetPad,
"get_qualified_name_for_kind": GetQualifiedNameForKind,
"has_callbacks": mojom.HasCallbacks,
"has_sync_methods": mojom.HasSyncMethods,
"requires_context_for_data_view": RequiresContextForDataView,
"should_inline": ShouldInlineStruct,
"should_inline_union": ShouldInlineUnion,
"is_array_kind": mojom.IsArrayKind,
"is_enum_kind": mojom.IsEnumKind,
"is_integral_kind": mojom.IsIntegralKind,
"is_native_only_kind": IsNativeOnlyKind,
"is_any_handle_kind": mojom.IsAnyHandleKind,
"is_any_interface_kind": mojom.IsAnyInterfaceKind,
"is_any_handle_or_interface_kind": mojom.IsAnyHandleOrInterfaceKind,
"is_associated_kind": mojom.IsAssociatedKind,
"is_hashable": IsHashableKind,
"is_map_kind": mojom.IsMapKind,
"is_nullable_kind": mojom.IsNullableKind,
"is_object_kind": mojom.IsObjectKind,
"is_reference_kind": mojom.IsReferenceKind,
"is_string_kind": mojom.IsStringKind,
"is_struct_kind": mojom.IsStructKind,
"is_typemapped_kind": IsTypemappedKind,
"is_union_kind": mojom.IsUnionKind,
"passes_associated_kinds": mojom.PassesAssociatedKinds,
"struct_constructors": GetStructConstructors,
"stylize_method": generator.StudlyCapsToCamel,
"under_to_camel": generator.UnderToCamel,
"unmapped_type_for_serializer": GetUnmappedTypeForSerializer,
"wtf_hash_fn_name_for_enum": GetWtfHashFnNameForEnum,
}
def GetExtraTraitsHeaders(self):
extra_headers = set()
for typemap in self._GetAllUsedTypemaps():
extra_headers.update(typemap.get("traits_headers", []))
return sorted(extra_headers)
def _GetAllUsedTypemaps(self):
"""Returns the typemaps for types needed for serialization in this module.
A type is needed for serialization if it is contained by a struct or union
defined in this module, is a parameter of a message in an interface in
this module or is contained within another type needed for serialization.
"""
used_typemaps = []
seen_types = set()
def AddKind(kind):
if (mojom.IsIntegralKind(kind) or mojom.IsStringKind(kind) or
mojom.IsDoubleKind(kind) or mojom.IsFloatKind(kind) or
mojom.IsAnyHandleKind(kind) or
mojom.IsInterfaceKind(kind) or
mojom.IsInterfaceRequestKind(kind) or
mojom.IsAssociatedKind(kind)):
pass
elif mojom.IsArrayKind(kind):
AddKind(kind.kind)
elif mojom.IsMapKind(kind):
AddKind(kind.key_kind)
AddKind(kind.value_kind)
else:
name = GetFullMojomNameForKind(kind)
if name in seen_types:
return
seen_types.add(name)
typemap = _current_typemap.get(name, None)
if typemap:
used_typemaps.append(typemap)
if mojom.IsStructKind(kind) or mojom.IsUnionKind(kind):
for field in kind.fields:
AddKind(field.kind)
for kind in self.module.structs + self.module.unions:
for field in kind.fields:
AddKind(field.kind)
for interface in self.module.interfaces:
for method in interface.methods:
for parameter in method.parameters + (method.response_parameters or []):
AddKind(parameter.kind)
return used_typemaps
def GetExtraPublicHeaders(self):
all_enums = list(self.module.enums)
for struct in self.module.structs:
all_enums.extend(struct.enums)
for interface in self.module.interfaces:
all_enums.extend(interface.enums)
types = set(GetFullMojomNameForKind(typename)
for typename in
self.module.structs + all_enums + self.module.unions)
headers = set()
for typename, typemap in self.typemap.iteritems():
if typename in types:
headers.update(typemap.get("public_headers", []))
return sorted(headers)
def _GetDirectlyUsedKinds(self):
for struct in self.module.structs + self.module.unions:
for field in struct.fields:
yield field.kind
for interface in self.module.interfaces:
for method in interface.methods:
for param in method.parameters + (method.response_parameters or []):
yield param.kind
def GetJinjaExports(self):
structs = self.GetStructs()
interfaces = self.GetInterfaces()
all_enums = list(self.module.enums)
for struct in structs:
all_enums.extend(struct.enums)
for interface in interfaces:
all_enums.extend(interface.enums)
return {
"module": self.module,
"namespace": self.module.namespace,
"namespaces_as_array": NamespaceToArray(self.module.namespace),
"imports": self.module.imports,
"kinds": self.module.kinds,
"enums": self.module.enums,
"all_enums": all_enums,
"structs": structs,
"unions": self.GetUnions(),
"interfaces": interfaces,
"variant": self.variant,
"extra_traits_headers": self.GetExtraTraitsHeaders(),
"extra_public_headers": self.GetExtraPublicHeaders(),
"for_blink": self.for_blink,
"use_once_callback": self.use_once_callback,
"export_attribute": self.export_attribute,
"export_header": self.export_header,
}
@staticmethod
def GetTemplatePrefix():
return "cpp_templates"
@classmethod
def GetFilters(cls):
return cls.cpp_filters
@UseJinja("module.h.tmpl")
def GenerateModuleHeader(self):
return self.GetJinjaExports()
@UseJinja("module.cc.tmpl")
def GenerateModuleSource(self):
return self.GetJinjaExports()
@UseJinja("module-shared.h.tmpl")
def GenerateModuleSharedHeader(self):
return self.GetJinjaExports()
@UseJinja("module-shared-internal.h.tmpl")
def GenerateModuleSharedInternalHeader(self):
return self.GetJinjaExports()
@UseJinja("module-shared.cc.tmpl")
def GenerateModuleSharedSource(self):
return self.GetJinjaExports()
def GenerateFiles(self, args):
if self.generate_non_variant_code:
self.Write(self.GenerateModuleSharedHeader(),
self.MatchMojomFilePath("%s-shared.h" % self.module.name))
self.Write(
self.GenerateModuleSharedInternalHeader(),
self.MatchMojomFilePath("%s-shared-internal.h" % self.module.name))
self.Write(self.GenerateModuleSharedSource(),
self.MatchMojomFilePath("%s-shared.cc" % self.module.name))
else:
global _current_typemap
_current_typemap = self.typemap
global _for_blink
_for_blink = self.for_blink
global _use_once_callback
_use_once_callback = self.use_once_callback
global _variant
_variant = self.variant
global _export_attribute
_export_attribute = self.export_attribute
suffix = "-%s" % self.variant if self.variant else ""
self.Write(self.GenerateModuleHeader(),
self.MatchMojomFilePath("%s%s.h" % (self.module.name, suffix)))
self.Write(
self.GenerateModuleSource(),
self.MatchMojomFilePath("%s%s.cc" % (self.module.name, suffix)))