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

Unified Diff: lib/protobuf/plugin/MessageGenerator.dart

Issue 10595002: Protocol Buffer runtime library and 'protoc' plugin (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Work around http://code.google.com/p/dart/issues/detail?id=3806 Created 8 years, 6 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « lib/protobuf/plugin/IndentingWriter.dart ('k') | lib/protobuf/plugin/ProtoGenDartConfig.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/protobuf/plugin/MessageGenerator.dart
diff --git a/lib/protobuf/plugin/MessageGenerator.dart b/lib/protobuf/plugin/MessageGenerator.dart
new file mode 100644
index 0000000000000000000000000000000000000000..d9d5e71df2489a9cdce2f539bccda77f64727c93
--- /dev/null
+++ b/lib/protobuf/plugin/MessageGenerator.dart
@@ -0,0 +1,311 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class MessageGenerator implements ProtobufContainer {
+
+ // Variables controlling output prettiness
+ static final String sp = " ";
+ static final bool _blankLines = true;
+ static final bool _fieldComments = true;
+
+ String _builderClassname;
+ String _classname;
+ GenerationContext _context;
+ final GoogleProtobuf_DescriptorProto _descriptor;
+ List<EnumGenerator> _enumGenerators;
+ List<ProtobufField> _fieldList;
+ String _fqname;
+ List<MessageGenerator> _messageGenerators;
+ List<ExtensionGenerator> _extensionGenerators;
+ GoogleProtobuf_FileOptions_OptimizeMode _optimizeFor;
+ ProtobufContainer _parent;
+
+ String get classname() => _classname;
+ String get fqname() => _fqname;
+ GoogleProtobuf_FileOptions_OptimizeMode get optimizeFor() => _optimizeFor;
+
+ MessageGenerator(GoogleProtobuf_DescriptorProto this._descriptor,
+ ProtobufContainer this._parent, GenerationContext this._context) {
+ String name = _descriptor.name;
+ _classname = (_parent === null || _parent.classname == "") ?
+ name :
+ "${_parent.classname}_${name}";
+
+ _builderClassname = "${_classname}_Builder";
+ _fqname = (_parent === null || _parent.fqname === null) ? _descriptor.name :
+ ( _parent.fqname == "." ?
+ ".${_descriptor.name}" :
+ "${_parent.fqname}.${_descriptor.name}" );
+ _optimizeFor = _parent != null ? _parent.optimizeFor : null;
+ _context.register(this);
+
+ _fieldList = [];
+
+ _enumGenerators = new List<EnumGenerator>();
+ for (GoogleProtobuf_EnumDescriptorProto e in _descriptor.enumType) {
+ _enumGenerators.add(new EnumGenerator(e, this, _context));
+ }
+
+ _messageGenerators = new List<MessageGenerator>();
+ for (GoogleProtobuf_DescriptorProto n in _descriptor.nestedType) {
+ _messageGenerators.add(new MessageGenerator(n, this, _context));
+ }
+
+ _extensionGenerators = new List<ExtensionGenerator>();
+ for (GoogleProtobuf_FieldDescriptorProto x in _descriptor.extension) {
+ _extensionGenerators.add(new ExtensionGenerator(x, this, _context));
+ }
+ }
+
+ void initializeFields() {
+ _fieldList = [];
+ ProtobufField._resetIndices();
+ for (GoogleProtobuf_FieldDescriptorProto field in _descriptor.field) {
+ _fieldList.add(new ProtobufField(field, _context));
+ }
+ for (MessageGenerator m in _messageGenerators) {
+ m.initializeFields();
+ }
+ }
+
+ void generate(IndentingWriter out,
+ [List<ExtensionGenerator> allExtensions = null]) {
+ for (EnumGenerator e in _enumGenerators) {
+ e.generate(out);
+ }
+
+ for (MessageGenerator m in _messageGenerators) {
+ m.generate(out, allExtensions);
+ }
+
+ out.addBlock("class ${_classname} extends GeneratedMessage${sp}{", "}", (){
+ for (ExtensionGenerator x in _extensionGenerators) {
+ if (allExtensions != null) {
+ allExtensions.add(x);
+ }
+ x.generate(out);
+ }
+
+ out.println("static ${_classname} _d;");
+ out.println("static ${_builderClassname} newBuilder()${sp}=>"
+ "${sp}new ${_builderClassname}();");
+ out.println("static ${_classname} get defaultInstance()${sp}=>"
+ "${sp}null${sp}==${sp}_d${sp}?${sp}(_d${sp}=${sp}newBuilder()."
+ "buildPartial())${sp}:${sp}_d;");
+ out.println("static ${_classname} parseFromBuffer(List<int> i,"
+ "${sp}[ExtensionRegistry r])"
+ "${sp}=>${sp}GeneratedMessage.parseBuffer(newBuilder(),"
+ "${sp}i,${sp}r);");
+ out.println("static Future<${_classname}> parseFromStream("
+ "InputStream i,${sp}[ExtensionRegistry r])${sp}=>${sp}"
+ "GeneratedMessage.parseStream(newBuilder(),${sp}i,${sp}r);");
+ out.println("static ${_classname} parseFromJson("
+ "String i,"
+ "${sp}[ExtensionRegistry r])"
+ "${sp}=>${sp}GeneratedMessage.parseJson(newBuilder(),${sp}i,${sp}r);");
+ out.println("${_classname}._fromBuilder(${_builderClassname} b)"
+ "${sp}:${sp}super(b);");
+ out.println("${_builderClassname} toBuilder()"
+ "${sp}=>${sp}newBuilder().mergeFromMessage(this);");
+
+ generateFields(out);
+ });
+
+ // -------------------------- BUILDER --------------------------
+ out.blankLine();
+ out.addBlock("class ${_builderClassname} extends Builder${sp}{",
+ "}", ()
+ {
+ out.println("static BuilderInfo _i;");
+
+ if (_blankLines) {
+ out.blankLine();
+ }
+ out.addBlock("void initialize_()${sp}{","}",(){
+ out.addBlock("if${sp}(null${sp}==${sp}_i)${sp}{", "}", () {
+ out.println("_i${sp}=${sp}new BuilderInfo(this,${sp}"
+ "\"${_classname}\");");
+
+ for (ProtobufField field in _fieldList) {
+ String type = field.shortTypeName;
+
+ String makeDefault = null;
+ if (field.hasInitialization) {
+ makeDefault = "${field.initialization}";
+ }
+ String subBuilder = null;
+ if (field.message || field.group) {
+ subBuilder = "()${sp}=>${sp}new ${field.baseType}_Builder()";
+ }
+ String valueOf = null;
+ if (field.enum) {
+ valueOf = "(var v)${sp}=>${sp}${field.baseType}.valueOf(v)";
+ }
+ if ("PM" == type) {
+ // Repeated message: default is an empty list
+ out.println("_i.m(${field.number},${sp}'"
+ "${field.externalFieldName}',${sp}$subBuilder,"
+ "${sp}()${sp}=>${sp}new PbList<${field.baseType}>(this));");
+ } else if (type[0] == "P" && type != "PG" && type != "PE") {
+ // Repeated, not a message or enum: default is an empty list,
+ // subBuilder is null, valueOf is null
+ out.println("_i.p(${field.number},${sp}"
+ "'${field.externalFieldName}',${sp}Builder.$type);");
+ } else if (type == "OE" || type == "QE") {
+ out.println("_i.e(${field.number},${sp}"
+ "'${field.externalFieldName}',${sp}Builder.$type,"
+ "${sp}$makeDefault,${sp}$valueOf);");
+ } else {
+ if (makeDefault == null && subBuilder == null && valueOf == null) {
+ out.println("_i.a(${field.number},${sp}"
+ "'${field.externalFieldName}',${sp}Builder.$type);");
+ } else if (subBuilder == null && valueOf == null) {
+ out.println("_i.a(${field.number},${sp}"
+ "'${field.externalFieldName}',${sp}Builder.$type,"
+ "${sp}$makeDefault);");
+ } else if (valueOf == null) {
+ out.println("_i.a(${field.number},${sp}"
+ "'${field.externalFieldName}',${sp}Builder.$type,"
+ "${sp}$makeDefault,${sp}$subBuilder);");
+ } else {
+ out.println("_i.a(${field.number},${sp}"
+ "'${field.externalFieldName}',${sp}Builder.$type,"
+ "${sp}$makeDefault,${sp}$subBuilder,${sp}$valueOf);");
+ }
+ }
+ }
+
+ if (_descriptor.extensionRange.length > 0) {
+ out.println("_i.hasExtensions${sp}=${sp}true;");
+ }
+ if (!_hasRequiredFields(this, new Set())) {
+ out.println("_i.hasRequiredFields${sp}=${sp}false;");
+ }
+ });
+ });
+
+ if (_blankLines) {
+ out.blankLine();
+ }
+ out.println("$_classname build()${sp}=>${sp}super.build();");
+ out.println("$_classname buildPartial()${sp}=>${sp}"
+ "partial(new ${_classname}._fromBuilder(this));");
+ out.println("BuilderInfo get info_()${sp}=>${sp}_i;");
+
+ generateFieldsAccessorsMutators(out);
+ });
+ out.blankLine();
+ }
+
+ void generateFields(IndentingWriter out) {
+
+//
+// Disable 'noSuchMethod' dependency for now until dart2js code generation
+// improves
+//
+
+// if (optimizeFor == GoogleProtobuf_FileOptions_OptimizeMode.SPEED) {
+ for (ProtobufField field in _fieldList) {
+ if (_blankLines) {
+ out.blankLine();
+ }
+
+ String label = field.label.name.substring(6).toLowerCase();
+ String type = field.type.name.substring(5).toLowerCase();
+ if ("message" == type || "group" == type) {
+ type = field.typeName.substring(1);
+ }
+ String options = "";
+ if ((field.options != null) && field.options.packed) {
+ if (options.length == 0) {
+ options = " [";
+ }
+ options = "${options}packed=true";
+ }
+ if (options.length > 0) {
+ options = "${options}]";
+ }
+ if (_fieldComments) {
+ out.println("// $label $type ${field.name}${sp}=${sp}"
+ "${field.number}${options};");
+ }
+ out.println(
+ "${field.typeString} get ${field.externalFieldName}()${sp}=>"
+ "${sp}g_(${field.number});");
+ if (field.single) {
+ out.println("bool has${field.titlecaseFieldName}()${sp}=>"
+ "${sp}h_(${field.number});");
+ }
+// }
+ }
+ }
+
+ // Returns true if the message type has any required fields. If it doesn't,
+ // we can optimize out calls to its isInitialized()/_findInvalidFields()
+ // methods.
+ //
+ // already_seen is used to avoid checking the same type multiple times
+ // (and also to protect against unbounded recursion).
+ bool _hasRequiredFields(MessageGenerator type, Set alreadySeen) {
+ if (alreadySeen.contains(type._fqname)) {
+ // The type is already in cache. This means that either:
+ // a. The type has no required fields.
+ // b. We are in the midst of checking if the type has required fields,
+ // somewhere up the stack. In this case, we know that if the type
+ // has any required fields, they'll be found when we return to it,
+ // and the whole call to HasRequiredFields() will return true.
+ // Therefore, we don't have to check if this type has required fields
+ // here.
+ return false;
+ }
+ alreadySeen.add(type._fqname);
+ // If the type has extensions, an extension with message type could contain
+ // required fields, so we have to be conservative and assume such an
+ // extension exists.
+ if (type._descriptor.extensionRange.length > 0) {
+ return true;
+ }
+
+ for (ProtobufField field in type._fieldList) {
+ if (field.required) {
+ return true;
+ }
+ if (field.message) {
+ ProtobufContainer messageType = _context[field.typeName];
+ if (messageType != null && messageType is MessageGenerator) {
+ if (_hasRequiredFields(messageType, alreadySeen)) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ void generateFieldsAccessorsMutators(IndentingWriter out) {
+ for (ProtobufField field in _fieldList) {
+//
+// Disable code size optimization for now until dart2js code generation
+// is better able to handle 'noSuchMethod'
+//
+
+// if (optimizeFor == GoogleProtobuf_FileOptions_OptimizeMode.SPEED) {
+ if (_blankLines) {
+ out.blankLine();
+ }
+ out.println("${field.typeString} get ${field.externalFieldName}()"
+ "${sp}=>${sp}g_(${field.number});");
+ if (field.single) {
+ out.println("void set ${field.externalFieldName}"
+ "(${field.typeString} v)${sp}"
+ "{${sp}s_(${field.number},${sp}v);${sp}}");
+ out.println("bool has${field.titlecaseFieldName}()${sp}=>"
+ "${sp}h_(${field.number});");
+ out.println("void clear${field.titlecaseFieldName}()${sp}=>"
+ "${sp}c_(${field.number});");
+ }
+// }
+ }
+ }
+}
« no previous file with comments | « lib/protobuf/plugin/IndentingWriter.dart ('k') | lib/protobuf/plugin/ProtoGenDartConfig.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698