Exemplo n.º 1
0
        private static Expression CreateReadAccessor(Expression rowData, string valueArrayName, int ordinalValue, DbType dbType, string subFieldName)
        {
            var ordinal        = Expression.Constant(ordinalValue);
            var notnulldata    = Expression.Field(rowData, "NotNulls");
            var arrayindexdata = Expression.Field(rowData, "FieldArrayIndexes");

            var        underlyingType = DeriveSystemType(dbType);
            var        indexinarray   = Expression.ArrayIndex(arrayindexdata, ordinal);
            Expression fieldValue     = Expression.ArrayIndex(Expression.Field(rowData, valueArrayName), indexinarray);

            var isnotnull = Expression.Call(typeof(BitVector), "Get", null, notnulldata, ordinal);

            // value types use Nullable(T) to pass nullability information
            if (fieldValue.Type.IsValueType)
            {
                var nullabletype = typeof(UnboxableNullable <>).MakeGenericType(underlyingType);

                if (subFieldName != null)
                {
                    fieldValue = Expression.Field(fieldValue, subFieldName);
                }

                return(Expression.Condition(
                           isnotnull,
                           ExpressionTreeExtensions.MakeNewNullable(nullabletype, fieldValue),
                           ExpressionTreeExtensions.MakeNewNullable(nullabletype)));
            }

            // null values of reference types simply take value of null
            return(Expression.Condition(isnotnull, fieldValue, Expression.Constant(null, fieldValue.Type)));
        }
 private static Expression PredefinedAtom_Null(ParseTreeNode root, CompilerState state)
 {
     // clients are responsible for translating this expression into appropriate type
     return(ExpressionTreeExtensions.MakeNewNullable(typeof(UnboxableNullable <ExpressionTreeExtensions.VoidTypeMarker>)));
 }
Exemplo n.º 3
0
        private Expression BuildSwitchStatementExpression(CompilerState state, ParseTreeNode caseVariableNode, ParseTreeNode whenThenListNode, Expression caseDefault)
        {
            var switchVariable = Analyze(caseVariableNode.ChildNodes[0], state);

            switchVariable.RequireNonVoid(caseVariableNode.ChildNodes[0]);

            if (switchVariable is ConstantExpression)
            {
                throw new CompilationException("CASE variable should not be a constant value", caseVariableNode);
            }

            var        cases              = new List <Tuple <Expression[], Expression, ParseTreeNode> >(whenThenListNode.ChildNodes.Count);
            Expression firstNonVoidThen   = null;
            var        mustReturnNullable = false;

            foreach (var caseWhenThenNode in whenThenListNode.ChildNodes)
            {
                caseWhenThenNode.RequireChildren(4);
                var whenNodesRoot = ExpressionTreeExtensions.UnwindTupleExprList(caseWhenThenNode.RequireChild(null, 1));
                var thenNode      = caseWhenThenNode.RequireChild(null, 3);

                IList <ParseTreeNode> whenNodes;
                if (whenNodesRoot.Term.Name == "exprList")
                {
                    whenNodes = whenNodesRoot.ChildNodes;
                }
                else
                {
                    whenNodes = new[] { whenNodesRoot };
                }

                var when = new Expression[whenNodes.Count];
                for (var i = 0; i < whenNodes.Count; i++)
                {
                    var whenNode = whenNodes[i];
                    when[i] = Analyze(whenNode, state);

                    if (!when[i].IsVoid() && !(when[i] is ConstantExpression))
                    {
                        throw new CompilationException("CASE statement with a test variable requires WHEN clauses to be constant values", whenNode);
                    }

                    Expression adjusted;
                    if (ExpressionTreeExtensions.TryAdjustReturnType(whenNode, when[i], switchVariable.Type, out adjusted))
                    {
                        when[i] = adjusted;
                    }
                    else
                    {
                        throw new CompilationException(
                                  string.Format(
                                      "Could not adjust WHEN value type {0} to CASE argument type {1}",
                                      when[i].Type.FullName, switchVariable.Type.FullName), whenNode);
                    }
                }

                var then = Analyze(thenNode, state);
                cases.Add(new Tuple <Expression[], Expression, ParseTreeNode>(when, then, thenNode));

                if (then.IsVoid())
                {
                    // if there is at least one "void" return value, resulting value must be nullable
                    mustReturnNullable = true;
                }
                else if (firstNonVoidThen == null)
                {
                    firstNonVoidThen = then;
                }
            }

            if (firstNonVoidThen == null && !caseDefault.IsVoid())
            {
                firstNonVoidThen = caseDefault;
            }

            var adjustedCaseDefault = caseDefault;

            // now try to adjust whatever remaining VOID "then-s" to the first-met non-void then
            // if all THENs are void, then just leave it as-is - type will be adjusted by caller
            if (firstNonVoidThen != null)
            {
                if (mustReturnNullable && firstNonVoidThen.Type.IsValueType && !firstNonVoidThen.IsNullableType())
                {
                    firstNonVoidThen = ExpressionTreeExtensions.MakeNewNullable(
                        typeof(UnboxableNullable <>).MakeGenericType(firstNonVoidThen.Type),
                        firstNonVoidThen);
                }

                for (var i = 0; i < cases.Count; i++)
                {
                    var thenNode = cases[i].Item3;
                    var then     = cases[i].Item2;

                    if (!ReferenceEquals(then, firstNonVoidThen) && then.IsVoid())
                    {
                        Expression adjusted;
                        if (ExpressionTreeExtensions.TryAdjustReturnType(thenNode, then, firstNonVoidThen.Type, out adjusted))
                        {
                            cases[i] = new Tuple <Expression[], Expression, ParseTreeNode>(cases[i].Item1, adjusted, cases[i].Item3);
                        }
                        else
                        {
                            throw new CompilationException(
                                      string.Format(
                                          "Could not adjust THEN value type {0} to first-met THEN value type {1}",
                                          then.Type.FullName, firstNonVoidThen.Type.FullName), thenNode);
                        }
                    }
                }

                if (caseDefault != null &&
                    !ExpressionTreeExtensions.TryAdjustReturnType(caseVariableNode, caseDefault, firstNonVoidThen.Type, out adjustedCaseDefault))
                {
                    throw new CompilationException(
                              string.Format(
                                  "Could not adjust CASE default value's type {0} to first-met THEN value type {1}",
                                  caseDefault.Type.FullName, firstNonVoidThen.Type.FullName), caseVariableNode);
                }
            }

            if (adjustedCaseDefault == null)
            {
                adjustedCaseDefault = ExpressionTreeExtensions.GetDefaultExpression(
                    firstNonVoidThen == null
                        ? typeof(UnboxableNullable <ExpressionTreeExtensions.VoidTypeMarker>)
                        : firstNonVoidThen.Type);
            }

            return(Expression.Switch(
                       switchVariable, adjustedCaseDefault, null,
                       cases.Select(x => Expression.SwitchCase(x.Item2, x.Item1))));
        }