<PackageReference Include="Microsoft.CSharp" Version="4.4.0" />

ExpressionTreeRewriter

using Microsoft.CSharp.RuntimeBinder.Syntax; namespace Microsoft.CSharp.RuntimeBinder.Semantics { internal sealed class ExpressionTreeRewriter : ExprVisitorBase { private ExprFactory expressionFactory; private SymbolLoader symbolLoader; private ExprBoundLambda currentAnonMeth; private bool alwaysRewrite; public static Expr Rewrite(Expr expr, ExprFactory expressionFactory, SymbolLoader symbolLoader) { ExpressionTreeRewriter expressionTreeRewriter = new ExpressionTreeRewriter(expressionFactory, symbolLoader); expressionTreeRewriter.alwaysRewrite = true; return expressionTreeRewriter.Visit(expr); } private ExprFactory GetExprFactory() { return expressionFactory; } private SymbolLoader GetSymbolLoader() { return symbolLoader; } private ExpressionTreeRewriter(ExprFactory expressionFactory, SymbolLoader symbolLoader) { this.expressionFactory = expressionFactory; this.symbolLoader = symbolLoader; alwaysRewrite = false; } protected override Expr Dispatch(Expr expr) { Expr expr2 = base.Dispatch(expr); if (expr2 == expr) throw Error.InternalCompilerError(); return expr2; } protected override Expr VisitASSIGNMENT(ExprAssignment assignment) { ExprProperty exprProperty; Expr arg; if ((exprProperty = (assignment.LHS as ExprProperty)) != null) { if (exprProperty.OptionalArguments == null) arg = Visit(exprProperty); else { Expr arg2 = Visit(exprProperty.MemberGroup.OptionalObject); Expr arg3 = GetExprFactory().CreatePropertyInfo(exprProperty.PropWithTypeSlot.Prop(), exprProperty.PropWithTypeSlot.Ats); Expr arg4 = GenerateParamsArray(GenerateArgsList(exprProperty.OptionalArguments), PredefinedType.PT_EXPRESSION); arg = GenerateCall(PREDEFMETH.PM_EXPRESSION_PROPERTY, arg2, arg3, arg4); } } else arg = Visit(assignment.LHS); Expr arg5 = Visit(assignment.RHS); return GenerateCall(PREDEFMETH.PM_EXPRESSION_ASSIGN, arg, arg5); } protected override Expr VisitMULTIGET(ExprMultiGet pExpr) { return Visit(pExpr.OptionalMulti.Left); } protected override Expr VisitMULTI(ExprMulti pExpr) { Expr arg = Visit(pExpr.Operator); Expr arg2 = Visit(pExpr.Left); return GenerateCall(PREDEFMETH.PM_EXPRESSION_ASSIGN, arg2, arg); } protected override Expr VisitBOUNDLAMBDA(ExprBoundLambda anonmeth) { ExprBoundLambda exprBoundLambda = currentAnonMeth; currentAnonMeth = anonmeth; MethodSymbol preDefMethod = GetPreDefMethod(PREDEFMETH.PM_EXPRESSION_LAMBDA); CType delegateType = anonmeth.DelegateType; TypeArray typeArgs = GetSymbolLoader().getBSymmgr().AllocParams(1, new CType[1] { delegateType }); AggregateType optPredefTypeErr = GetSymbolLoader().GetOptPredefTypeErr(PredefinedType.PT_EXPRESSION, true); MethWithInst methWithInst = new MethWithInst(preDefMethod, optPredefTypeErr, typeArgs); Expr expr = CreateWraps(anonmeth); Expr op = RewriteLambdaBody(anonmeth); Expr op2 = RewriteLambdaParameters(anonmeth); Expr pOptionalArguments = GetExprFactory().CreateList(op, op2); CType pType = GetSymbolLoader().GetTypeManager().SubstType(methWithInst.Meth().RetType, methWithInst.GetType(), methWithInst.TypeArgs); ExprMemberGroup pMemberGroup = GetExprFactory().CreateMemGroup(null, methWithInst); ExprCall exprCall = GetExprFactory().CreateCall((EXPRFLAG)0, pType, pOptionalArguments, pMemberGroup, methWithInst); Expr expr2 = exprCall; exprCall.PredefinedMethod = PREDEFMETH.PM_EXPRESSION_LAMBDA; currentAnonMeth = exprBoundLambda; if (expr != null) expr2 = GetExprFactory().CreateSequence(expr, expr2); Expr expr3 = DestroyWraps(anonmeth, expr2); if (currentAnonMeth != null) expr3 = GenerateCall(PREDEFMETH.PM_EXPRESSION_QUOTE, expr3); return expr3; } protected override Expr VisitCONSTANT(ExprConstant expr) { return GenerateConstant(expr); } protected override Expr VisitLOCAL(ExprLocal local) { if (local.Local.wrap != null) return local.Local.wrap; return GetExprFactory().CreateHoistedLocalInExpression(local); } protected override Expr VisitFIELD(ExprField expr) { Expr arg = (expr.OptionalObject != null) ? Visit(expr.OptionalObject) : GetExprFactory().CreateNull(); ExprFieldInfo arg2 = GetExprFactory().CreateFieldInfo(expr.FieldWithType.Field(), expr.FieldWithType.GetType()); return GenerateCall(PREDEFMETH.PM_EXPRESSION_FIELD, arg, arg2); } protected override Expr VisitUSERDEFINEDCONVERSION(ExprUserDefinedConversion expr) { return GenerateUserDefinedConversion(expr, expr.Argument); } protected override Expr VisitCAST(ExprCast pExpr) { Expr argument = pExpr.Argument; if (argument.Type == pExpr.Type || GetSymbolLoader().IsBaseClassOfClass(argument.Type, pExpr.Type) || CConversions.FImpRefConv(GetSymbolLoader(), argument.Type, pExpr.Type)) return Visit(argument); if (pExpr.Type != null && pExpr.Type.isPredefType(PredefinedType.PT_G_EXPRESSION) && argument is ExprBoundLambda) return Visit(argument); Expr expr = GenerateConversion(argument, pExpr.Type, pExpr.isChecked()); if ((pExpr.Flags & EXPRFLAG.EXF_USERCALLABLE) != 0) expr.Flags |= EXPRFLAG.EXF_USERCALLABLE; return expr; } protected override Expr VisitCONCAT(ExprConcat expr) { PREDEFMETH pdm = (!expr.FirstArgument.Type.isPredefType(PredefinedType.PT_STRING) || !expr.SecondArgument.Type.isPredefType(PredefinedType.PT_STRING)) ? PREDEFMETH.PM_STRING_CONCAT_OBJECT_2 : PREDEFMETH.PM_STRING_CONCAT_STRING_2; Expr arg = Visit(expr.FirstArgument); Expr arg2 = Visit(expr.SecondArgument); MethodSymbol preDefMethod = GetPreDefMethod(pdm); Expr arg3 = GetExprFactory().CreateMethodInfo(preDefMethod, GetSymbolLoader().GetReqPredefType(PredefinedType.PT_STRING), null); return GenerateCall(PREDEFMETH.PM_EXPRESSION_ADD_USER_DEFINED, arg, arg2, arg3); } protected override Expr VisitBINOP(ExprBinOp expr) { if ((SymWithType)expr.UserDefinedCallMethod != (SymWithType)null) return GenerateUserDefinedBinaryOperator(expr); return GenerateBuiltInBinaryOperator(expr); } protected override Expr VisitUNARYOP(ExprUnaryOp pExpr) { if ((SymWithType)pExpr.UserDefinedCallMethod != (SymWithType)null) return GenerateUserDefinedUnaryOperator(pExpr); return GenerateBuiltInUnaryOperator(pExpr); } protected override Expr VisitARRAYINDEX(ExprArrayIndex pExpr) { Expr arg = Visit(pExpr.Array); Expr expr = GenerateIndexList(pExpr.Index); if (expr is ExprList) { Expr arg2 = GenerateParamsArray(expr, PredefinedType.PT_EXPRESSION); return GenerateCall(PREDEFMETH.PM_EXPRESSION_ARRAYINDEX2, arg, arg2); } return GenerateCall(PREDEFMETH.PM_EXPRESSION_ARRAYINDEX, arg, expr); } protected override Expr VisitARRAYLENGTH(ExprArrayLength pExpr) { return GenerateBuiltInUnaryOperator(PREDEFMETH.PM_EXPRESSION_ARRAYLENGTH, pExpr.Array, pExpr); } protected override Expr VisitQUESTIONMARK(ExprQuestionMark pExpr) { Expr arg = Visit(pExpr.TestExpression); Expr arg2 = GenerateQuestionMarkOperand(pExpr.Consequence.OptionalLeftChild); Expr arg3 = GenerateQuestionMarkOperand(pExpr.Consequence.OptionalRightChild); return GenerateCall(PREDEFMETH.PM_EXPRESSION_CONDITION, arg, arg2, arg3); } protected override Expr VisitCALL(ExprCall expr) { switch (expr.NullableCallLiftKind) { case NullableCallLiftKind.NullableConversion: case NullableCallLiftKind.NullableConversionConstructor: case NullableCallLiftKind.NullableIntermediateConversion: return GenerateConversion(expr.OptionalArguments, expr.Type, expr.isChecked()); case NullableCallLiftKind.UserDefinedConversion: case NullableCallLiftKind.NotLiftedIntermediateConversion: return GenerateUserDefinedConversion(expr.OptionalArguments, expr.Type, expr.MethWithInst); default: { if (expr.MethWithInst.Meth().IsConstructor()) return GenerateConstructor(expr); ExprMemberGroup memberGroup = expr.MemberGroup; if (memberGroup.IsDelegate) return GenerateDelegateInvoke(expr); Expr arg; if (expr.MethWithInst.Meth().isStatic || expr.MemberGroup.OptionalObject == null) arg = GetExprFactory().CreateNull(); else { arg = expr.MemberGroup.OptionalObject; ExprCast exprCast; if (arg != null && (exprCast = (arg as ExprCast)) != null && exprCast.IsBoxingCast) arg = exprCast.Argument; arg = Visit(arg); } Expr arg2 = GetExprFactory().CreateMethodInfo(expr.MethWithInst); Expr args = GenerateArgsList(expr.OptionalArguments); Expr arg3 = GenerateParamsArray(args, PredefinedType.PT_EXPRESSION); PREDEFMETH pdm = PREDEFMETH.PM_EXPRESSION_CALL; return GenerateCall(pdm, arg, arg2, arg3); } } } protected override Expr VisitPROP(ExprProperty expr) { Expr arg = (!expr.PropWithTypeSlot.Prop().isStatic && expr.MemberGroup.OptionalObject != null) ? Visit(expr.MemberGroup.OptionalObject) : GetExprFactory().CreateNull(); Expr arg2 = GetExprFactory().CreatePropertyInfo(expr.PropWithTypeSlot.Prop(), expr.PropWithTypeSlot.GetType()); if (expr.OptionalArguments != null) { Expr args = GenerateArgsList(expr.OptionalArguments); Expr arg3 = GenerateParamsArray(args, PredefinedType.PT_EXPRESSION); return GenerateCall(PREDEFMETH.PM_EXPRESSION_PROPERTY, arg, arg2, arg3); } return GenerateCall(PREDEFMETH.PM_EXPRESSION_PROPERTY, arg, arg2); } protected override Expr VisitARRINIT(ExprArrayInit expr) { Expr arg = CreateTypeOf(expr.Type.AsArrayType().GetElementType()); Expr args = GenerateArgsList(expr.OptionalArguments); Expr arg2 = GenerateParamsArray(args, PredefinedType.PT_EXPRESSION); return GenerateCall(PREDEFMETH.PM_EXPRESSION_NEWARRAYINIT, arg, arg2); } protected override Expr VisitZEROINIT(ExprZeroInit expr) { if (expr.IsConstructor) { ExprTypeOf arg = CreateTypeOf(expr.Type); return GenerateCall(PREDEFMETH.PM_EXPRESSION_NEW_TYPE, arg); } return GenerateConstant(expr); } protected override Expr VisitTYPEOF(ExprTypeOf expr) { return GenerateConstant(expr); } private Expr GenerateQuestionMarkOperand(Expr pExpr) { ExprCast exprCast; if ((exprCast = (pExpr as ExprCast)) != null) return GenerateConversion(exprCast.Argument, pExpr.Type, pExpr.isChecked()); return Visit(pExpr); } private Expr GenerateDelegateInvoke(ExprCall expr) { ExprMemberGroup memberGroup = expr.MemberGroup; Expr optionalObject = memberGroup.OptionalObject; Expr arg = Visit(optionalObject); Expr args = GenerateArgsList(expr.OptionalArguments); Expr arg2 = GenerateParamsArray(args, PredefinedType.PT_EXPRESSION); return GenerateCall(PREDEFMETH.PM_EXPRESSION_INVOKE, arg, arg2); } private Expr GenerateBuiltInBinaryOperator(ExprBinOp expr) { PREDEFMETH pdm; switch (expr.Kind) { case ExpressionKind.LeftShirt: pdm = PREDEFMETH.PM_EXPRESSION_LEFTSHIFT; break; case ExpressionKind.RightShift: pdm = PREDEFMETH.PM_EXPRESSION_RIGHTSHIFT; break; case ExpressionKind.BitwiseExclusiveOr: pdm = PREDEFMETH.PM_EXPRESSION_EXCLUSIVEOR; break; case ExpressionKind.BitwiseOr: pdm = PREDEFMETH.PM_EXPRESSION_OR; break; case ExpressionKind.BitwiseAnd: pdm = PREDEFMETH.PM_EXPRESSION_AND; break; case ExpressionKind.LogicalAnd: pdm = PREDEFMETH.PM_EXPRESSION_ANDALSO; break; case ExpressionKind.LogicalOr: pdm = PREDEFMETH.PM_EXPRESSION_ORELSE; break; case ExpressionKind.StringEq: pdm = PREDEFMETH.PM_EXPRESSION_EQUAL; break; case ExpressionKind.Eq: pdm = PREDEFMETH.PM_EXPRESSION_EQUAL; break; case ExpressionKind.StringNotEq: pdm = PREDEFMETH.PM_EXPRESSION_NOTEQUAL; break; case ExpressionKind.NotEq: pdm = PREDEFMETH.PM_EXPRESSION_NOTEQUAL; break; case ExpressionKind.GreaterThanOrEqual: pdm = PREDEFMETH.PM_EXPRESSION_GREATERTHANOREQUAL; break; case ExpressionKind.LessThanOrEqual: pdm = PREDEFMETH.PM_EXPRESSION_LESSTHANOREQUAL; break; case ExpressionKind.LessThan: pdm = PREDEFMETH.PM_EXPRESSION_LESSTHAN; break; case ExpressionKind.GreaterThan: pdm = PREDEFMETH.PM_EXPRESSION_GREATERTHAN; break; case ExpressionKind.Modulo: pdm = PREDEFMETH.PM_EXPRESSION_MODULO; break; case ExpressionKind.Divide: pdm = PREDEFMETH.PM_EXPRESSION_DIVIDE; break; case ExpressionKind.Multiply: pdm = (expr.isChecked() ? PREDEFMETH.PM_EXPRESSION_MULTIPLYCHECKED : PREDEFMETH.PM_EXPRESSION_MULTIPLY); break; case ExpressionKind.Subtract: pdm = (expr.isChecked() ? PREDEFMETH.PM_EXPRESSION_SUBTRACTCHECKED : PREDEFMETH.PM_EXPRESSION_SUBTRACT); break; case ExpressionKind.Add: pdm = (expr.isChecked() ? PREDEFMETH.PM_EXPRESSION_ADDCHECKED : PREDEFMETH.PM_EXPRESSION_ADD); break; default: throw Error.InternalCompilerError(); } Expr optionalLeftChild = expr.OptionalLeftChild; Expr optionalRightChild = expr.OptionalRightChild; CType cType = optionalLeftChild.Type; CType cType2 = optionalRightChild.Type; Expr arg = Visit(optionalLeftChild); Expr expr2 = Visit(optionalRightChild); bool flag = false; CType cType3 = null; CType cType4 = null; if (cType.isEnumType()) { cType3 = GetSymbolLoader().GetTypeManager().GetNullable(cType.underlyingEnumType()); cType = cType3; flag = true; } else if (cType.IsNullableType() && cType.StripNubs().isEnumType()) { cType3 = GetSymbolLoader().GetTypeManager().GetNullable(cType.StripNubs().underlyingEnumType()); cType = cType3; flag = true; } if (cType2.isEnumType()) { cType4 = GetSymbolLoader().GetTypeManager().GetNullable(cType2.underlyingEnumType()); cType2 = cType4; flag = true; } else if (cType2.IsNullableType() && cType2.StripNubs().isEnumType()) { cType4 = GetSymbolLoader().GetTypeManager().GetNullable(cType2.StripNubs().underlyingEnumType()); cType2 = cType4; flag = true; } if (cType.IsNullableType() && cType.StripNubs() == cType2) cType4 = cType; if (cType2.IsNullableType() && cType2.StripNubs() == cType) cType3 = cType2; if (cType3 != null) arg = GenerateCall(PREDEFMETH.PM_EXPRESSION_CONVERT, arg, CreateTypeOf(cType3)); if (cType4 != null) expr2 = GenerateCall(PREDEFMETH.PM_EXPRESSION_CONVERT, expr2, CreateTypeOf(cType4)); Expr expr3 = GenerateCall(pdm, arg, expr2); if (flag && expr.Type.StripNubs().isEnumType()) expr3 = GenerateCall(PREDEFMETH.PM_EXPRESSION_CONVERT, expr3, CreateTypeOf(expr.Type)); return expr3; } private Expr GenerateBuiltInUnaryOperator(ExprUnaryOp expr) { PREDEFMETH pdm; switch (expr.Kind) { case ExpressionKind.UnaryPlus: return Visit(expr.Child); case ExpressionKind.BitwiseNot: pdm = PREDEFMETH.PM_EXPRESSION_NOT; break; case ExpressionKind.LogicalNot: pdm = PREDEFMETH.PM_EXPRESSION_NOT; break; case ExpressionKind.Negate: pdm = (expr.isChecked() ? PREDEFMETH.PM_EXPRESSION_NEGATECHECKED : PREDEFMETH.PM_EXPRESSION_NEGATE); break; default: throw Error.InternalCompilerError(); } Expr child = expr.Child; return GenerateBuiltInUnaryOperator(pdm, child, expr); } private Expr GenerateBuiltInUnaryOperator(PREDEFMETH pdm, Expr pOriginalOperator, Expr pOperator) { Expr arg = Visit(pOriginalOperator); if (pOriginalOperator.Type.IsNullableType() && pOriginalOperator.Type.StripNubs().isEnumType()) { CType pUnderlyingType = pOriginalOperator.Type.StripNubs().underlyingEnumType(); CType nullable = GetSymbolLoader().GetTypeManager().GetNullable(pUnderlyingType); arg = GenerateCall(PREDEFMETH.PM_EXPRESSION_CONVERT, arg, CreateTypeOf(nullable)); } Expr expr = GenerateCall(pdm, arg); if (pOriginalOperator.Type.IsNullableType() && pOriginalOperator.Type.StripNubs().isEnumType()) expr = GenerateCall(PREDEFMETH.PM_EXPRESSION_CONVERT, expr, CreateTypeOf(pOperator.Type)); return expr; } private Expr GenerateUserDefinedBinaryOperator(ExprBinOp expr) { PREDEFMETH pdm; switch (expr.Kind) { case ExpressionKind.LogicalOr: pdm = PREDEFMETH.PM_EXPRESSION_ORELSE_USER_DEFINED; break; case ExpressionKind.LogicalAnd: pdm = PREDEFMETH.PM_EXPRESSION_ANDALSO_USER_DEFINED; break; case ExpressionKind.LeftShirt: pdm = PREDEFMETH.PM_EXPRESSION_LEFTSHIFT_USER_DEFINED; break; case ExpressionKind.RightShift: pdm = PREDEFMETH.PM_EXPRESSION_RIGHTSHIFT_USER_DEFINED; break; case ExpressionKind.BitwiseExclusiveOr: pdm = PREDEFMETH.PM_EXPRESSION_EXCLUSIVEOR_USER_DEFINED; break; case ExpressionKind.BitwiseOr: pdm = PREDEFMETH.PM_EXPRESSION_OR_USER_DEFINED; break; case ExpressionKind.BitwiseAnd: pdm = PREDEFMETH.PM_EXPRESSION_AND_USER_DEFINED; break; case ExpressionKind.Modulo: pdm = PREDEFMETH.PM_EXPRESSION_MODULO_USER_DEFINED; break; case ExpressionKind.Divide: pdm = PREDEFMETH.PM_EXPRESSION_DIVIDE_USER_DEFINED; break; case ExpressionKind.Eq: case ExpressionKind.NotEq: case ExpressionKind.LessThan: case ExpressionKind.LessThanOrEqual: case ExpressionKind.GreaterThan: case ExpressionKind.GreaterThanOrEqual: case ExpressionKind.StringEq: case ExpressionKind.StringNotEq: case ExpressionKind.DelegateEq: case ExpressionKind.DelegateNotEq: return GenerateUserDefinedComparisonOperator(expr); case ExpressionKind.Subtract: case ExpressionKind.DelegateSubtract: pdm = (expr.isChecked() ? PREDEFMETH.PM_EXPRESSION_SUBTRACTCHECKED_USER_DEFINED : PREDEFMETH.PM_EXPRESSION_SUBTRACT_USER_DEFINED); break; case ExpressionKind.Add: case ExpressionKind.DelegateAdd: pdm = (expr.isChecked() ? PREDEFMETH.PM_EXPRESSION_ADDCHECKED_USER_DEFINED : PREDEFMETH.PM_EXPRESSION_ADD_USER_DEFINED); break; case ExpressionKind.Multiply: pdm = (expr.isChecked() ? PREDEFMETH.PM_EXPRESSION_MULTIPLYCHECKED_USER_DEFINED : PREDEFMETH.PM_EXPRESSION_MULTIPLY_USER_DEFINED); break; default: throw Error.InternalCompilerError(); } Expr pp = expr.OptionalLeftChild; Expr pp2 = expr.OptionalRightChild; Expr optionalUserDefinedCall = expr.OptionalUserDefinedCall; if (optionalUserDefinedCall != null) { ExprCall exprCall; if ((exprCall = (optionalUserDefinedCall as ExprCall)) != null) { ExprList exprList = (ExprList)exprCall.OptionalArguments; pp = exprList.OptionalElement; pp2 = exprList.OptionalNextListNode; } else { ExprUserLogicalOp exprUserLogicalOp = optionalUserDefinedCall as ExprUserLogicalOp; ExprList exprList2 = (ExprList)exprUserLogicalOp.OperatorCall.OptionalArguments; pp = ((ExprWrap)exprList2.OptionalElement).OptionalExpression; pp2 = exprList2.OptionalNextListNode; } } pp = Visit(pp); pp2 = Visit(pp2); FixLiftedUserDefinedBinaryOperators(expr, ref pp, ref pp2); Expr arg = GetExprFactory().CreateMethodInfo(expr.UserDefinedCallMethod); Expr expr2 = GenerateCall(pdm, pp, pp2, arg); if (expr.Kind == ExpressionKind.DelegateSubtract || expr.Kind == ExpressionKind.DelegateAdd) { Expr arg2 = CreateTypeOf(expr.Type); return GenerateCall(PREDEFMETH.PM_EXPRESSION_CONVERT, expr2, arg2); } return expr2; } private Expr GenerateUserDefinedUnaryOperator(ExprUnaryOp expr) { Expr pExpr = expr.Child; ExprCall exprCall = (ExprCall)expr.OptionalUserDefinedCall; if (exprCall != null) pExpr = exprCall.OptionalArguments; PREDEFMETH pdm; switch (expr.Kind) { case ExpressionKind.True: case ExpressionKind.False: return Visit(exprCall); case ExpressionKind.UnaryPlus: pdm = PREDEFMETH.PM_EXPRESSION_UNARYPLUS_USER_DEFINED; break; case ExpressionKind.BitwiseNot: pdm = PREDEFMETH.PM_EXPRESSION_NOT_USER_DEFINED; break; case ExpressionKind.LogicalNot: pdm = PREDEFMETH.PM_EXPRESSION_NOT_USER_DEFINED; break; case ExpressionKind.Negate: case ExpressionKind.DecimalNegate: pdm = (expr.isChecked() ? PREDEFMETH.PM_EXPRESSION_NEGATECHECKED_USER_DEFINED : PREDEFMETH.PM_EXPRESSION_NEGATE_USER_DEFINED); break; case ExpressionKind.Inc: case ExpressionKind.Dec: case ExpressionKind.DecimalInc: case ExpressionKind.DecimalDec: pdm = PREDEFMETH.PM_EXPRESSION_CALL; break; default: throw Error.InternalCompilerError(); } Expr expr2 = Visit(pExpr); Expr arg = GetExprFactory().CreateMethodInfo(expr.UserDefinedCallMethod); if (expr.Kind == ExpressionKind.Inc || expr.Kind == ExpressionKind.Dec || expr.Kind == ExpressionKind.DecimalInc || expr.Kind == ExpressionKind.DecimalDec) return GenerateCall(pdm, null, arg, GenerateParamsArray(expr2, PredefinedType.PT_EXPRESSION)); return GenerateCall(pdm, expr2, arg); } private Expr GenerateUserDefinedComparisonOperator(ExprBinOp expr) { PREDEFMETH pdm; switch (expr.Kind) { case ExpressionKind.StringEq: pdm = PREDEFMETH.PM_EXPRESSION_EQUAL_USER_DEFINED; break; case ExpressionKind.StringNotEq: pdm = PREDEFMETH.PM_EXPRESSION_NOTEQUAL_USER_DEFINED; break; case ExpressionKind.DelegateEq: pdm = PREDEFMETH.PM_EXPRESSION_EQUAL_USER_DEFINED; break; case ExpressionKind.DelegateNotEq: pdm = PREDEFMETH.PM_EXPRESSION_NOTEQUAL_USER_DEFINED; break; case ExpressionKind.Eq: pdm = PREDEFMETH.PM_EXPRESSION_EQUAL_USER_DEFINED; break; case ExpressionKind.NotEq: pdm = PREDEFMETH.PM_EXPRESSION_NOTEQUAL_USER_DEFINED; break; case ExpressionKind.LessThanOrEqual: pdm = PREDEFMETH.PM_EXPRESSION_LESSTHANOREQUAL_USER_DEFINED; break; case ExpressionKind.LessThan: pdm = PREDEFMETH.PM_EXPRESSION_LESSTHAN_USER_DEFINED; break; case ExpressionKind.GreaterThanOrEqual: pdm = PREDEFMETH.PM_EXPRESSION_GREATERTHANOREQUAL_USER_DEFINED; break; case ExpressionKind.GreaterThan: pdm = PREDEFMETH.PM_EXPRESSION_GREATERTHAN_USER_DEFINED; break; default: throw Error.InternalCompilerError(); } Expr pp = expr.OptionalLeftChild; Expr pp2 = expr.OptionalRightChild; if (expr.OptionalUserDefinedCall != null) { ExprCall exprCall = (ExprCall)expr.OptionalUserDefinedCall; ExprList exprList = (ExprList)exprCall.OptionalArguments; pp = exprList.OptionalElement; pp2 = exprList.OptionalNextListNode; } pp = Visit(pp); pp2 = Visit(pp2); FixLiftedUserDefinedBinaryOperators(expr, ref pp, ref pp2); Expr arg = GetExprFactory().CreateBoolConstant(false); Expr arg2 = GetExprFactory().CreateMethodInfo(expr.UserDefinedCallMethod); return GenerateCall(pdm, pp, pp2, arg, arg2); } private Expr RewriteLambdaBody(ExprBoundLambda anonmeth) { ExprBlock optionalBody = anonmeth.OptionalBody; ExprReturn exprReturn; if ((exprReturn = (optionalBody.OptionalStatements as ExprReturn)) != null) return Visit(exprReturn.OptionalObject); throw Error.InternalCompilerError(); } private Expr RewriteLambdaParameters(ExprBoundLambda anonmeth) { Expr first = null; Expr last = first; for (Symbol symbol = anonmeth.ArgumentScope; symbol != null; symbol = symbol.nextChild) { if (symbol.IsLocalVariableSymbol()) { LocalVariableSymbol localVariableSymbol = symbol.AsLocalVariableSymbol(); if (!localVariableSymbol.isThis) GetExprFactory().AppendItemToList(localVariableSymbol.wrap, ref first, ref last); } } return GenerateParamsArray(first, PredefinedType.PT_PARAMETEREXPRESSION); } private Expr GenerateConversion(Expr arg, CType CType, bool bChecked) { return GenerateConversionWithSource(Visit(arg), CType, bChecked || arg.isChecked()); } private Expr GenerateConversionWithSource(Expr pTarget, CType pType, bool bChecked) { PREDEFMETH pdm = bChecked ? PREDEFMETH.PM_EXPRESSION_CONVERTCHECKED : PREDEFMETH.PM_EXPRESSION_CONVERT; Expr arg = CreateTypeOf(pType); return GenerateCall(pdm, pTarget, arg); } private Expr GenerateValueAccessConversion(Expr pArgument) { CType cType = pArgument.Type.StripNubs(); Expr arg = CreateTypeOf(cType); return GenerateCall(PREDEFMETH.PM_EXPRESSION_CONVERT, Visit(pArgument), arg); } private Expr GenerateUserDefinedConversion(Expr arg, CType type, MethWithInst method) { Expr target = Visit(arg); return GenerateUserDefinedConversion(arg, type, target, method); } private Expr GenerateUserDefinedConversion(Expr arg, CType CType, Expr target, MethWithInst method) { if (isEnumToDecimalConversion(arg.Type, CType)) { CType pUnderlyingType = arg.Type.StripNubs().underlyingEnumType(); CType nullable = GetSymbolLoader().GetTypeManager().GetNullable(pUnderlyingType); Expr arg2 = CreateTypeOf(nullable); target = GenerateCall(PREDEFMETH.PM_EXPRESSION_CONVERT, target, arg2); } CType cType = GetSymbolLoader().GetTypeManager().SubstType(method.Meth().RetType, method.GetType(), method.TypeArgs); bool flag = cType == CType || (IsNullableValueType(arg.Type) && IsNullableValueType(CType)); Expr arg3 = CreateTypeOf(flag ? CType : cType); Expr arg4 = GetExprFactory().CreateMethodInfo(method); PREDEFMETH pdm = arg.isChecked() ? PREDEFMETH.PM_EXPRESSION_CONVERTCHECKED_USER_DEFINED : PREDEFMETH.PM_EXPRESSION_CONVERT_USER_DEFINED; Expr expr = GenerateCall(pdm, target, arg3, arg4); if (flag) return expr; PREDEFMETH pdm2 = arg.isChecked() ? PREDEFMETH.PM_EXPRESSION_CONVERTCHECKED : PREDEFMETH.PM_EXPRESSION_CONVERT; Expr arg5 = CreateTypeOf(CType); return GenerateCall(pdm2, expr, arg5); } private Expr GenerateUserDefinedConversion(ExprUserDefinedConversion pExpr, Expr pArgument) { Expr userDefinedCall = pExpr.UserDefinedCall; Expr argument = pExpr.Argument; Expr target; if (!isEnumToDecimalConversion(pArgument.Type, pExpr.Type) && IsNullableValueAccess(argument, pArgument)) target = GenerateValueAccessConversion(pArgument); else { ExprCall exprCall = userDefinedCall as ExprCall; Expr expr = exprCall?.PConversions; if (expr != null) { ExprCall exprCall2; if ((exprCall2 = (expr as ExprCall)) != null) { Expr optionalArguments = exprCall2.OptionalArguments; target = ((!IsNullableValueAccess(optionalArguments, pArgument)) ? Visit(optionalArguments) : GenerateValueAccessConversion(pArgument)); return GenerateConversionWithSource(target, userDefinedCall.Type, exprCall.isChecked()); } return GenerateUserDefinedConversion((ExprUserDefinedConversion)expr, pArgument); } target = Visit(argument); } return GenerateUserDefinedConversion(argument, pExpr.Type, target, pExpr.UserDefinedCallMethod); } private Expr GenerateParameter(string name, CType CType) { GetSymbolLoader().GetReqPredefType(PredefinedType.PT_STRING); ExprConstant arg = GetExprFactory().CreateStringConstant(name); ExprTypeOf arg2 = CreateTypeOf(CType); return GenerateCall(PREDEFMETH.PM_EXPRESSION_PARAMETER, arg2, arg); } private MethodSymbol GetPreDefMethod(PREDEFMETH pdm) { return GetSymbolLoader().getPredefinedMembers().GetMethod(pdm); } private ExprTypeOf CreateTypeOf(CType CType) { return GetExprFactory().CreateTypeOf(CType); } private Expr CreateWraps(ExprBoundLambda anonmeth) { Expr expr = null; for (Symbol symbol = anonmeth.ArgumentScope.firstChild; symbol != null; symbol = symbol.nextChild) { if (symbol.IsLocalVariableSymbol()) { LocalVariableSymbol localVariableSymbol = symbol.AsLocalVariableSymbol(); if (!localVariableSymbol.isThis) { Expr pOptionalWrap = GenerateParameter(localVariableSymbol.name.Text, localVariableSymbol.GetType()); localVariableSymbol.wrap = GetExprFactory().CreateWrapNoAutoFree(anonmeth.OptionalBody.OptionalScopeSymbol, pOptionalWrap); Expr expr2 = GetExprFactory().CreateSave(localVariableSymbol.wrap); expr = ((expr != null) ? GetExprFactory().CreateSequence(expr, expr2) : expr2); } } } return expr; } private Expr DestroyWraps(ExprBoundLambda anonmeth, Expr sequence) { for (Symbol symbol = anonmeth.ArgumentScope; symbol != null; symbol = symbol.nextChild) { if (symbol.IsLocalVariableSymbol()) { LocalVariableSymbol localVariableSymbol = symbol.AsLocalVariableSymbol(); if (!localVariableSymbol.isThis) { Expr p = GetExprFactory().CreateWrap(anonmeth.OptionalBody.OptionalScopeSymbol, localVariableSymbol.wrap); sequence = GetExprFactory().CreateReverseSequence(sequence, p); } } } return sequence; } private Expr GenerateConstructor(ExprCall expr) { if (IsDelegateConstructorCall(expr)) return GenerateDelegateConstructor(expr); Expr arg = GetExprFactory().CreateMethodInfo(expr.MethWithInst); Expr args = GenerateArgsList(expr.OptionalArguments); Expr arg2 = GenerateParamsArray(args, PredefinedType.PT_EXPRESSION); if (expr.Type.IsAggregateType() && expr.Type.AsAggregateType().getAggregate().IsAnonymousType()) { Expr arg3 = GenerateMembersArray(expr.Type.AsAggregateType(), PredefinedType.PT_METHODINFO); return GenerateCall(PREDEFMETH.PM_EXPRESSION_NEW_MEMBERS, arg, arg2, arg3); } return GenerateCall(PREDEFMETH.PM_EXPRESSION_NEW, arg, arg2); } private Expr GenerateDelegateConstructor(ExprCall expr) { ExprList exprList = (ExprList)expr.OptionalArguments; Expr optionalElement = exprList.OptionalElement; ExprFuncPtr exprFuncPtr = (ExprFuncPtr)exprList.OptionalNextListNode; MethodSymbol preDefMethod = GetPreDefMethod(PREDEFMETH.PM_METHODINFO_CREATEDELEGATE_TYPE_OBJECT); AggregateType optPredefTypeErr = GetSymbolLoader().GetOptPredefTypeErr(PredefinedType.PT_DELEGATE, true); MethWithInst mwi = new MethWithInst(preDefMethod, optPredefTypeErr); Expr arg = GenerateConstant(GetExprFactory().CreateMethodInfo(exprFuncPtr.MethWithInst)); Expr arg2 = GetExprFactory().CreateMethodInfo(mwi); Expr op = GenerateConstant(CreateTypeOf(expr.Type)); Expr op2 = Visit(optionalElement); Expr args = GetExprFactory().CreateList(op, op2); Expr arg3 = GenerateParamsArray(args, PredefinedType.PT_EXPRESSION); Expr arg4 = GenerateCall(PREDEFMETH.PM_EXPRESSION_CALL, arg, arg2, arg3); Expr arg5 = CreateTypeOf(expr.Type); return GenerateCall(PREDEFMETH.PM_EXPRESSION_CONVERT, arg4, arg5); } private Expr GenerateArgsList(Expr oldArgs) { Expr first = null; Expr last = first; ExpressionIterator expressionIterator = new ExpressionIterator(oldArgs); while (!expressionIterator.AtEnd()) { Expr pExpr = expressionIterator.Current(); GetExprFactory().AppendItemToList(Visit(pExpr), ref first, ref last); expressionIterator.MoveNext(); } return first; } private Expr GenerateIndexList(Expr oldIndices) { CType reqPredefType = symbolLoader.GetReqPredefType(PredefinedType.PT_INT, true); Expr first = null; Expr last = first; ExpressionIterator expressionIterator = new ExpressionIterator(oldIndices); while (!expressionIterator.AtEnd()) { Expr expr = expressionIterator.Current(); if (expr.Type != reqPredefType) { ExprClass pType = expressionFactory.CreateClass(reqPredefType, null); expr = expressionFactory.CreateCast(EXPRFLAG.EXF_LITERALCONST, pType, expr); expr.Flags |= EXPRFLAG.EXF_CHECKOVERFLOW; } Expr newItem = Visit(expr); expressionFactory.AppendItemToList(newItem, ref first, ref last); expressionIterator.MoveNext(); } return first; } private Expr GenerateConstant(Expr expr) { EXPRFLAG nFlags = (EXPRFLAG)0; AggregateType reqPredefType = GetSymbolLoader().GetReqPredefType(PredefinedType.PT_OBJECT, true); if (expr.Type.IsNullType()) { ExprTypeOf arg = CreateTypeOf(reqPredefType); return GenerateCall(PREDEFMETH.PM_EXPRESSION_CONSTANT_OBJECT_TYPE, expr, arg); } AggregateType reqPredefType2 = GetSymbolLoader().GetReqPredefType(PredefinedType.PT_STRING, true); if (expr.Type != reqPredefType2) nFlags = EXPRFLAG.EXF_CTOR; ExprClass pType = GetExprFactory().MakeClass(reqPredefType); ExprCast arg2 = GetExprFactory().CreateCast(nFlags, pType, expr); ExprTypeOf arg3 = CreateTypeOf(expr.Type); return GenerateCall(PREDEFMETH.PM_EXPRESSION_CONSTANT_OBJECT_TYPE, arg2, arg3); } private ExprCall GenerateCall(PREDEFMETH pdm, Expr arg1) { MethodSymbol preDefMethod = GetPreDefMethod(pdm); if (preDefMethod == null) return null; AggregateType optPredefTypeErr = GetSymbolLoader().GetOptPredefTypeErr(PredefinedType.PT_EXPRESSION, true); MethWithInst methWithInst = new MethWithInst(preDefMethod, optPredefTypeErr); ExprMemberGroup pMemberGroup = GetExprFactory().CreateMemGroup(null, methWithInst); ExprCall exprCall = GetExprFactory().CreateCall((EXPRFLAG)0, methWithInst.Meth().RetType, arg1, pMemberGroup, methWithInst); exprCall.PredefinedMethod = pdm; return exprCall; } private ExprCall GenerateCall(PREDEFMETH pdm, Expr arg1, Expr arg2) { MethodSymbol preDefMethod = GetPreDefMethod(pdm); if (preDefMethod == null) return null; AggregateType optPredefTypeErr = GetSymbolLoader().GetOptPredefTypeErr(PredefinedType.PT_EXPRESSION, true); Expr pOptionalArguments = GetExprFactory().CreateList(arg1, arg2); MethWithInst methWithInst = new MethWithInst(preDefMethod, optPredefTypeErr); ExprMemberGroup pMemberGroup = GetExprFactory().CreateMemGroup(null, methWithInst); ExprCall exprCall = GetExprFactory().CreateCall((EXPRFLAG)0, methWithInst.Meth().RetType, pOptionalArguments, pMemberGroup, methWithInst); exprCall.PredefinedMethod = pdm; return exprCall; } private ExprCall GenerateCall(PREDEFMETH pdm, Expr arg1, Expr arg2, Expr arg3) { MethodSymbol preDefMethod = GetPreDefMethod(pdm); if (preDefMethod == null) return null; AggregateType optPredefTypeErr = GetSymbolLoader().GetOptPredefTypeErr(PredefinedType.PT_EXPRESSION, true); Expr pOptionalArguments = GetExprFactory().CreateList(arg1, arg2, arg3); MethWithInst methWithInst = new MethWithInst(preDefMethod, optPredefTypeErr); ExprMemberGroup pMemberGroup = GetExprFactory().CreateMemGroup(null, methWithInst); ExprCall exprCall = GetExprFactory().CreateCall((EXPRFLAG)0, methWithInst.Meth().RetType, pOptionalArguments, pMemberGroup, methWithInst); exprCall.PredefinedMethod = pdm; return exprCall; } private ExprCall GenerateCall(PREDEFMETH pdm, Expr arg1, Expr arg2, Expr arg3, Expr arg4) { MethodSymbol preDefMethod = GetPreDefMethod(pdm); if (preDefMethod == null) return null; AggregateType optPredefTypeErr = GetSymbolLoader().GetOptPredefTypeErr(PredefinedType.PT_EXPRESSION, true); Expr pOptionalArguments = GetExprFactory().CreateList(arg1, arg2, arg3, arg4); MethWithInst methWithInst = new MethWithInst(preDefMethod, optPredefTypeErr); ExprMemberGroup pMemberGroup = GetExprFactory().CreateMemGroup(null, methWithInst); ExprCall exprCall = GetExprFactory().CreateCall((EXPRFLAG)0, methWithInst.Meth().RetType, pOptionalArguments, pMemberGroup, methWithInst); exprCall.PredefinedMethod = pdm; return exprCall; } private ExprArrayInit GenerateParamsArray(Expr args, PredefinedType pt) { int num = ExpressionIterator.Count(args); AggregateType optPredefTypeErr = GetSymbolLoader().GetOptPredefTypeErr(pt, true); ArrayType array = GetSymbolLoader().GetTypeManager().GetArray(optPredefTypeErr, 1, true); ExprConstant pOptionalArgumentDimensions = GetExprFactory().CreateIntegerConstant(num); ExprArrayInit exprArrayInit = GetExprFactory().CreateArrayInit(EXPRFLAG.EXF_CANTBENULL, array, args, pOptionalArgumentDimensions, null); exprArrayInit.DimensionSize = num; exprArrayInit.DimensionSizes = new int[1] { exprArrayInit.DimensionSize }; return exprArrayInit; } private ExprArrayInit GenerateMembersArray(AggregateType anonymousType, PredefinedType pt) { Expr first = null; Expr last = first; int num = 0; AggregateSymbol aggregate = anonymousType.getAggregate(); for (Symbol symbol = aggregate.firstChild; symbol != null; symbol = symbol.nextChild) { if (symbol.IsMethodSymbol()) { MethodSymbol methodSymbol = symbol.AsMethodSymbol(); if (methodSymbol.MethKind() == MethodKindEnum.PropAccessor) { ExprMethodInfo newItem = GetExprFactory().CreateMethodInfo(methodSymbol, anonymousType, methodSymbol.Params); GetExprFactory().AppendItemToList(newItem, ref first, ref last); num++; } } } AggregateType optPredefTypeErr = GetSymbolLoader().GetOptPredefTypeErr(pt, true); ArrayType array = GetSymbolLoader().GetTypeManager().GetArray(optPredefTypeErr, 1, true); ExprConstant pOptionalArgumentDimensions = GetExprFactory().CreateIntegerConstant(num); ExprArrayInit exprArrayInit = GetExprFactory().CreateArrayInit(EXPRFLAG.EXF_CANTBENULL, array, first, pOptionalArgumentDimensions, null); exprArrayInit.DimensionSize = num; exprArrayInit.DimensionSizes = new int[1] { exprArrayInit.DimensionSize }; return exprArrayInit; } private void FixLiftedUserDefinedBinaryOperators(ExprBinOp expr, ref Expr pp1, ref Expr pp2) { MethodSymbol methodSymbol = expr.UserDefinedCallMethod.Meth(); Expr optionalLeftChild = expr.OptionalLeftChild; Expr optionalRightChild = expr.OptionalRightChild; Expr expr2 = pp1; Expr expr3 = pp2; CType cType = methodSymbol.Params[0]; CType cType2 = methodSymbol.Params[1]; CType type = optionalLeftChild.Type; CType type2 = optionalRightChild.Type; if (!cType.IsNullableType() && !cType2.IsNullableType() && cType.IsAggregateType() && cType2.IsAggregateType() && cType.AsAggregateType().getAggregate().IsValueType() && cType2.AsAggregateType().getAggregate().IsValueType()) { CType nullable = GetSymbolLoader().GetTypeManager().GetNullable(cType); CType nullable2 = GetSymbolLoader().GetTypeManager().GetNullable(cType2); if (type.IsNullType() || (type == cType && (type2 == nullable2 || type2.IsNullType()))) expr2 = GenerateCall(PREDEFMETH.PM_EXPRESSION_CONVERT, expr2, CreateTypeOf(nullable)); if (type2.IsNullType() || (type2 == cType2 && (type == nullable || type.IsNullType()))) expr3 = GenerateCall(PREDEFMETH.PM_EXPRESSION_CONVERT, expr3, CreateTypeOf(nullable2)); pp1 = expr2; pp2 = expr3; } } private bool IsNullableValueType(CType pType) { if (pType.IsNullableType()) { CType cType = pType.StripNubs(); if (cType.IsAggregateType()) return cType.AsAggregateType().getAggregate().IsValueType(); return false; } return false; } private bool IsNullableValueAccess(Expr pExpr, Expr pObject) { ExprProperty exprProperty; if ((exprProperty = (pExpr as ExprProperty)) != null && exprProperty.MemberGroup.OptionalObject == pObject) return pObject.Type.IsNullableType(); return false; } private bool IsDelegateConstructorCall(Expr pExpr) { ExprCall exprCall; if ((exprCall = (pExpr as ExprCall)) == null) return false; ExprList exprList; if (exprCall.MethWithInst.Meth() != null && exprCall.MethWithInst.Meth().IsConstructor() && exprCall.Type.isDelegateType() && exprCall.OptionalArguments != null && (exprList = (exprCall.OptionalArguments as ExprList)) != null) return exprList.OptionalNextListNode.Kind == ExpressionKind.FunctionPointer; return false; } private static bool isEnumToDecimalConversion(CType argtype, CType desttype) { CType cType = argtype.IsNullableType() ? argtype.StripNubs() : argtype; CType cType2 = desttype.IsNullableType() ? desttype.StripNubs() : desttype; if (cType.isEnumType()) return cType2.isPredefType(PredefinedType.PT_DECIMAL); return false; } } }