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);
printer->Indent();
/*
* Field generator should know if it is generating code for builder
* or for fair class to choose between 'val' and 'var'.
* Also note that fields should be declared before init section.
*/
// Generate code for property declaration
printer->Print("//========== Properties ===========\n");
for (FieldGenerator *gen: properties) {
gen->generateCode(printer, isBuilder);
printer->Print("\n");
}
// Generate field for errors code
printer->Print("\n");
printer->Print("var errorCode: Int = 0\n");
printer->Print("var errorCode: Int = 0\n\n");
printer->Print("\n");
generateInitSection(printer);
printer->Print("\n");
// enum declarations and nested classes declarations only for fair classes
if (!isBuilder) {
if (enumsDeclaraions.size() > 0) {
printer->Print("//========== Nested enums declarations ===========\n");
}
for (EnumGenerator *gen: enumsDeclaraions) {
gen->generateCode(printer);
printer->Print("\n");
}
if (classesDeclarations.size() > 0) {
printer->Print("//========== Nested classes declarations ===========\n");
}
for (ClassGenerator *gen: classesDeclarations) {
gen->generateCode(printer);
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)
printer->Print("\n");
printer->Print("//========== Serialization methods ===========\n");
generateWriteToMethod(printer);
printer->Print("\n");
// builder, mergeFrom and only for fair classes
if (!isBuilder) {
printer->Print("\n");
generateBuilder(printer);
printer->Print("\n");
generateMergeMethods(printer);
printer->Print("\n");
}
// build() and setters are only for builders
if (isBuilder) {
printer->Print("\n");
printer->Print("//========== Mutating methods ===========\n");
generateBuildMethod(printer);
printer->Print("\n");
generateParseMethods(printer);
printer->Print("\n");
}
// getSize()
printer->Print("//========== Size-related methods ===========\n");
generateGetSizeMethod(printer);
printer->Print("\n");
if (!isBuilder) {
printer->Print("//========== Builder ===========\n");
generateBuilder(printer);
printer->Print("\n");
}
printer->Outdent();
printer->Print("}\n");
}
@@ -139,7 +148,6 @@ void ClassGenerator::generateMergeMethods(io::Printer *printer) const {
map <string, string> vars;
// mergeWith(other: Message)
printer->Print("\n");
vars["className"] = getFullType();
printer->Print(vars, "fun mergeWith (other: $className$) {\n");
printer->Indent();
@@ -203,6 +211,7 @@ void ClassGenerator::generateWriteToMethod(io::Printer *printer) const {
// generate code for serialization/deserialization of fields
for (int i = 0; i < properties.size(); ++i) {
properties[i]->generateSerializationCode(printer, /* isRead = */ false, /* noTag = */ false);
printer->Print("\n");
}
printer->Outdent();
@@ -319,7 +328,7 @@ void ClassGenerator::generateParseMethods(io::Printer *printer) const {
printer->Print("return true");
printer->Outdent();
printer->Print("}\n"); // parseFieldFrom body
printer->Print("\n");
// ====== parseFromWithSize(input: CodedInputStream, expectedSize: Int) =========
printer->Print(vars,
@@ -346,7 +355,7 @@ void ClassGenerator::generateParseMethods(io::Printer *printer) const {
printer->Outdent(); // function body
printer->Print("}\n");
printer->Print("\n");
// ======== parseFrom(input: CodedInputStream) =========
printer->Print(vars,
@@ -375,7 +384,7 @@ void ClassGenerator::generateGetSizeMethod(io::Printer *printer) const {
printer->Print("return size\n");
printer->Outdent();
printer->Print("}\n");
printer->Print("\n");
// getSizeNoTag(): Int
printer->Print("fun getSizeNoTag(): Int {\n");
@@ -32,6 +32,10 @@ void FieldGenerator::generateCode(io::Printer *printer, bool isBuilder) const {
map<string, string> vars;
vars["name"] = simpleName;
vars["field"] = getFullType();
vars["protoType"] = getProtoType();
generateComment(printer);
printer->Print(vars, "var $name$ : $field$\n");
// make setter private
@@ -93,13 +97,19 @@ void FieldGenerator::generateSerializationForPacked(io::Printer *printer, bool i
*/
FieldGenerator singleFieldGen = getUnderlyingTypeGenerator();
singleFieldGen.simpleName = "singleElemSize";
printer->Print("\n");
singleFieldGen.generateSerializationCode(printer, isRead, /* noTag = */ true, /* isField = */ false);
printer->Print("\n");
printer->Print(vars, "val arraySize = expectedByteSize / singleElemSize\n");
// Allocate new array of estimated size
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(vars, "while(i < arraySize) {\n");
printer->Indent();
@@ -113,7 +123,10 @@ void FieldGenerator::generateSerializationForPacked(io::Printer *printer, bool i
printer->Print(vars, "$fieldName$[i] = tmp\n");
printer->Print("i += 1\n");
printer->Outdent();
printer->Outdent(); // while-loop
printer->Print("}\n");
printer->Outdent(); // anonymous scope
printer->Print("}\n");
}
else {
@@ -129,10 +142,17 @@ void FieldGenerator::generateSerializationForPacked(io::Printer *printer, bool i
// length
printer->Print(vars, "var arrayByteSize = 0\n");
printer->Print("\n");
generateSizeEstimationCode(printer, "arrayByteSize", /* noTag = */ true, /* isField = */ false);
printer->Print(vars, "output.writeInt32NoTag(arrayByteSize)\n");
printer->Print("\n");
// 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(vars, "while (i < $fieldName$.size) {\n");
printer->Indent();
@@ -145,7 +165,11 @@ void FieldGenerator::generateSerializationForPacked(io::Printer *printer, bool i
singleFieldGen.generateSerializationCode(printer, isRead, /* noTag = */ isPrimitive, /* isField = */ false);
printer->Print(vars, "i += 1\n");
printer->Outdent(); // for-loop
printer->Outdent(); // while-loop
printer->Print("}\n");
printer->Outdent(); // anonymous scope
printer->Print("}\n");
}
}
@@ -250,6 +274,9 @@ void FieldGenerator::generateSerializationCode(io::Printer *printer, bool isRead
vars["fieldName"] = simpleName;
vars["initValue"] = getInitValue();
if (isField) {
generateComment(printer);
}
/* Try to generate syntax for serialization of repeated fields.
* 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);
printer->Print(vars, "i += 1\n");
printer->Outdent(); // for-loop
printer->Print("}\n");
@@ -498,6 +525,17 @@ string FieldGenerator::getWireType() const {
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 compiler
@@ -22,13 +22,12 @@ class NameResolver; // declared in kotlin_name_resolver.h
class FieldGenerator {
private:
FieldDescriptor const * descriptor;
// TODO: refactor from field generator to some static utility namespace
void generateSetter(io::Printer * printer) const;
void generateComment(io::Printer * printer) const;
void generateRepeatedMethods(io::Printer * printer, bool isBuilder) 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 generateSerializationForMessages (io::Printer * printer, bool isRead, bool noTag, bool isField) const;
void generateSerializationForPrimitives (io::Printer * printer, bool isRead, bool noTag, bool isField) const;