Пример #1
0
        static string GetType(PyClass pyClass, string methodName, string rustType, string sphinxType)
        {
            // The type in the docs (sphinx type) is more accurate than the type in the source code
            // since `u32` is used in the source code if it's an enum value.
            if (sphinxType != string.Empty)
            {
                var sphinxTypes    = ParseUtils.SplitSphinxTypes(sphinxType).ToList();
                var convertedTypes = new List <string>();
                foreach (var stype in sphinxTypes)
                {
                    if (!ParseUtils.TryConvertSphinxTypeToTypeName(stype, out var typeName))
                    {
                        typeName = stype;
                    }
                    convertedTypes.Add(typeName);
                }
                int index = convertedTypes.Count == 1 ? -1 : convertedTypes.IndexOf("None");
                if (index >= 0)
                {
                    convertedTypes.RemoveAt(index);
                }
                string typeStr;
                if (convertedTypes.Count > 1)
                {
                    typeStr = "Union[" + string.Join(", ", convertedTypes.ToArray()) + "]";
                }
                else
                {
                    typeStr = convertedTypes[0];
                }
                if (index >= 0)
                {
                    return("Optional[" + typeStr + "]");
                }
                return(typeStr);
            }

            if (ParseUtils.TryRemovePrefixSuffix(rustType, "PyResult<", ">", out var extractedType))
            {
                rustType = extractedType;
            }
            switch (rustType)
            {
            case "i8" or "i16" or "i32" or "i64" or "isize" or
                "u8" or "u16" or "u32" or "u64" or "usize":
                return("int");

            case "bool":
                return("bool");

            case "&str" or "String":
                return("str");

            case "PyRef<Self>" or "PyRefMut<Self>" or "Self":
                return(pyClass.Name);

            case "&PyAny":
                return("Any");

            default:
                if (ParseUtils.TryRemovePrefixSuffix(rustType, "IterNextOutput<", ", ()>", out extractedType))
                {
                    return(extractedType);
                }
                break;
            }

            throw new InvalidOperationException($"Method {pyClass.Name}.{methodName}(): Couldn't convert Rust/sphinx type to Python type: Rust=`{rustType}`, sphinx=`{sphinxType}`");
        }
Пример #2
0
        // Gets all required enum fields that must be part of the pyi file because they're
        // default values in some methods.
        Dictionary <EnumType, HashSet <EnumValue> > GetRequiredEnumFields(List <PyClass> classes)
        {
            var reqEnumFields = new Dictionary <EnumType, HashSet <EnumValue> >();
            var argToEnumType = new Dictionary <string, EnumType>(StringComparer.Ordinal);

            foreach (var pyClass in classes)
            {
                foreach (var method in pyClass.Methods)
                {
                    DocComments docComments;
                    if (method.Attributes.Any(AttributeKind.New))
                    {
                        docComments = pyClass.DocComments;
                    }
                    else
                    {
                        docComments = method.DocComments;
                    }
                    var docs = docComments.Sections.OfType <ArgsDocCommentSection>().FirstOrDefault();
                    if (docs is null)
                    {
                        continue;
                    }
                    int hasThis = method.Arguments.Count != 0 && method.Arguments[0].IsSelf ? 1 : 0;
                    if (docs.Args.Length != (method.Arguments.Count - hasThis))
                    {
                        throw new InvalidOperationException();
                    }
                    argToEnumType.Clear();
                    for (int i = 0; i < docs.Args.Length; i++)
                    {
                        var docArg = docs.Args[i];
                        if (docArg.Name != method.Arguments[hasThis + i].Name)
                        {
                            throw new InvalidOperationException();
                        }
                        if (!ParseUtils.TryConvertSphinxTypeToTypeName(docArg.SphinxType, out var typeName))
                        {
                            continue;
                        }
                        if (!exportedPythonTypes.TryFindByName(typeName, out var enumType))
                        {
                            continue;
                        }
                        argToEnumType.Add(docArg.Name, enumType);
                    }

                    var argsAttr = method.Attributes.Attributes.FirstOrDefault(a => a.Kind == AttributeKind.Args);
                    if (argsAttr is null)
                    {
                        continue;
                    }
                    foreach (var(name, value) in ParseUtils.GetArgsNameValues(argsAttr.Text))
                    {
                        if (!argToEnumType.TryGetValue(name, out var enumType))
                        {
                            continue;
                        }
                        if (!uint.TryParse(value, out var rawValue))
                        {
                            throw new InvalidOperationException($"Couldn't parse {value} as an integer");
                        }
                        var enumValue = enumType.Values.FirstOrDefault(a => a.Value == rawValue);
                        if (enumValue is null)
                        {
                            throw new InvalidOperationException($"Couldn't find an enum value in {enumType.RawName} with a value equal to {value}");
                        }
                        if (!reqEnumFields.TryGetValue(enumType, out var hash))
                        {
                            reqEnumFields.Add(enumType, hash = new HashSet <EnumValue>());
                        }
                        hash.Add(enumValue);
                    }
                }
            }
            return(reqEnumFields);
        }