/// <inheritdoc/> public IEnumerable <Overload> CreateOverloads(Function function) { if (!IsApplicable(function)) { yield break; } var arrayParameter = function.Parameters.Last(); var arrayParameterType = arrayParameter.Type; var newName = function.Name.Singularize(false); var newParameters = SkipLastExtension.SkipLast(new List <Parameter>(function.Parameters), 2).ToList(); var newArrayParameterType = new TypeSignatureBuilder(arrayParameterType) .WithArrayDimensions(0) .WithIndirectionLevel(0) .Build(); var newArrayParameter = new ParameterSignatureBuilder(arrayParameter) .WithType(newArrayParameterType) .Build(); newParameters.Add(newArrayParameter); var sb = new StringBuilder(); sb.AppendLine("// ArrayParameterOverloader"); sb.AppendLine(function.Name + "(1, &" + newArrayParameter.Name + ");"); yield return(new Overload(new FunctionSignatureBuilder(function) .WithName(newName) .WithParameters(newParameters) .Build(), sb, true)); }
/// <summary> /// Returns a signature that represents an instantiation of the generic type represented /// by this signature. /// </summary> /// <param name="typeArguments">The type arguments of the instantiation.</param> /// <returns>A <see cref="TypeSignature"/> representing the instantiation of the generic /// type whose definition is represented by this signature and whose type arguments are /// given.</returns> /// <exception cref="ArgumentException"><paramref name="typeArguments"/> is empty.</exception> /// <exception cref="InvalidOperationException">This signature does not represent a class or value /// type.</exception> public TypeSignature makeGenericInstance(ReadOnlySpan <TypeSignature> typeArguments) { if (typeArguments.Length == 0) { throw new ArgumentException("Type arguments must not be empty.", nameof(typeArguments)); } byte firstByte = getFirstByte(); if (firstByte != (byte)SignatureTypeKind.Class && firstByte != (byte)SignatureTypeKind.ValueType) { throw new InvalidOperationException("Generic instantiation is only allowed for class and valuetype signatures."); } var builder = TypeSignatureBuilder.getInstance(); try { builder.appendByte((byte)SignatureTypeCode.GenericTypeInstance); builder.appendSignature(this); builder.appendCompressedUnsignedInt(typeArguments.Length); for (int i = 0; i < typeArguments.Length; i++) { builder.appendSignature(typeArguments[i]); } return(builder.makeSignature()); } finally { builder.clear(); } }
private TypeSignature _addTypeCodePrefix(SignatureTypeCode code) { if (isByRef()) { throw new InvalidOperationException("Cannot use a by-ref type as the element type of an array, pointer or by-ref type."); } int compactLength = (int)(m_compact >> 56); if (compactLength < 7) { return(new TypeSignature((long)(compactLength + 1) << 56 | m_compact << 8 | (byte)code)); } var builder = TypeSignatureBuilder.getInstance(); try { builder.appendByte((byte)code); builder.appendSignature(this); return(builder.makeSignature()); } finally { builder.clear(); } }
/// <summary> /// Returns a signature that represents an instantiation of the generic type represented /// by this signature with its own type parameters as type arguments. /// </summary> /// <param name="typeParamCount">The number of type parameters in the generic type.</param> /// <returns>A <see cref="TypeSignature"/> representing the instantiation of the generic /// type whose definition is represented by this signature and whose type arguments are /// the generic type's own type parameters.</returns> /// <exception cref="ArgumentOutOfRangeException"><paramref name="typeParamCount"/> is zero or negative.</exception> /// <exception cref="InvalidOperationException">This signature does not represent a class or value /// type.</exception> public TypeSignature makeGenericSelfInstance(int typeParamCount) { if (typeParamCount <= 0) { throw new ArgumentOutOfRangeException(nameof(typeParamCount)); } byte firstByte = getFirstByte(); if (firstByte != (byte)SignatureTypeKind.Class && firstByte != (byte)SignatureTypeKind.ValueType) { throw new InvalidOperationException("Generic instantiation is only allowed for class or valuetype signatures."); } var builder = TypeSignatureBuilder.getInstance(); try { builder.appendByte((byte)SignatureTypeCode.GenericTypeInstance); builder.appendSignature(this); builder.appendCompressedUnsignedInt(typeParamCount); for (int i = 0; i < typeParamCount; i++) { builder.appendByte((byte)SignatureTypeCode.GenericTypeParameter); builder.appendCompressedUnsignedInt(i); } return(builder.makeSignature()); } finally { builder.clear(); } }
/// <inheritdoc/> public TypeSignature Map(TypeSignature input) { if (_typemap.TryGetValue(input, out var result)) { return(result); } if (input.IsArray || input.IsPointer) { var baseType = new TypeSignatureBuilder(input) .WithArrayDimensions(0) .WithIndirectionLevel(0) .Build(); if (_typemap.TryGetValue(baseType, out var baseMappedType)) { var newMappedType = new TypeSignatureBuilder(baseMappedType) .WithArrayDimensions(baseMappedType.ArrayDimensions + input.ArrayDimensions) .WithIndirectionLevel(baseMappedType.IndirectionLevel + input.IndirectionLevel) .Build(); return(newMappedType); } } if (!_allowPassthrough) { throw new KeyNotFoundException("Could not find a valid mapping for the given type."); } return(input); }
public bool TryGetParameterVariant(Parameter parameter, out Parameter variant, Project core) { if (parameter.Type.OriginalGroup is null || core.Enums.All (x => x.Name != parameter.Type.OriginalGroup) /* || (parameter.Type.OriginalName != "GLenum" && * parameter.Type.OriginalName != "CLenum")*/) { variant = null; return(false); } var t = new TypeSignatureBuilder(parameter.Type).WithName (parameter.Type.OriginalGroup) .Build(); t.OriginalName = t.Name; // stop GLenum mapping variant = new ParameterSignatureBuilder(parameter).WithType ( t ) .Build() ; return(true); }
/// <inheritdoc/> public IEnumerable <(FunctionSignature, StringBuilder)> CreateOverloads(FunctionSignature function) { if (!IsApplicable(function)) { yield break; } var lastParameterType = function.Parameters.Last().Type; var newReturnType = new TypeSignatureBuilder(lastParameterType) .WithIndirectionLevel(lastParameterType.IndirectionLevel - 1) .WithArrayDimensions(0) .Build(); var newParameters = SkipLastExtension.SkipLast(function.Parameters, 1).ToList(); var newName = function.Name.Singularize(false); var functionBuilder = new FunctionSignatureBuilder(function) .WithName(newName) .WithReturnType(newReturnType); var sb = new StringBuilder(); var strParams = newParameters.Select(x => Utilities.CSharpKeywords.Contains(x.Name) ? "@" + x.Name : x.Name) .Concat(new[] { "ret" }); sb.AppendLine(lastParameterType + " ret = null;"); sb.Append(function.Name + "("); sb.Append(string.Join(", ", strParams)); sb.AppendLine(");"); sb.AppendLine("return *ret;"); if (!newParameters.Any()) { yield return(functionBuilder .WithParameters(newParameters) .Build(), sb); yield break; } // TODO: check if this has anything to do with CLS compliance var sizeParameterType = newParameters.Last().Type; if (!sizeParameterType.Name.StartsWith("int", StringComparison.OrdinalIgnoreCase) || sizeParameterType.IsPointer) { yield return(functionBuilder .WithParameters(newParameters) .Build(), sb); yield break; } newParameters = SkipLastExtension.SkipLast(newParameters, 1).ToList(); yield return ( functionBuilder .WithParameters(newParameters) .Build(), sb ); }
/// <inheritdoc/> public IEnumerable <FunctionSignature> CreateOverloads(FunctionSignature function) { var newReturnType = new TypeSignatureBuilder(function.ReturnType) .WithIndirectionLevel(0) .WithName(nameof(IntPtr)) .Build(); yield return(new FunctionSignatureBuilder(function) .WithReturnType(newReturnType) .Build()); }
/// <inheritdoc/> public IEnumerable <FunctionSignature> CreateOverloads(FunctionSignature function) { var baseParameters = function.Parameters; var staticCountPermutation = new List <ParameterSignature>(baseParameters); for (int i = 0; i < baseParameters.Count; ++i) { var baseParameter = baseParameters[i]; var baseType = baseParameter.Type; if (!HasStaticCount(baseParameter)) { continue; } // ReSharper disable once PossibleNullReferenceException var count = baseParameter.Count.Count; if (count > 1) { // TODO: Support higher-ranked types continue; } if (!baseType.IsPointer || baseType.IndirectionLevel > 1) { continue; } var refTypeBuilder = new TypeSignatureBuilder(baseType) .WithIndirectionLevel(0) .WithByRef(true); if (baseParameter.Flow == FlowDirection.Out) { refTypeBuilder = refTypeBuilder.WithIsOut(true); } var refType = refTypeBuilder.Build(); var refParameter = new ParameterSignatureBuilder(baseParameter) .WithType(refType) .Build(); staticCountPermutation[i] = refParameter; } yield return(new FunctionSignatureBuilder(function) .WithParameters(staticCountPermutation) .Build()); }
/// <inheritdoc/> public bool HasMapping(TypeSignature input) { if (!input.IsArray && !input.IsPointer) { return(_typemap.ContainsKey(input)); } var baseType = new TypeSignatureBuilder(input) .WithArrayDimensions(0) .WithIndirectionLevel(0) .Build(); return(_typemap.TryGetValue(baseType, out _) || _typemap.ContainsKey(input)); }
public bool TryCreateVariant(Type returnType, out Type variant, Project core) { if (returnType.OriginalGroup is null || core.Enums.All (x => x.Name != returnType.OriginalGroup) || returnType.OriginalName != "GLenum" || returnType.OriginalName != "CLenum") { variant = null; return(false); } variant = new TypeSignatureBuilder(returnType).WithName (returnType.OriginalGroup) .Build(); return(true); }
private bool TryCreateEnumVariant(Function function, out Function variant, Project core) { var varied = false; var newParameters = new List <Parameter>(); var paramsMod = false; Type newReturnType = function.ReturnType; foreach (var functionParameter in function.Parameters) { if (functionParameter.Type.OriginalGroup is null || core.Enums.All (x => x.Name != functionParameter.Type.OriginalGroup)) { newParameters.Add(functionParameter); continue; } paramsMod = true; varied = true; var t = new TypeSignatureBuilder(functionParameter.Type).WithName (functionParameter.Type.OriginalGroup) .Build(); t.OriginalName = t.Name; // stop GLenum mapping newParameters.Add ( new ParameterSignatureBuilder(functionParameter).WithType ( t ).Build() ); } if (!(function.ReturnType.OriginalGroup is null || core.Enums.All (x => x.Name != function.ReturnType.OriginalGroup))) { varied = true; newReturnType = new TypeSignatureBuilder(function.ReturnType).WithName (function.ReturnType.OriginalGroup) .Build(); newReturnType.OriginalName = newReturnType.Name; } variant = new FunctionSignatureBuilder(function).WithParameters(newParameters) .WithName(paramsMod ? function.Name : function.Name + "G") .WithReturnType(newReturnType) .Build(); return(varied); }
public bool TryGetParameterVariant(Parameter parameter, out Parameter variant, Project core) { Struct s; if (parameter.Type.OriginalClass is null || (s = core.Structs.FirstOrDefault (x => x.NativeName == parameter.Type.OriginalClass)) is null) { variant = null; return(false); } var t = new TypeSignatureBuilder(parameter.Type).WithName(s.Name).Build(); t.OriginalName = t.Name; // stop GLenum mapping variant = new ParameterSignatureBuilder(parameter).WithType(t).Build(); return(true); }
private static TypeSignature _forClassOrValueType(EntityHandle handle, bool isValueType) { if (handle.IsNil) { throw new ArgumentException("Handle for a class or value type must not be null.", nameof(handle)); } var builder = TypeSignatureBuilder.getInstance(); try { builder.appendByte((byte)(isValueType ? SignatureTypeKind.ValueType : SignatureTypeKind.Class)); builder.appendCompressedUnsignedInt(CodedIndex.TypeDefOrRefOrSpec(handle)); return(builder.makeSignature()); } finally { builder.clear(); } }
/// <summary> /// Returns a signature representing a general array type whose element type is represented /// by this signature. /// </summary> /// /// <param name="rank">The number of array dimensions.</param> /// <param name="lengths">A span containing the lengths for each dimension. The length of /// this argument must not be greater than <paramref name="rank"/>.</param> /// <param name="lowerBounds">A span containing the lower bounds for each dimension. The length of /// this argument must not be greater than <paramref name="rank"/>.</param> /// /// <returns>A <see cref="TypeSignature"/> representing the array type whose element type /// is represented by this signature and whose rank, lengths and lower bounds are given.</returns> /// /// <exception cref="InvalidOperationException">This signature represents a by-ref type.</exception> /// <exception cref="ArgumentOutOfRangeException">The rank is negative or zero, or the length /// of <paramref name="lengths"/> or <paramref name="lowerBounds"/> is greater than the rank.</exception> /// /// <remarks> /// This method creates a signature for a general array. To create a signature for a single-dimensional /// zero-based array, use <see cref="makeSZArray"/>. In particular, setting <paramref name="rank"/> /// to 1 and <paramref name="lengths"/> and <paramref name="lowerBounds"/> to empty spans does not /// create the same signature as <see cref="makeSZArray"/>. /// </remarks> public TypeSignature makeArray( int rank, ReadOnlySpan <int> lengths = default, ReadOnlySpan <int> lowerBounds = default) { if (rank <= 0) { throw new ArgumentOutOfRangeException(nameof(rank)); } if (lengths.Length > rank || lowerBounds.Length > rank) { throw new ArgumentOutOfRangeException("Number of lengths or lower bounds is greater than the array rank."); } if (isByRef()) { throw new InvalidOperationException("Cannot use a by-ref type as the element type of an array, pointer or by-ref type."); } var builder = TypeSignatureBuilder.getInstance(); try { builder.appendByte((byte)SignatureTypeCode.Array); builder.appendSignature(this); builder.appendCompressedUnsignedInt(rank); builder.appendCompressedUnsignedInt(lengths.Length); for (int i = 0; i < lengths.Length; i++) { builder.appendCompressedUnsignedInt(lengths[i]); } builder.appendCompressedUnsignedInt(lowerBounds.Length); for (int i = 0; i < lowerBounds.Length; i++) { builder.appendCompressedSignedInt(lowerBounds[i]); } return(builder.makeSignature()); } finally { builder.clear(); } }
/// <inheritdoc/> public ParameterSignature Map(ParameterSignature input) { var newType = _glTypeMapper.Map(input.Type); if (newType.Name.Equals("string", StringComparison.OrdinalIgnoreCase)) { if (input.Flow == FlowDirection.Out) { newType = new TypeSignatureBuilder(newType) .WithByRef(true) .WithIsOut(true) .Build(); } } return(new ParameterSignatureBuilder(input) .WithType(newType) .Build()); }
/// <inheritdoc/> public IEnumerable <ImplementedFunction> CreateOverloads(Function function) { if (!function.ReturnType.IsIntPtr()) { yield break; } var newReturnType = new TypeSignatureBuilder(function.ReturnType) .WithIndirectionLevel(1) .WithName("void") .Build(); yield return(Cast( new FunctionSignatureBuilder(function) .WithReturnType(newReturnType) .WithName($"{function.Name}AsPointer") .Build(), function)); }
/// <inheritdoc/> public IEnumerable <(FunctionSignature, StringBuilder)> CreateOverloads(FunctionSignature function) { if (!function.ReturnType.IsVoidPointer()) { yield break; } var newReturnType = new TypeSignatureBuilder(function.ReturnType) .WithIndirectionLevel(0) .WithName(nameof(IntPtr)) .Build(); yield return(Cast( new FunctionSignatureBuilder(function) .WithReturnType(newReturnType) .WithName(function.Name + "Ptr") .Build(), function)); }
/// <inheritdoc/> public IEnumerable <FunctionSignature> CreateOverloads(FunctionSignature function) { var lastParameterType = function.Parameters.Last().Type; var newReturnType = new TypeSignatureBuilder(lastParameterType) .WithIndirectionLevel(lastParameterType.IndirectionLevel - 1) .WithArrayDimensions(0) .Build(); var newParameters = SkipLastExtension.SkipLast(function.Parameters, 1).ToList(); var newName = function.Name.Singularize(false); var functionBuilder = new FunctionSignatureBuilder(function) .WithName(newName) .WithReturnType(newReturnType); if (!newParameters.Any()) { yield return(functionBuilder .WithParameters(newParameters) .Build()); yield break; } // TODO: check if this has anything to do with CLS compliance var sizeParameterType = newParameters.Last().Type; if (!sizeParameterType.Name.StartsWith("int", StringComparison.OrdinalIgnoreCase) || sizeParameterType.IsPointer) { yield return(functionBuilder .WithParameters(newParameters) .Build()); yield break; } newParameters = SkipLastExtension.SkipLast(newParameters, 1).ToList(); yield return(functionBuilder .WithParameters(newParameters) .Build()); }
/// <inheritdoc/> public bool TryGetFunctionVariant(Function function, out ImplementedFunction overload, Project core) { if (!IsApplicable(function)) { overload = null; return(false); } var arrayParameter = function.Parameters.Last(); var arrayParameterType = arrayParameter.Type; var newName = function.Name.Singularize(false); var newParameters = SkipLastExtension.SkipLast(new List <Parameter>(function.Parameters), 2).ToList(); var newArrayParameterType = new TypeSignatureBuilder(arrayParameterType) .WithArrayDimensions(0) .WithIndirectionLevel(0) .Build(); var newArrayParameter = new ParameterSignatureBuilder(arrayParameter) .WithType(newArrayParameterType) .Build(); newParameters.Add(newArrayParameter); var sb = new StringBuilder(); sb.AppendLine("// ArrayParameterOverloader"); sb.AppendLine($"{function.Name}(1, &{newArrayParameter.Name});"); overload = new ImplementedFunction(new FunctionSignatureBuilder(function) .WithName(newName) .WithParameters(newParameters) .Build(), sb, function, true); return(true); }
/// <summary> /// Returns a signature representing the type parameter of a generic method at the /// given position. /// </summary> /// <param name="position">The zero-based position of the type parameter.</param> /// <returns>A <see cref="TypeSignature"/> representing the type parameter of a generic method at the /// given position.</returns> /// <exception cref="ArgumentOutOfRangeException"><paramref name="position"/> is zero or negative.</exception> public static TypeSignature forGenericMethodParam(int position) { if (position < 0) { throw new ArgumentOutOfRangeException(nameof(position)); } if (position < 127) { return(new TypeSignature( (2L << 56) | (long)(position << 8) | (byte)SignatureTypeCode.GenericMethodParameter)); } var builder = TypeSignatureBuilder.getInstance(); try { builder.appendByte((byte)SignatureTypeCode.GenericMethodParameter); builder.appendCompressedUnsignedInt(position); return(builder.makeSignature()); } finally { builder.clear(); } }
/// <inheritdoc/> public IEnumerable <FunctionSignature> CreateOverloads(FunctionSignature function) { var arrayParameter = function.Parameters.Last(); var arrayParameterType = arrayParameter.Type; var newName = function.Name.Singularize(false); var newParameters = SkipLastExtension.SkipLast(new List <ParameterSignature>(function.Parameters), 2).ToList(); var newArrayParameterType = new TypeSignatureBuilder(arrayParameterType) .WithArrayDimensions(0) .WithIndirectionLevel(0) .Build(); var newArrayParameter = new ParameterSignatureBuilder(arrayParameter) .WithType(newArrayParameterType) .Build(); newParameters.Add(newArrayParameter); yield return(new FunctionSignatureBuilder(function) .WithName(newName) .WithParameters(newParameters) .Build()); }
public IEnumerable <Overload> CreateOverloads(Function function) { if (!function.Parameters.Any(x => x.Type.IsPointer && !x.Type.IsVoidPointer())) { yield break; } var sb = new StringBuilder(); var parameters = new List <string>(); var ind = string.Empty; var sig = new FunctionSignatureBuilder(function); var newParameters = new Parameter[function.Parameters.Count]; sb.AppendLine("// FlowPointerOverloader"); for (var i = 0; i < function.Parameters.Count; i++) { var param = function.Parameters[i]; if (param.Type.IsPointer && !param.Type.IsVoidPointer()) { var newParameterType = new TypeSignatureBuilder(param.Type) .WithIndirectionLevel(param.Type.IndirectionLevels - 1); switch (param.Flow) { case FlowDirection.Undefined: newParameterType = newParameterType.WithByRef(true); break; case FlowDirection.In: newParameterType = newParameterType.WithIsIn(true); break; case FlowDirection.Out: newParameterType = newParameterType.WithIsOut(true); break; default: throw new ArgumentOutOfRangeException(); } var newParameter = new ParameterSignatureBuilder(param).WithType(newParameterType.Build()); var ptrName = (param.Name + "Ptr").Replace("@", ""); parameters.Add(ptrName); sb.AppendLine(ind + $"fixed ({param.Type} {ptrName} = &{param.Name})"); sb.AppendLine(ind + "{"); ind += " "; newParameters[i] = newParameter.Build(); } else { parameters.Add((Utilities.CSharpKeywords.Contains(param.Name) ? "@" : string.Empty) + param.Name); newParameters[i] = param; } } sb.Append(ind); if (function.ReturnType.ToString() != "void") { sb.Append("return "); } sb.AppendLine(function.Name + "(" + string.Join(", ", parameters) + ");"); while (!string.IsNullOrEmpty(ind)) { ind = ind.Remove(ind.Length - 4, 4); sb.AppendLine(ind + "}"); } yield return(new Overload(sig.WithParameters(newParameters).Build(), sb, true)); }
/// <inheritdoc/> public IEnumerable <FunctionSignature> CreateOverloads(FunctionSignature function) { var baseParameters = function.Parameters; var newIntPtrParameters = new List <ParameterSignature>(baseParameters); var newGenericArray1DParameters = new List <ParameterSignature>(baseParameters); var newGenericArray2DParameters = new List <ParameterSignature>(baseParameters); var newGenericArray3DParameters = new List <ParameterSignature>(baseParameters); var newGenericRefParameters = new List <ParameterSignature>(baseParameters); var newGenericTypeParameters = new List <GenericTypeParameterSignature>(); for (int i = 0; i < baseParameters.Count; ++i) { var parameter = baseParameters[i]; if (!parameter.Type.IsVoidPointer()) { continue; } string genericTypeParameterName; if (baseParameters.Count(p => p.Type.IsVoidPointer()) > 1) { genericTypeParameterName = $"T{newGenericTypeParameters.Count + 1}"; } else { genericTypeParameterName = "T"; } var genericTypeParameter = new GenericTypeParameterSignature(genericTypeParameterName); newGenericTypeParameters.Add(genericTypeParameter); var newIntPtrParameterType = new TypeSignatureBuilder(parameter.Type) .WithIndirectionLevel(0) .WithName(nameof(IntPtr)) .Build(); // TODO: Simplify and generalize this var newGenericArray1DParameterType = new TypeSignatureBuilder(parameter.Type) .WithIndirectionLevel(0) .WithArrayDimensions(1) .WithName(genericTypeParameterName) .Build(); var newGenericArray2DParameterType = new TypeSignatureBuilder(parameter.Type) .WithIndirectionLevel(0) .WithArrayDimensions(2) .WithName(genericTypeParameterName) .Build(); var newGenericArray3DParameterType = new TypeSignatureBuilder(parameter.Type) .WithIndirectionLevel(0) .WithArrayDimensions(3) .WithName(genericTypeParameterName) .Build(); var newGenericRefParameterType = new TypeSignatureBuilder(parameter.Type) .WithIndirectionLevel(0) .WithName(genericTypeParameterName) .WithByRef(true) .Build(); newIntPtrParameters[i] = new ParameterSignatureBuilder(parameter) .WithType(newIntPtrParameterType) .Build(); newGenericArray1DParameters[i] = new ParameterSignatureBuilder(parameter) .WithType(newGenericArray1DParameterType) .Build(); newGenericArray2DParameters[i] = new ParameterSignatureBuilder(parameter) .WithType(newGenericArray2DParameterType) .Build(); newGenericArray3DParameters[i] = new ParameterSignatureBuilder(parameter) .WithType(newGenericArray3DParameterType) .Build(); newGenericRefParameters[i] = new ParameterSignatureBuilder(parameter) .WithType(newGenericRefParameterType) .Build(); } yield return(new FunctionSignatureBuilder(function) .WithParameters(newIntPtrParameters) .Build()); yield return(new FunctionSignatureBuilder(function) .WithParameters(newGenericArray1DParameters) .WithGenericTypeParameters(newGenericTypeParameters) .Build()); yield return(new FunctionSignatureBuilder(function) .WithParameters(newGenericArray2DParameters) .WithGenericTypeParameters(newGenericTypeParameters) .Build()); yield return(new FunctionSignatureBuilder(function) .WithParameters(newGenericArray3DParameters) .WithGenericTypeParameters(newGenericTypeParameters) .Build()); yield return(new FunctionSignatureBuilder(function) .WithParameters(newGenericRefParameters) .WithGenericTypeParameters(newGenericTypeParameters) .Build()); }
/// <inheritdoc/> public IEnumerable <(FunctionSignature, StringBuilder)> CreateOverloads(FunctionSignature function) { if (!function.Parameters.Any(p => p.Type.IsVoidPointer())) { yield break; } var baseParameters = function.Parameters; var newIntPtrParameters = new List <ParameterSignature>(baseParameters); var newGenericArray1DParameters = new List <ParameterSignature>(baseParameters); var newGenericArray2DParameters = new List <ParameterSignature>(baseParameters); var newGenericArray3DParameters = new List <ParameterSignature>(baseParameters); var newGenericTypeParameters = new List <GenericTypeParameterSignature>(); for (var i = 0; i < baseParameters.Count; ++i) { var parameter = baseParameters[i]; if (!parameter.Type.IsVoidPointer()) { continue; } var genericTypeParameterName = baseParameters.Count(p => p.Type.IsVoidPointer()) > 1 ? $"T{newGenericTypeParameters.Count + 1}" : "T"; var genericTypeParameter = new GenericTypeParameterSignature( genericTypeParameterName, new[] { "unmanaged" }); newGenericTypeParameters.Add(genericTypeParameter); var newIntPtrParameterType = new TypeSignatureBuilder(parameter.Type) .WithIndirectionLevel(0) .WithName(nameof(IntPtr)) .Build(); // TODO: Simplify and generalize this var newGenericArray1DParameterType = new TypeSignatureBuilder(parameter.Type) .WithIndirectionLevel(0) .WithArrayDimensions(1) .WithName(genericTypeParameterName) .Build(); var newGenericArray2DParameterType = new TypeSignatureBuilder(parameter.Type) .WithIndirectionLevel(0) .WithArrayDimensions(2) .WithName(genericTypeParameterName) .Build(); var newGenericArray3DParameterType = new TypeSignatureBuilder(parameter.Type) .WithIndirectionLevel(0) .WithArrayDimensions(3) .WithName(genericTypeParameterName) .Build(); newIntPtrParameters[i] = new ParameterSignatureBuilder(parameter) .WithType(newIntPtrParameterType) .Build(); newGenericArray1DParameters[i] = new ParameterSignatureBuilder(parameter) .WithType(newGenericArray1DParameterType) .Build(); newGenericArray2DParameters[i] = new ParameterSignatureBuilder(parameter) .WithType(newGenericArray2DParameterType) .Build(); newGenericArray3DParameters[i] = new ParameterSignatureBuilder(parameter) .WithType(newGenericArray3DParameterType) .Build(); } yield return(ToPointer ( new FunctionSignatureBuilder(function) .WithParameters(newIntPtrParameters) .Build(), function )); yield return(Fixed ( new FunctionSignatureBuilder(function) .WithParameters(newGenericArray1DParameters) .WithGenericTypeParameters(newGenericTypeParameters) .Build() )); yield return(Fixed ( new FunctionSignatureBuilder(function) .WithParameters(newGenericArray2DParameters) .WithGenericTypeParameters(newGenericTypeParameters) .Build() )); yield return(Fixed ( new FunctionSignatureBuilder(function) .WithParameters(newGenericArray3DParameters) .WithGenericTypeParameters(newGenericTypeParameters) .Build() )); }
/// <summary> /// Writes this struct to a file. /// </summary> /// <param name="struct">The enum to write.</param> /// <param name="file">The file to write to.</param> /// <param name="profile">The subsystem containing this enum.</param> /// <param name="project">The project containing this enum.</param> public static void WriteStruct(this Struct @struct, string file, Profile profile, Project project, BindState task) { if (@struct.Attributes.IsBuildToolsIntrinsic(out var args)) { WriteBuildToolsIntrinsic(@struct, file, profile, project, task, args); return; } var sw = new StreamWriter(file); sw.WriteLine(task.LicenseText()); sw.WriteLine(); sw.WriteCoreUsings(); sw.WriteLine(); sw.WriteLine("#pragma warning disable 1591"); sw.WriteLine(); var ns = project.IsRoot ? task.Task.Namespace : task.Task.ExtensionsNamespace; sw.WriteLine($"namespace {ns}{project.Namespace}"); sw.WriteLine("{"); foreach (var attr in @struct.Attributes) { if (attr.Name == "BuildToolsIntrinsic") { continue; } sw.WriteLine($" {attr}"); } sw.WriteLine($" [NativeName(\"Name\", \"{@struct.NativeName}\")]"); sw.WriteLine($" public unsafe partial struct {@struct.Name}"); sw.WriteLine(" {"); foreach (var comBase in @struct.ComBases) { var asSuffix = comBase.Split('.').Last(); asSuffix = (asSuffix.StartsWith('I') ? asSuffix.Substring(1) : comBase); asSuffix = asSuffix.StartsWith(task.Task.FunctionPrefix) ? asSuffix.Substring(task.Task.FunctionPrefix.Length) : asSuffix; var fromSuffix = @struct.Name.Split('.').Last(); fromSuffix = (fromSuffix.StartsWith('I') ? fromSuffix.Substring(1) : comBase); fromSuffix = fromSuffix.StartsWith(task.Task.FunctionPrefix) ? fromSuffix.Substring(task.Task.FunctionPrefix.Length) : fromSuffix; sw.WriteLine($" public static implicit operator {comBase}({@struct.Name} val)"); sw.WriteLine($" => Unsafe.As<{@struct.Name}, {comBase}>(ref val);"); sw.WriteLine(); if (@struct.Functions.Any(x => x.Signature.Name.Equals("QueryInterface"))) { sw.WriteLine($" public static explicit operator {@struct.Name}({comBase} val)"); sw.WriteLine($" => From{fromSuffix}(in val);"); sw.WriteLine(); sw.WriteLine($" public readonly ref {comBase} As{asSuffix}()"); sw.WriteLine(" {"); // yes i know this is unsafe and that there's a good reason why struct members can't return themselves // by reference, but this should work well enough. sw.WriteLine("#if NETSTANDARD2_1 || NET5_0 || NETCOREAPP3_1"); sw.WriteLine($" return ref Unsafe.As<{@struct.Name}, {comBase}>"); sw.WriteLine($" ("); sw.WriteLine($" ref MemoryMarshal.GetReference"); sw.WriteLine($" ("); sw.WriteLine($" MemoryMarshal.CreateSpan"); sw.WriteLine($" ("); sw.WriteLine($" ref Unsafe.AsRef(in this),"); sw.WriteLine($" 1"); sw.WriteLine($" )"); sw.WriteLine($" )"); sw.WriteLine($" );"); sw.WriteLine("#else"); sw.WriteLine($" fixed ({@struct.Name}* @this = &this)"); sw.WriteLine($" {{"); sw.WriteLine($" return ref *({comBase}*) @this;"); sw.WriteLine($" }}"); sw.WriteLine("#endif"); sw.WriteLine(" }"); sw.WriteLine(); sw.WriteLine($" public static ref {@struct.Name} From{fromSuffix}(in {comBase} @this)"); sw.WriteLine(" {"); sw.WriteLine($" {@struct.Name}* ret = default;"); sw.WriteLine($" SilkMarshal.ThrowHResult"); sw.WriteLine($" ("); sw.WriteLine($" @this.QueryInterface"); sw.WriteLine($" ("); sw.WriteLine($" ref SilkMarshal.GuidOf<{@struct.Name}>(),"); sw.WriteLine($" (void**) &ret"); sw.WriteLine($" )"); sw.WriteLine($" );"); sw.WriteLine(); sw.WriteLine($" return ref *ret;"); sw.WriteLine(" }"); sw.WriteLine(); } } if (@struct.Fields.Any(x => x.Count is null)) { sw.WriteLine($" public {@struct.Name}"); sw.WriteLine(" ("); var first = true; foreach (var field in @struct.Fields) { if (!(field.Count is null)) { continue; // I've chosen not to initialize multi-count fields from ctors. } var argName = field.Name[0].ToString().ToLower() + field.Name.Substring(1); argName = Utilities.CSharpKeywords.Contains(argName) ? $"@{argName}" : argName; if (!first) { sw.WriteLine(","); } else { first = false; } var nullable = field.Type.ToString().Contains('*') ? null : "?"; sw.Write($" {field.Type}{nullable} {argName} = {field.DefaultAssignment ?? "null"}"); } sw.WriteLine(); sw.WriteLine(" ) : this()"); sw.WriteLine(" {"); first = true; foreach (var field in @struct.Fields) { if (!(field.Count is null)) { continue; // I've chosen not to initialize multi-count fields from ctors. } var argName = field.Name[0].ToString().ToLower() + field.Name.Substring(1); argName = Utilities.CSharpKeywords.Contains(argName) ? $"@{argName}" : argName; if (!first) { sw.WriteLine(); } else { first = false; } sw.WriteLine($" if ({argName} is not null)"); sw.WriteLine(" {"); var value = field.Type.ToString().Contains('*') ? null : ".Value"; sw.WriteLine($" {field.Name} = {argName}{value};"); sw.WriteLine(" }"); } sw.WriteLine(" }"); sw.WriteLine(); } foreach (var structField in @struct.Fields) { if (!(structField.Count is null)) { if (!Field.FixedCapableTypes.Contains(structField.Type.Name)) { var count = structField.Count.IsConstant ? int.Parse ( profile.Projects.SelectMany(x => x.Value.Classes.SelectMany(y => y.Constants)) .FirstOrDefault(x => x.NativeName == structField.Count.ConstantName) ? .Value ?? throw new InvalidDataException("Couldn't find constant referenced") ) : structField.Count.IsStatic ? structField.Count.StaticCount : 1; var typeFixup09072020 = new TypeSignatureBuilder(structField.Type).WithIndirectionLevel (structField.Type.IndirectionLevels - 1).Build(); sw.WriteLine($" {structField.Doc}"); foreach (var attr in structField.Attributes) { sw.WriteLine($" {attr}"); } sw.WriteLine($" [NativeName(\"Type\", \"{structField.NativeType}\")]"); sw.WriteLine($" [NativeName(\"Type.Name\", \"{structField.Type.OriginalName}\")]"); sw.WriteLine($" [NativeName(\"Name\", \"{structField.NativeName}\")]"); sw.WriteLine($" public {structField.Name}Buffer {structField.Name};"); sw.WriteLine(); sw.WriteLine($" public struct {structField.Name}Buffer"); sw.WriteLine(" {"); for (var i = 0; i < count; i++) { sw.WriteLine($" public {typeFixup09072020} Element{i};"); } sw.WriteLine($" public ref {typeFixup09072020} this[int index]"); sw.WriteLine(" {"); sw.WriteLine(" get"); sw.WriteLine(" {"); sw.WriteLine($" if (index > {count - 1} || index < 0)"); sw.WriteLine(" {"); sw.WriteLine(" throw new ArgumentOutOfRangeException(nameof(index));"); sw.WriteLine(" }"); sw.WriteLine(); sw.WriteLine($" fixed ({typeFixup09072020}* ptr = &Element0)"); sw.WriteLine(" {"); sw.WriteLine(" return ref ptr[index];"); sw.WriteLine(" }"); sw.WriteLine(" }"); sw.WriteLine(" }"); if (!typeFixup09072020.IsPointer) { sw.WriteLine(); sw.WriteLine("#if NETSTANDARD2_1"); sw.WriteLine($" public Span<{typeFixup09072020}> AsSpan()"); sw.WriteLine($" => MemoryMarshal.CreateSpan(ref Element0, {count});"); sw.WriteLine("#endif"); } sw.WriteLine(" }"); sw.WriteLine(); } else { if (!string.IsNullOrEmpty(structField.Doc)) { sw.WriteLine($" {structField.Doc}"); } var count = structField.Count.IsConstant ? Utilities.ParseInt ( profile.Projects.SelectMany(x => x.Value.Classes.SelectMany(y => y.Constants)) .FirstOrDefault(x => x.NativeName == structField.Count.ConstantName)? .Value ?? profile.Projects.SelectMany(x => x.Value.Enums.SelectMany(y => y.Tokens)) .FirstOrDefault(x => x.NativeName == structField.Count.ConstantName)? .Value ?? throw new InvalidDataException("Couldn't find constant referenced") ) : structField.Count.IsStatic ? structField.Count.StaticCount : 1; var typeFixup09072020 = new TypeSignatureBuilder(structField.Type).WithIndirectionLevel //(structField.Type.IndirectionLevels - 1).Build(); (0).Build(); foreach (var attr in structField.Attributes) { sw.WriteLine($" {attr}"); } sw.WriteLine($" [NativeName(\"Type\", \"{structField.NativeType}\")]"); sw.WriteLine($" [NativeName(\"Type.Name\", \"{structField.Type.OriginalName}\")]"); sw.WriteLine($" [NativeName(\"Name\", \"{structField.NativeName}\")]"); sw.WriteLine($" public fixed {typeFixup09072020} {structField.Name}[{count}];"); } }
public static void Implement(StringBuilder sb, Function function, Struct parent, int index, bool retDeref = false) { if (function.Attributes.IsBuildToolsIntrinsic(out var args) && args[0] == "$CPPRETFIXUP") { sb.AppendLine($"{function.ReturnType} silkDotNetReturnFixupResult;"); sb.AppendLine("var pSilkDotNetReturnFixupResult = &silkDotNetReturnFixupResult;"); var indIncremented = new TypeSignatureBuilder(function.ReturnType) .WithIndirectionLevel(function.ReturnType.IndirectionLevels + 1) .Build(); var fixedUpFunction = new FunctionSignatureBuilder(function) .WithReturnType(indIncremented) .WithAttributes(Array.Empty <Attribute>()) .WithParameters ( function.Parameters.Prepend ( new Parameter { Name = "pSilkDotNetReturnFixupResult", Type = indIncremented } ).ToArray() ).Build(); Implement(sb, fixedUpFunction, parent, index, true); function.Attributes.RemoveAll(x => x.Name == "BuildToolsIntrinsic"); return; } var ind = ""; sb.AppendLine($"var @this = ({parent.Name}*) Unsafe.AsPointer(ref Unsafe.AsRef(in this));"); var epilogue = new List <Action>(); var parameterInvocations = new List <(Type Type, string Parameter)> { (new Type { Name = parent.Name, IndirectionLevels = 1 }, "@this") }; if (function.ReturnType.ToString() != "void") { sb.AppendLine($"{function.ReturnType} ret = default;"); } for (var i = 0; i < function.Parameters.Count; i++) { var parameter = function.Parameters[i]; if (parameter.Type.Name == "string") { // assume ansi if (parameter.Type.IsIn) { sb.AppendLine ($"var {parameter.Name}PtrInit = (byte*) Marshal.StringToHGlobalAnsi({parameter.Name});"); sb.AppendLine($"var {parameter.Name}Ptr = &{parameter.Name}PtrInit;"); parameterInvocations.Add ((new Type { Name = "byte", IndirectionLevels = 2 }, $"{parameter.Name}Ptr")); epilogue.Add(() => sb.AppendLine($"Marshal.FreeHGlobal((nint){parameter.Name}PtrInit);")); } else if (parameter.Type.IsByRef) { sb.AppendLine ($"var {parameter.Name}PtrInit = (byte*) Marshal.StringToHGlobalAnsi({parameter.Name});"); sb.AppendLine($"var {parameter.Name}Ptr = &{parameter.Name}PtrInit;"); parameterInvocations.Add ((new Type { Name = "byte", IndirectionLevels = 2 }, $"{parameter.Name}Ptr")); epilogue.Add ( () => { sb.AppendLine($"{parameter.Name} = Marshal.PtrToStringAnsi(*{parameter.Name}Ptr);"); sb.AppendLine($"Marshal.FreeHGlobal((nint){parameter.Name}PtrInit);"); } ); } else if (parameter.Type.IsOut) { throw new NotSupportedException ( "COM VTables don't support out strings due to lack of flow and count information." ); } else { sb.AppendLine ($"var {parameter.Name}Ptr = (byte*) Marshal.StringToHGlobalAnsi({parameter.Name});"); parameterInvocations.Add ((new Type { Name = "byte", IndirectionLevels = 1 }, $"{parameter.Name}Ptr")); epilogue.Add ( () => { sb.AppendLine($"Marshal.FreeHGlobal((nint){parameter.Name}Ptr);"); } ); } } else if (parameter.Type.IsIn || parameter.Type.IsOut || parameter.Type.IsByRef) { var noRef = new TypeSignatureBuilder(parameter.Type) .WithByRef(false) .WithIsIn(false) .WithIsOut(false) .WithIndirectionLevel(parameter.Type.IndirectionLevels + 1) .Build(); sb.AppendLine ( ind + $"fixed ({noRef} {parameter.Name}Ptr = &{parameter.Name})" ); sb.AppendLine(ind + "{"); parameterInvocations.Add((noRef, $"{parameter.Name}Ptr")); ind += " "; epilogue.Add ( () => { ind = ind.Substring(0, ind.Length - 4); sb.AppendLine(ind + "}"); } ); } else { parameterInvocations.Add((parameter.Type, parameter.Name)); } } if (function.ReturnType.ToString() != "void") { sb.Append(ind + "ret = "); } else { sb.Append(ind); } var conv = function.Convention switch { CallingConvention.Winapi => throw new NotImplementedException(), CallingConvention.Cdecl => "Cdecl", CallingConvention.StdCall => "Stdcall", CallingConvention.ThisCall => "Thiscall", CallingConvention.FastCall => "Fastcall", _ => "Cdecl" }; var fnPtrSig = string.Join(", ", parameterInvocations.Select(x => x.Type.ToString())); if (!string.IsNullOrWhiteSpace(fnPtrSig)) { fnPtrSig += ", "; } fnPtrSig += function.ReturnType; sb.Append($"((delegate* unmanaged[{conv}]<{fnPtrSig}>)"); sb.Append($"LpVtbl[{index}])"); sb.AppendLine("(" + string.Join(", ", parameterInvocations.Select(x => x.Parameter)) + ");"); for (var i = epilogue.Count - 1; i >= 0; i--) { epilogue[i](); } if (retDeref) { sb.AppendLine("return *ret;"); } else if (function.ReturnType.ToString() != "void") { sb.AppendLine("return ret;"); } } }
/// <inheritdoc/> public IEnumerable <Overload> CreateOverloads(Function function) { if (!IsApplicable(function)) { yield break; } var lastParameterType = function.Parameters.Last().Type; var newReturnType = new TypeSignatureBuilder(lastParameterType) .WithIndirectionLevel(lastParameterType.IndirectionLevels - 1) .WithArrayDimensions(0) .Build(); var newParameters = SkipLastExtension.SkipLast(function.Parameters, 1).ToList(); var newName = function.Name.Singularize(false); var functionBuilder = new FunctionSignatureBuilder(function) .WithName(newName) .WithReturnType(newReturnType); var sb = new StringBuilder(); var strParams = newParameters.Select(x => Utilities.CSharpKeywords.Contains(x.Name) ? "@" + x.Name : x.Name) .Concat(new[] { "&ret" }); sb.AppendLine("// ReturnTypeOverloader"); sb.AppendLine(newReturnType + " ret = default;"); sb.Append(function.Name + "("); sb.Append(string.Join(", ", strParams)); sb.AppendLine(");"); sb.AppendLine("return ret;"); if (!newParameters.Any()) { yield return(new Overload(functionBuilder .WithParameters(newParameters) .Build(), sb, true)); yield break; } var sizeParameterType = newParameters.Last().Type; if ((sizeParameterType.Name != "int" && sizeParameterType.Name != "uint") || sizeParameterType.IsPointer) { yield return(new Overload(functionBuilder .WithParameters(newParameters) .Build(), sb, true)); yield break; } var n = newParameters.Last().Name; sb.Insert(0, "const " + (sizeParameterType.Name == "uint" ? "uint " : "int ") + (Utilities.CSharpKeywords.Contains(n) ? "@" : "") + n + " = 1;\n"); newParameters = SkipLastExtension.SkipLast(newParameters, 1).ToList(); yield return(new Overload ( functionBuilder .WithParameters(newParameters) .Build(), sb, true )); }
/// <inheritdoc/> public IEnumerable <ImplementedFunction> CreateOverloads(Function function) { if (!IsApplicable(function)) { yield break; } var lastParameterType = function.Parameters.Last().Type; var newReturnType = new TypeSignatureBuilder(lastParameterType) .WithIndirectionLevel(lastParameterType.IndirectionLevels - 1) .WithArrayDimensions(0) .Build(); var newParameters = SkipLastExtension.SkipLast(function.Parameters, 1).ToList(); var newName = function.Name.Singularize(false); var functionBuilder = new FunctionSignatureBuilder(function) .WithName(newName) .WithReturnType(newReturnType); var sb = new StringBuilder(); var strParams = newParameters.Select(Convert).Concat(new[] { "&ret" }); sb.AppendLine("// ReturnTypeOverloader"); sb.AppendLine($"{newReturnType} ret = default;"); sb.Append($"{function.Name}("); sb.Append(string.Join(", ", strParams)); sb.AppendLine(");"); sb.AppendLine("return ret;"); if (!newParameters.Any()) { yield return(new ImplementedFunction(functionBuilder .WithParameters(newParameters) .Build(), sb, true)); yield break; } var sizeParameterType = newParameters.Last().Type; if ((sizeParameterType.Name != "int" && sizeParameterType.Name != "uint") || sizeParameterType.IsPointer) { yield return(new ImplementedFunction(functionBuilder .WithParameters(newParameters) .Build(), sb, true)); yield break; } var n = newParameters.Last().Name; sb.Insert(0, $"const {(sizeParameterType.Name == "uint" ? "uint " : "int ")}{(Utilities.CSharpKeywords.Contains(n) ? "@" : "")}{n} = 1;\n" ); newParameters = SkipLastExtension.SkipLast(newParameters, 1).ToList(); yield return(new ImplementedFunction ( functionBuilder .WithParameters(newParameters) .Build(), sb, true )); string Convert(Parameter x) { var pre = x.Type.IsOut ? "out " : string.Empty; return(pre + (Utilities.CSharpKeywords.Contains(x.Name) ? $"@{x.Name}" : x.Name)); } }
/// <inheritdoc/> public IEnumerable <FunctionSignature> CreateOverloads(FunctionSignature function) { var baseParameters = function.Parameters; var refParameterPermutation = new List <ParameterSignature>(baseParameters); var arrayParameterPermutation = new List <ParameterSignature>(baseParameters); for (int i = 0; i < baseParameters.Count; ++i) { var baseParameter = baseParameters[i]; var baseType = baseParameter.Type; if (!baseType.IsPointer || baseType.IndirectionLevel > 1) { continue; } if (baseType.Name.Equals(typeof(void).Name, StringComparison.OrdinalIgnoreCase)) { // Skip void pointers continue; } var refTypeBuilder = new TypeSignatureBuilder(baseType) .WithIndirectionLevel(0) .WithByRef(true); if (baseParameter.Flow == FlowDirection.Out) { refTypeBuilder = refTypeBuilder.WithIsOut(true); } var refType = refTypeBuilder.Build(); var refParameter = new ParameterSignatureBuilder(baseParameter) .WithType(refType) .Build(); refParameterPermutation[i] = refParameter; if (!(baseParameter.Count is null) && baseParameter.Count.IsStatic && baseParameter.Count.Count == 1) { // Single-element count pointers don't need array overloads continue; } var arrayType = new TypeSignatureBuilder(baseType) .WithIndirectionLevel(0) .WithArrayDimensions(1) .Build(); var arrayParameter = new ParameterSignatureBuilder(baseParameter) .WithType(arrayType) .Build(); arrayParameterPermutation[i] = arrayParameter; } yield return(new FunctionSignatureBuilder(function) .WithParameters(refParameterPermutation) .Build()); yield return(new FunctionSignatureBuilder(function) .WithParameters(arrayParameterPermutation) .Build()); }