/// <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; }
static string GeneratePartialClassContextStub(ICodeContext context) { var member = context.CurrentMember; if (member == null) return ""; var builder = new TypeSystemAstBuilder(); MethodDeclaration decl; if (member is IMethod) { // If it's a method, convert it directly (including parameters + type parameters) decl = (MethodDeclaration)builder.ConvertEntity(member); } else { // Otherwise, create a method anyways, and copy the parameters decl = new MethodDeclaration(); if (member is IParameterizedMember) { foreach (var p in ((IParameterizedMember)member).Parameters) { decl.Parameters.Add(builder.ConvertParameter(p)); } } } decl.Name = "__DebuggerStub__"; decl.ReturnType = builder.ConvertType(member.ReturnType); decl.Modifiers = member.IsStatic ? Modifiers.Static : Modifiers.None; // Make the method look like an explicit interface implementation so that it doesn't appear in CC decl.PrivateImplementationType = new SimpleType("__DummyType__"); decl.Body = GenerateBodyFromContext(builder, context.LocalVariables.ToArray()); return WrapInType(context.CurrentTypeDefinition, decl).ToString(); }
/// <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); }
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 expressoins we know. /// </summary> /// <param name="expr"></param> /// <param name="result"></param> /// <param name="gc"></param> /// <returns></returns> public Expression ProcessMethodCall(MethodCallExpression expr, IGeneratedQueryCode gc, ICodeContext context, CompositionContainer container) { if (expr == (MethodCallExpression)null) throw new ArgumentNullException("expr"); var h = FindHandler(expr.Method.DeclaringType); return h.ProcessMethodCall(expr, gc, context, 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 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> /// 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); }
public override ICodeCompletionBinding CreateCompletionBinding(string expressionToComplete, ICodeContext context) { if (context == null) throw new ArgumentNullException("context"); string content = GeneratePartialClassContextStub(context); const string caretPoint = "$__Caret_Point__$;"; int caretOffset = content.IndexOf(caretPoint, StringComparison.Ordinal) + expressionToComplete.Length; SD.Log.DebugFormatted("context used for dot completion: {0}", content.Replace(caretPoint, "$" + expressionToComplete + "|$")); var doc = new ReadOnlyDocument(content.Replace(caretPoint, expressionToComplete)); return new CSharpCompletionBinding(context, doc.GetLocation(caretOffset), doc.CreateSnapshot()); }
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> /// 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); }
/// <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; }
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; }
/// <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> /// 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> /// 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; }
public static CSharpCompletionContext Get(ITextEditor editor, ICodeContext context, TextLocation currentLocation, ITextSource fileContent) { IDocument document = new ReadOnlyDocument(fileContent); var projectContent = context.Compilation.MainAssembly.UnresolvedAssembly as IProjectContent; if (projectContent == null) return null; CSharpParser parser = new CSharpParser(); parser.GenerateTypeSystemMode = false; SyntaxTree cu = parser.Parse(fileContent, Path.GetRandomFileName() + ".cs"); cu.Freeze(); CSharpUnresolvedFile unresolvedFile = cu.ToTypeSystem(); ICompilation compilation = projectContent.AddOrUpdateFiles(unresolvedFile).CreateCompilation(SD.ParserService.GetCurrentSolutionSnapshot()); return new CSharpCompletionContext(editor, EmptyList<string>.Instance, compilation, projectContent, document, unresolvedFile, currentLocation); }
/// <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> /// 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> /// This will be handled later on, by the general infrastructure. /// </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) { return(null); }
public CSharpCompletionBinding(ICodeContext context, TextLocation currentLocation, ITextSource fileContent) { this.context = context; this.currentLocation = currentLocation; this.fileContent = fileContent; }
/// <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(); }
/// <summary> /// Code up the min/max result operators. We run the loop out, and then /// we return the result whatever it is. We only work when the type is /// something simple we can deal with! /// </summary> /// <param name="resultOperator"></param> /// <param name="queryModel"></param> /// <param name="_codeEnv"></param> /// <param name="_codeContext"></param> /// <param name="container"></param> /// <returns></returns> public Expression ProcessResultOperator(ResultOperatorBase resultOperator, QueryModel queryModel, IGeneratedQueryCode gc, ICodeContext cc, CompositionContainer container) { /// /// Some argument checking /// if (cc == null) { throw new ArgumentNullException("cc"); } if (gc == null) { throw new ArgumentNullException("gc"); } if (gc.Depth == 1) { throw new ArgumentException("The Max/Min operators can't be used as result operators for a query - they can only be used in a sub-query"); } /// /// Is it min or max? /// var minOperator = resultOperator as MinResultOperator; var maxOperator = resultOperator as MaxResultOperator; if (minOperator == null && maxOperator == null) { throw new InvalidOperationException("Should always have min or max operator!"); } bool doMax = maxOperator != null; bool returnDefaultValue = false; if (doMax) { returnDefaultValue = maxOperator.ReturnDefaultWhenEmpty; } else { returnDefaultValue = minOperator.ReturnDefaultWhenEmpty; } /// /// Next, look at the type of the current result that is running. /// var valueExpr = queryModel.SelectClause.Selector; if (!TimeCanBeCompared(valueExpr.Type)) { throw new ArgumentException(string.Format("I don't know how to fix the min or max of a sequence of '{0}'s", cc.LoopVariable.Type.Name)); } /// /// Now, declare two variables, one bool which gets set when we get the first value, /// and the other to hold the min/max value! Note that we initalize the variable to /// the proper type. We don't declare minmax holder - as it may end up be used /// externally. /// var vIsFilled = DeclarableParameter.CreateDeclarableParameterExpression(typeof(bool)); vIsFilled.InitialValue = new ValSimple("false", typeof(bool), null); var vMaxMin = DeclarableParameter.CreateDeclarableParameterExpression(valueExpr.Type); vMaxMin.InitialValue = new ValSimple("0", typeof(int), null); gc.AddOutsideLoop(vIsFilled); /// /// The expression we want to mimize or maximize /// var exprToMinOrMaximize = ExpressionToCPP.GetExpression(valueExpr, gc, cc, container); /// /// Now, we just have to put the x-checks in there. /// var ifStatement = new Statements.StatementMinMaxTest(vIsFilled, vMaxMin, exprToMinOrMaximize, doMax); gc.Add(ifStatement); return(vMaxMin); }
public IValue ProcessMemberReference(MemberExpression expr, IGeneratedQueryCode gc, ICodeContext cc, System.ComponentModel.Composition.Hosting.CompositionContainer container) { return(null); }
public Expression ProcessResultOperator(Remotion.Linq.Clauses.ResultOperatorBase resultOperator, Remotion.Linq.QueryModel queryModel, IGeneratedQueryCode _codeEnv, ICodeContext codeContext, CompositionContainer container) { throw new NotImplementedException(); }
/// <summary> /// Performs all expression subsitutions known by the code context on the input. It does not /// touch the input - but returns a new IValue. Types are not tracked. /// </summary> /// <param name="input"></param> /// <param name="cc"></param> /// <returns></returns> /// <remarks> /// This exists because sometimes you need to do this sort of replacement when dealing with complex /// expressions that don't translated to C# easily. In partiuclar, for example, the iterator expressions /// that are used to move through maps in the Group By operators. Otherwise, the regular GetExpression would /// do this just fine. /// </remarks> public static IValue PerformAllSubstitutions(this IValue input, ICodeContext cc) { var vFinder = new Regex(@"\b(?<vname>[\w]*)\b"); string v = input.RawValue; bool subDone = true; int count = 0; while (subDone) { count++; if (count > 100) throw new InvalidOperationException(string.Format("Unable to translate '{0}' due to too many sutstitutions.", input.RawValue)); subDone = false; foreach (Match match in vFinder.Matches(v)) { var vname = match.Groups["vname"].Value; var r = cc.GetReplacement(vname); if (r != null) { v = Regex.Replace(v, string.Format(@"\b{0}\b", vname), r.ParameterName()); subDone = true; } } } if (count == 1) return input; return new ValSimple(v, input.Type, input.Dependants); }
public Expression ProcessMethodCall(MethodCallExpression expr, IGeneratedQueryCode gc, ICodeContext context, System.ComponentModel.Composition.Hosting.CompositionContainer container) { return(expr); }
public Tuple<Expression, IDeclaredParameter> AddLoop(IGeneratedQueryCode env, ICodeContext context, CompositionContainer container) { return null; }
ICodeCompletionBinding ILanguageBinding.CreateCompletionBinding(string expressionToComplete, ICodeContext context) { return null; }
public Tuple<bool, Expression> ProcessIdentityQuery(ResultOperatorBase resultOperator, QueryModel queryModel, IGeneratedQueryCode _codeEnv, ICodeContext _codeContext, CompositionContainer container) { return null; }
public Expression ProcessMethodCall(MethodCallExpression expr, IGeneratedQueryCode gc, ICodeContext context, CompositionContainer container) { throw new NotImplementedException(); }
/// <summary> /// Code up the min/max result operators. We run the loop out, and then /// we return the result whatever it is. We only work when the type is /// something simple we can deal with! /// </summary> /// <param name="resultOperator"></param> /// <param name="queryModel"></param> /// <param name="_codeEnv"></param> /// <param name="_codeContext"></param> /// <param name="container"></param> /// <returns></returns> public Expression ProcessResultOperator(ResultOperatorBase resultOperator, QueryModel queryModel, IGeneratedQueryCode gc, ICodeContext cc, CompositionContainer container) { /// /// Some argument checking /// if (cc == null) throw new ArgumentNullException("cc"); if (gc == null) throw new ArgumentNullException("gc"); if (gc.Depth == 1) throw new ArgumentException("The Max/Min operators can't be used as result operators for a query - they can only be used in a sub-query"); /// /// Is it min or max? /// var minOperator = resultOperator as MinResultOperator; var maxOperator = resultOperator as MaxResultOperator; if (minOperator == null && maxOperator == null) throw new InvalidOperationException("Should always have min or max operator!"); bool doMax = maxOperator != null; bool returnDefaultValue = false; if (doMax) returnDefaultValue = maxOperator.ReturnDefaultWhenEmpty; else returnDefaultValue = minOperator.ReturnDefaultWhenEmpty; /// /// Next, look at the type of the current result that is running. /// var valueExpr = queryModel.SelectClause.Selector; if (!TimeCanBeCompared(valueExpr.Type)) throw new ArgumentException(string.Format("I don't know how to fix the min or max of a sequence of '{0}'s", cc.LoopVariable.Type.Name)); /// /// Now, declare two variables, one bool which gets set when we get the first value, /// and the other to hold the min/max value! Note that we initalize the variable to /// the proper type. We don't declare minmax holder - as it may end up be used /// externally. /// var vIsFilled = DeclarableParameter.CreateDeclarableParameterExpression(typeof(bool)); vIsFilled.InitialValue = new ValSimple("false", typeof(bool), null); var vMaxMin = DeclarableParameter.CreateDeclarableParameterExpression(valueExpr.Type); vMaxMin.InitialValue = new ValSimple("0", typeof(int), null); gc.AddOutsideLoop(vIsFilled); /// /// The expression we want to mimize or maximize /// var exprToMinOrMaximize = ExpressionToCPP.GetExpression(valueExpr, gc, cc, container); /// /// Now, we just have to put the x-checks in there. /// var ifStatement = new Statements.StatementMinMaxTest(vIsFilled, vMaxMin, exprToMinOrMaximize, doMax); gc.Add(ifStatement); return vMaxMin; }
/// <summary> /// The AsQueriable, for us, is a no-op. We will just pass things 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 _codeEnv, ICodeContext _codeContext, CompositionContainer container) { }
/// <summary> /// A method call is our bread and butter. However, there is no internal translation to be done, so we can wait /// until the end of the translation process when it is time to turn it into real IValue. /// </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) { return expr; }
public IValue ProcessMemberReference(MemberExpression expr, IGeneratedQueryCode gc, ICodeContext cc, CompositionContainer container) { throw new NotImplementedException(); }
public Tuple <bool, Expression> ProcessIdentityQuery(ResultOperatorBase resultOperator, QueryModel queryModel, IGeneratedQueryCode _codeEnv, ICodeContext _codeContext, CompositionContainer container) { return(null); }