Esempio n. 1
0
        protected override bool EmitInternal(ConditionalExpression node, EmittingContext context, GroboIL.Label returnDefaultValueLabel, ResultType whatReturn, bool extend, out Type resultType)
        {
            var test                = node.Test;
            var ifTrue              = node.IfTrue;
            var ifFalse             = node.IfFalse;
            var ifTrueBranchIsEmpty = ifTrue.NodeType == ExpressionType.Default && ifTrue.Type == typeof(void);

            if (ifTrueBranchIsEmpty)
            {
                test = Expression.Not(test);
                var temp = ifTrue;
                ifTrue  = ifFalse;
                ifFalse = temp;
            }
            var  result          = false;
            var  il              = context.Il;
            var  testIsNullLabel = il.DefineLabel("testIsNull");
            Type testType;
            var  testIsNullLabelUsed = ExpressionEmittersCollection.Emit(test, context, testIsNullLabel, out testType);

            if (testType == typeof(bool?))
            {
                context.ConvertFromNullableBoolToBool();
            }
            var ifFalseLabel = il.DefineLabel("ifFalse");

            il.Brfalse(ifFalseLabel);
            Type ifTrueType;

            result |= ExpressionEmittersCollection.Emit(ifTrue, context, returnDefaultValueLabel, whatReturn, extend, out ifTrueType);
            if (node.Type == typeof(void) && ifTrueType != typeof(void))
            {
                using (var temp = context.DeclareLocal(ifTrueType))
                    il.Stloc(temp);
            }
            var doneLabel = il.DefineLabel("done");

            il.Br(doneLabel);
            if (testIsNullLabelUsed)
            {
                context.MarkLabelAndSurroundWithSP(testIsNullLabel);
                il.Pop();
            }
            context.MarkLabelAndSurroundWithSP(ifFalseLabel);
            Type ifFalseType;

            result |= ExpressionEmittersCollection.Emit(ifFalse, context, returnDefaultValueLabel, whatReturn, extend, out ifFalseType);
            if (node.Type == typeof(void) && ifFalseType != typeof(void))
            {
                using (var temp = context.DeclareLocal(ifFalseType))
                    il.Stloc(temp);
            }
            context.MarkLabelAndSurroundWithSP(doneLabel);
            if (ifTrueType != typeof(void) && ifFalseType != typeof(void) && ifTrueType != ifFalseType)
            {
                throw new InvalidOperationException(string.Format("ifTrue type '{0}' is not equal to ifFalse type '{1}'", ifTrueType, ifFalseType));
            }
            resultType = node.Type == typeof(void) ? typeof(void) : ifTrueType;
            return(result);
        }
Esempio n. 2
0
        protected override bool EmitInternal(BinaryExpression node, EmittingContext context, GroboIL.Label returnDefaultValueLabel, ResultType whatReturn, bool extend, out Type resultType)
        {
            var          il     = context.Il;
            var          left   = node.Left;
            var          right  = node.Right;
            bool         result = false;
            Type         assigneeType;
            AssigneeKind assigneeKind;
            bool         checkNullReferences = context.Options.HasFlag(CompilerOptions.CheckNullReferences);

            extend |= context.Options.HasFlag(CompilerOptions.ExtendOnAssign);

            GroboIL.Label assigneeIsNullLabel     = null;
            bool          assigneeIsNullLabelUsed = false;

            switch (left.NodeType)
            {
            case ExpressionType.Parameter:
                assigneeType        = null;
                assigneeKind        = AssigneeKind.Parameter;
                checkNullReferences = false;
                break;

            case ExpressionType.MemberAccess:
                var memberExpression = (MemberExpression)left;
                if (memberExpression.Expression == null)
                {
                    assigneeType        = null;
                    assigneeKind        = memberExpression.Member is FieldInfo ? AssigneeKind.StaticField : AssigneeKind.StaticProperty;
                    checkNullReferences = false;
                }
                else
                {
                    bool closureAssign = memberExpression.Expression == context.ParsedLambda.ClosureParameter || memberExpression.Expression.Type.IsStaticClosure();
                    checkNullReferences &= !closureAssign;
                    if (node.NodeType != ExpressionType.Assign && context.CanReturn)
                    {
                        result |= ExpressionEmittersCollection.Emit(memberExpression.Expression, context, returnDefaultValueLabel, ResultType.ByRefValueTypesOnly, extend, out assigneeType);
                    }
                    else
                    {
                        assigneeIsNullLabel     = !closureAssign && context.CanReturn ? il.DefineLabel("assigneeIsNull") : null;
                        assigneeIsNullLabelUsed = ExpressionEmittersCollection.Emit(memberExpression.Expression, context, assigneeIsNullLabel, ResultType.ByRefValueTypesOnly, extend, out assigneeType);
                    }
                    assigneeKind = memberExpression.Member is FieldInfo ? AssigneeKind.InstanceField : AssigneeKind.InstanceProperty;
                }
                break;

            case ExpressionType.Index:
                var indexExpression = (IndexExpression)left;
                if (indexExpression.Object == null)
                {
                    throw new InvalidOperationException("Indexing of null object is invalid");
                }
                if ((indexExpression.Object.Type.IsArray && indexExpression.Object.Type.GetArrayRank() == 1) || indexExpression.Object.Type.IsList())
                {
                    if (node.NodeType != ExpressionType.Assign && context.CanReturn)
                    {
                        result |= ArrayIndexExpressionEmitter.Emit(indexExpression.Object, indexExpression.Arguments.Single(), context, returnDefaultValueLabel, ResultType.ByRefAll, extend, out assigneeType);
                        checkNullReferences = false;
                    }
                    else
                    {
                        assigneeIsNullLabel     = context.CanReturn ? il.DefineLabel("assigneeIsNull") : null;
                        assigneeIsNullLabelUsed = ArrayIndexExpressionEmitter.Emit(indexExpression.Object, indexExpression.Arguments.Single(), context, assigneeIsNullLabel, ResultType.ByRefAll, extend, out assigneeType);
                    }
                    assigneeKind = AssigneeKind.SimpleArray;
                }
                else
                {
                    if (node.NodeType != ExpressionType.Assign && context.CanReturn)
                    {
                        result |= ExpressionEmittersCollection.Emit(indexExpression.Object, context, returnDefaultValueLabel, ResultType.ByRefValueTypesOnly, extend, out assigneeType);
                    }
                    else
                    {
                        assigneeIsNullLabel     = context.CanReturn ? il.DefineLabel("assigneeIsNull") : null;
                        assigneeIsNullLabelUsed = ExpressionEmittersCollection.Emit(indexExpression.Object, context, assigneeIsNullLabel, ResultType.ByRefValueTypesOnly, extend, out assigneeType);
                    }
                    assigneeKind = indexExpression.Indexer != null ? AssigneeKind.IndexedProperty : AssigneeKind.MultiDimensionalArray;
                }
                break;

            default:
                throw new InvalidOperationException("Unable to assign to an expression of type '" + left.NodeType + "'");
            }
            if (assigneeType != null && assigneeType.IsValueType)
            {
                using (var temp = context.DeclareLocal(assigneeType))
                {
                    il.Stloc(temp);
                    il.Ldloca(temp);
                }
                assigneeType = assigneeType.MakeByRefType();
            }

            if (node.NodeType == ExpressionType.Assign)
            {
                if (!checkNullReferences)
                {
                    if (whatReturn == ResultType.Void)
                    {
                        EmitAssign(assigneeKind, left, context, null, right);
                    }
                    else
                    {
                        if (assigneeKind == AssigneeKind.Parameter)
                        {
                            EmitAssign(assigneeKind, left, context, null, right);
                            EmitAccess(assigneeKind, left, context);
                        }
                        else
                        {
                            context.EmitLoadArguments(right);
                            using (var value = context.DeclareLocal(right.Type))
                            {
                                il.Stloc(value);
                                EmitAssign(assigneeKind, left, context, null, value);
                                il.Ldloc(value);
                            }
                        }
                    }
                }
                else
                {
                    if (whatReturn == ResultType.Void)
                    {
                        il.Dup();
                        var skipAssigneeLabel = il.DefineLabel("skipAssignee");
                        il.Brfalse(skipAssigneeLabel);
                        EmitAssign(assigneeKind, left, context, null, right);
                        var returnLabel = il.DefineLabel("return");
                        il.Br(returnLabel);
                        context.MarkLabelAndSurroundWithSP(skipAssigneeLabel);
                        il.Pop();
                        context.MarkLabelAndSurroundWithSP(returnLabel);
                    }
                    else
                    {
                        // load value
                        var  rightIsNullLabel = context.CanReturn ? il.DefineLabel("rightIsNull") : null;
                        Type valueType;
                        bool labelUsed = ExpressionEmittersCollection.Emit(right, context, rightIsNullLabel, out valueType); // stack: [address, value]
                        if (right.Type == typeof(bool) && valueType == typeof(bool?))
                        {
                            context.ConvertFromNullableBoolToBool();
                        }
                        if (labelUsed && context.CanReturn)
                        {
                            context.EmitReturnDefaultValue(right.Type, rightIsNullLabel, il.DefineLabel("rightIsNotNull"));
                        }
                        using (var value = context.DeclareLocal(right.Type))
                        {
                            il.Stloc(value);
                            il.Dup();
                            var skipAssigneeLabel = il.DefineLabel("skipAssignee");
                            il.Brfalse(skipAssigneeLabel);
                            EmitAssign(assigneeKind, left, context, null, value);
                            var returnValueLabel = il.DefineLabel("returnValue");
                            il.Br(returnValueLabel);
                            context.MarkLabelAndSurroundWithSP(skipAssigneeLabel);
                            il.Pop();
                            context.MarkLabelAndSurroundWithSP(returnValueLabel);
                            il.Ldloc(value);
                        }
                    }
                }
            }
            else
            {
                if (checkNullReferences)
                {
                    il.Dup();
                    il.Brfalse(returnDefaultValueLabel);
                    result = true;
                }
                if (assigneeType != null)
                {
                    il.Dup();
                }
                object[] arguments = EmitAccess(assigneeKind, left, context);
                context.EmitLoadArguments(right);
                context.EmitArithmeticOperation(GetOp(node.NodeType), left.Type, left.Type, right.Type, node.Method);
                if (whatReturn == ResultType.Void)
                {
                    EmitAssign(assigneeKind, left, context, arguments);
                }
                else
                {
                    if (assigneeKind == AssigneeKind.Parameter)
                    {
                        EmitAssign(assigneeKind, left, context, arguments);
                        EmitAccess(assigneeKind, left, context);
                    }
                    else
                    {
                        using (var temp = context.DeclareLocal(left.Type))
                        {
                            il.Stloc(temp);
                            EmitAssign(assigneeKind, left, context, arguments, temp);
                            il.Ldloc(temp);
                        }
                    }
                }
            }
            resultType = whatReturn == ResultType.Void ? typeof(void) : left.Type;
            if (assigneeIsNullLabelUsed)
            {
                context.EmitReturnDefaultValue(resultType, assigneeIsNullLabel, il.DefineLabel("assigneeIsNotNull"));
            }
            return(result);
        }
        protected override bool EmitInternal(BlockExpression node, EmittingContext context, GroboIL.Label returnDefaultValueLabel, ResultType whatReturn, bool extend, out Type resultType)
        {
            var variables = node.Variables.Where(variable => !context.VariablesToLocals.ContainsKey(variable)).ToArray();

            foreach (var variable in variables)
            {
                var local = string.IsNullOrEmpty(variable.Name)
                                ? context.Il.DeclareLocal(variable.Type)
                                : context.Il.DeclareLocal(variable.Type, variable.Name, appendUniquePrefix: false);
                if (context.DebugInfoGenerator != null)
                {
                    local.SetLocalSymInfo(local.Name);
                }
                context.VariablesToLocals.Add(variable, local);
                context.Variables.Push(variable);
            }
            resultType = typeof(void);
            for (var index = 0; index < node.Expressions.Count; index++)
            {
                var expression       = node.Expressions[index];
                var il               = context.Il;
                var valueIsNullLabel = il.DefineLabel("valueIsNull");
                var labelUsed        = ExpressionEmittersCollection.Emit(expression, context, valueIsNullLabel, index < node.Expressions.Count - 1 ? ResultType.Void : whatReturn, extend, out resultType);
                if (resultType != typeof(void) && index < node.Expressions.Count - 1)
                {
                    // eat results of all expressions except the last one
                    if (resultType.IsStruct())
                    {
                        using (var temp = context.DeclareLocal(resultType))
                            context.Il.Stloc(temp);
                    }
                    else
                    {
                        context.Il.Pop();
                    }
                }
                if (labelUsed)
                {
                    var doneLabel = il.DefineLabel("done");
                    il.Br(doneLabel);
                    context.MarkLabelAndSurroundWithSP(valueIsNullLabel);
                    il.Pop();
                    if (resultType != typeof(void) && index == node.Expressions.Count - 1)
                    {
                        // return default value for the last expression in the block
                        context.EmitLoadDefaultValue(resultType);
                    }
                    context.MarkLabelAndSurroundWithSP(doneLabel);
                }
            }
            if (node.Type == typeof(bool) && resultType == typeof(bool?))
            {
                resultType = typeof(bool);
                context.ConvertFromNullableBoolToBool();
            }
            else if (node.Type == typeof(void) && resultType != typeof(void))
            {
                // eat result of the last expression if the result of block is void
                if (resultType.IsStruct())
                {
                    using (var temp = context.DeclareLocal(resultType))
                        context.Il.Stloc(temp);
                }
                else
                {
                    context.Il.Pop();
                }
                resultType = typeof(void);
            }
            foreach (var variable in variables)
            {
                context.VariablesToLocals.Remove(variable);
                context.Variables.Pop();
            }
            return(false);
        }