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 /// A Dart function called on each item added to a repeated list | 7 /// A Dart function called on each item added to a repeated list |
8 /// to check its type and range. | 8 /// to check its type and range. |
9 const checkItem = '\$checkItem'; | 9 const checkItem = '\$checkItem'; |
10 | 10 |
11 class MessageGenerator extends ProtobufContainer { | 11 class MessageGenerator extends ProtobufContainer { |
12 // List of Dart language reserved words in names which cannot be used in a | 12 // List of Dart language reserved words in names which cannot be used in a |
13 // subclass of GeneratedMessage. | 13 // subclass of GeneratedMessage. |
14 static final List<String> reservedWords = | 14 static final List<String> reservedWords = [ |
15 ['assert', 'break', 'case', 'catch', 'class', 'const', 'continue', | 15 'assert', |
16 'default', 'do', 'else', 'enum', 'extends', 'false', 'final', | 16 'break', |
17 'finally', 'for', 'if', 'in', 'is', 'new', 'null', 'rethrow', 'return', | 17 'case', |
18 'super', 'switch', 'this', 'throw', 'true', 'try', 'var', 'void', | 18 'catch', |
19 'while', 'with']; | 19 'class', |
| 20 'const', |
| 21 'continue', |
| 22 'default', |
| 23 'do', |
| 24 'else', |
| 25 'enum', |
| 26 'extends', |
| 27 'false', |
| 28 'final', |
| 29 'finally', |
| 30 'for', |
| 31 'if', |
| 32 'in', |
| 33 'is', |
| 34 'new', |
| 35 'null', |
| 36 'rethrow', |
| 37 'return', |
| 38 'super', |
| 39 'switch', |
| 40 'this', |
| 41 'throw', |
| 42 'true', |
| 43 'try', |
| 44 'var', |
| 45 'void', |
| 46 'while', |
| 47 'with' |
| 48 ]; |
20 | 49 |
21 // List of names used in the generated class itself | 50 // List of names used in the generated class itself |
22 static final List<String> generatedNames = | 51 static final List<String> generatedNames = [ |
23 ['create', 'createRepeated', 'getDefault', checkItem]; | 52 'create', |
| 53 'createRepeated', |
| 54 'getDefault', |
| 55 checkItem |
| 56 ]; |
24 | 57 |
25 // Returns the mixin for this message, or null if none. | 58 // Returns the mixin for this message, or null if none. |
26 static PbMixin _getMixin(DescriptorProto desc, PbMixin defaultValue) { | 59 static PbMixin _getMixin(DescriptorProto desc, PbMixin defaultValue) { |
27 if (!desc.hasOptions()) return defaultValue; | 60 if (!desc.hasOptions()) return defaultValue; |
28 if (!desc.options.hasExtension(Dart_options.mixin)) return defaultValue; | 61 if (!desc.options.hasExtension(Dart_options.mixin)) return defaultValue; |
29 | 62 |
30 String name = desc.options.getExtension(Dart_options.mixin); | 63 String name = desc.options.getExtension(Dart_options.mixin); |
31 if (name.isEmpty) return null; // don't use a mixin (override any default) | 64 if (name.isEmpty) return null; // don't use a mixin (override any default) |
32 var mixin = findMixin(name); | 65 var mixin = findMixin(name); |
33 if (mixin == null) { | 66 if (mixin == null) { |
34 throw("unknown mixin class: ${name}"); | 67 throw ("unknown mixin class: ${name}"); |
35 } | 68 } |
36 return mixin; | 69 return mixin; |
37 } | 70 } |
38 | 71 |
39 final String classname; | 72 final String classname; |
40 final String fqname; | 73 final String fqname; |
41 final PbMixin mixin; | 74 final PbMixin mixin; |
42 | 75 |
43 final ProtobufContainer _parent; | 76 final ProtobufContainer _parent; |
44 final DescriptorProto _descriptor; | 77 final DescriptorProto _descriptor; |
45 final List<EnumGenerator> _enumGenerators = <EnumGenerator>[]; | 78 final List<EnumGenerator> _enumGenerators = <EnumGenerator>[]; |
46 final List<MessageGenerator> _messageGenerators = <MessageGenerator>[]; | 79 final List<MessageGenerator> _messageGenerators = <MessageGenerator>[]; |
47 final List<ExtensionGenerator> _extensionGenerators = <ExtensionGenerator>[]; | 80 final List<ExtensionGenerator> _extensionGenerators = <ExtensionGenerator>[]; |
48 | 81 |
49 // populated by resolve() | 82 // populated by resolve() |
50 List<ProtobufField> _fieldList; | 83 List<ProtobufField> _fieldList; |
51 | 84 |
52 // Used during generation. | 85 // Used during generation. |
53 final Set<String> _methodNames = new Set<String>(); | 86 final Set<String> _methodNames = new Set<String>(); |
54 | 87 |
55 MessageGenerator( | 88 MessageGenerator(DescriptorProto descriptor, ProtobufContainer parent, |
56 DescriptorProto descriptor, ProtobufContainer parent, PbMixin defaultMixin
) | 89 PbMixin defaultMixin) |
57 : _descriptor = descriptor, | 90 : _descriptor = descriptor, |
58 _parent = parent, | 91 _parent = parent, |
59 classname = (parent.classname == '') ? | 92 classname = (parent.classname == '') |
60 descriptor.name : '${parent.classname}_${descriptor.name}', | 93 ? descriptor.name |
61 fqname = (parent == null || parent.fqname == null) ? descriptor.name : | 94 : '${parent.classname}_${descriptor.name}', |
62 (parent.fqname == '.' ? | 95 fqname = (parent == null || parent.fqname == null) |
63 '.${descriptor.name}' : '${parent.fqname}.${descriptor.name}'), | 96 ? descriptor.name |
| 97 : (parent.fqname == '.' |
| 98 ? '.${descriptor.name}' |
| 99 : '${parent.fqname}.${descriptor.name}'), |
64 mixin = _getMixin(descriptor, defaultMixin) { | 100 mixin = _getMixin(descriptor, defaultMixin) { |
65 | |
66 for (EnumDescriptorProto e in _descriptor.enumType) { | 101 for (EnumDescriptorProto e in _descriptor.enumType) { |
67 _enumGenerators.add(new EnumGenerator(e, this)); | 102 _enumGenerators.add(new EnumGenerator(e, this)); |
68 } | 103 } |
69 | 104 |
70 for (DescriptorProto n in _descriptor.nestedType) { | 105 for (DescriptorProto n in _descriptor.nestedType) { |
71 _messageGenerators.add( | 106 _messageGenerators.add(new MessageGenerator(n, this, defaultMixin)); |
72 new MessageGenerator(n, this, defaultMixin)); | |
73 } | 107 } |
74 | 108 |
75 for (FieldDescriptorProto x in _descriptor.extension) { | 109 for (FieldDescriptorProto x in _descriptor.extension) { |
76 _extensionGenerators.add(new ExtensionGenerator(x, this)); | 110 _extensionGenerators.add(new ExtensionGenerator(x, this)); |
77 } | 111 } |
78 } | 112 } |
79 | 113 |
80 String get package => _parent.package; | 114 String get package => _parent.package; |
81 | 115 |
82 /// The generator of the .pb.dart file that will declare this type. | 116 /// The generator of the .pb.dart file that will declare this type. |
(...skipping 22 matching lines...) Expand all Loading... |
105 output.addAll(mixin.findMixinsToApply()); | 139 output.addAll(mixin.findMixinsToApply()); |
106 } | 140 } |
107 for (var m in _messageGenerators) { | 141 for (var m in _messageGenerators) { |
108 m.addMixinsTo(output); | 142 m.addMixinsTo(output); |
109 } | 143 } |
110 } | 144 } |
111 | 145 |
112 // Registers message and enum types that can be used elsewhere. | 146 // Registers message and enum types that can be used elsewhere. |
113 void register(GenerationContext ctx) { | 147 void register(GenerationContext ctx) { |
114 ctx.registerFieldType(fqname, this); | 148 ctx.registerFieldType(fqname, this); |
115 for (var m in _messageGenerators) { | 149 for (var m in _messageGenerators) { |
116 m.register(ctx); | 150 m.register(ctx); |
117 } | 151 } |
118 for (var e in _enumGenerators) { | 152 for (var e in _enumGenerators) { |
119 e.register(ctx); | 153 e.register(ctx); |
120 } | 154 } |
121 } | 155 } |
122 | 156 |
123 // Creates fields and resolves extension targets. | 157 // Creates fields and resolves extension targets. |
124 void resolve(GenerationContext ctx) { | 158 void resolve(GenerationContext ctx) { |
125 if (_fieldList != null) throw new StateError("message already resolved"); | 159 if (_fieldList != null) throw new StateError("message already resolved"); |
126 | 160 |
127 var sorted = new List<FieldDescriptorProto>.from(_descriptor.field) | 161 var sorted = new List<FieldDescriptorProto>.from(_descriptor.field) |
128 ..sort((FieldDescriptorProto a, FieldDescriptorProto b) { | 162 ..sort((FieldDescriptorProto a, FieldDescriptorProto b) { |
129 if (a.number < b.number) return -1; | 163 if (a.number < b.number) return -1; |
130 if (a.number > b.number) return 1; | 164 if (a.number > b.number) return 1; |
131 throw "multiple fields defined for tag ${a.number} in $fqname"; | 165 throw "multiple fields defined for tag ${a.number} in $fqname"; |
132 }); | 166 }); |
133 | 167 |
134 _fieldList = <ProtobufField>[]; | 168 _fieldList = <ProtobufField>[]; |
135 for (FieldDescriptorProto field in sorted) { | 169 for (FieldDescriptorProto field in sorted) { |
136 int index = _fieldList.length; | 170 int index = _fieldList.length; |
137 _fieldList.add(new ProtobufField(field, index, this, ctx)); | 171 _fieldList.add(new ProtobufField(field, index, this, ctx)); |
138 } | 172 } |
139 | 173 |
140 for (var m in _messageGenerators) { | 174 for (var m in _messageGenerators) { |
141 m.resolve(ctx); | 175 m.resolve(ctx); |
142 } | 176 } |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
197 for (MessageGenerator m in _messageGenerators) { | 231 for (MessageGenerator m in _messageGenerators) { |
198 m.generate(out); | 232 m.generate(out); |
199 } | 233 } |
200 | 234 |
201 var mixinClause = ''; | 235 var mixinClause = ''; |
202 if (mixin != null) { | 236 if (mixin != null) { |
203 var mixinNames = mixin.findMixinsToApply().map((m) => m.name); | 237 var mixinNames = mixin.findMixinsToApply().map((m) => m.name); |
204 mixinClause = ' with ${mixinNames.join(", ")}'; | 238 mixinClause = ' with ${mixinNames.join(", ")}'; |
205 } | 239 } |
206 | 240 |
207 out.addBlock('class ${classname} extends GeneratedMessage${mixinClause} {', | 241 out.addBlock( |
208 '}', () | 242 'class ${classname} extends GeneratedMessage${mixinClause} {', '}', () { |
209 { | |
210 out.addBlock( | 243 out.addBlock( |
211 'static final BuilderInfo _i = new BuilderInfo(\'${classname}\')', | 244 'static final BuilderInfo _i = new BuilderInfo(\'${classname}\')', |
212 ';', () { | 245 ';', () { |
213 for (ProtobufField field in _fieldList) { | 246 for (ProtobufField field in _fieldList) { |
214 out.println(field.generateBuilderInfoCall(package)); | 247 out.println(field.generateBuilderInfoCall(package)); |
215 } | 248 } |
216 | 249 |
217 if (_descriptor.extensionRange.length > 0) { | 250 if (_descriptor.extensionRange.length > 0) { |
218 out.println('..hasExtensions = true'); | 251 out.println('..hasExtensions = true'); |
219 } | 252 } |
(...skipping 18 matching lines...) Expand all Loading... |
238 out.println('${classname} clone() =>' | 271 out.println('${classname} clone() =>' |
239 ' new ${classname}()..mergeFromMessage(this);'); | 272 ' new ${classname}()..mergeFromMessage(this);'); |
240 | 273 |
241 out.println('BuilderInfo get info_ => _i;'); | 274 out.println('BuilderInfo get info_ => _i;'); |
242 | 275 |
243 // Factory functions which can be used as default value closures. | 276 // Factory functions which can be used as default value closures. |
244 out.println('static ${classname} create() =>' | 277 out.println('static ${classname} create() =>' |
245 ' new ${classname}();'); | 278 ' new ${classname}();'); |
246 out.println('static PbList<${classname}> createRepeated() =>' | 279 out.println('static PbList<${classname}> createRepeated() =>' |
247 ' new PbList<${classname}>();'); | 280 ' new PbList<${classname}>();'); |
248 out.addBlock('static ${classname} getDefault() {', | 281 out.addBlock('static ${classname} getDefault() {', '}', () { |
249 '}', () { | 282 out.println( |
250 out.println('if (_defaultInstance == null) _defaultInstance = new _Reado
nly${classname}();'); | 283 'if (_defaultInstance == null) _defaultInstance = new _Readonly${cla
ssname}();'); |
251 out.println('return _defaultInstance;'); | 284 out.println('return _defaultInstance;'); |
252 }); | 285 }); |
253 out.println('static ${classname} _defaultInstance;'); | 286 out.println('static ${classname} _defaultInstance;'); |
254 out.addBlock('static void $checkItem($classname v) {', '}', () { | 287 out.addBlock('static void $checkItem($classname v) {', '}', () { |
255 out.println('if (v is !$classname)' | 288 out.println('if (v is !$classname)' |
256 " checkItemFailed(v, '$classname');"); | 289 " checkItemFailed(v, '$classname');"); |
257 }); | 290 }); |
258 generateFieldsAccessorsMutators(out); | 291 generateFieldsAccessorsMutators(out); |
259 }); | 292 }); |
260 out.println(); | 293 out.println(); |
261 | 294 |
262 out.println('class _Readonly${classname} extends ${classname} with ReadonlyM
essageMixin {}'); | 295 out.println( |
| 296 'class _Readonly${classname} extends ${classname} with ReadonlyMessageMi
xin {}'); |
263 out.println(); | 297 out.println(); |
264 } | 298 } |
265 | 299 |
266 // Returns true if the message type has any required fields. If it doesn't, | 300 // Returns true if the message type has any required fields. If it doesn't, |
267 // we can optimize out calls to its isInitialized()/_findInvalidFields() | 301 // we can optimize out calls to its isInitialized()/_findInvalidFields() |
268 // methods. | 302 // methods. |
269 // | 303 // |
270 // already_seen is used to avoid checking the same type multiple times | 304 // already_seen is used to avoid checking the same type multiple times |
271 // (and also to protect against unbounded recursion). | 305 // (and also to protect against unbounded recursion). |
272 bool _hasRequiredFields(MessageGenerator type, Set alreadySeen) { | 306 bool _hasRequiredFields(MessageGenerator type, Set alreadySeen) { |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
308 void generateFieldsAccessorsMutators(IndentingWriter out) { | 342 void generateFieldsAccessorsMutators(IndentingWriter out) { |
309 for (ProtobufField field in _fieldList) { | 343 for (ProtobufField field in _fieldList) { |
310 out.println(); | 344 out.println(); |
311 | 345 |
312 // Choose non-conflicting names. | 346 // Choose non-conflicting names. |
313 String identifier = field.dartFieldName; | 347 String identifier = field.dartFieldName; |
314 String hasIdentifier = field.hasMethodName; | 348 String hasIdentifier = field.hasMethodName; |
315 String clearIdentifier = field.clearMethodName; | 349 String clearIdentifier = field.clearMethodName; |
316 if (!field.isRepeated) { | 350 if (!field.isRepeated) { |
317 while (_methodNames.contains(identifier) || | 351 while (_methodNames.contains(identifier) || |
318 _methodNames.contains(hasIdentifier) || | 352 _methodNames.contains(hasIdentifier) || |
319 _methodNames.contains(clearIdentifier)) { | 353 _methodNames.contains(clearIdentifier)) { |
320 identifier += '_' + field.number.toString(); | 354 identifier += '_' + field.number.toString(); |
321 hasIdentifier += '_' + field.number.toString(); | 355 hasIdentifier += '_' + field.number.toString(); |
322 clearIdentifier += '_' + field.number.toString(); | 356 clearIdentifier += '_' + field.number.toString(); |
323 } | 357 } |
324 _methodNames.add(identifier); | 358 _methodNames.add(identifier); |
325 _methodNames.add(hasIdentifier); | 359 _methodNames.add(hasIdentifier); |
326 _methodNames.add(clearIdentifier); | 360 _methodNames.add(clearIdentifier); |
327 } else { | 361 } else { |
328 while (_methodNames.contains(identifier)) { | 362 while (_methodNames.contains(identifier)) { |
329 identifier += '_' + field.number.toString(); | 363 identifier += '_' + field.number.toString(); |
330 } | 364 } |
331 _methodNames.add(identifier); | 365 _methodNames.add(identifier); |
332 } | 366 } |
333 | 367 |
334 var fieldTypeString = field.getDartType(package); | 368 var fieldTypeString = field.getDartType(package); |
335 var defaultExpr = field.getDefaultExpr(); | 369 var defaultExpr = field.getDefaultExpr(); |
336 out.println('${fieldTypeString} get ${identifier}' | 370 out.println('${fieldTypeString} get ${identifier}' |
337 ' => \$_get(${field.index}, ${field.number}, $defaultExpr);'); | 371 ' => \$_get(' |
| 372 '${field.index}, ${field.number}, $defaultExpr);'); |
338 if (!field.isRepeated) { | 373 if (!field.isRepeated) { |
339 var fastSetter = field.baseType.setter; | 374 var fastSetter = field.baseType.setter; |
340 if (fastSetter != null) { | 375 if (fastSetter != null) { |
341 out.println('void set $identifier' | 376 out.println('void set $identifier' |
342 '($fieldTypeString v) { ' | 377 '($fieldTypeString v) { ' |
343 '$fastSetter(${field.index}, ${field.number}, v);' | 378 '$fastSetter(${field.index}, ${field.number}, v);' |
344 ' }'); | 379 ' }'); |
345 } else { | 380 } else { |
346 out.println('void set $identifier' | 381 out.println('void set $identifier' |
347 '($fieldTypeString v) { ' | 382 '($fieldTypeString v) { ' |
(...skipping 13 matching lines...) Expand all Loading... |
361 /// to avoid duplication. | 396 /// to avoid duplication. |
362 void generateConstants(IndentingWriter out) { | 397 void generateConstants(IndentingWriter out) { |
363 const nestedTypeTag = 3; | 398 const nestedTypeTag = 3; |
364 const enumTypeTag = 4; | 399 const enumTypeTag = 4; |
365 assert(_descriptor.info_.fieldInfo[nestedTypeTag].name == "nestedType"); | 400 assert(_descriptor.info_.fieldInfo[nestedTypeTag].name == "nestedType"); |
366 assert(_descriptor.info_.fieldInfo[enumTypeTag].name == "enumType"); | 401 assert(_descriptor.info_.fieldInfo[enumTypeTag].name == "enumType"); |
367 | 402 |
368 var name = getJsonConstant(fileGen); | 403 var name = getJsonConstant(fileGen); |
369 var json = _descriptor.writeToJsonMap(); | 404 var json = _descriptor.writeToJsonMap(); |
370 var nestedTypeNames = | 405 var nestedTypeNames = |
371 _messageGenerators.map((m) => m.getJsonConstant(fileGen)) | 406 _messageGenerators.map((m) => m.getJsonConstant(fileGen)).toList(); |
372 .toList(); | |
373 var nestedEnumNames = | 407 var nestedEnumNames = |
374 _enumGenerators.map((e) => e.getJsonConstant(fileGen)) | 408 _enumGenerators.map((e) => e.getJsonConstant(fileGen)).toList(); |
375 .toList(); | |
376 | 409 |
377 out.addBlock("const $name = const {", "};", () { | 410 out.addBlock("const $name = const {", "};", () { |
378 for (var key in json.keys) { | 411 for (var key in json.keys) { |
379 out.print("'$key': "); | 412 out.print("'$key': "); |
380 if (key == "$nestedTypeTag") { | 413 if (key == "$nestedTypeTag") { |
381 // refer to message constants by name instead of repeating each value | 414 // refer to message constants by name instead of repeating each value |
382 out.println("const [${nestedTypeNames.join(", ")}],"); | 415 out.println("const [${nestedTypeNames.join(", ")}],"); |
383 continue; | 416 continue; |
384 } else if (key == "$enumTypeTag") { | 417 } else if (key == "$enumTypeTag") { |
385 // refer to enum constants by name | 418 // refer to enum constants by name |
386 out.println("const [${nestedEnumNames.join(", ")}],"); | 419 out.println("const [${nestedEnumNames.join(", ")}],"); |
387 continue; | 420 continue; |
388 } | 421 } |
389 writeJsonConst(out, json[key]); | 422 writeJsonConst(out, json[key]); |
390 out.println(","); | 423 out.println(","); |
391 } | 424 } |
392 }); | 425 }); |
393 out.println(); | 426 out.println(); |
394 | 427 |
395 for (var m in _messageGenerators) { | 428 for (var m in _messageGenerators) { |
396 m.generateConstants(out); | 429 m.generateConstants(out); |
397 } | 430 } |
398 | 431 |
399 for (var e in _enumGenerators) { | 432 for (var e in _enumGenerators) { |
400 e.generateConstants(out); | 433 e.generateConstants(out); |
401 } | 434 } |
402 } | 435 } |
403 } | 436 } |
OLD | NEW |