| 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 if (!desc.hasOptions() || |
| 24 !desc.options.hasExtension(Dart_options.importedMixins)) { |
| 25 return <String, PbMixin>{}; |
| 17 } | 26 } |
| 18 var name = desc.options.getExtension(Dart_options.defaultMixin); | 27 var dartMixins = <String, DartMixin>{}; |
| 19 PbMixin mixin = findMixin(name); | 28 ImportedMixins importedMixins = |
| 20 if (mixin == null) { | 29 desc.options.getExtension(Dart_options.importedMixins); |
| 21 throw ("unknown mixin class: ${name}"); | 30 for (DartMixin mixin in importedMixins.mixins) { |
| 31 if (dartMixins.containsKey(mixin.name)) { |
| 32 throw mixinError('Duplicate mixin name: "${mixin.name}"'); |
| 33 } |
| 34 if (!mixin.name.startsWith(_dartIdentifier)) { |
| 35 throw mixinError( |
| 36 '"${mixin.name}" is not a valid dart class identifier'); |
| 37 } |
| 38 if (mixin.hasParent() && !mixin.parent.startsWith(_dartIdentifier)) { |
| 39 throw mixinError('Mixin parent "${mixin.parent}" of "${mixin.name}" is ' |
| 40 'not a valid dart class identifier'); |
| 41 } |
| 42 dartMixins[mixin.name] = mixin; |
| 22 } | 43 } |
| 23 return mixin; | 44 |
| 45 // Detect cycles and unknown parents. |
| 46 for (var mixin in dartMixins.values) { |
| 47 if (!mixin.hasParent()) continue; |
| 48 var currentMixin = mixin; |
| 49 var parentChain = <String>[]; |
| 50 while (currentMixin.hasParent()) { |
| 51 var parentName = currentMixin.parent; |
| 52 |
| 53 bool declaredMixin = dartMixins.containsKey(parentName); |
| 54 bool internalMixin = !declaredMixin && findMixin(parentName) != null; |
| 55 |
| 56 if (internalMixin) break; // No further validation of parent chain. |
| 57 |
| 58 if (!declaredMixin) { |
| 59 throw mixinError('Unknown mixin parent "${mixin.parent}" of ' |
| 60 '"${currentMixin.name}"'); |
| 61 } |
| 62 |
| 63 if (parentChain.contains(parentName)) { |
| 64 var cycle = parentChain.join('->') + '->$parentName'; |
| 65 throw mixinError('Cycle in parent chain: $cycle'); |
| 66 } |
| 67 parentChain.add(parentName); |
| 68 currentMixin = dartMixins[parentName]; |
| 69 } |
| 70 } |
| 71 |
| 72 // Turn DartMixins into PbMixins. |
| 73 final pbMixins = <String, PbMixin>{}; |
| 74 PbMixin resolveMixin(String name) { |
| 75 if (pbMixins.containsKey(name)) return pbMixins[name]; |
| 76 if (dartMixins.containsKey(name)) { |
| 77 var dartMixin = dartMixins[name]; |
| 78 var pbMixin = new PbMixin(dartMixin.name, |
| 79 importFrom: dartMixin.importFrom, |
| 80 parent: resolveMixin(dartMixin.parent)); |
| 81 pbMixins[name] = pbMixin; |
| 82 return pbMixin; |
| 83 } |
| 84 return findMixin(name); |
| 85 } |
| 86 for (var mixin in dartMixins.values) { |
| 87 resolveMixin(mixin.name); |
| 88 } |
| 89 return pbMixins; |
| 24 } | 90 } |
| 25 | 91 |
| 26 final FileDescriptorProto _fileDescriptor; | 92 final FileDescriptorProto _fileDescriptor; |
| 27 | 93 |
| 28 // The relative path used to import the .proto file, as a URI. | 94 // The relative path used to import the .proto file, as a URI. |
| 29 final Uri protoFileUri; | 95 final Uri protoFileUri; |
| 30 | 96 |
| 31 final List<EnumGenerator> enumGenerators = <EnumGenerator>[]; | 97 final List<EnumGenerator> enumGenerators = <EnumGenerator>[]; |
| 32 final List<MessageGenerator> messageGenerators = <MessageGenerator>[]; | 98 final List<MessageGenerator> messageGenerators = <MessageGenerator>[]; |
| 33 final List<ExtensionGenerator> extensionGenerators = <ExtensionGenerator>[]; | 99 final List<ExtensionGenerator> extensionGenerators = <ExtensionGenerator>[]; |
| 34 final List<ClientApiGenerator> clientApiGenerators = <ClientApiGenerator>[]; | 100 final List<ClientApiGenerator> clientApiGenerators = <ClientApiGenerator>[]; |
| 35 final List<ServiceGenerator> serviceGenerators = <ServiceGenerator>[]; | 101 final List<ServiceGenerator> serviceGenerators = <ServiceGenerator>[]; |
| 36 | 102 |
| 37 /// True if cross-references have been resolved. | 103 /// True if cross-references have been resolved. |
| 38 bool _linked = false; | 104 bool _linked = false; |
| 39 | 105 |
| 40 FileGenerator(FileDescriptorProto descriptor) | 106 FileGenerator(FileDescriptorProto descriptor) |
| 41 : _fileDescriptor = descriptor, | 107 : _fileDescriptor = descriptor, |
| 42 protoFileUri = new Uri.file(descriptor.name) { | 108 protoFileUri = new Uri.file(descriptor.name) { |
| 43 if (protoFileUri.isAbsolute) { | 109 if (protoFileUri.isAbsolute) { |
| 44 // protoc should never generate an import with an absolute path. | 110 // protoc should never generate an import with an absolute path. |
| 45 throw "FAILURE: Import with absolute path is not supported"; | 111 throw "FAILURE: Import with absolute path is not supported"; |
| 46 } | 112 } |
| 47 | 113 |
| 48 var defaultMixin = _getDefaultMixin(_fileDescriptor); | 114 var declaredMixins = _getDeclaredMixins(descriptor); |
| 115 var defaultMixinName = |
| 116 descriptor.options?.getExtension(Dart_options.defaultMixin) ?? ''; |
| 117 var defaultMixin = |
| 118 declaredMixins[defaultMixinName] ?? findMixin(defaultMixinName); |
| 119 if (defaultMixin == null && defaultMixinName.isNotEmpty) { |
| 120 throw ('Option default_mixin on file ${descriptor.name}: Unknown mixin ' |
| 121 '$defaultMixinName'); |
| 122 } |
| 49 | 123 |
| 50 // Load and register all enum and message types. | 124 // Load and register all enum and message types. |
| 51 for (EnumDescriptorProto enumType in _fileDescriptor.enumType) { | 125 for (EnumDescriptorProto enumType in _fileDescriptor.enumType) { |
| 52 enumGenerators.add(new EnumGenerator(enumType, this)); | 126 enumGenerators.add(new EnumGenerator(enumType, this)); |
| 53 } | 127 } |
| 54 for (DescriptorProto messageType in _fileDescriptor.messageType) { | 128 for (DescriptorProto messageType in _fileDescriptor.messageType) { |
| 55 messageGenerators | 129 messageGenerators.add(new MessageGenerator( |
| 56 .add(new MessageGenerator(messageType, this, defaultMixin)); | 130 messageType, this, declaredMixins, defaultMixin)); |
| 57 } | 131 } |
| 58 for (FieldDescriptorProto extension in _fileDescriptor.extension) { | 132 for (FieldDescriptorProto extension in _fileDescriptor.extension) { |
| 59 extensionGenerators.add(new ExtensionGenerator(extension, this)); | 133 extensionGenerators.add(new ExtensionGenerator(extension, this)); |
| 60 } | 134 } |
| 61 for (ServiceDescriptorProto service in _fileDescriptor.service) { | 135 for (ServiceDescriptorProto service in _fileDescriptor.service) { |
| 62 var serviceGen = new ServiceGenerator(service, this); | 136 var serviceGen = new ServiceGenerator(service, this); |
| 63 serviceGenerators.add(serviceGen); | 137 serviceGenerators.add(serviceGen); |
| 64 clientApiGenerators.add(new ClientApiGenerator(serviceGen)); | 138 clientApiGenerators.add(new ClientApiGenerator(serviceGen)); |
| 65 } | 139 } |
| 66 } | 140 } |
| (...skipping 348 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 415 FileGenerator target, String extension) { | 489 FileGenerator target, String extension) { |
| 416 Uri resolvedImport = | 490 Uri resolvedImport = |
| 417 config.resolveImport(target.protoFileUri, protoFileUri, extension); | 491 config.resolveImport(target.protoFileUri, protoFileUri, extension); |
| 418 out.print("import '$resolvedImport'"); | 492 out.print("import '$resolvedImport'"); |
| 419 if (package != target.package && target.package.isNotEmpty) { | 493 if (package != target.package && target.package.isNotEmpty) { |
| 420 out.print(' as ${target.packageImportPrefix}'); | 494 out.print(' as ${target.packageImportPrefix}'); |
| 421 } | 495 } |
| 422 out.println(';'); | 496 out.println(';'); |
| 423 } | 497 } |
| 424 } | 498 } |
| OLD | NEW |