/// <summary> /// Appends numbers indicating the block a statement belongs to. /// <remarks> /// A statement written in the format: /// /// > var nested = from x in a /// > from y in b /// > select x + y; /// > /// > var fetch = from x in nested /// > from y in b /// > select x + y; /// /// will be rewritten as: /// /// > a.SelectMany( /// > x => b, /// > x, y => x + y /// > ).SelectMany( /// > x => b /// > x, y => x + y /// > ); /// /// Because there are two variables named "x", and these /// expressions are written inline, we need to number them, /// in case they end up in the same applicative group. /// </remarks> /// </summary> public static IEnumerable <QueryStatement> NumberBlocks(List <QueryStatement> statements) { var blockNumber = 0; var statementCounter = 0; var numStatements = statements.Count(); var isFirst = true; foreach (var statement in statements) { statementCounter++; // SplitBind functions that take one non-transparent parameter are binding the entire result from another monad. // This will hide any variables that were in scope in that monad. statement.StartsBlock = isFirst; if (statement.Match( bind => bind.BindVariables.ParameterNames.Count == 1 && !ParseExpression.IsTransparent(bind.Expressions.Bind.Parameters.First()), let => false) ) { blockNumber++; statement.StartsBlock = true; } statement.BlockNumber = blockNumber; if (statementCounter == numStatements) { statement.IsFinal = true; } isFirst = false; yield return(statement); } }
/// <summary> /// We only want to rewrite transparent identifier accessors. /// </summary> protected override Expression VisitMember(MemberExpression node) { if (ParseExpression.IsFromTransparent(node) && !ParseExpression.IsTransparentMember(node)) { return(RewritePropertyAccess(node)); } return(base.VisitMember(node)); }
/// <summary> /// Gets the variables in a (bind, project) pair. /// </summary> private static QueryStatement GetVariables(BindProjectPair pair) { var project = pair.Project; var isLet = project.Parameters.Any(param => param.Name.StartsWith(LET_PREFIX)); if (isLet) { var letParam = project.Parameters.ElementAt(1); var letName = letParam.Name; var originalName = Regex.Split(letName, LET_PREFIX)[1]; var letExpression = Expression.Lambda(project.Body, project.Parameters.First(), Expression.Parameter(letParam.Type, originalName)); var letVariables = ParseExpression.GetExpressionVariables(letExpression); return(new LetStatement(originalName, letExpression, letVariables)); } var bindVars = ParseExpression.GetExpressionVariables(pair.Bind); var projectVars = ParseExpression.GetExpressionVariables(project); return(new BindProjectStatement(pair, bindVars, projectVars) { IsSelect = pair.IsSelect }); }