From 69215096807a8d47d94bff35091b510efb349e6a Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Mon, 4 Nov 2013 22:26:06 +0100 Subject: [PATCH] Added "reuse" directive for enums Sometimes an enum may reuse the tokens of another enum verbatim (possibly adding a few extra tokens.) The reuse directive simplifies the handling of this case: --- Source/Bind/XmlSpecReader.cs | 84 +++++++++++++++++++++++++++--------- 1 file changed, 64 insertions(+), 20 deletions(-) diff --git a/Source/Bind/XmlSpecReader.cs b/Source/Bind/XmlSpecReader.cs index fb8c1937..e6128735 100644 --- a/Source/Bind/XmlSpecReader.cs +++ b/Source/Bind/XmlSpecReader.cs @@ -333,6 +333,9 @@ namespace Bind if (nav != null) { + var reuse_list = new List>(); + + // First pass: collect all available tokens and enums foreach (XPathNavigator node in nav.SelectChildren("enum", String.Empty)) { Enum e = new Enum() @@ -344,7 +347,6 @@ namespace Bind 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). @@ -372,40 +374,82 @@ namespace Bind }; break; + case "reuse": + var reuse_enum = param.GetAttribute("enum", String.Empty).Trim(); + reuse_list.Add(new KeyValuePair(e, reuse_enum)); + break; + default: throw new NotSupportedException(); } - Utilities.Merge(all, c); - try + + if (c != null) { - if (!e.ConstantCollection.ContainsKey(c.Name)) + Utilities.Merge(all, c); + try { - 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) + if (!e.ConstantCollection.ContainsKey(c.Name)) { - e.ConstantCollection[c.Name] = c; + e.ConstantCollection.Add(c.Name, c); } - else if (existing.Reference == null && c.Reference != null) - { } // Keep existing - else + else if (e.ConstantCollection[c.Name].Value != c.Value) { - Console.WriteLine("[Warning] Conflicting token {0}.{1} with value {2} != {3}", - e.Name, c.Name, 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); + 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);