/src/Otis/CodeGen/AggregateExpressionBuilder.cs

http://otis-lib.googlecode.com/ · C# · 160 lines · 135 code · 25 blank · 0 comment · 16 complexity · 6c79f5c86d57bc29664577959a7bac15 MD5 · raw file

  1. using System;
  2. using System.CodeDom;
  3. using System.Collections.Generic;
  4. using System.Text;
  5. using Otis.Functions;
  6. using Otis.Parsing;
  7. namespace Otis.CodeGen
  8. {
  9. class AggregateExpressionBuilder
  10. {
  11. private List<CodeStatement> m_statements = null;
  12. private List<AggregateFunctionContext> m_contexts = null;
  13. public AggregateExpressionBuilder(ClassMappingDescriptor descriptor, ICollection<MemberMappingDescriptor> members, FunctionMap functionMap)
  14. {
  15. m_contexts = new List<AggregateFunctionContext>(members.Count);
  16. foreach (MemberMappingDescriptor member in members)
  17. {
  18. m_contexts.Add(CreateMemberContext(descriptor, member, functionMap));
  19. }
  20. }
  21. public CodeStatement[] GetStatements()
  22. {
  23. if (m_statements == null)
  24. Generate();
  25. return m_statements.ToArray();
  26. }
  27. private void Generate()
  28. {
  29. m_statements = new List<CodeStatement>(50);
  30. if(m_contexts.Count < 1)
  31. return;
  32. foreach (AggregateFunctionContext context in m_contexts)
  33. {
  34. m_statements.AddRange(context.Generator.GetInitializationStatements(context));
  35. }
  36. m_statements.AddRange(GetPathTraversalStatements());
  37. foreach (AggregateFunctionContext context in m_contexts)
  38. {
  39. m_statements.Add(context.Generator.GetAssignmentStatement(context));
  40. }
  41. }
  42. private IEnumerable<CodeStatement> GetPathTraversalStatements()
  43. {
  44. string exp = "";
  45. IList<AggregateExpressionPathItem> pathItems
  46. = ExpressionParser.BuildAggregatePathItem(m_contexts[0].Descriptor, m_contexts[0].Member);
  47. foreach (AggregateExpressionPathItem pathItem in pathItems)
  48. {
  49. if (pathItem.IsCollection)
  50. {
  51. exp += string.Format("foreach({0} {1} in {2}.{3})",
  52. TypeHelper.GetTypeDefinition(pathItem.Type),
  53. pathItem.Object,
  54. pathItem.Target,
  55. pathItem.Expression);
  56. }
  57. }
  58. exp += Environment.NewLine + "\t\t\t\t{" + Environment.NewLine;
  59. foreach (AggregateFunctionContext context in m_contexts)
  60. {
  61. IEnumerable<string> itemExpressions = context.Generator.GetIterationStatements(context, context.PathItems);
  62. foreach (string itemExpression in itemExpressions)
  63. {
  64. exp += "\t\t\t\t\t";
  65. exp += itemExpression;
  66. if(!exp.EndsWith(";"))
  67. exp += ";";
  68. exp += Environment.NewLine; // todo: smarter way
  69. }
  70. }
  71. exp += "\t\t\t\t}";
  72. CodeConditionStatement ifStatement = new CodeConditionStatement(
  73. new CodeSnippetExpression(pathItems[0].Target + "." + pathItems[0].Expression + " != null"),
  74. new CodeStatement[] { new CodeExpressionStatement(new CodeSnippetExpression(exp)) },
  75. new CodeStatement[0]);
  76. CodeStatementCollection statements = new CodeStatementCollection();
  77. statements.Add(ifStatement);
  78. CodeStatement[] arr = new CodeStatement[statements.Count];
  79. statements.CopyTo(arr, 0);
  80. return arr;
  81. }
  82. private Type GetSourceItemType(IList<AggregateExpressionPathItem> items, MemberMappingDescriptor member)
  83. {
  84. if (items == null || items.Count < 1)
  85. {
  86. string msg = ErrorBuilder.InvalidAggregatePathError(member);
  87. throw new OtisException(msg);
  88. }
  89. return items[items.Count - 1].Type;
  90. }
  91. private IAggregateFunctionCodeGenerator GetGeneratorImpl(Type implementationType, MemberMappingDescriptor member)
  92. {
  93. Type[] interfaces = implementationType.GetInterfaces();
  94. foreach (Type itf in interfaces) // first check if it has its own implementation of IAggregateFunctionCodeGenerator
  95. {
  96. if (itf == typeof (IAggregateFunctionCodeGenerator))
  97. return Activator.CreateInstance(implementationType, true) as IAggregateFunctionCodeGenerator;
  98. }
  99. foreach (Type itf in interfaces) // now check if it only implement IAggregateFunction
  100. {
  101. if (itf.IsGenericType && itf.GetGenericTypeDefinition() == typeof(IAggregateFunction<>))
  102. return new DefaultAggregateFunctionCodeGenerator();
  103. }
  104. string msg = ErrorBuilder.InvalidAggregatePathError(member);
  105. throw new OtisException(msg); // test
  106. }
  107. private AggregateFunctionContext CreateMemberContext(ClassMappingDescriptor descriptor, MemberMappingDescriptor member, FunctionMap functionMap)
  108. {
  109. Type implementationType = functionMap.GetTypeForFunction(member.AggregateMappingDescription.FunctionName);
  110. string functionObjectName = string.Format("_{0}_to_{1}_Fn_",
  111. member.AggregateMappingDescription.FunctionObject,
  112. member.Member);
  113. if (implementationType.IsGenericType)
  114. {
  115. if (member.IsArray || member.IsList)
  116. {
  117. Type instanceType = member.IsArray ?
  118. member.AggregateMappingDescription.TargetType.GetElementType() :
  119. member.AggregateMappingDescription.TargetType.GetGenericArguments()[0];
  120. implementationType = implementationType.MakeGenericType(instanceType);
  121. }
  122. else
  123. {
  124. implementationType = implementationType.MakeGenericType(member.AggregateMappingDescription.TargetType);
  125. }
  126. }
  127. IAggregateFunctionCodeGenerator generator = GetGeneratorImpl(implementationType, member);
  128. return new AggregateFunctionContext(member,
  129. descriptor,
  130. implementationType,
  131. functionObjectName,
  132. generator);
  133. }
  134. }
  135. }