| OLD | NEW |
| (Empty) |
| 1 # Copyright 2014 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 dart source files from a mojom.Module.""" | |
| 6 | |
| 7 import errno | |
| 8 import os | |
| 9 import re | |
| 10 import shutil | |
| 11 import sys | |
| 12 | |
| 13 import mojom.fileutil as fileutil | |
| 14 import mojom.generate.constant_resolver as resolver | |
| 15 import mojom.generate.generator as generator | |
| 16 import mojom.generate.module as mojom | |
| 17 import mojom.generate.pack as pack | |
| 18 from mojom.generate.template_expander import UseJinja | |
| 19 | |
| 20 GENERATOR_PREFIX = 'dart' | |
| 21 | |
| 22 # CAUTION: To generate Dart-style names, and to avoid generating reserved words | |
| 23 # for identifiers, the template files should generate names using | |
| 24 # {{element|name}}, not {{element.name}}. | |
| 25 | |
| 26 # Dart reserved words from: | |
| 27 # http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-408.pdf | |
| 28 # We must not generate reserved words for identifiers. | |
| 29 # NB: async, await, and yield are not technically reserved words, but since | |
| 30 # they are not valid identifiers in all contexts, we include them here as well. | |
| 31 _dart_reserved_words = [ | |
| 32 "assert", | |
| 33 "async", | |
| 34 "await", | |
| 35 "break", | |
| 36 "case", | |
| 37 "catch", | |
| 38 "class", | |
| 39 "const", | |
| 40 "continue", | |
| 41 "default", | |
| 42 "do", | |
| 43 "else", | |
| 44 "enum", | |
| 45 "extends", | |
| 46 "false", | |
| 47 "final", | |
| 48 "finally", | |
| 49 "for", | |
| 50 "if", | |
| 51 "in", | |
| 52 "is", | |
| 53 "new", | |
| 54 "null", | |
| 55 "rethrow", | |
| 56 "return", | |
| 57 "super", | |
| 58 "switch", | |
| 59 "this", | |
| 60 "throw", | |
| 61 "true", | |
| 62 "try", | |
| 63 "var", | |
| 64 "void", | |
| 65 "while", | |
| 66 "with", | |
| 67 "yield", | |
| 68 ] | |
| 69 | |
| 70 # These names are the class fields and methods of the Proxy class in | |
| 71 # lib/src/proxy.dart of Dart's mojo package. If these names appear in a .mojom | |
| 72 # they must be mangled to avoid name conflicts. They are mangled by appending | |
| 73 # an underscore ('_'), which is banned on names in mojom interfaces. | |
| 74 _reserved_words = _dart_reserved_words + [ | |
| 75 "close", | |
| 76 "connectToService", | |
| 77 "ctrl", | |
| 78 "fromEndpoint", | |
| 79 "fromHandle", | |
| 80 "fromMock", | |
| 81 "impl", | |
| 82 "newFromEndpoint", | |
| 83 "responseOrError", | |
| 84 "serviceDescription", | |
| 85 "serviceName", | |
| 86 "unbound", | |
| 87 ] | |
| 88 | |
| 89 _kind_to_dart_default_value = { | |
| 90 mojom.BOOL: "false", | |
| 91 mojom.INT8: "0", | |
| 92 mojom.UINT8: "0", | |
| 93 mojom.INT16: "0", | |
| 94 mojom.UINT16: "0", | |
| 95 mojom.INT32: "0", | |
| 96 mojom.UINT32: "0", | |
| 97 mojom.FLOAT: "0.0", | |
| 98 mojom.HANDLE: "null", | |
| 99 mojom.DCPIPE: "null", | |
| 100 mojom.DPPIPE: "null", | |
| 101 mojom.MSGPIPE: "null", | |
| 102 mojom.SHAREDBUFFER: "null", | |
| 103 mojom.NULLABLE_HANDLE: "null", | |
| 104 mojom.NULLABLE_DCPIPE: "null", | |
| 105 mojom.NULLABLE_DPPIPE: "null", | |
| 106 mojom.NULLABLE_MSGPIPE: "null", | |
| 107 mojom.NULLABLE_SHAREDBUFFER: "null", | |
| 108 mojom.INT64: "0", | |
| 109 mojom.UINT64: "0", | |
| 110 mojom.DOUBLE: "0.0", | |
| 111 mojom.STRING: "null", | |
| 112 mojom.NULLABLE_STRING: "null" | |
| 113 } | |
| 114 | |
| 115 _kind_to_dart_decl_type = { | |
| 116 mojom.BOOL: "bool", | |
| 117 mojom.INT8: "int", | |
| 118 mojom.UINT8: "int", | |
| 119 mojom.INT16: "int", | |
| 120 mojom.UINT16: "int", | |
| 121 mojom.INT32: "int", | |
| 122 mojom.UINT32: "int", | |
| 123 mojom.FLOAT: "double", | |
| 124 mojom.HANDLE: "core.MojoHandle", | |
| 125 mojom.DCPIPE: "core.MojoDataPipeConsumer", | |
| 126 mojom.DPPIPE: "core.MojoDataPipeProducer", | |
| 127 mojom.MSGPIPE: "core.MojoMessagePipeEndpoint", | |
| 128 mojom.SHAREDBUFFER: "core.MojoSharedBuffer", | |
| 129 mojom.NULLABLE_HANDLE: "core.MojoHandle", | |
| 130 mojom.NULLABLE_DCPIPE: "core.MojoDataPipeConsumer", | |
| 131 mojom.NULLABLE_DPPIPE: "core.MojoDataPipeProducer", | |
| 132 mojom.NULLABLE_MSGPIPE: "core.MojoMessagePipeEndpoint", | |
| 133 mojom.NULLABLE_SHAREDBUFFER: "core.MojoSharedBuffer", | |
| 134 mojom.INT64: "int", | |
| 135 mojom.UINT64: "int", | |
| 136 mojom.DOUBLE: "double", | |
| 137 mojom.STRING: "String", | |
| 138 mojom.NULLABLE_STRING: "String" | |
| 139 } | |
| 140 | |
| 141 _spec_to_decode_method = { | |
| 142 mojom.BOOL.spec: 'decodeBool', | |
| 143 mojom.DCPIPE.spec: 'decodeConsumerHandle', | |
| 144 mojom.DOUBLE.spec: 'decodeDouble', | |
| 145 mojom.DPPIPE.spec: 'decodeProducerHandle', | |
| 146 mojom.FLOAT.spec: 'decodeFloat', | |
| 147 mojom.HANDLE.spec: 'decodeHandle', | |
| 148 mojom.INT16.spec: 'decodeInt16', | |
| 149 mojom.INT32.spec: 'decodeInt32', | |
| 150 mojom.INT64.spec: 'decodeInt64', | |
| 151 mojom.INT8.spec: 'decodeInt8', | |
| 152 mojom.MSGPIPE.spec: 'decodeMessagePipeHandle', | |
| 153 mojom.NULLABLE_DCPIPE.spec: 'decodeConsumerHandle', | |
| 154 mojom.NULLABLE_DPPIPE.spec: 'decodeProducerHandle', | |
| 155 mojom.NULLABLE_HANDLE.spec: 'decodeHandle', | |
| 156 mojom.NULLABLE_MSGPIPE.spec: 'decodeMessagePipeHandle', | |
| 157 mojom.NULLABLE_SHAREDBUFFER.spec: 'decodeSharedBufferHandle', | |
| 158 mojom.NULLABLE_STRING.spec: 'decodeString', | |
| 159 mojom.SHAREDBUFFER.spec: 'decodeSharedBufferHandle', | |
| 160 mojom.STRING.spec: 'decodeString', | |
| 161 mojom.UINT16.spec: 'decodeUint16', | |
| 162 mojom.UINT32.spec: 'decodeUint32', | |
| 163 mojom.UINT64.spec: 'decodeUint64', | |
| 164 mojom.UINT8.spec: 'decodeUint8', | |
| 165 } | |
| 166 | |
| 167 _spec_to_encode_method = { | |
| 168 mojom.BOOL.spec: 'encodeBool', | |
| 169 mojom.DCPIPE.spec: 'encodeConsumerHandle', | |
| 170 mojom.DOUBLE.spec: 'encodeDouble', | |
| 171 mojom.DPPIPE.spec: 'encodeProducerHandle', | |
| 172 mojom.FLOAT.spec: 'encodeFloat', | |
| 173 mojom.HANDLE.spec: 'encodeHandle', | |
| 174 mojom.INT16.spec: 'encodeInt16', | |
| 175 mojom.INT32.spec: 'encodeInt32', | |
| 176 mojom.INT64.spec: 'encodeInt64', | |
| 177 mojom.INT8.spec: 'encodeInt8', | |
| 178 mojom.MSGPIPE.spec: 'encodeMessagePipeHandle', | |
| 179 mojom.NULLABLE_DCPIPE.spec: 'encodeConsumerHandle', | |
| 180 mojom.NULLABLE_DPPIPE.spec: 'encodeProducerHandle', | |
| 181 mojom.NULLABLE_HANDLE.spec: 'encodeHandle', | |
| 182 mojom.NULLABLE_MSGPIPE.spec: 'encodeMessagePipeHandle', | |
| 183 mojom.NULLABLE_SHAREDBUFFER.spec: 'encodeSharedBufferHandle', | |
| 184 mojom.NULLABLE_STRING.spec: 'encodeString', | |
| 185 mojom.SHAREDBUFFER.spec: 'encodeSharedBufferHandle', | |
| 186 mojom.STRING.spec: 'encodeString', | |
| 187 mojom.UINT16.spec: 'encodeUint16', | |
| 188 mojom.UINT32.spec: 'encodeUint32', | |
| 189 mojom.UINT64.spec: 'encodeUint64', | |
| 190 mojom.UINT8.spec: 'encodeUint8', | |
| 191 } | |
| 192 | |
| 193 # The mojom_types.mojom and service_describer.mojom files are special because | |
| 194 # they are used to generate mojom Type's and ServiceDescription implementations. | |
| 195 # They need to be imported, unless the file itself is being generated. | |
| 196 _service_describer_pkg_short = "service_describer" | |
| 197 _service_describer_pkg = "package:mojo/mojo/bindings/types/%s.mojom.dart" % \ | |
| 198 _service_describer_pkg_short | |
| 199 _mojom_types_pkg_short = "mojom_types" | |
| 200 _mojom_types_pkg = "package:mojo/mojo/bindings/types/%s.mojom.dart" % \ | |
| 201 _mojom_types_pkg_short | |
| 202 | |
| 203 def GetDartType(kind): | |
| 204 if kind.imported_from: | |
| 205 return kind.imported_from["unique_name"] + "." + GetNameForElement(kind) | |
| 206 return GetNameForElement(kind) | |
| 207 | |
| 208 def DartDefaultValue(field): | |
| 209 if field.default: | |
| 210 if mojom.IsStructKind(field.kind): | |
| 211 assert field.default == "default" | |
| 212 return "new %s()" % GetDartType(field.kind) | |
| 213 if mojom.IsEnumKind(field.kind): | |
| 214 return ("new %s(%s)" % | |
| 215 (GetDartType(field.kind), ExpressionToText(field.default))) | |
| 216 return ExpressionToText(field.default) | |
| 217 if field.kind in mojom.PRIMITIVES: | |
| 218 return _kind_to_dart_default_value[field.kind] | |
| 219 if mojom.IsStructKind(field.kind): | |
| 220 return "null" | |
| 221 if mojom.IsUnionKind(field.kind): | |
| 222 return "null" | |
| 223 if mojom.IsArrayKind(field.kind): | |
| 224 return "null" | |
| 225 if mojom.IsMapKind(field.kind): | |
| 226 return "null" | |
| 227 if mojom.IsInterfaceKind(field.kind) or \ | |
| 228 mojom.IsInterfaceRequestKind(field.kind): | |
| 229 return "null" | |
| 230 if mojom.IsEnumKind(field.kind): | |
| 231 return "null" | |
| 232 | |
| 233 def DartDeclType(kind): | |
| 234 if kind in mojom.PRIMITIVES: | |
| 235 return _kind_to_dart_decl_type[kind] | |
| 236 if mojom.IsStructKind(kind): | |
| 237 return GetDartType(kind) | |
| 238 if mojom.IsUnionKind(kind): | |
| 239 return GetDartType(kind) | |
| 240 if mojom.IsArrayKind(kind): | |
| 241 array_type = DartDeclType(kind.kind) | |
| 242 return "List<" + array_type + ">" | |
| 243 if mojom.IsMapKind(kind): | |
| 244 key_type = DartDeclType(kind.key_kind) | |
| 245 value_type = DartDeclType(kind.value_kind) | |
| 246 return "Map<"+ key_type + ", " + value_type + ">" | |
| 247 if mojom.IsInterfaceKind(kind): | |
| 248 return ("%sInterface" % GetDartType(kind)) | |
| 249 if mojom.IsInterfaceRequestKind(kind): | |
| 250 return ("%sInterfaceRequest" % GetDartType(kind.kind)) | |
| 251 if mojom.IsEnumKind(kind): | |
| 252 return GetDartType(kind) | |
| 253 | |
| 254 def NameToComponent(name): | |
| 255 # insert '_' between anything and a Title name (e.g, HTTPEntry2FooBar -> | |
| 256 # HTTP_Entry2_FooBar). Numbers terminate a string of lower-case characters. | |
| 257 name = re.sub('([^_])([A-Z][^A-Z1-9_]+)', r'\1_\2', name) | |
| 258 # insert '_' between non upper and start of upper blocks (e.g., | |
| 259 # HTTP_Entry2_FooBar -> HTTP_Entry2_Foo_Bar). | |
| 260 name = re.sub('([^A-Z_])([A-Z])', r'\1_\2', name) | |
| 261 return [x.lower() for x in name.split('_')] | |
| 262 | |
| 263 def UpperCamelCase(name): | |
| 264 return ''.join([x.capitalize() for x in NameToComponent(name)]) | |
| 265 | |
| 266 def CamelCase(name): | |
| 267 uccc = UpperCamelCase(name) | |
| 268 return uccc[0].lower() + uccc[1:] | |
| 269 | |
| 270 def DotToUnderscore(name): | |
| 271 return name.replace('.', '_') | |
| 272 | |
| 273 def IsParamStruct(kind): | |
| 274 assert(isinstance(kind, mojom.Struct)) | |
| 275 return kind.name.endswith('_Params') | |
| 276 | |
| 277 # This may generate Dart reserved words. Call GetNameForElement to avoid | |
| 278 # generating reserved words. | |
| 279 def GetNameForElementUnsafe(element): | |
| 280 if (mojom.IsInterfaceKind(element) or mojom.IsUnionKind(element)): | |
| 281 return UpperCamelCase(element.name) | |
| 282 if mojom.IsStructKind(element): | |
| 283 if (IsParamStruct(element)): | |
| 284 # Param Structs are library private. | |
| 285 return '_' + UpperCamelCase(element.name) | |
| 286 return UpperCamelCase(element.name) | |
| 287 if mojom.IsInterfaceRequestKind(element): | |
| 288 return GetNameForElement(element.kind) | |
| 289 if isinstance(element, (mojom.Constant, | |
| 290 mojom.EnumField, | |
| 291 mojom.Field, | |
| 292 mojom.Method, | |
| 293 mojom.NamedValue, | |
| 294 mojom.Parameter, | |
| 295 mojom.UnionField)): | |
| 296 return CamelCase(element.name) | |
| 297 if mojom.IsEnumKind(element): | |
| 298 # If the enum is nested in some other mojom element, then we | |
| 299 # mangle the enum name by prepending it with the name of the containing | |
| 300 # element. | |
| 301 if element.parent_kind: | |
| 302 return ("%s%s" % (GetNameForElement(element.parent_kind), | |
| 303 UpperCamelCase(element.name))) | |
| 304 return UpperCamelCase(element.name) | |
| 305 if isinstance(element, mojom.EnumValue): | |
| 306 return (GetNameForElement(element.enum) + '.' + CamelCase(element.name)) | |
| 307 raise Exception('Unexpected element: %s' % element) | |
| 308 | |
| 309 def GetNameForElement(element): | |
| 310 name = GetNameForElementUnsafe(element) | |
| 311 if name in _reserved_words: | |
| 312 name = name + '_' | |
| 313 return name | |
| 314 | |
| 315 def GetInterfaceResponseName(method): | |
| 316 return UpperCamelCase(method.name + 'Response') | |
| 317 | |
| 318 def GetDartTrueFalse(value): | |
| 319 return 'true' if value else 'false' | |
| 320 | |
| 321 def GetArrayNullabilityFlags(kind): | |
| 322 """Returns nullability flags for an array type, see codec.dart. | |
| 323 | |
| 324 As we have dedicated decoding functions for arrays, we have to pass | |
| 325 nullability information about both the array itself, as well as the array | |
| 326 element type there. | |
| 327 """ | |
| 328 assert mojom.IsArrayKind(kind) | |
| 329 ARRAY_NULLABLE = 'bindings.kArrayNullable' | |
| 330 ELEMENT_NULLABLE = 'bindings.kElementNullable' | |
| 331 NOTHING_NULLABLE = 'bindings.kNothingNullable' | |
| 332 | |
| 333 flags_to_set = [] | |
| 334 if mojom.IsNullableKind(kind): | |
| 335 flags_to_set.append(ARRAY_NULLABLE) | |
| 336 if mojom.IsNullableKind(kind.kind): | |
| 337 flags_to_set.append(ELEMENT_NULLABLE) | |
| 338 | |
| 339 if not flags_to_set: | |
| 340 flags_to_set = [NOTHING_NULLABLE] | |
| 341 return ' | '.join(flags_to_set) | |
| 342 | |
| 343 def AppendDecodeParams(initial_params, kind, bit): | |
| 344 """ Appends standard parameters for decode calls. """ | |
| 345 params = list(initial_params) | |
| 346 if (kind == mojom.BOOL): | |
| 347 params.append(str(bit)) | |
| 348 if mojom.IsReferenceKind(kind): | |
| 349 if mojom.IsArrayKind(kind): | |
| 350 params.append(GetArrayNullabilityFlags(kind)) | |
| 351 else: | |
| 352 params.append(GetDartTrueFalse(mojom.IsNullableKind(kind))) | |
| 353 if mojom.IsInterfaceKind(kind): | |
| 354 params.append('%sProxy.newFromEndpoint' % GetDartType(kind)) | |
| 355 if mojom.IsArrayKind(kind) and mojom.IsInterfaceKind(kind.kind): | |
| 356 params.append('%sProxy.newFromEndpoint' % GetDartType(kind.kind)) | |
| 357 if mojom.IsInterfaceRequestKind(kind): | |
| 358 params.append('%sStub.newFromEndpoint' % GetDartType(kind.kind)) | |
| 359 if mojom.IsArrayKind(kind) and mojom.IsInterfaceRequestKind(kind.kind): | |
| 360 params.append('%sStub.newFromEndpoint' % GetDartType(kind.kind.kind)) | |
| 361 if mojom.IsArrayKind(kind): | |
| 362 params.append(GetArrayExpectedLength(kind)) | |
| 363 return params | |
| 364 | |
| 365 def AppendEncodeParams(initial_params, kind, bit): | |
| 366 """ Appends standard parameters shared between encode and decode calls. """ | |
| 367 params = list(initial_params) | |
| 368 if (kind == mojom.BOOL): | |
| 369 params.append(str(bit)) | |
| 370 if mojom.IsReferenceKind(kind): | |
| 371 if mojom.IsArrayKind(kind): | |
| 372 params.append(GetArrayNullabilityFlags(kind)) | |
| 373 else: | |
| 374 params.append(GetDartTrueFalse(mojom.IsNullableKind(kind))) | |
| 375 if mojom.IsArrayKind(kind): | |
| 376 params.append(GetArrayExpectedLength(kind)) | |
| 377 return params | |
| 378 | |
| 379 def DecodeMethod(kind, offset, bit): | |
| 380 def _DecodeMethodName(kind): | |
| 381 if mojom.IsArrayKind(kind): | |
| 382 return _DecodeMethodName(kind.kind) + 'Array' | |
| 383 if mojom.IsInterfaceRequestKind(kind): | |
| 384 return 'decodeInterfaceRequest' | |
| 385 if mojom.IsInterfaceKind(kind): | |
| 386 return 'decodeServiceInterface' | |
| 387 return _spec_to_decode_method[kind.spec] | |
| 388 methodName = _DecodeMethodName(kind) | |
| 389 params = AppendDecodeParams([ str(offset) ], kind, bit) | |
| 390 return '%s(%s)' % (methodName, ', '.join(params)) | |
| 391 | |
| 392 def EncodeMethod(kind, variable, offset, bit): | |
| 393 def _EncodeMethodName(kind): | |
| 394 if mojom.IsStructKind(kind): | |
| 395 return 'encodeStruct' | |
| 396 if mojom.IsUnionKind(kind): | |
| 397 return 'encodeUnion' | |
| 398 if mojom.IsArrayKind(kind): | |
| 399 return _EncodeMethodName(kind.kind) + 'Array' | |
| 400 if mojom.IsEnumKind(kind): | |
| 401 return 'encodeEnum' | |
| 402 if mojom.IsInterfaceRequestKind(kind): | |
| 403 return 'encodeInterfaceRequest' | |
| 404 if mojom.IsInterfaceKind(kind): | |
| 405 return 'encodeInterface' | |
| 406 return _spec_to_encode_method[kind.spec] | |
| 407 methodName = _EncodeMethodName(kind) | |
| 408 params = AppendEncodeParams([ variable, str(offset) ], kind, bit) | |
| 409 return '%s(%s)' % (methodName, ', '.join(params)) | |
| 410 | |
| 411 def TranslateConstants(token): | |
| 412 if isinstance(token, mojom.BuiltinValue): | |
| 413 if token.value == "double.INFINITY" or token.value == "float.INFINITY": | |
| 414 return "double.INFINITY"; | |
| 415 if token.value == "double.NEGATIVE_INFINITY" or \ | |
| 416 token.value == "float.NEGATIVE_INFINITY": | |
| 417 return "double.NEGATIVE_INFINITY"; | |
| 418 if token.value == "double.NAN" or token.value == "float.NAN": | |
| 419 return "double.NAN"; | |
| 420 | |
| 421 # Strip leading '+'. | |
| 422 if token[0] == '+': | |
| 423 token = token[1:] | |
| 424 | |
| 425 return token | |
| 426 | |
| 427 def ExpressionToText(token): | |
| 428 if isinstance(token, (mojom.EnumValue, mojom.NamedValue)): | |
| 429 return str(token.resolved_value) | |
| 430 return TranslateConstants(token) | |
| 431 | |
| 432 def GetArrayKind(kind, size = None): | |
| 433 if size is None: | |
| 434 return mojom.Array(kind) | |
| 435 else: | |
| 436 array = mojom.Array(kind, 0) | |
| 437 array.dart_map_size = size | |
| 438 return array | |
| 439 | |
| 440 def GetArrayExpectedLength(kind): | |
| 441 if mojom.IsArrayKind(kind) and kind.length is not None: | |
| 442 return getattr(kind, 'dart_map_size', str(kind.length)) | |
| 443 else: | |
| 444 return 'bindings.kUnspecifiedArrayLength' | |
| 445 | |
| 446 def IsPointerArrayKind(kind): | |
| 447 if not mojom.IsArrayKind(kind): | |
| 448 return False | |
| 449 sub_kind = kind.kind | |
| 450 return mojom.IsObjectKind(sub_kind) | |
| 451 | |
| 452 def IsEnumArrayKind(kind): | |
| 453 return mojom.IsArrayKind(kind) and mojom.IsEnumKind(kind.kind) | |
| 454 | |
| 455 def IsImportedKind(kind): | |
| 456 return hasattr(kind, 'imported_from') and kind.imported_from | |
| 457 | |
| 458 def ParseStringAttribute(attribute): | |
| 459 assert isinstance(attribute, basestring) | |
| 460 return attribute | |
| 461 | |
| 462 def GetPackage(module): | |
| 463 if module.attributes and 'DartPackage' in module.attributes: | |
| 464 package = ParseStringAttribute(module.attributes['DartPackage']) | |
| 465 package = package.strip() | |
| 466 if package != '': | |
| 467 return package | |
| 468 # Default package. | |
| 469 return 'mojom' | |
| 470 | |
| 471 def GetImportUri(module): | |
| 472 package = GetPackage(module); | |
| 473 elements = module.namespace.split('.') | |
| 474 elements.append("%s" % module.name) | |
| 475 return os.path.join(package, *elements) | |
| 476 | |
| 477 def RaiseHelper(msg): | |
| 478 raise Exception(msg) | |
| 479 | |
| 480 class Generator(generator.Generator): | |
| 481 | |
| 482 dart_filters = { | |
| 483 'array_expected_length': GetArrayExpectedLength, | |
| 484 'array': GetArrayKind, | |
| 485 'decode_method': DecodeMethod, | |
| 486 'default_value': DartDefaultValue, | |
| 487 'encode_method': EncodeMethod, | |
| 488 'is_imported_kind': IsImportedKind, | |
| 489 'is_array_kind': mojom.IsArrayKind, | |
| 490 'is_map_kind': mojom.IsMapKind, | |
| 491 'is_numerical_kind': mojom.IsNumericalKind, | |
| 492 'is_any_handle_kind': mojom.IsAnyHandleKind, | |
| 493 'is_string_kind': mojom.IsStringKind, | |
| 494 'is_nullable_kind': mojom.IsNullableKind, | |
| 495 'is_pointer_array_kind': IsPointerArrayKind, | |
| 496 'is_enum_array_kind': IsEnumArrayKind, | |
| 497 'is_struct_kind': mojom.IsStructKind, | |
| 498 'is_union_kind': mojom.IsUnionKind, | |
| 499 'is_enum_kind': mojom.IsEnumKind, | |
| 500 'is_interface_kind': mojom.IsInterfaceKind, | |
| 501 'is_interface_request_kind': mojom.IsInterfaceRequestKind, | |
| 502 'dart_true_false': GetDartTrueFalse, | |
| 503 'dart_type': DartDeclType, | |
| 504 'name': GetNameForElement, | |
| 505 'interface_response_name': GetInterfaceResponseName, | |
| 506 'dot_to_underscore': DotToUnderscore, | |
| 507 'is_cloneable_kind': mojom.IsCloneableKind, | |
| 508 'upper_camel': UpperCamelCase, | |
| 509 'lower_camel': CamelCase, | |
| 510 'raise': RaiseHelper, | |
| 511 } | |
| 512 | |
| 513 # If set to True, then mojom type information will be generated. | |
| 514 should_gen_mojom_types = False | |
| 515 | |
| 516 def GetParameters(self, args): | |
| 517 package = self.module.name.split('.')[0] | |
| 518 | |
| 519 # True if handles are used anywhere in the mojom. | |
| 520 has_handles = any(not mojom.IsCloneableKind(kind) | |
| 521 for kind in (self.GetStructs() + | |
| 522 self.GetStructsFromMethods() + | |
| 523 self.GetUnions())) | |
| 524 | |
| 525 # True if the binding will need dart:async | |
| 526 needs_dart_async = any(any(method.response_parameters is not None | |
| 527 for method in interface.methods) | |
| 528 for interface in self.GetInterfaces()) | |
| 529 | |
| 530 parameters = { | |
| 531 "namespace": self.module.namespace, | |
| 532 "imports": self.GetImports(args), | |
| 533 "kinds": self.module.kinds, | |
| 534 "enums": self.module.enums, | |
| 535 "module": resolver.ResolveConstants(self.module, ExpressionToText), | |
| 536 "structs": self.GetStructs() + self.GetStructsFromMethods(), | |
| 537 "unions": self.GetUnions(), | |
| 538 "interfaces": self.GetInterfaces(), | |
| 539 "imported_interfaces": self.GetImportedInterfaces(), | |
| 540 "imported_from": self.ImportedFrom(), | |
| 541 "typepkg": '%s.' % _mojom_types_pkg_short, | |
| 542 "descpkg": '%s.' % _service_describer_pkg_short, | |
| 543 "mojom_types_import": 'import \'%s\' as %s;' % \ | |
| 544 (_mojom_types_pkg, _mojom_types_pkg_short), | |
| 545 "service_describer_import": 'import \'%s\' as %s;' % \ | |
| 546 (_service_describer_pkg, _service_describer_pkg_short), | |
| 547 "has_handles": has_handles, | |
| 548 "needs_dart_async": needs_dart_async, | |
| 549 } | |
| 550 | |
| 551 # If this is the mojom types package, clear the import-related params. | |
| 552 if package == _mojom_types_pkg_short: | |
| 553 parameters["typepkg"] = "" | |
| 554 parameters["mojom_types_import"] = "" | |
| 555 | |
| 556 # If this is the service describer package, clear the import-related params. | |
| 557 if package == _service_describer_pkg_short: | |
| 558 parameters["descpkg"] = "" | |
| 559 parameters["service_describer_import"] = "" | |
| 560 | |
| 561 # If no interfaces were defined, the service describer import isn't needed. | |
| 562 if len(self.module.interfaces) == 0: | |
| 563 parameters["service_describer_import"] = "" | |
| 564 | |
| 565 return parameters | |
| 566 | |
| 567 def GetGlobals(self): | |
| 568 return { | |
| 569 'should_gen_mojom_types': self.should_gen_mojom_types, | |
| 570 } | |
| 571 | |
| 572 @UseJinja("dart_templates/module.lib.tmpl", filters=dart_filters) | |
| 573 def GenerateLibModule(self, args): | |
| 574 return self.GetParameters(args) | |
| 575 | |
| 576 | |
| 577 def GenerateFiles(self, args): | |
| 578 self.should_gen_mojom_types = "--generate_type_info" in args | |
| 579 | |
| 580 elements = self.module.namespace.split('.') | |
| 581 elements.append("%s.dart" % self.module.name) | |
| 582 | |
| 583 lib_module = self.GenerateLibModule(args) | |
| 584 | |
| 585 # List of packages with checked in bindings. | |
| 586 # TODO(johnmccutchan): Stop generating bindings as part of build system | |
| 587 # and then remove this. | |
| 588 packages_with_checked_in_bindings = [ | |
| 589 '_mojo_for_test_only', | |
| 590 'mojo', | |
| 591 'mojo_apptest', | |
| 592 'mojo_services', | |
| 593 'mojo_sdk', | |
| 594 'mojom', | |
| 595 ] | |
| 596 package_name = GetPackage(self.module) | |
| 597 if not (package_name in packages_with_checked_in_bindings): | |
| 598 pkg_path = os.path.join("dart-pkg", package_name, "lib", *elements) | |
| 599 self.Write(lib_module, pkg_path) | |
| 600 | |
| 601 gen_path = os.path.join("dart-gen", package_name, "lib", *elements) | |
| 602 full_gen_path = os.path.join(self.output_dir, gen_path) | |
| 603 self.Write(lib_module, gen_path) | |
| 604 | |
| 605 link = self.MatchMojomFilePath("%s.dart" % self.module.name) | |
| 606 full_link_path = os.path.join(self.output_dir, link) | |
| 607 try: | |
| 608 os.unlink(full_link_path) | |
| 609 except OSError, exc: | |
| 610 # If the file does not exist, ignore the error. | |
| 611 if errno.ENOENT == exc.errno: | |
| 612 pass | |
| 613 else: | |
| 614 raise | |
| 615 fileutil.EnsureDirectoryExists(os.path.dirname(full_link_path)) | |
| 616 try: | |
| 617 if sys.platform == "win32": | |
| 618 shutil.copy(full_gen_path, full_link_path) | |
| 619 else: | |
| 620 os.symlink(full_gen_path, full_link_path) | |
| 621 except OSError as e: | |
| 622 # Errno 17 is file already exists. If the link fails because file already | |
| 623 # exists assume another instance of this script tried to create the same | |
| 624 # file and continue on. | |
| 625 if e.errno != 17: | |
| 626 raise e | |
| 627 | |
| 628 def GetImports(self, args): | |
| 629 used_imports = self.GetUsedImports(self.module) | |
| 630 used_names = set() | |
| 631 for each_import in used_imports.values(): | |
| 632 simple_name = each_import["module_name"].split(".")[0] | |
| 633 | |
| 634 # Since each import is assigned a library in Dart, they need to have | |
| 635 # unique names. | |
| 636 unique_name = simple_name | |
| 637 counter = 0 | |
| 638 while unique_name in used_names: | |
| 639 counter += 1 | |
| 640 unique_name = simple_name + str(counter) | |
| 641 | |
| 642 used_names.add(unique_name) | |
| 643 each_import["unique_name"] = unique_name + '_mojom' | |
| 644 counter += 1 | |
| 645 | |
| 646 each_import["rebased_path"] = GetImportUri(each_import['module']) | |
| 647 return sorted(used_imports.values(), key=lambda x: x['rebased_path']) | |
| 648 | |
| 649 def GetImportedInterfaces(self): | |
| 650 interface_to_import = {} | |
| 651 for each_import in self.module.imports: | |
| 652 for each_interface in each_import["module"].interfaces: | |
| 653 name = each_interface.name | |
| 654 interface_to_import[name] = each_import["unique_name"] + "." + name | |
| 655 return interface_to_import | |
| 656 | |
| 657 def ImportedFrom(self): | |
| 658 interface_to_import = {} | |
| 659 for each_import in self.module.imports: | |
| 660 for each_interface in each_import["module"].interfaces: | |
| 661 name = each_interface.name | |
| 662 interface_to_import[name] = each_import["unique_name"] + "." | |
| 663 return interface_to_import | |
| OLD | NEW |