Chromium Code Reviews| Index: mojo/public/tools/bindings/generators/mojom_go_generator.py |
| diff --git a/mojo/public/tools/bindings/generators/mojom_go_generator.py b/mojo/public/tools/bindings/generators/mojom_go_generator.py |
| index 7b1c7ac8920cce3fc3d6ca2834880a4a8f1aa672..582ff4535509cb82644cd2e0ffbc764aa71faaf0 100644 |
| --- a/mojo/public/tools/bindings/generators/mojom_go_generator.py |
| +++ b/mojo/public/tools/bindings/generators/mojom_go_generator.py |
| @@ -5,6 +5,7 @@ |
| '''Generates Go source files from a mojom.Module.''' |
| from itertools import chain |
| +import base64 |
|
azani
2015/10/19 18:27:02
unused?
alexfandrianto
2015/10/19 21:36:30
Done. Yes, it was unused. I was using it earlier f
|
| import os |
| import re |
| @@ -57,8 +58,20 @@ _kind_infos = { |
| mojom.NULLABLE_STRING: KindInfo('string', 'String', 'String', 64), |
| } |
| +# _imports keeps track of the imports that the .go.mojom file needs to import. |
| _imports = {} |
| +# _mojom_imports keeps a list of the other .mojom files imported by this one. |
| +_mojom_imports = {} |
| + |
| +# The mojom_types.mojom and service_describer.mojom files are special because |
| +# they are used to generate mojom Type's and ServiceDescription implementations. |
| +_service_describer_pkg_short = "service_describer" |
| +_service_describer_pkg = "mojo/public/interfaces/bindings/%s" % \ |
| + _service_describer_pkg_short |
| +_mojom_types_pkg_short = "mojom_types" |
| +_mojom_types_pkg = "mojo/public/interfaces/bindings/%s" % _mojom_types_pkg_short |
| + |
| def GetBitSize(kind): |
| if isinstance(kind, (mojom.Union)): |
| return 128 |
| @@ -186,18 +199,72 @@ def EncodeSuffix(kind): |
| return EncodeSuffix(mojom.MSGPIPE) |
| return _kind_infos[kind].encode_suffix |
| +# This helper assists in the production of mojom_types.Type for simple kinds. |
| +# See _kind_infos above. |
| +def GetMojomTypeValue(kind, typepkg=''): |
| + if not kind in _kind_infos: |
| + return '' |
| + if kind == mojom.BOOL: |
| + return '%sTypeSimpleType{%sSimpleType_Bool}' % (typepkg, typepkg) |
|
azani
2015/10/19 18:27:02
There is a lot of repetition in those strings. You
alexfandrianto
2015/10/19 21:36:30
It's a bit smaller now. Unfortunately, I had to ha
|
| + elif kind == mojom.INT8: |
| + return '%sTypeSimpleType{%sSimpleType_InT8}' % (typepkg, typepkg) |
| + elif kind == mojom.UINT8: |
| + return '%sTypeSimpleType{%sSimpleType_UinT8}' % (typepkg, typepkg) |
| + elif kind == mojom.INT16: |
| + return '%sTypeSimpleType{%sSimpleType_InT16}' % (typepkg, typepkg) |
| + elif kind == mojom.UINT16: |
| + return '%sTypeSimpleType{%sSimpleType_UinT16}' % (typepkg, typepkg) |
| + elif kind == mojom.INT32: |
| + return '%sTypeSimpleType{%sSimpleType_InT32}' % (typepkg, typepkg) |
| + elif kind == mojom.UINT32: |
| + return '%sTypeSimpleType{%sSimpleType_UinT32}' % (typepkg, typepkg) |
| + elif kind == mojom.INT64: |
| + return '%sTypeSimpleType{%sSimpleType_InT64}' % (typepkg, typepkg) |
|
azani
2015/10/19 18:27:02
I could be wrong, but InT64 does not look right to
alexfandrianto
2015/10/19 21:36:30
It looks weird to me too. It's an artifact of send
|
| + elif kind == mojom.UINT64: |
| + return '%sTypeSimpleType{%sSimpleType_UinT64}' % (typepkg, typepkg) |
| + elif kind == mojom.FLOAT: |
| + return '%sTypeSimpleType{%sSimpleType_Float}' % (typepkg, typepkg) |
| + elif kind == mojom.DOUBLE: |
| + return '%sTypeSimpleType{%sSimpleType_Double}' % (typepkg, typepkg) |
| + elif kind == mojom.HANDLE: |
| + return '%sTypeHandleType{%sHandleType{Nullable: false, Kind: %sHandleType_Kind_Unspecified}}' % (typepkg, typepkg, typepkg) |
| + elif kind == mojom.DCPIPE: |
| + return '%sTypeHandleType{%sHandleType{Nullable: false, Kind: %sHandleType_Kind_DataPipeConsumer}}' % (typepkg, typepkg, typepkg) |
| + elif kind == mojom.DPPIPE: |
| + return '%sTypeHandleType{%sHandleType{Nullable: false, Kind: %sHandleType_Kind_DataPipeProducer}}' % (typepkg, typepkg, typepkg) |
| + elif kind == mojom.MSGPIPE: |
| + return '%sTypeHandleType{%sHandleType{Nullable: false, Kind: %sHandleType_Kind_MessagePipe}}' % (typepkg, typepkg, typepkg) |
| + elif kind == mojom.SHAREDBUFFER: |
| + return '%sTypeHandleType{%sHandleType{Nullable: false, Kind: %sHandleType_Kind_SharedBuffer}}' % (typepkg, typepkg, typepkg) |
| + elif kind == mojom.NULLABLE_HANDLE: |
| + return '%sTypeHandleType{%sHandleType{Nullable: true, Kind: %sHandleType_Kind_Unspecified}}' % (typepkg, typepkg, typepkg) |
| + elif kind == mojom.NULLABLE_DCPIPE: |
| + return '%sTypeHandleType{%sHandleType{Nullable: true, Kind: %sHandleType_Kind_DataPipeConsumer}}' % (typepkg, typepkg, typepkg) |
| + elif kind == mojom.NULLABLE_DPPIPE: |
| + return '%sTypeHandleType{%sHandleType{Nullable: true, Kind: %sHandleType_Kind_DataPipeProducer}}' % (typepkg, typepkg, typepkg) |
| + elif kind == mojom.NULLABLE_MSGPIPE: |
| + return '%sTypeHandleType{%sHandleType{Nullable: true, Kind: %sHandleType_Kind_MessagePipe}}' % (typepkg, typepkg, typepkg) |
| + elif kind == mojom.NULLABLE_SHAREDBUFFER: |
| + return '%sTypeHandleType{%sHandleType{Nullable: true, Kind: %sHandleType_Kind_SharedBuffer}}' % (typepkg, typepkg, typepkg) |
| + elif kind == mojom.STRING: |
| + return '%sTypeStringType{%sStringType{false}}' % (typepkg, typepkg) |
| + elif kind == mojom.NULLABLE_STRING: |
| + return '%sTypeStringType{%sStringType{true}}' % (typepkg, typepkg) |
| + else: |
| + raise Exception('Missing case for kind: %s' % kind) |
| + |
| def GetPackageName(module): |
| return module.name.split('.')[0] |
| -def GetPackageNameForElement(element): |
| +def GetPackageNameForElement(element, default=''): |
|
azani
2015/10/19 18:27:02
It looks like the default logic is only used when
alexfandrianto
2015/10/19 21:36:30
Done.
|
| if not hasattr(element, 'imported_from') or not element.imported_from: |
| - return '' |
| + return default |
| path = '' |
| if element.imported_from['module'].path: |
| path += GetPackagePath(element.imported_from['module']) |
| if path in _imports: |
| return _imports[path] |
| - return '' |
| + return default |
| def GetQualifiedName(name, package=None, exported=True): |
| if not package: |
| @@ -220,6 +287,7 @@ def GetAllEnums(module): |
| # Adds an import required to use the provided |element|. |
| # The required import is stored at '_imports'. |
| +# The mojom imports are also stored separately in '_mojom_imports'. |
| def AddImport(module, element): |
| if not isinstance(element, mojom.Kind): |
| return |
| @@ -244,10 +312,39 @@ def AddImport(module, element): |
| if path in _imports: |
| return |
| name = GetPackageName(imported['module']) |
| - while name in _imports.values(): |
| + while name in _imports.values(): # This avoids repeated names. |
| name += '_' |
| _imports[path] = name |
| + _mojom_imports[path] = name |
| + |
| +# The identifier cache is used by the Type generator to determine if a type has |
| +# already been generated or not. This prevents over-generation of the same type |
| +# when it is referred to in multiple ways. |
| +identifier_cache = {} |
| +def GetIdentifier(kind, default): |
| + package = GetPackageNameForElement(kind, default) |
|
azani
2015/10/19 18:27:02
I think what you are looking for that you pass in
alexfandrianto
2015/10/19 21:36:30
Changed a little bit. Unfortunately, kind.module d
azani
2015/10/19 21:43:07
I would expect that kind.module would exist for al
|
| + |
| + # Most kinds have a name, but those that don't should rely on their spec. |
| + # Since spec can have : and ? characters, these must be replaced. Since ? is |
| + # replaced with '', the caller must keep track of optionality on its own. |
| + package_unique = (kind.name if hasattr(kind, 'name') else kind.spec).replace(':', '_').replace('?', '') |
| + return '%s_%s' % (package, package_unique) |
| + |
| +def StoreIdentifier(identifier, cache_name): |
| + if not cache_name in identifier_cache: |
| + identifier_cache[cache_name] = {} |
| + identifier_cache[cache_name][identifier] = True |
| + return '' |
| + |
| +def CheckIdentifier(identifier, cache_name): |
| + if not cache_name in identifier_cache: |
| + identifier_cache[cache_name] = {} |
| + return identifier in identifier_cache[cache_name] |
| +# Get the mojom type's identifier suffix. |
| +def GetMojomTypeIdentifier(kind, default): |
| + # Since this should be unique, it is based on the type's identifier. |
| + return "%s__" % GetIdentifier(kind, default) |
| class Generator(generator.Generator): |
| go_filters = { |
| @@ -258,6 +355,9 @@ class Generator(generator.Generator): |
| 'go_type': GetGoType, |
| 'expression_to_text': ExpressionToText, |
| 'has_response': lambda method: method.response_parameters is not None, |
| + 'identifier': GetIdentifier, |
| + 'identifier_check': CheckIdentifier, |
| + 'identifier_store': StoreIdentifier, |
| 'is_array': mojom.IsArrayKind, |
| 'is_enum': mojom.IsEnumKind, |
| 'is_handle': mojom.IsAnyHandleKind, |
| @@ -271,6 +371,8 @@ class Generator(generator.Generator): |
| 'is_struct': mojom.IsStructKind, |
| 'is_union': mojom.IsUnionKind, |
| 'qualified': GetQualifiedName, |
| + 'mojom_type': GetMojomTypeValue, |
| + 'mojom_type_identifier': GetMojomTypeIdentifier, |
| 'name': GetNameForElement, |
| 'unqualified_name': GetUnqualifiedNameForElement, |
| 'package': GetPackageNameForElement, |
| @@ -278,13 +380,17 @@ class Generator(generator.Generator): |
| } |
| def GetParameters(self): |
| + package = GetPackageName(self.module) |
| return { |
| 'enums': GetAllEnums(self.module), |
| - 'imports': self.GetImports(), |
| + 'imports': self.GetImports()[0], |
| 'interfaces': self.GetInterfaces(), |
| - 'package': GetPackageName(self.module), |
| + 'mojom_imports': self.GetMojomImports(), |
| + 'package': package, |
| 'structs': self.GetStructs(), |
| - 'unions': self.GetUnions(), |
| + 'descpkg': '%s.' % _service_describer_pkg_short if package != _service_describer_pkg_short else '', |
| + 'typepkg': '%s.' % _mojom_types_pkg_short if package != _mojom_types_pkg_short else '', |
| + 'unions': self.GetUnions() |
| } |
| @UseJinja('go_templates/source.tmpl', filters=go_filters) |
| @@ -308,8 +414,11 @@ class Generator(generator.Generator): |
| } |
| # Scans |self.module| for elements that require imports and adds all found |
| - # imports to '_imports' dict. Returns a list of imports that should include |
| - # the generated go file. |
| + # imports to '_imports' dict. Mojom imports are stored in the '_mojom_imports' |
| + # dict. This operation is idempotent. |
| + # Returns a tuple: |
| + # - list of imports that should include the generated go file |
| + # - the dictionary of _mojom_imports |
| def GetImports(self): |
| # Imports can only be used in structs, constants, enums, interfaces. |
| all_structs = list(self.module.structs) |
| @@ -344,6 +453,17 @@ class Generator(generator.Generator): |
| if field.value: |
| AddImport(self.module, field.value) |
| + num_user_defined_types = len(self.module.interfaces) + \ |
| + len(self.module.unions) + len(all_structs) + len(GetAllEnums(self.module)) |
| + if num_user_defined_types > 0 \ |
| + and GetPackageName(self.module) != _mojom_types_pkg_short: |
| + _imports[_mojom_types_pkg] = _mojom_types_pkg_short |
| + |
| + if len(self.module.interfaces) > 0 \ |
| + and GetPackageName(self.module) != _mojom_types_pkg_short \ |
| + and GetPackageName(self.module) != _service_describer_pkg_short: |
| + _imports[_service_describer_pkg] = _service_describer_pkg_short |
| + |
| # TODO(rogulenko): add these after generating constants and struct defaults. |
| # for constant in GetAllConstants(self.module): |
| # AddImport(self.module, constant.value) |
| @@ -354,7 +474,11 @@ class Generator(generator.Generator): |
| imports_list.append('"%s"' % i) |
| else: |
| imports_list.append('%s "%s"' % (_imports[i], i)) |
| - return sorted(imports_list) |
| + return sorted(imports_list), _mojom_imports |
| + |
| + def GetMojomImports(self): |
| + # GetImports (idempotent) prepares the _imports and _mojom_imports maps. |
| + return self.GetImports()[1] |
| # Overrides the implementation from the base class in order to customize the |
| # struct and field names. |