string GetDelegateCall(Source src, DelegateType dt, List <string> arguments) { var parameters = dt.Parameters; // + 1 for the delegate itself if (parameters.Length + 1 != arguments.Count) { Log.Error(src, ErrorCode.E0000, "Foreign CPlusPlus error: Wrong number of arguments for macro call to delegate " + dt.FullName + "."); } string[] foreignParamTypes; string[] unoArgs; ConvertDelegateArguments(src, parameters, out foreignParamTypes, out unoArgs); var returnConversion = GetConversion(src, dt.ReturnType); using (var sw = new StringWriter()) using (var tf = new TextFormatter(sw)) { tf.BeginLine(); tf.Write("[] (" + Helpers.CompiledType(dt) + " __unoDelegate"); for (var i = 0; i < parameters.Length; ++i) { var p = parameters[i]; tf.Write(", " + foreignParamTypes[i] + " " + p.Name); } tf.Write(") -> " + returnConversion.ForeignType); tf.EndLine(); tf.Indent("{"); var call = Helpers.CallDelegate( Helpers.StringExpr(dt, "__unoDelegate"), parameters.Select((p, i) => Helpers.StringExpr(p.Type, unoArgs[i])).ToArray()); tf.WriteLine((dt.ReturnType.IsVoid ? call : "return " + call) + ";"); tf.Unindent(); tf.Write("} (" + string.Join(", ", arguments) + ")"); return(sw.ToString()); } }
string WrapBody(Function f, string body) { if (!f.IsStatic) { Log.Error(f.Source, ErrorCode.E0000, "Foreign CPlusPlus functions must be static"); } var paramConversions = f.Parameters.Select(GetParamConversion).ToArray(); var paramNames = f.Parameters.Select((x, i) => "@IL$" + i).ToArray(); var foreignParamNames = f.Parameters.Select(x => x.UnoName).ToArray(); var returnConversion = GetConversion(f.Source, f.ReturnType); var arguments = paramConversions.Select((p, i) => p.FromUno(paramNames[i])).ToArray(); if (paramConversions.All(x => x.IsIdentity)) { return(body); } else { using (var sw = new StringWriter()) { using (var tf = new TextFormatter(sw)) { tf.BeginLine(); tf.Write("[] "); tf.Write(ForeignTypeParamList(paramConversions, foreignParamNames)); tf.Write(" -> "); tf.Write(returnConversion.ForeignType); tf.EndLine(); tf.Indent("{"); tf.WriteLines(body); tf.Unindent(); tf.Write("} ("); tf.Write(string.Join(", ", arguments)); tf.Write(")"); return(MakeReturnStatement(f.ReturnType, sw.ToString())); } } } }
TypeConversion GetDelegateConversion(Source src, DelegateType dt) { var paramConversions = dt.Parameters.Select(GetParamConversion).ToArray(); var returnConversion = GetConversion(src, dt.ReturnType); var compiledType = Helpers.CompiledType(dt); var foreignType = "::uObjC::Function<" + returnConversion.ForeignType + ((paramConversions.Length > 0) ? ", " : "") + ForeignTypes(paramConversions) + ">"; Func <string, string> fromUno = (string x) => { var convertedArguments = paramConversions.Select((p, i) => p.ToUno(dt.Parameters[i].Name)).ToList(); var preStatements = convertedArguments.SelectMany(a => a.PreStatements).ToList(); var arguments = convertedArguments.Select((arg, i) => Helpers.StringExpr(dt.Parameters[i].Type, arg.Expression)).ToArray(); var postStatements = convertedArguments.SelectMany(a => a.PostStatements).ToList(); using (var tw = new StringWriter()) { using (var ftw = new TextFormatter(tw)) { ftw.WriteLine("[] (id<UnoObject> __delegateRef) -> " + foreignType); ftw.Indent("{"); ftw.WriteLine("return __delegateRef == nil ? (" + foreignType + ")nil : (^ " + returnConversion.ForeignType + " " + ForeignTypeParamList(paramConversions, dt.Parameters.Select(p => p.Name).ToArray())); ftw.Indent("{"); ftw.WriteLine("::uForeignPool __foreignPool;"); ftw.WriteLine(compiledType + " __unoDelegate = (" + compiledType + ")__delegateRef.unoObject;"); ftw.WriteLines(ReturnWithPrePostStatements( dt.ReturnType, preStatements, returnConversion.FromUno(Helpers.CallDelegate(Helpers.StringExpr(dt, "__unoDelegate"), arguments)), postStatements)); ftw.Unindent("});"); ftw.Unindent(); ftw.Write("} ([::StrongUnoObject strongUnoObjectWithUnoObject: " + x + "])"); return(tw.ToString()); } } }; Func <string, string> toUno = (string x) => { var convertedArguments = paramConversions.Select((p, i) => p.FromUno(GetDelegateArgumentString(dt.Parameters[i]))).ToList(); var preStatements = convertedArguments.SelectMany(a => a.PreStatements).ToList(); var arguments = convertedArguments.Select(a => a.Expression).ToList(); var postStatements = convertedArguments.SelectMany(a => a.PostStatements).ToList(); using (var tw = new StringWriter()) { using (var ftw = new TextFormatter(tw)) { ftw.Write("::uObjC::NewUnoDelegate(" + Helpers.TypeOf(dt) + ", "); string fptrType = "::uObjC::RawFunction<void, " + Helpers.CompiledType(Essentials.Object) + ((paramConversions.Length) > 0 ? ", " : "") + string.Join(", ", paramConversions.Select(GetDelegateParameterType)) + (dt.ReturnType.IsVoid ? "" : (", " + Helpers.CompiledType(returnConversion.UnoType) + "*")) + ">"; ftw.Write("(void*) (" + fptrType + ") [] ("); ftw.Write(Helpers.CompiledType(Essentials.Object) + " __this" + ((paramConversions.Length > 0) ? ", " : "") + string.Join(", ", paramConversions.Select((p, i) => GetDelegateParameterType(p) + " " + dt.Parameters[i].Name)) + (dt.ReturnType.IsVoid ? "" : (", " + GetDelegateReturnType(returnConversion) + " __ret"))); ftw.Write(")"); ftw.EndLine(); ftw.Indent("{"); ftw.WriteLine(Helpers.CompiledType(_objCObject) + " __thisObj = (" + Helpers.CompiledType(_objCObject) + ")__this;"); preStatements.ForEach(ftw.WriteLine); ftw.BeginLine(); if (!dt.ReturnType.IsVoid) { ftw.Write(GetDelegateReturnString(returnConversion, "__ret") + " = "); } ftw.Write(returnConversion.ToUno("((" + foreignType + ")" + Helpers.CallStatic(_getHandle, Helpers.StringExpr(_objCObject, "__thisObj")) + ")(" + string.Join(", ", arguments) + ")") + ";"); ftw.EndLine(); postStatements.ForEach(ftw.WriteLine); ftw.Unindent(); ftw.Write("}, " + Helpers.CallStatic(_newObjCObject, Helpers.StringExpr(_objCID, x)) + ")"); return(tw.ToString()); } } }; return(TypeConversion.Boxed( dt, foreignType, fromUno, toUno)); }
string WrapBody(Function f, string body) { var paramConversions = new List <ParamTypeConversion>(); var paramNames = new List <string>(); var foreignParamNames = new List <string>(); if (!f.IsStatic && body.Contains("_this")) { paramConversions.Add( GetParamConversion( new Parameter( f.Source, new NewObject[0], ParameterModifier.This, f.DeclaringType, "@IL$$", null))); paramNames.Add("@IL$$"); foreignParamNames.Add("_this"); } paramConversions.AddRange(f.Parameters.Select(GetParamConversion)); paramNames.AddRange(f.Parameters.Select((x, i) => "@IL$" + i)); foreignParamNames.AddRange(f.Parameters.Select(x => x.UnoName)); var returnConversion = GetConversion(f.Source, f.ReturnType); var convertedArguments = paramConversions.Select((p, i) => p.FromUno(paramNames[i])).ToList(); var preStatements = convertedArguments.SelectMany(x => x.PreStatements).ToList(); var arguments = convertedArguments.Select(x => x.Expression).ToList(); var postStatements = convertedArguments.SelectMany(x => x.PostStatements).ToList(); if (paramConversions.All(x => x.IsIdentity) && returnConversion.IsIdentity && preStatements.Count == 0 && postStatements.Count == 0 && f.Parameters.All(p => p.Name == p.UnoName)) { return(WithObjCAutoreleasePool(body)); } else { using (var tw = new StringWriter()) { using (var ftw = new TextFormatter(tw)) { ftw.BeginLine(); ftw.Write("[] "); ftw.Write(ForeignTypeParamList(paramConversions, foreignParamNames.ToArray())); ftw.Write(" -> "); ftw.Write(returnConversion.ForeignType); ftw.EndLine(); ftw.Indent("{"); ftw.WriteLines(body); ftw.Unindent(); ftw.Write("} ("); ftw.Write(string.Join(", ", arguments)); ftw.Write(")"); return(WithObjCAutoreleasePool(ReturnWithPrePostStatements(f.ReturnType, preStatements, returnConversion.ToUno(tw.ToString()), postStatements))); } } } }