Ejemplo n.º 1
0
        /// <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));
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Deal with an inline conditional expression (test ? ans1 : ans2). We can translate this directly to C++, fortunately!
        /// </summary>
        /// <param name="expression"></param>
        /// <returns></returns>
        /// <remarks>
        /// We turn this into a real if statement, rather than a fake if statement. This is to try to keep any code
        /// associated with the side that won't be executed, not being executed.
        /// Note that Resolver has some good code already to special case handle a bool result.
        /// </remarks>
        protected override Expression VisitConditional(ConditionalExpression expression)
        {
            var testExpression  = expression.Test;
            var trueExpression  = expression.IfTrue;
            var falseExpression = expression.IfFalse;

            // Run the test.
            var testBoolInCode = AssignExpreaaionToEvaluationIfNeededBool(_codeEnv, _codeContext, MEFContainer, testExpression);

            // Next, do the result cache.
            var resultInCode = DeclarableParameter.CreateDeclarableParameterExpression(expression.Type);

            _codeEnv.Add(resultInCode);
            _result = resultInCode;

            // Get the result if the test is true.
            var topScope = _codeEnv.CurrentScope;

            _codeEnv.Add(new Statements.StatementFilter(testBoolInCode));
            _codeEnv.Add(new Statements.StatementAssign(resultInCode, GetExpression(trueExpression, _codeEnv, _codeContext, MEFContainer)));
            _codeEnv.CurrentScope = topScope;

            _codeEnv.Add(new Statements.StatementFilter(GetExpression(Expression.Not(testBoolInCode), _codeEnv, _codeContext, MEFContainer)));
            _codeEnv.Add(new Statements.StatementAssign(resultInCode, GetExpression(falseExpression, _codeEnv, _codeContext, MEFContainer)));
            _codeEnv.CurrentScope = topScope;

            // Result is set. Continue to process other items in the tree.
            return(expression);
        }
            /// <summary>
            /// Actually add the loop to the code and return everything!
            /// </summary>
            /// <param name="env"></param>
            /// <param name="context"></param>
            /// <param name="container"></param>
            /// <returns></returns>
            public Tuple <Expression, IDeclaredParameter> AddLoop(IGeneratedQueryCode env, ICodeContext context, CompositionContainer container)
            {
                // Create the index variable!
                var loopVariable = DeclarableParameter.CreateDeclarableParameterExpression(typeof(int));
                var floop        = new Statements.StatementForLoop(loopVariable, _maxValue, _minValue);

                env.Add(floop);

                return(Tuple.Create(loopVariable as Expression, loopVariable as IDeclaredParameter));
            }
Ejemplo n.º 4
0
            /// <summary>
            /// We only support a sub-class of expressions for now - so we'd better make sure we are protected!
            /// </summary>
            /// <param name="expression"></param>
            /// <returns></returns>
            protected override Expression VisitConditional(ConditionalExpression expression)
            {
                // We can support complex sub-expressions so long as they don't leak out of the
                // comparison.
                if (expression.Type.IsClass &&
                    (
                        CheckForSubQueries.CheckExpression(expression.IfFalse) ||
                        CheckForSubQueries.CheckExpression(expression.IfTrue))
                    )
                {
                    throw new NotSupportedException(string.Format("Complex true/false clauses in a conditional expression are not supported: '{0}'", expression.ToString()));
                }

                // If this is a class as a result, then we can't do much extra processing here. So skip.
                if (expression.Type.IsClass)
                {
                    return(base.VisitConditional(expression));
                }

                // Run the code for the test, and then create the if/then/else that will support it.
                var testExpression           = base.Visit(expression.Test);
                var testExpressionEvaluation = ExpressionToCPP.GetExpression(testExpression, GeneratedCode, CodeContext, MEFContainer);
                var testBoolInCode           = testExpressionEvaluation is DeclarableParameter p ? p : DeclarableParameter.CreateDeclarableParameterExpression(typeof(bool));

                if (testBoolInCode != testExpressionEvaluation)
                {
                    GeneratedCode.Add(testBoolInCode);
                    GeneratedCode.Add(new Statements.StatementAssign(testBoolInCode, testExpressionEvaluation));
                }

                // The result
                var conditionalResult = DeclarableParameter.CreateDeclarableParameterExpression(expression.Type);

                GeneratedCode.Add(conditionalResult);

                // Do the if true statement
                var topScope = GeneratedCode.CurrentScope;

                GeneratedCode.Add(new Statements.StatementFilter(testBoolInCode));
                var iftrueExpression = Visit(expression.IfTrue);

                GeneratedCode.Add(new Statements.StatementAssign(conditionalResult, ExpressionToCPP.GetExpression(iftrueExpression, GeneratedCode, CodeContext, MEFContainer)));
                GeneratedCode.CurrentScope = topScope;

                // Do the if false statement
                GeneratedCode.Add(new Statements.StatementFilter(ExpressionToCPP.GetExpression(Expression.Not(testBoolInCode), GeneratedCode, CodeContext, MEFContainer)));
                var ifFalseExpression = Visit(expression.IfFalse);

                GeneratedCode.Add(new Statements.StatementAssign(conditionalResult, ExpressionToCPP.GetExpression(ifFalseExpression, GeneratedCode, CodeContext, MEFContainer)));
                GeneratedCode.CurrentScope = topScope;

                // Consider this expression now transformed, so return the result, not
                // the conditional expression itself.
                return(conditionalResult);
            }
        public void TestDeclarableParameterReplacement()
        {
            var e1 = DeclarableParameter.CreateDeclarableParameterExpression(typeof(int));
            var e2 = DeclarableParameter.CreateDeclarableParameterExpression(typeof(int));

            var cc = new CodeContext();

            cc.Add(e1.ParameterName, e2);

            var expr = ParameterReplacementExpressionVisitor.ReplaceParameters(e1, cc);

            Assert.AreEqual(e2, expr, "value of translation");
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Some method is being called. Offer plug-ins a chance to transform this method call.
        /// </summary>
        /// <param name="expression"></param>
        /// <returns></returns>
        protected override Expression VisitMethodCall(MethodCallExpression expression)
        {
            _result = TypeHandlers.CodeMethodCall(expression, _codeEnv, MEFContainer);

            // Cache this so that we don't have to re-call it later (if need be) if this is a simple type.

            if (_result.Type.IsNumberType() && !_result.IsSimpleTerm())
            {
                var cachedValue = DeclarableParameter.CreateDeclarableParameterExpression(_result.Type);
                _codeEnv.Add(cachedValue);
                var assign = new Statements.StatementAssign(cachedValue, _result);
                _codeEnv.Add(assign);
                _result = cachedValue;
            }

            // Always return the expression

            return(expression);
        }
Ejemplo n.º 7
0
        /// <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);
        }
Ejemplo n.º 8
0
        /// <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);
        }