Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(126)

Side by Side Diff: lib/file_generator.dart

Issue 2086253002: Allow application of external mixins to generated dart protos. (Closed) Base URL: https://github.com/dart-lang/dart-protoc-plugin.git@master
Patch Set: Update from code review. Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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 }
OLDNEW
« no previous file with comments | « Makefile ('k') | lib/message_generator.dart » ('j') | lib/message_generator.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698