public void TypeOfSequence() { var qmb = new QueryModelBuilder(); qmb.AddClause(new SelectClause(Expression.Constant(1.0))); int[] list = new int[10]; qmb.AddClause(new MainFromClause("r1", typeof(int), Expression.Constant(list))); var h = new QMFuncHeader() { Arguments = new object[] { }, IsSequence = true, QM = qmb.Build(), QMText = "hi" }; var src = new QMFuncSource(h); Assert.AreEqual(typeof(double[]), src.ResultType, "result type"); Assert.AreEqual(typeof(double[]), src.CacheVariable.Type, "Type of cache"); Assert.AreEqual(typeof(bool), src.CacheVariableGood.Type, "Type of the cache good flag"); }
/// <summary> /// Create the QM Func Source starting from a pre-parsed bunch of header info. /// </summary> /// <param name="f"></param> public QMFuncSource(QMFuncHeader f) { this._header = f; Name = "QMFunction".CreateUniqueVariableName(); Arguments = f.Arguments.Select(a => new QMFunctionArgument(a)); StatementBlock = null; // If this is a sequence, then we need to get a non-normal type. if (_header.IsSequence) { _sequenceType = _header.QM.GetResultType().GetGenericArguments().First(); _sequenceType = _sequenceType.MakeArrayType(); } // Now we can create the cached variables, etc. CacheVariable = DeclarableParameter.CreateDeclarableParameterExpression(ResultType); CacheVariableGood = DeclarableParameter.CreateDeclarableParameterExpression(typeof(bool)); }
/// <summary> /// The main entry point that we watch - we generate a method info stub when we need it /// from this. /// </summary> /// <param name="queryModel"></param> public override void VisitQueryModel(QueryModel queryModel) { // If the type is something that is friendly to be returned from a // method, then we should cache this guy. _qmContextStack.Push(new QMContext()); // Now, run through the query model. base.VisitQueryModel(queryModel); // And if the QM result type is something we can reasonably cache, then we should do it. // - Do not cache the outter most QM. This guy has the best place to start combining things. // - Do not cache anything that is enumerable. We'll have to deal with that later. // - Do not cache any anonymous types // - Deal with later somethign that is an iterator (used in a later loop). var isEnumerable = typeof(IEnumerable).IsAssignableFrom(queryModel.GetResultType()); var selectSequence = !queryModel.ResultOperators.Any(); if (_qmContextStack.Count > 1 && ((selectSequence && isGoodSelectSequenceType(queryModel.GetResultType())) || !isEnumerable) && !queryModel.GetResultType().IsClass ) { var qmText = FormattingQueryVisitor.Format(queryModel); if (!FoundFunctions.Where(ff => ff.QMText == qmText).Any()) { var sref = _qmContextStack.Peek(); var f = new QMFuncHeader() { QM = queryModel, QMText = qmText, Arguments = sref._arguments.Cast <object>(), IsSequence = selectSequence }; FoundFunctions.Add(f); } } // Go back to working on the previous qm. _qmContextStack.Pop(); }
/// <summary> /// Generate a function with no arguments that returns an int given that name. The /// actual statement is a very simple constant. /// </summary> /// <param name="fname"></param> /// <returns></returns> public static QMFuncSource GenerateFunction() { int[] ints = new int[10]; var qmb = new QueryModelBuilder(); qmb.AddClause(new MainFromClause("i", typeof(int), Expression.Constant(ints))); qmb.AddClause(new SelectClause(Expression.Constant(1))); qmb.AddResultOperator(new Remotion.Linq.Clauses.ResultOperators.CountResultOperator()); var h = new QMFuncHeader() { Arguments = new object[] { }, QM = qmb.Build() }; h.QMText = h.QM.ToString(); var f = new QMFuncSource(h); var p = DeclarableParameter.CreateDeclarableParameterExpression(typeof(int)); var st = new StatementAssign(p, new ValSimple("5", typeof(int))); var inlineblock = new StatementInlineBlock(); inlineblock.Add(st); inlineblock.Add(new StatementReturn(p)); f.SetCodeBody(inlineblock); return f; }
/// <summary> /// Empty ctor. /// </summary> public QMFuncSource() { this._header = null; }
/// <summary> /// The main entry point that we watch - we generate a method info stub when we need it /// from this. /// </summary> /// <param name="queryModel"></param> public override void VisitQueryModel(QueryModel queryModel) { // If the type is something that is friendly to be returned from a // method, then we should cache this guy. _qmContextStack.Push(new QMContext()); // Now, run through the query model. base.VisitQueryModel(queryModel); // And if the QM result type is something we can reasonably cache, then we should do it. // - Do not cache the outter most QM. This guy has the best place to start combining things. // - Do not cache anything that is enumerable. We'll have to deal with that later. // - Do not cache any anonymous types // - Deal with later somethign that is an iterator (used in a later loop). var isEnumerable = typeof(IEnumerable).IsAssignableFrom(queryModel.GetResultType()); var selectSequence = !queryModel.ResultOperators.Any(); if (_qmContextStack.Count > 1 && ((selectSequence && isGoodSelectSequenceType(queryModel.GetResultType())) || !isEnumerable) && !queryModel.GetResultType().IsClass ) { var qmText = FormattingQueryVisitor.Format(queryModel); if (!FoundFunctions.Where(ff => ff.QMText == qmText).Any()) { var sref = _qmContextStack.Peek(); var f = new QMFuncHeader() { QM = queryModel, QMText = qmText, Arguments = sref._arguments.Cast<object>(), IsSequence = selectSequence }; FoundFunctions.Add(f); } } // Go back to working on the previous qm. _qmContextStack.Pop(); }
private QMFuncSource[] GenerateFunction2() { var fsub = QMFuncUtils.GenerateFunction(); int[] ints = new int[10]; var h = new QMFuncHeader() { Arguments = new object[] { }, QM = new QueryModel(new MainFromClause("i", typeof(int), Expression.Constant(ints)), new SelectClause(Expression.Constant(10))) }; h.QMText = h.QM.ToString(); var f = new QMFuncSource(h); var p = DeclarableParameter.CreateDeclarableParameterExpression(typeof(int)); var st = new StatementAssign(p, new ValSimple(fsub.Name + "()", typeof(int))); var inlineblock = new StatementInlineBlock(); inlineblock.Add(st); inlineblock.Add(new StatementReturn(p)); f.SetCodeBody(inlineblock); return new QMFuncSource[] { fsub, f }; }