@ -26,11 +26,15 @@
# include <google/protobuf/descriptor.h>
// TODO: Clang format.
# include <algorithm>
# include <vector>
# include <map>
# include <string>
# include <tuple>
// TODO: Remove.
# include <iostream>
int protoc_main ( int argc , char * argv [ ] ) {
google : : protobuf : : compiler : : CommandLineInterface cli ;
cli . AllowPlugins ( " protoc- " ) ;
@ -58,14 +62,13 @@ namespace detail {
class GeneratorContextImpl : public : : google : : protobuf : : compiler : : GeneratorContext {
public :
GeneratorContextImpl ( const std : : vector < const : : google : : protobuf : : FileDescriptor * > & parsed_files ,
std : : map < std : : string , std : : string > * files_out ) :
std : : vector < std : : pair < std : : string , std : : string > > * files_out ) :
files_ ( files_out ) ,
parsed_files_ ( parsed_files ) { }
: : google : : protobuf : : io : : ZeroCopyOutputStream * Open ( const std : : string & filename ) {
// TODO(rbellevi): Learn not to dream impossible dreams. :(
auto [ iter , _ ] = files_ - > emplace ( filename , " " ) ;
return new : : google : : protobuf : : io : : StringOutputStream ( & ( iter - > second ) ) ;
files_ - > emplace_back ( filename , " " ) ;
return new : : google : : protobuf : : io : : StringOutputStream ( & ( files_ - > back ( ) . second ) ) ;
}
// NOTE: Equivalent to Open, since all files start out empty.
@ -84,7 +87,7 @@ public:
}
private :
std : : map < std : : string , std : : string > * files_ ;
std : : vector < std : : pair < std : : string , std : : string > > * files_ ;
const std : : vector < const : : google : : protobuf : : FileDescriptor * > & parsed_files_ ;
} ;
@ -113,11 +116,25 @@ private:
} // end namespace detail
static void calculate_transitive_closure ( const : : google : : protobuf : : FileDescriptor * descriptor ,
std : : vector < const : : google : : protobuf : : FileDescriptor * > * transitive_closure )
{
for ( int i = 0 ; i < descriptor - > dependency_count ( ) ; + + i ) {
const : : google : : protobuf : : FileDescriptor * dependency = descriptor - > dependency ( i ) ;
// NOTE: Probably want an O(1) lookup method for very large transitive
// closures.
if ( std : : find ( transitive_closure - > begin ( ) , transitive_closure - > end ( ) , dependency ) = = transitive_closure - > end ( ) ) {
calculate_transitive_closure ( dependency , transitive_closure ) ;
}
}
transitive_closure - > push_back ( descriptor ) ;
}
// TODO: Handle multiple include paths.
static int generate_code ( : : google : : protobuf : : compiler : : CodeGenerator * code_generator ,
char * protobuf_path ,
char * include_path ,
std : : map < std : : string , std : : string > * files_out ,
std : : vector < std : : pair < std : : string , std : : string > > * files_out ,
std : : vector < ProtocError > * errors ,
std : : vector < ProtocWarning > * warnings )
{
@ -129,16 +146,21 @@ static int generate_code(::google::protobuf::compiler::CodeGenerator* code_gener
if ( parsed_file = = nullptr ) {
return 1 ;
}
detail : : GeneratorContextImpl generator_context ( { parsed_file } , files_out ) ;
// TODO: Figure out if the dependency list is flat or recursive.
// TODO: Ensure there's a topological ordering here.
std : : vector < const : : google : : protobuf : : FileDescriptor * > transitive_closure ;
calculate_transitive_closure ( parsed_file , & transitive_closure ) ;
detail : : GeneratorContextImpl generator_context ( transitive_closure , files_out ) ;
std : : string error ;
: : google : : protobuf : : compiler : : python : : Generator python_generator ;
python_generator . Generate ( parsed_file , " " , & generator_context , & error ) ;
for ( const auto descriptor : transitive_closure ) {
code_generator - > Generate ( descriptor , " " , & generator_context , & error ) ;
}
return 0 ;
}
int protoc_get_protos ( char * protobuf_path ,
char * include_path ,
std : : map < std : : string , std : : string > * files_out ,
std : : vector < std : : pair < std : : string , std : : string > > * files_out ,
std : : vector < ProtocError > * errors ,
std : : vector < ProtocWarning > * warnings )
{
@ -148,7 +170,7 @@ int protoc_get_protos(char* protobuf_path,
int protoc_get_services ( char * protobuf_path ,
char * include_path ,
std : : map < std : : string , std : : string > * files_out ,
std : : vector < std : : pair < std : : string , std : : string > > * files_out ,
std : : vector < ProtocError > * errors ,
std : : vector < ProtocWarning > * warnings )
{