Example #1
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("...");
                }
            }
        }
Example #2
0
        void WritePyi(List <PyClass> classes)
        {
            var reqEnumFields = GetRequiredEnumFields(classes);

            var filename = genTypes.Dirs.GetPythonPyFilename("_iced_x86_py.pyi");

            using (var writer = new FileWriter(TargetLanguage.Python, FileUtils.OpenWrite(filename))) {
                writer.WriteFileHeader();
                writer.WriteLine("from collections.abc import Iterator");
                writer.WriteLine("from enum import IntEnum, IntFlag");
                writer.WriteLine("from typing import Any, List, Optional, Union");
                writer.WriteLine();

                var idConverter  = PythonIdentifierConverter.Create();
                var allEnumTypes = exportedPythonTypes.Enums.Select(a => (enumType: a, pythonName: a.Name(idConverter)));
                var toEnumType   = allEnumTypes.ToDictionary(a => a.pythonName, a => a.enumType, StringComparer.Ordinal);
                foreach (var(enumType, pythonName) in allEnumTypes.OrderBy(a => a.pythonName, StringComparer.Ordinal))
                {
                    var baseClass = enumType.IsFlags ? "IntFlag" : "IntEnum";
                    if (reqEnumFields.TryGetValue(enumType, out var fields))
                    {
                        writer.WriteLine($"class {pythonName}({baseClass}):");
                        using (writer.Indent()) {
                            bool uppercaseRawName = PythonUtils.UppercaseEnum(enumType.TypeId.Id1);
                            foreach (var value in enumType.Values)
                            {
                                if (fields.Contains(value))
                                {
                                    fields.Remove(value);
                                    var(valueName, numStr) = PythonUtils.GetEnumNameValue(idConverter, value, uppercaseRawName);
                                    writer.WriteLine($"{valueName} = {numStr}");
                                }
                                if (fields.Count == 0)
                                {
                                    break;
                                }
                            }
                            if (fields.Count != 0)
                            {
                                throw new InvalidOperationException();
                            }
                            writer.WriteLine("...");
                        }
                    }
                    else
                    {
                        writer.WriteLine($"class {pythonName}({baseClass}): ...");
                    }
                }

                var docGen = new PyiDocGen();
                foreach (var pyClass in classes.OrderBy(a => a.Name, StringComparer.Ordinal))
                {
                    writer.WriteLine();
                    writer.WriteLine($"class {idConverter.Type(pyClass.Name)}:");
                    using (writer.Indent()) {
                        WriteDocs(writer, docGen.Convert(pyClass.DocComments));

                        int defCount = 0;
                        foreach (var member in GetMembers(pyClass))
                        {
                            switch (member)
                            {
                            case PyMethod method:
                                var docComments = method.Attributes.Any(AttributeKind.New) ?
                                                  pyClass.DocComments : method.DocComments;
                                Write(writer, docGen, idConverter, pyClass, method, docComments, toEnumType);
                                defCount++;
                                break;

                            case PyProperty property:
                                Write(writer, docGen, idConverter, pyClass, property.Getter, property.Getter.DocComments, toEnumType);
                                defCount++;
                                if (property.Setter is not null)
                                {
                                    Write(writer, docGen, idConverter, pyClass, property.Setter, property.Getter.DocComments, toEnumType);
                                    defCount++;
                                }
                                break;

                            default:
                                throw new InvalidOperationException();
                            }
                        }
                        if (defCount == 0)
                        {
                            throw new InvalidOperationException($"class {pyClass.Name}: No class members");
                        }
                    }
                }
            }
        }