Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / mojo / public / tools / bindings / pylib / mojom / parse / translate.py
index 8407a08..77e92c5 100644 (file)
 """Translates parse tree to Mojom IR."""
 
 
-import ast
+import re
 
+from . import ast
 
-def _MapTree(func, tree, name):
+
+def _MapTreeForType(func, tree, type_to_map):
+  assert isinstance(type_to_map, type)
   if not tree:
     return []
-  return [func(subtree) for subtree in tree if subtree[0] == name]
+  return [func(subtree) for subtree in tree if isinstance(subtree, type_to_map)]
+
+_FIXED_ARRAY_REGEXP = re.compile(r'\[[0-9]+\]')
 
 def _MapKind(kind):
-  map_to_kind = { 'bool': 'b',
-                  'int8': 'i8',
-                  'int16': 'i16',
-                  'int32': 'i32',
-                  'int64': 'i64',
-                  'uint8': 'u8',
-                  'uint16': 'u16',
-                  'uint32': 'u32',
-                  'uint64': 'u64',
-                  'float': 'f',
-                  'double': 'd',
-                  'string': 's',
-                  'handle': 'h',
-                  'handle<data_pipe_consumer>': 'h:d:c',
-                  'handle<data_pipe_producer>': 'h:d:p',
-                  'handle<message_pipe>': 'h:m',
-                  'handle<shared_buffer>': 'h:s'}
+  map_to_kind = {'bool': 'b',
+                 'int8': 'i8',
+                 'int16': 'i16',
+                 'int32': 'i32',
+                 'int64': 'i64',
+                 'uint8': 'u8',
+                 'uint16': 'u16',
+                 'uint32': 'u32',
+                 'uint64': 'u64',
+                 'float': 'f',
+                 'double': 'd',
+                 'string': 's',
+                 'handle': 'h',
+                 'handle<data_pipe_consumer>': 'h:d:c',
+                 'handle<data_pipe_producer>': 'h:d:p',
+                 'handle<message_pipe>': 'h:m',
+                 'handle<shared_buffer>': 'h:s'}
+  if kind.endswith('?'):
+    base_kind = _MapKind(kind[0:-1])
+    # NOTE: This doesn't rule out enum types. Those will be detected later, when
+    # cross-reference is established.
+    reference_kinds = ('s', 'h', 'a', 'r', 'x')
+    if base_kind[0] not in reference_kinds:
+      raise Exception(
+          'A type (spec "%s") cannot be made nullable' % base_kind)
+    return '?' + base_kind
   if kind.endswith('[]'):
-    return 'a:' + _MapKind(kind[0:len(kind)-2])
+    typename = kind[0:-2]
+    if _FIXED_ARRAY_REGEXP.search(typename):
+      raise Exception('Arrays of fixed sized arrays not supported')
+    return 'a:' + _MapKind(typename)
+  if kind.endswith(']'):
+    lbracket = kind.rfind('[')
+    typename = kind[0:lbracket]
+    if typename.find('[') != -1:
+      raise Exception('Fixed sized arrays of arrays not supported')
+    return 'a' + kind[lbracket+1:-1] + ':' + _MapKind(typename)
   if kind.endswith('&'):
-    return 'r:' + _MapKind(kind[0:len(kind)-1])
+    return 'r:' + _MapKind(kind[0:-1])
   if kind in map_to_kind:
     return map_to_kind[kind]
   return 'x:' + kind
 
-def _MapAttributes(attributes):
-  if not attributes:
+def _AttributeListToDict(attribute_list):
+  if attribute_list is None:
     return {}
-  return dict([(attribute[1], attribute[2])
-               for attribute in attributes if attribute[0] == 'ATTRIBUTE'])
-
-def _GetAttribute(attributes, name):
-  out = None
-  if attributes:
-    for attribute in attributes:
-      if attribute[0] == 'ATTRIBUTE' and attribute[1] == name:
-        out = attribute[2]
-  return out
-
-def _MapField(tree):
-  assert type(tree[3]) is ast.Ordinal
-  return {'name': tree[2],
-          'kind': _MapKind(tree[1]),
-          'ordinal': tree[3].value,
-          'default': tree[4]}
-
-def _MapParameter(tree):
-  assert type(tree[3]) is ast.Ordinal
-  return {'name': tree[2],
-          'kind': _MapKind(tree[1]),
-          'ordinal': tree[3].value}
-
-def _MapMethod(tree):
-  assert type(tree[3]) is ast.Ordinal
-  method = {'name': tree[1],
-            'parameters': _MapTree(_MapParameter, tree[2], 'PARAM'),
-            'ordinal': tree[3].value}
-  if tree[4] != None:
-    method['response_parameters'] = _MapTree(_MapParameter, tree[4], 'PARAM')
-  return method
-
-def _MapEnumField(tree):
-  return {'name': tree[1],
-          'value': tree[2]}
-
-def _MapStruct(tree):
-  struct = {}
-  struct['name'] = tree[1]
-  struct['attributes'] = _MapAttributes(tree[2])
-  struct['fields'] = _MapTree(_MapField, tree[3], 'FIELD')
-  struct['enums'] = _MapTree(_MapEnum, tree[3], 'ENUM')
-  struct['constants'] = _MapTree(_MapConstant, tree[3], 'CONST')
-  return struct
-
-def _MapInterface(tree):
-  interface = {}
-  interface['name'] = tree[1]
-  interface['client'] = _GetAttribute(tree[2], 'Client')
-  interface['methods'] = _MapTree(_MapMethod, tree[3], 'METHOD')
-  interface['enums'] = _MapTree(_MapEnum, tree[3], 'ENUM')
-  interface['constants'] = _MapTree(_MapConstant, tree[3], 'CONST')
-  return interface
-
-def _MapEnum(tree):
-  enum = {}
-  enum['name'] = tree[1]
-  enum['fields'] = _MapTree(_MapEnumField, tree[2], 'ENUM_FIELD')
-  return enum
-
-def _MapConstant(tree):
-  constant = {}
-  constant['name'] = tree[2]
-  constant['kind'] = _MapKind(tree[1])
-  constant['value'] = tree[3]
-  return constant
-
-def _MapModule(tree, name):
-  mojom = {}
-  mojom['name'] = name
-  mojom['namespace'] = tree[1]
-  mojom['attributes'] = _MapAttributes(tree[2])
-  mojom['structs'] = _MapTree(_MapStruct, tree[3], 'STRUCT')
-  mojom['interfaces'] = _MapTree(_MapInterface, tree[3], 'INTERFACE')
-  mojom['enums'] = _MapTree(_MapEnum, tree[3], 'ENUM')
-  mojom['constants'] = _MapTree(_MapConstant, tree[3], 'CONST')
-  return mojom
-
-def _MapImport(tree):
-  import_item = {}
-  import_item['filename'] = tree[1]
-  return import_item
+  assert isinstance(attribute_list, ast.AttributeList)
+  # TODO(vtl): Check for duplicate keys here.
+  return dict([(attribute.key, attribute.value)
+                   for attribute in attribute_list])
+
+def _EnumToDict(enum):
+  def EnumValueToDict(enum_value):
+    assert isinstance(enum_value, ast.EnumValue)
+    return {'name': enum_value.name,
+            'value': enum_value.value}
+
+  assert isinstance(enum, ast.Enum)
+  return {'name': enum.name,
+          'fields': map(EnumValueToDict, enum.enum_value_list)}
+
+def _ConstToDict(const):
+  assert isinstance(const, ast.Const)
+  return {'name': const.name,
+          'kind': _MapKind(const.typename),
+          'value': const.value}
 
 
 class _MojomBuilder(object):
@@ -132,11 +92,67 @@ class _MojomBuilder(object):
     self.mojom = {}
 
   def Build(self, tree, name):
-    modules = [_MapModule(item, name) for item in tree if item[0] == 'MODULE']
-    if len(modules) != 1:
-      raise Exception('A mojom file must contain exactly 1 module.')
-    self.mojom = modules[0]
-    self.mojom['imports'] = _MapTree(_MapImport, tree, 'IMPORT')
+    def StructToDict(struct):
+      def StructFieldToDict(struct_field):
+        assert isinstance(struct_field, ast.StructField)
+        return {'name': struct_field.name,
+                'kind': _MapKind(struct_field.typename),
+                'ordinal': struct_field.ordinal.value \
+                    if struct_field.ordinal else None,
+                'default': struct_field.default_value}
+
+      assert isinstance(struct, ast.Struct)
+      return {'name': struct.name,
+              'attributes': _AttributeListToDict(struct.attribute_list),
+              'fields': _MapTreeForType(StructFieldToDict, struct.body,
+                                        ast.StructField),
+              'enums': _MapTreeForType(_EnumToDict, struct.body, ast.Enum),
+              'constants': _MapTreeForType(_ConstToDict, struct.body,
+                                           ast.Const)}
+
+    def InterfaceToDict(interface):
+      def MethodToDict(method):
+        def ParameterToDict(param):
+          assert isinstance(param, ast.Parameter)
+          return {'name': param.name,
+                  'kind': _MapKind(param.typename),
+                  'ordinal': param.ordinal.value if param.ordinal else None}
+
+        assert isinstance(method, ast.Method)
+        rv = {'name': method.name,
+              'parameters': map(ParameterToDict, method.parameter_list),
+              'ordinal': method.ordinal.value if method.ordinal else None}
+        if method.response_parameter_list is not None:
+          rv['response_parameters'] = map(ParameterToDict,
+                                          method.response_parameter_list)
+        return rv
+
+      assert isinstance(interface, ast.Interface)
+      attributes = _AttributeListToDict(interface.attribute_list)
+      return {'name': interface.name,
+              'attributes': attributes,
+              'client': attributes.get('Client'),
+              'methods': _MapTreeForType(MethodToDict, interface.body,
+                                         ast.Method),
+              'enums': _MapTreeForType(_EnumToDict, interface.body, ast.Enum),
+              'constants': _MapTreeForType(_ConstToDict, interface.body,
+                                           ast.Const)}
+
+    assert isinstance(tree, ast.Mojom)
+    self.mojom['name'] = name
+    self.mojom['namespace'] = tree.module.name[1] if tree.module else ''
+    self.mojom['imports'] = \
+        [{'filename': imp.import_filename} for imp in tree.import_list]
+    self.mojom['attributes'] = \
+        _AttributeListToDict(tree.module.attribute_list) if tree.module else {}
+    self.mojom['structs'] = \
+        _MapTreeForType(StructToDict, tree.definition_list, ast.Struct)
+    self.mojom['interfaces'] = \
+        _MapTreeForType(InterfaceToDict, tree.definition_list, ast.Interface)
+    self.mojom['enums'] = \
+        _MapTreeForType(_EnumToDict, tree.definition_list, ast.Enum)
+    self.mojom['constants'] = \
+        _MapTreeForType(_ConstToDict, tree.definition_list, ast.Const)
     return self.mojom