public CodeMemberMethod GenerateMethod(Smoke *smoke, Smoke.Method *method, string mungedName, CodeTypeReference iface) { string cppSignature = smoke->GetMethodSignature(method); CodeMemberMethod cmm = GenerateBasicMethodDefinition(smoke, method, cppSignature, iface); if (cmm == null) { return(null); } // put the method into the correct type CodeTypeDeclaration containingType = type; if (cmm.Name.StartsWith("operator") || cmm.Name.StartsWith("explicit ")) { if (!data.CSharpTypeMap.TryGetValue(cmm.Parameters[0].Type.GetStringRepresentation(), out containingType)) { if (cmm.Parameters.Count < 2 || !data.CSharpTypeMap.TryGetValue(cmm.Parameters[1].Type.GetStringRepresentation(), out containingType)) { Debug.Print(" |--Can't find containing type for {0} - skipping", cppSignature); } return(null); } } // already implemented? if (containingType.HasMethod(cmm)) { if (iface == null || (method->flags & (uint)Smoke.MethodFlags.mf_protected) > 0) { // protected methods are not available in interfaces Debug.Print(" |--Skipping already implemented method {0}", cppSignature); return(null); } else { cmm.PrivateImplementationType = iface; } } if (PreMethodBodyHooks != null) { PreMethodBodyHooks(smoke, method, cmm, containingType); } // do we have pass-by-ref parameters? bool generateInvokeForRefParams = cmm.Parameters.Cast <CodeParameterDeclarationExpression>().Any(expr => expr.Direction == FieldDirection.Ref); // generate the SmokeMethod attribute CodeAttributeDeclaration attr = new CodeAttributeDeclaration("SmokeMethod", new CodeAttributeArgument( new CodePrimitiveExpression(cppSignature))); cmm.CustomAttributes.Add(attr); // choose the correct 'interceptor' CodeMethodInvokeExpression invoke; if ((cmm.Attributes & MemberAttributes.Static) == MemberAttributes.Static) { invoke = new CodeMethodInvokeExpression(SmokeSupport.staticInterceptor_Invoke); } else { invoke = new CodeMethodInvokeExpression(SmokeSupport.interceptor_Invoke); } // first pass the munged name, then the C++ signature invoke.Parameters.Add(new CodePrimitiveExpression(mungedName)); invoke.Parameters.Add(new CodePrimitiveExpression(cppSignature)); // retrieve the return type CodeTypeReference returnType; if ((method->flags & (uint)Smoke.MethodFlags.mf_dtor) > 0) { // destructor returnType = new CodeTypeReference(typeof(void)); } else if (cmm.Name.StartsWith("explicit operator ")) { // strip 'explicit operator' from the name to get the return type returnType = new CodeTypeReference(cmm.Name.Substring(18)); } else { returnType = cmm.ReturnType; } // add the return type invoke.Parameters.Add(new CodeTypeOfExpression(returnType)); invoke.Parameters.Add(new CodePrimitiveExpression(generateInvokeForRefParams)); invoke.Parameters.Add(new CodeVariableReferenceExpression("smokeArgs")); CodeArrayCreateExpression argsInitializer = new CodeArrayCreateExpression(typeof(object[])); // add the parameters foreach (CodeParameterDeclarationExpression param in cmm.Parameters) { argsInitializer.Initializers.Add(new CodeTypeOfExpression(param.Type)); string argReference = param.Name; int indexOfSpace = argReference.IndexOf(' '); if (indexOfSpace > 0) { argReference = argReference.Substring(0, indexOfSpace); } argsInitializer.Initializers.Add(new CodeArgumentReferenceExpression(argReference)); } CodeStatement argsStatement = new CodeVariableDeclarationStatement(typeof(object[]), "smokeArgs", argsInitializer); cmm.Statements.Add(argsStatement); // we have to call "CreateProxy()" in constructors if (cmm is CodeConstructor) { cmm.Statements.Add( new CodeExpressionStatement(new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), "CreateProxy"))); } // add the method call statement CodeStatement statement; if (!generateInvokeForRefParams) { if (method->ret > 0 && (method->flags & (uint)Smoke.MethodFlags.mf_ctor) == 0) { statement = new CodeMethodReturnStatement(new CodeCastExpression(returnType, invoke)); } else { statement = new CodeExpressionStatement(invoke); } cmm.Statements.Add(statement); } else { if (method->ret > 0 && (method->flags & (uint)Smoke.MethodFlags.mf_ctor) == 0) { statement = new CodeVariableDeclarationStatement(returnType, "smokeRetval", new CodeCastExpression(returnType, invoke)); cmm.Statements.Add(statement); } else { statement = new CodeExpressionStatement(invoke); cmm.Statements.Add(statement); } int i = 0; foreach (CodeParameterDeclarationExpression param in cmm.Parameters) { ++i; if (param.Direction != FieldDirection.Ref) { continue; } cmm.Statements.Add(new CodeAssignStatement(new CodeVariableReferenceExpression(param.Name), new CodeCastExpression(param.Type.BaseType, new CodeArrayIndexerExpression( new CodeVariableReferenceExpression("smokeArgs"), new CodePrimitiveExpression(i * 2 - 1) ) ) )); } if (method->ret > 0 && (method->flags & (uint)Smoke.MethodFlags.mf_ctor) == 0) { cmm.Statements.Add(new CodeMethodReturnStatement(new CodeVariableReferenceExpression("smokeRetval"))); } } if (PostMethodBodyHooks != null) { PostMethodBodyHooks(smoke, method, cmm, containingType); } containingType.Members.Add(cmm); if ((method->flags & (uint)Smoke.MethodFlags.mf_dtor) != 0) { containingType.BaseTypes.Add(new CodeTypeReference(typeof(IDisposable))); CodeMemberMethod dispose = new CodeMemberMethod(); dispose.Name = "Dispose"; dispose.Attributes = MemberAttributes.Public | MemberAttributes.New | MemberAttributes.Final; dispose.Statements.AddRange(cmm.Statements); dispose.Statements.Add(new CodeExpressionStatement(new CodeMethodInvokeExpression( new CodeTypeReferenceExpression("GC"), "SuppressFinalize", new CodeThisReferenceExpression() ))); containingType.Members.Add(dispose); } this.DistributeMethod(cmm); return(cmm); }
public void Run() { HashSet<short> interfaceClasses = GetClassList(); // Make the interfaces known first, otherwise Translator won't work correctly. foreach (short idx in interfaceClasses) { Smoke.Class* klass = data.Smoke->classes + idx; string className = ByteArrayManager.GetString(klass->className); int colon = className.LastIndexOf("::", StringComparison.Ordinal); string prefix = (colon != -1) ? className.Substring(0, colon) : string.Empty; string name = (colon != -1) ? className.Substring(colon + 2) : className; CodeTypeDeclaration ifaceDecl = new CodeTypeDeclaration('I' + name); ifaceDecl.IsInterface = true; CodeAttributeDeclaration attr = new CodeAttributeDeclaration("SmokeClass", new CodeAttributeArgument( new CodePrimitiveExpression(className))); ifaceDecl.CustomAttributes.Add(attr); data.GetTypeCollection(prefix).Add(ifaceDecl); data.InterfaceTypeMap[className] = ifaceDecl; } // Now generate the methods. foreach (short idx in interfaceClasses) { Smoke.Class* klass = data.Smoke->classes + idx; string className = ByteArrayManager.GetString(klass->className); CodeTypeDeclaration ifaceDecl = data.InterfaceTypeMap[className]; short* parent = data.Smoke->inheritanceList + klass->parents; while (*parent > 0) { ifaceDecl.BaseTypes.Add(translator.CppToCSharp(data.Smoke->classes + *parent, ifaceDecl)); parent++; } MethodsGenerator mg = new MethodsGenerator(data, translator, ifaceDecl, klass); AttributeGenerator ag = new AttributeGenerator(data, translator, ifaceDecl); List<IntPtr> methods = new List<IntPtr>(); ///TODO: replace this algorithm, it's highly inefficient for (short i = 0; i <= data.Smoke->numMethods && data.Smoke->methods[i].classId <= idx; i++) { Smoke.Method* meth = data.Smoke->methods + i; if (meth->classId != idx) continue; string methName = ByteArrayManager.GetString(data.Smoke->methodNames[meth->name]); // we don't want anything except protected, const or empty flags if ((meth->flags & (ushort) Smoke.MethodFlags.mf_enum) > 0 || (meth->flags & (ushort) Smoke.MethodFlags.mf_ctor) > 0 || (meth->flags & (ushort) Smoke.MethodFlags.mf_copyctor) > 0 || (meth->flags & (ushort) Smoke.MethodFlags.mf_dtor) > 0 || (meth->flags & (ushort) Smoke.MethodFlags.mf_static) > 0 || (meth->flags & (ushort) Smoke.MethodFlags.mf_internal) > 0 || (meth->flags & (ushort) Smoke.MethodFlags.mf_protected) > 0 || methName.StartsWith("operator")) { continue; } if ((meth->flags & (ushort) Smoke.MethodFlags.mf_attribute) > 0) { ag.ScheduleAttributeAccessor(meth); continue; } methods.Add((IntPtr) meth); } methods.Sort(CompareSmokeMethods); foreach (Smoke.Method* method in methods) { CodeMemberMethod cmm = mg.GenerateBasicMethodDefinition(data.Smoke, method); if (cmm != null && !ifaceDecl.HasMethod(cmm)) { ifaceDecl.Members.Add(cmm); } } mg.GenerateProperties(); foreach (CodeMemberProperty prop in ag.GenerateBasicAttributeDefinitions()) { ifaceDecl.Members.Add(prop); } } }
public void Run() { HashSet <short> interfaceClasses = GetClassList(); // Make the interfaces known first, otherwise Translator won't work correctly. foreach (short idx in interfaceClasses) { Smoke.Class *klass = data.Smoke->classes + idx; string className = ByteArrayManager.GetString(klass->className); int colon = className.LastIndexOf("::", StringComparison.Ordinal); string prefix = (colon != -1) ? className.Substring(0, colon) : string.Empty; string name = (colon != -1) ? className.Substring(colon + 2) : className; CodeTypeDeclaration ifaceDecl = new CodeTypeDeclaration('I' + name); ifaceDecl.IsInterface = true; CodeAttributeDeclaration attr = new CodeAttributeDeclaration("SmokeClass", new CodeAttributeArgument( new CodePrimitiveExpression(className))); ifaceDecl.CustomAttributes.Add(attr); data.GetTypeCollection(prefix).Add(ifaceDecl); data.InterfaceTypeMap[className] = ifaceDecl; } // Now generate the methods. foreach (short idx in interfaceClasses) { Smoke.Class * klass = data.Smoke->classes + idx; string className = ByteArrayManager.GetString(klass->className); CodeTypeDeclaration ifaceDecl = data.InterfaceTypeMap[className]; short *parent = data.Smoke->inheritanceList + klass->parents; while (*parent > 0) { ifaceDecl.BaseTypes.Add(translator.CppToCSharp(data.Smoke->classes + *parent)); parent++; } MethodsGenerator mg = new MethodsGenerator(data, translator, ifaceDecl, klass); AttributeGenerator ag = new AttributeGenerator(data, translator, ifaceDecl); List <IntPtr> methods = new List <IntPtr>(); ///TODO: replace this algorithm, it's highly inefficient for (short i = 0; i <= data.Smoke->numMethods && data.Smoke->methods[i].classId <= idx; i++) { Smoke.Method *meth = data.Smoke->methods + i; if (meth->classId != idx) { continue; } string methName = ByteArrayManager.GetString(data.Smoke->methodNames[meth->name]); // we don't want anything except protected, const or empty flags if ((meth->flags & (ushort)Smoke.MethodFlags.mf_enum) > 0 || (meth->flags & (ushort)Smoke.MethodFlags.mf_ctor) > 0 || (meth->flags & (ushort)Smoke.MethodFlags.mf_copyctor) > 0 || (meth->flags & (ushort)Smoke.MethodFlags.mf_dtor) > 0 || (meth->flags & (ushort)Smoke.MethodFlags.mf_static) > 0 || (meth->flags & (ushort)Smoke.MethodFlags.mf_internal) > 0 || (meth->flags & (ushort)Smoke.MethodFlags.mf_protected) > 0 || methName.StartsWith("operator")) { continue; } if ((meth->flags & (ushort)Smoke.MethodFlags.mf_attribute) > 0) { ag.ScheduleAttributeAccessor(meth); continue; } methods.Add((IntPtr)meth); } methods.Sort(CompareSmokeMethods); foreach (Smoke.Method *method in methods) { CodeMemberMethod cmm = mg.GenerateBasicMethodDefinition(data.Smoke, method); if (cmm != null && !ifaceDecl.HasMethod(cmm)) { ifaceDecl.Members.Add(cmm); } } mg.GenerateProperties(); foreach (CodeMemberProperty prop in ag.GenerateBasicAttributeDefinitions()) { ifaceDecl.Members.Add(prop); } } }