Protobuf: prettified generated code

This commit is contained in:
dsavvinov
2016-08-08 18:42:34 +03:00
parent 4779d517d9
commit 02225601e2
4 changed files with 70 additions and 24 deletions
@@ -21,31 +21,33 @@ void ClassGenerator::generateCode(io::Printer *printer, bool isBuilder) const {
generateHeader(printer, isBuilder); generateHeader(printer, isBuilder);
printer->Indent(); printer->Indent();
/* // Generate code for property declaration
* Field generator should know if it is generating code for builder printer->Print("//========== Properties ===========\n");
* or for fair class to choose between 'val' and 'var'.
* Also note that fields should be declared before init section.
*/
for (FieldGenerator *gen: properties) { for (FieldGenerator *gen: properties) {
gen->generateCode(printer, isBuilder); gen->generateCode(printer, isBuilder);
printer->Print("\n"); printer->Print("\n");
} }
// Generate field for errors code // Generate field for errors code
printer->Print("\n"); printer->Print("var errorCode: Int = 0\n\n");
printer->Print("var errorCode: Int = 0\n");
printer->Print("\n");
generateInitSection(printer); generateInitSection(printer);
printer->Print("\n");
// enum declarations and nested classes declarations only for fair classes // enum declarations and nested classes declarations only for fair classes
if (!isBuilder) { if (!isBuilder) {
if (enumsDeclaraions.size() > 0) {
printer->Print("//========== Nested enums declarations ===========\n");
}
for (EnumGenerator *gen: enumsDeclaraions) { for (EnumGenerator *gen: enumsDeclaraions) {
gen->generateCode(printer); gen->generateCode(printer);
printer->Print("\n"); printer->Print("\n");
} }
if (classesDeclarations.size() > 0) {
printer->Print("//========== Nested classes declarations ===========\n");
}
for (ClassGenerator *gen: classesDeclarations) { for (ClassGenerator *gen: classesDeclarations) {
gen->generateCode(printer); gen->generateCode(printer);
printer->Print("\n"); printer->Print("\n");
@@ -53,30 +55,37 @@ void ClassGenerator::generateCode(io::Printer *printer, bool isBuilder) const {
} }
// write serialization methods only for fair classes, read methods only for Builders) // write serialization methods only for fair classes, read methods only for Builders)
printer->Print("\n"); printer->Print("//========== Serialization methods ===========\n");
generateWriteToMethod(printer); generateWriteToMethod(printer);
printer->Print("\n");
// builder, mergeFrom and only for fair classes // builder, mergeFrom and only for fair classes
if (!isBuilder) { if (!isBuilder) {
printer->Print("\n");
generateBuilder(printer);
printer->Print("\n");
generateMergeMethods(printer); generateMergeMethods(printer);
printer->Print("\n");
} }
// build() and setters are only for builders // build() and setters are only for builders
if (isBuilder) { if (isBuilder) {
printer->Print("\n"); printer->Print("//========== Mutating methods ===========\n");
generateBuildMethod(printer); generateBuildMethod(printer);
printer->Print("\n"); printer->Print("\n");
generateParseMethods(printer); generateParseMethods(printer);
printer->Print("\n");
} }
// getSize() // getSize()
printer->Print("//========== Size-related methods ===========\n");
generateGetSizeMethod(printer); generateGetSizeMethod(printer);
printer->Print("\n");
if (!isBuilder) {
printer->Print("//========== Builder ===========\n");
generateBuilder(printer);
printer->Print("\n");
}
printer->Outdent(); printer->Outdent();
printer->Print("}\n"); printer->Print("}\n");
} }
@@ -139,7 +148,6 @@ void ClassGenerator::generateMergeMethods(io::Printer *printer) const {
map <string, string> vars; map <string, string> vars;
// mergeWith(other: Message) // mergeWith(other: Message)
printer->Print("\n");
vars["className"] = getFullType(); vars["className"] = getFullType();
printer->Print(vars, "fun mergeWith (other: $className$) {\n"); printer->Print(vars, "fun mergeWith (other: $className$) {\n");
printer->Indent(); printer->Indent();
@@ -203,6 +211,7 @@ void ClassGenerator::generateWriteToMethod(io::Printer *printer) const {
// generate code for serialization/deserialization of fields // generate code for serialization/deserialization of fields
for (int i = 0; i < properties.size(); ++i) { for (int i = 0; i < properties.size(); ++i) {
properties[i]->generateSerializationCode(printer, /* isRead = */ false, /* noTag = */ false); properties[i]->generateSerializationCode(printer, /* isRead = */ false, /* noTag = */ false);
printer->Print("\n");
} }
printer->Outdent(); printer->Outdent();
@@ -319,7 +328,7 @@ void ClassGenerator::generateParseMethods(io::Printer *printer) const {
printer->Print("return true"); printer->Print("return true");
printer->Outdent(); printer->Outdent();
printer->Print("}\n"); // parseFieldFrom body printer->Print("}\n"); // parseFieldFrom body
printer->Print("\n");
// ====== parseFromWithSize(input: CodedInputStream, expectedSize: Int) ========= // ====== parseFromWithSize(input: CodedInputStream, expectedSize: Int) =========
printer->Print(vars, printer->Print(vars,
@@ -346,7 +355,7 @@ void ClassGenerator::generateParseMethods(io::Printer *printer) const {
printer->Outdent(); // function body printer->Outdent(); // function body
printer->Print("}\n"); printer->Print("}\n");
printer->Print("\n");
// ======== parseFrom(input: CodedInputStream) ========= // ======== parseFrom(input: CodedInputStream) =========
printer->Print(vars, printer->Print(vars,
@@ -375,7 +384,7 @@ void ClassGenerator::generateGetSizeMethod(io::Printer *printer) const {
printer->Print("return size\n"); printer->Print("return size\n");
printer->Outdent(); printer->Outdent();
printer->Print("}\n"); printer->Print("}\n");
printer->Print("\n");
// getSizeNoTag(): Int // getSizeNoTag(): Int
printer->Print("fun getSizeNoTag(): Int {\n"); printer->Print("fun getSizeNoTag(): Int {\n");
@@ -32,6 +32,10 @@ void FieldGenerator::generateCode(io::Printer *printer, bool isBuilder) const {
map<string, string> vars; map<string, string> vars;
vars["name"] = simpleName; vars["name"] = simpleName;
vars["field"] = getFullType(); vars["field"] = getFullType();
vars["protoType"] = getProtoType();
generateComment(printer);
printer->Print(vars, "var $name$ : $field$\n"); printer->Print(vars, "var $name$ : $field$\n");
// make setter private // make setter private
@@ -93,13 +97,19 @@ void FieldGenerator::generateSerializationForPacked(io::Printer *printer, bool i
*/ */
FieldGenerator singleFieldGen = getUnderlyingTypeGenerator(); FieldGenerator singleFieldGen = getUnderlyingTypeGenerator();
singleFieldGen.simpleName = "singleElemSize"; singleFieldGen.simpleName = "singleElemSize";
printer->Print("\n");
singleFieldGen.generateSerializationCode(printer, isRead, /* noTag = */ true, /* isField = */ false); singleFieldGen.generateSerializationCode(printer, isRead, /* noTag = */ true, /* isField = */ false);
printer->Print("\n");
printer->Print(vars, "val arraySize = expectedByteSize / singleElemSize\n"); printer->Print(vars, "val arraySize = expectedByteSize / singleElemSize\n");
// Allocate new array of estimated size // Allocate new array of estimated size
printer->Print(vars, "val newArray = $arrayType$(arraySize)\n"); printer->Print(vars, "val newArray = $arrayType$(arraySize)\n");
// place declaration of new variable in anonymous scope for hygiene
printer->Print("run {\n");
printer->Indent();
printer->Print("var i = 0\n"); printer->Print("var i = 0\n");
printer->Print(vars, "while(i < arraySize) {\n"); printer->Print(vars, "while(i < arraySize) {\n");
printer->Indent(); printer->Indent();
@@ -113,7 +123,10 @@ void FieldGenerator::generateSerializationForPacked(io::Printer *printer, bool i
printer->Print(vars, "$fieldName$[i] = tmp\n"); printer->Print(vars, "$fieldName$[i] = tmp\n");
printer->Print("i += 1\n"); printer->Print("i += 1\n");
printer->Outdent(); printer->Outdent(); // while-loop
printer->Print("}\n");
printer->Outdent(); // anonymous scope
printer->Print("}\n"); printer->Print("}\n");
} }
else { else {
@@ -129,10 +142,17 @@ void FieldGenerator::generateSerializationForPacked(io::Printer *printer, bool i
// length // length
printer->Print(vars, "var arrayByteSize = 0\n"); printer->Print(vars, "var arrayByteSize = 0\n");
printer->Print("\n");
generateSizeEstimationCode(printer, "arrayByteSize", /* noTag = */ true, /* isField = */ false); generateSizeEstimationCode(printer, "arrayByteSize", /* noTag = */ true, /* isField = */ false);
printer->Print(vars, "output.writeInt32NoTag(arrayByteSize)\n"); printer->Print(vars, "output.writeInt32NoTag(arrayByteSize)\n");
printer->Print("\n");
// all elements // all elements
// place declaration of new variable in anonymous scope for hygiene
printer->Print("run {\n");
printer->Indent();
printer->Print("var i = 0\n"); printer->Print("var i = 0\n");
printer->Print(vars, "while (i < $fieldName$.size) {\n"); printer->Print(vars, "while (i < $fieldName$.size) {\n");
printer->Indent(); printer->Indent();
@@ -145,7 +165,11 @@ void FieldGenerator::generateSerializationForPacked(io::Printer *printer, bool i
singleFieldGen.generateSerializationCode(printer, isRead, /* noTag = */ isPrimitive, /* isField = */ false); singleFieldGen.generateSerializationCode(printer, isRead, /* noTag = */ isPrimitive, /* isField = */ false);
printer->Print(vars, "i += 1\n"); printer->Print(vars, "i += 1\n");
printer->Outdent(); // for-loop
printer->Outdent(); // while-loop
printer->Print("}\n");
printer->Outdent(); // anonymous scope
printer->Print("}\n"); printer->Print("}\n");
} }
} }
@@ -250,6 +274,9 @@ void FieldGenerator::generateSerializationCode(io::Printer *printer, bool isRead
vars["fieldName"] = simpleName; vars["fieldName"] = simpleName;
vars["initValue"] = getInitValue(); vars["initValue"] = getInitValue();
if (isField) {
generateComment(printer);
}
/* Try to generate syntax for serialization of repeated fields. /* Try to generate syntax for serialization of repeated fields.
* Note that it should be first check because of Google's FieldDescriptor structure */ * Note that it should be first check because of Google's FieldDescriptor structure */
@@ -376,7 +403,7 @@ void FieldGenerator::generateSizeEstimationCode(io::Printer *printer, string var
singleFieldGen.generateSizeEstimationCode(printer, "arraySize", noTag, /* isField = */ false); singleFieldGen.generateSizeEstimationCode(printer, "arraySize", noTag, /* isField = */ false);
printer->Print(vars, "i += 1\n"); printer->Print(vars, "i += 1\n");
printer->Outdent(); // for-loop printer->Outdent(); // for-loop
printer->Print("}\n"); printer->Print("}\n");
@@ -498,6 +525,17 @@ string FieldGenerator::getWireType() const {
return name_resolving::protobufTypeToKotlinWireType(descriptor->type()); return name_resolving::protobufTypeToKotlinWireType(descriptor->type());
} }
void FieldGenerator::generateComment(io::Printer *printer) const {
map <string, string> vars;
vars["repeated"] = descriptor->is_repeated() ? "repeated " : "";
vars["declared_type"] = descriptor->type_name();
vars["name"] = descriptor->name();
vars["number"] = std::to_string(descriptor->number());
printer->Print(vars, "//$repeated$$declared_type$ $name$ = $number$\n");
}
} // namespace kotlin } // namespace kotlin
} // namespace compiler } // namespace compiler
@@ -22,13 +22,12 @@ class NameResolver; // declared in kotlin_name_resolver.h
class FieldGenerator { class FieldGenerator {
private: private:
FieldDescriptor const * descriptor; FieldDescriptor const * descriptor;
// TODO: refactor from field generator to some static utility namespace
void generateSetter(io::Printer * printer) const; void generateSetter(io::Printer * printer) const;
void generateComment(io::Printer * printer) const;
void generateRepeatedMethods(io::Printer * printer, bool isBuilder) const; void generateRepeatedMethods(io::Printer * printer, bool isBuilder) const;
void generateSerializationForPacked (io::Printer * printer, bool isRead, bool noTag, bool isField) const; void generateSerializationForPacked (io::Printer * printer, bool isRead, bool noTag, bool isField) const;
void generateSerializationForRepeated (io::Printer * printer, bool isRead, bool noTag, bool isField) const;
void generateSerializationForEnums (io::Printer * printer, bool isRead, bool noTag, bool isField) const; void generateSerializationForEnums (io::Printer * printer, bool isRead, bool noTag, bool isField) const;
void generateSerializationForMessages (io::Printer * printer, bool isRead, bool noTag, bool isField) const; void generateSerializationForMessages (io::Printer * printer, bool isRead, bool noTag, bool isField) const;
void generateSerializationForPrimitives (io::Printer * printer, bool isRead, bool noTag, bool isField) const; void generateSerializationForPrimitives (io::Printer * printer, bool isRead, bool noTag, bool isField) const;