/// <summary> /// Create a new GeneratorContext instance /// </summary> internal GeneratorContext(FileDescriptorProto file, NameNormalizer nameNormalizer, TextWriter output, string indentToken) { File = file; NameNormalizer = nameNormalizer; Output = output; IndentToken = indentToken; }
/// <summary> /// Create a new GeneratorContext instance /// </summary> internal GeneratorContext(CommonCodeGenerator generator, FileDescriptorProto file, NameNormalizer nameNormalizer, TextWriter output, string indentToken, Dictionary <string, string> options) { if (nameNormalizer == null) { string nn = null; if (options != null) { options.TryGetValue("names", out nn); } // todo: support getting from a .proto extension? if (nn != null) { nn = nn.Trim(); } if (string.Equals(nn, "auto", StringComparison.OrdinalIgnoreCase)) { nameNormalizer = NameNormalizer.Default; } else if (string.Equals(nn, "original", StringComparison.OrdinalIgnoreCase)) { nameNormalizer = NameNormalizer.Null; } } string langver = null; if (options != null) { options.TryGetValue("langver", out langver); // explicit option first } if (string.IsNullOrWhiteSpace(langver)) { langver = generator?.GetLanguageVersion(file); // then from file } if (nameNormalizer == null) { nameNormalizer = NameNormalizer.Default; } nameNormalizer.IsCaseSensitive = generator.IsCaseSensitive; File = file; NameNormalizer = nameNormalizer; Output = output; IndentToken = indentToken; LanguageVersion = ParseVersion(langver); EmitRequiredDefaults = file.Options.GetOptions()?.EmitRequiredDefaults ?? false; _options = options; OneOfEnums = (File.Options?.GetOptions()?.EmitOneOfEnum ?? false) || (_options != null && _options.TryGetValue("oneof", out var oneof) && string.Equals(oneof, "enum", StringComparison.OrdinalIgnoreCase)); }
private string MakeRelativeName(FieldDescriptorProto field, IType target, NameNormalizer normalizer) { if (target == null) { return(Escape(field.TypeName)); // the only thing we know } var declaringType = field.Parent; if (declaringType is IType type) { var name = FindNameFromCommonAncestor(type, target, normalizer); if (!string.IsNullOrWhiteSpace(name)) { return(name); } } return(Escape(field.TypeName)); // give up! }
/// <summary> /// Execute the code generator against a FileDescriptorSet, yielding a sequence of files /// </summary> public override IEnumerable <CodeFile> Generate(FileDescriptorSet set, NameNormalizer normalizer = null) { foreach (var file in set.Files) { if (!file.IncludeInOutput) { continue; } var fileName = Path.ChangeExtension(file.Name, DefaultFileExtension); string generated; using (var buffer = new StringWriter()) { var ctx = new GeneratorContext(file, normalizer ?? NameNormalizer.Default, buffer, Indent); ctx.BuildTypeIndex(); // populates for TryFind<T> WriteFile(ctx, file); generated = buffer.ToString(); } yield return(new CodeFile(fileName, generated)); } }
// k, what we do is; we have two types; each knows the parent, but nothing else, so: // for each, use a stack to build the ancestry tree - the "top" of the stack will be the // package, the bottom of the stack will be the type itself. They will often be stacks // of different heights. // // Find how many is in the smallest stack; now take that many items, in turn, until we // get something that is different (at which point, put that one back on the stack), or // we run out of items in one of the stacks. // // There are now two options: // - we ran out of things in the "target" stack - in which case, they are common enough to not // need any resolution - just give back the fixed name // - we have things left in the "target" stack - in which case we have found a common ancestor, // or the target is a descendent; either way, just concat what is left (including the package // if the package itself was different) private string FindNameFromCommonAncestor(IType declaring, IType target, NameNormalizer normalizer) { // trivial case; asking for self, or asking for immediate child if (ReferenceEquals(declaring, target) || ReferenceEquals(declaring, target.Parent)) { if (target is DescriptorProto message) { return(Escape(normalizer.GetName(message))); } if (target is EnumDescriptorProto @enum) { return(Escape(normalizer.GetName(@enum))); } return(null); } var origTarget = target; var xStack = new Stack <IType>(); while (declaring != null) { xStack.Push(declaring); declaring = declaring.Parent; } var yStack = new Stack <IType>(); while (target != null) { yStack.Push(target); target = target.Parent; } int lim = Math.Min(xStack.Count, yStack.Count); for (int i = 0; i < lim; i++) { declaring = xStack.Peek(); target = yStack.Pop(); if (!ReferenceEquals(target, declaring)) { // special-case: if both are the package (file), and they have the same namespace: we're OK if (target is FileDescriptorProto && declaring is FileDescriptorProto && normalizer.GetName((FileDescriptorProto)declaring) == normalizer.GetName((FileDescriptorProto)target)) { // that's fine, keep going } else { // put it back yStack.Push(target); break; } } } // if we used everything, then the target is an ancestor-or-self if (yStack.Count == 0) { target = origTarget; if (target is DescriptorProto message) { return(Escape(normalizer.GetName(message))); } if (target is EnumDescriptorProto @enum) { return(Escape(normalizer.GetName(@enum))); } return(null); } var sb = new StringBuilder(); while (yStack.Count != 0) { target = yStack.Pop(); string nextName; if (target is FileDescriptorProto file) { nextName = normalizer.GetName(file); } else if (target is DescriptorProto message) { nextName = normalizer.GetName(message); } else if (target is EnumDescriptorProto @enum) { nextName = normalizer.GetName(@enum); } else { return(null); } if (!string.IsNullOrWhiteSpace(nextName)) { if (sb.Length == 0 && target is FileDescriptorProto) { sb.Append("global::"); } else if (sb.Length != 0) { sb.Append('.'); } sb.Append(Escape(nextName)); } } return(sb.ToString()); }
/// <summary> /// Execute the code generator against a FileDescriptorSet, yielding a sequence of files /// </summary> public abstract IEnumerable <CodeFile> Generate(FileDescriptorSet set, NameNormalizer normalizer = null, Dictionary <string, string> options = null);
/// <summary> /// Execute the code generator against a FileDescriptorSet, yielding a sequence of files /// </summary> public IEnumerable <CodeFile> Generate(FileDescriptorSet set, NameNormalizer normalizer) => Generate(set, normalizer, null);
/// <summary> /// Execute the code generator against a FileDescriptorSet, yielding a sequence of files /// </summary> public abstract IEnumerable <CodeFile> Generate(FileDescriptorSet set, NameNormalizer normalizer = null);