Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 part of protoc; | 5 part of protoc; |
| 6 | 6 |
| 7 final _dartIdentifier = new RegExp(r'^\w+$'); | |
| 8 | |
| 7 /// Generates the Dart output files for one .proto input file. | 9 /// Generates the Dart output files for one .proto input file. |
| 8 /// | 10 /// |
| 9 /// Outputs include .pb.dart, pbenum.dart, and .pbjson.dart. | 11 /// Outputs include .pb.dart, pbenum.dart, and .pbjson.dart. |
| 10 class FileGenerator extends ProtobufContainer { | 12 class FileGenerator extends ProtobufContainer { |
| 11 /// Returns the the mixin to use by default in this file, | 13 /// Reads and the declared mixins in the file, keyed by name. |
| 12 /// or null for no mixin by default. | 14 /// |
| 13 static PbMixin _getDefaultMixin(FileDescriptorProto desc) { | 15 /// Performs some basic validation on declared mixins, e.g. whether names |
| 14 if (!desc.hasOptions()) return null; | 16 /// are valid dart identifiers and whether there are cycles in the `parent` |
| 15 if (!desc.options.hasExtension(Dart_options.defaultMixin)) { | 17 /// hierarchy. |
| 16 return null; | 18 /// Does not check for existence of import files or classes. |
| 19 static Map<String, PbMixin> _getDeclaredMixins(FileDescriptorProto desc) { | |
| 20 String mixinError(String error) => | |
| 21 'Option "mixins" in file ${desc.name}: $error'; | |
| 22 | |
| 23 final dartMixins = <String, DartMixin>{}; | |
|
skybrian
2016/06/23 19:01:42
can move down
frederikmutzel
2016/06/27 08:44:31
Done.
| |
| 24 if (!desc.hasOptions() || !desc.options.hasExtension(Dart_options.mixins)) { | |
| 25 return <String, PbMixin>{}; | |
| 17 } | 26 } |
| 18 var name = desc.options.getExtension(Dart_options.defaultMixin); | 27 for (DartMixin mixin in desc.options.getExtension(Dart_options.mixins)) { |
| 19 PbMixin mixin = findMixin(name); | 28 if (dartMixins.containsKey(mixin.name)) { |
| 20 if (mixin == null) { | 29 throw mixinError('Duplicate mixin name: "${mixin.name}"'); |
| 21 throw ("unknown mixin class: ${name}"); | 30 } |
| 31 if (!mixin.name.startsWith(_dartIdentifier)) { | |
| 32 throw mixinError( | |
| 33 '"${mixin.name}" is not a valid dart class identifier'); | |
| 34 } | |
| 35 if (mixin.hasParent() && !mixin.parent.startsWith(_dartIdentifier)) { | |
| 36 throw mixinError('Mixin parent "${mixin.parent}" of "${mixin.name}" is ' | |
| 37 'not a valid dart class identifier'); | |
| 38 } | |
| 39 dartMixins[mixin.name] = mixin; | |
| 22 } | 40 } |
| 23 return mixin; | 41 |
| 42 // Detect cycles and unknown parents. | |
| 43 for (var mixin in dartMixins.values) { | |
| 44 if (!mixin.hasParent()) continue; | |
| 45 var currentMixin = mixin; | |
| 46 var parentChain = <String>[]; | |
| 47 while (currentMixin.hasParent()) { | |
| 48 var parentName = currentMixin.parent; | |
| 49 | |
| 50 bool declaredMixin = dartMixins.containsKey(parentName); | |
| 51 bool internalMixin = !declaredMixin && findMixin(parentName) != null; | |
|
skybrian
2016/06/23 19:01:42
Should we allow inheritance between declared and i
frederikmutzel
2016/06/27 08:44:31
I think it could make migration easier if you don'
| |
| 52 | |
| 53 if (internalMixin) break; // No further validation of parent chain. | |
| 54 | |
| 55 if (!declaredMixin) { | |
| 56 throw mixinError('Unknown mixin parent "${mixin.parent}" of ' | |
| 57 '"${currentMixin.name}"'); | |
| 58 } | |
| 59 | |
| 60 if (parentChain.contains(parentName)) { | |
| 61 var cycle = parentChain.join('->') + '->$parentName'; | |
| 62 throw mixinError('Cycle in parent chain: $cycle'); | |
| 63 } | |
| 64 parentChain.add(parentName); | |
| 65 currentMixin = dartMixins[parentName]; | |
| 66 } | |
| 67 } | |
| 68 | |
| 69 // Turn DartMixins into PbMixins. | |
| 70 final pbMixins = <String, PbMixin>{}; | |
| 71 PbMixin resolveMixin(String name) { | |
| 72 if (pbMixins.containsKey(name)) return pbMixins[name]; | |
| 73 if (dartMixins.containsKey(name)) { | |
| 74 var dartMixin = dartMixins[name]; | |
| 75 var pbMixin = new PbMixin(dartMixin.name, | |
| 76 importFrom: dartMixin.importFrom, | |
| 77 parent: resolveMixin(dartMixin.parent)); | |
| 78 pbMixins[name] = pbMixin; | |
| 79 return pbMixin; | |
| 80 } | |
| 81 return findMixin(name); | |
| 82 } | |
| 83 for (var mixin in dartMixins.values) { | |
| 84 resolveMixin(mixin.name); | |
| 85 } | |
| 86 return pbMixins; | |
| 24 } | 87 } |
| 25 | 88 |
| 26 final FileDescriptorProto _fileDescriptor; | 89 final FileDescriptorProto _fileDescriptor; |
| 27 | 90 |
| 28 // The relative path used to import the .proto file, as a URI. | 91 // The relative path used to import the .proto file, as a URI. |
| 29 final Uri protoFileUri; | 92 final Uri protoFileUri; |
| 30 | 93 |
| 31 final List<EnumGenerator> enumGenerators = <EnumGenerator>[]; | 94 final List<EnumGenerator> enumGenerators = <EnumGenerator>[]; |
| 32 final List<MessageGenerator> messageGenerators = <MessageGenerator>[]; | 95 final List<MessageGenerator> messageGenerators = <MessageGenerator>[]; |
| 33 final List<ExtensionGenerator> extensionGenerators = <ExtensionGenerator>[]; | 96 final List<ExtensionGenerator> extensionGenerators = <ExtensionGenerator>[]; |
| 34 final List<ClientApiGenerator> clientApiGenerators = <ClientApiGenerator>[]; | 97 final List<ClientApiGenerator> clientApiGenerators = <ClientApiGenerator>[]; |
| 35 final List<ServiceGenerator> serviceGenerators = <ServiceGenerator>[]; | 98 final List<ServiceGenerator> serviceGenerators = <ServiceGenerator>[]; |
| 36 | 99 |
| 37 /// True if cross-references have been resolved. | 100 /// True if cross-references have been resolved. |
| 38 bool _linked = false; | 101 bool _linked = false; |
| 39 | 102 |
| 40 FileGenerator(FileDescriptorProto descriptor) | 103 FileGenerator(FileDescriptorProto descriptor) |
| 41 : _fileDescriptor = descriptor, | 104 : _fileDescriptor = descriptor, |
| 42 protoFileUri = new Uri.file(descriptor.name) { | 105 protoFileUri = new Uri.file(descriptor.name) { |
| 43 if (protoFileUri.isAbsolute) { | 106 if (protoFileUri.isAbsolute) { |
| 44 // protoc should never generate an import with an absolute path. | 107 // protoc should never generate an import with an absolute path. |
| 45 throw "FAILURE: Import with absolute path is not supported"; | 108 throw "FAILURE: Import with absolute path is not supported"; |
| 46 } | 109 } |
| 47 | 110 |
| 48 var defaultMixin = _getDefaultMixin(_fileDescriptor); | 111 var declaredMixins = _getDeclaredMixins(descriptor); |
| 112 var defaultMixin = | |
| 113 descriptor.options?.getExtension(Dart_options.defaultMixin) ?? ''; | |
| 114 if (defaultMixin.isNotEmpty && | |
| 115 !declaredMixins.containsKey(defaultMixin) && | |
| 116 findMixin(defaultMixin) == null) { | |
| 117 throw ('Option default_mixin on file ${descriptor.name}: Unknown mixin ' | |
| 118 '$defaultMixin'); | |
| 119 } | |
| 49 | 120 |
| 50 // Load and register all enum and message types. | 121 // Load and register all enum and message types. |
| 51 for (EnumDescriptorProto enumType in _fileDescriptor.enumType) { | 122 for (EnumDescriptorProto enumType in _fileDescriptor.enumType) { |
| 52 enumGenerators.add(new EnumGenerator(enumType, this)); | 123 enumGenerators.add(new EnumGenerator(enumType, this)); |
| 53 } | 124 } |
| 54 for (DescriptorProto messageType in _fileDescriptor.messageType) { | 125 for (DescriptorProto messageType in _fileDescriptor.messageType) { |
| 55 messageGenerators | 126 messageGenerators.add(new MessageGenerator( |
| 56 .add(new MessageGenerator(messageType, this, defaultMixin)); | 127 messageType, this, declaredMixins, defaultMixin)); |
| 57 } | 128 } |
| 58 for (FieldDescriptorProto extension in _fileDescriptor.extension) { | 129 for (FieldDescriptorProto extension in _fileDescriptor.extension) { |
| 59 extensionGenerators.add(new ExtensionGenerator(extension, this)); | 130 extensionGenerators.add(new ExtensionGenerator(extension, this)); |
| 60 } | 131 } |
| 61 for (ServiceDescriptorProto service in _fileDescriptor.service) { | 132 for (ServiceDescriptorProto service in _fileDescriptor.service) { |
| 62 var serviceGen = new ServiceGenerator(service, this); | 133 var serviceGen = new ServiceGenerator(service, this); |
| 63 serviceGenerators.add(serviceGen); | 134 serviceGenerators.add(serviceGen); |
| 64 clientApiGenerators.add(new ClientApiGenerator(serviceGen)); | 135 clientApiGenerators.add(new ClientApiGenerator(serviceGen)); |
| 65 } | 136 } |
| 66 } | 137 } |
| (...skipping 348 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 415 FileGenerator target, String extension) { | 486 FileGenerator target, String extension) { |
| 416 Uri resolvedImport = | 487 Uri resolvedImport = |
| 417 config.resolveImport(target.protoFileUri, protoFileUri, extension); | 488 config.resolveImport(target.protoFileUri, protoFileUri, extension); |
| 418 out.print("import '$resolvedImport'"); | 489 out.print("import '$resolvedImport'"); |
| 419 if (package != target.package && target.package.isNotEmpty) { | 490 if (package != target.package && target.package.isNotEmpty) { |
| 420 out.print(' as ${target.packageImportPrefix}'); | 491 out.print(' as ${target.packageImportPrefix}'); |
| 421 } | 492 } |
| 422 out.println(';'); | 493 out.println(';'); |
| 423 } | 494 } |
| 424 } | 495 } |
| OLD | NEW |