/*
     * Returns a list of accessible members from class 'klass' and superclasses (just nested classes and properties for now).
     */

    public List <InternalMemberInfo> GetAccessibleMembers(Smoke.Class *klass)
    {
        List <InternalMemberInfo> members = new List <InternalMemberInfo>();

        GetAccessibleMembers(klass, members);
        return(members);
    }
    private void GenerateInternalImplementationMethods()
    {
        for (short i = 1; i <= data.Smoke->numClasses; i++)
        {
            Smoke.Class *klass = data.Smoke->classes + i;
            if (klass->external)
            {
                continue;
            }
            CodeTypeDeclaration type = data.SmokeTypeMap[(IntPtr)klass];

            CodeTypeDeclaration implType;
            if (!data.InternalTypeMap.TryGetValue(type, out implType))
            {
                continue;
            }

            MethodsGenerator methgen = new MethodsGenerator(data, translator, implType, klass);
            methgen.InternalImplementation = true;

            foreach (KeyValuePair <Smoke.ModuleIndex, string> pair in Util.GetAbstractMethods(data.Smoke, i))
            {
                methgen.GenerateMethod(pair.Key.smoke, pair.Key.index, pair.Value);
            }
            methgen.GenerateProperties();
        }
    }
Exemple #3
0
 public MethodsGenerator(GeneratorData data, Translator translator, CodeTypeDeclaration type, Smoke.Class *klass)
 {
     this.data       = data;
     this.translator = translator;
     this.type       = type;
     this.smokeClass = klass;
 }
Exemple #4
0
 // Recursively adds base classes to a hash set.
 private void AddBaseClassesToHashSet(Smoke.Class *klass, ISet <short> set)
 {
     for (short *parent = data.Smoke->inheritanceList + klass->parents; *parent > 0; parent++)
     {
         Smoke.Class *baseClass = data.Smoke->classes + *parent;
         if (baseClass->external)
         {
             continue;
         }
         set.Add(*parent);
         AddBaseClassesToHashSet(baseClass, set);
     }
 }
    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);
        }
    }
Exemple #6
0
    public void PreMembersHook(Smoke *smoke, Smoke.Class *klass, CodeTypeDeclaration type)
    {
        if (type.Name == "QObject")
        {
            // Add 'Qt' base class
            type.BaseTypes.Add(new CodeTypeReference("Qt"));

            // add the Q_EMIT field
            CodeMemberField Q_EMIT = new CodeMemberField(typeof(object), "Q_EMIT");
            Q_EMIT.Attributes     = MemberAttributes.Family;
            Q_EMIT.InitExpression = new CodePrimitiveExpression(null);
            type.Members.Add(Q_EMIT);
        }
    }
    private void GetAccessibleMembers(Smoke.Class *klass, List <InternalMemberInfo> list)
    {
        if (Debug)
        {
            Console.Error.WriteLine("members from class {0}", ByteArrayManager.GetString(klass->className));
        }
        if (klass->external)
        {
            AddReferencedMembers(klass, list);
            return;
        }

        CodeTypeDeclaration typeDecl;

        if (!SmokeTypeMap.TryGetValue((IntPtr)klass, out typeDecl))
        {
            AddReferencedMembers(klass, list);
            return;
        }
        foreach (CodeTypeMember member in typeDecl.Members)
        {
            if (member is CodeMemberProperty)
            {
                list.Add(new InternalMemberInfo(MemberTypes.Property, member.Name));
            }
            else if (member is CodeMemberMethod)
            {
                list.Add(new InternalMemberInfo(MemberTypes.Method, member.Name));
            }
            else if (member is CodeMemberField)
            {
                list.Add(new InternalMemberInfo(MemberTypes.Field, member.Name));
            }
            else if (member is CodeTypeDeclaration)
            {
                list.Add(new InternalMemberInfo(MemberTypes.NestedType, member.Name));
            }
        }

        for (short *parent = Smoke->inheritanceList + klass->parents; *parent > 0; parent++)
        {
            Smoke.Class *parentClass = Smoke->classes + *parent;
            GetAccessibleMembers(parentClass, list);
        }
    }
    private void AddReferencedMembers(Smoke.Class *klass, ICollection <InternalMemberInfo> list)
    {
        string smokeClassName = ByteArrayManager.GetString(klass->className);
        Type   type;

        if (!ReferencedTypeMap.TryGetValue(smokeClassName, out type))
        {
            Console.Error.WriteLine("Couldn't find referenced class {0}", smokeClassName);
            return;
        }

        foreach (
            MemberInfo member in
            type.GetMembers(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static))
        {
            list.Add(new InternalMemberInfo(member.MemberType, member.Name));
        }
    }
    /*
     * Returns the collection of sub-types for a given prefix (which may be a namespace or a class).
     * If 'prefix' is empty, returns the collection of the default namespace.
     */

    public IList GetTypeCollection(string prefix)
    {
        if (string.IsNullOrEmpty(prefix))
        {
            return(DefaultNamespace.Types);
        }
        CodeNamespace       nspace;
        CodeTypeDeclaration typeDecl;

        // Did we already define the class or namespace?
        if (NamespaceMap.TryGetValue(prefix, out nspace))
        {
            return(nspace.Types);
        }
        if (CSharpTypeMap.TryGetValue(prefix, out typeDecl))
        {
            return(typeDecl.Members);
        }

        // Make sure that we don't define a namespace where a class should actually be.
        // This shouldn't happen, but to be sure we check it again.
        short id = Smoke->IDClass(prefix);

        Smoke.Class *klass = Smoke->classes + id;
        if (id != 0 && klass->size > 0)
        {
            throw new Exception("Found class instead of namespace - this should not happen!");
        }

        // Define a new namespace.
        nspace = new CodeNamespace(prefix.Replace("::", "."));
        this.AddUsings(nspace);

        CompileUnit.Namespaces.Add(nspace);
        NamespaceMap[prefix] = nspace;
        return(nspace.Types);
    }
Exemple #10
0
    /*
     * Returns a list of classes for which we need to generate interfaces.
     */

    private HashSet <short> GetClassList()
    {
        HashSet <short> set = new HashSet <short>();

        for (short i = 1; i <= data.Smoke->numClasses; i++)
        {
            Smoke.Class *klass = data.Smoke->classes + i;

            if (!klass->external && translator.InterfaceClasses.Contains(ByteArrayManager.GetString(klass->className)))
            {
                set.Add(i);
                // also generate interfaces for the base classes of the base classes
                AddBaseClassesToHashSet(klass, set);
            }

            bool firstParent = true;
            for (short *parent = data.Smoke->inheritanceList + klass->parents; *parent > 0; parent++)
            {
                if (firstParent)
                {
                    // don't generate interfaces for the first base class
                    firstParent = false;
                    continue;
                }

                Smoke.Class *baseClass = data.Smoke->classes + *parent;
                if (baseClass->external)
                {
                    continue;
                }
                set.Add(*parent);
                AddBaseClassesToHashSet(baseClass, set);
            }
        }
        return(set);
    }
    /*
     * Create a .NET class from a smoke class.
     * A class Namespace::Foo is mapped to Namespace.Foo. Classes that are not in any namespace go into the default namespace.
     * For namespaces that contain functions, a Namespace.Global class is created which holds the functions as methods.
     */

    private void DefineClass(short classId)
    {
        Smoke.Class *smokeClass = data.Smoke->classes + classId;
        string       smokeName  = ByteArrayManager.GetString(smokeClass->className);
        string       mapName    = smokeName;
        string       name;
        string       prefix = string.Empty;

        if (smokeClass->size == 0 && !translator.NamespacesAsClasses.Contains(smokeName))
        {
            if (smokeName == "QGlobalSpace")
            {
                // global space
                name    = data.GlobalSpaceClassName;
                mapName = name;
            }
            else
            {
                // namespace
                prefix  = smokeName;
                name    = "Global";
                mapName = prefix + "::Global";
            }
        }
        else
        {
            int colon = smokeName.LastIndexOf("::", StringComparison.Ordinal);
            prefix = (colon != -1) ? smokeName.Substring(0, colon) : string.Empty;
            name   = (colon != -1) ? smokeName.Substring(colon + 2) : smokeName;
        }

        // define the .NET class
        CodeTypeDeclaration type;
        bool alreadyDefined;

        if (!(alreadyDefined = data.CSharpTypeMap.TryGetValue(mapName, out type)))
        {
            type = new CodeTypeDeclaration(name);
            CodeAttributeDeclaration attr = new CodeAttributeDeclaration("SmokeClass",
                                                                         new CodeAttributeArgument(
                                                                             new CodePrimitiveExpression(smokeName)));
            type.CustomAttributes.Add(attr);
            type.IsPartial = true;
        }
        else
        {
            int toBeRemoved = -1;

            for (int i = 0; i < type.CustomAttributes.Count; i++)
            {
                CodeAttributeDeclaration attr = type.CustomAttributes[i];
                if (attr.Name == "SmokeClass" && attr.Arguments.Count == 1 &&
                    ((string)((CodePrimitiveExpression)attr.Arguments[0].Value).Value) == "QGlobalSpace")
                {
                    toBeRemoved = i;
                    break;
                }
            }

            if (toBeRemoved > -1)
            {
                type.CustomAttributes.RemoveAt(toBeRemoved);
                CodeAttributeDeclaration attr = new CodeAttributeDeclaration("SmokeClass",
                                                                             new CodeAttributeArgument(
                                                                                 new CodePrimitiveExpression(smokeName)));
                type.CustomAttributes.Add(attr);
            }
        }

        if (smokeClass->parents != 0)
        {
            short *parent = data.Smoke->inheritanceList + smokeClass->parents;
            if (*parent > 0)
            {
                type.BaseTypes.Add(
                    new CodeTypeReference(ByteArrayManager.GetString((data.Smoke->classes + *parent)->className).Replace("::", ".")));
            }
        }

        if (Util.IsClassAbstract(data.Smoke, classId))
        {
            type.TypeAttributes |= TypeAttributes.Abstract;
        }

        if (PreMembersHooks != null)
        {
            PreMembersHooks(data.Smoke, smokeClass, type);
        }

        if (!alreadyDefined)
        {
            DefineWrapperClassFieldsAndMethods(smokeClass, type);
            data.CSharpTypeMap[mapName] = type;
            IList collection = data.GetTypeCollection(prefix);
            collection.Add(type);
            type.UserData.Add("parent", prefix);

            // add the internal implementation type for abstract classes
            if ((type.TypeAttributes & TypeAttributes.Abstract) == TypeAttributes.Abstract)
            {
                CodeTypeDeclaration implType = new CodeTypeDeclaration();
                implType.Name = type.Name + "Internal";
                implType.BaseTypes.Add(new CodeTypeReference(type.Name));
                implType.IsPartial      = true;
                implType.TypeAttributes = TypeAttributes.NotPublic;

                CodeConstructor dummyCtor = new CodeConstructor();
                dummyCtor.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference(typeof(Type)), "dummy"));
                dummyCtor.BaseConstructorArgs.Add(new CodeSnippetExpression("(System.Type) null"));
                dummyCtor.Attributes = MemberAttributes.Family;
                implType.Members.Add(dummyCtor);

                data.InternalTypeMap[type] = implType;

                collection.Add(implType);
            }
        }

        data.SmokeTypeMap[(IntPtr)smokeClass] = type;
    }
    /*
     * Adds complementing operators if necessary.
     */

    private void AddMissingOperators()
    {
        for (short i = 1; i <= this.data.Smoke->numClasses; i++)
        {
            Smoke.Class *klass = this.data.Smoke->classes + i;
            // skip external classes and namespaces
            if (klass->external || klass->size == 0)
            {
                continue;
            }

            CodeTypeDeclaration typeDecl = this.data.SmokeTypeMap[(IntPtr)klass];

            var lessThanOperators           = new List <CodeMemberMethod>();
            var greaterThanOperators        = new List <CodeMemberMethod>();
            var lessThanOrEqualOperators    = new List <CodeMemberMethod>();
            var greaterThanOrEqualOperators = new List <CodeMemberMethod>();
            var equalOperators   = new List <CodeMemberMethod>();
            var inequalOperators = new List <CodeMemberMethod>();

            foreach (CodeMemberMethod method in typeDecl.Members.OfType <CodeMemberMethod>())
            {
                switch (method.Name)
                {
                case "operator<":
                    lessThanOperators.Add(method);
                    break;

                case "operator>":
                    greaterThanOperators.Add(method);
                    break;

                case "operator<=":
                    lessThanOrEqualOperators.Add(method);
                    break;

                case "operator>=":
                    greaterThanOrEqualOperators.Add(method);
                    break;

                case "operator==":
                    equalOperators.Add(method);
                    break;

                case "operator!=":
                    inequalOperators.Add(method);
                    break;
                }
            }

            AddComplementingOperatorsFn checkAndAdd =
                delegate(IList <CodeMemberMethod> ops, IList <CodeMemberMethod> otherOps, string opName, string expr)
            {
                foreach (CodeMemberMethod op in ops)
                {
                    if (otherOps.Any(otherOp => op.ParametersEqual(otherOp)))
                    {
                        continue;
                    }

                    CodeMemberMethod complement = new CodeMemberMethod();
                    complement.Name       = opName;
                    complement.Attributes = op.Attributes;
                    complement.ReturnType = op.ReturnType;
                    complement.Parameters.AddRange(op.Parameters);
                    complement.Statements.Add(new CodeMethodReturnStatement(new CodeSnippetExpression(expr)));
                    typeDecl.Members.Add(complement);
                }
            };

            checkAndAdd(lessThanOperators, greaterThanOperators, "operator>", "!(arg1 < arg2) && arg1 != arg2");
            checkAndAdd(greaterThanOperators, lessThanOperators, "operator<", "!(arg1 > arg2) && arg1 != arg2");

            checkAndAdd(lessThanOrEqualOperators, greaterThanOrEqualOperators, "operator>=", "!(arg1 < arg2)");
            checkAndAdd(greaterThanOrEqualOperators, lessThanOrEqualOperators, "operator<=", "!(arg1 > arg2)");

            checkAndAdd(equalOperators, inequalOperators, "operator!=", "!(arg1 == arg2)");
            checkAndAdd(inequalOperators, equalOperators, "operator==", "!(arg1 != arg2)");

            if (equalOperators.Count == 0 && inequalOperators.Count == 0)
            {
                continue;                 // then we're done
            }
            // add Equals(object) and GetHashCode() overrides
            CodeSnippetTypeMember equals = new CodeSnippetTypeMember(string.Format(EqualsCode, typeDecl.Name));

            typeDecl.Members.Add(equals);
            typeDecl.Members.Add(getHashCode);
        }
    }
    /*
     * 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();
    }
    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);
            }
        }
    }
    private void DefineWrapperClassFieldsAndMethods(Smoke.Class *smokeClass, CodeTypeDeclaration type)
    {
        // define the dummy constructor
        if (smokeClass->size > 0)
        {
            CodeConstructor dummyCtor = new CodeConstructor();
            dummyCtor.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference(typeof(Type)), "dummy"));
            if (data.Smoke->inheritanceList[smokeClass->parents] > 0)
            {
                dummyCtor.BaseConstructorArgs.Add(new CodeSnippetExpression("(System.Type) null"));
            }
            dummyCtor.Attributes = MemberAttributes.Family;
            if (SupportingMethodsHooks != null)
            {
                SupportingMethodsHooks(data.Smoke, (Smoke.Method *) 0, dummyCtor, type);
            }
            type.Members.Add(dummyCtor);
        }

        CodeMemberField staticInterceptor = new CodeMemberField("SmokeInvocation", "staticInterceptor");

        staticInterceptor.Attributes = MemberAttributes.Static;
        CodeObjectCreateExpression initExpression = new CodeObjectCreateExpression("SmokeInvocation");

        initExpression.Parameters.Add(new CodeTypeOfExpression(type.Name));
        initExpression.Parameters.Add(new CodePrimitiveExpression(null));
        staticInterceptor.InitExpression = initExpression;
        type.Members.Add(staticInterceptor);

        if (smokeClass->size == 0)
        {
            return;
        }

        // we only need this for real classes
        CodeMemberMethod createProxy = new CodeMemberMethod();

        createProxy.Name       = "CreateProxy";
        createProxy.Attributes = MemberAttributes.Public;
        if (data.Smoke->inheritanceList[smokeClass->parents] != 0)
        {
            createProxy.Attributes |= MemberAttributes.Override;
        }
        createProxy.Statements.Add(new CodeAssignStatement(
                                       new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), "interceptor"),
                                       // left hand side
                                       new CodeObjectCreateExpression("SmokeInvocation", new CodeTypeOfExpression(type.Name),
                                                                      new CodeThisReferenceExpression())             // right hand side
                                       ));
        type.Members.Add(createProxy);

        if (data.Smoke->inheritanceList[smokeClass->parents] != 0)
        {
            return;
        }
        // The following fields are only necessary for classes without superclasses.

        CodeMemberField interceptor = new CodeMemberField("SmokeInvocation", "interceptor");

        interceptor.Attributes = MemberAttributes.Family;
        type.Members.Add(interceptor);
        CodeMemberField smokeObject = new CodeMemberField(typeof(IntPtr), "smokeObject");

        type.Members.Add(smokeObject);
        type.BaseTypes.Add(new CodeTypeReference("ISmokeObject"));
        CodeMemberProperty propertySmokeObject = new CodeMemberProperty();

        propertySmokeObject.Name       = "SmokeObject";
        propertySmokeObject.Type       = new CodeTypeReference(typeof(IntPtr));
        propertySmokeObject.Attributes = MemberAttributes.Public;
        CodeFieldReferenceExpression smokeObjectReference = new CodeFieldReferenceExpression(
            new CodeThisReferenceExpression(), smokeObject.Name);

        propertySmokeObject.GetStatements.Add(new CodeMethodReturnStatement(smokeObjectReference));
        propertySmokeObject.SetStatements.Add(new CodeAssignStatement(smokeObjectReference,
                                                                      new CodePropertySetValueReferenceExpression()));
        type.Members.Add(propertySmokeObject);
    }
    /*
     * Loops through all wrapped methods. Any class that is found is converted to a .NET class (see DefineClass()).
     * A MethodGenerator is then created to generate the methods for that class.
     */

    public void Run()
    {
        for (short i = 1; i <= data.Smoke->numClasses; i++)
        {
            Smoke.Class *klass = data.Smoke->classes + i;
            if (klass->external)
            {
                continue;
            }

            DefineClass(i);
        }

        eg.DefineEnums();

        // create interfaces if necessary
        ClassInterfacesGenerator cig = new ClassInterfacesGenerator(data, translator);

        cig.Run();

        for (short i = 1; i <= data.Smoke->numClasses; i++)
        {
            Smoke.Class *klass = data.Smoke->classes + i;
            if (klass->external)
            {
                continue;
            }

            string className         = ByteArrayManager.GetString(klass->className);
            CodeTypeDeclaration type = data.SmokeTypeMap[(IntPtr)klass];
            CodeTypeDeclaration iface;
            if (data.InterfaceTypeMap.TryGetValue(className, out iface))
            {
                type.BaseTypes.Add(new CodeTypeReference('I' + type.Name));
            }

            short *parent      = data.Smoke->inheritanceList + klass->parents;
            bool   firstParent = true;
            while (*parent > 0)
            {
                if (firstParent)
                {
                    firstParent = false;
                    parent++;
                    continue;
                }
                // Translator.CppToCSharp() will take care of 'interfacifying' the class name
                type.BaseTypes.Add(translator.CppToCSharp(data.Smoke->classes + *parent));
                parent++;
            }
        }

        if (PreClassesHook != null)
        {
            PreClassesHook();
        }

        GenerateMethods();
        GenerateInternalImplementationMethods();

        if (PostClassesHook != null)
        {
            PostClassesHook();
        }
        MethodsGenerator.Provider.Dispose();
    }
Exemple #17
0
 public MethodsGenerator(GeneratorData data, Translator translator, CodeTypeDeclaration type, Smoke.Class* klass)
 {
     this.data = data;
     this.translator = translator;
     this.type = type;
     this.smokeClass = klass;
 }
Exemple #18
0
 public static unsafe bool IsQObject(Smoke.Class *klass)
 {
     return(IsDerivedFrom(ByteArrayManager.GetString(klass->className), "QObject"));
 }
Exemple #19
0
    public void PostMembersHook(Smoke *smoke, Smoke.Class *klass, CodeTypeDeclaration type)
    {
        if (Util.IsQObject(klass))
        {
            CodeMemberProperty emit = new CodeMemberProperty();
            emit.Name       = "Emit";
            emit.Attributes = MemberAttributes.Family | MemberAttributes.New | MemberAttributes.Final;
            emit.HasGet     = true;
            emit.HasSet     = false;

            string            signalsIfaceName = "I" + type.Name + "Signals";
            CodeTypeReference returnType       = new CodeTypeReference(signalsIfaceName);
            emit.Type = returnType;

            emit.GetStatements.Add(new CodeMethodReturnStatement(new CodeCastExpression(
                                                                     returnType,
                                                                     new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), "Q_EMIT")
                                                                     )));

            type.Members.Add(emit);

            string className = ByteArrayManager.GetString(klass->className);
            int    colon     = className.LastIndexOf("::", StringComparison.Ordinal);
            string prefix    = (colon != -1) ? className.Substring(0, colon) : string.Empty;

            IList typeCollection          = Data.GetTypeCollection(prefix);
            CodeTypeDeclaration ifaceDecl = new CodeTypeDeclaration(signalsIfaceName);
            ifaceDecl.IsInterface = true;

            if (className != "QObject")
            {
                string parentClassName = ByteArrayManager.GetString(smoke->classes[smoke->inheritanceList[klass->parents]].className);
                colon  = parentClassName.LastIndexOf("::", StringComparison.Ordinal);
                prefix = (colon != -1) ? parentClassName.Substring(0, colon) : string.Empty;
                if (colon != -1)
                {
                    parentClassName = parentClassName.Substring(colon + 2);
                }

                string parentInterface = (prefix != string.Empty) ? prefix.Replace("::", ".") + "." : string.Empty;
                parentInterface += "I" + parentClassName + "Signals";

                ifaceDecl.BaseTypes.Add(new CodeTypeReference(parentInterface));
            }
            Dictionary <CodeSnippetTypeMember, CodeMemberMethod> signalEvents = new Dictionary <CodeSnippetTypeMember, CodeMemberMethod>();
            GetSignals(smoke, klass, delegate(string signature, string name, string typeName, IntPtr metaMethod)
            {
                CodeMemberMethod signal = new CodeMemberMethod();
                signal.Attributes       = MemberAttributes.Abstract;

                // capitalize the first letter
                StringBuilder builder = new StringBuilder(name);
                builder[0]            = char.ToUpper(builder[0]);
                string tmp            = builder.ToString();

                signal.Name = tmp;
                bool isRef;
                try
                {
                    if (typeName == string.Empty)
                    {
                        signal.ReturnType = new CodeTypeReference(typeof(void));
                    }
                    else
                    {
                        signal.ReturnType = Translator.CppToCSharp(typeName, out isRef);
                    }
                }
                catch (NotSupportedException)
                {
                    Debug.Print("  |--Won't wrap signal {0}::{1}", className, signature);
                    return;
                }

                CodeAttributeDeclaration attr = new CodeAttributeDeclaration("Q_SIGNAL",
                                                                             new CodeAttributeArgument(new CodePrimitiveExpression(signature)));
                signal.CustomAttributes.Add(attr);

                int argNum = 1;
                StringBuilder fullNameBuilder = new StringBuilder("Slot");
                GetMetaMethodParameters(metaMethod, delegate(string paramType, string paramName)
                {
                    if (paramName == string.Empty)
                    {
                        paramName = "arg" + argNum.ToString();
                    }
                    argNum++;

                    CodeParameterDeclarationExpression param;
                    try
                    {
                        short id = smoke->IDType(paramType);
                        CodeTypeReference paramTypeRef;
                        if (id > 0)
                        {
                            paramTypeRef = Translator.CppToCSharp(smoke->types + id, out isRef);
                        }
                        else
                        {
                            if (!paramType.Contains("::"))
                            {
                                id = smoke->IDType(className + "::" + paramType);
                                if (id > 0)
                                {
                                    paramTypeRef = Translator.CppToCSharp(smoke->types + id, out isRef);
                                }
                                else
                                {
                                    paramTypeRef = Translator.CppToCSharp(paramType, out isRef);
                                }
                            }
                            else
                            {
                                paramTypeRef = Translator.CppToCSharp(paramType, out isRef);
                            }
                        }
                        param = new CodeParameterDeclarationExpression(paramTypeRef, paramName);
                    }
                    catch (NotSupportedException)
                    {
                        Debug.Print("  |--Won't wrap signal {0}::{1}", className, signature);
                        return;
                    }
                    if (isRef)
                    {
                        param.Direction = FieldDirection.Ref;
                    }
                    signal.Parameters.Add(param);
                    if (argNum == 2)
                    {
                        fullNameBuilder.Append('<');
                    }
                    fullNameBuilder.Append(param.Type.BaseType);
                    fullNameBuilder.Append(',');
                });
                if (fullNameBuilder[fullNameBuilder.Length - 1] == ',')
                {
                    fullNameBuilder[fullNameBuilder.Length - 1] = '>';
                }
                ifaceDecl.Members.Add(signal);
                CodeSnippetTypeMember signalEvent = new CodeSnippetTypeMember();
                signalEvent.Name = signal.Name;
                CodeSnippetTypeMember existing = signalEvents.Keys.FirstOrDefault(m => m.Name == signal.Name);
                if (existing != null)
                {
                    CodeSnippetTypeMember signalEventToUse;
                    CodeMemberMethod signalToUse;
                    if (signal.Parameters.Count == 0)
                    {
                        signalEventToUse = existing;
                        signalToUse      = signalEvents[existing];
                    }
                    else
                    {
                        signalEventToUse = signalEvent;
                        signalToUse      = signal;
                    }
                    string suffix = signalToUse.Parameters.Cast <CodeParameterDeclarationExpression>().Last().Name;
                    if (suffix.StartsWith("arg") && suffix.Length > 3 && char.IsDigit(suffix[3]))
                    {
                        string lastType = signalToUse.Parameters.Cast <CodeParameterDeclarationExpression>().Last().Type.BaseType;
                        suffix          = lastType.Substring(lastType.LastIndexOf('.') + 1);
                    }
                    else
                    {
                        StringBuilder lastParamBuilder = new StringBuilder(suffix);
                        lastParamBuilder[0]            = char.ToUpper(lastParamBuilder[0]);
                        suffix = lastParamBuilder.ToString();
                    }
                    signalEventToUse.Text = signalEventToUse.Text.Replace(signalEventToUse.Name, signalEventToUse.Name += suffix);
                }
                signalEvent.Text = string.Format(@"
        public event {0} {1}
		{{
			add
			{{
                QObject.Connect(this, Qt.SIGNAL(""{2}""), (QObject) value.Target, Qt.SLOT(value.Method.Name + ""{3}""));
			}}
			remove
			{{
                QObject.Disconnect(this, Qt.SIGNAL(""{2}""), (QObject) value.Target, Qt.SLOT(value.Method.Name + ""{3}""));
			}}
		}}"        , fullNameBuilder, signalEvent.Name, signature, signature.Substring(signature.IndexOf('(')));
                signalEvents.Add(signalEvent, signal);
            });

            typeCollection.Add(ifaceDecl);
            foreach (KeyValuePair <CodeSnippetTypeMember, CodeMemberMethod> signalEvent in signalEvents)
            {
                CodeSnippetTypeMember          implementation = signalEvent.Key;
                CodeCommentStatementCollection comments       = new CodeCommentStatementCollection();
                foreach (CodeTypeMember current in from CodeTypeMember member in type.Members
                         where member.Name == implementation.Name
                         select member)
                {
                    if (comments.Count == 0)
                    {
                        comments.AddRange(current.Comments);
                    }
                    current.Name = "On" + current.Name;
                }
                signalEvent.Value.Comments.AddRange(comments);
                signalEvent.Key.Comments.AddRange(comments);
                type.Members.Add(signalEvent.Key);
            }
        }
    }
Exemple #20
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);
            }
        }
    }
Exemple #21
0
    public CodeTypeReference CppToCSharp(Smoke.Class *klass)
    {
        bool isRef;

        return(this.CppToCSharp(ByteArrayManager.GetString(klass->className), out isRef));
    }