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 const String SP = ' '; | 7 const String SP = ' '; |
8 | 8 |
9 class MessageGenerator extends ProtobufContainer { | 9 class MessageGenerator extends ProtobufContainer { |
10 // List of Dart language reserved words in names which cannot be used in a | 10 // List of Dart language reserved words in names which cannot be used in a |
(...skipping 13 matching lines...) Expand all Loading... |
24 'writeToBuffer', 'writeToCodedBufferWriter', | 24 'writeToBuffer', 'writeToCodedBufferWriter', |
25 'mergeFromCodedBufferReader', 'mergeFromBuffer', | 25 'mergeFromCodedBufferReader', 'mergeFromBuffer', |
26 'writeToJson', 'mergeFromJson', | 26 'writeToJson', 'mergeFromJson', |
27 'writeToJsonMap', 'mergeFromJsonMap', | 27 'writeToJsonMap', 'mergeFromJsonMap', |
28 'addExtension', 'getExtension', 'setExtension', | 28 'addExtension', 'getExtension', 'setExtension', |
29 'hasExtension', 'clearExtension', | 29 'hasExtension', 'clearExtension', |
30 'getField', 'setField', 'hasField', 'clearField', | 30 'getField', 'setField', 'hasField', 'clearField', |
31 'extensionsAreInitialized', 'mergeFromMessage', 'mergeUnknownFields', | 31 'extensionsAreInitialized', 'mergeFromMessage', 'mergeUnknownFields', |
32 '==', 'info_', 'GeneratedMessage', 'Object']; | 32 '==', 'info_', 'GeneratedMessage', 'Object']; |
33 | 33 |
34 // List of names that can't be used in a subclass that implements Map. | 34 // Returns the mixin for this message, or null if none. |
35 static final List<String> reservedNamesForMap = | 35 static PbMixin _getMixin(DescriptorProto desc, PbMixin defaultValue) { |
36 ['addAll', 'containsKey', 'containsValue', 'forEach', 'putIfAbsent', | 36 if (!desc.hasOptions()) return defaultValue; |
37 'remove', 'isEmpty', 'isNotEmpty', 'keys', 'length', 'values']; | 37 if (!desc.options.hasExtension(Dart_options.mixin)) return defaultValue; |
38 | 38 |
39 // This should match the extension in dart_options.proto. | 39 String name = desc.options.getExtension(Dart_options.mixin); |
40 static const int implementMapOption = 95333044; | 40 if (name.isEmpty) return null; // don't use a mixin (override any default) |
41 | 41 var mixin = findMixin(name); |
42 // Returns true if the implement_map option is turned on for the message. | 42 if (mixin == null) { |
43 static bool _shouldImplementMap(DescriptorProto desc, bool defaultValue) { | 43 throw("unknown mixin class: ${name}"); |
44 if (!desc.hasOptions()) return defaultValue; | 44 } |
45 | 45 return mixin; |
46 var val = desc.options.unknownFields.getField(implementMapOption); | |
47 if (val == null || val.length != 1) return defaultValue; | |
48 | |
49 return val.values[0] == 1; | |
50 } | 46 } |
51 | 47 |
52 final String classname; | 48 final String classname; |
53 final String fqname; | 49 final String fqname; |
54 final bool implementsMap; | 50 final PbMixin mixin; |
55 | 51 |
56 final ProtobufContainer _parent; | 52 final ProtobufContainer _parent; |
57 final GenerationContext _context; | 53 final GenerationContext _context; |
58 final DescriptorProto _descriptor; | 54 final DescriptorProto _descriptor; |
59 final List<EnumGenerator> _enumGenerators = <EnumGenerator>[]; | 55 final List<EnumGenerator> _enumGenerators = <EnumGenerator>[]; |
60 final List<ProtobufField> _fieldList = <ProtobufField>[]; | 56 final List<ProtobufField> _fieldList = <ProtobufField>[]; |
61 final List<MessageGenerator> _messageGenerators = <MessageGenerator>[]; | 57 final List<MessageGenerator> _messageGenerators = <MessageGenerator>[]; |
62 final List<ExtensionGenerator> _extensionGenerators = <ExtensionGenerator>[]; | 58 final List<ExtensionGenerator> _extensionGenerators = <ExtensionGenerator>[]; |
63 final Set<String> _methodNames = new Set<String>(); | 59 final Set<String> _methodNames = new Set<String>(); |
64 | 60 |
65 MessageGenerator( | 61 MessageGenerator( |
66 DescriptorProto descriptor, ProtobufContainer parent, this._context, | 62 DescriptorProto descriptor, ProtobufContainer parent, this._context, |
67 bool implementMapByDefault) | 63 PbMixin defaultMixin) |
68 : _descriptor = descriptor, | 64 : _descriptor = descriptor, |
69 _parent = parent, | 65 _parent = parent, |
70 classname = (parent.classname == '') ? | 66 classname = (parent.classname == '') ? |
71 descriptor.name : '${parent.classname}_${descriptor.name}', | 67 descriptor.name : '${parent.classname}_${descriptor.name}', |
72 fqname = (parent == null || parent.fqname == null) ? descriptor.name : | 68 fqname = (parent == null || parent.fqname == null) ? descriptor.name : |
73 (parent.fqname == '.' ? | 69 (parent.fqname == '.' ? |
74 '.${descriptor.name}' : '${parent.fqname}.${descriptor.name}'), | 70 '.${descriptor.name}' : '${parent.fqname}.${descriptor.name}'), |
75 implementsMap = _shouldImplementMap(descriptor, implementMapByDefault) { | 71 mixin = _getMixin(descriptor, defaultMixin) { |
76 _context.register(this); | 72 _context.register(this); |
77 | 73 |
78 for (EnumDescriptorProto e in _descriptor.enumType) { | 74 for (EnumDescriptorProto e in _descriptor.enumType) { |
79 _enumGenerators.add(new EnumGenerator(e, this, _context)); | 75 _enumGenerators.add(new EnumGenerator(e, this, _context)); |
80 } | 76 } |
81 | 77 |
82 for (DescriptorProto n in _descriptor.nestedType) { | 78 for (DescriptorProto n in _descriptor.nestedType) { |
83 _messageGenerators.add( | 79 _messageGenerators.add( |
84 new MessageGenerator(n, this, _context, implementMapByDefault)); | 80 new MessageGenerator(n, this, _context, defaultMixin)); |
85 } | 81 } |
86 | 82 |
87 for (FieldDescriptorProto x in _descriptor.extension) { | 83 for (FieldDescriptorProto x in _descriptor.extension) { |
88 _extensionGenerators.add(new ExtensionGenerator(x, this, _context)); | 84 _extensionGenerators.add(new ExtensionGenerator(x, this, _context)); |
89 } | 85 } |
90 } | 86 } |
91 | 87 |
92 String get package => _parent.package; | 88 String get package => _parent.package; |
93 | 89 |
94 bool get needsMapMixinImport { | 90 /// Adds all mixins used in this message and any submessages. |
95 if (implementsMap) return true; | 91 void addMixinsTo(Set<PbMixin> output) { |
96 | 92 if (mixin != null) { |
| 93 output.addAll(mixin.findMixinsToApply()); |
| 94 } |
97 for (var m in _messageGenerators) { | 95 for (var m in _messageGenerators) { |
98 if (m.implementsMap) return true; | 96 m.addMixinsTo(output); |
99 } | 97 } |
100 | |
101 return false; | |
102 } | 98 } |
103 | 99 |
104 void initializeFields() { | 100 void initializeFields() { |
105 _fieldList.clear(); | 101 _fieldList.clear(); |
106 for (FieldDescriptorProto field in _descriptor.field) { | 102 for (FieldDescriptorProto field in _descriptor.field) { |
107 _fieldList.add(new ProtobufField(field, this, _context)); | 103 _fieldList.add(new ProtobufField(field, this, _context)); |
108 } | 104 } |
109 for (MessageGenerator m in _messageGenerators) { | 105 for (MessageGenerator m in _messageGenerators) { |
110 m.initializeFields(); | 106 m.initializeFields(); |
111 } | 107 } |
112 } | 108 } |
113 | 109 |
114 void generate(IndentingWriter out) { | 110 void generate(IndentingWriter out) { |
115 _methodNames.clear(); | 111 _methodNames.clear(); |
116 _methodNames.addAll(reservedWords); | 112 _methodNames.addAll(reservedWords); |
117 _methodNames.addAll(reservedNames); | 113 _methodNames.addAll(reservedNames); |
118 | 114 |
119 if (implementsMap) { | 115 if (mixin != null) { |
120 _methodNames.addAll(reservedNamesForMap); | 116 _methodNames.addAll(mixin.findReservedNames()); |
121 } | 117 } |
122 | 118 |
123 for (EnumGenerator e in _enumGenerators) { | 119 for (EnumGenerator e in _enumGenerators) { |
124 e.generate(out); | 120 e.generate(out); |
125 } | 121 } |
126 | 122 |
127 for (MessageGenerator m in _messageGenerators) { | 123 for (MessageGenerator m in _messageGenerators) { |
128 m.generate(out); | 124 m.generate(out); |
129 } | 125 } |
130 | 126 |
131 var implClause = ""; | 127 var mixinClause = ''; |
132 if (implementsMap) { | 128 if (mixin != null) { |
133 implClause = " with MapMixin"; | 129 var mixinNames = mixin.findMixinsToApply().map((m) => m.name); |
| 130 mixinClause = ' with ${mixinNames.join(", ")}'; |
134 } | 131 } |
135 | 132 |
136 out.addBlock('class ${classname} extends GeneratedMessage${implClause} {', | 133 out.addBlock('class ${classname} extends GeneratedMessage${mixinClause} {', |
137 '}', () | 134 '}', () |
138 { | 135 { |
139 out.addBlock( | 136 out.addBlock( |
140 'static final BuilderInfo _i = new BuilderInfo(\'${classname}\')', | 137 'static final BuilderInfo _i = new BuilderInfo(\'${classname}\')', |
141 ';', () { | 138 ';', () { |
142 for (ProtobufField field in _fieldList) { | 139 for (ProtobufField field in _fieldList) { |
143 String type = field.shortTypeName; | 140 String type = field.shortTypeName; |
144 String fieldType = field.baseTypeForPackage(package); | 141 String fieldType = field.baseTypeForPackage(package); |
145 | 142 |
146 String makeDefault = null; | 143 String makeDefault = null; |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
216 '${SP}new ${classname}()..mergeFromMessage(this);'); | 213 '${SP}new ${classname}()..mergeFromMessage(this);'); |
217 | 214 |
218 out.println('BuilderInfo get info_${SP}=>${SP}_i;'); | 215 out.println('BuilderInfo get info_${SP}=>${SP}_i;'); |
219 | 216 |
220 // Factory functions which can be used as default value closures. | 217 // Factory functions which can be used as default value closures. |
221 out.println('static ${classname}${SP}create()${SP}=>' | 218 out.println('static ${classname}${SP}create()${SP}=>' |
222 '${SP}new ${classname}();'); | 219 '${SP}new ${classname}();'); |
223 out.println('static PbList<${classname}>${SP}createRepeated()${SP}=>' | 220 out.println('static PbList<${classname}>${SP}createRepeated()${SP}=>' |
224 '${SP}new PbList<${classname}>();'); | 221 '${SP}new PbList<${classname}>();'); |
225 | 222 |
226 | |
227 if (implementsMap) { | |
228 // clear() is inherited from GeneratedMessage. | |
229 // Other map operations are implemented by MapMixin. | |
230 out.println(''' | |
231 @override | |
232 operator [] (key) { | |
233 if (key is !String) return null; | |
234 if (!key.contains(".")) { | |
235 var tag = getTagNumber(key); | |
236 if (tag == null) return null; | |
237 return getField(tag); | |
238 } | |
239 | |
240 var keys = key.split('.'); | |
241 var item = this; | |
242 for (var key in keys) { | |
243 if (item is !GeneratedMessage) return null; | |
244 var tag = item.getTagNumber(key); | |
245 if (tag == null) return null; | |
246 item = item.getField(tag); | |
247 } | |
248 | |
249 return item; | |
250 } | |
251 | |
252 @override | |
253 operator []= (String key, val) { | |
254 if (!key.contains(".")) { | |
255 var tag = _mustGetTagNumber(this, key); | |
256 setField(tag, val); | |
257 return; | |
258 } | |
259 | |
260 var keys = key.split('.'); | |
261 var lastKey = keys.removeLast(); | |
262 var item = this; | |
263 for (var key in keys) { | |
264 var tag = _mustGetTagNumber(item, key); | |
265 item = item.getField(tag); | |
266 if (item is !GeneratedMessage) { | |
267 throw new ArgumentError( | |
268 "field '\${key}' in \${info._messageName} isn't a GeneratedMessage:"); | |
269 } | |
270 } | |
271 var tag = _mustGetTagNumber(item, lastKey); | |
272 item.setField(tag, val); | |
273 } | |
274 | |
275 _mustGetTagNumber(GeneratedMessage msg, String key) { | |
276 var tag = msg.getTagNumber(key); | |
277 if (tag == null) { | |
278 throw new ArgumentError( | |
279 "field '\${key}' not found in \${msg.info_.messageName}"); | |
280 } | |
281 return tag; | |
282 } | |
283 | |
284 @override | |
285 get keys => info_.byName.keys; | |
286 | |
287 @override | |
288 get length => info_.byName.length; | |
289 | |
290 remove(key) { | |
291 throw new UnsupportedError("remove() not supported by \${info_.messageName}"); | |
292 } | |
293 '''); | |
294 } | |
295 | |
296 generateFieldsAccessorsMutators(out); | 223 generateFieldsAccessorsMutators(out); |
297 }); | 224 }); |
298 out.println(); | 225 out.println(); |
299 } | 226 } |
300 | 227 |
301 // Returns true if the message type has any required fields. If it doesn't, | 228 // Returns true if the message type has any required fields. If it doesn't, |
302 // we can optimize out calls to its isInitialized()/_findInvalidFields() | 229 // we can optimize out calls to its isInitialized()/_findInvalidFields() |
303 // methods. | 230 // methods. |
304 // | 231 // |
305 // already_seen is used to avoid checking the same type multiple times | 232 // already_seen is used to avoid checking the same type multiple times |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
371 '(${fieldTypeString} v)${SP}' | 298 '(${fieldTypeString} v)${SP}' |
372 '{${SP}setField(${field.number},${SP}v);${SP}}'); | 299 '{${SP}setField(${field.number},${SP}v);${SP}}'); |
373 out.println('bool $hasIdentifier()${SP}=>' | 300 out.println('bool $hasIdentifier()${SP}=>' |
374 '${SP}hasField(${field.number});'); | 301 '${SP}hasField(${field.number});'); |
375 out.println('void $clearIdentifier()${SP}=>' | 302 out.println('void $clearIdentifier()${SP}=>' |
376 '${SP}clearField(${field.number});'); | 303 '${SP}clearField(${field.number});'); |
377 } | 304 } |
378 } | 305 } |
379 } | 306 } |
380 } | 307 } |
OLD | NEW |