| 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 | |
| 8 /// to check its type and range. | |
| 9 const checkItem = '\$checkItem'; | |
| 10 | |
| 11 class MessageGenerator extends ProtobufContainer { | 7 class MessageGenerator extends ProtobufContainer { |
| 12 // List of Dart language reserved words in names which cannot be used in a | |
| 13 // subclass of GeneratedMessage. | |
| 14 static final List<String> reservedWords = [ | |
| 15 'assert', | |
| 16 'break', | |
| 17 'case', | |
| 18 'catch', | |
| 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 ]; | |
| 49 | |
| 50 // List of names used in the generated class itself | |
| 51 static final List<String> generatedNames = [ | |
| 52 'create', | |
| 53 'createRepeated', | |
| 54 'getDefault', | |
| 55 checkItem | |
| 56 ]; | |
| 57 | |
| 58 // Returns the mixin for this message, or null if none. | 8 // Returns the mixin for this message, or null if none. |
| 59 static PbMixin _getMixin(DescriptorProto desc, PbMixin defaultValue) { | 9 static PbMixin _getMixin(DescriptorProto desc, PbMixin defaultValue) { |
| 60 if (!desc.hasOptions()) return defaultValue; | 10 if (!desc.hasOptions()) return defaultValue; |
| 61 if (!desc.options.hasExtension(Dart_options.mixin)) return defaultValue; | 11 if (!desc.options.hasExtension(Dart_options.mixin)) return defaultValue; |
| 62 | 12 |
| 63 String name = desc.options.getExtension(Dart_options.mixin); | 13 String name = desc.options.getExtension(Dart_options.mixin); |
| 64 if (name.isEmpty) return null; // don't use a mixin (override any default) | 14 if (name.isEmpty) return null; // don't use a mixin (override any default) |
| 65 var mixin = findMixin(name); | 15 var mixin = findMixin(name); |
| 66 if (mixin == null) { | 16 if (mixin == null) { |
| 67 throw ("unknown mixin class: ${name}"); | 17 throw ("unknown mixin class: ${name}"); |
| 68 } | 18 } |
| 69 return mixin; | 19 return mixin; |
| 70 } | 20 } |
| 71 | 21 |
| 72 final String classname; | 22 final String classname; |
| 73 final String fqname; | 23 final String fqname; |
| 74 final PbMixin mixin; | 24 final PbMixin mixin; |
| 75 | 25 |
| 76 final ProtobufContainer _parent; | 26 final ProtobufContainer _parent; |
| 77 final DescriptorProto _descriptor; | 27 final DescriptorProto _descriptor; |
| 78 final List<EnumGenerator> _enumGenerators = <EnumGenerator>[]; | 28 final List<EnumGenerator> _enumGenerators = <EnumGenerator>[]; |
| 79 final List<MessageGenerator> _messageGenerators = <MessageGenerator>[]; | 29 final List<MessageGenerator> _messageGenerators = <MessageGenerator>[]; |
| 80 final List<ExtensionGenerator> _extensionGenerators = <ExtensionGenerator>[]; | 30 final List<ExtensionGenerator> _extensionGenerators = <ExtensionGenerator>[]; |
| 81 | 31 |
| 82 // populated by resolve() | 32 // populated by resolve() |
| 83 List<ProtobufField> _fieldList; | 33 List<ProtobufField> _fieldList; |
| 84 | 34 |
| 85 // Used during generation. | |
| 86 final Set<String> _methodNames = new Set<String>(); | |
| 87 | |
| 88 MessageGenerator(DescriptorProto descriptor, ProtobufContainer parent, | 35 MessageGenerator(DescriptorProto descriptor, ProtobufContainer parent, |
| 89 PbMixin defaultMixin) | 36 PbMixin defaultMixin) |
| 90 : _descriptor = descriptor, | 37 : _descriptor = descriptor, |
| 91 _parent = parent, | 38 _parent = parent, |
| 92 classname = (parent.classname == '') | 39 classname = (parent.classname == '') |
| 93 ? descriptor.name | 40 ? descriptor.name |
| 94 : '${parent.classname}_${descriptor.name}', | 41 : '${parent.classname}_${descriptor.name}', |
| 95 fqname = (parent == null || parent.fqname == null) | 42 fqname = (parent == null || parent.fqname == null) |
| 96 ? descriptor.name | 43 ? descriptor.name |
| 97 : (parent.fqname == '.' | 44 : (parent.fqname == '.' |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 151 } | 98 } |
| 152 for (var e in _enumGenerators) { | 99 for (var e in _enumGenerators) { |
| 153 e.register(ctx); | 100 e.register(ctx); |
| 154 } | 101 } |
| 155 } | 102 } |
| 156 | 103 |
| 157 // Creates fields and resolves extension targets. | 104 // Creates fields and resolves extension targets. |
| 158 void resolve(GenerationContext ctx) { | 105 void resolve(GenerationContext ctx) { |
| 159 if (_fieldList != null) throw new StateError("message already resolved"); | 106 if (_fieldList != null) throw new StateError("message already resolved"); |
| 160 | 107 |
| 161 var sorted = new List<FieldDescriptorProto>.from(_descriptor.field) | 108 var reserved = mixin?.findReservedNames() ?? const <String>[]; |
| 162 ..sort((FieldDescriptorProto a, FieldDescriptorProto b) { | 109 var fields = messageFieldNames(_descriptor, reserved: reserved); |
| 163 if (a.number < b.number) return -1; | |
| 164 if (a.number > b.number) return 1; | |
| 165 throw "multiple fields defined for tag ${a.number} in $fqname"; | |
| 166 }); | |
| 167 | 110 |
| 168 _fieldList = <ProtobufField>[]; | 111 _fieldList = <ProtobufField>[]; |
| 169 for (FieldDescriptorProto field in sorted) { | 112 for (MemberNames names in fields.values) { |
| 170 int index = _fieldList.length; | 113 _fieldList.add(new ProtobufField.message(names, this, ctx)); |
| 171 _fieldList.add(new ProtobufField(field, index, this, ctx)); | |
| 172 } | 114 } |
| 173 | 115 |
| 174 for (var m in _messageGenerators) { | 116 for (var m in _messageGenerators) { |
| 175 m.resolve(ctx); | 117 m.resolve(ctx); |
| 176 } | 118 } |
| 177 for (var x in _extensionGenerators) { | 119 for (var x in _extensionGenerators) { |
| 178 x.resolve(ctx); | 120 x.resolve(ctx); |
| 179 } | 121 } |
| 180 } | 122 } |
| 181 | 123 |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 235 m.addConstantImportsTo(imports); | 177 m.addConstantImportsTo(imports); |
| 236 } | 178 } |
| 237 for (var x in _extensionGenerators) { | 179 for (var x in _extensionGenerators) { |
| 238 x.addConstantImportsTo(imports); | 180 x.addConstantImportsTo(imports); |
| 239 } | 181 } |
| 240 } | 182 } |
| 241 | 183 |
| 242 void generate(IndentingWriter out) { | 184 void generate(IndentingWriter out) { |
| 243 checkResolved(); | 185 checkResolved(); |
| 244 | 186 |
| 245 _methodNames.clear(); | |
| 246 _methodNames.addAll(reservedWords); | |
| 247 _methodNames.addAll(GeneratedMessage_reservedNames); | |
| 248 _methodNames.addAll(generatedNames); | |
| 249 | |
| 250 if (mixin != null) { | |
| 251 _methodNames.addAll(mixin.findReservedNames()); | |
| 252 } | |
| 253 | |
| 254 for (MessageGenerator m in _messageGenerators) { | 187 for (MessageGenerator m in _messageGenerators) { |
| 255 m.generate(out); | 188 m.generate(out); |
| 256 } | 189 } |
| 257 | 190 |
| 258 var mixinClause = ''; | 191 var mixinClause = ''; |
| 259 if (mixin != null) { | 192 if (mixin != null) { |
| 260 var mixinNames = mixin.findMixinsToApply().map((m) => m.name); | 193 var mixinNames = mixin.findMixinsToApply().map((m) => m.name); |
| 261 mixinClause = ' with ${mixinNames.join(", ")}'; | 194 mixinClause = ' with ${mixinNames.join(", ")}'; |
| 262 } | 195 } |
| 263 | 196 |
| 264 out.addBlock( | 197 out.addBlock( |
| 265 'class ${classname} extends GeneratedMessage${mixinClause} {', '}', () { | 198 'class ${classname} extends GeneratedMessage${mixinClause} {', '}', () { |
| 266 out.addBlock( | 199 out.addBlock( |
| 267 'static final BuilderInfo _i = new BuilderInfo(\'${classname}\')', | 200 'static final BuilderInfo _i = new BuilderInfo(\'${classname}\')', |
| 268 ';', () { | 201 ';', () { |
| 269 for (ProtobufField field in _fieldList) { | 202 for (ProtobufField field in _fieldList) { |
| 270 out.println(field.generateBuilderInfoCall(package)); | 203 var dartFieldName = field.memberNames.fieldName; |
| 204 out.println(field.generateBuilderInfoCall(package, dartFieldName)); |
| 271 } | 205 } |
| 272 | 206 |
| 273 if (_descriptor.extensionRange.length > 0) { | 207 if (_descriptor.extensionRange.length > 0) { |
| 274 out.println('..hasExtensions = true'); | 208 out.println('..hasExtensions = true'); |
| 275 } | 209 } |
| 276 if (!_hasRequiredFields(this, new Set())) { | 210 if (!_hasRequiredFields(this, new Set())) { |
| 277 out.println('..hasRequiredFields = false'); | 211 out.println('..hasRequiredFields = false'); |
| 278 } | 212 } |
| 279 }); | 213 }); |
| 280 | 214 |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 359 } | 293 } |
| 360 } | 294 } |
| 361 } | 295 } |
| 362 return false; | 296 return false; |
| 363 } | 297 } |
| 364 | 298 |
| 365 void generateFieldsAccessorsMutators(IndentingWriter out) { | 299 void generateFieldsAccessorsMutators(IndentingWriter out) { |
| 366 for (ProtobufField field in _fieldList) { | 300 for (ProtobufField field in _fieldList) { |
| 367 out.println(); | 301 out.println(); |
| 368 | 302 |
| 369 // Choose non-conflicting names. | |
| 370 String identifier = field.dartFieldName; | |
| 371 String hasIdentifier = field.hasMethodName; | |
| 372 String clearIdentifier = field.clearMethodName; | |
| 373 if (!field.isRepeated) { | |
| 374 while (_methodNames.contains(identifier) || | |
| 375 _methodNames.contains(hasIdentifier) || | |
| 376 _methodNames.contains(clearIdentifier)) { | |
| 377 identifier += '_' + field.number.toString(); | |
| 378 hasIdentifier += '_' + field.number.toString(); | |
| 379 clearIdentifier += '_' + field.number.toString(); | |
| 380 } | |
| 381 _methodNames.add(identifier); | |
| 382 _methodNames.add(hasIdentifier); | |
| 383 _methodNames.add(clearIdentifier); | |
| 384 } else { | |
| 385 while (_methodNames.contains(identifier)) { | |
| 386 identifier += '_' + field.number.toString(); | |
| 387 } | |
| 388 _methodNames.add(identifier); | |
| 389 } | |
| 390 | |
| 391 var fieldTypeString = field.getDartType(package); | 303 var fieldTypeString = field.getDartType(package); |
| 392 var defaultExpr = field.getDefaultExpr(); | 304 var defaultExpr = field.getDefaultExpr(); |
| 393 out.println('${fieldTypeString} get ${identifier}' | 305 var names = field.memberNames; |
| 306 |
| 307 out.println('${fieldTypeString} get ${names.fieldName}' |
| 394 ' => \$_get(' | 308 ' => \$_get(' |
| 395 '${field.index}, ${field.number}, $defaultExpr);'); | 309 '${field.index}, ${field.number}, $defaultExpr);'); |
| 396 if (!field.isRepeated) { | 310 if (!field.isRepeated) { |
| 397 var fastSetter = field.baseType.setter; | 311 var fastSetter = field.baseType.setter; |
| 398 if (fastSetter != null) { | 312 if (fastSetter != null) { |
| 399 out.println('void set $identifier' | 313 out.println('void set ${names.fieldName}' |
| 400 '($fieldTypeString v) { ' | 314 '($fieldTypeString v) { ' |
| 401 '$fastSetter(${field.index}, ${field.number}, v);' | 315 '$fastSetter(${field.index}, ${field.number}, v);' |
| 402 ' }'); | 316 ' }'); |
| 403 } else { | 317 } else { |
| 404 out.println('void set $identifier' | 318 out.println('void set ${names.fieldName}' |
| 405 '($fieldTypeString v) { ' | 319 '($fieldTypeString v) { ' |
| 406 'setField(${field.number}, v);' | 320 'setField(${field.number}, v);' |
| 407 ' }'); | 321 ' }'); |
| 408 } | 322 } |
| 409 out.println('bool $hasIdentifier() =>' | 323 out.println('bool ${names.hasMethodName}() =>' |
| 410 ' \$_has(${field.index}, ${field.number});'); | 324 ' \$_has(${field.index}, ${field.number});'); |
| 411 out.println('void $clearIdentifier() =>' | 325 out.println('void ${names.clearMethodName}() =>' |
| 412 ' clearField(${field.number});'); | 326 ' clearField(${field.number});'); |
| 413 } | 327 } |
| 414 } | 328 } |
| 415 } | 329 } |
| 416 | 330 |
| 417 void generateEnums(IndentingWriter out) { | 331 void generateEnums(IndentingWriter out) { |
| 418 for (EnumGenerator e in _enumGenerators) { | 332 for (EnumGenerator e in _enumGenerators) { |
| 419 e.generate(out); | 333 e.generate(out); |
| 420 } | 334 } |
| 421 | 335 |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 460 | 374 |
| 461 for (var m in _messageGenerators) { | 375 for (var m in _messageGenerators) { |
| 462 m.generateConstants(out); | 376 m.generateConstants(out); |
| 463 } | 377 } |
| 464 | 378 |
| 465 for (var e in _enumGenerators) { | 379 for (var e in _enumGenerators) { |
| 466 e.generateConstants(out); | 380 e.generateConstants(out); |
| 467 } | 381 } |
| 468 } | 382 } |
| 469 } | 383 } |
| OLD | NEW |