예제 #1
0
        protected override NodeBase Expand(Context ctx, bool mustReturn)
        {
            var leftType = LeftOperand.Resolve(ctx, mustReturn);

            // create a lambda expression that passes the result of left function to the right one
            if (leftType.IsCallableType())
            {
                var leftVar      = ctx.Unique.TempVariableName();
                var rightVar     = ctx.Unique.TempVariableName();
                var delegateType = ReflectionHelper.WrapDelegate(leftType);
                var argDefs      = delegateType.ArgumentTypes.Select(x => Expr.Arg(ctx.Unique.AnonymousArgName(), x.FullName)).ToArray();

                return(Expr.Lambda(
                           argDefs,
                           Expr.Block(
                               Expr.Let(leftVar, LeftOperand),
                               Expr.Let(rightVar, RightOperand),
                               Expr.Invoke(
                                   Expr.Get(rightVar),
                                   Expr.Invoke(
                                       Expr.Get(leftVar),
                                       argDefs.Select(x => Expr.Get(x.Name)).ToArray()
                                       )
                                   )
                               )
                           ));
            }

            return(base.Expand(ctx, mustReturn));
        }
예제 #2
0
        protected override NodeBase Expand(Context ctx, bool mustReturn)
        {
            if (Resolve(ctx).IsNullableType())
            {
                var leftNullable  = LeftOperand.Resolve(ctx).IsNullableType();
                var rightNullable = RightOperand.Resolve(ctx).IsNullableType();
                if (leftNullable && rightNullable)
                {
                    return(Expr.If(
                               Expr.And(
                                   Expr.GetMember(LeftOperand, "HasValue"),
                                   Expr.GetMember(RightOperand, "HasValue")
                                   ),
                               Expr.Block(
                                   RecreateSelfWithArgs(
                                       Expr.GetMember(LeftOperand, "Value"),
                                       Expr.GetMember(RightOperand, "Value")
                                       )
                                   ),
                               Expr.Block(Expr.Null())
                               ));
                }

                if (leftNullable)
                {
                    return(Expr.If(
                               Expr.GetMember(LeftOperand, "HasValue"),
                               Expr.Block(
                                   RecreateSelfWithArgs(
                                       Expr.GetMember(LeftOperand, "Value"),
                                       RightOperand
                                       )
                                   ),
                               Expr.Block(Expr.Null())
                               ));
                }

                if (rightNullable)
                {
                    return(Expr.If(
                               Expr.GetMember(RightOperand, "HasValue"),
                               Expr.Block(
                                   RecreateSelfWithArgs(
                                       LeftOperand,
                                       Expr.GetMember(RightOperand, "Value")
                                       )
                                   ),
                               Expr.Block(Expr.Null())
                               ));
                }
            }

            return(base.Expand(ctx, mustReturn));
        }
예제 #3
0
        /// <summary>
        /// Loads both arguments and converts them to the biggest common type.
        /// </summary>
        protected void LoadAndConvertNumerics(Context ctx, Type type = null)
        {
            var left  = LeftOperand.Resolve(ctx);
            var right = RightOperand.Resolve(ctx);

            if (type == null)
            {
                type = TypeExtensions.GetNumericOperationType(left, right);
            }

            Expr.Cast(LeftOperand, type).Emit(ctx, true);
            Expr.Cast(RightOperand, type).Emit(ctx, true);
        }
예제 #4
0
        /// <summary>
        /// Repeats a typed or untyped sequence.
        /// </summary>
        private NodeBase SeqExpand(Context ctx)
        {
            var seqType = LeftOperand.Resolve(ctx);

            NodeBase leftWrapper;

            if (seqType == typeof(IEnumerable))
            {
                leftWrapper = Expr.Invoke(Expr.GetMember("System.Linq.Enumerable", "OfType", "object"), LeftOperand);
                seqType     = typeof(IEnumerable <object>);
            }
            else
            {
                leftWrapper = LeftOperand;
            }

            var tmpLeft   = ctx.Scope.DeclareImplicit(ctx, seqType, false);
            var tmpResult = ctx.Scope.DeclareImplicit(ctx, seqType, false);
            var tmpIndex  = ctx.Scope.DeclareImplicit(ctx, typeof(int), false);

            // a = <left>
            // result = a
            // for x in 1..(Math.Abs <right>) do
            //   result = result.Concat a
            // result
            return(Expr.Block(
                       Expr.Set(tmpLeft, leftWrapper),
                       Expr.Set(tmpResult, Expr.Get(tmpLeft)),
                       Expr.For(
                           tmpIndex,
                           Expr.Int(1),
                           Expr.Invoke(
                               "System.Math",
                               "Abs",
                               RightOperand
                               ),
                           Expr.Block(
                               Expr.Set(
                                   tmpResult,
                                   Expr.Invoke(
                                       "System.Linq.Enumerable",
                                       "Concat",
                                       Expr.Get(tmpResult),
                                       Expr.Get(tmpLeft)
                                       )
                                   )
                               )
                           ),
                       Expr.Get(tmpResult)
                       ));
        }
예제 #5
0
        protected override Type ResolveInternal(Context ctx, bool mustReturn)
        {
            ctx.CheckTypedExpression(LeftOperand, allowNull: true);
            ctx.CheckTypedExpression(RightOperand, allowNull: true);

            var left  = LeftOperand.Resolve(ctx);
            var right = RightOperand.Resolve(ctx);

            // no types inferrable
            if (left == typeof(NullType) && right == typeof(NullType))
            {
                return(left);
            }

            // only one type known
            if (right == typeof(NullType))
            {
                return(left);
            }

            if (left == typeof(NullType))
            {
                return(right.IsValueType
                    ? typeof(Nullable <>).MakeGenericType(right)
                    : right);
            }


            if (left.IsValueType && !left.IsNullableType())
            {
                Error(LeftOperand, CompilerMessages.CoalesceOperatorLeftNotNull, left.FullName);
            }

            var baseLeft  = left.GetNullableUnderlyingType() ?? left;
            var baseRight = right.GetNullableUnderlyingType() ?? right;

            // do not accept combinations like "nullable<int>" and "string"
            if (baseLeft.IsValueType != baseRight.IsValueType)
            {
                Error(CompilerMessages.CoalesceOperatorTypeMismatch, left.FullName, right.FullName);
            }

            var common = new[] { baseLeft, baseRight }.GetMostCommonType();

            return(right.IsNullableType()
                ? typeof(Nullable <>).MakeGenericType(common)
                : common);
        }
예제 #6
0
        protected override void EmitOperator(Context ctx)
        {
            var gen = ctx.CurrentMethod.Generator;

            if (LeftOperand.Resolve(ctx).IsNumericType())
            {
                LoadAndConvertNumerics(ctx);
            }
            else
            {
                LeftOperand.Emit(ctx, true);
                RightOperand.Emit(ctx, true);
            }

            gen.EmitXor();
        }
예제 #7
0
        /// <summary>
        /// Returns the code to concatenate two dictionaries.
        /// </summary>
        private NodeBase DictExpand(Context ctx)
        {
            var keyValueTypes = LeftOperand.Resolve(ctx).GetGenericArguments();
            var dictType      = typeof(Dictionary <,>).MakeGenericType(keyValueTypes);
            var currType      = typeof(KeyValuePair <,>).MakeGenericType(keyValueTypes);
            var tmpDict       = ctx.Scope.DeclareImplicit(ctx, dictType, false);
            var tmpCurr       = ctx.Scope.DeclareImplicit(ctx, currType, false);

            // a = new Dictionary<T, T2>(<left>)
            // foreach(var kvp in <right>)
            //    a[kvp.Key] = kvp.Value
            return(Expr.Block(
                       Expr.Set(
                           tmpDict,
                           Expr.New(
                               dictType,
                               Expr.Cast(
                                   LeftOperand,
                                   typeof(IDictionary <,>).MakeGenericType(keyValueTypes)
                                   )
                               )
                           ),
                       Expr.For(
                           tmpCurr,
                           RightOperand,
                           Expr.Block(
                               Expr.SetIdx(
                                   Expr.Get(tmpDict),
                                   Expr.GetMember(
                                       Expr.Get(tmpCurr),
                                       "Key"
                                       ),
                                   Expr.GetMember(
                                       Expr.Get(tmpCurr),
                                       "Value"
                                       )
                                   )
                               )
                           ),
                       Expr.Get(tmpDict)
                       ));
        }
예제 #8
0
        protected override void EmitOperator(Context ctx)
        {
            var leftType   = LeftOperand.Resolve(ctx);
            var rightType  = RightOperand.Resolve(ctx);
            var isEquality = Kind == ComparisonOperatorKind.Equals || Kind == ComparisonOperatorKind.NotEquals;

            if (!CanCompare(leftType, rightType, isEquality))
            {
                Error(CompilerMessages.TypesIncomparable, leftType, rightType);
            }

            if (isEquality)
            {
                EmitEqualityComparison(ctx, leftType, rightType);
            }
            else
            {
                EmitRelation(ctx, leftType, rightType);
            }
        }
예제 #9
0
        /// <summary>
        /// Extra hint for function composition.
        /// </summary>
        protected override Type ResolveInternal(Context ctx, bool mustReturn)
        {
            var leftType = LeftOperand.Resolve(ctx);

            // check if the shift operator is used for function composition
            if (leftType.IsCallableType())
            {
                // add left operand's return type as hint to right operand
                var leftDelegate = ReflectionHelper.WrapDelegate(leftType);
                if (RightOperand is GetMemberNode)
                {
                    var mbr = RightOperand as GetMemberNode;
                    if (mbr.TypeHints == null || mbr.TypeHints.Count == 0)
                    {
                        mbr.TypeHints = new List <TypeSignature> {
                            leftDelegate.ReturnType.FullName
                        }
                    }
                    ;
                }
                else if (RightOperand is LambdaNode)
                {
                    var lambda = RightOperand as LambdaNode;
                    lambda.Resolve(ctx);
                    if (lambda.MustInferArgTypes)
                    {
                        lambda.SetInferredArgumentTypes(new[] { leftDelegate.ReturnType });
                    }
                }

                var rightType = RightOperand.Resolve(ctx);

                if (!ReflectionHelper.CanCombineDelegates(leftType, rightType))
                {
                    Error(Translations.CompilerMessages.DelegatesNotCombinable, leftType, rightType);
                }
            }

            // resolve as a possibly overloaded operator
            return(base.ResolveInternal(ctx, mustReturn));
        }
예제 #10
0
        protected override NodeBase Expand(Context ctx, bool mustReturn)
        {
            var left   = LeftOperand.Resolve(ctx);
            var right  = RightOperand.Resolve(ctx);
            var common = Resolve(ctx);

            var body = Expr.Block();

            var leftAccessor = LeftOperand;

            if (!(LeftOperand is GetIdentifierNode))
            {
                var tmpVar = ctx.Scope.DeclareImplicit(ctx, left, false);
                body.Add(Expr.Set(tmpVar, LeftOperand));
                leftAccessor = Expr.Get(tmpVar);
            }

            var condition  = Expr.Compare(ComparisonOperatorKind.Equals, leftAccessor, Expr.Null());
            var leftResult = left.IsNullableType() && left != right
                ? Expr.GetMember(leftAccessor, nameof(Nullable <int> .Value))
                : leftAccessor;

            var rightResult = right.IsNullableType() && left != right
                ? Expr.GetMember(RightOperand, nameof(Nullable <int> .Value))
                : RightOperand;

            body.Add(
                Expr.If(
                    condition,
                    Expr.Block(
                        Expr.Cast(rightResult, common)
                        ),
                    Expr.Block(
                        Expr.Cast(leftResult, common)
                        )
                    )
                );

            return(body);
        }
예제 #11
0
        protected override Type ResolveInternal(Context ctx, bool mustReturn)
        {
            var leftType  = LeftOperand.Resolve(ctx);
            var rightType = RightOperand.Resolve(ctx);

            var result = ResolveOperatorType(ctx, leftType, rightType);

            if (result != null)
            {
                return(result);
            }

            if (OverloadedMethodName != null)
            {
                try
                {
                    OverloadedMethod = ctx.ResolveMethod(leftType, OverloadedMethodName, new[] { leftType, rightType });
                }
                catch
                {
                    try
                    {
                        OverloadedMethod = ctx.ResolveMethod(rightType, OverloadedMethodName, new[] { leftType, rightType });
                    }
                    catch
                    {
                    }
                }

                // cannot be generic
                if (OverloadedMethod != null)
                {
                    return(OverloadedMethod.ReturnType);
                }
            }

            if (IsNumericOperator)
            {
                if (leftType.IsNullableType() || rightType.IsNullableType())
                {
                    var leftNullable  = leftType.IsNullableType() ? leftType.GetGenericArguments()[0] : leftType;
                    var rightNullable = rightType.IsNullableType() ? rightType.GetGenericArguments()[0] : rightType;

                    var commonNumericType = TypeExtensions.GetNumericOperationType(leftNullable, rightNullable);
                    if (commonNumericType == null)
                    {
                        Error(CompilerMessages.OperatorTypesSignednessMismatch);
                    }

                    return(typeof(Nullable <>).MakeGenericType(commonNumericType));
                }

                if (leftType.IsNumericType() && rightType.IsNumericType())
                {
                    var commonNumericType = TypeExtensions.GetNumericOperationType(leftType, rightType);
                    if (commonNumericType == null)
                    {
                        Error(CompilerMessages.OperatorTypesSignednessMismatch);
                    }

                    return(commonNumericType);
                }
            }

            Error(this, CompilerMessages.OperatorBinaryTypesMismatch, OperatorRepresentation, leftType, rightType);
            return(null);
        }
예제 #12
0
        /// <summary>
        /// Repeats an array.
        /// </summary>
        private NodeBase ArrayExpand(Context ctx)
        {
            var arrayType = LeftOperand.Resolve(ctx);
            var tmpLeft   = ctx.Scope.DeclareImplicit(ctx, arrayType, false);
            var tmpResult = ctx.Scope.DeclareImplicit(ctx, arrayType, false);
            var tmpRight  = ctx.Scope.DeclareImplicit(ctx, typeof(int), false);
            var tmpIndex  = ctx.Scope.DeclareImplicit(ctx, typeof(int), false);

            // a = <left>
            // b = right
            // result = new T[a.Length * b]
            // for idx in 0..a.Length-1 do
            //    Array::Copy(from: a; to: result; targetIndex: idx * a.Length)
            // result
            return(Expr.Block(
                       Expr.Set(tmpLeft, LeftOperand),
                       Expr.Set(
                           tmpRight,
                           Expr.Invoke(
                               "System.Math",
                               "Abs",
                               RightOperand
                               )
                           ),
                       Expr.Set(
                           tmpResult,
                           Expr.Array(
                               arrayType.GetElementType(),
                               Expr.Mult(
                                   Expr.GetMember(
                                       Expr.Get(tmpLeft),
                                       "Length"
                                       ),
                                   Expr.Get(tmpRight)
                                   )
                               )
                           ),
                       Expr.For(
                           tmpIndex,
                           Expr.Int(0),
                           Expr.Get(tmpRight),
                           Expr.Block(
                               Expr.Invoke(
                                   "System.Array",
                                   "Copy",
                                   Expr.Get(tmpLeft),
                                   Expr.Int(0),
                                   Expr.Get(tmpResult),
                                   Expr.Mult(
                                       Expr.Get(tmpIndex),
                                       Expr.GetMember(
                                           Expr.Get(tmpLeft),
                                           "Length"
                                           )
                                       ),
                                   Expr.GetMember(
                                       Expr.Get(tmpLeft),
                                       "Length"
                                       )
                                   )
                               )
                           ),
                       Expr.Get(tmpResult)
                       ));
        }