Free cookie consent management tool by TermsFeed Policy Generator

Changeset 9005


Ignore:
Timestamp:
12/06/12 12:07:31 (11 years ago)
Author:
epitzer
Message:

#1990 Enable correct parsing of generics and nested classes.

Location:
trunk/sources
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/sources/HeuristicLab.Persistence/3.3/Auxiliary/TypeName.cs

    r8698 r9005  
    5151
    5252    /// <summary>
     53    /// Gets or sets the number of generic args for
     54    /// each class in a series of nested classes.
     55    /// </summary>
     56    [Storable]
     57    public List<int> GenericArgCounts { get; private set; }
     58
     59      /// <summary>
    5360    /// Gets or sets the generic args.
    5461    /// </summary>
     
    103110    /// <param name="nameSpace">The namespace.</param>
    104111    /// <param name="className">Name of the class.</param>
    105     internal TypeName(string nameSpace, string className) {
     112    internal TypeName(string nameSpace, string className, List<int> genericArgCounts=null) {
    106113      Namespace = nameSpace;
    107114      ClassName = className;
     
    109116      MemoryMagic = "";
    110117      AssemblyAttribues = new Dictionary<string, string>();
     118      if (genericArgCounts != null)
     119        GenericArgCounts = genericArgCounts.ToList();
    111120    }
    112121
    113122    internal TypeName(TypeName typeName, string className = null, string nameSpace = null) {
    114       Namespace = typeName.Namespace;
    115       ClassName = typeName.ClassName;
     123      Namespace = nameSpace ?? typeName.Namespace;
     124      ClassName = className ?? typeName.ClassName;
    116125      GenericArgs = new List<TypeName>(typeName.GenericArgs);
    117126      AssemblyAttribues = new Dictionary<string, string>(typeName.AssemblyAttribues);
     
    119128      AssemblyName = typeName.AssemblyName;
    120129      IsReference = typeName.IsReference;
    121       if (nameSpace != null)
    122         Namespace = nameSpace;
    123       if (className != null)
    124         ClassName = className;
     130      if (typeName.GenericArgCounts != null)
     131        GenericArgCounts = typeName.GenericArgCounts.ToList();
    125132    }
    126133
     
    148155    /// </returns>
    149156    public string ToString(bool full, bool includeAssembly) {
    150       StringBuilder sb = new StringBuilder();
     157      var sb = new StringBuilder();
    151158      if (!string.IsNullOrEmpty(Namespace))
    152159        sb.Append(Namespace).Append('.');
    153       sb.Append(ClassName);
     160      if (GenericArgCounts != null) {
     161        sb.Append(string.Join("+",
     162          ClassName
     163          .Split('+')
     164          .Zip(GenericArgCounts, (n, c) =>
     165            c > 0 ? String.Format("{0}`{1}", n, c) : n)));
     166      } else {
     167        sb.Append(ClassName);
     168        if (IsGeneric)
     169          sb.Append('`').Append(GenericArgs.Count);
     170      }
    154171      if (IsGeneric) {
    155         sb.Append('`').Append(GenericArgs.Count).Append('[');
    156         bool first = true;
    157         foreach (TypeName t in GenericArgs) {
    158           if (first)
    159             first = false;
    160           else
    161             sb.Append(',');
    162           sb.Append('[').Append(t.ToString(full)).Append(']');
    163         }
     172        sb.Append('[');
     173        sb.Append(String.Join(",", GenericArgs.Select(a =>
     174          string.Format("[{0}]", a.ToString(full)))));
    164175        sb.Append(']');
    165176      }
     
    174185    }
    175186
    176     public string GetTypeNameInCode(HashSet<string> omitNamespaces) {
    177       StringBuilder sb = new StringBuilder();
    178       if (!string.IsNullOrEmpty(Namespace) && omitNamespaces == null || !omitNamespaces.Contains(Namespace))
    179         sb.Append(Namespace).Append('.');
    180       sb.Append(ClassName);
    181       if (IsGeneric) {
    182         sb.Append("<");
    183         sb.Append(
    184           string.Join(", ",
    185             GenericArgs
    186               .Select(a => a.GetTypeNameInCode(omitNamespaces))
    187               .ToArray()));
    188         sb.Append(">");
     187    private IEnumerable<string> GetNestedClassesInCode(HashSet<string> omitNamespaces, bool includeAllNamespaces) {
     188      var i = 0;
     189      foreach (var pair in ClassName.Split('+').Zip(GenericArgCounts, (n, c) => new {n, c})) {
     190        if (pair.c == 0) {
     191          yield return pair.n;
     192        }
     193        else {
     194          yield return string.Format("{0}<{1}>",
     195            pair.n,
     196            string.Join(",",
     197              GenericArgs
     198                .GetRange(i, pair.c)
     199                .Select(a => a.GetTypeNameInCode(omitNamespaces, includeAllNamespaces))));
     200          i += pair.c;
     201        }
     202      }
     203    }
     204
     205    private string GetTypeNameInCode(HashSet<string> omitNamespaces, bool includeNamespaces) {
     206      var sb = new StringBuilder();
     207      if (!string.IsNullOrEmpty(Namespace) &&
     208            (omitNamespaces == null && includeNamespaces) ||
     209             omitNamespaces != null && !omitNamespaces.Contains(Namespace))
     210          sb.Append(Namespace).Append('.');
     211      if (GenericArgCounts != null) {
     212        sb.Append(string.Join(".", GetNestedClassesInCode(omitNamespaces, includeNamespaces)));
     213      } else {
     214        sb.Append(ClassName);
     215        if (IsGeneric) {
     216          sb.Append("<");
     217          sb.Append(
     218            string.Join(", ",
     219                        GenericArgs
     220                          .Select(a => a.GetTypeNameInCode(omitNamespaces, includeNamespaces))
     221                          .ToArray()));
     222          sb.Append(">");
     223        }
    189224      }
    190225      sb.Append(MemoryMagic);
     
    192227    }
    193228
    194     public string GetTypeNameInCode(bool includeAllNamespaces) {
    195       StringBuilder sb = new StringBuilder();
    196       if (includeAllNamespaces)
    197         sb.Append(Namespace).Append('.');
    198       sb.Append(ClassName);
    199       if (IsGeneric) {
    200         sb.Append("<");
    201         sb.Append(
    202           string.Join(", ",
    203             GenericArgs
    204               .Select(a => a.GetTypeNameInCode(includeAllNamespaces))
    205               .ToArray()));
    206         sb.Append(">");
    207       }
    208       sb.Append(MemoryMagic);
    209       return sb.ToString();
     229    public string GetTypeNameInCode(HashSet<string> omitNamespaces) {
     230      return GetTypeNameInCode(omitNamespaces, false);
     231    }
     232
     233    public string GetTypeNameInCode(bool includeNamespaces) {
     234      return GetTypeNameInCode(null, includeNamespaces);
    210235    }
    211236
  • trunk/sources/HeuristicLab.Persistence/3.3/Auxiliary/TypeNameParser.cs

    r7259 r9005  
    2121
    2222using System;
     23using System.Linq;
    2324using System.Collections.Generic;
    2425using System.Text;
     
    4647  ///
    4748  /// SimpleTypeSpec := (IDENTIFIER '.')*
    48   ///                   (IDENTIFIER '+')*
     49  ///                   (IDENTIFIER '`\d+'? '+')*
    4950  ///                    IDENTIFIER
    5051  ///                   ( '`\d+[' Generics ']' )?
     
    6970
    7071      SimpleTypeSpec := (IDENTIFIER '.')*
    71                         (IDENTIFIER '+')*
    72                          IDENTIFIER
    73                         ( '`\d+[' Generics ']' )?
     72                        (IDENTIFIER '`\d+'?
     73                        ( '+' IDENTIFIER '`\d+'? )*
     74                        ( '[' Generics ']' )?
    7475                        (\*|\[(\d+\.\.\d+|\d+\.\.\.|(|\*)(,(|\*))*)\])*
    7576                        (',\s*' IDENTIFIER (',\s*' AssemblyProperty)* )?
    7677
    77       Generics := '[' SimpleTypeSpec ']' (',[' SimpleTypeSpec ']')
     78      Generics := '[' SimpleTypeSpec ']' (',[' SimpleTypeSpec ']')*
    7879
    7980      AssemblyProperty := 'Version=' Version
     
    8889
    8990    private class Token {
    90       private static Dictionary<string, string> tokens =
    91         new Dictionary<string, string> {
    92           {"-", "DASH"},
    93           {"&", "AMPERSAND"},
    94           {".", "DOT"},
    95           {"+", "PLUS"},
    96           {",", "COMMA"},
    97           {"[", "OPEN_BRACKET"},
    98           {"]", "CLOSE_BRACKET"},
    99           {"*", "ASTERISK"},
    100           {" ", "SPACE"},
    101           {"=", "EQUALS"},
    102           {"`", "BACKTICK"} };
    103       private static Regex NumberRegex = new Regex("^\\d+$");
    104       private static Regex IdentifierRegex = new Regex("^[_a-zA-Z][_a-zA-Z0-9]*$");
    105       private static Regex TokenRegex = new Regex("[-&.+,\\[\\]* =`]|[a-f0-9]+|\\d+|[_a-zA-Z][_a-zA-Z0-9]*");
    106       public string Name { get; private set; }
     91      public enum Symbol {None, Dash, Ampersand, Dot, Plus, Comma, OpenBracket, CloseBracket, Asterisk, Space, Equals, Backtick}
     92      private static readonly Dictionary<string, Symbol> TOKENS =
     93        new Dictionary<string, Symbol> {
     94          {"-", Symbol.Dash},
     95          {"&", Symbol.Ampersand},
     96          {".", Symbol.Dot},
     97          {"+", Symbol.Plus},
     98          {",", Symbol.Comma},
     99          {"[", Symbol.OpenBracket},
     100          {"]", Symbol.CloseBracket},
     101          {"*", Symbol.Asterisk},
     102          {" ", Symbol.Space},
     103          {"=", Symbol.Equals},
     104          {"`", Symbol.Backtick}};
     105      private static readonly Regex NumberRegex = new Regex("^\\d+$");
     106      private static readonly Regex IdentifierRegex = new Regex("^[_a-zA-Z][_a-zA-Z0-9]*$");
     107      private static readonly Regex TokenRegex = new Regex("[-&.+,\\[\\]* =`]|[a-f0-9]+|\\d+|[_a-zA-Z][_a-zA-Z0-9]*");
     108      public Symbol Name { get; private set; }
    107109      public string Value { get; private set; }
    108110      public bool IsIdentifier { get; private set; }
     
    111113      private Token(string value, int pos) {
    112114        Position = pos;
    113         if (tokens.ContainsKey(value)) {
    114           Name = tokens[value];
     115        Name = Symbol.None;
     116        if (TOKENS.ContainsKey(value)) {
     117          Name = TOKENS[value];
    115118        } else if (NumberRegex.IsMatch(value)) {
    116119          Number = int.Parse(value);
     
    128131      }
    129132      public override string ToString() {
    130         if (Name != null)
     133        if (Name != Symbol.None)
    131134          return "Token(" + Name + ")";
    132135        if (Value != null)
     
    181184    private TypeName TransformTypeSpec() {
    182185      TypeName t = TransformSimpleTypeSpec();
    183       t.IsReference = ConsumeToken("AMPERSAND");
     186      t.IsReference = ConsumeToken(Token.Symbol.Ampersand);
    184187      return t;
    185188    }
    186189
    187190    private TypeName TransformSimpleTypeSpec() {
    188       List<string> nameSpace = new List<string>();
    189       nameSpace.Add(ConsumeIdentifier());
    190       while (ConsumeToken("DOT"))
     191      var nameSpace = new List<string> {ConsumeIdentifier()};
     192      while (ConsumeToken(Token.Symbol.Dot))
    191193        nameSpace.Add(ConsumeIdentifier());
    192       List<string> className = new List<string>();
     194      var className = new List<string>();
    193195      if (nameSpace.Count > 0) {
    194196        className.Add(nameSpace[nameSpace.Count - 1]);
    195197        nameSpace.RemoveAt(nameSpace.Count - 1);
    196198      }
    197       while (ConsumeToken("PLUS"))
     199      var genericArgCounts = new List<int> {
     200        ConsumeToken(Token.Symbol.Backtick) ? ConsumeNumber() : 0
     201      };
     202      while(ConsumeToken(Token.Symbol.Plus)) {
    198203        className.Add(ConsumeIdentifier());
    199       TypeName typeName = new TypeName(
     204        genericArgCounts.Add(ConsumeToken(Token.Symbol.Backtick) ? ConsumeNumber() : 0);
     205      }
     206      var nGenericArgs = genericArgCounts.Sum();
     207      var typeName = new TypeName(
    200208        string.Join(".", nameSpace.ToArray()),
    201         string.Join("+", className.ToArray()));
    202       if (ConsumeToken("BACKTICK")) {
    203         int nGenericArgs = ConsumeNumber();
    204         if (ConsumeToken("OPEN_BRACKET") &&
    205           CanConsumeToken("OPEN_BRACKET")) {
    206           typeName.GenericArgs.AddRange(TransformGenerics());
    207           ConsumeToken("CLOSE_BRACKET", true);
    208         }
    209       }
    210       StringBuilder pointerOrArray = new StringBuilder();
     209        string.Join("+", className.ToArray()),
     210        nGenericArgs > genericArgCounts.Last() ? genericArgCounts : null);
     211      if (nGenericArgs > 0 && ConsumeToken(Token.Symbol.OpenBracket, true)) {
     212        typeName.GenericArgs.AddRange(TransformGenerics());
     213        ConsumeToken(Token.Symbol.CloseBracket, true);
     214      }
     215      var pointerOrArray = new StringBuilder();
    211216      while (true) {
    212         if (ConsumeToken("ASTERSIK")) {
     217        if (ConsumeToken(Token.Symbol.Asterisk)) {
    213218          pointerOrArray.Append("*");
    214         } else if (ConsumeToken("OPEN_BRACKET")) {
     219        } else if (ConsumeToken(Token.Symbol.OpenBracket)) {
    215220          pointerOrArray.Append('[');
    216221          ParseDimension(pointerOrArray);
    217           while (ConsumeToken("COMMA")) {
     222          while (ConsumeToken(Token.Symbol.Comma)) {
    218223            pointerOrArray.Append(",");
    219224            ParseDimension(pointerOrArray);
    220225          }
    221           ConsumeToken("CLOSE_BRACKET", true);
     226          ConsumeToken(Token.Symbol.CloseBracket, true);
    222227          pointerOrArray.Append(']');
    223228        } else {
     
    227232      typeName.MemoryMagic = pointerOrArray.ToString();
    228233      if (ConsumeComma()) {
    229         StringBuilder sb = new StringBuilder();
     234        var sb = new StringBuilder();
    230235        sb.Append(ConsumeIdentifier());
    231         while (CanConsumeToken("DOT") ||
    232           CanConsumeToken("DASH") ||
     236        while (CanConsumeToken(Token.Symbol.Dot) ||
     237          CanConsumeToken(Token.Symbol.Dash) ||
    233238          CanConsumeNumber() ||
    234239          CanConsumeIdentifier()) {
    235           if (ConsumeToken("DOT"))
     240          if (ConsumeToken(Token.Symbol.Dot))
    236241            sb.Append('.');
    237           else if (ConsumeToken("DASH"))
     242          else if (ConsumeToken(Token.Symbol.Dash))
    238243            sb.Append('-');
    239244          else if (CanConsumeNumber())
     
    253258
    254259    private void ParseDimension(StringBuilder sb) {
    255       if (ConsumeToken("ASTERSIK")) {
     260      if (ConsumeToken(Token.Symbol.Asterisk)) {
    256261        sb.Append("*");
    257262      } else if (CanConsumeNumber()) {
    258263        sb.Append(ConsumeNumber());
    259         ConsumeToken("DOT", true);
    260         ConsumeToken("DOT", true);
    261         if (ConsumeToken("DOT")) {
     264        ConsumeToken(Token.Symbol.Dot, true);
     265        ConsumeToken(Token.Symbol.Dot, true);
     266        if (ConsumeToken(Token.Symbol.Dot)) {
    262267          sb.Append("...");
    263268        } else {
     
    268273
    269274    private IEnumerable<TypeName> TransformGenerics() {
    270       ConsumeToken("OPEN_BRACKET", true);
     275      ConsumeToken(Token.Symbol.OpenBracket, true);
    271276      yield return TransformSimpleTypeSpec();
    272       ConsumeToken("CLOSE_BRACKET", true);
    273       while (ConsumeToken("COMMA")) {
    274         ConsumeToken("OPEN_BRACKET", true);
     277      ConsumeToken(Token.Symbol.CloseBracket, true);
     278      while (ConsumeToken(Token.Symbol.Comma)) {
     279        ConsumeToken(Token.Symbol.OpenBracket, true);
    275280        yield return TransformSimpleTypeSpec();
    276         ConsumeToken("CLOSE_BRACKET", true);
     281        ConsumeToken(Token.Symbol.CloseBracket, true);
    277282      }
    278283    }
     
    280285    private KeyValuePair<string, string> TransformAssemblyProperty() {
    281286      if (ConsumeIdentifier("Version")) {
    282         ConsumeToken("EQUALS", true);
     287        ConsumeToken(Token.Symbol.Equals, true);
    283288        return new KeyValuePair<string, string>(
    284289          "Version",
     
    300305
    301306    private KeyValuePair<string, string> ConsumeAssignment(string name) {
    302       ConsumeToken("EQUALS", true);
     307      ConsumeToken(Token.Symbol.Equals, true);
    303308      return new KeyValuePair<string, string>(name, ConsumeToken());
    304309    }
     
    307312      StringBuilder version = new StringBuilder();
    308313      version.Append(ConsumeNumber());
    309       ConsumeToken("DOT");
     314      ConsumeToken(Token.Symbol.Dot);
    310315      version.Append('.').Append(ConsumeNumber());
    311       ConsumeToken("DOT");
     316      ConsumeToken(Token.Symbol.Dot);
    312317      version.Append('.').Append(ConsumeNumber());
    313       ConsumeToken("DOT");
     318      ConsumeToken(Token.Symbol.Dot);
    314319      version.Append('.').Append(ConsumeNumber());
    315320      return version.ToString();
     
    368373
    369374    private bool ConsumeComma() {
    370       if (ConsumeToken("COMMA")) {
    371         while (ConsumeToken("SPACE")) ;
     375      if (ConsumeToken(Token.Symbol.Comma)) {
     376        while (ConsumeToken(Token.Symbol.Space)) ;
    372377        return true;
    373378      } else {
     
    376381    }
    377382
    378     private bool ConsumeToken(string name) {
    379       return ConsumeToken(name, false);
    380     }
    381 
    382     private bool CanConsumeToken(string name) {
    383       if (tokens.Count == 0)
    384         return false;
    385       if (tokens.Peek().Name == name)
     383    private bool ConsumeToken(Token.Symbol symbol) {
     384      return ConsumeToken(symbol, false);
     385    }
     386
     387    private bool CanConsumeToken(Token.Symbol symbol) {
     388      if (tokens.Count == 0)
     389        return false;
     390      if (tokens.Peek().Name == symbol)
    386391        return true;
    387392      return false;
    388393    }
    389394
    390     private bool ConsumeToken(string name, bool force) {
     395    private bool ConsumeToken(Token.Symbol symbol, bool force) {
    391396      if (tokens.Count == 0)
    392397        if (force)
    393398          throw new ParseError(String.Format(
    394399            "end of input while expecting token \"{0}\"",
    395             name));
     400            symbol));
    396401        else
    397402          return false;
    398       if (tokens.Peek().Name == name) {
     403      if (tokens.Peek().Name == symbol) {
    399404        tokens.Dequeue();
    400405        return true;
     
    402407        throw new ParseError(String.Format(
    403408          "expected \"{0}\" found \"{1}\"",
    404           name,
     409          symbol,
    405410          tokens.Peek().ToString()));
    406411      } else {
  • trunk/sources/HeuristicLab.Tests/HeuristicLab.Persistence-3.3/UseCases.cs

    r7915 r9005  
    13231323    }
    13241324
     1325    public class G<T,T2> {
     1326      public class S {}
     1327      public class S2<T3,T4> {}
     1328    }
     1329
     1330    [TestMethod]
     1331    public void TestInternalClassOfGeneric() {
     1332      var s = new G<int, char>.S();
     1333      var typeName = s.GetType().AssemblyQualifiedName;
     1334      Assert.AreEqual(
     1335        "UseCases.G<Int32,Char>.S",
     1336        TypeNameParser.Parse(typeName).GetTypeNameInCode(false));
     1337      XmlGenerator.Serialize(s, tempFile);
     1338      var s1 = XmlParser.Deserialize(tempFile);
     1339    }
     1340
     1341    [TestMethod]
     1342    public void TestInternalClassOfGeneric2() {
     1343      var s = new G<int, float>.S2<int, char>();
     1344      var typeName = s.GetType().AssemblyQualifiedName;
     1345      Assert.AreEqual(
     1346        "UseCases.G<Int32,Single>.S2<Int32,Char>",
     1347        TypeNameParser.Parse(typeName).GetTypeNameInCode(false));
     1348      XmlGenerator.Serialize(s, tempFile);
     1349      var s1 = XmlParser.Deserialize(tempFile);
     1350    }
     1351
    13251352    [ClassInitialize]
    13261353    public static void Initialize(TestContext testContext) {
Note: See TracChangeset for help on using the changeset viewer.