PageRenderTime 60ms CodeModel.GetById 50ms app.highlight 8ms RepoModel.GetById 1ms app.codeStats 0ms

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