Пример #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
 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 GeneratorData(Smoke *smoke, string defaultNamespace, List <string> imports, List <Assembly> references,
                         CodeCompileUnit unit, string destination, string docs)
    {
        Destination = destination;
        Docs        = docs;
        Smoke       = smoke;
        string argNamesFile = GetArgNamesFile(Smoke);

        if (File.Exists(argNamesFile))
        {
            foreach (string[] strings in File.ReadAllLines(argNamesFile).Select(line => line.Split(';')))
            {
                ArgumentNames[strings[0]] = strings[1].Split(',');
            }
        }
        CompileUnit = unit;
        Imports     = imports;

        References       = references;
        DefaultNamespace = new CodeNamespace(defaultNamespace);
        this.AddUsings(DefaultNamespace);

        foreach (Assembly assembly in References)
        {
            smokeClassAttribute = assembly.GetType("QtCore.SmokeClass", false);
            if (smokeClassAttribute != null)
            {
                smokeClassGetSignature = smokeClassAttribute.GetProperty("Signature").GetGetMethod();
                break;
            }
        }
        foreach (Assembly assembly in References)
        {
            foreach (Type type in assembly.GetTypes())
            {
                object[] attributes = type.GetCustomAttributes(smokeClassAttribute, false);
                if (attributes.Length != 0)
                {
                    string smokeClassName = (string)smokeClassGetSignature.Invoke(attributes[0], null);
                    Type   t;
                    if (ReferencedTypeMap.TryGetValue(smokeClassName, out t) && t.IsInterface)
                    {
                        continue;
                    }
                    ReferencedTypeMap[smokeClassName] = type;
                }
                else
                {
                    ReferencedTypeMap[type.Name] = type;
                }
            }
        }

        CompileUnit.Namespaces.Add(DefaultNamespace);
        NamespaceMap[defaultNamespace] = DefaultNamespace;
    }
Пример #4
0
    public GeneratorData(Smoke* smoke, string defaultNamespace, List<string> imports, List<Assembly> references,
	                     CodeCompileUnit unit, string destination, string docs)
    {
        Destination = destination;
        Docs = docs;
        Smoke = smoke;
        string argNamesFile = GetArgNamesFile(Smoke);
        if (File.Exists(argNamesFile))
        {
            foreach (string[] strings in File.ReadAllLines(argNamesFile).Select(line => line.Split(';')))
            {
                ArgumentNames[strings[0]] = strings[1].Split(',');
            }
        }
        CompileUnit = unit;
        Imports = imports;

        References = references;
        DefaultNamespace = new CodeNamespace(defaultNamespace);
        this.AddUsings(DefaultNamespace);

        foreach (Assembly assembly in References)
        {
            smokeClassAttribute = assembly.GetType("QtCore.SmokeClass", false);
            if (smokeClassAttribute != null)
            {
                smokeClassGetSignature = smokeClassAttribute.GetProperty("Signature").GetGetMethod();
                break;
            }
        }
        foreach (Assembly assembly in References)
        {
            foreach (Type type in assembly.GetTypes())
            {
                object[] attributes = type.GetCustomAttributes(smokeClassAttribute, false);
                if (attributes.Length != 0)
                {
                    string smokeClassName = (string) smokeClassGetSignature.Invoke(attributes[0], null);
                    Type t;
                    if (ReferencedTypeMap.TryGetValue(smokeClassName, out t) && t.IsInterface)
                    {
                        continue;
                    }
                    ReferencedTypeMap[smokeClassName] = type;
                }
                else
                {
                    ReferencedTypeMap[type.Name] = type;
                }
            }
        }

        CompileUnit.Namespaces.Add(DefaultNamespace);
        NamespaceMap[defaultNamespace] = DefaultNamespace;
    }
Пример #5
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;
        }
    }
Пример #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);
        }
    }
Пример #7
0
    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;
                    }
                }
            }
        }
    }
Пример #8
0
 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;
             }
         }
     }
 }
Пример #9
0
    private CodeParameterDeclarationExpression GetArgument(Smoke *smoke, short *typeIndex, IList <string> methodArgs, IEnumerable args, ref int count)
    {
        bool isRef;
        CodeTypeReference argType = translator.CppToCSharp(smoke->types + *typeIndex, out isRef);
        string            argName = this.GetArgName(smoke, typeIndex, methodArgs, ref count, isRef, argType);

        if (!argName.Contains(" = "))
        {
            RemoveDefaultValuesFromPreviousArgs(args);
        }
        CodeParameterDeclarationExpression arg = new CodeParameterDeclarationExpression(argType, argName);

        if (isRef)
        {
            arg.Direction = FieldDirection.Ref;
        }
        return(arg);
    }
Пример #10
0
    public string GetArgNamesFile(Smoke *smoke)
    {
        string dest = Destination;

        if (string.IsNullOrEmpty(dest))
        {
            if (Environment.OSVersion.Platform == PlatformID.Win32NT)
            {
                dest = Path.GetDirectoryName(Path.GetDirectoryName(Environment.GetFolderPath(Environment.SpecialFolder.System)));
            }
            else
            {
                dest = Path.DirectorySeparatorChar.ToString(CultureInfo.InvariantCulture);
            }
        }
        dest = Path.Combine(dest, "share");
        dest = Path.Combine(dest, "smoke");
        return(Path.Combine(dest, ByteArrayManager.GetString(smoke->module_name) + ".argnames.txt"));
    }
Пример #11
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);
            }
        }
    }
Пример #12
0
 public GeneratorData(Smoke *smoke, string defaultNamespace, List <string> imports, List <Assembly> references,
                      string destination, string docs)
     : this(smoke, defaultNamespace, imports, references, new CodeCompileUnit(), destination, docs)
 {
 }
Пример #13
0
 private static extern bool GetProperties(Smoke *smoke, short classId, AddProperty addProp);
Пример #14
0
 private void PostMethodBodyHooks(Smoke *smoke, Smoke.Method *smokeMethod, CodeMemberMethod cmm, CodeTypeDeclaration type)
 {
     this.CommentMember(smoke, smokeMethod, cmm, type);
     GenerateEvent(cmm, cmm.Name, type, true);
 }
Пример #15
0
    // adapted from QtRuby's findAllMethods()
    public void FindAllMethods(short c, IDictionary <ModuleIndex, string> ret, bool searchSuperClasses)
    {
        Class *klass = classes + c;

        if (klass->external)
        {
            Smoke *smoke = (Smoke *)0;
            short  index = 0;
            if (!Util.GetModuleIndexFromClassName(klass->className, ref smoke, ref index))
            {
                Console.Error.WriteLine("  |--Failed resolving external class {0}", ByteArrayManager.GetString(klass->className));
                return;
            }
            smoke->FindAllMethods(index, ret, true);
            return;
        }

        Smoke *thisPtr;

        fixed(Smoke *smoke = &this)
        {
            thisPtr = smoke;             // hackish, but this is the cleanest way that I know to get the 'this' pointer
        }

        short imax = numMethodMaps;
        short imin = 0;
        short methmin = -1, methmax = -1;
        int   icmp = -1;

        while (imax >= imin)
        {
            short icur = (short)((imin + imax) / 2);
            icmp = methodMaps[icur].classId - c;
            if (icmp == 0)
            {
                short pos = icur;
                while (icur > 0 && methodMaps[icur - 1].classId == c)
                {
                    icur--;
                }
                methmin = icur;
                icur    = pos;
                while (icur < imax && methodMaps[icur + 1].classId == c)
                {
                    icur++;
                }
                methmax = icur;
                break;
            }
            if (icmp > 0)
            {
                imax = (short)(icur - 1);
            }
            else
            {
                imin = (short)(icur + 1);
            }
        }

        if (icmp != 0)
        {
            Console.Error.WriteLine("WARNING: FindAllMethods failed for class {0}",
                                    ByteArrayManager.GetString(classes[c].className));
            return;
        }

        for (short i = methmin; i <= methmax; i++)
        {
            string mungedName = ByteArrayManager.GetString(methodNames[methodMaps[i].name]);
            short  methId     = methodMaps[i].method;
            if (methId > 0)
            {
                ret[new ModuleIndex(thisPtr, methId)] = mungedName;
            }
            else
            {
                for (short *overload = ambiguousMethodList + (-methId); *overload > 0; overload++)
                {
                    ret[new ModuleIndex(thisPtr, *overload)] = mungedName;
                }
            }
        }
        if (searchSuperClasses)
        {
            for (short *parent = inheritanceList + classes[c].parents; *parent > 0; parent++)
            {
                FindAllMethods(*parent, ret, true);
            }
        }
    }
Пример #16
0
 static extern void GetSignals(Smoke *smoke, void *klass, AddSignal addSignalFn);
Пример #17
0
    public static unsafe int Main(string[] args)
    {
        string baseDirectory = AppDomain.CurrentDomain.BaseDirectory;
        string pluginDirectory;

        if (baseDirectory.EndsWith("bin"))
        {
            // Windows
            pluginDirectory = Path.GetFullPath(Path.Combine(baseDirectory, "..\\lib\\plugins"));
        }
        else
        {
            // *nix
            pluginDirectory = Path.Combine(baseDirectory, "plugins");
        }

        List <string>          codeFiles       = new List <string>();
        List <CodeCompileUnit> codeSnippets    = new List <CodeCompileUnit>();
        List <Assembly>        references      = new List <Assembly>();
        List <string>          imports         = new List <string>();
        StringBuilder          compilerOptions = new StringBuilder();
        bool   codeOnly         = false;
        string codeFile         = string.Empty;
        string assemblyFile     = "out.dll";
        int    warnLevel        = 0;
        string smokeLib         = null;
        string defaultNamespace = "Qyoto";
        string globalClass      = "Global";
        string destination      = string.Empty;
        string docs             = string.Empty;

        List <Assembly> plugins = new List <Assembly>();

        foreach (string arg in args)
        {
            if (arg == "-help" || arg == "--help" || arg == "-h")
            {
                PrintHelp();
                return(0);
            }
            if (arg == "-verbose")
            {
                Debug.Listeners.Add(new ConsoleTraceListener(true));
                continue;
            }
            if (arg == "-code-only")
            {
                codeOnly = true;
                continue;
            }
            if (arg.StartsWith("-code-file:"))
            {
                codeFile = arg.Substring(11);
                continue;
            }
            if (arg.StartsWith("-out:"))
            {
                assemblyFile = arg.Substring(5);
                continue;
            }
            if (arg.StartsWith("-warn:"))
            {
                warnLevel = int.Parse(arg.Substring(6));
                continue;
            }
            if (arg.StartsWith("-r:"))
            {
                references.Add(Assembly.LoadFrom(arg.Substring(3)));
                continue;
            }
            if (arg.StartsWith("-reference:"))
            {
                references.Add(Assembly.LoadFrom(arg.Substring(11)));
                continue;
            }
            if (arg.StartsWith("-global-class:"))
            {
                globalClass = arg.Substring(14);
                continue;
            }
            if (arg.StartsWith("-namespace:"))
            {
                defaultNamespace = arg.Substring(11);
                continue;
            }
            if (arg.StartsWith("-dest:"))
            {
                destination = arg.Substring("-dest:".Length);
                continue;
            }
            if (arg.StartsWith("-import:"))
            {
                imports.AddRange(arg.Substring(8).Split(','));
                continue;
            }
            if (arg.StartsWith("-docs:"))
            {
                docs = arg.Substring("-docs:".Length);
                continue;
            }
            if (arg.StartsWith("-plugins:"))
            {
                foreach (string str in arg.Substring(9).Split(','))
                {
                    Assembly a;
                    try
                    {
                        a = Assembly.LoadFrom(str);
                    }
                    catch (FileNotFoundException)
                    {
                        a = Assembly.LoadFrom(Path.Combine(pluginDirectory, str));
                    }
                    plugins.Add(a);
                }
                continue;
            }
            if (arg.StartsWith("-"))
            {
                compilerOptions.Append(" /");
                compilerOptions.Append(arg.Substring(1));
                continue;
            }

            if (smokeLib == null)
            {
                smokeLib = arg;
                continue;
            }

            codeFiles.Add(arg);
            FileStream   fs = new FileStream(arg, FileMode.Open);
            StreamReader sr = new StreamReader(fs);
            codeSnippets.Add(new CodeSnippetCompileUnit(sr.ReadToEnd()));
            sr.Close();
            fs.Close();
        }
        if (!string.IsNullOrEmpty(docs))
        {
            compilerOptions.Append(" /doc:" + Path.ChangeExtension(Path.GetFileName(assemblyFile), ".xml"));
        }

        compilerOptions.Append(" -debug");

        if (smokeLib == null)
        {
            PrintHelp();
            return(1);
        }

        Smoke *smoke = InitSmoke(smokeLib);

        if (smoke == (Smoke *)0)
        {
            return(SmokeLoadingFailure);
        }

        List <ICustomTranslator> customTranslators = (from plugin in plugins
                                                      from type in plugin.GetTypes()
                                                      from iface in type.GetInterfaces()
                                                      where iface == typeof(ICustomTranslator)
                                                      select(ICustomTranslator) Activator.CreateInstance(type)).ToList();

        GeneratorData data = new GeneratorData(smoke, defaultNamespace, imports, references, destination, docs);

        data.GlobalSpaceClassName = globalClass;
        Translator translator = new Translator(data, customTranslators);

        foreach (IHookProvider provider in from type in plugins.SelectMany(plugin => plugin.GetTypes())
                 where type.GetInterfaces().Any(iface => iface == typeof(IHookProvider))
                 select(IHookProvider) Activator.CreateInstance(type))
        {
            provider.Translator = translator;
            provider.Data       = data;
            provider.RegisterHooks();
        }

        ClassesGenerator classgen = new ClassesGenerator(data, translator);

        Console.Error.WriteLine("Generating CodeCompileUnit...");
        classgen.Run();
        DestroySmoke((IntPtr)smoke);

        Dictionary <string, string> providerOptions = new Dictionary <string, string>();

        providerOptions.Add("CompilerVersion", "v4.0");
        CodeDomProvider csharp = new CSharpCodeProvider(providerOptions);

        if (codeFile != string.Empty)
        {
            FileStream   fs = new FileStream(codeFile, FileMode.Create);
            StreamWriter sw = new StreamWriter(fs);

            Console.Error.WriteLine("Generating code...");
            CodeGeneratorOptions cgo = new CodeGeneratorOptions();
            csharp.GenerateCodeFromCompileUnit(data.CompileUnit, sw, cgo);
            sw.Close();
            fs.Close();
            codeFiles.Add(codeFile);
        }

        if (codeOnly)
        {
            if (codeFile == string.Empty)
            {
                Console.Error.WriteLine("Missing output filename. Use the -code-file:<file> option.");
                return(MissingOptionError);
            }
            return(NoError);
        }

        codeSnippets.Add(data.CompileUnit);

        Console.Error.WriteLine("Compiling assembly...");
        CompilerParameters cp = new CompilerParameters();

        cp.GenerateExecutable    = false;
        cp.TreatWarningsAsErrors = false;
        cp.OutputAssembly        = assemblyFile;
        cp.GenerateInMemory      = false;
        cp.WarningLevel          = warnLevel;
        cp.CompilerOptions       = compilerOptions.ToString();
        cp.ReferencedAssemblies.Add(typeof(Regex).Assembly.Location);
        cp.ReferencedAssemblies.Add(typeof(ExtensionAttribute).Assembly.Location);
        foreach (Assembly assembly in references)
        {
            cp.ReferencedAssemblies.Add(assembly.Location);
        }
        CompilerResults cr;

        if (codeFile == null)
        {
            cr = csharp.CompileAssemblyFromDom(cp, codeSnippets.ToArray());
        }
        else
        {
            cr = csharp.CompileAssemblyFromFile(cp, codeFiles.ToArray());
        }

        bool errorsOccured = false;

        foreach (CompilerError error in cr.Errors)
        {
            if (!error.IsWarning)
            {
                errorsOccured = true;
            }
            Console.Error.WriteLine(error);
        }

        if (errorsOccured)
        {
            Console.Error.WriteLine("Errors occured. No assembly was generated.");
            return(CompilationError);
        }
        Console.Error.WriteLine("Done.");
        return(NoError);
    }
Пример #18
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);
    }
Пример #19
0
 private static extern long GetEnumValue(Smoke *smoke, Smoke.Method *meth);
Пример #20
0
 public static unsafe bool IsClassAbstract(Smoke *smoke, short classId)
 {
     return(GetAbstractMethods(smoke, classId).Count > 0);
 }
Пример #21
0
 public CodeMemberMethod GenerateBasicMethodDefinition(Smoke *smoke, Smoke.Method *method)
 {
     return(GenerateBasicMethodDefinition(smoke, method, null));
 }
Пример #22
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);
    }
Пример #23
0
    public CodeMemberMethod GenerateBasicMethodDefinition(Smoke *smoke, Smoke.Method *method, CodeTypeReference iface)
    {
        string cppSignature = smoke->GetMethodSignature(method);

        return(GenerateBasicMethodDefinition(smoke, method, cppSignature, iface));
    }
Пример #24
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);
    }
Пример #25
0
    private string GetArgName(Smoke *smoke, short *typeIndex, IList <string> methodArgs, ref int count, bool isRef, CodeTypeReference argType)
    {
        if (methodArgs == null)
        {
            return("arg" + count++);
        }
        string arg     = methodArgs[count++ - 1];
        int    nameEnd = arg.IndexOf(' ');

        if (nameEnd > 0)
        {
            string defaultValue = arg.Substring(nameEnd + 3);
            arg = arg.Substring(0, nameEnd);
            if (isRef)
            {
                return(arg);
            }
            // HACK
            if (argType.BaseType.EndsWith("NativeLong") || argType.BaseType.EndsWith("NativeULong"))
            {
                return(arg);
            }
            arg = Provider.CreateEscapedIdentifier(arg);
            Smoke.TypeId typeId = (Smoke.TypeId)((smoke->types + *typeIndex)->flags & (ushort)Smoke.TypeFlags.tf_elem);
            switch (typeId)
            {
            case Smoke.TypeId.t_voidp:
            case Smoke.TypeId.t_class:
                switch (argType.BaseType)
                {
                case "System.Int64":
                    return(arg + " = 0");

                case "System.IntPtr":
                    return(arg + " = new IntPtr()");
                }
                if (argType.BaseType.Contains("QObjectWrapOption"))
                {
                    return(arg + " = 0");
                }
                switch (defaultValue)
                {
                case "0":
                    return(arg + " = null");

                case "QString()":
                    return(arg + " = \"\"");
                }
                break;

            case Smoke.TypeId.t_int:
                if (char.IsLetter(defaultValue[0]))
                {
                    int    indexOfColon = defaultValue.IndexOf("::", StringComparison.Ordinal);
                    string containingType;
                    string enumMember;
                    string additional;
                    if (indexOfColon > 0)
                    {
                        containingType = defaultValue.Substring(0, indexOfColon);
                        Match match = Regex.Match(defaultValue, @"::(\w+)(.*)");
                        enumMember = match.Groups[1].Value;
                        additional = match.Groups[2].Value;
                    }
                    else
                    {
                        containingType = this.type.Name;
                        enumMember     = defaultValue;
                        additional     = string.Empty;
                    }
                    string enumType = (from keyValue in this.data.EnumTypeMap
                                       where keyValue.Value.IsEnum && keyValue.Key.StartsWith(containingType + "::")
                                       from CodeTypeMember member in keyValue.Value.Members
                                       where member.Name == enumMember
                                       select keyValue.Value.Name).FirstOrDefault() ??
                                      (from referencedType in this.data.ReferencedTypeMap.Values
                                       where referencedType.IsEnum && referencedType.FullName.Contains("." + containingType + "+")
                                       from FieldInfo member in referencedType.GetFields(BindingFlags.Public | BindingFlags.Static)
                                       where member.Name == enumMember
                                       select referencedType.Name).FirstOrDefault();
                    if (string.IsNullOrEmpty(enumType))
                    {
                        var result = (from CodeTypeReference baseType in this.type.BaseTypes
                                      where this.data.CSharpTypeMap.ContainsKey(baseType.BaseType)
                                      let baseTypeDeclaration =
                                          this.data.CSharpTypeMap[baseType.BaseType]
                                          from CodeTypeDeclaration member in
                                          baseTypeDeclaration.Members.OfType <CodeTypeDeclaration>()
                                          where member.IsEnum
                                          from CodeTypeMember enumValue in member.Members
                                          where enumValue.Name == enumMember
                                          select new KeyValuePair <string, string>(baseType.BaseType, member.Name)).FirstOrDefault();
                        containingType = result.Key;
                        enumType       = result.Value;
                    }
                    return(arg + " = (int) " + GetEnumMembers(string.Format("{0}.{1}", containingType, enumType), enumMember) + additional);
                }
                goto default;

            case Smoke.TypeId.t_uint:
            case Smoke.TypeId.t_enum:
                if (defaultValue == "0" || defaultValue.EndsWith("()"))
                {
                    return(arg + " = 0");
                }
                if (char.IsLetter(defaultValue[0]))
                {
                    return(arg + " = " + GetEnumMembers(argType.BaseType, defaultValue));
                }
                goto default;

            case Smoke.TypeId.t_char:
                break;

            default:
                return(arg + " = " + defaultValue);
            }
        }
        return(arg);
    }
Пример #26
0
 public static extern unsafe bool GetModuleIndexFromClassName(byte *name, ref Smoke *smoke, ref short index);
Пример #27
0
 public CodeMemberMethod GenerateMethod(Smoke *smoke, short idx, string mungedName)
 {
     return(GenerateMethod(smoke, smoke->methods + idx, mungedName, null));
 }
Пример #28
0
 public ModuleIndex(Smoke *smoke, short index)
 {
     this.smoke = smoke;
     this.index = index;
 }
Пример #29
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);
    }