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