Пример #1
0
 public PyClass(string name, DocComments docComments, RustAttributes attributes)
 {
     Name        = name;
     DocComments = docComments;
     Attributes  = attributes;
     Methods     = new List <PyMethod>();
 }
Пример #2
0
 public PyMethod(string name, DocComments docComments, RustAttributes attributes, List <PyMethodArg> arguments, string rustReturnType)
 {
     Name           = name;
     DocComments    = docComments;
     Attributes     = attributes;
     Arguments      = arguments;
     RustReturnType = rustReturnType;
 }
Пример #3
0
        static void Write(FileWriter writer, PyiDocGen docGen, IdentifierConverter idConverter, PyClass pyClass, PyMethod method, DocComments docComments, Dictionary <string, EnumType> toEnumType)
        {
            if (method.Attributes.Any(AttributeKind.ClassMethod))
            {
                writer.WriteLine("@classmethod");
            }
            if (method.Attributes.Any(AttributeKind.StaticMethod))
            {
                writer.WriteLine("@staticmethod");
            }
            bool isGetter = method.Attributes.Any(AttributeKind.Getter);
            bool isSetter = method.Attributes.Any(AttributeKind.Setter);

            if (isGetter)
            {
                writer.WriteLine("@property");
            }
            if (isSetter)
            {
                writer.WriteLine($"@{method.Name}.setter");
            }

            string sphinxReturnType = string.Empty;

            if (isGetter || isSetter)
            {
                if (docComments.Sections.FirstOrDefault() is not TextDocCommentSection textDocs || textDocs.Lines.Length == 0)
                {
                    throw new InvalidOperationException();
                }
                if (!ParseUtils.TryParseTypeAndDocs(textDocs.Lines[0], out _, out var typeInfo))
                {
                    throw new InvalidOperationException();
                }
                sphinxReturnType = typeInfo.SphinxType;
            }
            else
            {
                var returns = docComments.Sections.OfType <ReturnsDocCommentSection>().FirstOrDefault();
                if (returns is not null)
                {
                    sphinxReturnType = returns.Returns.SphinxType;
                }
            }

            bool isCtor = method.Attributes.Any(AttributeKind.New);

            writer.Write("def ");
            writer.Write(isCtor ? "__init__" : method.Name);
            writer.Write("(");
            int argCount = 0;

            if (isCtor)
            {
                writer.Write("self");
                argCount++;
            }
            var argsDocs = docComments.Sections.OfType <ArgsDocCommentSection>().FirstOrDefault();
            int hasThis  = method.Arguments.Count != 0 && method.Arguments[0].IsSelf ? 1 : 0;

            Dictionary <string, string> toDefaultValue;
            var argsAttr = method.Attributes.Attributes.FirstOrDefault(a => a.Kind == AttributeKind.Args);

            if (argsAttr is null)
            {
                toDefaultValue = new Dictionary <string, string>(StringComparer.Ordinal);
            }
            else
            {
                toDefaultValue = ParseUtils.GetArgsNameValues(argsAttr.Text).ToDictionary(a => a.name, a => a.value, StringComparer.Ordinal);
            }

            for (int i = 0; i < method.Arguments.Count; i++)
            {
                if (argsDocs is not null && argsDocs.Args.Length != method.Arguments.Count - hasThis)
                {
                    throw new InvalidOperationException();
                }
                var methodArg = method.Arguments[i];
                if (argCount > 0)
                {
                    writer.Write(", ");
                }
                argCount++;
                if (methodArg.IsSelf)
                {
                    writer.Write("self");
                }
                else
                {
                    writer.Write(methodArg.Name);

                    string docsSphinxType;
                    if (argsDocs is not null)
                    {
                        var docsArg = argsDocs.Args[i - hasThis];
                        if (docsArg.Name != methodArg.Name)
                        {
                            throw new InvalidOperationException();
                        }
                        docsSphinxType = docsArg.SphinxType;
                    }
                    else
                    {
                        docsSphinxType = string.Empty;
                    }
                    if (i == 1 && isSetter)
                    {
                        docsSphinxType = sphinxReturnType;
                    }

                    writer.Write(": ");
                    var type = GetType(pyClass, method.Name, methodArg.RustType, docsSphinxType);
                    writer.Write(type);

                    if (toDefaultValue.TryGetValue(methodArg.Name, out var defaultValueStr))
                    {
                        writer.Write(" = ");
                        if (!TryGetValueStr(idConverter, type, defaultValueStr, toEnumType, out var valueStr))
                        {
                            throw new InvalidOperationException($"method {pyClass.Name}.{method.Name}(): Couldn't convert default value `{defaultValueStr}` to a Python value");
                        }
                        writer.Write(valueStr);
                    }
                }
            }
            writer.Write(") -> ");
            if (method.HasReturnType && !isCtor)
            {
                writer.Write(GetReturnType(pyClass, method.Name, method.RustReturnType, sphinxReturnType));
            }
            else
            {
                writer.Write("None");
            }
            if (method.DocComments.Sections.Count == 0)
            {
                writer.WriteLine(": ...");
            }
            else
            {
                writer.WriteLine(":");
                using (writer.Indent()) {
                    WriteDocs(writer, docGen.Convert(method.DocComments));
                    writer.WriteLine("...");
                }
            }
        }
Пример #4
0
        public List <string> Convert(DocComments docComments)
        {
            converted.Clear();

            bool addEmptyLine  = false;
            var  colDefs       = new List <(int start, int length)>();
            var  tableLines    = new List <List <string> >();
            var  columnLengths = new List <int>();
            var  sb            = new StringBuilder();

            foreach (var section in docComments.Sections)
            {
                if (addEmptyLine)
                {
                    converted.Add(string.Empty);
                }
                addEmptyLine = true;

                switch (section)
                {
                case TextDocCommentSection text:
                    for (int i = 0; i < text.Lines.Length; i++)
                    {
                        var line = text.Lines[i];

                        // Convert tables to code blocks. They're not converted to
                        // markdown tables because Jedi doesn't support tables in
                        // tooltips. Instead, we create a text block that will be
                        // rendered with a monospaced font.
                        if (IsTableLine(line))
                        {
                            GetColumnDefs(colDefs, line);
                            if (colDefs.Count < 2)
                            {
                                throw new InvalidOperationException($"Invalid table, expected at least 2 columns. First line: {line}");
                            }

                            i++;
                            if (!TryGetNextTableLine(text.Lines, ref i, out var tblLine) || IsTableLine(tblLine))
                            {
                                throw new InvalidOperationException("Invalid table");
                            }
                            tableLines.Add(GetColumns(colDefs, tblLine));
                            if (!TryGetNextTableLine(text.Lines, ref i, out tblLine) || !IsTableLine(tblLine))
                            {
                                throw new InvalidOperationException("Invalid table");
                            }
                            while (TryGetNextTableLine(text.Lines, ref i, out tblLine) && !IsTableLine(tblLine))
                            {
                                tableLines.Add(GetColumns(colDefs, tblLine));
                            }

                            foreach (var tableCols in tableLines)
                            {
                                for (int j = 0; j < tableCols.Count; j++)
                                {
                                    tableCols[j] = FixTableColumn(tableCols[j], j == 0);
                                }
                            }

                            columnLengths.Clear();
                            for (int j = 0; j < colDefs.Count; j++)
                            {
                                columnLengths.Add(0);
                            }
                            foreach (var tableCols in tableLines)
                            {
                                if (tableCols.Count != columnLengths.Count)
                                {
                                    throw new InvalidOperationException();
                                }
                                for (int j = 0; j < columnLengths.Count; j++)
                                {
                                    columnLengths[j] = Math.Max(columnLengths[j], tableCols[j].Length);
                                }
                            }
                            const int colSepLen = 2;
                            for (int j = 0; j < columnLengths.Count - 1; j++)
                            {
                                columnLengths[j] += colSepLen;
                            }

                            converted.Add("```text");
                            for (int j = 0; j < tableLines.Count; j++)
                            {
                                var tableCols = tableLines[j];
                                sb.Clear();
                                for (int k = 0; k < tableCols.Count; k++)
                                {
                                    var col = tableCols[k];
                                    sb.Append(FixCodeBlockLine(col));
                                    int colLen = columnLengths[k];
                                    if (col.Length > colLen)
                                    {
                                        throw new InvalidOperationException();
                                    }
                                    if (k + 1 != tableCols.Count)
                                    {
                                        sb.Append(' ', colLen - col.Length);
                                    }
                                }
                                converted.Add(sb.ToString());
                                if (j == 0)
                                {
                                    sb.Clear();
                                    sb.Append('-', columnLengths.Sum() - columnLengths[^ 1] + tableLines[0][^ 1].Length);