예제 #1
0
 /// <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;
 }
예제 #2
0
            /// <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!
        }
예제 #4
0
        /// <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());
        }
예제 #6
0
 /// <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);
예제 #7
0
 /// <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);
예제 #8
0
 /// <summary>
 /// Execute the code generator against a FileDescriptorSet, yielding a sequence of files
 /// </summary>
 public abstract IEnumerable <CodeFile> Generate(FileDescriptorSet set, NameNormalizer normalizer = null);