/// <summary> /// Generate the code that we will use to access this array. Loop symantics in this framework are basically "foreach" rather than "for" - so /// we return an object that can be used to reference each array element. /// </summary> /// <param name="env"></param> /// <param name="context"></param> /// <param name="indexName"></param> /// <param name="popVariableContext"></param> /// <returns></returns> public Tuple<Expression, IDeclaredParameter> AddLoop(IGeneratedQueryCode env, ICodeContext context, CompositionContainer container) { /// /// First, we will need to know the length of this array /// var lenExpression = Expression.ArrayLength(_arrayExpression); var lenTranslation = ExpressionToCPP.GetExpression(lenExpression, env, context, container); /// /// Next, generate the expression that forms the basis of the index lookup. We don't /// translate this - that only gets to happen when one is actually looking at a final result. /// var loopVariable = DeclarableParameter.CreateDeclarableParameterExpression(typeof(int)); var indexExpression = Expression.MakeBinary(ExpressionType.ArrayIndex, _arrayExpression, loopVariable); /// /// Now the for loop statement! /// env.Add(new StatementForLoop(loopVariable, lenTranslation)); /// /// Return the index expression - the thing that can be used to replace all expressions and /// reference the item we are looping over. /// return Tuple.Create<Expression, IDeclaredParameter>(indexExpression, loopVariable); }
/// <summary> /// Actually try and process this! The count consisits of a count integer and something to increment it /// at its current spot. /// </summary> /// <param name="resultOperator"></param> /// <param name="queryModel"></param> /// <param name="codeEnv"></param> /// <returns></returns> public Expression ProcessResultOperator(ResultOperatorBase resultOperator, QueryModel queryModel, IGeneratedQueryCode gc, ICodeContext cc, CompositionContainer container) { if (gc == null) throw new ArgumentNullException("CodeEnv must not be null!"); var c = resultOperator as CountResultOperator; if (c == null) throw new ArgumentNullException("resultOperator can only be a CountResultOperator and must not be null"); // // The accumulator where we will store the result. // var accumulator = DeclarableParameter.CreateDeclarableParameterExpression(typeof(int)); accumulator.SetInitialValue("0"); // // Use the Aggregate infrasturcutre to do the adding. This // has the advantage that it will correctly combine with // similar statements during query optimization. // var add = Expression.Add(accumulator, Expression.Constant((int)1)); var addResolved = ExpressionToCPP.GetExpression(add, gc, cc, container); gc.Add(new StatementAggregate(accumulator, addResolved)); return accumulator; }
public static Expression Resolve(this Expression source, IGeneratedQueryCode gc, ICodeContext cc, CompositionContainer container) { if (cc == null) { cc = new CodeContext(); } // It does happen that we are asked to translate a null expression. This could be a static method call, for example. if (source == null) return null; try { Debug.WriteLine("Expression Resolver: Resolving {0}{1}", source.ToString(), ""); Debug.Indent(); var r = ResolveToExpression.Translate(source, gc, cc, container); Debug.WriteLine("Expression Resolver: Result: {0}{1}", r == null ? "<null>" : r.ToString(), ""); return r; } finally { Debug.Unindent(); } }
/// <summary> /// Implement the skipping. We have a main limitation: we currently know only how to implement integer skipping. /// We implement with "if" statements to support composability, even if it means running longer in the end... /// We actually return nothing when goes - we aren't really a final result the way "Count" is. /// </summary> /// <param name="resultOperator"></param> /// <param name="queryModel"></param> /// <param name="_codeEnv"></param> /// <returns></returns> public void ProcessResultOperator(ResultOperatorBase resultOperator, QueryModel queryModel, IGeneratedQueryCode codeEnv, ICodeContext codeContext, CompositionContainer container) { /// /// Quick checks to make sure /// if (codeEnv == null) throw new ArgumentNullException("codeEnv cannot be null"); var take = resultOperator as TakeResultOperator; var skip = resultOperator as SkipResultOperator; if (take == null && skip == null) { throw new ArgumentNullException("resultOperator must not be null and must represent either a take or a skip operation!"); } if (take != null && take.Count.Type != typeof(int)) throw new ArgumentException("Take operator count must be an integer!"); if (skip != null && skip.Count.Type != typeof(int)) throw new ArgumentException("Skip operator count must be an integer!"); // If this is a "global" take, then we need to declare the variable a bit specially. // Global: we have a limit on the number of objects that goes across events. We test this by seeing if this // is a sub-query that is registered (or not). var isGlobalTake = codeContext.IsInTopLevelQueryModel(queryModel); // Now, we create a count variable and that is how we will tell if we are still skipping or // taking. It must be declared in the current block, before our current code! :-) var counter = DeclarableParameter.CreateDeclarableParameterExpression(typeof(int), otherDependencies: codeContext.LoopIndexVariable.Return<IDeclaredParameter>()); if (isGlobalTake) { counter.DeclareAsStatic = true; codeEnv.Add(counter); } else { codeEnv.AddOutsideLoop(counter); } var comparison = StatementIfOnCount.ComparisonOperator.LessThanEqual; IValue limit = null; if (skip != null) { comparison = StatementIfOnCount.ComparisonOperator.GreaterThan; limit = ExpressionToCPP.GetExpression(skip.Count, codeEnv, codeContext, container); } else { limit = ExpressionToCPP.GetExpression(take.Count, codeEnv, codeContext, container); } codeEnv.Add(new StatementIfOnCount(counter, limit, comparison)); /// /// We are particularly fortunate here. We don't have to update the Loop variable - whatever it is, is /// still the right one! Normally we'd have to futz with the LoopVariable in code context because we /// were iterating over something new. :-) Easy! /// }
/// <summary> /// Run the method call against the expressions we know. /// </summary> /// <param name="expr"></param> /// <param name="result"></param> /// <param name="gc"></param> /// <returns></returns> public IValue CodeMethodCall(MethodCallExpression expr, IGeneratedQueryCode gc, CompositionContainer container) { if (expr == (MethodCallExpression)null) throw new ArgumentNullException("expr"); var h = FindHandler(expr.Method.DeclaringType); return h.CodeMethodCall(expr, gc, container); }
/// <summary> /// Create a new visitor and add our code to the current spot we are in the "code". /// </summary> /// <param name="code"></param> public QueryVisitor(IGeneratedQueryCode code, ICodeContext context, CompositionContainer container) { _codeEnv = code; _codeContext = context; MEFContainer = container; if (_codeContext == null) _codeContext = new CodeContext(); }
public IValue CodeMethodCall( TypeHandlerReplacementCall target, MethodCallExpression expr, IGeneratedQueryCode gc ) { var result01 = target.CodeMethodCall(expr, gc, MEFUtilities.MEFContainer); return result01; }
public IVariable TestProcessResultOperator([PexAssumeUnderTest]ROSum target, SumResultOperator sumro, QueryModel qm, IGeneratedQueryCode gc, ICodeContext cc) { var result = target.ProcessResultOperator(sumro, qm, gc, cc, MEFUtilities.MEFContainer); return result; }
/// <summary> /// Called late to replace a constant expression of this type. By the time we get here these should not exist! /// The expression holder can't hold anything interesting (like parameters) - by the time we are here /// it is too late to do the parsing. /// </summary> /// <param name="expr"></param> /// <param name="codeEnv"></param> /// <param name="container"></param> /// <returns></returns> public IValue ProcessConstantReference(ConstantExpression expr, IGeneratedQueryCode codeEnv, CompositionContainer container) { var holder = expr.Value as IExpressionHolder; if (holder == null) throw new InvalidOperationException("Can't get at the interface to get at the expression."); var e = holder.HeldExpression; return ExpressionToCPP.InternalGetExpression(e, codeEnv, null, container); }
#pragma warning restore 649 /// <summary> /// Process the constant reference /// </summary> /// <param name="expr"></param> /// <param name="codeEnv"></param> /// <returns></returns> public IValue ProcessConstantReference(ConstantExpression expr, IGeneratedQueryCode codeEnv, CompositionContainer container) { // <pex> if (expr == (ConstantExpression)null) throw new ArgumentNullException("expr"); // </pex> var h = FindHandler(expr.Type); return h.ProcessConstantReference(expr, codeEnv, container); }
/// <summary> /// Translate an expression. /// </summary> /// <param name="expr"></param> /// <param name="cc"></param> /// <returns></returns> public static Expression Translate(Expression expr, IGeneratedQueryCode gc, ICodeContext cc, CompositionContainer container) { var tr = new ResolveToExpression() { CodeContext = cc, GeneratedCode = gc, MEFContainer = container }; if (container != null) { container.SatisfyImportsOnce(tr); } return tr.Visit(expr); }
/// <summary> /// Find all statements that can be lifted out of their current block, and bubble them up /// as much as possible. /// </summary> /// <param name="result"></param> /// <remarks> /// We only lift things outside of loops, we don't lift them outside of if statements. /// If statements are an efficiency thing on their own - they should prevent expensive tests /// from happening if they don't need to. /// </remarks> internal static void Optimize(IGeneratedQueryCode result) { var statements = result.CodeBody as IStatementCompound; VisitOptimizableStatements(statements); foreach (var f in result.Functions.Where(f => f.StatementBlock != null)) { VisitOptimizableStatements(f.StatementBlock); } }
internal IValue ProcessConstantReference( [PexAssumeUnderTest]TypeHandlerHelpers target, ConstantExpression expr, IGeneratedQueryCode codeEnv ) { IValue result = target.ProcessConstantReference(expr, codeEnv, null); return result; // TODO: add assertions to method TypeHandlerHelpersTest.ProcessConstantReference(TypeHandlerHelpers, ConstantExpression, IGeneratedCode) }
public IValue ProcessConstantReference( TypeHandlerCache target, ConstantExpression expr, IGeneratedQueryCode codeEnv ) { IValue result = target.ProcessConstantReference(expr, codeEnv, null); return result; // TODO: add assertions to method TypeHandlerCacheTest.ProcessConstantReference(TypeHandlerCache, ConstantExpression, IGeneratedCode) }
/// <summary> /// Deal with the various method calls to convert. /// </summary> /// <param name="expr"></param> /// <param name="result"></param> /// <param name="gc"></param> /// <param name="context"></param> /// <param name="container"></param> /// <returns></returns> public IValue CodeMethodCall(MethodCallExpression expr, IGeneratedQueryCode gc, CompositionContainer container) { if (expr.Method.Name == "ToDouble") return ProcessToDouble(expr, gc, container); /// /// We don't know how to deal with this particular convert! /// throw new NotImplementedException("Can't translate the call Convert." + expr.Method.Name); }
internal Expression ProcessMethodCall( [PexAssumeUnderTest]TypeHandlerHelpers target, MethodCallExpression expr, IGeneratedQueryCode gc, ICodeContext context ) { Expression result01 = target.ProcessMethodCall(expr, gc, context, null); return result01; // TODO: add assertions to method TypeHandlerHelpersTest.ProcessMethodCall(TypeHandlerHelpers, MethodCallExpression, IValue&, IGeneratedCode, ICodeContext) }
internal IValue ProcessConstantReference( [PexAssumeUnderTest] TypeHandlerHelpers target, ConstantExpression expr, IGeneratedQueryCode codeEnv ) { IValue result = target.ProcessConstantReference(expr, codeEnv, null); return(result); // TODO: add assertions to method TypeHandlerHelpersTest.ProcessConstantReference(TypeHandlerHelpers, ConstantExpression, IGeneratedCode) }
/// <summary>Test stub for ProcessMethodCall(MethodCallExpression, IValue&, IGeneratedCode, ICodeContext)</summary> ///[PexMethod] public Expression ProcessMethodCall( TypeHandlerReplacementCall target, MethodCallExpression expr, IGeneratedQueryCode gc, ICodeContext context ) { Expression result01 = target.ProcessMethodCall(expr, gc, context, MEFUtilities.MEFContainer); return result01; // TODO: add assertions to method TypeHandlerReplacementCallTest.ProcessMethodCall(TypeHandlerReplacementCall, MethodCallExpression, IValue&, IGeneratedCode, ICodeContext) }
public IValue ProcessConstantReference( TypeHandlerCache target, ConstantExpression expr, IGeneratedQueryCode codeEnv ) { IValue result = target.ProcessConstantReference(expr, codeEnv, null); return(result); // TODO: add assertions to method TypeHandlerCacheTest.ProcessConstantReference(TypeHandlerCache, ConstantExpression, IGeneratedCode) }
/// <summary> /// Called during the high-level expression parsing. We will parse the expression and method to other expressions... /// So we drive everything through (get rid of sub-queries, etc.). First part of two pass parsing. Second part is below /// that will actually generate the C++ code. /// </summary> /// <param name="expr"></param> /// <param name="gc"></param> /// <param name="context"></param> /// <param name="container"></param> /// <returns></returns> public Expression ProcessMethodCall(MethodCallExpression expr, IGeneratedQueryCode gc, ICodeContext context, CompositionContainer container) { // // Pick apart the various things in the method call we need. // var robj = expr.Object.Resolve(gc, context, container); var method = expr.Method; var rargs = expr.Arguments.Select(e => e.Resolve(gc, context, container)); return(Expression.Call(robj, method, rargs)); }
/// <summary> /// Try to do a fast count. Basically, what we are dealing with here is the fact that we have /// a simple array, we need only take its length, and return that. /// </summary> /// <param name="resultOperator"></param> /// <param name="queryModel"></param> /// <param name="_codeEnv"></param> /// <param name="_codeContext"></param> /// <param name="container"></param> /// <returns></returns> public Tuple<bool, Expression> ProcessIdentityQuery(ResultOperatorBase resultOperator, QueryModel queryModel, IGeneratedQueryCode _codeEnv, ICodeContext _codeContext, CompositionContainer container) { // // We just need to return a length expression. We are low enough level we need to do some basic resolution. // if (!queryModel.MainFromClause.FromExpression.Type.IsArray) return Tuple.Create(false, null as Expression); var lengthExpr = Expression.ArrayLength(queryModel.MainFromClause.FromExpression).Resolve(_codeEnv, _codeContext, container); return Tuple.Create(true, lengthExpr as Expression); }
internal Expression ProcessMethodCall( [PexAssumeUnderTest] TypeHandlerHelpers target, MethodCallExpression expr, IGeneratedQueryCode gc, ICodeContext context ) { Expression result01 = target.ProcessMethodCall(expr, gc, context, null); return(result01); // TODO: add assertions to method TypeHandlerHelpersTest.ProcessMethodCall(TypeHandlerHelpers, MethodCallExpression, IValue&, IGeneratedCode, ICodeContext) }
/// <summary>Test stub for ProcessMethodCall(MethodCallExpression, IValue&, IGeneratedCode, ICodeContext)</summary> ///[PexMethod] public Expression ProcessMethodCall( TypeHandlerReplacementCall target, MethodCallExpression expr, IGeneratedQueryCode gc, ICodeContext context ) { Expression result01 = target.ProcessMethodCall(expr, gc, context, MEFUtilities.MEFContainer); return(result01); // TODO: add assertions to method TypeHandlerReplacementCallTest.ProcessMethodCall(TypeHandlerReplacementCall, MethodCallExpression, IValue&, IGeneratedCode, ICodeContext) }
/// <summary> /// Deal with the various method calls to convert. /// </summary> /// <param name="expr"></param> /// <param name="result"></param> /// <param name="gc"></param> /// <param name="context"></param> /// <param name="container"></param> /// <returns></returns> public IValue CodeMethodCall(MethodCallExpression expr, IGeneratedQueryCode gc, CompositionContainer container) { if (expr.Method.Name == "ToDouble") { return(ProcessToDouble(expr, gc, container)); } /// /// We don't know how to deal with this particular convert! /// throw new NotImplementedException("Can't translate the call Convert." + expr.Method.Name); }
/// Pex seems to hang when it tries to explore this one. ///[PexMethod] public Expression ProcessResultOperator( ROAggregate target, AggregateFromSeedResultOperator resultOperator, QueryModel queryModel, IGeneratedQueryCode _codeEnv ) { CodeContext c = new CodeContext(); Expression result = target.ProcessResultOperator(resultOperator, queryModel, _codeEnv, c, MEFUtilities.MEFContainer); return result; // TODO: add assertions to method ROAggregateTest.ProcessResultOperator(ROAggregate, ResultOperatorBase, QueryModel, IGeneratedCode) }
/// <summary> /// Process a new against an expression - that hopefully we know! /// </summary> /// <param name="expression"></param> /// <param name="result"></param> /// <param name="gc"></param> /// <param name="context"></param> /// <param name="container"></param> /// <returns></returns> internal Expression ProcessNew(NewExpression expression, out IValue result, IGeneratedQueryCode gc, CompositionContainer container) { if (expression == null) { throw new ArgumentNullException("expression"); } var h = FindHandler(expression.Type); return(h.ProcessNew(expression, out result, gc, container)); throw new NotImplementedException(); }
#pragma warning restore 649 /// <summary> /// Process the constant reference /// </summary> /// <param name="expr"></param> /// <param name="codeEnv"></param> /// <returns></returns> public IValue ProcessConstantReference(ConstantExpression expr, IGeneratedQueryCode codeEnv, CompositionContainer container) { // <pex> if (expr == (ConstantExpression)null) { throw new ArgumentNullException("expr"); } // </pex> var h = FindHandler(expr.Type); return(h.ProcessConstantReference(expr, codeEnv, container)); }
/// <summary> /// Try to do a member reference. Return null if we can't do it. /// </summary> /// <param name="expr"></param> /// <param name="gc"></param> /// <param name="cc"></param> /// <param name="container"></param> internal IValue TryMemberReference(MemberExpression expr, IGeneratedQueryCode gc, ICodeContext cc, CompositionContainer container) { var h = FindHandler(expr.Expression.Type, false); if (h == null) { return(null); } return(h.ProcessMemberReference(expr, gc, cc, container)); throw new NotImplementedException(); }
/// <summary> /// Called late to replace a constant expression of this type. By the time we get here these should not exist! /// The expression holder can't hold anything interesting (like parameters) - by the time we are here /// it is too late to do the parsing. /// </summary> /// <param name="expr"></param> /// <param name="codeEnv"></param> /// <param name="container"></param> /// <returns></returns> public IValue ProcessConstantReference(ConstantExpression expr, IGeneratedQueryCode codeEnv, CompositionContainer container) { var holder = expr.Value as IExpressionHolder; if (holder == null) { throw new InvalidOperationException("Can't get at the interface to get at the expression."); } var e = holder.HeldExpression; return(ExpressionToCPP.InternalGetExpression(e, codeEnv, null, container)); }
internal Expression ProcessResultOperator( [PexAssumeUnderTest]ROMinMax target, ResultOperatorBase resultOperator, QueryModel queryModel, IGeneratedQueryCode gc, ICodeContext cc, CompositionContainer container ) { Expression result = target.ProcessResultOperator(resultOperator, queryModel, gc, cc, container); return result; // TODO: add assertions to method ROMinMaxTest.ProcessResultOperator(ROMinMax, ResultOperatorBase, QueryModel, IGeneratedQueryCode, ICodeContext, CompositionContainer) }
/// <summary> /// Given array info, code a loop over it. /// </summary> /// <param name="query">The query this loop is associated with</param> /// <param name="arrayRef">The reference to the array</param> /// <remarks>Will add the query to the code context to forward to the variable that is being dealt with here.</remarks> public static IVariableScopeHolder CodeLoopOverArrayInfo(this IArrayInfo arrayRef, IQuerySource query, IGeneratedQueryCode gc, ICodeContext cc, CompositionContainer container) { var indexVar = arrayRef.AddLoop(gc, cc, container); if (indexVar == null) return null; /// /// Next, make sure the index variable can be used for later references! /// var result = cc.Add(query, indexVar.Item1); cc.SetLoopVariable(indexVar.Item1, indexVar.Item2); return result; }
/// Pex seems to hang when it tries to explore this one. ///[PexMethod] public Expression ProcessResultOperator( ROAggregate target, ResultOperatorBase resultOperator, QueryModel queryModel, IGeneratedQueryCode _codeEnv ) { CodeContext c = new CodeContext(); Expression result = target.ProcessResultOperator(resultOperator, queryModel, _codeEnv, c, MEFUtilities.MEFContainer); return(result); // TODO: add assertions to method ROAggregateTest.ProcessResultOperator(ROAggregate, ResultOperatorBase, QueryModel, IGeneratedCode) }
internal Expression ProcessNew( [PexAssumeUnderTest] TypeHandlerCache target, NewExpression expression, out IValue _result, IGeneratedQueryCode _codeEnv, CompositionContainer MEFContainer ) { Expression result = target.ProcessNew (expression, out _result, _codeEnv, MEFContainer); return(result); // TODO: add assertions to method TypeHandlerCacheTest.ProcessNew(TypeHandlerCache, NewExpression, IValue&, IGeneratedQueryCode, ICodeContext, CompositionContainer) }
/// <summary> /// Translate an expression. /// </summary> /// <param name="expr"></param> /// <param name="cc"></param> /// <returns></returns> public static Expression Translate(Expression expr, IGeneratedQueryCode gc, ICodeContext cc, CompositionContainer container) { var tr = new ResolveToExpression() { CodeContext = cc, GeneratedCode = gc, MEFContainer = container }; if (container != null) { container.SatisfyImportsOnce(tr); } return(tr.Visit(expr)); }
/// <summary> /// Do a type check, and then create the range info... which is dirt simple, of course! /// </summary> /// <param name="expr"></param> /// <param name="gc"></param> /// <param name="cc"></param> /// <param name="container"></param> /// <param name="ReGetIArrayInfo"></param> /// <returns></returns> public IArrayInfo GetIArrayInfo(Expression expr, IGeneratedQueryCode gc, ICodeContext cc, CompositionContainer container, Func <Expression, IArrayInfo> ReGetIArrayInfo) { if (expr.NodeType == ExpressionType.Constant) { return(ProcessPossibleConstEnumerableRange(expr, gc, cc, container, ReGetIArrayInfo)); } if (expr.NodeType == EnumerableRangeExpression.ExpressionType) { return(ProcessEnumerableRangeExpression(expr, gc, cc, container, ReGetIArrayInfo)); } return(null); }
internal Expression ProcessResultOperator( [PexAssumeUnderTest] ROMinMax target, ResultOperatorBase resultOperator, QueryModel queryModel, IGeneratedQueryCode gc, ICodeContext cc, CompositionContainer container ) { Expression result = target.ProcessResultOperator(resultOperator, queryModel, gc, cc, container); return(result); // TODO: add assertions to method ROMinMaxTest.ProcessResultOperator(ROMinMax, ResultOperatorBase, QueryModel, IGeneratedQueryCode, ICodeContext, CompositionContainer) }
/// <summary> /// Given an array expression return an array info that can be used /// for the various needed things. Throws if it can't figure out how to do /// a loop. It might return null, in which case the array index context has /// just been "setup". /// </summary> /// <param name="expr"></param> /// <returns>null, if no further setup is required to run the loop, and an IArrayInfo if further work is required.</returns> private IArrayInfo GetIArrayInfo(Expression expr, IGeneratedQueryCode gc, ICodeContext cc, CompositionContainer container) { expr = NormalizeExpression(expr); // // See if we can find something that will handle the array. // var arInfo = (from h in _handlers let r = h.GetIArrayInfo(expr, gc, cc, container, e => GetIArrayInfo(e, gc, cc, container)) where r != null select r).FirstOrDefault(); return(arInfo); }
internal Expression ProcessResultOperator( [PexAssumeUnderTest] ROAnyAll target, ResultOperatorBase resultOperator, QueryModel queryModel, IGeneratedQueryCode _codeEnv, ICodeContext _codeContext, CompositionContainer container ) { Expression result = target.ProcessResultOperator (resultOperator, queryModel, _codeEnv, _codeContext, container); return(result); // TODO: add assertions to method ROAnyAllTest.ProcessResultOperator(ROAnyAll, ResultOperatorBase, QueryModel, IGeneratedQueryCode, ICodeContext, CompositionContainer) }
/// <summary> /// Given an array expression return an array info that can be used /// for the various needed things. Throws if it can't figure out how to do /// a loop. It might return null, in which case the array index context has /// just been "setup". /// </summary> /// <param name="expr"></param> /// <returns>null, if no further setup is required to run the loop, and an IArrayInfo if further work is required.</returns> private IArrayInfo GetIArrayInfo(Expression expr, IGeneratedQueryCode gc, ICodeContext cc, CompositionContainer container) { expr = NormalizeExpression(expr); // // See if we can find something that will handle the array. // var arInfo = (from h in _handlers let r = h.GetIArrayInfo(expr, gc, cc, container, e => GetIArrayInfo(e, gc, cc, container)) where r != null select r).FirstOrDefault(); return arInfo; }
/// <summary> /// Translate the CPP code reference into the code /// </summary> /// <param name="expr"></param> /// <param name="result"></param> /// <param name="gc"></param> /// <param name="context"></param> /// <param name="container"></param> /// <returns></returns> public IValue CodeMethodCall(MethodCallExpression expr, IGeneratedQueryCode gc, CompositionContainer container) { if (expr == null) throw new ArgumentNullException("expr"); /// /// Get the coding attribute off the method /// var code = expr.Method.TypeHasAttribute<CPPCodeAttribute>(); if (code == null) throw new InvalidOperationException(string.Format("Asked to generate code for a CPP method '{0}' but no CPPCode attribute found on that method!", expr.Method.Name)); return CPPCodeStatement.BuildCPPCodeStatement(expr, gc, container, code.IncludeFiles, code.Code); }
/// <summary> /// Take the incoming stream of items, and send them along! :-) /// </summary> /// <param name="resultOperator"></param> /// <param name="queryModel"></param> /// <param name="_codeEnv"></param> /// <param name="_codeContext"></param> /// <param name="container"></param> public void ProcessResultOperator(ResultOperatorBase resultOperator, QueryModel queryModel, IGeneratedQueryCode gc, ICodeContext cc, CompositionContainer container) { // // Some basic checks on the input. // if (cc == null) throw new ArgumentNullException("cc"); if (gc == null) throw new ArgumentNullException("gc"); if (cc.LoopVariable == null) throw new ArgumentNullException("No defined loop variable!"); // // Get the indexer that is being used to access things. We will just push that onto a temp vector of int's. That will be // a list of the items that we want to come back and look at. That said, once done we need to pop-up one level in our // depth. // var arrayRecord = DeclarableParameter.CreateDeclarableParameterArrayExpression(typeof(int)); gc.AddOutsideLoop(arrayRecord); var recordIndexStatement = new Statements.StatementRecordIndicies(ExpressionToCPP.GetExpression(cc.LoopIndexVariable.AsExpression(), gc, cc, container), arrayRecord); gc.Add(recordIndexStatement); gc.Pop(); // // Now, we go down one loop and run over the pairs with a special loop. // var index1 = DeclarableParameter.CreateDeclarableParameterExpression(typeof(int)); var index2 = DeclarableParameter.CreateDeclarableParameterExpression(typeof(int)); var indexIterator = new Statements.StatementPairLoop(arrayRecord, index1, index2); gc.Add(indexIterator); // // Finally, build the resulting loop variable. For now it is just a tuple, which is basically the formed expression we started with, // but with the other index properties. Other bits will have to do the translation for us. :-) // var item1 = cc.LoopVariable.ReplaceSubExpression(cc.LoopIndexVariable.AsExpression(), index1); var item2 = cc.LoopVariable.ReplaceSubExpression(cc.LoopIndexVariable.AsExpression(), index2); var tupleType = typeof(Tuple<,>).MakeGenericType(cc.LoopVariable.Type, cc.LoopVariable.Type); var newTuple = Expression.New(tupleType.GetConstructor(new Type[] { cc.LoopVariable.Type, cc.LoopVariable.Type }), item1, item2); cc.SetLoopVariable(newTuple, null); }
/// <summary> /// See if we can't resolve a group-by object into a looper of some sort. /// </summary> /// <param name="expr"></param> /// <param name="gc"></param> /// <param name="cc"></param> /// <param name="container"></param> /// <param name="ReGetIArrayInfo"></param> /// <returns></returns> public IArrayInfo GetIArrayInfo(Expression expr, IGeneratedQueryCode gc, ICodeContext cc, CompositionContainer container, Func <Expression, IArrayInfo> ReGetIArrayInfo) { if (!expr.Type.IsGenericType || expr.Type.GetGenericTypeDefinition() != typeof(GroupByTypeTagEnum <int, int>).GetGenericTypeDefinition()) { return(null); } var param = expr as ConstantExpression; if (param == null) { return(null); } var groupObj = param.Value as BaseGroupInfo; if (groupObj == null) { throw new InvalidOperationException("Group object has a null value - should never happen!"); } // // Loop over the groups. groupIndex represents the actual group index. // var loopOverGroups = new Statements.StatementLoopOverGroups(groupObj.MapRecord); gc.Add(loopOverGroups); // // Finally, the loop index variable and we have to create the index object now, which is the grouping // (which can also be iterated over). // var t_return = typeof(GroupByType <int, int>).GetGenericTypeDefinition().MakeGenericType(param.Value.GetType().GetGenericArguments()); var ctor = t_return.GetConstructor(new Type[] { }); var o = ctor.Invoke(new object[] { }) as BaseGroupInfo; o.MapRecord = groupObj.MapRecord; o.TargetExpression = groupObj.TargetExpression; o.TargetExpressionLoopVariable = groupObj.TargetExpressionLoopVariable; o.GroupIndexVariable = loopOverGroups.IndexVariable; o.GroupLoopStatement = loopOverGroups; var loopVar = Expression.Constant(o); return(new SimpleLoopVarSetting(loopVar, loopOverGroups.IndexVariable)); }
public IArrayInfo GetIArrayInfo(Expression expr, IGeneratedQueryCode gc, ICodeContext cc, CompositionContainer container, Func <Expression, IArrayInfo> ReGetIArrayInfo) { if (expr is SubQueryExpression) { return(null); } var translated = AttemptTranslationToArray(expr, cc); if (translated != null) { return(ReGetIArrayInfo(translated)); } return(null); }
/// <summary> /// If one of the helper functions needs to be parsed, we end up here. /// Note: this is a bit tricky, and, worse, this is not tested (too complex :-)). /// </summary> /// <param name="expr"></param> /// <param name="result"></param> /// <param name="gc"></param> /// <param name="context"></param> /// <returns></returns> public System.Linq.Expressions.Expression ProcessMethodCall(MethodCallExpression expr, IGeneratedQueryCode gc, ICodeContext context, CompositionContainer container) { if (expr == null) throw new ArgumentNullException("expr"); if (expr.Method.Name == "ApplyReturnFirst") { /// /// Load out the parameter names we are looking at so we cna do the translation. /// var parameters = expr.Method.GetParameters(); var action = RaiseLambda(expr.Arguments[2]); var methodGenericArguments = expr.Method.GetGenericArguments(); var actionType = typeof(Action<,>).MakeGenericType(new Type[] { methodGenericArguments[0], methodGenericArguments[1] }); var expressionGeneric = typeof(Expression<>).MakeGenericType(new Type[] { actionType }); var parameterSpec = expressionGeneric.GetProperty("Parameters"); var lambdaParameters = (parameterSpec.GetValue(action, null) as IEnumerable<ParameterExpression>).ToArray(); /// /// Next, do the lambda expression. Order of p1 and p2 is b/c we should make sure that it happens /// before any parameters are replaced! Note we parse the body of the lambda here! Parameters are defined and should /// correctly deal with any substitution in process. /// var p2 = context.Add(lambdaParameters[1].Name, expr.Arguments[1]); var p1 = context.Add(lambdaParameters[0].Name, expr.Arguments[0]); var statementBody = ExpressionToCPP.GetExpression(action.Body.Resolve(gc, context, container), gc, context, container); p1.Pop(); p2.Pop(); gc.Add(new Statements.StatementSimpleStatement(statementBody.RawValue, resultVars: new string[0] { }, dependentVars: statementBody.Dependants.Select(i => i.RawValue).ToArray())); /// /// Finally, what we will return if this is the last thing we are doing! /// return expr.Arguments[0]; } else { throw new NotImplementedException("Helpers." + expr.Method.Name + " is not handled!"); } }
/// <summary> /// Do the work of translating this to code by fetching the data from the interface. /// </summary> /// <param name="expr"></param> /// <param name="gc"></param> /// <param name="container"></param> /// <returns></returns> public IValue CodeMethodCall(MethodCallExpression expr, IGeneratedQueryCode gc, CompositionContainer container) { if (expr == null) throw new ArgumentNullException("expr"); // Get a reference to the object so we can code the call to get back the C++ code. var onTheFly = (expr?.Object as ConstantExpression)?.Value as IOnTheFlyCPPObject; if (onTheFly == null) { throw new InvalidOperationException("Unable to find the IOnTheFlyCPPObject!"); } var includeFiles = onTheFly.IncludeFiles(); var loc = onTheFly.LinesOfCode(expr.Method.Name).ToArray(); return CPPCodeStatement.BuildCPPCodeStatement(expr, gc, container, includeFiles, loc); }
/// <summary> /// Internal expression resolver. /// </summary> /// <param name="expr"></param> /// <param name="ce"></param> /// <param name="cc"></param> /// <param name="container"></param> /// <returns></returns> /// <remarks> /// Cache and do cache lookup of expressions to try to short-circuit the expression resolution. /// </remarks> public static IValue InternalGetExpression(Expression expr, IGeneratedQueryCode ce, ICodeContext cc, CompositionContainer container) { // If we are looking at a null expression, then we resolve to a null value if (expr == null) { return(null); } // If this is a known sub-expression, then we should return // the cached value. if (ce != null) { var v = ce.LookupSubexpression(expr); if (v != null) { return(v); } } // We are going to do the visit. Create the resolver we are going to use // and configure it. if (cc == null) { cc = new CodeContext(); } var visitor = new ExpressionToCPP(ce, cc); visitor.MEFContainer = container; if (container != null) { container.SatisfyImportsOnce(visitor); } // Do the visit visitor.Visit(expr); // Cache the result. if (ce != null) { ce.RememberSubexpression(expr, visitor.Result); } return(visitor.Result); }
/// <summary> /// We want to print the results out to a file. /// </summary> /// <param name="resultOperator"></param> /// <param name="queryModel"></param> /// <param name="_codeEnv"></param> /// <param name="_codeContext"></param> /// <param name="container"></param> /// <returns></returns> /// <remarks> /// We can handle several types of streams here: /// 1) a stream of double's - this is just one column. /// 2) A stream of Tuples /// 3) A stream of custom objects /// </remarks> public override Expression ProcessResultOperator(ResultOperatorBase resultOperator, QueryModel queryModel, IGeneratedQueryCode gc, ICodeContext cc, CompositionContainer container) { // Argument checking var asTTree = resultOperator as AsTTreeResultOperator; if (asTTree == null) throw new ArgumentException("resultOperaton"); // Declare the includes. gc.AddIncludeFile("<map>"); gc.AddIncludeFile("TSystem.h"); gc.AddIncludeFile("TFile.h"); gc.AddIncludeFile("TTree.h"); // If we were left to our own devices generating an output file, then make one up based on the tree name. var outputFile = asTTree.OutputFile != null ? asTTree.OutputFile : new FileInfo($"{asTTree.TreeName}.root"); // Declare the TTree and the file we will be using! // Initialization is not important as we will over-write this directly. var stream = DeclarableParameter.CreateDeclarableParameterExpression(typeof(OutputTTreeFileType)); stream.InitialValue = new OutputTTreeFileType(outputFile); // Generate a real filename. We are going to key the file by the cache key. Unfortunately, at this // point in the generation the cache key isn't known. So we have to have a 'promise' that can be used // for later when the code is actually generated. var outputFilePromise = GenerateUniqueFile(outputFile, cc); // Open the file and declare the tree gc.AddInitalizationStatement(new StatementSimpleStatement(() => $"{stream.RawValue}.first = new TFile(\"{outputFilePromise().FullName.AddCPPEscapeCharacters()}\",\"RECREATE\")", dependentVars: new string[0], resultVars: new string[] { stream.RawValue })); gc.AddInitalizationStatement(new StatementSimpleStatement($"{stream.RawValue}.second = new TTree(\"{asTTree.TreeName}\", \"{asTTree.TreeTitle}\")", dependentVars: new string[0], resultVars: new string[] { stream.RawValue })); // Get the list of item values we are going to need here. List<Expression> itemValues = ExtractItemValueExpressions(queryModel); // We are just going to print out the line with the item in it. var itemAsValues = itemValues.Select(iv => ExpressionToCPP.GetExpression(iv, gc, cc, container)).ToArray(); var pstatement = new StatementFillTree(stream, itemAsValues.Zip(asTTree.HeaderColumns, (i, h) => Tuple.Create(i, h)).ToArray()); gc.Add(pstatement); // The return is a file path in the C# world. But here in C++, what should be returned? // We will use a string. return stream; }
/// <summary> /// Convert something to a double. We don't actually do anything as long as this is an expression that we /// can naturally convert (int, float, etc.). /// /// We are expecting an expressio nthat is ToDouble(Convert()), so if we can't see the convert, then we bail. /// </summary> /// <param name="expr"></param> /// <param name="result"></param> /// <param name="gc"></param> /// <param name="context"></param> /// <param name="container"></param> /// <returns></returns> private static IValue ProcessToDouble(MethodCallExpression expr, IGeneratedQueryCode gc, CompositionContainer container) { var srcExpr = expr.Arguments[0]; if (srcExpr.NodeType != ExpressionType.Convert) { throw new NotImplementedException("Expecting a Convert expression inside the call to Convert.ToDouble"); } var cvtExpr = srcExpr as UnaryExpression; var result = ExpressionToCPP.InternalGetExpression(cvtExpr.Operand, gc, null, container); if (!result.Type.IsNumberType()) { throw new NotImplementedException("Do not know how to convert '" + srcExpr.Type.Name + "' to a double!"); } return(result); }
/// <summary> /// Parse an array expression, and turn it into a loop. Use indexName as the loop variable. Bomb if we can't do it. If you hand in null we will make up our own. /// </summary> /// <param name="query">The query that this loop is associated with.</param> /// <param name="expr">The expression that evaluates to an array.</param> /// <param name="gc"></param> /// <param name="cc"></param> /// <param name="container"></param> public static IVariableScopeHolder ParseArrayExpression(IQuerySource query, Expression expr, IGeneratedQueryCode gc, ICodeContext cc, CompositionContainer container) { if (_parser == null) { _parser = new ArrayExpressionParser(); container.SatisfyImportsOnce(_parser); } var result = _parser.GetIArrayInfo(expr, gc, cc, container); if (result == null) throw new InvalidOperationException($"Can't figure out how to loop over this array: '{expr.ToString()}' (expression: '{expr.NodeType}', type: '{expr.Type.FullyQualifiedName()}')"); // // Turn it into code - any code that we need. // return result.CodeLoopOverArrayInfo(query, gc, cc, container); }
/// <summary> /// Evaluate an expression. If the result is just DeclareableParameter, return that, otherwise make an assignment. /// </summary> /// <param name="ce"></param> /// <param name="cc"></param> /// <param name="container"></param> /// <param name="exprToHandIn"></param> /// <returns></returns> private static DeclarableParameter AssignExpreaaionToEvaluationIfNeededBool(IGeneratedQueryCode ce, ICodeContext cc, CompositionContainer container, Expression exprToHandIn, IScopeInfo whereToDeclare = null) { IValue exprEvaluation = GetExpression(exprToHandIn, ce, cc, container); if (exprEvaluation is DeclarableParameter p) { // We can only return this if the variable is declared at the place we want it to be! var currentScope = ce.CurrentScope; try { if (whereToDeclare != null) { ce.CurrentScope = whereToDeclare; } if (ce.CodeBody.AllDeclaredVariables.Where(dp => dp == p).Any()) { return(p); } } finally { ce.CurrentScope = currentScope; } } // Create and assign an expression. var result = DeclarableParameter.CreateDeclarableParameterExpression(typeof(bool)); result.InitialValue = new ValSimple("false", typeof(bool)); if (whereToDeclare == null) { ce.Add(result); } else { var currentScope = ce.CurrentScope; ce.CurrentScope = whereToDeclare; ce.Add(result); ce.CurrentScope = currentScope; } ce.Add(new Statements.StatementAssign(result, exprEvaluation)); return(result); }
/// <summary> /// For a root variable we create a special variable which holds onto the initial value, and /// also will get loaded at the correct time. /// </summary> /// <param name="expr"></param> /// <param name="codeEnv"></param> /// <returns></returns> public IValue ProcessConstantReference(ConstantExpression expr, IGeneratedQueryCode codeEnv, CompositionContainer container) { /// /// The value is a reference that will do the loading. /// var rootObject = expr.Value as ROOTNET.Interface.NTNamed; if (rootObject == null) { throw new ArgumentException("the object to be stored must derive from NTNamed! It is of type '" + expr.Value.GetType().Name + "' which does not appear to derive from TNamed."); } // // Queue this object for transfer, get a "unique" name back. This will also double check // to see if the object is already up there read to be queued. // var varNameForTransport = codeEnv.QueueForTransfer(rootObject); // // Now, we need to generate an IValue for the object that can be used in our expression parsing. // When in the middle of a tight loop, since finding the object is a "slow" linear lookup, we will cache it in a static // variable. This isn't so pretty when there is a one-time initialization, but it shouldn't add too much. // var staticCache = new ROOTObjectStaticHolder(rootObject.GetType(), rootObject); staticCache.DeclareAsStatic = true; staticCache.InitialValue = new ValSimple("nullptr", staticCache.Type); codeEnv.Add(staticCache); codeEnv.Add(new Statements.StatementFilter(new ValSimple($"{staticCache.RawValue} == nullptr", typeof(bool), new IDeclaredParameter[] { staticCache }))); var CPPType = rootObject.GetType().AsCPPType(); var val = new ROOTObjectCopiedValue(varNameForTransport, rootObject.GetType(), CPPType, rootObject.Name, rootObject.Title); codeEnv.Add(new Statements.StatementAssign(staticCache, val)); codeEnv.Pop(); // And the rest of the code should use the static cache. return(staticCache); }
/// <summary> /// We want to print the results out to a file. /// </summary> /// <param name="resultOperator"></param> /// <param name="queryModel"></param> /// <param name="_codeEnv"></param> /// <param name="_codeContext"></param> /// <param name="container"></param> /// <returns></returns> /// <remarks> /// We can handle several types of streams here: /// 1) a stream of double's - this is just one column. /// 2) A stream of Tuples /// 3) A stream of custom objects /// </remarks> public override Expression ProcessResultOperator(ResultOperatorBase resultOperator, QueryModel queryModel, IGeneratedQueryCode gc, ICodeContext cc, CompositionContainer container) { // Argument checking var asCSV = resultOperator as AsCSVResultOperator; if (asCSV == null) throw new ArgumentException("resultOperaton"); // Declare the includes. gc.AddIncludeFile("<fstream>"); gc.AddIncludeFile("<iostream>"); // The output filename. How we do this is a little funny because we need the hash from the completely // done query, which isn't ready just yet. var outputFile = GenerateUniqueFile(asCSV.OutputFile, cc); var stream = DeclarableParameter.CreateDeclarableParameterExpression(typeof(OutputCSVTextFileType)); stream.InitialValue = new OutputCSVTextFileType(outputFile); var headerline = new StringBuilder(); bool first = true; foreach (var h in asCSV.HeaderColumns) { if (!first) { headerline.Append(", "); } headerline.Append(h); first = false; } gc.AddInitalizationStatement(new Statements.StatementSimpleStatement($"{stream.RawValue} << \"{headerline.ToString()}\" << std::endl;", dependentVars: new string[0], resultVars: new string[] { stream.RawValue })); // Get the list of item values we are going to need here. List<Expression> itemValues = ExtractItemValueExpressions(queryModel); // We are just going to print out the line with the item in it. var itemAsValues = itemValues.Select(iv => ExpressionToCPP.GetExpression(iv, gc, cc, container)); var pstatement = new StatementCSVDump(stream, itemAsValues.ToArray()); gc.Add(pstatement); // The return is a file path in the C# world. But here in C++, what should be returned? // We will use a string. return stream; }
/// <summary> /// Do the work of translating this to code by fetching the data from the interface. /// </summary> /// <param name="expr"></param> /// <param name="gc"></param> /// <param name="container"></param> /// <returns></returns> public IValue CodeMethodCall(MethodCallExpression expr, IGeneratedQueryCode gc, CompositionContainer container) { if (expr == null) { throw new ArgumentNullException("expr"); } // Get a reference to the object so we can code the call to get back the C++ code. var onTheFly = (expr?.Object as ConstantExpression)?.Value as IOnTheFlyCPPObject; if (onTheFly == null) { throw new InvalidOperationException("Unable to find the IOnTheFlyCPPObject!"); } var includeFiles = onTheFly.IncludeFiles(); var loc = onTheFly.LinesOfCode(expr.Method.Name).ToArray(); return(CPPCodeStatement.BuildCPPCodeStatement(expr, gc, container, includeFiles, loc)); }
/// <summary> /// Translate the CPP code reference into the code /// </summary> /// <param name="expr"></param> /// <param name="result"></param> /// <param name="gc"></param> /// <param name="context"></param> /// <param name="container"></param> /// <returns></returns> public IValue CodeMethodCall(MethodCallExpression expr, IGeneratedQueryCode gc, CompositionContainer container) { if (expr == null) { throw new ArgumentNullException("expr"); } /// /// Get the coding attribute off the method /// var code = expr.Method.TypeHasAttribute <CPPCodeAttribute>(); if (code == null) { throw new InvalidOperationException(string.Format("Asked to generate code for a CPP method '{0}' but no CPPCode attribute found on that method!", expr.Method.Name)); } return(CPPCodeStatement.BuildCPPCodeStatement(expr, gc, container, code.IncludeFiles, code.Code)); }
/// <summary> /// We are looking at a&&b or a||b. We wnat to make sure we evaluate b iff we need it, depending on the result of a. /// </summary> /// <param name="expr"></param> /// <param name="ce"></param> /// <param name="cc"></param> /// <param name="container"></param> /// <returns></returns> /// <remarks> /// To prevent us from updating variables (which makes optmization harder), we will implement the code as follows for a&&b: /// bool_1 = false; bool_2 = false; bool_3 = false; /// bool_1 = a /// if (bool_1) bool_2 = b /// bool_3 = bool_1 && bool_2 ///</remarks> private static IValue GetExpressionForBoolAndOr(Expression expr, IGeneratedQueryCode ce, ICodeContext cc, CompositionContainer container) { // Svae to make sure we can get back. var outterScope = ce.CurrentScope; // Create a variable to hold the result of this test var resultBool3 = DeclarableParameter.CreateDeclarableParameterExpression(typeof(bool)); resultBool3.InitialValue = new ValSimple("false", typeof(bool)); ce.Add(resultBool3); // Create and evaluate bool_1 var binaryExpression = expr as BinaryExpression; DeclarableParameter resultBool1 = AssignExpreaaionToEvaluationIfNeededBool(ce, cc, container, binaryExpression.Left); // Now, see if we need to evalute the right hand operand. if (expr.NodeType == ExpressionType.AndAlso) { ce.Add(new Statements.StatementFilter(resultBool1)); } else { var notYet = new ValSimple($"!{resultBool1.RawValue}", typeof(bool), new IDeclaredParameter[] { resultBool1 }); ce.Add(new Statements.StatementFilter(notYet)); } // Create and evaluate bool 1. var resultBool2 = AssignExpreaaionToEvaluationIfNeededBool(ce, cc, container, binaryExpression.Right, outterScope); ce.CurrentScope = outterScope; // Finally, evaluate bool3. var termEvaluation = expr.NodeType == ExpressionType.AndAlso ? $"{resultBool1.RawValue}&&{resultBool2.RawValue}" : $"{resultBool1.RawValue}||{resultBool2.RawValue}"; ce.Add(new Statements.StatementAssign(resultBool3, new ValSimple(termEvaluation, typeof(bool), new[] { resultBool1, resultBool2 }))); // Return the value we've now filled. return(resultBool3); }
/// <summary> /// Helper routine to return the expression as a string. /// </summary> /// <param name="expr"></param> /// <returns></returns> public static IValue GetExpression(Expression expr, IGeneratedQueryCode ce, ICodeContext cc, CompositionContainer container) { try { // Get setup and deal with simple cases. Debug.WriteLine("ExpressionToCPP: Parsing {0}{1}", expr.ToString(), ""); Debug.Indent(); if (expr == null) { return(null); } if (cc == null) { cc = new CodeContext(); } // Special case we can deal with seperately - when there is a bool and an AndAlso or OrElse. // We want to make sure we guard the second expression so it isn't executed if it isn't needed. if (expr.Type == typeof(bool) && (expr.NodeType == ExpressionType.AndAlso || expr.NodeType == ExpressionType.OrElse)) { return(GetExpressionForBoolAndOr(expr, ce, cc, container)); } // Cache the list of variables that need to be eliminated when CPP is done. var cachedScopedVariables = cc.ResetCachedVariableList(); var r = InternalGetExpression(expr.Resolve(ce, cc, container), ce, cc, container).PerformAllSubstitutions(cc); Debug.WriteLine("ExpressionToCPP: Returning value {0}{1}", r.ToString(), ""); cc.PopCachedVariableList(); cc.LoadCachedVariableList(cachedScopedVariables); return(r); } finally { Debug.Unindent(); } }
public IArrayInfo GetIArrayInfo(Expression expr, IGeneratedQueryCode gc, ICodeContext cc, CompositionContainer container, Func <Expression, IArrayInfo> ReGetIArrayInfo) { if (!(expr is SubQueryExpression)) { return(null); } var resolved = expr.Resolve(gc, cc, container); if (resolved == null) { return(new DummyArrayInfo()); } if (resolved is SubQueryExpression) { throw new InvalidOperationException(string.Format("Unable to translate '{0}' to something we can loop over!", expr.ToString())); } return(ReGetIArrayInfo(resolved)); }
public IArrayInfo GetIArrayInfo(Expression expr, IGeneratedQueryCode gc, ICodeContext cc, CompositionContainer container, Func <Expression, IArrayInfo> ReGetIArrayInfo) { if (!(expr is QuerySourceReferenceExpression)) { return(null); } var preplacements = ParameterReplacementExpressionVisitor.ReplaceParameters(expr, cc); var r = TranslatingExpressionVisitor.Translate(preplacements, cc.CacheCookies, e => e); // // If we don't know what we are doing here, bail! // if (r == expr) { return(null); } return(ReGetIArrayInfo(r)); }
/// <summary> /// Look to see if this is a member access, and if so, then attempt to decode it. /// </summary> /// <param name="expr"></param> /// <param name="gc"></param> /// <param name="cc"></param> /// <param name="container"></param> /// <param name="ReGetIArrayInfo"></param> /// <returns></returns> public IArrayInfo GetIArrayInfo(Expression expr, IGeneratedQueryCode gc, ICodeContext cc, CompositionContainer container, Func <Expression, IArrayInfo> ReGetIArrayInfo) { // Make sure this is an expression we expect to be dealing with! if (expr.NodeType != ExpressionType.MemberAccess) { return(null); } // get the root expression, and decode it. var ma = expr as MemberExpression; var resolved = ma.Expression.Resolve(gc, cc, container); if (resolved == ma.Expression) { return(null); } // Create a new member access and attempt to resolve that mess. var maNew = Expression.MakeMemberAccess(resolved, ma.Member); return(ReGetIArrayInfo(maNew)); }
/// <summary> /// No member lookup is possible (though it might be eventually!). /// </summary> /// <param name="expr"></param> /// <param name="gc"></param> /// <param name="cc"></param> /// <param name="container"></param> /// <returns></returns> public IValue ProcessMemberReference(MemberExpression expr, IGeneratedQueryCode gc, ICodeContext cc, CompositionContainer container) { throw new NotImplementedException(); }