/src/Otis/Parsing/ExpressionParser.cs

http://otis-lib.googlecode.com/ · C# · 129 lines · 109 code · 19 blank · 1 comment · 15 complexity · dfe36007571e3a1bfde0df0bec93958e MD5 · raw file

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Reflection;
  4. using System.Text;
  5. using System.Text.RegularExpressions;
  6. using Otis.CodeGen;
  7. namespace Otis.Parsing
  8. {
  9. class ExpressionParser
  10. {
  11. static Regex s_regex = new Regex(@"^\w+:.+\w$"); // match all like 'xxx:....'
  12. static Regex s_literal = new Regex(@"^\[.+\]$"); // match all like '[....]'
  13. static Regex s_projection = new Regex(@"^(\s*[^\s:=>,]+\s*=>\s*[^\s:=>,]+\s*;)*(\s*[^\s:=>,]+\s*=>\s*[^\s:=>,]+\s*);?$"); // match all like 'a=>b;c=>d'
  14. public static bool IsAggregateExpression(string expression)
  15. {
  16. return s_regex.IsMatch(expression.Trim());
  17. }
  18. public static bool IsLiteralExpression(string expression)
  19. {
  20. return s_literal.IsMatch(expression.Trim());
  21. }
  22. public static bool IsProjectionExpression(string expression)
  23. {
  24. return s_projection.IsMatch(expression.Trim());
  25. }
  26. public static IList<AggregateExpressionPathItem> BuildAggregatePathItem(ClassMappingDescriptor descriptor, MemberMappingDescriptor member)
  27. {
  28. string firstPart = member.AggregateMappingDescription.PathParts[0];
  29. string targetName = firstPart.StartsWith("$") ? "source" : "";
  30. List<AggregateExpressionPathItem> pathItems = new List<AggregateExpressionPathItem>(3);
  31. Type targetType = descriptor.SourceType;
  32. foreach (string pathPart in member.AggregateMappingDescription.PathParts)
  33. {
  34. if (pathPart.Contains("."))
  35. {
  36. string[] subParts = pathPart.Split('.');
  37. foreach (string subPart in subParts)
  38. {
  39. targetName = AddPathItems(member, pathItems, subPart, targetName, ref targetType);
  40. }
  41. }
  42. else
  43. {
  44. targetName = AddPathItems(member, pathItems, pathPart, targetName, ref targetType);
  45. }
  46. }
  47. return pathItems;
  48. }
  49. private static string AddPathItems(MemberMappingDescriptor member, List<AggregateExpressionPathItem> pathItems, string pathPart, string targetName, ref Type targetType) {
  50. targetType = GetTargetType(targetType, pathPart.Replace("$", ""));
  51. string objectName = GetCollectionItemName(pathPart);
  52. bool isCollection = IsCollection(targetType);
  53. if(isCollection)
  54. pathItems.Add(new AggregateExpressionPathItem(ToInstanceType(member, targetType), objectName, targetName, pathPart, isCollection));
  55. else
  56. pathItems.Add(new AggregateExpressionPathItem(ToInstanceType(member, targetType), objectName, targetName, pathPart, isCollection));
  57. targetType = ToInstanceType(member, targetType);
  58. targetName = objectName;
  59. return targetName;
  60. }
  61. private static Type GetTargetType(Type type, string memberName)
  62. {
  63. FieldInfo field = type.GetField(memberName, BindingFlags.Public | BindingFlags.Instance);
  64. if (field != null)
  65. return field.FieldType;
  66. PropertyInfo property = type.GetProperty(memberName, BindingFlags.Public | BindingFlags.Instance);
  67. if (property != null)
  68. return property.PropertyType;
  69. throw new OtisException("Expression type can't be deduced"); // todo: msg, test
  70. }
  71. private static bool IsCollection(Type type)
  72. {
  73. return (type.IsArray
  74. || type.GetInterface(typeof (ICollection<>).FullName) != null
  75. || typeof (System.Collections.ICollection).IsAssignableFrom(type));
  76. }
  77. private static Type ToInstanceType(MemberMappingDescriptor member, Type type)
  78. {
  79. if(type.IsArray)
  80. {
  81. return type.GetElementType();
  82. }
  83. if(typeof(System.Collections.ICollection).IsAssignableFrom(type))
  84. {
  85. string msg = ErrorBuilder.CantAggregateOverUntypedCollections(member);
  86. throw new OtisException(msg);
  87. }
  88. if(type.GetInterface(typeof(ICollection<>).FullName) != null) // generic collection
  89. {
  90. return type.GetGenericArguments()[0];
  91. }
  92. // simple type
  93. return type;
  94. }
  95. private static string GetCollectionItemName(string part)
  96. {
  97. part = part.Replace("$", "");
  98. string itemName = "__" + part.ToLower().Trim();
  99. if (itemName.EndsWith("s"))
  100. itemName = itemName.Substring(0, itemName.Length - 1);
  101. return itemName;
  102. }
  103. public static string NormalizeExpression(string input)
  104. {
  105. if (ExpressionParser.IsLiteralExpression(input))
  106. input = input.Replace('\'', '\"').Substring(1, input.Length - 2);
  107. return input;
  108. }
  109. }
  110. }