Example #1
0
 /// <summary>
 /// Merges the given enum into the enum list. If an enum of the same name exists,
 /// it merges their respective constants.
 /// </summary>
 /// <param name="enums"></param>
 /// <param name="t"></param>
 internal static void Merge(EnumCollection enums, Enum t)
 {
     if (!enums.ContainsKey(t.Name))
     {
         enums.Add(t.Name, t);
     }
     else
     {
         Enum e = enums[t.Name];
         foreach (Constant c in t.ConstantCollection.Values)
         {
             Merge(e, c);
         }
     }
 }
Example #2
0
 /// <summary>
 /// Merges the given enum into the enum list. If an enum of the same name exists,
 /// it merges their respective constants.
 /// </summary>
 /// <param name="enums"></param>
 /// <param name="t"></param>
 internal static void Merge(EnumCollection enums, Enum t)
 {
     if (!enums.ContainsKey(t.Name))
     {
         enums.Add(t.Name, t);
     }
     else
     {
         Enum e = enums[t.Name];
         foreach (Constant c in t.ConstantCollection.Values)
         {
             Merge(e, c);
         }
     }
 }
Example #3
0
 static bool IsEnum(string s, EnumCollection enums)
 {
     return enums.ContainsKey(s);
 }
Example #4
0
 static bool IsEnum(string s, EnumCollection enums)
 {
     return(enums.ContainsKey(s));
 }
Example #5
0
        private EnumCollection ReadEnums(XPathNavigator nav)
        {
            EnumCollection enums = new EnumCollection();
            Enum           all   = new Enum()
            {
                Name = Settings.CompleteEnumName
            };

            if (nav != null)
            {
                var reuse_list = new List <KeyValuePair <Enum, string> >();

                // First pass: collect all available tokens and enums
                foreach (XPathNavigator node in nav.SelectChildren("enum", String.Empty))
                {
                    Enum e = new Enum()
                    {
                        Name = node.GetAttribute("name", String.Empty).Trim(),
                        Type = node.GetAttribute("type", String.Empty).Trim()
                    };

                    e.Obsolete = node.GetAttribute("obsolete", String.Empty).Trim();

                    if (String.IsNullOrEmpty(e.Name))
                    {
                        throw new InvalidOperationException(String.Format("Empty name for enum element {0}", node.ToString()));
                    }

                    // It seems that all flag collections contain "Mask" in their names.
                    // This looks like a heuristic, but it holds 100% in practice
                    // (checked all enums to make sure).
                    e.IsFlagCollection = e.Name.ToLower().Contains("mask");

                    foreach (XPathNavigator param in node.SelectChildren(XPathNodeType.Element))
                    {
                        Constant c = null;
                        switch (param.Name)
                        {
                        case "token":
                            c = new Constant
                            {
                                Name  = param.GetAttribute("name", String.Empty).Trim(),
                                Value = param.GetAttribute("value", String.Empty).Trim()
                            };
                            break;

                        case "use":
                            c = new Constant
                            {
                                Name      = param.GetAttribute("token", String.Empty).Trim(),
                                Reference = param.GetAttribute("enum", String.Empty).Trim(),
                                Value     = param.GetAttribute("token", String.Empty).Trim(),
                            };
                            break;

                        case "reuse":
                            var reuse_enum = param.GetAttribute("enum", String.Empty).Trim();
                            reuse_list.Add(new KeyValuePair <Enum, string>(e, reuse_enum));
                            break;

                        default:
                            throw new NotSupportedException();
                        }

                        if (c != null)
                        {
                            Utilities.Merge(all, c);
                            try
                            {
                                if (!e.ConstantCollection.ContainsKey(c.Name))
                                {
                                    e.ConstantCollection.Add(c.Name, c);
                                }
                                else if (e.ConstantCollection[c.Name].Value != c.Value)
                                {
                                    var existing = e.ConstantCollection[c.Name];
                                    if (existing.Reference != null && c.Reference == null)
                                    {
                                        e.ConstantCollection[c.Name] = c;
                                    }
                                    else if (existing.Reference == null && c.Reference != null)
                                    {
                                        // Keep existing
                                    }
                                    else
                                    {
                                        Console.WriteLine("[Warning] Conflicting token {0}.{1} with value {2} != {3}",
                                                          e.Name, c.Name, e.ConstantCollection[c.Name].Value, c.Value);
                                    }
                                }
                            }
                            catch (ArgumentException ex)
                            {
                                Console.WriteLine("[Warning] Failed to add constant {0} to enum {1}: {2}", c.Name, e.Name, ex.Message);
                            }
                        }
                    }

                    Utilities.Merge(enums, e);
                }

                // Second pass: resolve "reuse" directives
restart:
                foreach (var pair in reuse_list)
                {
                    var e     = pair.Key;
                    var reuse = pair.Value;
                    var count = e.ConstantCollection.Count;

                    if (enums.ContainsKey(reuse))
                    {
                        var reuse_enum = enums[reuse];
                        foreach (var token in reuse_enum.ConstantCollection.Values)
                        {
                            Utilities.Merge(e, token);
                        }
                    }
                    else
                    {
                        Console.WriteLine("[Warning] Reuse token not found: {0}", reuse);
                    }

                    if (count != e.ConstantCollection.Count)
                    {
                        // Restart resolution of reuse directives whenever
                        // we modify an enum. This is the simplest (brute) way
                        // to resolve chains of reuse directives:
                        // e.g. enum A reuses B which reuses C
                        goto restart;
                    }
                }
            }

            Utilities.Merge(enums, all);
            return(enums);
        }
Example #6
0
        public virtual EnumCollection ReadEnums(StreamReader specFile)
        {
            Trace.WriteLine("Reading opengl enumerant specs.");
            Trace.Indent();

            EnumCollection enums = new EnumCollection();

            // complete_enum contains all opengl enumerants.
            Bind.Structures.Enum complete_enum = new Bind.Structures.Enum();
            complete_enum.Name = Settings.CompleteEnumName;

            do
            {
                string line = NextValidLine(specFile);
                if (String.IsNullOrEmpty(line))
                    break;

                line = line.Replace('\t', ' ');

                // We just encountered the start of a new enumerant:
                while (!String.IsNullOrEmpty(line) && line.Contains("enum"))
                {
                    string[] words = line.Split(Utilities.Separators, StringSplitOptions.RemoveEmptyEntries);
                    if (words.Length == 0)
                        continue;

                    // Declare a new enumerant
                    Bind.Structures.Enum e = new Bind.Structures.Enum();
                    e.Name = Char.IsDigit(words[0][0]) ? Settings.ConstantPrefix + words[0] : words[0];

                    // And fill in the values for this enumerant
                    do
                    {
                        line = NextValidLine(specFile);

                        if (String.IsNullOrEmpty(line) || line.StartsWith("#"))
                            continue;

                        if (line.Contains("enum:") || specFile.EndOfStream)
                            break;

                        line = line.Replace('\t', ' ');
                        words = line.Split(Utilities.Separators, StringSplitOptions.RemoveEmptyEntries);

                        if (words.Length == 0)
                            continue;

                        // If we reach this point, we have found a new value for the current enumerant
                        Constant c = new Constant();
                        if (line.Contains("="))
                        {
                            // Trim the name's prefix, but only if not in Tao compat mode.
                            if (Settings.Compatibility == Settings.Legacy.Tao)
                            {
                            }
                            else
                            {
                                if (words[0].StartsWith(Settings.ConstantPrefix))
                                    words[0] = words[0].Substring(Settings.ConstantPrefix.Length);

                                if (Char.IsDigit(words[0][0]))
                                    words[0] = Settings.ConstantPrefix + words[0];
                            }

                            c.Name = words[0];

                            uint number;
                            if (UInt32.TryParse(words[2].Replace("0x", String.Empty), System.Globalization.NumberStyles.AllowHexSpecifier, null, out number))
                            {
                                // The value is a number, check if it should be unchecked.
                                if (number > 0x7FFFFFFF)
                                {
                                    c.Unchecked = true;
                                }
                            }
                            else
                            {
                                // The value is not a number. Strip the prefix.
                                if (words[2].StartsWith(Settings.ConstantPrefix))
                                    words[2] = words[2].Substring(Settings.ConstantPrefix.Length);

                                // If the name now starts with a digit (doesn't matter whether we
                                // stripped "GL_" above), add a "GL_" prefix.
                                // (e.g. GL_4_BYTES).
                                if (Char.IsDigit(words[2][0]))
                                    words[2] = Settings.ConstantPrefix + words[2];
                            }

                            c.Value = words[2];
                        }
                        else if (words[0] == "use")
                        {
                            // Trim the prefix.
                            if (words[2].StartsWith(Settings.ConstantPrefix))
                                words[2] = words[2].Substring(Settings.ConstantPrefix.Length);

                            // If the remaining string starts with a digit, we were wrong above.
                            // Re-add the "GL_"
                            if (Char.IsDigit(words[2][0]))
                                words[2] = Settings.ConstantPrefix + words[2];

                            c.Name = words[2];
                            c.Reference = words[1];
                            c.Value = words[2];
                        }

                        //if (!String.IsNullOrEmpty(c.Name) && !e.Members.Contains.Contains(c))
                        //SpecTranslator.Merge(e.Members, c);
                        if (!e.ConstantCollection.ContainsKey(c.Name))
                            e.ConstantCollection.Add(c.Name, c);
                        else
                            Trace.WriteLine(String.Format(
                                "Spec error: Constant {0} defined twice in enum {1}, discarding last definition.",
                                c.Name, e.Name));

                        // Insert the current constant in the list of all constants.
                        //SpecTranslator.Merge(complete_enum.Members, c);
                        complete_enum = Utilities.Merge(complete_enum, c);
                    }
                    while (!specFile.EndOfStream);

                    // At this point, the complete value list for the current enumerant has been read, so add this
                    // enumerant to the list.
                    //e.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "public enum " + e.Name));
                    //e.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, "public enum " + e.Name));

                    // (disabled) Hack - discard Boolean enum, it fsucks up the fragile translation code ahead.
                    //if (!e.Name.Contains("Bool"))
                    //Utilities.Merge(enums, e);

                    //e.Translate();

                    if (!enums.ContainsKey(e.Name))
                    {
                        enums.Add(e.Name, e);
                    }
                    else
                    {
                        // The enum already exists, merge constants.
                        Trace.WriteLine(String.Format("Conflict: Enum {0} already exists, merging constants.", e.Name));
                        foreach (Constant t in e.ConstantCollection.Values)
                        {
                            Utilities.Merge(enums[e.Name], t);
                        }
                    }

                    //enums.Add(e);
                }
                //SpecTranslator.Merge(enums, complete_enum);
            }
            while (!specFile.EndOfStream);

            enums.Add(complete_enum.Name, complete_enum);

            Trace.Unindent();

            return enums;
        }
Example #7
0
        public virtual EnumCollection ReadEnums(StreamReader specFile)
        {
            Trace.WriteLine("Reading opengl enumerant specs.");
            Trace.Indent();

            EnumCollection enums = new EnumCollection();

            // complete_enum contains all opengl enumerants.
            Enum complete_enum = new Enum();
            complete_enum.Name = Settings.CompleteEnumName;

            do
            {
                string line = NextValidLine(specFile);
                if (String.IsNullOrEmpty(line))
                    break;

                line = line.Replace('\t', ' ');

                // We just encountered the start of a new enumerant:
                while (!String.IsNullOrEmpty(line) && line.Contains("enum"))
                {
                    string[] words = line.Split(Utilities.Separators, StringSplitOptions.RemoveEmptyEntries);
                    if (words.Length == 0)
                        continue;

                    // Declare a new enumerant
                    Enum e = new Enum();
                    e.Name = Char.IsDigit(words[0][0]) ? Settings.ConstantPrefix + words[0] : words[0];

                    // And fill in the values for this enumerant
                    do
                    {
                        line = NextValidLine(specFile);

                        if (String.IsNullOrEmpty(line) || line.StartsWith("#"))
                            continue;

                        if (line.Contains("enum:") || specFile.EndOfStream)
                            break;

                        line = line.Replace('\t', ' ');
                        words = line.Split(Utilities.Separators, StringSplitOptions.RemoveEmptyEntries);

                        if (words.Length == 0)
                            continue;

                        // If we reach this point, we have found a new value for the current enumerant
                        Constant c = new Constant();
                        if (line.Contains("="))
                        {
                            // Trim the name's prefix, but only if not in Tao compat mode.
                            if (Settings.Compatibility == Settings.Legacy.Tao)
                            {
                            }
                            else
                            {
                                if (words[0].StartsWith(Settings.ConstantPrefix))
                                    words[0] = words[0].Substring(Settings.ConstantPrefix.Length);

                                if (Char.IsDigit(words[0][0]))
                                    words[0] = Settings.ConstantPrefix + words[0];
                            }

                            c.Name = words[0];
                            c.Value = words[2];
                        }
                        else if (words[0] == "use")
                        {
                            // Trim the prefix.
                            if (words[2].StartsWith(Settings.ConstantPrefix))
                                words[2] = words[2].Substring(Settings.ConstantPrefix.Length);

                            // If the remaining string starts with a digit, we were wrong above.
                            // Re-add the "GL_"
                            if (Char.IsDigit(words[2][0]))
                                words[2] = Settings.ConstantPrefix + words[2];

                            c.Name = words[2];
                            c.Reference = words[1];
                            c.Value = words[2];
                        }
                        else
                        {
                            // Typical cause is hand-editing the specs and forgetting to add an '=' sign.
                            throw new InvalidOperationException(String.Format(
                                "[Error] Invalid constant definition: \"{0}\"", line));
                        }

                        //if (!String.IsNullOrEmpty(c.Name) && !e.Members.Contains.Contains(c))
                        //SpecTranslator.Merge(e.Members, c);
                        if (!e.ConstantCollection.ContainsKey(c.Name))
                            e.ConstantCollection.Add(c.Name, c);
                        else
                            Trace.WriteLine(String.Format(
                                "Spec error: Constant {0} defined twice in enum {1}, discarding last definition.",
                                c.Name, e.Name));

                        // Insert the current constant in the list of all constants.
                        //SpecTranslator.Merge(complete_enum.Members, c);
                        complete_enum = Utilities.Merge(complete_enum, c);
                    }
                    while (!specFile.EndOfStream);

                    // At this point, the complete value list for the current enumerant has been read, so add this
                    // enumerant to the list.
                    //e.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "public enum " + e.Name));
                    //e.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, "public enum " + e.Name));

                    // (disabled) Hack - discard Boolean enum, it fsucks up the fragile translation code ahead.
                    //if (!e.Name.Contains("Bool"))
                    //Utilities.Merge(enums, e);

                    //e.Translate();

                    if (!enums.ContainsKey(e.Name))
                        enums.Add(e.Name, e);
                    else
                    {
                        // The enum already exists, merge constants.
                        foreach (Constant t in e.ConstantCollection.Values)
                            Utilities.Merge(enums[e.Name], t);
                    }
                }
            }
            while (!specFile.EndOfStream);

            enums.Add(complete_enum.Name, complete_enum);

            Trace.Unindent();

            return enums;
        }
Example #8
0
        public virtual EnumCollection ReadEnums(StreamReader specFile)
        {
            Trace.WriteLine("Reading opengl enumerant specs.");
            Trace.Indent();

            EnumCollection enums = new EnumCollection();

            // complete_enum contains all opengl enumerants.
            Enum complete_enum = new Enum();

            complete_enum.Name = Settings.CompleteEnumName;

            do
            {
                string line = NextValidLine(specFile);
                if (String.IsNullOrEmpty(line))
                {
                    break;
                }

                line = line.Replace('\t', ' ');

                // We just encountered the start of a new enumerant:
                while (!String.IsNullOrEmpty(line) && line.Contains("enum"))
                {
                    string[] words = line.Split(Utilities.Separators, StringSplitOptions.RemoveEmptyEntries);
                    if (words.Length == 0)
                    {
                        continue;
                    }

                    // Declare a new enumerant
                    Enum e = new Enum();
                    e.Name = Char.IsDigit(words[0][0]) ? Settings.ConstantPrefix + words[0] : words[0];

                    // And fill in the values for this enumerant
                    do
                    {
                        line = NextValidLine(specFile);

                        if (String.IsNullOrEmpty(line) || line.StartsWith("#"))
                        {
                            continue;
                        }

                        if (line.Contains("enum:") || specFile.EndOfStream)
                        {
                            break;
                        }

                        line  = line.Replace('\t', ' ');
                        words = line.Split(Utilities.Separators, StringSplitOptions.RemoveEmptyEntries);

                        if (words.Length == 0)
                        {
                            continue;
                        }

                        // If we reach this point, we have found a new value for the current enumerant
                        Constant c = new Constant();
                        if (line.Contains("="))
                        {
                            // Trim the name's prefix, but only if not in Tao compat mode.
                            if (Settings.Compatibility == Settings.Legacy.Tao)
                            {
                            }
                            else
                            {
                                if (words[0].StartsWith(Settings.ConstantPrefix))
                                {
                                    words[0] = words[0].Substring(Settings.ConstantPrefix.Length);
                                }

                                if (Char.IsDigit(words[0][0]))
                                {
                                    words[0] = Settings.ConstantPrefix + words[0];
                                }
                            }

                            c.Name  = words[0];
                            c.Value = words[2];
                        }
                        else if (words[0] == "use")
                        {
                            // Trim the prefix.
                            if (words[2].StartsWith(Settings.ConstantPrefix))
                            {
                                words[2] = words[2].Substring(Settings.ConstantPrefix.Length);
                            }

                            // If the remaining string starts with a digit, we were wrong above.
                            // Re-add the "GL_"
                            if (Char.IsDigit(words[2][0]))
                            {
                                words[2] = Settings.ConstantPrefix + words[2];
                            }

                            c.Name      = words[2];
                            c.Reference = words[1];
                            c.Value     = words[2];
                        }
                        else
                        {
                            // Typical cause is hand-editing the specs and forgetting to add an '=' sign.
                            throw new InvalidOperationException(String.Format(
                                                                    "[Error] Invalid constant definition: \"{0}\"", line));
                        }

                        //if (!String.IsNullOrEmpty(c.Name) && !e.Members.Contains.Contains(c))
                        //SpecTranslator.Merge(e.Members, c);
                        if (!e.ConstantCollection.ContainsKey(c.Name))
                        {
                            e.ConstantCollection.Add(c.Name, c);
                        }
                        else
                        {
                            Trace.WriteLine(String.Format(
                                                "Spec error: Constant {0} defined twice in enum {1}, discarding last definition.",
                                                c.Name, e.Name));
                        }

                        // Insert the current constant in the list of all constants.
                        //SpecTranslator.Merge(complete_enum.Members, c);
                        complete_enum = Utilities.Merge(complete_enum, c);
                    }while (!specFile.EndOfStream);

                    // At this point, the complete value list for the current enumerant has been read, so add this
                    // enumerant to the list.
                    //e.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "public enum " + e.Name));
                    //e.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, "public enum " + e.Name));

                    // (disabled) Hack - discard Boolean enum, it breaks up the fragile translation code ahead.
                    //if (!e.Name.Contains("Bool"))
                    //Utilities.Merge(enums, e);

                    //e.Translate();

                    if (!enums.ContainsKey(e.Name))
                    {
                        enums.Add(e.Name, e);
                    }
                    else
                    {
                        // The enum already exists, merge constants.
                        foreach (Constant t in e.ConstantCollection.Values)
                        {
                            Utilities.Merge(enums[e.Name], t);
                        }
                    }
                }
            }while (!specFile.EndOfStream);

            enums.Add(complete_enum.Name, complete_enum);

            Trace.Unindent();

            return(enums);
        }
        void TranslateType(Bind.Structures.Type type,
            XPathNavigator function_override, XPathNavigator overrides,
            EnumProcessor enum_processor, EnumCollection enums,
            string category, string apiname)
        {
            Bind.Structures.Enum @enum;
            string s;

            category = enum_processor.TranslateEnumName(category);

            // Try to find out if it is an enum. If the type exists in the normal GLEnums list, use this.
            // Special case for Boolean which is there simply because C89 does not support bool types.
            // We don't really need that in C#
            bool normal =
                enums.TryGetValue(type.CurrentType, out @enum) ||
                enums.TryGetValue(enum_processor.TranslateEnumName(type.CurrentType), out @enum);

            // Translate enum types
            type.IsEnum = false;
            if (normal && @enum.Name != "GLenum" && @enum.Name != "Boolean")
            {
                type.IsEnum = true;

                if ((Settings.Compatibility & Settings.Legacy.ConstIntEnums) != Settings.Legacy.None)
                {
                    type.QualifiedType = "int";
                }
                else
                {
                    // Some functions and enums have the same names.
                    // Make sure we reference the enums rather than the functions.
                    if (normal)
                    {
                        type.QualifiedType = String.Format("{0}.{1}", Settings.EnumsOutput, @enum.Name);
                    }
                }
            }
            else if (Generator.GLTypes.TryGetValue(type.CurrentType, out s))
            {
                // Check if the parameter is a generic GLenum. If it is, search for a better match,
                // otherwise fallback to Settings.CompleteEnumName (named 'All' by default).
                if (s.Contains("GLenum") /*&& !String.IsNullOrEmpty(category)*/)
                {
                    type.IsEnum = true;

                    if ((Settings.Compatibility & Settings.Legacy.ConstIntEnums) != Settings.Legacy.None)
                    {
                        type.QualifiedType = "int";
                    }
                    else
                    {
                        // Better match: enum.Name == function.Category (e.g. GL_VERSION_1_1 etc)
                        // Note: for backwards compatibility we use "category" only for the gl api.
                        // glcore, gles1 and gles2 use the All enum instead.
                        if (apiname == "gl" && enums.ContainsKey(category))
                        {
                            type.QualifiedType = String.Format("{0}{1}{2}", Settings.EnumsOutput,
                                Settings.NamespaceSeparator, enum_processor.TranslateEnumName(category));
                        }
                        else
                        {
                            type.QualifiedType = String.Format("{0}{1}{2}", Settings.EnumsOutput,
                                Settings.NamespaceSeparator, Settings.CompleteEnumName);
                        }
                    }
                }
                else
                {
                    // Todo: what is the point of this here? It is overwritten below.
                    // A few translations for consistency
                    switch (type.CurrentType.ToLower())
                    {
                        case "string":
                            type.QualifiedType = "String";
                            break;
                    }

                    type.QualifiedType = s;
                }
            }

            type.CurrentType =
                Generator.CSTypes.ContainsKey(type.CurrentType) ?
                Generator.CSTypes[type.CurrentType] : type.CurrentType;

            // Make sure that enum parameters follow enum overrides, i.e.
            // if enum ErrorCodes is overriden to ErrorCode, then parameters
            // of type ErrorCodes should also be overriden to ErrorCode.
            XPathNavigator enum_override = overrides.SelectSingleNode(
                EnumProcessor.GetOverridesPath(apiname, type.CurrentType));
            if (enum_override != null)
            {
                // For consistency - many overrides use string instead of String.
                if (enum_override.Value == "string")
                    type.QualifiedType = "String";
                else if (enum_override.Value == "StringBuilder")
                    type.QualifiedType = "StringBuilder";
                else
                    type.CurrentType = enum_override.Value;
            }

            if (type.CurrentType == "IntPtr" && String.IsNullOrEmpty(type.PreviousType))
                type.Pointer = 0;

            if (type.Pointer >= 3)
            {
                System.Diagnostics.Trace.WriteLine(String.Format(
                    "[Error] Type '{0}' has a high pointer level. Bindings will be incorrect.",
                    type));
            }

            if (!type.IsEnum)
            {
                // Remove qualifier if type is not an enum
                // Resolves issues when replacing / overriding
                // an enum parameter with a non-enum type
                type.QualifiedType = type.CurrentType;
            }
        }
Example #10
0
        EnumCollection ReadEnums(XPathNavigator nav)
        {
            EnumCollection enums = new EnumCollection();
            Enum all = new Enum() { Name = Settings.CompleteEnumName };

            if (nav != null)
            {
                var reuse_list = new List<KeyValuePair<Enum, string>>();

                // First pass: collect all available tokens and enums
                foreach (XPathNavigator node in nav.SelectChildren("enum", String.Empty))
                {
                    Enum e = new Enum()
                    {
                        Name = node.GetAttribute("name", String.Empty).Trim(),
                        Type = node.GetAttribute("type", String.Empty).Trim()
                    };

                    if (String.IsNullOrEmpty(e.Name))
                        throw new InvalidOperationException(String.Format("Empty name for enum element {0}", node.ToString()));

                    // It seems that all flag collections contain "Mask" in their names.
                    // This looks like a heuristic, but it holds 100% in practice
                    // (checked all enums to make sure).
                    e.IsFlagCollection = e.Name.ToLower().Contains("mask");

                    foreach (XPathNavigator param in node.SelectChildren(XPathNodeType.Element))
                    {
                        Constant c = null;
                        switch (param.Name)
                        {
                            case "token":
                                c = new Constant
                                {
                                    Name = param.GetAttribute("name", String.Empty).Trim(),
                                    Value = param.GetAttribute("value", String.Empty).Trim()
                                };
                                break;

                            case "use":
                                c = new Constant
                                {
                                    Name = param.GetAttribute("token", String.Empty).Trim(),
                                    Reference = param.GetAttribute("enum", String.Empty).Trim(),
                                    Value = param.GetAttribute("token", String.Empty).Trim(),
                                };
                                break;

                            case "reuse":
                                var reuse_enum = param.GetAttribute("enum", String.Empty).Trim();
                                reuse_list.Add(new KeyValuePair<Enum, string>(e, reuse_enum));
                                break;

                            default:
                                throw new NotSupportedException();
                        }

                        if (c != null)
                        {
                            Utilities.Merge(all, c);
                            try
                            {
                                if (!e.ConstantCollection.ContainsKey(c.Name))
                                {
                                    e.ConstantCollection.Add(c.Name, c);
                                }
                                else if (e.ConstantCollection[c.Name].Value != c.Value)
                                {
                                    var existing = e.ConstantCollection[c.Name];
                                    if (existing.Reference != null && c.Reference == null)
                                    {
                                        e.ConstantCollection[c.Name] = c;
                                    }
                                    else if (existing.Reference == null && c.Reference != null)
                                    {
                                        // Keep existing
                                    }
                                    else
                                    {
                                        Console.WriteLine("[Warning] Conflicting token {0}.{1} with value {2} != {3}",
                                            e.Name, c.Name, e.ConstantCollection[c.Name].Value, c.Value);
                                    }
                                }
                            }
                            catch (ArgumentException ex)
                            {
                                Console.WriteLine("[Warning] Failed to add constant {0} to enum {1}: {2}", c.Name, e.Name, ex.Message);
                            }
                        }
                    }

                    Utilities.Merge(enums, e);
                }

                // Second pass: resolve "reuse" directives
restart:
                foreach (var pair in reuse_list)
                {
                    var e = pair.Key;
                    var reuse = pair.Value;
                    var count = e.ConstantCollection.Count;

                    if (enums.ContainsKey(reuse))
                    {
                        var reuse_enum = enums[reuse];
                        foreach (var token in reuse_enum.ConstantCollection.Values)
                        {
                            Utilities.Merge(e, token);
                        }
                    }
                    else
                    {
                        Console.WriteLine("[Warning] Reuse token not found: {0}", reuse);
                    }

                    if (count != e.ConstantCollection.Count)
                    {
                        // Restart resolution of reuse directives whenever
                        // we modify an enum. This is the simplest (brute) way
                        // to resolve chains of reuse directives:
                        // e.g. enum A reuses B which reuses C
                        goto restart;
                    }
                }
            }

            Utilities.Merge(enums, all);
            return enums;
        }
Example #11
0
        /// <summary>
        /// Replces the Value of the given constant with the value referenced by the [c.Reference, c.Value] pair.
        /// </summary>
        /// <param name="c">The Constant to translate</param>
        /// <param name="enums">The list of enums to check.</param>
        /// <param name="auxEnums">The list of auxilliary enums to check.</param>
        /// <returns>True if the reference was found; false otherwise.</returns>
        public static bool TranslateConstantWithReference(Constant c, EnumCollection enums, EnumCollection auxEnums)
        {
            if (!String.IsNullOrEmpty(c.Reference))
            {
                Constant referenced_constant;

                if (enums.ContainsKey(c.Reference) && enums[c.Reference].ConstantCollection.ContainsKey(c.Value))
                {
                    TranslateConstantWithReference(enums[c.Reference].ConstantCollection[c.Value] as Constant, enums, auxEnums);
                    referenced_constant = (enums[c.Reference].ConstantCollection[c.Value] as Constant);
                }
                else if (auxEnums.ContainsKey(c.Reference) && auxEnums[c.Reference].ConstantCollection.ContainsKey(c.Value))
                {
                    TranslateConstantWithReference(auxEnums[c.Reference].ConstantCollection[c.Value] as Constant, enums, auxEnums);
                    referenced_constant = (auxEnums[c.Reference].ConstantCollection[c.Value] as Constant);
                }
                else
                {
                    Console.WriteLine("[Warning] Reference {0} not found for token {1}.", c.Reference, c);
                    return false;
                }
                //else throw new InvalidOperationException(String.Format("Unknown Enum \"{0}\" referenced by Constant \"{1}\"",
                //                                                       c.Reference, c.ToString()));

                c.Value = referenced_constant.Value;
                c.Reference = null;
                c.Unchecked = referenced_constant.Unchecked;
            }

            return true;
        }
Example #12
0
        void TranslateType(Bind.Structures.Type type,
                           XPathNavigator function_override, XPathNavigator overrides,
                           EnumProcessor enum_processor, EnumCollection enums,
                           string category, string apiname)
        {
            Bind.Structures.Enum @enum;
            string s;

            category = enum_processor.TranslateEnumName(category);

            // Try to find out if it is an enum. If the type exists in the normal GLEnums list, use this.
            // Special case for Boolean - it is an enum, but it is dumb to use that instead of the 'bool' type.
            bool normal = enums.TryGetValue(type.CurrentType, out @enum);

            // Translate enum types
            type.IsEnum = false;
            if (normal && @enum.Name != "GLenum" && @enum.Name != "Boolean")
            {
                type.IsEnum = true;

                if ((Settings.Compatibility & Settings.Legacy.ConstIntEnums) != Settings.Legacy.None)
                {
                    type.QualifiedType = "int";
                }
                else
                {
                    // Some functions and enums have the same names.
                    // Make sure we reference the enums rather than the functions.
                    if (normal)
                    {
                        type.QualifiedType = type.CurrentType.Insert(0, String.Format("{0}.", Settings.EnumsOutput));
                    }
                }
            }
            else if (Generator.GLTypes.TryGetValue(type.CurrentType, out s))
            {
                // Check if the parameter is a generic GLenum. If it is, search for a better match,
                // otherwise fallback to Settings.CompleteEnumName (named 'All' by default).
                if (s.Contains("GLenum") /*&& !String.IsNullOrEmpty(category)*/)
                {
                    type.IsEnum = true;

                    if ((Settings.Compatibility & Settings.Legacy.ConstIntEnums) != Settings.Legacy.None)
                    {
                        type.QualifiedType = "int";
                    }
                    else
                    {
                        // Better match: enum.Name == function.Category (e.g. GL_VERSION_1_1 etc)
                        // Note: for backwards compatibility we use "category" only for the gl api.
                        // glcore, gles1 and gles2 use the All enum instead.
                        if (apiname == "gl" && enums.ContainsKey(category))
                        {
                            type.QualifiedType = String.Format("{0}{1}{2}", Settings.EnumsOutput,
                                                               Settings.NamespaceSeparator, enum_processor.TranslateEnumName(category));
                        }
                        else
                        {
                            type.QualifiedType = String.Format("{0}{1}{2}", Settings.EnumsOutput,
                                                               Settings.NamespaceSeparator, Settings.CompleteEnumName);
                        }
                    }
                }
                else
                {
                    // Todo: what is the point of this here? It is overwritten below.
                    // A few translations for consistency
                    switch (type.CurrentType.ToLower())
                    {
                    case "string":
                        type.QualifiedType = "String";
                        break;
                    }

                    type.QualifiedType = s;
                }
            }

            type.CurrentType =
                Generator.CSTypes.ContainsKey(type.CurrentType) ?
                Generator.CSTypes[type.CurrentType] : type.CurrentType;

            // Make sure that enum parameters follow enum overrides, i.e.
            // if enum ErrorCodes is overriden to ErrorCode, then parameters
            // of type ErrorCodes should also be overriden to ErrorCode.
            XPathNavigator enum_override = overrides.SelectSingleNode(
                EnumProcessor.GetOverridesPath(apiname, type.CurrentType));

            if (enum_override != null)
            {
                // For consistency - many overrides use string instead of String.
                if (enum_override.Value == "string")
                {
                    type.QualifiedType = "String";
                }
                else if (enum_override.Value == "StringBuilder")
                {
                    type.QualifiedType = "StringBuilder";
                }
                else
                {
                    type.CurrentType = enum_override.Value;
                }
            }

            if (type.CurrentType == "IntPtr" && String.IsNullOrEmpty(type.PreviousType))
            {
                type.Pointer = 0;
            }

            if (type.Pointer >= 3)
            {
                System.Diagnostics.Trace.WriteLine(String.Format(
                                                       "[Error] Type '{0}' has a high pointer level. Bindings will be incorrect.",
                                                       type));
            }

            if (!type.IsEnum)
            {
                // Remove qualifier if type is not an enum
                // Resolves issues when replacing / overriding
                // an enum parameter with a non-enum type
                type.QualifiedType = type.CurrentType;
            }
        }
Example #13
0
        public virtual EnumCollection ReadEnums(StreamReader specFile)
        {
            Trace.WriteLine("Reading opengl enumerant specs.");
            Trace.Indent();

            EnumCollection enums = new EnumCollection();

            // complete_enum contains all opengl enumerants.
            Bind.Structures.Enum complete_enum = new Bind.Structures.Enum();
            complete_enum.Name = Settings.CompleteEnumName;

            do
            {
                string line = NextValidLine(specFile);
                if (String.IsNullOrEmpty(line))
                {
                    break;
                }

                line = line.Replace('\t', ' ');

                // We just encountered the start of a new enumerant:
                while (!String.IsNullOrEmpty(line) && line.Contains("enum"))
                {
                    string[] words = line.Split(Utilities.Separators, StringSplitOptions.RemoveEmptyEntries);
                    if (words.Length == 0)
                    {
                        continue;
                    }

                    // Declare a new enumerant
                    Bind.Structures.Enum e = new Bind.Structures.Enum();
                    e.Name = Char.IsDigit(words[0][0]) ? Settings.ConstantPrefix + words[0] : words[0];

                    // And fill in the values for this enumerant
                    do
                    {
                        line = NextValidLine(specFile);

                        if (String.IsNullOrEmpty(line) || line.StartsWith("#"))
                        {
                            continue;
                        }

                        if (line.Contains("enum:") || specFile.EndOfStream)
                        {
                            break;
                        }

                        line  = line.Replace('\t', ' ');
                        words = line.Split(Utilities.Separators, StringSplitOptions.RemoveEmptyEntries);

                        if (words.Length == 0)
                        {
                            continue;
                        }

                        // If we reach this point, we have found a new value for the current enumerant
                        Constant c = new Constant();
                        if (line.Contains("="))
                        {
                            // Trim the name's prefix, but only if not in Tao compat mode.
                            if (Settings.Compatibility == Settings.Legacy.Tao)
                            {
                            }
                            else
                            {
                                if (words[0].StartsWith(Settings.ConstantPrefix))
                                {
                                    words[0] = words[0].Substring(Settings.ConstantPrefix.Length);
                                }

                                if (Char.IsDigit(words[0][0]))
                                {
                                    words[0] = Settings.ConstantPrefix + words[0];
                                }
                            }

                            c.Name = words[0];

                            uint number;
                            if (UInt32.TryParse(words[2].Replace("0x", String.Empty), System.Globalization.NumberStyles.AllowHexSpecifier, null, out number))
                            {
                                // The value is a number, check if it should be unchecked.
                                if (number > 0x7FFFFFFF)
                                {
                                    c.Unchecked = true;
                                }
                            }
                            else
                            {
                                // The value is not a number. Strip the prefix.
                                if (words[2].StartsWith(Settings.ConstantPrefix))
                                {
                                    words[2] = words[2].Substring(Settings.ConstantPrefix.Length);
                                }

                                // If the name now starts with a digit (doesn't matter whether we
                                // stripped "GL_" above), add a "GL_" prefix.
                                // (e.g. GL_4_BYTES).
                                if (Char.IsDigit(words[2][0]))
                                {
                                    words[2] = Settings.ConstantPrefix + words[2];
                                }
                            }

                            c.Value = words[2];
                        }
                        else if (words[0] == "use")
                        {
                            // Trim the prefix.
                            if (words[2].StartsWith(Settings.ConstantPrefix))
                            {
                                words[2] = words[2].Substring(Settings.ConstantPrefix.Length);
                            }

                            // If the remaining string starts with a digit, we were wrong above.
                            // Re-add the "GL_"
                            if (Char.IsDigit(words[2][0]))
                            {
                                words[2] = Settings.ConstantPrefix + words[2];
                            }

                            c.Name      = words[2];
                            c.Reference = words[1];
                            c.Value     = words[2];
                        }

                        //if (!String.IsNullOrEmpty(c.Name) && !e.Members.Contains.Contains(c))
                        //SpecTranslator.Merge(e.Members, c);
                        if (!e.ConstantCollection.ContainsKey(c.Name))
                        {
                            e.ConstantCollection.Add(c.Name, c);
                        }
                        else
                        {
                            Trace.WriteLine(String.Format(
                                                "Spec error: Constant {0} defined twice in enum {1}, discarding last definition.",
                                                c.Name, e.Name));
                        }

                        // Insert the current constant in the list of all constants.
                        //SpecTranslator.Merge(complete_enum.Members, c);
                        complete_enum = Utilities.Merge(complete_enum, c);
                    }while (!specFile.EndOfStream);

                    // At this point, the complete value list for the current enumerant has been read, so add this
                    // enumerant to the list.
                    //e.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "public enum " + e.Name));
                    //e.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, "public enum " + e.Name));

                    // (disabled) Hack - discard Boolean enum, it fsucks up the fragile translation code ahead.
                    //if (!e.Name.Contains("Bool"))
                    //Utilities.Merge(enums, e);

                    //e.Translate();

                    if (!enums.ContainsKey(e.Name))
                    {
                        enums.Add(e.Name, e);
                    }
                    else
                    {
                        // The enum already exists, merge constants.
                        Trace.WriteLine(String.Format("Conflict: Enum {0} already exists, merging constants.", e.Name));
                        foreach (Constant t in e.ConstantCollection.Values)
                        {
                            Utilities.Merge(enums[e.Name], t);
                        }
                    }

                    //enums.Add(e);
                }
                //SpecTranslator.Merge(enums, complete_enum);
            }while (!specFile.EndOfStream);

            enums.Add(complete_enum.Name, complete_enum);

            Trace.Unindent();

            return(enums);
        }
Example #14
0
        /// <summary>
        /// Replces the Value of the given constant with the value referenced by the [c.Reference, c.Value] pair.
        /// </summary>
        /// <param name="c">The Constant to translate</param>
        /// <param name="enums">The list of enums to check.</param>
        /// <param name="auxEnums">The list of auxilliary enums to check.</param>
        /// <returns>True if the reference was found; false otherwise.</returns>
        public static bool TranslateConstantWithReference(Constant c, EnumCollection enums, EnumCollection auxEnums)
        {
            if (c == null)
                throw new ArgumentNullException("c");
            if (enums == null)
                throw new ArgumentNullException("enums");

            if (++CurrentReferenceDepth >= MaxReferenceDepth)
                throw new InvalidOperationException("Enum specification contains cycle");

            if (!String.IsNullOrEmpty(c.Reference))
            {
                Constant referenced_constant;

                if (enums.ContainsKey(c.Reference) && enums[c.Reference].ConstantCollection.ContainsKey(c.Value))
                {
                    // Transitively translate the referenced token
                    // Todo: this may cause loops if two tokens reference each other.
                    // Add a max reference depth and bail out?
                    TranslateConstantWithReference(enums[c.Reference].ConstantCollection[c.Value], enums, auxEnums);
                    referenced_constant = (enums[c.Reference].ConstantCollection[c.Value]);
                }
                else if (auxEnums != null && auxEnums.ContainsKey(c.Reference) && auxEnums[c.Reference].ConstantCollection.ContainsKey(c.Value))
                {
                    // Legacy from previous generator incarnation.
                    // Todo: merge everything into enums and get rid of auxEnums.
                    TranslateConstantWithReference(auxEnums[c.Reference].ConstantCollection[c.Value], enums, auxEnums);
                    referenced_constant = (auxEnums[c.Reference].ConstantCollection[c.Value]);
                }
                else if (enums.ContainsKey(Settings.CompleteEnumName) &&
                    enums[Settings.CompleteEnumName].ConstantCollection.ContainsKey(c.Value))
                {
                    // Try the All enum
                    var reference = enums[Settings.CompleteEnumName].ConstantCollection[c.Value];
                    if (reference.Reference == null)
                        referenced_constant = (enums[Settings.CompleteEnumName].ConstantCollection[c.Value]);
                    else
                    {
                        --CurrentReferenceDepth;
                        return false;
                    }
                }
                else
                {
                    --CurrentReferenceDepth;
                    return false;
                }
                //else throw new InvalidOperationException(String.Format("Unknown Enum \"{0}\" referenced by Constant \"{1}\"",
                //                                                       c.Reference, c.ToString()));

                c.Value = referenced_constant.Value;
                c.Reference = null;
            }

            --CurrentReferenceDepth;
            return true;
        }