Esempio n. 1
0
        /// <summary>
        /// Generate a function call statement for the cached function we are going to emit.
        /// </summary>
        /// <param name="qmSource"></param>
        /// <returns></returns>
        private void GenerateQMFunctionCall(IQMFunctionSource qmSource)
        {
            // Assemble what we need for the sequence call.
            if (qmSource.Arguments.Any())
            {
                throw new NotImplementedException("Can only deal with internal functions with no arguments.");
            }
            // NOTE: If we add parameters then we will have to fix up dependencies below.
            var call = string.Format("{0} ()", qmSource.Name);

            if (qmSource.IsSequence)
            {
                // For the sequence we get the resulting vector array.
                var cvar = DeclarableParameter.CreateDeclarableParameterExpression(qmSource.ResultType);
                _codeEnv.Add(cvar);
                _codeEnv.Add(new StatementAssign(cvar, new ValSimple(call, qmSource.ResultType, null)));

                // Now, do a loop over it.
                var loopVar = DeclarableParameter.CreateDeclarableParameterExpression(typeof(int));
                _codeEnv.Add(new StatementForLoop(loopVar, new ValSimple(string.Format("{0}.size()", cvar.RawValue), typeof(int), new IDeclaredParameter[] { cvar })));

                // Finally, we setup the loop index variables to match what they did when we ran the function.
                var        oldLoopIndex    = qmSource.OldLoopIndexVariable;
                Expression oldLoopVariable = qmSource.OldLoopExpression;

                var arrayLookup = Expression.ArrayIndex(cvar, loopVar);
                _codeContext.SetLoopVariable(arrayLookup, loopVar);
            }
            else
            {
                // For the non-sequence this just returns a value that we need.
                _codeEnv.SetResult(Expression.Parameter(qmSource.ResultType, call));
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Generate a function call statement for the cached function we are going to emit.
        /// </summary>
        /// <param name="qmSource"></param>
        /// <returns></returns>
        private void GenerateQMFunctionCall(IQMFunctionSource qmSource)
        {
            // Assemble what we need for the sequence call.
            if (qmSource.Arguments.Any())
                throw new NotImplementedException("Can only deal with internal functions with no arguments.");
            // NOTE: If we add parameters then we will have to fix up dependencies below.
            var call = string.Format("{0} ()", qmSource.Name);

            if (qmSource.IsSequence)
            {
                // For the sequence we get the resulting vector array.
                var cvar = DeclarableParameter.CreateDeclarableParameterExpression(qmSource.ResultType);
                _codeEnv.Add(cvar);
                _codeEnv.Add(new StatementAssign(cvar, new ValSimple(call, qmSource.ResultType, null)));

                // Now, do a loop over it.
                var loopVar = DeclarableParameter.CreateDeclarableParameterExpression(typeof(int));
                _codeEnv.Add(new StatementForLoop(loopVar, new ValSimple(string.Format("{0}.size()", cvar.RawValue), typeof(int), new IDeclaredParameter[] { cvar })));

                // Finally, we setup the loop index variables to match what they did when we ran the function.
                var oldLoopIndex = qmSource.OldLoopIndexVariable;
                Expression oldLoopVariable = qmSource.OldLoopExpression;

                var arrayLookup = Expression.ArrayIndex(cvar, loopVar);
                _codeContext.SetLoopVariable(arrayLookup, loopVar);
            }
            else
            {
                // For the non-sequence this just returns a value that we need.
                _codeEnv.SetResult(Expression.Parameter(qmSource.ResultType, call));
            }
        }
Esempio n. 3
0
        /// <summary>
        /// Cache the result of a query model into a function.
        /// </summary>
        /// <param name="queryModel"></param>
        /// <param name="qmSource"></param>
        private void VisitQueryModelCache(QueryModel queryModel, IQMFunctionSource qmSource)
        {
            // If we already have the answer for this cache, then we should just re-call the routine.
            if (qmSource.StatementBlock != null)
            {
                Debug.WriteLine("Using previously cached QM result");
                GenerateQMFunctionCall(qmSource);
                return;
            }
            Debug.WriteLine("Cache: Gathering Data");
            Debug.Indent();

            // Since we don't have it cached, we need to re-run things, and carefully watch for
            // everything new that shows up. What shows up will be what we declare as the function
            // body.
            var currentScope      = _codeEnv.CurrentScope;
            var topLevelStatement = new StatementInlineBlock();

            _codeEnv.Add(topLevelStatement);
            _codeEnv.SetCurrentScopeAsResultScope();

            // If this variable has been cached, then return it. Otherwise, mark the cache as filled.
            _codeEnv.Add(new StatementFilter(qmSource.CacheVariableGood));
            _codeEnv.Add(new StatementReturn(qmSource.CacheVariable));
            _codeEnv.Pop();
            _codeEnv.Add(new StatementAssign(qmSource.CacheVariableGood, new ValSimple("true", typeof(bool), null)));

            // Now, run the code to process the query model!

            VisitQueryModelNoCache(queryModel);

            // The result is treated differently depending on it being a sequence or a single value.
            if (qmSource.IsSequence)
            {
                // Push the good values into our cache object.
                if (!(_codeContext.LoopIndexVariable is IDeclaredParameter))
                {
                    throw new InvalidOperationException("Can't deal with anythign that isn't a loop var");
                }
                _codeEnv.Add(new StatementRecordIndicies(ExpressionToCPP.GetExpression(_codeContext.LoopVariable, _codeEnv, _codeContext, MEFContainer), qmSource.CacheVariable));

                // Remember what the loop index variable is, as we are going to need it when we generate the return function!
                qmSource.SequenceVariable(_codeContext.LoopIndexVariable, _codeContext.LoopVariable);
            }
            else
            {
                // This is a specific result. Save just the result and return it.
                // Grab the result, cache it, and return it.
                var rtnExpr = ExpressionToCPP.GetExpression(_codeEnv.ResultValue, _codeEnv, _codeContext, MEFContainer);
                topLevelStatement.Add(new StatementAssign(qmSource.CacheVariable, rtnExpr));

                // If the return is a declared parameter, then it must be actually defined somewhere (we normally don't).
                var declParam = _codeEnv.ResultValue as IDeclaredParameter;
                if (declParam != null)
                {
                    topLevelStatement.Add(declParam, false);
                }
            }

            // Always return the proper value...
            topLevelStatement.Add(new StatementReturn(qmSource.CacheVariable));

            // Now extract the block of code and put it in the function block.
            _codeEnv.CurrentScope = currentScope;
            qmSource.SetCodeBody(topLevelStatement);

            // Reset our state and remove the function code. And put in the function call in its place.
            _codeEnv.Remove(topLevelStatement);
            GenerateQMFunctionCall(qmSource);

            Debug.Unindent();
        }
Esempio n. 4
0
        /// <summary>
        /// Cache the result of a query model into a function.
        /// </summary>
        /// <param name="queryModel"></param>
        /// <param name="qmSource"></param>
        private void VisitQueryModelCache(QueryModel queryModel, IQMFunctionSource qmSource)
        {
            // If we already have the answer for this cache, then we should just re-call the routine.
            if (qmSource.StatementBlock != null)
            {
                Debug.WriteLine("Using previously cached QM result");
                GenerateQMFunctionCall(qmSource);
                return;
            }
            Debug.WriteLine("Cache: Gathering Data");
            Debug.Indent();

            // Since we don't have it cached, we need to re-run things, and carefully watch for
            // everything new that shows up. What shows up will be what we declare as the function
            // body.
            var currentScope = _codeEnv.CurrentScope;
            var topLevelStatement = new StatementInlineBlock();
            _codeEnv.Add(topLevelStatement);
            _codeEnv.SetCurrentScopeAsResultScope();

            // If this variable has been cached, then return it. Otherwise, mark the cache as filled.
            _codeEnv.Add(new StatementFilter(qmSource.CacheVariableGood));
            _codeEnv.Add(new StatementReturn(qmSource.CacheVariable));
            _codeEnv.Pop();
            _codeEnv.Add(new StatementAssign(qmSource.CacheVariableGood, new ValSimple("true", typeof(bool), null)));

            // Now, run the code to process the query model!

            VisitQueryModelNoCache(queryModel);

            // The result is treated differently depending on it being a sequence or a single value.
            if (qmSource.IsSequence)
            {
                // Push the good values into our cache object.
                if (!(_codeContext.LoopIndexVariable is IDeclaredParameter))
                    throw new InvalidOperationException("Can't deal with anythign that isn't a loop var");
                _codeEnv.Add(new StatementRecordIndicies(ExpressionToCPP.GetExpression(_codeContext.LoopVariable, _codeEnv, _codeContext, MEFContainer), qmSource.CacheVariable));

                // Remember what the loop index variable is, as we are going to need it when we generate the return function!
                qmSource.SequenceVariable(_codeContext.LoopIndexVariable, _codeContext.LoopVariable);
            }
            else
            {
                // This is a specific result. Save just the result and return it.
                // Grab the result, cache it, and return it.
                var rtnExpr = ExpressionToCPP.GetExpression(_codeEnv.ResultValue, _codeEnv, _codeContext, MEFContainer);
                topLevelStatement.Add(new StatementAssign(qmSource.CacheVariable, rtnExpr));

                // If the return is a declared parameter, then it must be actually defined somewhere (we normally don't).
                var declParam = _codeEnv.ResultValue as IDeclaredParameter;
                if (declParam != null)
                    topLevelStatement.Add(declParam, false);
            }

            // Always return the proper value...
            topLevelStatement.Add(new StatementReturn(qmSource.CacheVariable));

            // Now extract the block of code and put it in the function block.
            _codeEnv.CurrentScope = currentScope;
            qmSource.SetCodeBody(topLevelStatement);

            // Reset our state and remove the function code. And put in the function call in its place.
            _codeEnv.Remove(topLevelStatement);
            GenerateQMFunctionCall(qmSource);

            Debug.Unindent();
        }