Home | History | Annotate | Download | only in generators
      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 """Generates JavaScript source files from a mojom.Module."""
      6 
      7 import mojom.generate.generator as generator
      8 import mojom.generate.module as mojom
      9 import mojom.generate.pack as pack
     10 from mojom.generate.template_expander import UseJinja
     11 
     12 _kind_to_javascript_default_value = {
     13   mojom.BOOL:         "false",
     14   mojom.INT8:         "0",
     15   mojom.UINT8:        "0",
     16   mojom.INT16:        "0",
     17   mojom.UINT16:       "0",
     18   mojom.INT32:        "0",
     19   mojom.UINT32:       "0",
     20   mojom.FLOAT:        "0",
     21   mojom.HANDLE:       "null",
     22   mojom.DCPIPE:       "null",
     23   mojom.DPPIPE:       "null",
     24   mojom.MSGPIPE:      "null",
     25   mojom.SHAREDBUFFER: "null",
     26   mojom.INT64:        "0",
     27   mojom.UINT64:       "0",
     28   mojom.DOUBLE:       "0",
     29   mojom.STRING:       '""',
     30 }
     31 
     32 
     33 def JavaScriptDefaultValue(field):
     34   if field.default:
     35     if isinstance(field.kind, mojom.Struct):
     36       assert field.default == "default"
     37       return "new %s()" % JavascriptType(field.kind)
     38     return ExpressionToText(field.default)
     39   if field.kind in mojom.PRIMITIVES:
     40     return _kind_to_javascript_default_value[field.kind]
     41   if isinstance(field.kind, mojom.Struct):
     42     return "null"
     43   if isinstance(field.kind, mojom.Array):
     44     return "[]"
     45   if isinstance(field.kind, mojom.Interface) or \
     46      isinstance(field.kind, mojom.InterfaceRequest):
     47     return _kind_to_javascript_default_value[mojom.MSGPIPE]
     48   if isinstance(field.kind, mojom.Enum):
     49     return "0"
     50 
     51 
     52 def JavaScriptPayloadSize(packed):
     53   packed_fields = packed.packed_fields
     54   if not packed_fields:
     55     return 0
     56   last_field = packed_fields[-1]
     57   offset = last_field.offset + last_field.size
     58   pad = pack.GetPad(offset, 8)
     59   return offset + pad
     60 
     61 
     62 _kind_to_codec_type = {
     63   mojom.BOOL:         "codec.Uint8",
     64   mojom.INT8:         "codec.Int8",
     65   mojom.UINT8:        "codec.Uint8",
     66   mojom.INT16:        "codec.Int16",
     67   mojom.UINT16:       "codec.Uint16",
     68   mojom.INT32:        "codec.Int32",
     69   mojom.UINT32:       "codec.Uint32",
     70   mojom.FLOAT:        "codec.Float",
     71   mojom.HANDLE:       "codec.Handle",
     72   mojom.DCPIPE:       "codec.Handle",
     73   mojom.DPPIPE:       "codec.Handle",
     74   mojom.MSGPIPE:      "codec.Handle",
     75   mojom.SHAREDBUFFER: "codec.Handle",
     76   mojom.INT64:        "codec.Int64",
     77   mojom.UINT64:       "codec.Uint64",
     78   mojom.DOUBLE:       "codec.Double",
     79   mojom.STRING:       "codec.String",
     80 }
     81 
     82 
     83 def CodecType(kind):
     84   if kind in mojom.PRIMITIVES:
     85     return _kind_to_codec_type[kind]
     86   if isinstance(kind, mojom.Struct):
     87     return "new codec.PointerTo(%s)" % CodecType(kind.name)
     88   if isinstance(kind, mojom.Array):
     89     return "new codec.ArrayOf(%s)" % CodecType(kind.kind)
     90   if isinstance(kind, mojom.Interface) or \
     91      isinstance(kind, mojom.InterfaceRequest):
     92     return CodecType(mojom.MSGPIPE)
     93   if isinstance(kind, mojom.Enum):
     94     return _kind_to_codec_type[mojom.INT32]
     95   return kind
     96 
     97 
     98 def JavaScriptDecodeSnippet(kind):
     99   if kind in mojom.PRIMITIVES:
    100     return "decodeStruct(%s)" % CodecType(kind)
    101   if isinstance(kind, mojom.Struct):
    102     return "decodeStructPointer(%s)" % CodecType(kind.name)
    103   if isinstance(kind, mojom.Array):
    104     return "decodeArrayPointer(%s)" % CodecType(kind.kind)
    105   if isinstance(kind, mojom.Interface) or \
    106      isinstance(kind, mojom.InterfaceRequest):
    107     return JavaScriptDecodeSnippet(mojom.MSGPIPE)
    108   if isinstance(kind, mojom.Enum):
    109     return JavaScriptDecodeSnippet(mojom.INT32)
    110 
    111 
    112 def JavaScriptEncodeSnippet(kind):
    113   if kind in mojom.PRIMITIVES:
    114     return "encodeStruct(%s, " % CodecType(kind)
    115   if isinstance(kind, mojom.Struct):
    116     return "encodeStructPointer(%s, " % CodecType(kind.name)
    117   if isinstance(kind, mojom.Array):
    118     return "encodeArrayPointer(%s, " % CodecType(kind.kind)
    119   if isinstance(kind, mojom.Interface) or \
    120      isinstance(kind, mojom.InterfaceRequest):
    121     return JavaScriptEncodeSnippet(mojom.MSGPIPE)
    122   if isinstance(kind, mojom.Enum):
    123     return JavaScriptEncodeSnippet(mojom.INT32)
    124 
    125 
    126 def TranslateConstants(token):
    127   if isinstance(token, (mojom.EnumValue, mojom.NamedValue)):
    128     # Both variable and enum constants are constructed like:
    129     # NamespaceUid.Struct[.Enum].CONSTANT_NAME
    130     name = []
    131     if token.imported_from:
    132       name.append(token.imported_from["unique_name"])
    133     if token.parent_kind:
    134       name.append(token.parent_kind.name)
    135     if isinstance(token, mojom.EnumValue):
    136       name.append(token.enum_name)
    137     name.append(token.name)
    138     return ".".join(name)
    139   return token
    140 
    141 
    142 def ExpressionToText(value):
    143   return TranslateConstants(value)
    144 
    145 
    146 def JavascriptType(kind):
    147   if kind.imported_from:
    148     return kind.imported_from["unique_name"] + "." + kind.name
    149   return kind.name
    150 
    151 
    152 class Generator(generator.Generator):
    153 
    154   js_filters = {
    155     "default_value": JavaScriptDefaultValue,
    156     "payload_size": JavaScriptPayloadSize,
    157     "decode_snippet": JavaScriptDecodeSnippet,
    158     "encode_snippet": JavaScriptEncodeSnippet,
    159     "expression_to_text": ExpressionToText,
    160     "js_type": JavascriptType,
    161     "stylize_method": generator.StudlyCapsToCamel,
    162   }
    163 
    164   @UseJinja("js_templates/module.js.tmpl", filters=js_filters)
    165   def GenerateJsModule(self):
    166     return {
    167       "namespace": self.module.namespace,
    168       "imports": self.GetImports(),
    169       "kinds": self.module.kinds,
    170       "enums": self.module.enums,
    171       "module": self.module,
    172       "structs": self.GetStructs() + self.GetStructsFromMethods(),
    173       "interfaces": self.module.interfaces,
    174     }
    175 
    176   def GenerateFiles(self, args):
    177     self.Write(self.GenerateJsModule(), "%s.js" % self.module.name)
    178 
    179   def GetImports(self):
    180     # Since each import is assigned a variable in JS, they need to have unique
    181     # names.
    182     counter = 1
    183     for each in self.module.imports:
    184       each["unique_name"] = "import" + str(counter)
    185       counter += 1
    186     return self.module.imports
    187