コード例 #1
0
    private string[] GetMethodArgs(Smoke *smoke, Smoke.Method *method)
    {
        if (method->numArgs == 0)
        {
            return(new string[0]);
        }
        string className = ByteArrayManager.GetString(smoke->classes[method->classId].className);

        className = className.Substring(className.LastIndexOf(":") + 1);
        StringBuilder keyBuilder =
            new StringBuilder(className + "," + ByteArrayManager.GetString(smoke->methodNames[method->name]));

        for (short *typeIndex = smoke->argumentList + method->args; *typeIndex > 0; typeIndex++)
        {
            keyBuilder.Append(',');
            keyBuilder.Append(*typeIndex);
        }
        string key = keyBuilder.ToString();

        if (data.ArgumentNames.ContainsKey(key))
        {
            return(data.ArgumentNames[key]);
        }
        string argNamesFile = data.GetArgNamesFile(smoke);

        if (File.Exists(argNamesFile))
        {
            foreach (string[] strings in File.ReadAllLines(argNamesFile).Select(line => line.Split(';')))
            {
                data.ArgumentNames[strings[0]] = strings[1].Split(',');
            }
            return(data.ArgumentNames[key]);
        }
        return(null);
    }
コード例 #2
0
ファイル: QyotoHooks.cs プロジェクト: corngood/assemblygen
 public void SupportingMethodsHook(Smoke *smoke, Smoke.Method *method, CodeMemberMethod cmm, CodeTypeDeclaration type)
 {
     if (type.Name == "QObject" && cmm is CodeConstructor)
     {
         cmm.Statements.Add(new CodeSnippetStatement(QObjectDummyCtorCode));
     }
 }
コード例 #3
0
    public int GetHashCode(Smoke.ModuleIndex mi)
    {
        Smoke.Method *method   = mi.smoke->methods + mi.index;
        bool          isConst  = ((method->flags & (ushort)Smoke.MethodFlags.mf_const) > 0);
        bool          isStatic = ((method->flags & (ushort)Smoke.MethodFlags.mf_static) > 0);

        int hash = method->name << 18 + method->args << 2 + (isConst? 1 : 0) << 1 + (isStatic? 1 : 0);

        return((hash ^ (long)mi.smoke).GetHashCode());
    }
コード例 #4
0
    public bool Equals(Smoke.ModuleIndex first, Smoke.ModuleIndex second)
    {
        Smoke.Method *firstMeth  = first.smoke->methods + first.index;
        Smoke.Method *secondMeth = second.smoke->methods + second.index;

        bool firstConst  = ((firstMeth->flags & (ushort)Smoke.MethodFlags.mf_const) > 0);
        bool secondConst = ((secondMeth->flags & (ushort)Smoke.MethodFlags.mf_const) > 0);

        bool firstStatic  = ((firstMeth->flags & (ushort)Smoke.MethodFlags.mf_static) > 0);
        bool secondStatic = ((secondMeth->flags & (ushort)Smoke.MethodFlags.mf_static) > 0);

        bool firstAbstract  = ((firstMeth->flags & (ushort)Smoke.MethodFlags.mf_purevirtual) > 0);
        bool secondAbstract = ((secondMeth->flags & (ushort)Smoke.MethodFlags.mf_purevirtual) > 0);

        if (firstConst != secondConst || firstStatic != secondStatic ||
            (m_abstractIsDifference && (firstAbstract != secondAbstract)))
        {
            return(false);
        }

        if (first.smoke == second.smoke)
        {
            // when the methods are in the same module, we can be rather quick
            if (firstMeth->name == secondMeth->name && firstMeth->args == secondMeth->args && firstMeth->ret == secondMeth->ret)
            {
                return(true);
            }
            return(false);
        }
        else
        {
            if (ByteArrayManager.strcmp(first.smoke->methodNames[firstMeth->name], second.smoke->methodNames[secondMeth->name]) == 0 &&
                ByteArrayManager.strcmp(first.smoke->types[firstMeth->ret].name, second.smoke->types[secondMeth->ret].name) == 0 &&
                firstMeth->numArgs == secondMeth->numArgs)
            {
                // name and number of arguments match, now compare the arguments individually
                short *firstMethodArgPtr  = first.smoke->argumentList + firstMeth->args;
                short *secondMethodArgPtr = second.smoke->argumentList + secondMeth->args;

                while ((*firstMethodArgPtr) > 0)
                {
                    if (ByteArrayManager.strcmp(first.smoke->types[*firstMethodArgPtr].name, second.smoke->types[*secondMethodArgPtr].name) != 0)
                    {
                        return(false);
                    }
                    firstMethodArgPtr++;
                    secondMethodArgPtr++;
                }

                return(true);
            }

            return(false);
        }
    }
コード例 #5
0
    // this only has to work within the module boundaries
    public static bool EqualExceptConstness(Smoke.Method *firstMeth, Smoke.Method *secondMeth)
    {
        bool firstStatic  = ((firstMeth->flags & (ushort)Smoke.MethodFlags.mf_static) > 0);
        bool secondStatic = ((secondMeth->flags & (ushort)Smoke.MethodFlags.mf_static) > 0);

        if (firstMeth->name == secondMeth->name && firstMeth->args == secondMeth->args && firstStatic == secondStatic)
        {
            return(true);
        }

        return(false);
    }
コード例 #6
0
    public void ScheduleAttributeAccessor(Smoke *smoke, Smoke.Method *meth)
    {
        string name        = ByteArrayManager.GetString(smoke->methodNames[meth->name]);
        bool   isSetMethod = false;

        if (name.StartsWith("set"))
        {
            name        = name.Remove(0, 3);
            isSetMethod = true;
        }
        else
        {
            // capitalize the first letter
            StringBuilder builder = new StringBuilder(name);
            builder[0] = char.ToUpper(builder[0]);
            name       = builder.ToString();
        }

        // If the new name clashes with a name of a type declaration, keep the lower-case name.
        var typesWithSameName = from member in data.GetAccessibleMembers(smoke->classes + meth->classId)
                                where (member.Type == MemberTypes.NestedType ||
                                       member.Type == MemberTypes.Method) &&
                                member.Name == name
                                select member;

        if (typesWithSameName.Any())
        {
            string className = ByteArrayManager.GetString(smoke->classes[meth->classId].className);
            Debug.Print("  |--Conflicting names: property/type: {0} in class {1} - keeping original property name", name,
                        className);
            name = char.ToLower(name[0]) + name.Substring(1);
        }

        Attribute attr;

        if (!attributes.TryGetValue(name, out attr))
        {
            attr       = new Attribute();
            attr.Smoke = smoke;
            attributes.Add(name, attr);
        }

        if (isSetMethod)
        {
            attr.SetMethod = meth;
        }
        else
        {
            attr.GetMethod = meth;
        }
    }
コード例 #7
0
    private void GenerateInheritedMethods(Smoke.Class *klass, MethodsGenerator methgen, AttributeGenerator attrgen,
                                          List <Smoke.ModuleIndex> alreadyImplemented)
    {
        // Contains inherited methods that have to be implemented by the current class.
        // We use our custom comparer, so we don't end up with the same method multiple times.
        IDictionary <Smoke.ModuleIndex, string> implementMethods =
            new Dictionary <Smoke.ModuleIndex, string>(SmokeMethodEqualityComparer.DefaultEqualityComparer);

        bool firstParent = true;

        for (short *parent = data.Smoke->inheritanceList + klass->parents; *parent > 0; parent++)
        {
            if (firstParent)
            {
                // we're only interested in parents implemented as interfaces
                firstParent = false;
                continue;
            }
            // collect all methods (+ inherited ones) and add them to the implementMethods Dictionary
            data.Smoke->FindAllMethods(*parent, implementMethods, true);
        }

        foreach (KeyValuePair <Smoke.ModuleIndex, string> pair in implementMethods)
        {
            Smoke.Method *meth       = pair.Key.smoke->methods + pair.Key.index;
            Smoke.Class * ifaceKlass = pair.Key.smoke->classes + meth->classId;

            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)
            {
                // no need to check for properties here - QObjects don't support multiple inheritance anyway
                continue;
            }
            if (alreadyImplemented.Contains(pair.Key, SmokeMethodEqualityComparer.DefaultEqualityComparer))
            {
                continue;
            }
            if ((meth->flags & (ushort)Smoke.MethodFlags.mf_attribute) > 0)
            {
                attrgen.ScheduleAttributeAccessor(pair.Key.smoke, meth);
                continue;
            }

            CodeTypeReference type = translator.CppToCSharp(ByteArrayManager.GetString(ifaceKlass->className));
            methgen.GenerateMethod(pair.Key.smoke, meth, pair.Value, type);
        }
    }
コード例 #8
0
ファイル: QyotoHooks.cs プロジェクト: corngood/assemblygen
    private void PostEnumMemberHook(Smoke *smoke, Smoke.Method *smokeMethod, CodeMemberField cmm, CodeTypeDeclaration type)
    {
        CodeTypeDeclaration parentType = this.memberDocumentation.Keys.FirstOrDefault(t => t.Name == (string)type.UserData["parent"]);

        if (parentType != null)
        {
            IList <string> docs     = this.memberDocumentation[parentType];
            string         typeName = Regex.Escape(parentType.Name) + "::" + Regex.Escape(type.Name);
            if (type.Comments.Count == 0)
            {
                for (int i = 0; i < docs.Count; i++)
                {
                    const string enumDoc   = @"enum {0}(\s*flags {1}::\w+\s+)?(?<docsStart>.*?)(\n){{3}}";
                    Match        matchEnum = Regex.Match(docs[i], string.Format(enumDoc, typeName, parentType.Name), RegexOptions.Singleline);
                    if (matchEnum.Success)
                    {
                        string doc = (matchEnum.Groups["docsStart"].Value + matchEnum.Groups["docsEnd1"].Value).Trim();
                        doc = Regex.Replace(doc,
                                            @"(The \S+ type is a typedef for QFlags<\S+>\. It stores an OR combination of \S+ values\.)",
                                            string.Empty);
                        doc = Regex.Replace(doc,
                                            @"ConstantValue(Description)?.*?(((\n){2})|$)",
                                            string.Empty, RegexOptions.Singleline).Trim();
                        if (!string.IsNullOrEmpty(doc))
                        {
                            Util.FormatComment(doc, type, i > 0);
                            break;
                        }
                    }
                }
            }
            string memberName = Regex.Escape(parentType.Name) + "::" +
                                Regex.Escape(ByteArrayManager.GetString(smoke->methodNames[smokeMethod->name]));
            const string memberDoc = @"enum {0}.*{1}\t[^\t\n]+\t(?<docs>.*?)(&\w+;)?(\n)";
            for (int i = 0; i < docs.Count; i++)
            {
                Match match = Regex.Match(docs[i], string.Format(memberDoc, typeName, memberName), RegexOptions.Singleline);
                if (match.Success)
                {
                    string doc = match.Groups["docs"].Value.Trim();
                    if (!string.IsNullOrEmpty(doc))
                    {
                        Util.FormatComment(char.ToUpper(doc[0]) + doc.Substring(1), cmm, i > 0);
                        break;
                    }
                }
            }
        }
    }
コード例 #9
0
ファイル: QyotoHooks.cs プロジェクト: corngood/assemblygen
 private void CommentMember(Smoke *smoke, Smoke.Method *smokeMethod, CodeTypeMember cmm, CodeTypeDeclaration type)
 {
     if (this.memberDocumentation.ContainsKey(type))
     {
         IList <string> docs           = this.memberDocumentation[type];
         string         typeName       = Regex.Escape(type.Name);
         string         signature      = smoke->GetMethodSignature(smokeMethod);
         StringBuilder  signatureRegex = new StringBuilder();
         Match          matchSignature = Regex.Match(signature, @"(?<name>[^\(]+)\((?<args>.*)\)");
         string         methodName     = Regex.Escape(matchSignature.Groups["name"].Value);
         signatureRegex.Append(methodName);
         signatureRegex.Append(@"\s*\(\s*");
         string[]     argTypes  = matchSignature.Groups["args"].Value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
         const string separator = @",\s*";
         foreach (string argType in argTypes)
         {
             StringBuilder typeBuilder = new StringBuilder(Regex.Escape(argType));
             typeBuilder.Replace(@"\*", @"\s*\*").Replace(@"&", @"\s*&").Replace(type.Name + "::", string.Empty);
             signatureRegex.Append(Translator.MatchFunctionPointer(typeBuilder.ToString()).Success
                                                           ? @"[^,]+"
                                                           : (typeBuilder + @"\s+\w+(\s*=\s*\w+)?"));
             signatureRegex.Append(separator);
         }
         if (argTypes.Length > 0)
         {
             signatureRegex.Remove(signatureRegex.Length - separator.Length, separator.Length);
         }
         signatureRegex.Append(@"\s*\)\s*");
         string memberDoc = @"{0}( |(::)){1}( const)?( \[(\w+\s*)+\])?\n\W*(?<docs>.*?)(\n\s*){{1,2}}((&?\S* --)|((\n\s*){{2}}))";
         for (int i = 0; i < docs.Count; i++)
         {
             Match match = Regex.Match(docs[i], string.Format(memberDoc, typeName, signatureRegex), RegexOptions.Singleline);
             if (match.Success)
             {
                 Util.FormatComment(match.Groups["docs"].Value, cmm, i > 0);
                 break;
             }
             memberDoc = @"{0}( |(::)){1}\s*\([^\n]*\)( const)?( \[(\w+\s*)+\])?\n\W*(?<docs>.*?)(\n\s*){{1,2}}((&?\S* --)|((\n\s*){{2}}))";
             match     = Regex.Match(docs[i], string.Format(memberDoc, typeName, methodName), RegexOptions.Singleline);
             if (match.Success)
             {
                 Util.FormatComment(match.Groups["docs"].Value, cmm, i > 0);
                 break;
             }
         }
     }
 }
コード例 #10
0
    public static unsafe Stack <KeyValuePair <Smoke.ModuleIndex, string> > GetAbstractMethods(Smoke *smoke, short classId)
    {
        Dictionary <Smoke.ModuleIndex, string> methods =
            new Dictionary <Smoke.ModuleIndex, string>(SmokeMethodEqualityComparer.AbstractRespectingComparer);
        SmokeMethodEqualityComparer defaultComparer = SmokeMethodEqualityComparer.DefaultEqualityComparer;

        smoke->FindAllMethods(classId, methods, true);
        var abstractMethods = new Stack <KeyValuePair <Smoke.ModuleIndex, string> >();

        foreach (KeyValuePair <Smoke.ModuleIndex, string> pair in methods)
        {
            Smoke.Method *meth = pair.Key.smoke->methods + pair.Key.index;
            if ((meth->flags & (ushort)Smoke.MethodFlags.mf_purevirtual) == 0)
            {
                // only compare pure-virtuals
                continue;
            }
            abstractMethods.Push(pair);

            foreach (KeyValuePair <Smoke.ModuleIndex, string> other in methods)
            {
                // Break if we encounter our original Index. Anything after this one will be further up in the
                // hierarchy and thus can't override anything.
                if (pair.Key == other.Key)
                {
                    break;
                }

                Smoke.Method *otherMeth = other.Key.smoke->methods + other.Key.index;
                if (defaultComparer.Equals(pair.Key, other.Key))
                {
                    if ((otherMeth->flags & (ushort)Smoke.MethodFlags.mf_purevirtual) == 0)
                    {
                        // overriden with implementation
                        abstractMethods.Pop();
                    }
                    break;
                }
            }
        }

        return(abstractMethods);
    }
コード例 #11
0
    private void FillEnums()
    {
        for (short i = 1; i < this.data.Smoke->numMethodMaps; i++)
        {
            Smoke.MethodMap *map = this.data.Smoke->methodMaps + i;
            if (map->method > 0)
            {
                Smoke.Method *meth = this.data.Smoke->methods + map->method;
                if ((meth->flags & (ushort)Smoke.MethodFlags.mf_enum) > 0)
                {
                    this.eg.DefineMember(meth);
                }
            }
            else if (map->method < 0)
            {
                for (short *overload = this.data.Smoke->ambiguousMethodList + (-map->method); *overload > 0; overload++)
                {
                    Smoke.Method *meth = this.data.Smoke->methods + *overload;
                    if ((meth->flags & (ushort)Smoke.MethodFlags.mf_enum) > 0)
                    {
                        this.eg.DefineMember(meth);
                        continue;
                    }

                    // if the methods differ only by constness, we will generate special code
                    bool nextDiffersByConst = false;
                    if (*(overload + 1) > 0)
                    {
                        if (SmokeMethodEqualityComparer.EqualExceptConstness(meth, this.data.Smoke->methods + *(overload + 1)))
                        {
                            nextDiffersByConst = true;
                        }
                    }
                    if (nextDiffersByConst)
                    {
                        overload++;
                    }
                }
            }
        }
    }
コード例 #12
0
 private static int CompareSmokeMethods(IntPtr i1, IntPtr i2)
 {
     Smoke.Method *m1 = (Smoke.Method *)i1;
     Smoke.Method *m2 = (Smoke.Method *)i2;
     if (m1->name > m2->name)
     {
         return(1);
     }
     if (m1->name < m2->name)
     {
         return(-1);
     }
     if (m1->numArgs > m2->numArgs)
     {
         return(1);
     }
     if (m1->numArgs < m2->numArgs)
     {
         return(-1);
     }
     return(0);
 }
コード例 #13
0
ファイル: EnumGenerator.cs プロジェクト: corngood/assemblygen
    /*
     * Generates an Enum member, creating the Enum if necessary.
     */

    public void DefineMember(Smoke.Method *meth)
    {
        if ((meth->flags & (uint)Smoke.MethodFlags.mf_enum) == 0)
        {
            return;
        }

        string typeName = ByteArrayManager.GetString(data.Smoke->types[meth->ret].name);

        if (typeName == "long")         // unnamed enum
        {
            return;
        }

        CodeTypeDeclaration enumType;

        if (!data.EnumTypeMap.TryGetValue(typeName, out enumType))
        {
            enumType = DefineEnum(typeName);
        }
        CodeMemberField member = new CodeMemberField();

        member.Name = ByteArrayManager.GetString(data.Smoke->methodNames[meth->name]);
        long value = GetEnumValue(data.Smoke, meth);

        if (value > int.MaxValue && enumType.BaseTypes.Count == 0)
        {
            // make the enum derive from 'long' if necessary
            enumType.BaseTypes.Add(new CodeTypeReference(typeof(long)));
        }

        member.InitExpression = new CodePrimitiveExpression(value);
        if (PostEnumMemberHook != null)
        {
            PostEnumMemberHook(data.Smoke, meth, member, enumType);
        }
        enumType.Members.Add(member);
    }
コード例 #14
0
    public CodeMemberMethod GenerateBasicMethodDefinition(Smoke *smoke, Smoke.Method *method, string cppSignature,
                                                          CodeTypeReference iface)
    {
        // do we actually want that method?
        string className         = ByteArrayManager.GetString(smokeClass->className);
        string completeSignature = className + "::" + cppSignature;

        if (translator.ExcludedMethods.Any(regex => regex.IsMatch(completeSignature)))
        {
            return(null);
        }

        CodeParameterDeclarationExpressionCollection args = new CodeParameterDeclarationExpressionCollection();
        int  count = 1;
        bool isRef;

        // make instance operators static and bring the arguments in the correct order
        string methName               = ByteArrayManager.GetString(smoke->methodNames[method->name]);
        bool   isOperator             = false;
        string explicitConversionType = null;

        if (methName.StartsWith("operator"))
        {
            string op = methName.Substring(8);
            if (unsupportedOperators.Contains(op))
            {
                // not supported
                Debug.Print("  |--Won't wrap method {0}::{1}", className, cppSignature);
                return(null);
            }

            if (op == "<<")
            {
                methName = "Write";
            }
            else if (op == ">>")
            {
                methName = "Read";
            }

            // binary/unary operator
            if (binaryOperators.Contains(op) || unaryOperators.Contains(op))
            {
                // instance operator
                if (smoke->classes[method->classId].size > 0)
                {
                    if (op == "*" && method->numArgs == 0 || (op == "++" || op == "--") && method->numArgs == 1)
                    {
                        // dereference operator and postfix in-/decrement operator are not supported
                        Debug.Print("  |--Won't wrap method {0}::{1}", className, cppSignature);
                        return(null);
                    }

                    try
                    {
                        CodeParameterDeclarationExpression exp =
                            new CodeParameterDeclarationExpression(translator.CppToCSharp(className, out isRef), "arg" + count++);
                        args.Add(exp);
                    }
                    catch (NotSupportedException)
                    {
                        Debug.Print("  |--Won't wrap method {0}::{1}", className, cppSignature);
                        return(null);
                    }
                }
                else
                {
                    // global operator
                    if (op == "*" && method->numArgs == 0 || (op == "++" || op == "--") && method->numArgs == 2)
                    {
                        // dereference operator and postfix in-/decrement operator are not supported
                        Debug.Print("  |--Won't wrap method {0}::{1}", className, cppSignature);
                        return(null);
                    }
                }
                isOperator = true;
            }
            else if (op[0] == ' ')
            {
                // conversion operator
                explicitConversionType = op.Substring(1);
                if (explicitConversionType.Contains("QVariant"))
                {
                    return(null);
                }
                try
                {
                    explicitConversionType = translator.CppToCSharp(explicitConversionType, out isRef).GetStringRepresentation();
                    if (smoke->classes[method->classId].size > 0)
                    {
                        CodeParameterDeclarationExpression exp =
                            new CodeParameterDeclarationExpression(translator.CppToCSharp(className, out isRef), "arg" + count++);
                        args.Add(exp);
                    }
                }
                catch (NotSupportedException)
                {
                    Debug.Print("  |--Won't wrap method {0}::{1}", className, cppSignature);
                    return(null);
                }
                isOperator = true;
            }
        }

        // translate arguments
        string[] methodArgs = isOperator ? null : GetMethodArgs(smoke, method);
        for (short *typeIndex = smoke->argumentList + method->args; *typeIndex > 0; typeIndex++)
        {
            try
            {
                args.Add(this.GetArgument(smoke, typeIndex, methodArgs, args, ref count));
            }
            catch (NotSupportedException)
            {
                Debug.Print("  |--Won't wrap method {0}::{1}", className, cppSignature);
                return(null);
            }
        }
        this.RemovePreviousOverload(args, char.ToUpper(methName[0]) + methName.Substring(1));

        // translate return type
        CodeTypeReference returnType;

        try
        {
            returnType = translator.CppToCSharp(smoke->types + method->ret, out isRef);
        }
        catch (NotSupportedException)
        {
            Debug.Print("  |--Won't wrap method {0}::{1}", className, cppSignature);
            return(null);
        }

        CodeMemberMethod cmm;

        if ((method->flags & (uint)Smoke.MethodFlags.mf_ctor) > 0)
        {
            cmm            = new CodeConstructor();
            cmm.Attributes = 0;             // initialize to 0 so we can do |=
            ((CodeConstructor)cmm).ChainedConstructorArgs.Add(new CodeSnippetExpression("(System.Type) null"));
        }
        else
        {
            cmm            = new CodeMemberMethod();
            cmm.Attributes = 0;             // initialize to 0 so we can do |=

            string csName = methName;
            if (!isOperator && methName != "finalize" && !qMethodExp.IsMatch(methName))
            {
                // capitalize the first letter
                StringBuilder builder = new StringBuilder(csName);
                builder[0] = char.ToUpper(builder[0]);
                string tmp = builder.ToString();

                // If the new name clashes with a name of a type declaration, keep the lower-case name.
                var typesWithSameName = from member in data.GetAccessibleMembers(smokeClass)
                                        where member.Type == MemberTypes.NestedType && member.Name == tmp
                                        select member;

                var propertiesWithSameName = (from member in data.GetAccessibleMembers(smokeClass)
                                              where member.Type == MemberTypes.Property && member.Name == tmp
                                              select member).ToList();

                if (iface != null && propertiesWithSameName.Count() == 1 &&
                    (method->flags & (uint)Smoke.MethodFlags.mf_protected) == 0)
                {
                    cmm.PrivateImplementationType = iface;
                    csName = tmp;
                }
                else
                {
                    if (propertiesWithSameName.Any())
                    {
                        if ((method->flags & (uint)Smoke.MethodFlags.mf_virtual) == 0)
                        {
                            Debug.Print(
                                "  |--Conflicting names: method/(type or property): {0} in class {1} - keeping original method name", tmp,
                                className);
                        }
                        else
                        {
                            csName = tmp;
                        }
                    }
                    else if (typesWithSameName.Any())
                    {
                        Debug.Print("  |--Conflicting names: method/classname: {0} in class {1} - keeping original method name", tmp,
                                    className);
                    }
                    else
                    {
                        csName = tmp;
                    }
                }
            }

            if (explicitConversionType != null)
            {
                cmm.Name       = "explicit operator " + explicitConversionType;
                cmm.ReturnType = new CodeTypeReference(" ");
            }
            else
            {
                cmm.Name       = csName;
                cmm.ReturnType = returnType;
            }
        }

        // for destructors we already have this stuff set
        if ((method->flags & (uint)Smoke.MethodFlags.mf_dtor) == 0)
        {
            // set access
            if ((method->flags & (uint)Smoke.MethodFlags.mf_protected) > 0)
            {
                cmm.Attributes |= MemberAttributes.Family;
            }
            else
            {
                cmm.Attributes |= MemberAttributes.Public;
            }

            if (isOperator)
            {
                cmm.Attributes |= MemberAttributes.Final | MemberAttributes.Static;
            }
            else if (cmm.Name == "ToString" && args.Count == 0 && cmm.ReturnType.BaseType == "System.String")
            {
                cmm.Attributes = MemberAttributes.Public | MemberAttributes.Override;
            }
            else
            {
                if ((method->flags & (uint)Smoke.MethodFlags.mf_static) > 0)
                {
                    cmm.Attributes |= MemberAttributes.Static;
                }
                else
                {
                    // virtual/final
                    MemberAttributes access;
                    bool             foundInInterface;
                    bool             isOverride = MethodOverrides(smoke, method, out access, out foundInInterface);

                    // methods that have to be implemented from interfaces can't override anything
                    if (iface == null && (isOverride = MethodOverrides(smoke, method, out access, out foundInInterface)))
                    {
                        cmm.Attributes = access | MemberAttributes.Override;
                    }
                    else if (foundInInterface)
                    {
                        cmm.Attributes = access;
                    }

                    if ((method->flags & (uint)Smoke.MethodFlags.mf_purevirtual) > 0)
                    {
                        if (!m_internalImplementation)
                        {
                            cmm.Attributes = (cmm.Attributes & ~MemberAttributes.ScopeMask) | MemberAttributes.Abstract;

                            // The code generator doesn't like MemberAttributes.Abstract | MemberAttributes.Override being set.
                            if (isOverride && !type.IsInterface)
                            {
                                cmm.ReturnType.BaseType = "override " + cmm.ReturnType.BaseType == "System.Void"
                                                                                                ? "void"
                                                                                                : cmm.ReturnType.BaseType;
                            }
                        }
                        else
                        {
                            cmm.Attributes |= MemberAttributes.Override;
                        }
                    }

                    if ((method->flags & (uint)Smoke.MethodFlags.mf_virtual) == 0 &&
                        (method->flags & (uint)Smoke.MethodFlags.mf_purevirtual) == 0 &&
                        !isOverride)
                    {
                        cmm.Attributes |= MemberAttributes.Final | MemberAttributes.New;
                    }
                }
            }
        }
        else
        {
            // hack, so we don't have to use CodeSnippetTypeMember to generator the destructor
            cmm.ReturnType = new CodeTypeReference(" ");
        }

        // add the parameters
        foreach (CodeParameterDeclarationExpression exp in args)
        {
            cmm.Parameters.Add(exp);
        }
        this.DistributeMethod(cmm);
        return(cmm);
    }
コード例 #15
0
ファイル: EnumGenerator.cs プロジェクト: corngood/assemblygen
 private static extern long GetEnumValue(Smoke *smoke, Smoke.Method *meth);
コード例 #16
0
    public void Run()
    {
        for (short classId = 1; classId <= data.Smoke->numClasses; classId++)
        {
            Smoke.Class *klass = data.Smoke->classes + classId;
            if (klass->external)
            {
                continue;
            }

            List <Property> props = new List <Property>();
            if (!GetProperties(data.Smoke, classId,
                               (name, originalType, typeName, writable, isEnum) =>
                               props.Add(new Property(name, originalType, typeName, writable, isEnum))))
            {
                continue;
            }

            CodeTypeDeclaration type = data.SmokeTypeMap[(IntPtr)klass];
            string className         = ByteArrayManager.GetString(klass->className);

            foreach (Property prop in props)
            {
                CodeMemberProperty cmp = new CodeMemberProperty();

                try
                {
                    bool  isRef;
                    short id = data.Smoke->IDType(prop.Type);
                    if (id > 0)
                    {
                        cmp.Type = translator.CppToCSharp(data.Smoke->types + id, out isRef);
                    }
                    else
                    {
                        if (!prop.Type.Contains("::"))
                        {
                            id = data.Smoke->IDType(className + "::" + prop.Type);
                            if (id > 0)
                            {
                                cmp.Type = translator.CppToCSharp(data.Smoke->types + id, out isRef);
                            }
                            else
                            {
                                cmp.Type = translator.CppToCSharp(prop.Type, out isRef);
                            }
                        }
                        cmp.Type = translator.CppToCSharp(prop.Type, out isRef);
                    }
                }
                catch (NotSupportedException)
                {
                    Debug.Print("  |--Won't wrap Property {0}::{1}", className, prop.Name);
                    continue;
                }

                if (documentation.ContainsKey(type))
                {
                    IList <string> docs = documentation[type];
                    for (int i = 0; i < docs.Count; i++)
                    {
                        Match match = Regex.Match(docs[i],
                                                  prop.Name + " : (const )?" + prop.OriginalType +
                                                  @"\n(?<docs>This.*?)\nAccess functions:", RegexOptions.Singleline);
                        if (match.Success)
                        {
                            Util.FormatComment(match.Groups["docs"].Value, cmp, i > 0);
                            break;
                        }
                    }
                }
                cmp.Name = prop.Name;
                // capitalize the first letter
                StringBuilder builder = new StringBuilder(cmp.Name);
                builder[0] = char.ToUpper(builder[0]);
                string capitalized = builder.ToString();

                // If the new name clashes with a name of a type declaration, keep the lower-case name (or even make the name lower-case).
                var typesWithSameName = from member in data.GetAccessibleMembers(data.Smoke->classes + classId)
                                        where (member.Type == MemberTypes.NestedType ||
                                               member.Type == MemberTypes.Method) &&
                                        member.Name == capitalized
                                        select member;
                if (typesWithSameName.Any())
                {
                    Debug.Print(
                        "  |--Conflicting names: property/(type or method): {0} in class {1} - keeping original property name",
                        capitalized, className);

                    if (capitalized == cmp.Name)
                    {
                        builder[0] = char.ToLower(builder[0]);
                        cmp.Name   = builder.ToString();                       // lower case the property if necessary
                    }
                }
                else
                {
                    cmp.Name = capitalized;
                }

                cmp.HasGet     = true;
                cmp.HasSet     = prop.IsWritable;
                cmp.Attributes = MemberAttributes.Public | MemberAttributes.New | MemberAttributes.Final;

                cmp.CustomAttributes.Add(new CodeAttributeDeclaration("Q_PROPERTY",
                                                                      new CodeAttributeArgument(
                                                                          new CodePrimitiveExpression(prop.OriginalType)),
                                                                      new CodeAttributeArgument(
                                                                          new CodePrimitiveExpression(prop.Name))));

                // ===== get-method =====
                short getterMapId = FindQPropertyGetAccessorMethodMapId(classId, prop, capitalized);
                if (getterMapId == 0)
                {
                    Debug.Print("  |--Missing 'get' method for property {0}::{1} - using QObject.Property()", className, prop.Name);
                    cmp.GetStatements.Add(new CodeMethodReturnStatement(new CodeCastExpression(cmp.Type,
                                                                                               new CodeMethodInvokeExpression(
                                                                                                   new CodeThisReferenceExpression(),
                                                                                                   "Property",
                                                                                                   new CodePrimitiveExpression(prop.Name)))));
                }
                else
                {
                    Smoke.MethodMap *map      = data.Smoke->methodMaps + getterMapId;
                    short            getterId = map->method;
                    if (getterId < 0)
                    {
                        // simply choose the first (i.e. non-const) version if there are alternatives
                        getterId = data.Smoke->ambiguousMethodList[-getterId];
                    }

                    Smoke.Method *getter = data.Smoke->methods + getterId;
                    if (getter->classId != classId)
                    {
                        // The actual get method is defined in a parent class - don't create a property for it.
                        continue;
                    }
                    if ((getter->flags & (uint)Smoke.MethodFlags.mf_virtual) == 0 &&
                        (getter->flags & (uint)Smoke.MethodFlags.mf_purevirtual) == 0)
                    {
                        cmp.GetStatements.Add(new CodeMethodReturnStatement(new CodeCastExpression(cmp.Type,
                                                                                                   new CodeMethodInvokeExpression(
                                                                                                       SmokeSupport.interceptor_Invoke,
                                                                                                       new CodePrimitiveExpression(
                                                                                                           ByteArrayManager.GetString(
                                                                                                               data.Smoke->methodNames[getter->name
                                                                                                               ])),
                                                                                                       new CodePrimitiveExpression(
                                                                                                           data.Smoke->GetMethodSignature(getter)),
                                                                                                       new CodeTypeOfExpression(cmp.Type),
                                                                                                       new CodePrimitiveExpression(false)))));
                    }
                    else
                    {
                        cmp.HasGet = false;
                        if (!cmp.HasSet)
                        {
                            // the get accessor is virtual and there's no set accessor => continue
                            continue;
                        }
                    }
                }

                // ===== set-method =====
                if (!prop.IsWritable)
                {
                    // not writable? => continue
                    type.Members.Add(cmp);
                    continue;
                }

                char  mungedSuffix;
                short setterMethId = FindQPropertySetAccessorMethodId(classId, prop, capitalized, out mungedSuffix);
                if (setterMethId == 0)
                {
                    Debug.Print("  |--Missing 'set' method for property {0}::{1} - using QObject.SetProperty()", className, prop.Name);
                    cmp.SetStatements.Add(new CodeExpressionStatement(
                                              new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), "SetProperty",
                                                                             new CodePrimitiveExpression(prop.Name),
                                                                             new CodeArgumentReferenceExpression("value"))));
                }
                else
                {
                    Smoke.Method *setter = data.Smoke->methods + setterMethId;
                    if (setter->classId != classId)
                    {
                        // defined in parent class, continue
                        type.Members.Add(cmp);
                        continue;
                    }
                    string setterName = ByteArrayManager.GetString(data.Smoke->methodNames[setter->name]);
                    if (!cmp.HasGet)
                    {
                        // so the 'get' method is virtual - generating a property for only the 'set' method is a bad idea
                        MethodsGenerator mg = new MethodsGenerator(data, translator, type, klass);
                        mg.GenerateMethod(setterMethId, setterName + mungedSuffix);
                        continue;
                    }
                    cmp.SetStatements.Add(new CodeExpressionStatement(
                                              new CodeMethodInvokeExpression(SmokeSupport.interceptor_Invoke,
                                                                             new CodePrimitiveExpression(setterName + mungedSuffix),
                                                                             new CodePrimitiveExpression(
                                                                                 this.data.Smoke->GetMethodSignature(setterMethId)),
                                                                             new CodeTypeOfExpression(typeof(void)),
                                                                             new CodePrimitiveExpression(false),
                                                                             new CodeTypeOfExpression(cmp.Type),
                                                                             new CodeArgumentReferenceExpression("value"))));
                }

                type.Members.Add(cmp);
            }
        }
    }
コード例 #17
0
ファイル: QyotoHooks.cs プロジェクト: corngood/assemblygen
 private void PostMethodBodyHooks(Smoke *smoke, Smoke.Method *smokeMethod, CodeMemberMethod cmm, CodeTypeDeclaration type)
 {
     this.CommentMember(smoke, smokeMethod, cmm, type);
     GenerateEvent(cmm, cmm.Name, type, true);
 }
コード例 #18
0
    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);
            }
        }
    }
コード例 #19
0
    private static bool MethodOverrides(Smoke *smoke, Smoke.Method *method, out MemberAttributes access, out bool foundInInterface)
    {
        access           = MemberAttributes.Public;
        foundInInterface = false;

        if (smoke->inheritanceList[smoke->classes[method->classId].parents] == 0)
        {
            return(false);
        }

        long id = method - smoke->methods;

        Smoke.ModuleIndex methodModuleIndex = new Smoke.ModuleIndex(smoke, (short)id);

        Smoke.Method *firstMethod = (Smoke.Method *)IntPtr.Zero;
        short *       firstParent = smoke->inheritanceList + smoke->classes[method->classId].parents;

        for (short *parent = firstParent; *parent > 0; parent++)
        {
            if (firstMethod != (Smoke.Method *)IntPtr.Zero && !foundInInterface)
            {
                // already found a method in the first parent class
                break;
            }

            // Do this with linq... there's probably room for optimization here.
            // Select virtual and pure virtual methods from superclasses.
            var inheritedVirtuals = from key in smoke->FindAllMethods(*parent, true).Keys
                                    where ((key.smoke->methods[key.index].flags & (ushort)Smoke.MethodFlags.mf_virtual) > 0
                                           ||
                                           (key.smoke->methods[key.index].flags & (ushort)Smoke.MethodFlags.mf_purevirtual) > 0)
                                    select key;

            foreach (Smoke.ModuleIndex mi in inheritedVirtuals)
            {
                Smoke.Method *meth = mi.smoke->methods + mi.index;

                if (SmokeMethodEqualityComparer.DefaultEqualityComparer.Equals(methodModuleIndex, mi))
                {
                    if ((meth->flags & (uint)Smoke.MethodFlags.mf_protected) > 0)
                    {
                        access = MemberAttributes.Family;
                    }
                    else
                    {
                        access = MemberAttributes.Public;
                    }

                    // don't return here - we need the access of the method in the topmost superclass
                    firstMethod = meth;
                    if (parent != firstParent)
                    {
                        foundInInterface = true;
                    }
                }
            }
        }

        // we need to have a method that's not in a interface to mark it as overriden
        bool ret = firstMethod != (Smoke.Method *)IntPtr.Zero && !foundInInterface;

        // we need to have a public method in one of the interfaces for this to be set
        foundInInterface = firstMethod != (Smoke.Method *)IntPtr.Zero && foundInInterface && access == MemberAttributes.Public;

        return(ret);
    }
コード例 #20
0
 public CodeMemberMethod GenerateBasicMethodDefinition(Smoke *smoke, Smoke.Method *method)
 {
     return(GenerateBasicMethodDefinition(smoke, method, null));
 }
コード例 #21
0
    public CodeMemberMethod GenerateBasicMethodDefinition(Smoke *smoke, Smoke.Method *method, CodeTypeReference iface)
    {
        string cppSignature = smoke->GetMethodSignature(method);

        return(GenerateBasicMethodDefinition(smoke, method, cppSignature, iface));
    }
コード例 #22
0
    /*
     * Adds the methods to the classes created by Run()
     */

    private void GenerateMethods()
    {
        short currentClassId = 0;

        Smoke.Class *            klass              = (Smoke.Class *)IntPtr.Zero;
        MethodsGenerator         methgen            = null;
        AttributeGenerator       attrgen            = null;
        CodeTypeDeclaration      type               = null;
        List <Smoke.ModuleIndex> alreadyImplemented = new List <Smoke.ModuleIndex>();

        this.FillEnums();

        for (short i = 1; i < data.Smoke->numMethodMaps; i++)
        {
            Smoke.MethodMap *map = data.Smoke->methodMaps + i;

            if (currentClassId != map->classId)
            {
                // we encountered a new class
                if (attrgen != null)
                {
                    // generate inherited methods
                    this.GenerateInheritedMethods(klass, methgen, attrgen, alreadyImplemented);

                    // generate all scheduled attributes
                    attrgen.Run();

                    if (PostMembersHooks != null)
                    {
                        PostMembersHooks(data.Smoke, klass, type);
                    }
                    methgen.GenerateProperties();
                }

                currentClassId = map->classId;
                klass          = data.Smoke->classes + currentClassId;
                type           = data.SmokeTypeMap[(IntPtr)klass];

                alreadyImplemented.Clear();
                attrgen = new AttributeGenerator(data, translator, type);
                methgen = new MethodsGenerator(data, translator, type, klass);
            }

            string mungedName = ByteArrayManager.GetString(data.Smoke->methodNames[map->name]);
            if (map->method > 0)
            {
                Smoke.Method *meth = data.Smoke->methods + map->method;
                if ((meth->flags & (ushort)Smoke.MethodFlags.mf_enum) > 0)
                {
                    continue;
                }

                if ((meth->flags & (ushort)Smoke.MethodFlags.mf_property) > 0 &&               // non-virtual properties are excluded
                    (meth->flags & (ushort)Smoke.MethodFlags.mf_virtual) == 0 &&
                    (meth->flags & (ushort)Smoke.MethodFlags.mf_purevirtual) == 0)
                {
                    continue;
                }
                if ((meth->flags & (ushort)Smoke.MethodFlags.mf_attribute) > 0)
                {
                    attrgen.ScheduleAttributeAccessor(meth);
                    continue;
                }

                methgen.GenerateMethod(map->method, mungedName);
                alreadyImplemented.Add(new Smoke.ModuleIndex(data.Smoke, map->method));
            }
            else if (map->method < 0)
            {
                for (short *overload = data.Smoke->ambiguousMethodList + (-map->method); *overload > 0; overload++)
                {
                    Smoke.Method *meth = data.Smoke->methods + *overload;
                    if ((meth->flags & (ushort)Smoke.MethodFlags.mf_enum) > 0)
                    {
                        continue;
                    }

                    if ((meth->flags & (ushort)Smoke.MethodFlags.mf_property) > 0 &&                   // non-virtual properties are excluded
                        (meth->flags & (ushort)Smoke.MethodFlags.mf_virtual) == 0 &&
                        (meth->flags & (ushort)Smoke.MethodFlags.mf_purevirtual) == 0)
                    {
                        continue;
                    }
                    if ((meth->flags & (ushort)Smoke.MethodFlags.mf_attribute) > 0)
                    {
                        attrgen.ScheduleAttributeAccessor(meth);
                        continue;
                    }

                    // if the methods differ only by constness, we will generate special code
                    bool nextDiffersByConst = false;
                    if (*(overload + 1) > 0)
                    {
                        if (SmokeMethodEqualityComparer.EqualExceptConstness(meth, data.Smoke->methods + *(overload + 1)))
                        {
                            nextDiffersByConst = true;
                        }
                    }

                    methgen.GenerateMethod(*overload, mungedName);
                    alreadyImplemented.Add(new Smoke.ModuleIndex(data.Smoke, *overload));
                    if (nextDiffersByConst)
                    {
                        overload++;
                    }
                }
            }
        }

        // Generate the last scheduled attributes
        attrgen.Run();
        // Generate remaining inherited methods
        this.GenerateInheritedMethods(klass, methgen, attrgen, alreadyImplemented);

        if (PostMembersHooks != null)
        {
            PostMembersHooks(data.Smoke, klass, type);
        }
        methgen.GenerateProperties();
        AddMissingOperators();
    }
コード例 #23
0
    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);
    }
コード例 #24
0
 public void ScheduleAttributeAccessor(Smoke.Method *meth)
 {
     ScheduleAttributeAccessor(data.Smoke, meth);
 }