SLBaseExpr MarshalProtocolListTypeSpec(BaseDeclaration declContext, string name, ProtocolListTypeSpec protocols) { // let p = UnsafeMutablePointer<protoType>.allocate (argName) // p.initialize(to: argName) // exp is toIntPtr(value: p) // ... // if isInOut: // argName = p.pointee // always: // p.deinitialize () // p.deallocate () var bindingName = new SLIdentifier(MarshalEngine.Uniqueify(name, identifiersUsed)); var argType = typeMapper.TypeSpecMapper.MapType(declContext, imports, protocols, false); var ptrType = new SLBoundGenericType("UnsafeMutablePointer", argType); identifiersUsed.Add(bindingName.Name); var decl = new SLDeclaration(true, bindingName, ptrType, new SLFunctionCall(ptrType + ".allocate", false, new SLArgument(new SLIdentifier("capacity"), SLConstant.Val(1), true)), Visibility.None, false); var varBinding = new SLLine(decl); preMarshalCode.Add(varBinding); var initCall = SLFunctionCall.FunctionCallLine(bindingName.Name + ".initialize", new SLArgument(new SLIdentifier("to"), new SLIdentifier(name), true)); preMarshalCode.Add(initCall); imports.AddIfNotPresent("XamGlue"); if (protocols.IsInOut) { postMarshalCode.Add(new SLLine(new SLBinding(name, bindingName.Dot(new SLIdentifier("pointee"))))); } postMarshalCode.Add(SLFunctionCall.FunctionCallLine($"{bindingName.Name}.deinitialize", new SLArgument(new SLIdentifier("count"), SLConstant.Val(1), true))); postMarshalCode.Add(SLFunctionCall.FunctionCallLine($"{bindingName.Name}.deallocate")); return(new SLFunctionCall("toIntPtr", false, new SLArgument(new SLIdentifier("value"), bindingName, true))); }
SLType MapType(BaseDeclaration declContext, SLImportModules modules, NamedTypeSpec spec) { SLType retval = null; if (spec.HasModule) { modules.AddIfNotPresent(spec.Module); } if (declContext.IsTypeSpecGeneric(spec) && !spec.ContainsGenericParameters) { Tuple <int, int> depthIndex = declContext.GetGenericDepthAndIndex(spec); retval = new SLGenericReferenceType(depthIndex.Item1, depthIndex.Item2); } else if (spec.ContainsGenericParameters) { retval = new SLBoundGenericType(spec.NameWithoutModule, spec.GenericParameters.Select(p => MapType(declContext, modules, p, false))); } else { retval = new SLSimpleType(spec.Name.NameWithoutModule()); } if (spec.InnerType == null) { return(retval); } else { return(new SLCompoundType(retval, MapType(declContext, modules, spec.InnerType))); } }
SLType MapType(BaseDeclaration declContext, SLImportModules modules, NamedTypeSpec spec) { SLType retval = null; if (spec.HasModule(declContext, this.parent)) { modules.AddIfNotPresent(spec.Module); } if (declContext.IsTypeSpecGeneric(spec) && !spec.ContainsGenericParameters) { Tuple <int, int> depthIndex = declContext.GetGenericDepthAndIndex(spec); retval = new SLGenericReferenceType(depthIndex.Item1, depthIndex.Item2); } else if (spec.ContainsGenericParameters) { retval = new SLBoundGenericType(spec.NameWithoutModule, spec.GenericParameters.Select(p => MapType(declContext, modules, p, false))); } else { if (declContext.IsProtocolWithAssociatedTypesFullPath(spec, parent)) { // for T.AssocType var genPart = spec.Module; var depthIndex = declContext.GetGenericDepthAndIndex(genPart); var newGenPart = new SLGenericReferenceType(depthIndex.Item1, depthIndex.Item2); retval = new SLSimpleType($"{newGenPart}.{spec.NameWithoutModule}"); } else { retval = new SLSimpleType(spec.NameWithoutModule); } } if (spec.InnerType == null) { return(retval); } else { return(new SLCompoundType(retval, MapType(declContext, modules, spec.InnerType))); } }
SLBaseExpr MarshalTupleTypeSpec(BaseDeclaration declContext, string name, TupleTypeSpec tuple) { var bindingName = new SLIdentifier(MarshalEngine.Uniqueify(name, identifiersUsed)); var argType = typeMapper.TypeSpecMapper.MapType(declContext, imports, tuple, false); var ptrType = new SLBoundGenericType("UnsafeMutablePointer", argType); identifiersUsed.Add(bindingName.Name); var decl = new SLDeclaration(true, bindingName, ptrType, new SLFunctionCall(ptrType + ".allocate", false, new SLArgument(new SLIdentifier("capacity"), SLConstant.Val(1), true)), Visibility.None, false); var varBinding = new SLLine(decl); preMarshalCode.Add(varBinding); var initCall = SLFunctionCall.FunctionCallLine(bindingName.Name + ".initialize", new SLArgument(new SLIdentifier("to"), new SLIdentifier(name), true)); preMarshalCode.Add(initCall); imports.AddIfNotPresent("XamGlue"); if (tuple.IsInOut) { postMarshalCode.Add(new SLLine(new SLBinding(name, bindingName.Dot(new SLIdentifier("pointee"))))); } return(new SLFunctionCall("toIntPtr", false, new SLArgument(new SLIdentifier("value"), bindingName, true))); }
public IEnumerable <ICodeElement> MarshalFunctionCall(FunctionDeclaration func, string vtableName, string vtableElementName) { preMarshalCode.Clear(); postMarshalCode.Clear(); ICodeElement returnLine = null; var instanceEntity = typeMapper.GetEntityForTypeSpec(func.ParameterLists [0] [0].TypeSpec); bool instanceIsProtocol = instanceEntity.EntityType == EntityType.Protocol; // bool returnIsGeneric = func.ReturnTypeSpec != null && func.IsGenericType(func.ReturnTypeSpec); SLIdentifier returnIdent = null; if (func.ParameterLists.Count != 2) { throw new ArgumentException(String.Format("Method {0} is has {1} parameter lists - it should really have two (normal for an instance method).", func.ToFullyQualifiedName(true), func.ParameterLists.Count)); } var closureArgs = new List <SLBaseExpr> (); // marshal the regular arguments for (int i = 0; i < func.ParameterLists [1].Count; i++) { var parm = func.ParameterLists [1] [i]; var privateName = !String.IsNullOrEmpty(parm.PrivateName) ? parm.PrivateName : TypeSpecToSLType.ConjureIdentifier(null, i).Name; if (func.IsTypeSpecGeneric(parm)) { Tuple <int, int> depthIndex = func.GetGenericDepthAndIndex(parm.TypeSpec); closureArgs.Add(MarshalGenericTypeSpec(func, privateName, parm.TypeSpec as NamedTypeSpec, depthIndex.Item1, depthIndex.Item2)); } else { closureArgs.Add(MarshalTypeSpec(func, privateName, parm.TypeSpec)); } } string callName = String.Format("{0}.{1}", vtableName, vtableElementName); var callInvocation = new SLPostBang(new SLIdentifier(callName), false); if (instanceIsProtocol) { string protoName = MarshalEngine.Uniqueify("selfProto", identifiersUsed); identifiersUsed.Add(protoName); var selfProtoDecl = new SLDeclaration(false, new SLBinding(protoName, new SLIdentifier("self"), new SLSimpleType(func.ParameterLists [0] [0].TypeName.NameWithoutModule())), Visibility.None); preMarshalCode.Add(new SLLine(selfProtoDecl)); closureArgs.Insert(0, new SLAddressOf(new SLIdentifier(protoName), false)); } else { // add self as a parameter imports.AddIfNotPresent("XamGlue"); closureArgs.Insert(0, new SLFunctionCall("toIntPtr", false, new SLArgument(new SLIdentifier("value"), new SLIdentifier("self"), true))); } string throwReturnName = null; SLIdentifier throwReturn = null; SLType throwReturnType = null; throwReturnType = new SLTupleType( new SLNameTypePair(SLParameterKind.None, "_", func.ReturnTypeSpec == null || func.ReturnTypeSpec.IsEmptyTuple ? SLSimpleType.Void : typeMapper.TypeSpecMapper.MapType(func, imports, func.ReturnTypeSpec, true)), new SLNameTypePair(SLParameterKind.None, "_", new SLSimpleType("Swift.Error")), new SLNameTypePair(SLParameterKind.None, "_", new SLSimpleType("Bool"))); if (func.HasThrows) { throwReturnName = MarshalEngine.Uniqueify("retval", identifiersUsed); identifiersUsed.Add(throwReturnName); throwReturn = new SLIdentifier(throwReturnName); imports.AddIfNotPresent("XamGlue"); // FIXME for generics var throwReturnDecl = new SLDeclaration(true, new SLBinding(throwReturn, new SLFunctionCall(String.Format("UnsafeMutablePointer<{0}>.allocate", throwReturnType.ToString()), false, new SLArgument(new SLIdentifier("capacity"), SLConstant.Val(1), true))), Visibility.None); closureArgs.Insert(0, new SLFunctionCall("toIntPtr", false, new SLArgument(new SLIdentifier("value"), throwReturn, true))); preMarshalCode.Add(new SLLine(throwReturnDecl)); } if (func.HasThrows) { returnLine = new SLLine(new SLNamedClosureCall(callInvocation, new CommaListElementCollection <SLBaseExpr> (closureArgs))); string errName = MarshalEngine.Uniqueify("err", identifiersUsed); identifiersUsed.Add(errName); var errIdent = new SLIdentifier(errName); var errDecl = new SLDeclaration(true, new SLBinding(errIdent, new SLFunctionCall("getExceptionThrown", false, new SLArgument(new SLIdentifier("retval"), throwReturn, true))), Visibility.None); postMarshalCode.Add(new SLLine(errDecl)); var ifblock = new SLCodeBlock(null); SLCodeBlock elseblock = null; ifblock.Add(SLFunctionCall.FunctionCallLine($"{throwReturnName}.deinitialize", new SLArgument(new SLIdentifier("count"), SLConstant.Val(1), true))); ifblock.Add(SLFunctionCall.FunctionCallLine($"{throwReturnName}.deallocate")); ifblock.Add(new SLLine(new SLThrow(new SLPostBang(errIdent, false)))); if (func.ReturnTypeSpec != null && !func.ReturnTypeSpec.IsEmptyTuple) { elseblock = new SLCodeBlock(null); string retvalvalName = MarshalEngine.Uniqueify("retvalval", identifiersUsed); identifiersUsed.Add(retvalvalName); SLIdentifier retvalval = new SLIdentifier(retvalvalName); string tuplecracker = "getExceptionNotThrown"; var retvalvaldecl = new SLDeclaration(true, new SLBinding(retvalval, new SLFunctionCall(tuplecracker, false, new SLArgument(new SLIdentifier("retval"), throwReturn, true))), Visibility.None); elseblock.Add(new SLLine(retvalvaldecl)); elseblock.Add(SLFunctionCall.FunctionCallLine($"{throwReturnName}.deallocate")); ISLExpr returnExpr = new SLPostBang(retvalval, false); elseblock.Add(SLReturn.ReturnLine(returnExpr)); } postMarshalCode.Add(new SLIfElse(new SLBinaryExpr(BinaryOp.NotEqual, errIdent, SLConstant.Nil), ifblock, elseblock)); } else { if (func.ReturnTypeSpec == null || func.ReturnTypeSpec.IsEmptyTuple) { // On no return value // _vtable.entry!(args) // returnLine = new SLLine(new SLNamedClosureCall(callInvocation, new CommaListElementCollection <SLBaseExpr> (closureArgs))); } else { if (TypeSpec.IsBuiltInValueType(func.ReturnTypeSpec)) { // on simple return types (Int, UInt, Bool, etc) // return _vtable.entry!(args) // var closureCall = new SLNamedClosureCall(callInvocation, new CommaListElementCollection <SLBaseExpr> (closureArgs)); if (postMarshalCode.Count == 0) { returnLine = SLReturn.ReturnLine(closureCall); } else { returnIdent = new SLIdentifier(MarshalEngine.Uniqueify("retval", identifiersUsed)); identifiersUsed.Add(returnIdent.Name); var retvalDecl = new SLDeclaration(true, returnIdent, null, closureCall, Visibility.None); returnLine = new SLLine(retvalDecl); postMarshalCode.Add(SLReturn.ReturnLine(returnIdent)); } } else { if (func.IsTypeSpecGeneric(func.ReturnTypeSpec)) { imports.AddIfNotPresent("XamGlue"); // dealing with a generic here. // UnsafeMutablePointer<T> retval = UnsafeMutablePointer<T>.alloc(1) // someCall(toIntPtr(retval), ...) // T actualRetval = retval.move() // retval.dealloc(1) // return actualRetval returnIdent = new SLIdentifier(MarshalEngine.Uniqueify("retval", identifiersUsed)); identifiersUsed.Add(returnIdent.Name); Tuple <int, int> depthIndex = func.GetGenericDepthAndIndex(func.ReturnTypeSpec); var retvalDecl = new SLDeclaration(true, returnIdent, null, new SLFunctionCall(String.Format("UnsafeMutablePointer<{0}>.allocate", SLGenericReferenceType.DefaultNamer(depthIndex.Item1, depthIndex.Item2)), false, new SLArgument(new SLIdentifier("capacity"), SLConstant.Val(1), true)), Visibility.None); preMarshalCode.Add(new SLLine(retvalDecl)); closureArgs.Insert(0, new SLFunctionCall("toIntPtr", false, new SLArgument(new SLIdentifier("value"), returnIdent, true))); SLIdentifier actualReturnIdent = new SLIdentifier(MarshalEngine.Uniqueify("actualRetval", identifiersUsed)); identifiersUsed.Add(actualReturnIdent.Name); returnLine = new SLLine(new SLNamedClosureCall(callInvocation, new CommaListElementCollection <SLBaseExpr> (closureArgs))); var actualRetvalDecl = new SLDeclaration(true, actualReturnIdent, null, new SLFunctionCall(String.Format("{0}.move", returnIdent.Name), false), Visibility.None); postMarshalCode.Add(new SLLine(actualRetvalDecl)); postMarshalCode.Add(SLFunctionCall.FunctionCallLine(String.Format("{0}.deallocate", returnIdent.Name))); postMarshalCode.Add(SLReturn.ReturnLine(actualReturnIdent)); } else if (NamedSpecIsClass(func.ReturnTypeSpec as NamedTypeSpec)) { // class (not struct or enum) return type is a pointer // if we have no post marshal code: // return fromIntPtr(_vtable.entry!(args)) // if we have post marshal code: // let retval:returnType = fromIntPtr(_vtable.entry!(args)) // ... post marshal code // return retval; imports.AddIfNotPresent("XamGlue"); SLBaseExpr callExpr = new SLFunctionCall("fromIntPtr", false, new SLArgument(new SLIdentifier("ptr"), new SLNamedClosureCall(callInvocation, new CommaListElementCollection <SLBaseExpr> (closureArgs)), true)); if (postMarshalCode.Count > 0) { string retvalName = MarshalEngine.Uniqueify("retval", identifiersUsed); var retDecl = new SLDeclaration(true, retvalName, typeMapper.TypeSpecMapper.MapType(func, imports, func.ReturnTypeSpec, true), callExpr); returnLine = new SLLine(retDecl); postMarshalCode.Add(SLReturn.ReturnLine(new SLIdentifier(retvalName))); } else { returnLine = SLReturn.ReturnLine(callExpr); } } else { var entity = typeMapper.GetEntityForTypeSpec(func.ReturnTypeSpec); if (func.ReturnTypeSpec is NamedTypeSpec && entity == null) { throw new NotImplementedException($"Function {func.ToFullyQualifiedName (true)} has an unknown return type {func.ReturnTypeSpec.ToString ()}"); } if (entity?.EntityType == EntityType.TrivialEnum) { imports.AddIfNotPresent(entity.Type.Module.Name); var slSelf = new SLIdentifier($"{entity.Type.Name}.self"); SLBaseExpr callExpr = new SLFunctionCall("unsafeBitCast", false, new SLArgument(new SLIdentifier("_"), new SLNamedClosureCall(callInvocation, new CommaListElementCollection <SLBaseExpr> (closureArgs)), false), new SLArgument(new SLIdentifier("to"), slSelf, true)); if (postMarshalCode.Count == 0) { returnLine = SLReturn.ReturnLine(callExpr); } else { returnIdent = new SLIdentifier(MarshalEngine.Uniqueify("retval", identifiersUsed)); identifiersUsed.Add(returnIdent.Name); var retvalDecl = new SLDeclaration(true, returnIdent, null, callExpr, Visibility.None); returnLine = new SLLine(retvalDecl); postMarshalCode.Add(SLReturn.ReturnLine(returnIdent)); } } else { switch (func.ReturnTypeSpec.Kind) { case TypeSpecKind.Closure: // let retval:CT = allocSwiftClosureToFunc_ARGS () // _vtable.entry!(retval, args) // let actualReturn = netFuncToSwiftClosure (retval.move()) // retval.deallocate() // return actualReturn var ct = func.ReturnTypeSpec as ClosureTypeSpec; var slct = new SLBoundGenericType("UnsafeMutablePointer", ToMarshaledClosureType(func, ct)); var ptrName = MarshalEngine.Uniqueify("retval", identifiersUsed); identifiersUsed.Add(ptrName); var ptrAllocCallSite = ct.HasReturn() ? $"allocSwiftClosureToFunc_{ct.ArgumentCount()}" : $"allocSwiftClosureToAction_{ct.ArgumentCount ()}"; var ptrAllocCall = new SLFunctionCall(ptrAllocCallSite, false); var ptrDecl = new SLDeclaration(true, new SLIdentifier(ptrName), slct, ptrAllocCall, Visibility.None); preMarshalCode.Add(new SLLine(ptrDecl)); closureArgs.Insert(0, new SLIdentifier(ptrName)); returnLine = new SLLine(new SLNamedClosureCall(callInvocation, new CommaListElementCollection <SLBaseExpr> (closureArgs))); var actualReturnName = MarshalEngine.Uniqueify("actualReturn", identifiersUsed); identifiersUsed.Add(actualReturnName); var convertCallSite = ct.HasReturn() ? "netFuncToSwiftClosure" : "netActionToSwiftClosure"; var isEmptyClosure = !ct.HasReturn() && !ct.HasArguments(); var pointerMove = new SLFunctionCall($"{ptrName}.move", false); var convertCall = isEmptyClosure ? pointerMove : new SLFunctionCall(convertCallSite, false, new SLArgument(new SLIdentifier("a1"), pointerMove, true)); var actualDecl = new SLDeclaration(true, actualReturnName, value: convertCall, vis: Visibility.None); postMarshalCode.Add(new SLLine(actualDecl)); postMarshalCode.Add(new SLReturn(new SLIdentifier(actualReturnName))); break; case TypeSpecKind.ProtocolList: case TypeSpecKind.Tuple: case TypeSpecKind.Named: var namedReturn = func.ReturnTypeSpec as NamedTypeSpec; // enums and structs can't get returned directly // instead they will be inserted at the head of the argument list // let retval = UnsafeMutablePointer<StructOrEnumType>.allocate(capacity: 1) // _vtable.entry!(retval, args) // T actualRetval = retval.move() // retval.deallocate() // return actualRetval string allocCallSite = String.Format("UnsafeMutablePointer<{0}>.allocate", func.ReturnTypeName); if (namedReturn != null) { imports.AddIfNotPresent(namedReturn.Module); } string retvalName = MarshalEngine.Uniqueify("retval", identifiersUsed); identifiersUsed.Add(retvalName); var retDecl = new SLDeclaration(true, retvalName, null, new SLFunctionCall(allocCallSite, false, new SLArgument(new SLIdentifier("capacity"), SLConstant.Val(1), true)), Visibility.None); preMarshalCode.Add(new SLLine(retDecl)); closureArgs.Insert(0, new SLIdentifier(retvalName)); returnLine = new SLLine(new SLNamedClosureCall(callInvocation, new CommaListElementCollection <SLBaseExpr> (closureArgs))); SLIdentifier actualReturnIdent = new SLIdentifier(MarshalEngine.Uniqueify("actualRetval", identifiersUsed)); identifiersUsed.Add(actualReturnIdent.Name); var actualRetvalDecl = new SLDeclaration(true, actualReturnIdent, null, new SLFunctionCall(String.Format("{0}.move", retvalName), false), Visibility.None); postMarshalCode.Add(new SLLine(actualRetvalDecl)); postMarshalCode.Add(SLFunctionCall.FunctionCallLine( String.Format("{0}.deallocate", retvalName))); postMarshalCode.Add(SLReturn.ReturnLine(actualReturnIdent)); break; } } } } } } foreach (ICodeElement line in preMarshalCode) { yield return(line); } yield return(returnLine); foreach (ICodeElement line in postMarshalCode) { yield return(line); } }
public SLParameter ToParameter(TypeMapper typeMapper, FunctionDeclaration func, SLImportModules modules, ParameterItem p, int index, bool dontChangeInOut, SLGenericTypeDeclarationCollection genericDecl = null, bool remapSelf = false, string remappedSelfName = "") { var pIsGeneric = func.IsTypeSpecGeneric(p) && p.TypeSpec is NamedTypeSpec; var parmTypeEntity = !pIsGeneric?typeMapper.GetEntityForTypeSpec(p.TypeSpec) : null; if (parmTypeEntity == null && !pIsGeneric && p.IsInOut) { throw ErrorHelper.CreateError(ReflectorError.kTypeMapBase + 45, $"In function {func.ToFullyQualifiedName ()}, unknown type parameter type {p.PublicName}:{p.TypeName}."); } var parmKind = p.IsInOut && (pIsGeneric || !parmTypeEntity.IsStructOrEnum) ? SLParameterKind.InOut : SLParameterKind.None; SLType parmType = null; var pTypeSpec = remapSelf ? p.TypeSpec.ReplaceName("Self", remappedSelfName) : p.TypeSpec; if (genericDecl != null) { GatherGenerics(typeMapper, func, modules, pTypeSpec, genericDecl); } if (pIsGeneric) { if (pTypeSpec.ContainsGenericParameters) { var ns = pTypeSpec as NamedTypeSpec; var boundGen = new SLBoundGenericType(ns.Name, pTypeSpec.GenericParameters.Select(genParm => { return(MapType(func, modules, genParm, true)); })); if (parent.MustForcePassByReference(func, ns)) { boundGen = new SLBoundGenericType("UnsafeMutablePointer", boundGen); } parmType = boundGen; } else { var namedType = pTypeSpec as NamedTypeSpec; if (namedType == null) { throw new NotImplementedException("Can only have a named type spec here."); } var depthIndex = func.GetGenericDepthAndIndex(namedType.Name); var gd = func.GetGeneric(depthIndex.Item1, depthIndex.Item2); var genRef = new SLGenericReferenceType(depthIndex.Item1, depthIndex.Item2); parmType = genRef; } } else { parmType = MapType(func, modules, pTypeSpec, false); if (pIsGeneric) { Tuple <int, int> depthIndex = func.GetGenericDepthAndIndex(pTypeSpec); parmType = new SLGenericReferenceType(depthIndex.Item1, depthIndex.Item2); } else if (parent.MustForcePassByReference(func, pTypeSpec) && !dontChangeInOut) { parmType = new SLBoundGenericType(p.IsInOut ? "UnsafeMutablePointer" : "UnsafePointer", parmType); } } if (isForOverride && p.IsVariadic) { // if we get here, then parmType is an SLSimpleType of SwiftArray<someType> // we're going to turn it into "someType ..." var oldParmType = parmType as SLBoundGenericType; parmType = new SLVariadicType(oldParmType.BoundTypes [0]); } var publicName = !p.NameIsRequired ? null : ConjureIdentifier(p.PublicName, index); var privateName = !String.IsNullOrEmpty(p.PrivateName) ? p.PrivateName : null; return(new SLParameter(publicName, ConjureIdentifier(privateName, index), parmType, parmKind)); }