diff options
author | Jon Skeet <skeet@pobox.com> | 2008-10-22 13:30:34 +0100 |
---|---|---|
committer | Jon Skeet <skeet@pobox.com> | 2008-10-22 13:30:34 +0100 |
commit | 6803686bc06c4d96afd9bd2637f7b37a58596699 (patch) | |
tree | 4b21c563f4cd4e399fbc0b253bc2f15e822eae88 /src/ProtoGen/Generator.cs | |
parent | f0589506c96600dcd01319b9d1929d87505f3daa (diff) | |
download | protobuf-6803686bc06c4d96afd9bd2637f7b37a58596699.tar.gz protobuf-6803686bc06c4d96afd9bd2637f7b37a58596699.tar.bz2 protobuf-6803686bc06c4d96afd9bd2637f7b37a58596699.zip |
First cut at new layout
Diffstat (limited to 'src/ProtoGen/Generator.cs')
-rw-r--r-- | src/ProtoGen/Generator.cs | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/src/ProtoGen/Generator.cs b/src/ProtoGen/Generator.cs new file mode 100644 index 00000000..f656386b --- /dev/null +++ b/src/ProtoGen/Generator.cs @@ -0,0 +1,138 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Google.ProtocolBuffers.DescriptorProtos; +using System.IO; +using Google.ProtocolBuffers.Descriptors; +using Google.ProtocolBuffers.Collections; + +namespace Google.ProtocolBuffers.ProtoGen { + /// <summary> + /// Code generator for protocol buffers. Only C# is supported at the moment. + /// </summary> + public sealed class Generator { + + readonly GeneratorOptions options; + + private Generator(GeneratorOptions options) { + options.Validate(); + this.options = options; + } + + /// <summary> + /// Returns a generator configured with the specified options. + /// </summary> + public static Generator CreateGenerator(GeneratorOptions options) { + return new Generator(options); + } + + public void Generate() { + foreach (string inputFile in options.InputFiles) { + FileDescriptorSet descriptorProtos; + ExtensionRegistry extensionRegistry = ExtensionRegistry.CreateInstance(); + extensionRegistry.Add(CSharpOptions.CSharpUmbrellaClassname); + extensionRegistry.Add(CSharpOptions.CSharpMultipleFiles); + extensionRegistry.Add(CSharpOptions.CSharpNamespace); + extensionRegistry.Add(CSharpOptions.CSharpNestClasses); + extensionRegistry.Add(CSharpOptions.CSharpPublicClasses); + using (Stream inputStream = File.OpenRead(inputFile)) { + descriptorProtos = FileDescriptorSet.ParseFrom(inputStream, extensionRegistry); + } + IList<FileDescriptor> descriptors = ConvertDescriptors(descriptorProtos); + + foreach (FileDescriptor descriptor in descriptors) { + Generate(descriptor); + } + } + } + + /// <summary> + /// Generates code for a particular file. All dependencies must + /// already have been resolved. + /// </summary> + private void Generate(FileDescriptor descriptor) { + string umbrellaClass = DescriptorUtil.GetUmbrellaClassName(descriptor); + string ns = DescriptorUtil.GetNamespace(descriptor); + using (TextWriter textWriter = File.CreateText(Path.Combine(options.OutputDirectory, umbrellaClass + ".cs"))) { + TextGenerator writer = new TextGenerator(textWriter); + + UmbrellaClassGenerator ucg = new UmbrellaClassGenerator(descriptor); + ucg.Generate(writer); + /* + GenerateSiblings(umbrellaSource, descriptor, descriptor.MessageTypes); + GenerateSiblings(umbrellaSource, descriptor, descriptor.EnumTypes); + GenerateSiblings(umbrellaSource, descriptor, descriptor.Services);*/ + } + } + + private static void GenerateSiblings<T>(SourceFileGenerator parentSourceGenerator, FileDescriptor file, IEnumerable<T> siblings) + where T : IDescriptor { + } + + /// <summary> + /// Resolves any dependencies and converts FileDescriptorProtos into FileDescriptors. + /// The list returned is in the same order as the protos are listed in the descriptor set. + /// Note: this method is internal rather than private to allow testing. + /// </summary> + /// <exception cref="DependencyResolutionException">Not all dependencies could be resolved.</exception> + internal static IList<FileDescriptor> ConvertDescriptors(FileDescriptorSet descriptorProtos) { + // Simple strategy: Keep going through the list of protos to convert, only doing ones where + // we've already converted all the dependencies, until we get to a stalemate + IList<FileDescriptorProto> fileList = descriptorProtos.FileList; + FileDescriptor[] converted = new FileDescriptor[fileList.Count]; + + Dictionary<string, FileDescriptor> convertedMap = new Dictionary<string, FileDescriptor>(); + + int totalConverted = 0; + + bool madeProgress = true; + while (madeProgress && totalConverted < converted.Length) { + madeProgress = false; + for (int i = 0; i < converted.Length; i++) { + if (converted[i] != null) { + // Already done this one + continue; + } + FileDescriptorProto candidate = fileList[i]; + FileDescriptor[] dependencies = new FileDescriptor[candidate.DependencyList.Count]; + bool foundAllDependencies = true; + for (int j = 0; j < dependencies.Length; j++) { + if (!convertedMap.TryGetValue(candidate.DependencyList[j], out dependencies[j])) { + foundAllDependencies = false; + break; + } + } + if (!foundAllDependencies) { + continue; + } + madeProgress = true; + totalConverted++; + converted[i] = FileDescriptor.BuildFrom(candidate, dependencies); + convertedMap[candidate.Name] = converted[i]; + } + } + if (!madeProgress) { + StringBuilder remaining = new StringBuilder(); + for (int i = 0; i < converted.Length; i++) { + if (converted[i] == null) { + if (remaining.Length != 0) { + remaining.Append(", "); + } + FileDescriptorProto failure = fileList[i]; + remaining.Append(failure.Name); + remaining.Append(":"); + foreach (string dependency in failure.DependencyList) { + if (!convertedMap.ContainsKey(dependency)) { + remaining.Append(" "); + remaining.Append(dependency); + } + } + remaining.Append(";"); + } + } + throw new DependencyResolutionException("Unable to resolve all dependencies: " + remaining); + } + return Lists.AsReadOnly(converted); + } + } +} |