public ExprMemberGroup CreateMemGroup(EXPRFLAG nFlags, Name pName, TypeArray pTypeArgs, SYMKIND symKind, CType pTypePar, MethodOrPropertySymbol pMPS, Expr pObject, CMemberLookupResults memberLookupResults) { Debug.Assert(0 == (nFlags & ~( EXPRFLAG.EXF_CTOR | EXPRFLAG.EXF_INDEXER | EXPRFLAG.EXF_OPERATOR | EXPRFLAG.EXF_NEWOBJCALL | EXPRFLAG.EXF_BASECALL | EXPRFLAG.EXF_DELEGATE | EXPRFLAG.EXF_USERCALLABLE | EXPRFLAG.EXF_MASK_ANY ) )); ExprMemberGroup rval = new ExprMemberGroup(); rval.Kind = ExpressionKind.EK_MEMGRP; rval.Type = GetTypes().GetMethGrpType(); rval.Flags = nFlags; rval.Name = pName; rval.TypeArgs = pTypeArgs; rval.SymKind = symKind; rval.ParentType = pTypePar; rval.OptionalObject = pObject; rval.MemberLookupResults = memberLookupResults; rval.OptionalLHS = null; if (rval.TypeArgs == null) { rval.TypeArgs = BSYMMGR.EmptyTypeArray(); } Debug.Assert(rval != null); return(rval); }
public ExprMultiGet(CType type, EXPRFLAG flags, ExprMulti multi) : base(ExpressionKind.MultiGet, type) { Debug.Assert((flags & ~EXPRFLAG.EXF_MASK_ANY) == 0); Flags = flags; OptionalMulti = multi; }
public EXPRMEMGRP CreateMemGroup(EXPRFLAG nFlags, Name pName, TypeArray pTypeArgs, SYMKIND symKind, CType pTypePar, MethodOrPropertySymbol pMPS, EXPR pObject, CMemberLookupResults memberLookupResults) { Debug.Assert(0 == (nFlags & ~( EXPRFLAG.EXF_CTOR | EXPRFLAG.EXF_INDEXER | EXPRFLAG.EXF_OPERATOR | EXPRFLAG.EXF_NEWOBJCALL | EXPRFLAG.EXF_BASECALL | EXPRFLAG.EXF_DELEGATE | EXPRFLAG.EXF_USERCALLABLE | EXPRFLAG.EXF_MASK_ANY ) )); EXPRMEMGRP rval = new EXPRMEMGRP(); rval.kind = ExpressionKind.EK_MEMGRP; rval.type = GetTypes().GetMethGrpType(); rval.flags = nFlags; rval.name = pName; rval.typeArgs = pTypeArgs; rval.sk = symKind; rval.SetParentType(pTypePar); rval.SetOptionalObject(pObject); rval.SetMemberLookupResults(memberLookupResults); rval.SetOptionalLHS(null); if (rval.typeArgs == null) { rval.typeArgs = BSYMMGR.EmptyTypeArray(); } Debug.Assert(rval != null); return(rval); }
private bool bindImplicitConversionToBase(AggregateType pSource) { // 13.1.4 Implicit reference conversions // // * From any reference-type to object. // * From any class-type S to any class-type T, provided S is derived from T. // * From any class-type S to any interface-type T, provided S implements T. // * From any interface-type S to any interface-type T, provided S is derived from T. // * From any delegate-type to System.Delegate. // * From any delegate-type to System.ICloneable. if (!(_typeDest is AggregateType) || !GetSymbolLoader().HasBaseConversion(pSource, _typeDest)) { return(false); } EXPRFLAG flags = 0x00; if (pSource.getAggregate().IsStruct() && _typeDest.fundType() == FUNDTYPE.FT_REF) { flags = EXPRFLAG.EXF_BOX | EXPRFLAG.EXF_CANTBENULL; } else if (_exprSrc != null) { flags = _exprSrc.Flags & EXPRFLAG.EXF_CANTBENULL; } if (_needsExprDest) { _binder.bindSimpleCast(_exprSrc, _typeDest, out _exprDest, flags); } return(true); }
public CMethodIterator(CSemanticChecker checker, SymbolLoader symLoader, Name name, TypeArray containingTypes, CType @object, CType qualifyingType, AggregateDeclaration context, bool allowBogusAndInaccessible, bool allowExtensionMethods, int arity, EXPRFLAG flags, symbmask_t mask) { Debug.Assert(name != null); Debug.Assert(symLoader != null); Debug.Assert(checker != null); Debug.Assert(containingTypes != null); _pSemanticChecker = checker; _pSymbolLoader = symLoader; _pCurrentType = null; _pCurrentSym = null; _pName = name; _pContainingTypes = containingTypes; _pQualifyingType = qualifyingType; _pContext = context; _bAllowBogusAndInaccessible = allowBogusAndInaccessible; _nArity = arity; _flags = flags; _mask = mask; _nCurrentTypeCount = 0; _bIsCheckingInstanceMethods = true; _bAtEnd = false; _bCurrentSymIsBogus = false; _bCurrentSymIsInaccessible = false; _bcanIncludeExtensionsInResults = allowExtensionMethods; _bEndIterationAtCurrentExtensionList = false; }
public EXPRTHISPOINTER CreateThis(LocalVariableSymbol pLocal, bool fImplicit) { Debug.Assert(pLocal == null || pLocal.isThis); CType type = null; if (pLocal != null) { type = pLocal.GetType(); } EXPRFLAG flags = EXPRFLAG.EXF_CANTBENULL; if (fImplicit) { flags |= EXPRFLAG.EXF_IMPLICITTHIS; } if (type != null && type.isStructType()) { flags |= EXPRFLAG.EXF_LVALUE; } EXPRTHISPOINTER rval = new EXPRTHISPOINTER(); rval.kind = ExpressionKind.EK_THISPOINTER; rval.type = type; rval.flags = flags; rval.local = pLocal; Debug.Assert(rval != null); return(rval); }
public CMethodIterator GetMethodIterator( CSemanticChecker pChecker, SymbolLoader pSymLoader, CType pObject, CType pQualifyingType, Declaration pContext, bool allowBogusAndInaccessible, bool allowExtensionMethods, int arity, EXPRFLAG flags, symbmask_t mask) { Debug.Assert(pSymLoader != null); CMethodIterator iterator = new CMethodIterator(pChecker, pSymLoader, _pName, ContainingTypes, pObject, pQualifyingType, pContext, allowBogusAndInaccessible, allowExtensionMethods, arity, flags, mask); return iterator; }
public CMethodIterator(CSemanticChecker checker, SymbolLoader symLoader, Name name, TypeArray containingTypes, CType @object, CType qualifyingType, Declaration context, bool allowBogusAndInaccessible, bool allowExtensionMethods, int arity, EXPRFLAG flags, symbmask_t mask) { Debug.Assert(name != null); Debug.Assert(symLoader != null); Debug.Assert(checker != null); Debug.Assert(containingTypes != null); _pSemanticChecker = checker; _pSymbolLoader = symLoader; _pCurrentType = null; _pCurrentSym = null; _pName = name; _pContainingTypes = containingTypes; _pQualifyingType = qualifyingType; _pContext = context; _bAllowBogusAndInaccessible = allowBogusAndInaccessible; _bAllowExtensionMethods = allowExtensionMethods; _nArity = arity; _flags = flags; _mask = mask; _nCurrentTypeCount = 0; _bIsCheckingInstanceMethods = true; _bAtEnd = false; _bCurrentSymIsBogus = false; _bCurrentSymIsInaccessible = false; _bcanIncludeExtensionsInResults = _bAllowExtensionMethods; _bEndIterationAtCurrentExtensionList = false; }
public static ExprUnaryOp CreateNeg(EXPRFLAG flags, Expr operand) { Debug.Assert(operand != null); ExprUnaryOp unary = CreateUnaryOp(ExpressionKind.Negate, operand.Type, operand); unary.Flags |= flags; return(unary); }
public ExprFuncPtr(CType type, EXPRFLAG flags, Expr optionalObject, MethWithInst method) : base(ExpressionKind.FunctionPointer, type) { Debug.Assert((flags & ~EXPRFLAG.EXF_BASECALL) == 0); Flags = flags; OptionalObject = optionalObject; MethWithInst = new MethWithInst(method); }
public EXPRUNARYOP CreateNeg(EXPRFLAG nFlags, EXPR pOperand) { Debug.Assert(pOperand != null); EXPRUNARYOP pUnaryOp = CreateUnaryOp(ExpressionKind.EK_NEG, pOperand.type, pOperand); pUnaryOp.flags |= nFlags; return(pUnaryOp); }
public ExprUnaryOp CreateNeg(EXPRFLAG nFlags, Expr pOperand) { Debug.Assert(pOperand != null); ExprUnaryOp pUnaryOp = CreateUnaryOp(ExpressionKind.EK_NEG, pOperand.Type, pOperand); pUnaryOp.Flags |= nFlags; return(pUnaryOp); }
public ExprCast(EXPRFLAG flags, CType type, Expr argument) : base(ExpressionKind.Cast, type) { Debug.Assert(argument != null); Debug.Assert((flags & ~(EXPRFLAG.EXF_CAST_ALL | EXPRFLAG.EXF_MASK_ANY)) == 0); Argument = argument; Flags = flags; }
public ExprMultiGet CreateMultiGet(EXPRFLAG nFlags, CType pType, ExprMulti pOptionalMulti) { Debug.Assert(0 == (nFlags & ~(EXPRFLAG.EXF_MASK_ANY))); ExprMultiGet rval = new ExprMultiGet(pType); rval.Flags = nFlags; rval.OptionalMulti = pOptionalMulti; return(rval); }
public ExprLocal CreateLocal(EXPRFLAG nFlags, LocalVariableSymbol pLocal) { Debug.Assert(0 == (nFlags & ~(EXPRFLAG.EXF_MASK_ANY))); ExprLocal rval = new ExprLocal(); rval.Flags = nFlags; rval.Local = pLocal; return(rval); }
public ExprMulti(CType type, EXPRFLAG flags, Expr left, Expr op) : base(ExpressionKind.Multi, type) { Debug.Assert(left != null); Debug.Assert(op != null); Flags = flags; Left = left; Operator = op; }
public ExprFuncPtr CreateFunctionPointer(EXPRFLAG nFlags, CType pType, Expr pObject, MethWithInst MWI) { Debug.Assert(0 == (nFlags & ~(EXPRFLAG.EXF_BASECALL))); ExprFuncPtr rval = new ExprFuncPtr(pType); rval.Flags = nFlags; rval.OptionalObject = pObject; rval.MethWithInst = new MethWithInst(MWI); return(rval); }
public ExprField CreateField(EXPRFLAG nFlags, CType pType, Expr pOptionalObject, FieldWithType FWT) { Debug.Assert(0 == (nFlags & ~(EXPRFLAG.EXF_MEMBERSET | EXPRFLAG.EXF_MASK_ANY))); ExprField rval = new ExprField(pType); rval.Flags = nFlags; rval.OptionalObject = pOptionalObject; rval.FieldWithType = FWT; return(rval); }
public ExprCast(EXPRFLAG flags, ExprClass destinationType, Expr argument) : base(ExpressionKind.Cast) { Debug.Assert(argument != null); Debug.Assert(destinationType != null); Debug.Assert((flags & ~(EXPRFLAG.EXF_CAST_ALL | EXPRFLAG.EXF_MASK_ANY)) == 0); Argument = argument; Flags = flags; DestinationType = destinationType; }
public ExprMulti CreateMulti(EXPRFLAG nFlags, CType pType, Expr pLeft, Expr pOp) { Debug.Assert(pLeft != null); Debug.Assert(pOp != null); ExprMulti rval = new ExprMulti(pType); rval.Flags = nFlags; rval.Left = pLeft; rval.Operator = pOp; return(rval); }
public ExprMultiGet CreateMultiGet(EXPRFLAG nFlags, CType pType, ExprMulti pOptionalMulti) { Debug.Assert(0 == (nFlags & ~(EXPRFLAG.EXF_MASK_ANY))); ExprMultiGet rval = new ExprMultiGet(); rval.Kind = ExpressionKind.EK_MULTIGET; rval.Type = pType; rval.Flags = nFlags; rval.OptionalMulti = pOptionalMulti; Debug.Assert(rval != null); return(rval); }
public EXPRFUNCPTR CreateFunctionPointer(EXPRFLAG nFlags, CType pType, EXPR pObject, MethWithInst MWI) { Debug.Assert(0 == (nFlags & ~(EXPRFLAG.EXF_BASECALL))); EXPRFUNCPTR rval = new EXPRFUNCPTR(); rval.kind = ExpressionKind.EK_FUNCPTR; rval.type = pType; rval.flags = nFlags; rval.OptionalObject = pObject; rval.mwi = new MethWithInst(MWI); Debug.Assert(rval != null); return (rval); }
public ExprCast CreateCast(EXPRFLAG nFlags, ExprClass pType, Expr pArg) { Debug.Assert(pArg != null); Debug.Assert(pType != null); Debug.Assert(0 == (nFlags & ~(EXPRFLAG.EXF_CAST_ALL | EXPRFLAG.EXF_MASK_ANY))); ExprCast rval = new ExprCast(); rval.Argument = pArg; rval.Flags = nFlags; rval.DestinationType = pType; return(rval); }
public EXPRMULTIGET CreateMultiGet(EXPRFLAG nFlags, CType pType, EXPRMULTI pOptionalMulti) { Debug.Assert(0 == (nFlags & ~(EXPRFLAG.EXF_MASK_ANY))); EXPRMULTIGET rval = new EXPRMULTIGET(); rval.kind = ExpressionKind.EK_MULTIGET; rval.type = pType; rval.flags = nFlags; rval.SetOptionalMulti(pOptionalMulti); Debug.Assert(rval != null); return(rval); }
public ExprArrayInit CreateArrayInit(EXPRFLAG nFlags, CType pType, Expr pOptionalArguments, Expr pOptionalArgumentDimensions, int[] pDimSizes) { Debug.Assert(0 == (nFlags & ~(EXPRFLAG.EXF_MASK_ANY | EXPRFLAG.EXF_ARRAYCONST | EXPRFLAG.EXF_ARRAYALLCONST))); ExprArrayInit rval = new ExprArrayInit(pType); rval.OptionalArguments = pOptionalArguments; rval.OptionalArgumentDimensions = pOptionalArgumentDimensions; rval.DimensionSizes = pDimSizes; rval.DimensionSize = pDimSizes?.Length ?? 0; return(rval); }
public ExprCall(CType type, EXPRFLAG flags, Expr arguments, ExprMemberGroup member, MethWithInst method) : base(ExpressionKind.Call, type) { Debug.Assert( (flags & ~(EXPRFLAG.EXF_NEWOBJCALL | EXPRFLAG.EXF_CONSTRAINED | EXPRFLAG.EXF_NEWSTRUCTASSG | EXPRFLAG.EXF_IMPLICITSTRUCTASSG | EXPRFLAG.EXF_MASK_ANY)) == 0); Flags = flags; OptionalArguments = arguments; MemberGroup = member; NullableCallLiftKind = NullableCallLiftKind.NotLifted; MethWithInst = method; }
public ExprFuncPtr CreateFunctionPointer(EXPRFLAG nFlags, CType pType, Expr pObject, MethWithInst MWI) { Debug.Assert(0 == (nFlags & ~(EXPRFLAG.EXF_BASECALL))); ExprFuncPtr rval = new ExprFuncPtr(); rval.Kind = ExpressionKind.EK_FUNCPTR; rval.Type = pType; rval.Flags = nFlags; rval.OptionalObject = pObject; rval.MethWithInst = new MethWithInst(MWI); Debug.Assert(rval != null); return(rval); }
public EXPRFUNCPTR CreateFunctionPointer(EXPRFLAG nFlags, CType pType, EXPR pObject, MethWithInst MWI) { Debug.Assert(0 == (nFlags & ~(EXPRFLAG.EXF_BASECALL))); EXPRFUNCPTR rval = new EXPRFUNCPTR(); rval.kind = ExpressionKind.EK_FUNCPTR; rval.type = pType; rval.flags = nFlags; rval.OptionalObject = pObject; rval.mwi = new MethWithInst(MWI); Debug.Assert(rval != null); return(rval); }
public ExprMulti CreateMulti(EXPRFLAG nFlags, CType pType, Expr pLeft, Expr pOp) { Debug.Assert(pLeft != null); Debug.Assert(pOp != null); ExprMulti rval = new ExprMulti(); rval.Kind = ExpressionKind.EK_MULTI; rval.Type = pType; rval.Flags = nFlags; rval.Left = pLeft; rval.Operator = pOp; Debug.Assert(rval != null); return(rval); }
public ExprReturn CreateReturn(EXPRFLAG nFlags, Scope pCurrentScope, Expr pOptionalObject) { Debug.Assert(0 == (nFlags & ~(EXPRFLAG.EXF_ASLEAVE | EXPRFLAG.EXF_FINALLYBLOCKED | EXPRFLAG.EXF_RETURNISYIELD | EXPRFLAG.EXF_ASFINALLYLEAVE | EXPRFLAG.EXF_GENERATEDSTMT | EXPRFLAG.EXF_MARKING | EXPRFLAG.EXF_MASK_ANY ) )); ExprReturn rval = new ExprReturn(); rval.Flags = nFlags; rval.OptionalObject = pOptionalObject; return(rval); }
public EXPRMULTI CreateMulti(EXPRFLAG nFlags, CType pType, EXPR pLeft, EXPR pOp) { Debug.Assert(pLeft != null); Debug.Assert(pOp != null); EXPRMULTI rval = new EXPRMULTI(); rval.kind = ExpressionKind.EK_MULTI; rval.type = pType; rval.flags = nFlags; rval.SetLeft(pLeft); rval.SetOperator(pOp); Debug.Assert(rval != null); return(rval); }
public EXPRFIELD CreateField(EXPRFLAG nFlags, CType pType, EXPR pOptionalObject, uint nOffset, FieldWithType FWT, EXPR pOptionalLHS) { Debug.Assert(0 == (nFlags & ~(EXPRFLAG.EXF_MEMBERSET | EXPRFLAG.EXF_MASK_ANY))); EXPRFIELD rval = new EXPRFIELD(); rval.kind = ExpressionKind.EK_FIELD; rval.type = pType; rval.flags = nFlags; rval.SetOptionalObject(pOptionalObject); if (FWT != null) { rval.fwt = FWT; } Debug.Assert(rval != null); return (rval); }
public ExprMemberGroup(CType type, EXPRFLAG flags, Name name, TypeArray typeArgs, SYMKIND symKind, CType parentType, MethodOrPropertySymbol pMPS, Expr optionalObject, CMemberLookupResults memberLookupResults) : base(ExpressionKind.MemberGroup, type) { Debug.Assert( (flags & ~(EXPRFLAG.EXF_CTOR | EXPRFLAG.EXF_INDEXER | EXPRFLAG.EXF_OPERATOR | EXPRFLAG.EXF_NEWOBJCALL | EXPRFLAG.EXF_BASECALL | EXPRFLAG.EXF_DELEGATE | EXPRFLAG.EXF_USERCALLABLE | EXPRFLAG.EXF_MASK_ANY)) == 0); Flags = flags; Name = name; TypeArgs = typeArgs ?? BSYMMGR.EmptyTypeArray(); SymKind = symKind; ParentType = parentType; OptionalObject = optionalObject; MemberLookupResults = memberLookupResults; }
public EXPRARRINIT CreateArrayInit(EXPRFLAG nFlags, CType pType, EXPR pOptionalArguments, EXPR pOptionalArgumentDimensions, int[] pDimSizes) { Debug.Assert(0 == (nFlags & ~(EXPRFLAG.EXF_MASK_ANY | EXPRFLAG.EXF_ARRAYCONST | EXPRFLAG.EXF_ARRAYALLCONST))); EXPRARRINIT rval = new EXPRARRINIT(); rval.kind = ExpressionKind.EK_ARRINIT; rval.type = pType; rval.SetOptionalArguments(pOptionalArguments); rval.SetOptionalArgumentDimensions(pOptionalArgumentDimensions); rval.dimSizes = pDimSizes; rval.dimSize = pDimSizes != null ? pDimSizes.Length : 0; Debug.Assert(rval != null); return(rval); }
public EXPRCALL CreateCall(EXPRFLAG nFlags, CType pType, EXPR pOptionalArguments, EXPRMEMGRP pMemberGroup, MethWithInst MWI) { Debug.Assert(0 == (nFlags & ~( EXPRFLAG.EXF_NEWOBJCALL | EXPRFLAG.EXF_CONSTRAINED | EXPRFLAG.EXF_BASECALL | EXPRFLAG.EXF_NEWSTRUCTASSG | EXPRFLAG.EXF_IMPLICITSTRUCTASSG | EXPRFLAG.EXF_MASK_ANY ) )); EXPRCALL rval = new EXPRCALL(); rval.kind = ExpressionKind.EK_CALL; rval.type = pType; rval.flags = nFlags; rval.SetOptionalArguments(pOptionalArguments); rval.SetMemberGroup(pMemberGroup); rval.nubLiftKind = NullableCallLiftKind.NotLifted; rval.castOfNonLiftedResultToLiftedType = null; rval.mwi = MWI; Debug.Assert(rval != null); return (rval); }
/* Handles boolean unary operator (!). */ private EXPR BindBoolUnaOp(ExpressionKind ek, EXPRFLAG flags, EXPR arg) { Debug.Assert(arg.type.isPredefType(PredefinedType.PT_BOOL)); Debug.Assert(ek == ExpressionKind.EK_LOGNOT); // Get the result type and operand type. CType typeBool = GetReqPDT(PredefinedType.PT_BOOL); // Determine if arg has a constant value. // Strip off EXPRKIND.EK_SEQUENCE for constant checking. EXPR argConst = arg.GetConst(); if (argConst == null) return GetExprFactory().CreateUnaryOp(ExpressionKind.EK_LOGNOT, typeBool, arg); bool fRes = argConst.asCONSTANT().getVal().iVal != 0; EXPR rval = GetExprFactory().CreateConstant(typeBool, ConstValFactory.GetBool(!fRes)); return rval; }
/* Convert and constant fold an expression involving I4, U4, I8 or U8 operands. The operands are assumed to be already converted to the correct types. */ private EXPR BindIntOp(ExpressionKind kind, EXPRFLAG flags, EXPR op1, EXPR op2, PredefinedType ptOp) { //Debug.Assert(kind.isRelational() || kind.isArithmetic() || kind.isBitwise()); Debug.Assert(ptOp == PredefinedType.PT_INT || ptOp == PredefinedType.PT_UINT || ptOp == PredefinedType.PT_LONG || ptOp == PredefinedType.PT_ULONG); CType typeOp = GetReqPDT(ptOp); Debug.Assert(typeOp != null); Debug.Assert(op1 != null && op1.type == typeOp); Debug.Assert(op2 == null || op2.type == typeOp); Debug.Assert((op2 == null) == (kind == ExpressionKind.EK_NEG || kind == ExpressionKind.EK_UPLUS || kind == ExpressionKind.EK_BITNOT)); if (isDivByZero(kind, op2)) { GetErrorContext().Error(ErrorCode.ERR_IntDivByZero); EXPR rval = GetExprFactory().CreateBinop(kind, typeOp, op1, op2); rval.SetError(); return rval; } // This optimization CANNOT be moved to a later pass. See comments in // FoldIntegerConstants. EXPR exprFolded = FoldIntegerConstants(kind, flags, op1, op2, ptOp); if (exprFolded != null) { return exprFolded; } if (kind == ExpressionKind.EK_NEG) { return BindIntegerNeg(flags, op1, ptOp); } CType typeDest = kind.isRelational() ? GetReqPDT(PredefinedType.PT_BOOL) : typeOp; EXPR exprRes = GetExprFactory().CreateOperator(kind, typeDest, op1, op2); exprRes.flags |= flags; Debug.Assert((exprRes.flags & EXPRFLAG.EXF_LVALUE) == 0); return exprRes; }
private EXPRMULTI BindLiftedIncOp(ExpressionKind ek, EXPRFLAG flags, EXPR arg, UnaOpFullSig uofs) { Debug.Assert(ek == ExpressionKind.EK_ADD || ek == ExpressionKind.EK_SUB); Debug.Assert(uofs.isLifted()); NullableType type = uofs.GetType().AsNullableType(); Debug.Assert(arg != null); EXPR exprVal; #if ! CSEE EXPRMULTIGET exprGet = GetExprFactory().CreateMultiGet(EXPRFLAG.EXF_ASSGOP, arg.type, null); exprVal = exprGet; #else exprVal = arg; #endif EXPR nonLiftedResult = null; EXPR nonLiftedArg = exprVal; // We want to give the lifted argument as the binop, but use the non-lifted argument as the // argument of the call. //Debug.Assert(uofs.LiftArg() || type.IsValType()); nonLiftedArg = mustCast(nonLiftedArg, type.GetUnderlyingType()); nonLiftedResult = BindIncOpCore(ek, flags, nonLiftedArg, type.GetUnderlyingType()); exprVal = mustCast(exprVal, type); EXPRUNARYOP exprRes = GetExprFactory().CreateUnaryOp((ek == ExpressionKind.EK_ADD) ? ExpressionKind.EK_INC : ExpressionKind.EK_DEC, arg.type/* type */, exprVal); mustCast(mustCast(nonLiftedResult, type), arg.type); exprRes.flags |= flags; EXPRMULTI exprMulti = GetExprFactory().CreateMulti(EXPRFLAG.EXF_ASSGOP | flags, arg.type, arg, exprRes); #if ! CSEE exprGet.SetOptionalMulti(exprMulti); #endif return exprMulti; }
/* Handles standard unary decimal based operators. */ private EXPR BindDecUnaOp(ExpressionKind ek, EXPRFLAG flags, EXPR arg) { Debug.Assert(arg.type.isPredefType(PredefinedType.PT_DECIMAL)); Debug.Assert(ek == ExpressionKind.EK_NEG || ek == ExpressionKind.EK_UPLUS); CType typeDec = GetOptPDT(PredefinedType.PT_DECIMAL); Debug.Assert(typeDec != null); ek = ek == ExpressionKind.EK_NEG ? ExpressionKind.EK_DECIMALNEG : ExpressionKind.EK_UPLUS; // We want to fold if the argument is constant. Otherwise, keep the regular op. EXPR argConst = arg.GetConst(); if (argConst == null) // Non-constant. { if (ek == ExpressionKind.EK_DECIMALNEG) { PREDEFMETH predefMeth = PREDEFMETH.PM_DECIMAL_OPUNARYMINUS; return CreateUnaryOpForPredefMethodCall(ek, predefMeth, typeDec, arg); } return GetExprFactory().CreateUnaryOp(ek, typeDec, arg); } // If its a uplus, just return it. if (ek == ExpressionKind.EK_UPLUS) { return arg; } decimal dec = argConst.asCONSTANT().getVal().decVal; dec = dec * -1; // Allocate the result node. CONSTVAL cv = GetExprConstants().Create(dec); EXPR exprRes = GetExprFactory().CreateConstant(typeDec, cv); return exprRes; }
/* Handles string concatenation. */ private EXPR BindStrBinOp(ExpressionKind ek, EXPRFLAG flags, EXPR arg1, EXPR arg2) { Debug.Assert(ek == ExpressionKind.EK_ADD); Debug.Assert(arg1.type.isPredefType(PredefinedType.PT_STRING) || arg2.type.isPredefType(PredefinedType.PT_STRING)); return bindStringConcat(arg1, arg2); }
/* Bind a bool binary operator: ==, !=, &&, ||, , |, ^. If both operands are constant, the result will be a constant also. */ private EXPR BindBoolBinOp(ExpressionKind ek, EXPRFLAG flags, EXPR arg1, EXPR arg2) { Debug.Assert(arg1 != null); Debug.Assert(arg2 != null); Debug.Assert(arg1.type.isPredefType(PredefinedType.PT_BOOL) || (arg1.type.IsNullableType() && arg2.type.AsNullableType().GetUnderlyingType().isPredefType(PredefinedType.PT_BOOL))); Debug.Assert(arg2.type.isPredefType(PredefinedType.PT_BOOL) || (arg2.type.IsNullableType() && arg2.type.AsNullableType().GetUnderlyingType().isPredefType(PredefinedType.PT_BOOL))); EXPR exprRes = GetExprFactory().CreateBinop(ek, GetReqPDT(PredefinedType.PT_BOOL), arg1, arg2); return exprRes; }
/* Given a binary operator EXPRKIND, get the BinOpKind and flags. */ private bool GetBinopKindAndFlags(ExpressionKind ek, out BinOpKind pBinopKind, out EXPRFLAG flags) { flags = 0; switch (ek) { case ExpressionKind.EK_ADD: if (Context.CheckedNormal) { flags |= EXPRFLAG.EXF_CHECKOVERFLOW; } pBinopKind = BinOpKind.Add; break; case ExpressionKind.EK_SUB: if (Context.CheckedNormal) { flags |= EXPRFLAG.EXF_CHECKOVERFLOW; } pBinopKind = BinOpKind.Sub; break; case ExpressionKind.EK_DIV: case ExpressionKind.EK_MOD: // EXPRKIND.EK_DIV and EXPRKIND.EK_MOD need to be treated special for hasSideEffects, // hence the EXPRFLAG.EXF_ASSGOP. Yes, this is a hack. flags |= EXPRFLAG.EXF_ASSGOP; if (Context.CheckedNormal) { flags |= EXPRFLAG.EXF_CHECKOVERFLOW; } pBinopKind = BinOpKind.Mul; break; case ExpressionKind.EK_MUL: if (Context.CheckedNormal) { flags |= EXPRFLAG.EXF_CHECKOVERFLOW; } pBinopKind = BinOpKind.Mul; break; case ExpressionKind.EK_BITAND: case ExpressionKind.EK_BITOR: pBinopKind = BinOpKind.Bitwise; break; case ExpressionKind.EK_BITXOR: pBinopKind = BinOpKind.BitXor; break; case ExpressionKind.EK_LSHIFT: case ExpressionKind.EK_RSHIFT: pBinopKind = BinOpKind.Shift; break; case ExpressionKind.EK_LOGOR: case ExpressionKind.EK_LOGAND: pBinopKind = BinOpKind.Logical; break; case ExpressionKind.EK_LT: case ExpressionKind.EK_LE: case ExpressionKind.EK_GT: case ExpressionKind.EK_GE: pBinopKind = BinOpKind.Compare; break; case ExpressionKind.EK_EQ: case ExpressionKind.EK_NE: pBinopKind = BinOpKind.Equal; break; default: VSFAIL("Bad ek"); pBinopKind = BinOpKind.Add; return false; } return true; }
public void bindSimpleCast(EXPR exprSrc, EXPRTYPEORNAMESPACE exprTypeDest, out EXPR pexprDest, EXPRFLAG exprFlags) { Debug.Assert(exprTypeDest != null); Debug.Assert(exprTypeDest.TypeOrNamespace != null); Debug.Assert(exprTypeDest.TypeOrNamespace.IsType()); CType typeDest = exprTypeDest.TypeOrNamespace.AsType(); pexprDest = null; // If the source is a constant, and cast is really simple (no change in fundamental // type, no flags), then create a new constant node with the new type instead of // creating a cast node. This allows compile-time constants to be easily recognized. EXPR exprConst = exprSrc.GetConst(); // Make the cast expr anyway, and if we find that we have a constant, then set the cast expr // as the original tree for the constant. Otherwise, return the cast expr. EXPRCAST exprCast = GetExprFactory().CreateCast(exprFlags, exprTypeDest, exprSrc); if (Context.CheckedNormal) { exprCast.flags |= EXPRFLAG.EXF_CHECKOVERFLOW; } // Check if we have a compile time constant. If we do, create a constant for it and set the // original tree to the cast. if (exprConst != null && exprFlags == 0 && exprSrc.type.fundType() == typeDest.fundType() && (!exprSrc.type.isPredefType(PredefinedType.PT_STRING) || exprConst.asCONSTANT().getVal().IsNullRef())) { EXPRCONSTANT expr = GetExprFactory().CreateConstant(typeDest, exprConst.asCONSTANT().getVal()); pexprDest = expr; return; } pexprDest = exprCast; Debug.Assert(exprCast.GetArgument() != null); return; }
private EXPR BindLiftedStandardBinOp(BinOpArgInfo info, BinOpFullSig bofs, ExpressionKind ek, EXPRFLAG flags) { Debug.Assert(bofs.Type1().IsNullableType() || bofs.Type2().IsNullableType()); EXPR arg1 = info.arg1; EXPR arg2 = info.arg2; // We want to get the base types of the arguments and attempt to bind the non-lifted form of the // method so that we error report (ie divide by zero etc), and then we store in the resulting // binop that we have a lifted operator. EXPR pArgument1 = null; EXPR pArgument2 = null; EXPR nonLiftedArg1 = null; EXPR nonLiftedArg2 = null; EXPR nonLiftedResult = null; CType resultType = null; LiftArgument(arg1, bofs.Type1(), bofs.ConvertFirst(), out pArgument1, out nonLiftedArg1); LiftArgument(arg2, bofs.Type2(), bofs.ConvertSecond(), out pArgument2, out nonLiftedArg2); // Now call the non-lifted method to generate errors, and stash the result. if (!nonLiftedArg1.isNull() && !nonLiftedArg2.isNull()) { // Only compute the method if theres no nulls. If there are, we'll special case it // later, since operations with a null operand are null. nonLiftedResult = bofs.pfn(ek, flags, nonLiftedArg1, nonLiftedArg2); } // Check if we have a comparison. If so, set the result type to bool. if (info.binopKind == BinOpKind.Compare || info.binopKind == BinOpKind.Equal) { resultType = GetReqPDT(PredefinedType.PT_BOOL); } else { if (bofs.fnkind == BinOpFuncKind.EnumBinOp) { AggregateType enumType; resultType = GetEnumBinOpType(ek, nonLiftedArg1.type, nonLiftedArg2.type, out enumType); } else { resultType = pArgument1.type; } resultType = resultType.IsNullableType() ? resultType : GetSymbolLoader().GetTypeManager().GetNullable(resultType); } EXPRBINOP exprRes = GetExprFactory().CreateBinop(ek, resultType, pArgument1, pArgument2); mustCast(nonLiftedResult, resultType, 0); exprRes.isLifted = true; exprRes.flags |= flags; Debug.Assert((exprRes.flags & EXPRFLAG.EXF_LVALUE) == 0); return exprRes; }
protected EXPR BindStandardBinopCore(BinOpArgInfo info, BinOpFullSig bofs, ExpressionKind ek, EXPRFLAG flags) { if (bofs.pfn == null) { return BadOperatorTypesError(ek, info.arg1, info.arg2); } if (!bofs.isLifted() || !bofs.AutoLift()) { EXPR expr1 = info.arg1; EXPR expr2 = info.arg2; if (bofs.ConvertOperandsBeforeBinding()) { expr1 = mustConvert(expr1, bofs.Type1()); expr2 = mustConvert(expr2, bofs.Type2()); } if (bofs.fnkind == BinOpFuncKind.BoolBitwiseOp) { return BindBoolBitwiseOp(ek, flags, expr1, expr2, bofs); } return bofs.pfn(ek, flags, expr1, expr2); } Debug.Assert(bofs.fnkind != BinOpFuncKind.BoolBitwiseOp); return BindLiftedStandardBinOp(info, bofs, ek, flags); }
/* Bind an float/double operator: +, -, , /, %, <, >, <=, >=, ==, !=. If both operations are constants, the result will be a constant also. op2 can be null for a unary operator. The operands are assumed to be already converted to the correct type. */ // We have an intentional divide by 0 there, so disable the warning... #if _MSC_VER #pragma warning( disable : 4723 ) #endif private EXPR bindFloatOp(ExpressionKind kind, EXPRFLAG flags, EXPR op1, EXPR op2) { //Debug.Assert(kind.isRelational() || kind.isArithmetic()); Debug.Assert(op2 == null || op1.type == op2.type); Debug.Assert(op1.type.isPredefType(PredefinedType.PT_FLOAT) || op1.type.isPredefType(PredefinedType.PT_DOUBLE)); EXPR exprRes; EXPR opConst1 = op1.GetConst(); EXPR opConst2 = op2 != null ? op2.GetConst() : null; // Check for constants and fold them. if (opConst1 != null && (op2 == null || opConst2 != null)) { // Get the operands double d1 = opConst1.asCONSTANT().getVal().doubleVal; double d2 = opConst2 != null ? opConst2.asCONSTANT().getVal().doubleVal : 0.0; double result = 0; // if isBoolResult is false bool result_b = false; // if isBoolResult is true // Do the operation. switch (kind) { case ExpressionKind.EK_ADD: result = d1 + d2; break; case ExpressionKind.EK_SUB: result = d1 - d2; break; case ExpressionKind.EK_MUL: result = d1 * d2; break; case ExpressionKind.EK_DIV: result = d1 / d2; break; case ExpressionKind.EK_NEG: result = -d1; break; case ExpressionKind.EK_UPLUS: result = d1; break; case ExpressionKind.EK_MOD: result = d1 % d2; break; case ExpressionKind.EK_EQ: result_b = (d1 == d2); break; case ExpressionKind.EK_NE: result_b = (d1 != d2); break; case ExpressionKind.EK_LE: result_b = (d1 <= d2); break; case ExpressionKind.EK_LT: result_b = (d1 < d2); break; case ExpressionKind.EK_GE: result_b = (d1 >= d2); break; case ExpressionKind.EK_GT: result_b = (d1 > d2); break; default: Debug.Assert(false); result = 0.0; // unexpected operation. break; } CType typeDest; CONSTVAL cv = new CONSTVAL(); // Allocate the result node. if (kind.isRelational()) { cv.iVal = result_b ? 1 : 0; typeDest = GetReqPDT(PredefinedType.PT_BOOL); } else { // NaN has some implementation defined bits that differ between platforms. // Normalize it to produce identical images across all platforms /* * How do we get here? if (_isnan(result)) { cv = ConstValFactory.GetNan(); } else { * */ cv = GetExprConstants().Create(result); typeDest = op1.type; } exprRes = GetExprFactory().CreateConstant(typeDest, cv); } else { // Allocate the result expression. CType typeDest = kind.isRelational() ? GetReqPDT(PredefinedType.PT_BOOL) : op1.type; exprRes = GetExprFactory().CreateOperator(kind, typeDest, op1, op2); flags = ~EXPRFLAG.EXF_CHECKOVERFLOW; exprRes.flags |= flags; } return exprRes; }
private EXPR BindIntegerNeg(EXPRFLAG flags, EXPR op, PredefinedType ptOp) { // 14.6.2 Unary minus operator // For an operation of the form -x, unary operator overload resolution (14.2.3) is applied to select // a specific operator implementation. The operand is converted to the parameter type of the selected // operator, and the type of the result is the return type of the operator. The predefined negation // operators are: // // Integer negation: // // int operator -(int x); // long operator -(long x); // // The result is computed by subtracting x from zero. In a checked context, if the value of x is the // smallest int or long (-2^31 or -2^63, respectively), a System.OverflowException is thrown. In an // unchecked context, if the value of x is the smallest int or long, the result is that same value // and the overflow is not reported. // // If the operand of the negation operator is of type uint, it is converted to type long, and the // type of the result is long. An exception is the rule that permits the int value -2147483648 (-2^31) // to be written as a decimal integer literal (9.4.4.2). // // Negation of ulong is an error: // // void operator -(ulong x); // // Selection of this operator by unary operator overload resolution (14.2.3) always results in a // compile-time error. Consequently, if the operand of the negation operator is of type ulong, a // compile-time error occurs. An exception is the rule that permits the long value // -9223372036854775808 (-2^63) to be written as a decimal integer literal (9.4.4.2). Debug.Assert(ptOp == PredefinedType.PT_INT || ptOp == PredefinedType.PT_UINT || ptOp == PredefinedType.PT_LONG || ptOp == PredefinedType.PT_ULONG); CType typeOp = GetReqPDT(ptOp); Debug.Assert(typeOp != null); Debug.Assert(op != null && op.type == typeOp); if (ptOp == PredefinedType.PT_ULONG) { return BadOperatorTypesError(ExpressionKind.EK_NEG, op, null); } if (ptOp == PredefinedType.PT_UINT && op.type.fundType() == FUNDTYPE.FT_U4) { EXPRCLASS exprObj = GetExprFactory().MakeClass(GetReqPDT(PredefinedType.PT_LONG)); op = mustConvertCore(op, exprObj, CONVERTTYPE.NOUDC); } EXPR exprRes = GetExprFactory().CreateNeg(flags, op); Debug.Assert(0 == (exprRes.flags & EXPRFLAG.EXF_LVALUE)); return exprRes; }
private EXPR BindLiftedBoolBitwiseOp(ExpressionKind ek, EXPRFLAG flags, EXPR expr1, EXPR expr2) { return null; }
private EXPR BindBoolBitwiseOp(ExpressionKind ek, EXPRFLAG flags, EXPR expr1, EXPR expr2, BinOpFullSig bofs) { Debug.Assert(ek == ExpressionKind.EK_BITAND || ek == ExpressionKind.EK_BITOR); Debug.Assert(expr1.type.isPredefType(PredefinedType.PT_BOOL) || expr1.type.IsNullableType() && expr1.type.AsNullableType().GetUnderlyingType().isPredefType(PredefinedType.PT_BOOL)); Debug.Assert(expr2.type.isPredefType(PredefinedType.PT_BOOL) || expr2.type.IsNullableType() && expr2.type.AsNullableType().GetUnderlyingType().isPredefType(PredefinedType.PT_BOOL)); if (expr1.type.IsNullableType() || expr2.type.IsNullableType()) { CType typeBool = GetReqPDT(PredefinedType.PT_BOOL); CType typeRes = GetSymbolLoader().GetTypeManager().GetNullable(typeBool); // Get the non-lifted result. EXPR nonLiftedArg1 = CNullable.StripNullableConstructor(expr1); EXPR nonLiftedArg2 = CNullable.StripNullableConstructor(expr2); EXPR nonLiftedResult = null; if (!nonLiftedArg1.type.IsNullableType() && !nonLiftedArg2.type.IsNullableType()) { nonLiftedResult = BindBoolBinOp(ek, flags, nonLiftedArg1, nonLiftedArg2); } // Make the binop and set that its lifted. EXPRBINOP exprRes = GetExprFactory().CreateBinop(ek, typeRes, expr1, expr2); if (nonLiftedResult != null) { // Bitwise operators can have null non-lifted results if we have a nub sym somewhere. mustCast(nonLiftedResult, typeRes, 0); } exprRes.isLifted = true; exprRes.flags |= flags; Debug.Assert((exprRes.flags & EXPRFLAG.EXF_LVALUE) == 0); return exprRes; } return BindBoolBinOp(ek, flags, expr1, expr2); }
/* Handles pointer comparison operators. */ private EXPR BindPtrCmpOp(ExpressionKind ek, EXPRFLAG flags, EXPR arg1, EXPR arg2) { return null; }
/* Bind a shift operator: <<, >>. These can have integer or long first operands, and second operand must be int. */ private EXPR BindShiftOp(ExpressionKind ek, EXPRFLAG flags, EXPR arg1, EXPR arg2) { Debug.Assert(ek == ExpressionKind.EK_LSHIFT || ek == ExpressionKind.EK_RSHIFT); Debug.Assert(arg1.type.isPredefined()); Debug.Assert(arg2.type.isPredefType(PredefinedType.PT_INT)); PredefinedType ptOp = arg1.type.getPredefType(); Debug.Assert(ptOp == PredefinedType.PT_INT || ptOp == PredefinedType.PT_UINT || ptOp == PredefinedType.PT_LONG || ptOp == PredefinedType.PT_ULONG); // We want to check up front if we have two constants, because constant folding is supposed to // happen in the initial binding pass. EXPR argConst1 = arg1.GetConst(); EXPR argConst2 = arg2.GetConst(); if (argConst1 == null || argConst2 == null) // One or more aren't constants, so don't fold anything. { return GetExprFactory().CreateBinop(ek, arg1.type, arg1, arg2); } // Both constants, so fold them. CONSTVAL cv = new CONSTVAL(); int cbit = (ptOp == PredefinedType.PT_LONG || ptOp == PredefinedType.PT_ULONG) ? 0x3f : 0x1f; cv.iVal = argConst2.asCONSTANT().getVal().iVal & cbit; cbit = cv.iVal; // Fill in the CONSTVAL. if (ptOp == PredefinedType.PT_LONG || ptOp == PredefinedType.PT_ULONG) { Debug.Assert(0 <= cbit && cbit < 0x40); ulong u1 = argConst1.asCONSTANT().getVal().ulongVal; ulong uval; switch (ek) { case ExpressionKind.EK_LSHIFT: uval = u1 << cbit; break; case ExpressionKind.EK_RSHIFT: uval = (ptOp == PredefinedType.PT_LONG) ? (ulong)((long)u1 >> cbit) : (u1 >> cbit); break; default: VSFAIL("Unknown op"); uval = 0; break; } cv = GetExprConstants().Create(uval); } else { Debug.Assert(0 <= cbit && cbit < 0x20); uint u1 = argConst1.asCONSTANT().getVal().uiVal; switch (ek) { case ExpressionKind.EK_LSHIFT: cv.uiVal = u1 << cbit; break; case ExpressionKind.EK_RSHIFT: cv.uiVal = (ptOp == PredefinedType.PT_INT) ? (uint)((int)u1 >> cbit) : (u1 >> cbit); break; default: VSFAIL("Unknown op"); cv.uiVal = 0; break; } } EXPR exprRes = GetExprFactory().CreateConstant(GetReqPDT(ptOp), cv); return exprRes; }
/* Handles enum binary operators. */ private EXPR BindEnumBinOp(ExpressionKind ek, EXPRFLAG flags, EXPR arg1, EXPR arg2) { AggregateType typeEnum = null; AggregateType typeDst = GetEnumBinOpType(ek, arg1.type, arg2.type, out typeEnum); Debug.Assert(typeEnum != null); PredefinedType ptOp; switch (typeEnum.fundType()) { default: // Promote all smaller types to int. ptOp = PredefinedType.PT_INT; break; case FUNDTYPE.FT_U4: ptOp = PredefinedType.PT_UINT; break; case FUNDTYPE.FT_I8: ptOp = PredefinedType.PT_LONG; break; case FUNDTYPE.FT_U8: ptOp = PredefinedType.PT_ULONG; break; } CType typeOp = GetReqPDT(ptOp); arg1 = mustCast(arg1, typeOp, CONVERTTYPE.NOUDC); arg2 = mustCast(arg2, typeOp, CONVERTTYPE.NOUDC); EXPR exprRes = BindIntOp(ek, flags, arg1, arg2, ptOp); if (!exprRes.isOK()) { return exprRes; } if (exprRes.type != typeDst) { Debug.Assert(!typeDst.isPredefType(PredefinedType.PT_BOOL)); exprRes = mustCast(exprRes, typeDst, CONVERTTYPE.NOUDC); } return exprRes; }
/* Handles delegate binary operators. */ private EXPR BindDelBinOp(ExpressionKind ek, EXPRFLAG flags, EXPR arg1, EXPR arg2) { Debug.Assert(ek == ExpressionKind.EK_ADD || ek == ExpressionKind.EK_SUB || ek == ExpressionKind.EK_EQ || ek == ExpressionKind.EK_NE); Debug.Assert(arg1.type == arg2.type && (arg1.type.isDelegateType() || arg1.type.isPredefType(PredefinedType.PT_DELEGATE))); PREDEFMETH predefMeth = (PREDEFMETH)0; CType RetType = null; switch (ek) { case ExpressionKind.EK_ADD: predefMeth = PREDEFMETH.PM_DELEGATE_COMBINE; RetType = arg1.type; ek = ExpressionKind.EK_DELEGATEADD; break; case ExpressionKind.EK_SUB: predefMeth = PREDEFMETH.PM_DELEGATE_REMOVE; RetType = arg1.type; ek = ExpressionKind.EK_DELEGATESUB; break; case ExpressionKind.EK_EQ: predefMeth = PREDEFMETH.PM_DELEGATE_OPEQUALITY; RetType = GetReqPDT(PredefinedType.PT_BOOL); ek = ExpressionKind.EK_DELEGATEEQ; break; case ExpressionKind.EK_NE: predefMeth = PREDEFMETH.PM_DELEGATE_OPINEQUALITY; RetType = GetReqPDT(PredefinedType.PT_BOOL); ek = ExpressionKind.EK_DELEGATENE; break; } return CreateBinopForPredefMethodCall(ek, predefMeth, RetType, arg1, arg2); }
/* Handles reference equality operators. Type variables come through here. */ private EXPR BindRefCmpOp(ExpressionKind ek, EXPRFLAG flags, EXPR arg1, EXPR arg2) { Debug.Assert(ek == ExpressionKind.EK_EQ || ek == ExpressionKind.EK_NE); // Must box type variables for the verifier. arg1 = mustConvert(arg1, GetReqPDT(PredefinedType.PT_OBJECT), CONVERTTYPE.NOUDC); arg2 = mustConvert(arg2, GetReqPDT(PredefinedType.PT_OBJECT), CONVERTTYPE.NOUDC); return GetExprFactory().CreateBinop(ek, GetReqPDT(PredefinedType.PT_BOOL), arg1, arg2); }
/* Handles standard binary decimal based operators. This function is called twice by the EE for every binary operator it evaluates Here is how it works. 1. The EE on finding an Expr asks the Expression binder to bind it. 2. At this time the expression binder just creates a new binopexpr and returns it to the EE, the EE then uses the runtimesystem to find if any of the arguments of the expr can be evaluated to constants. 3. If so it creates new arguments and expr, aliases the original expr to the new one and passes it new expr to Expressionbinder to be bound. 4. This time the expression binder realizes that the 2 arguments are constants and tries to fold them. If the folding is successful the value is used by the EE (and we have avoided a funceval) 5. if the constant binding fails, then the Expression binders returns the same exp as it would have created for the compile case ( we func eval the same function as what would be executed at runtime). */ private EXPR BindDecBinOp(ExpressionKind ek, EXPRFLAG flags, EXPR arg1, EXPR arg2) { Debug.Assert(arg1.type.isPredefType(PredefinedType.PT_DECIMAL) && arg2.type.isPredefType(PredefinedType.PT_DECIMAL)); CType typeDec = GetOptPDT(PredefinedType.PT_DECIMAL); Debug.Assert(typeDec != null); EXPR argConst1 = arg1.GetConst(); EXPR argConst2 = arg2.GetConst(); CType typeRet = null; switch (ek) { default: VSFAIL("Bad kind"); break; case ExpressionKind.EK_ADD: case ExpressionKind.EK_SUB: case ExpressionKind.EK_MUL: case ExpressionKind.EK_DIV: case ExpressionKind.EK_MOD: typeRet = typeDec; break; case ExpressionKind.EK_LT: case ExpressionKind.EK_LE: case ExpressionKind.EK_GT: case ExpressionKind.EK_GE: case ExpressionKind.EK_EQ: case ExpressionKind.EK_NE: typeRet = GetReqPDT(PredefinedType.PT_BOOL); break; } #if CSEE // In the EE, even if we don't have two constants, we want to emit an EXPRBINOP with the // right EK so that when we evalsync we can just do the work ourselves instead of // delegating to method calls. if (!argConst1 || !argConst2) { // We don't have 2 constants, so just emit an EXPRBINOP... return GetExprFactory().CreateBinop(tree, ek, typeRet, arg1, arg2); } else { goto LBothConst; } LUserDefined: #endif // CSEE #if !CSEE if (argConst2 != null && argConst1 != null) { goto LBothConst; } #endif // At this point, for the compiler we don't want to optimize the binop just yet. Maintain the correct tree until // the arithmetic optimizer pass. return GetExprFactory().CreateBinop(ek, typeRet, arg1, arg2); LBothConst: decimal dec1; decimal dec2; decimal decRes = 0; bool fRes = false; bool fBool = false; dec1 = argConst1.asCONSTANT().getVal().decVal; dec2 = argConst2.asCONSTANT().getVal().decVal; // Do the operation. switch (ek) { case ExpressionKind.EK_ADD: decRes = dec1 + dec2; break; case ExpressionKind.EK_SUB: decRes = dec1 - dec2; break; case ExpressionKind.EK_MUL: decRes = dec1 * dec2; break; case ExpressionKind.EK_DIV: if (dec2 == 0) { GetErrorContext().Error(ErrorCode.ERR_IntDivByZero); EXPR rval = GetExprFactory().CreateBinop(ek, typeDec, arg1, arg2); rval.SetError(); return rval; } decRes = dec1 / dec2; break; case ExpressionKind.EK_MOD: { /* n % d = n - d truncate(n/d) */ decimal decDiv; if (dec2 == 0) { GetErrorContext().Error(ErrorCode.ERR_IntDivByZero); EXPR rval = GetExprFactory().CreateBinop(ek, typeDec, arg1, arg2); rval.SetError(); return rval; } decDiv = dec1 % dec2; break; } default: fBool = true; switch (ek) { default: VSFAIL("Bad ek"); break; case ExpressionKind.EK_EQ: fRes = dec1 == dec2; break; case ExpressionKind.EK_NE: fRes = dec1 != dec2; break; case ExpressionKind.EK_LE: fRes = dec1 <= dec2; break; case ExpressionKind.EK_LT: fRes = dec1 < dec2; break; case ExpressionKind.EK_GE: fRes = dec1 >= dec2; break; case ExpressionKind.EK_GT: fRes = dec1 > dec2; break; } break; } // Allocate the result node. CONSTVAL cv; EXPR exprRes; if (fBool) { cv = ConstValFactory.GetBool(fRes); exprRes = GetExprFactory().CreateConstant(GetReqPDT(PredefinedType.PT_BOOL), cv); } else { cv = GetExprConstants().Create(decRes); exprRes = GetExprFactory().CreateConstant(typeDec, cv); } return exprRes; }
/* Handles string equality. */ private EXPR BindStrCmpOp(ExpressionKind ek, EXPRFLAG flags, EXPR arg1, EXPR arg2) { Debug.Assert(ek == ExpressionKind.EK_EQ || ek == ExpressionKind.EK_NE); Debug.Assert(arg1.type.isPredefType(PredefinedType.PT_STRING) && arg2.type.isPredefType(PredefinedType.PT_STRING)); // Get the predefined method for string comparison, and then stash it in the EXPR so we can // transform it later. PREDEFMETH predefMeth = ek == ExpressionKind.EK_EQ ? PREDEFMETH.PM_STRING_OPEQUALITY : PREDEFMETH.PM_STRING_OPINEQUALITY; ek = ek == ExpressionKind.EK_EQ ? ExpressionKind.EK_STRINGEQ : ExpressionKind.EK_STRINGNE; return CreateBinopForPredefMethodCall(ek, predefMeth, GetReqPDT(PredefinedType.PT_BOOL), arg1, arg2); }
private EXPRMULTI BindNonliftedIncOp(ExpressionKind ek, EXPRFLAG flags, EXPR arg, UnaOpFullSig uofs) { Debug.Assert(ek == ExpressionKind.EK_ADD || ek == ExpressionKind.EK_SUB); Debug.Assert(!uofs.isLifted()); Debug.Assert(arg != null); EXPR exprVal; #if ! CSEE EXPRMULTIGET exprGet = GetExprFactory().CreateMultiGet(EXPRFLAG.EXF_ASSGOP, arg.type, null); exprVal = exprGet; #else exprVal = arg; #endif CType type = uofs.GetType(); Debug.Assert(!type.IsNullableType()); // These used to be converts, but we're making them casts now - this is because // we need to remove the ability to call inc(sbyte) etc for all types smaller than int. // Note however, that this will give us different error messages on compile time versus runtime // for checked increments. // // Also, we changed it so that we now generate the cast to and from enum for enum increments. exprVal = mustCast(exprVal, type); exprVal = BindIncOpCore(ek, flags, exprVal, type); EXPR op = mustCast(exprVal, arg.type, CONVERTTYPE.NOUDC); EXPRMULTI exprMulti = GetExprFactory().CreateMulti(EXPRFLAG.EXF_ASSGOP | flags, arg.type, arg, op); #if ! CSEE exprGet.SetOptionalMulti(exprMulti); #endif return exprMulti; }
public void setAssignment() { Debug.Assert(!this.isSTMT()); this.flags |= EXPRFLAG.EXF_ASSGOP; }
/* Handles enum unary operator (~). */ private EXPR BindEnumUnaOp(ExpressionKind ek, EXPRFLAG flags, EXPR arg) { Debug.Assert(ek == ExpressionKind.EK_BITNOT); Debug.Assert(arg.isCAST()); Debug.Assert(arg.asCAST().GetArgument().type.isEnumType()); PredefinedType ptOp; CType typeEnum = arg.asCAST().GetArgument().type; switch (typeEnum.fundType()) { default: // Promote all smaller types to int. ptOp = PredefinedType.PT_INT; break; case FUNDTYPE.FT_U4: ptOp = PredefinedType.PT_UINT; break; case FUNDTYPE.FT_I8: ptOp = PredefinedType.PT_LONG; break; case FUNDTYPE.FT_U8: ptOp = PredefinedType.PT_ULONG; break; } CType typeOp = GetReqPDT(ptOp); arg = mustCast(arg, typeOp, CONVERTTYPE.NOUDC); EXPR exprRes = BindIntOp(ek, flags, arg, null, ptOp); if (!exprRes.isOK()) { return exprRes; } return mustCastInUncheckedContext(exprRes, typeEnum, CONVERTTYPE.NOUDC); }
private EXPR FoldIntegerConstants(ExpressionKind kind, EXPRFLAG flags, EXPR op1, EXPR op2, PredefinedType ptOp) { //Debug.Assert(kind.isRelational() || kind.isArithmetic() || kind.isBitwise()); Debug.Assert(ptOp == PredefinedType.PT_INT || ptOp == PredefinedType.PT_UINT || ptOp == PredefinedType.PT_LONG || ptOp == PredefinedType.PT_ULONG); CType typeOp = GetReqPDT(ptOp); Debug.Assert(typeOp != null); Debug.Assert(op1 != null && op1.type == typeOp); Debug.Assert(op2 == null || op2.type == typeOp); Debug.Assert((op2 == null) == (kind == ExpressionKind.EK_NEG || kind == ExpressionKind.EK_UPLUS || kind == ExpressionKind.EK_BITNOT)); EXPRCONSTANT opConst1 = op1.GetConst().asCONSTANT(); EXPRCONSTANT opConst2 = (op2 != null) ? op2.GetConst().asCONSTANT() : null; // Fold operation if both args are constant. if (opConst1 != null && (op2 == null || opConst2 != null)) { if (ptOp == PredefinedType.PT_LONG || ptOp == PredefinedType.PT_ULONG) { return FoldConstI8Op(kind, op1, opConst1, op2, opConst2, ptOp); } else { return FoldConstI4Op(kind, op1, opConst1, op2, opConst2, ptOp); } } return null; }