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 |