• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2013 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Code shared by the various language-specific code generators."""
6
7from functools import partial
8import os.path
9import re
10
11import module as mojom
12import mojom.fileutil as fileutil
13import pack
14
15def ExpectedArraySize(kind):
16  if mojom.IsArrayKind(kind):
17    return kind.length
18  return None
19
20def StudlyCapsToCamel(studly):
21  return studly[0].lower() + studly[1:]
22
23def UnderToCamel(under):
24  """Converts underscore_separated strings to CamelCase strings."""
25  return ''.join(word.capitalize() for word in under.split('_'))
26
27def WriteFile(contents, full_path):
28  # Make sure the containing directory exists.
29  full_dir = os.path.dirname(full_path)
30  fileutil.EnsureDirectoryExists(full_dir)
31
32  # Dump the data to disk.
33  with open(full_path, "w+") as f:
34    f.write(contents)
35
36class Generator(object):
37  # Pass |output_dir| to emit files to disk. Omit |output_dir| to echo all
38  # files to stdout.
39  def __init__(self, module, output_dir=None, typemap=None, variant=None,
40               bytecode_path=None, for_blink=False,
41               use_new_wrapper_types=False):
42    self.module = module
43    self.output_dir = output_dir
44    self.typemap = typemap or {}
45    self.variant = variant
46    self.bytecode_path = bytecode_path
47    self.for_blink = for_blink
48    self.use_new_wrapper_types = use_new_wrapper_types
49
50  def GetStructsFromMethods(self):
51    result = []
52    for interface in self.module.interfaces:
53      for method in interface.methods:
54        result.append(self._GetStructFromMethod(method))
55        if method.response_parameters != None:
56          result.append(self._GetResponseStructFromMethod(method))
57    return result
58
59  def GetStructs(self):
60    return map(partial(self._AddStructComputedData, True), self.module.structs)
61
62  def GetUnions(self):
63    return map(self._AddUnionComputedData, self.module.unions)
64
65  def GetInterfaces(self):
66    return map(self._AddInterfaceComputedData, self.module.interfaces)
67
68  # Prepend the filename with a directory that matches the directory of the
69  # original .mojom file, relative to the import root.
70  def MatchMojomFilePath(self, filename):
71    return os.path.join(os.path.dirname(self.module.path), filename)
72
73  def Write(self, contents, filename):
74    if self.output_dir is None:
75      print contents
76      return
77    full_path = os.path.join(self.output_dir, filename)
78    WriteFile(contents, full_path)
79
80  def GenerateFiles(self, args):
81    raise NotImplementedError("Subclasses must override/implement this method")
82
83  def GetJinjaParameters(self):
84    """Returns default constructor parameters for the jinja environment."""
85    return {}
86
87  def GetGlobals(self):
88    """Returns global mappings for the template generation."""
89    return {}
90
91  def _AddStructComputedData(self, exported, struct):
92    """Adds computed data to the given struct. The data is computed once and
93    used repeatedly in the generation process."""
94    struct.packed = pack.PackedStruct(struct)
95    struct.bytes = pack.GetByteLayout(struct.packed)
96    struct.versions = pack.GetVersionInfo(struct.packed)
97    struct.exported = exported
98    return struct
99
100  def _AddUnionComputedData(self, union):
101    """Adds computed data to the given union. The data is computed once and
102    used repeatedly in the generation process."""
103    ordinal = 0
104    for field in union.fields:
105      if field.ordinal is not None:
106        ordinal = field.ordinal
107      field.ordinal = ordinal
108      ordinal += 1
109    return union
110
111  def _AddInterfaceComputedData(self, interface):
112    """Adds computed data to the given interface. The data is computed once and
113    used repeatedly in the generation process."""
114    interface.version = 0
115    for method in interface.methods:
116      if method.min_version is not None:
117        interface.version = max(interface.version, method.min_version)
118
119      method.param_struct = self._GetStructFromMethod(method)
120      interface.version = max(interface.version,
121                              method.param_struct.versions[-1].version)
122
123      if method.response_parameters is not None:
124        method.response_param_struct = self._GetResponseStructFromMethod(method)
125        interface.version = max(
126            interface.version,
127            method.response_param_struct.versions[-1].version)
128      else:
129        method.response_param_struct = None
130    return interface
131
132  def _GetStructFromMethod(self, method):
133    """Converts a method's parameters into the fields of a struct."""
134    params_class = "%s_%s_Params" % (method.interface.name, method.name)
135    struct = mojom.Struct(params_class, module=method.interface.module)
136    for param in method.parameters:
137      struct.AddField(param.name, param.kind, param.ordinal,
138                      attributes=param.attributes)
139    return self._AddStructComputedData(False, struct)
140
141  def _GetResponseStructFromMethod(self, method):
142    """Converts a method's response_parameters into the fields of a struct."""
143    params_class = "%s_%s_ResponseParams" % (method.interface.name, method.name)
144    struct = mojom.Struct(params_class, module=method.interface.module)
145    for param in method.response_parameters:
146      struct.AddField(param.name, param.kind, param.ordinal,
147                      attributes=param.attributes)
148    return self._AddStructComputedData(False, struct)
149