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>))); }
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)))); }