private bool ExtractFromClump(StatementList contractClump, Method method, GatherLocals gatherLocals, RequiresList Preconditions, EnsuresList Postconditions, RequiresList validations, EnsuresList modelPostconditions, SourceContext defaultContext, Method originalMethod, Block contractInitializer, ref HelperMethods.StackDepthTracker dupStackTracker) { // set the state so that the contract clump is used for extraction (as opposed to the method body as it used to) StatementList stmts = contractClump; int beginning = 0; int n = stmts.Count; int seginning = HelperMethods.FindNextRealStatement(((Block) stmts[beginning]).Statements, 0); bool endContractFound = false; bool postConditionFound = false; SourceContext currentSourceContext; for (int i = beginning; i < n; i++) { Block b = (Block) stmts[i]; if (b == null) continue; for (int j = 0, m = b.Statements == null ? 0 : b.Statements.Count; j < m; j++) { if (dupStackTracker.IsValid && dupStackTracker.Depth >= 0) { b.Statements[j] = dupStackTracker.Visit(b.Statements[j]); } Statement s = b.Statements[j]; if (s == null) continue; Block currentClump; Throw t = null; t = s as Throw; Method calledMethod = HelperMethods.IsMethodCall(s); if ((t != null || (calledMethod != null && calledMethod.DeclaringType != null && calledMethod.DeclaringType != this.contractNodes.ContractClass && HelperMethods.IsVoidType(calledMethod.ReturnType) && !this.contractNodes.IsContractOrValidatorOrAbbreviatorMethod(calledMethod)))) { // Treat throw statements as (part of) a precondition // don't accept "throw ..." unless it comes in the "precondition section" // then treat the current clump as a precondition, but need to massage it a bit: // all branches to the block just after the throw should be modified to be branches to // a new manufactured block that sets a fresh local to "true". The // throw itself should be changed to set the same local to "false". That way the // clump can be treated as the value of precondition (because the branch polarity has // already been negated as part of the code gen). // This test was supposed to be a sanity check that the current block contained // only "throw ..." or else "nop; throw ...". But I've also seen "ThrowHelper.Throw(...); nop", // so I'm just going to comment this out for now. //if (!((m == 1 && j == 0) || (m == 2 && j == 1))) { // Preconditions = new RequiresList(); // Postconditions = new EnsuresList(); // return; // throw new ExtractorException(); //} Expression exception; // The clump being extracted may contain code/blocks that represent (part of) // the expression that is being thrown (if the original throw expression had // control flow in it from boolean expressions and/or ternary expressions). b.Statements[j] = null; // wipe out throw statement currentClump = new Block(HelperMethods.ExtractClump(stmts, beginning, seginning, i, j)); int currentClumpLength = i - beginning + 1; // there better be a next block because that must have been the target for all of the branches // that didn't cause the throw to happen if (!(i < n - 1)) { this.HandleError(method, 1027, "Malformed contract.", s.SourceContext); return false; } Block nextBlock = (Block) stmts[i + 1]; // cast succeeds because body is clump Local valueOfPrecondition = new Local(Identifier.For("_preConditionHolds"), SystemTypes.Boolean); Block preconditionHolds = new Block(new StatementList(new AssignmentStatement(valueOfPrecondition, Literal.True))); ReplaceBranchTarget rbt = new ReplaceBranchTarget(nextBlock, preconditionHolds); rbt.VisitBlock(currentClump); int ILOffset; CountPopExpressions cpe = new CountPopExpressions(); currentSourceContext = s.SourceContext; cpe.Visit(s); if (0 < cpe.PopOccurrences) { // then there is a set of blocks that represent the exception: the Reader // was not able to decompile it back into an expression. Extract the set // from the current clump and make it into a block expression // Find the last block that has a branch to "preconditionHolds". After that are all of the blocks // that represent the evaluation of the exception int branchBlockIndex = currentClumpLength - 2; // can't be the current block: that has the throw in it while (0 <= branchBlockIndex) { Block possibleBranchBlock = currentClump.Statements[branchBlockIndex] as Block; Branch br = possibleBranchBlock.Statements[possibleBranchBlock.Statements.Count - 1] as Branch; if (br != null && br.Target == preconditionHolds) { break; } branchBlockIndex--; } if (branchBlockIndex < 0) { this.HandleError(method, 1028, "Malformed exception constructor in contract.", defaultContext); return false; } Block exceptionBlock = new Block(HelperMethods.ExtractClump(currentClump.Statements, branchBlockIndex + 1, 0, currentClumpLength - 1, ((Block) currentClump.Statements[currentClumpLength - 1]).Statements.Count - 1)); exceptionBlock.Statements.Add(new ExpressionStatement(t.Expression)); SourceContext sctx = ((Block) exceptionBlock.Statements[0]).Statements[0].SourceContext; if (sctx.IsValid) { currentSourceContext = sctx; } else { SourceContext tmp; bool foundContext = HelperMethods.GetLastSourceContext(exceptionBlock.Statements, out tmp); if (foundContext) currentSourceContext = tmp; } if (!CheckClump(method, gatherLocals, currentSourceContext, exceptionBlock)) return false; exception = new BlockExpression(exceptionBlock, SystemTypes.Exception); ILOffset = t.ILOffset; } else { currentSourceContext = s.SourceContext; if (t != null) { // then the statement is "throw ..." exception = t.Expression; ILOffset = t.ILOffset; } else { ExpressionStatement throwHelperCall = s as ExpressionStatement; Debug.Assert(throwHelperCall != null); exception = throwHelperCall.Expression; ILOffset = s.ILOffset; } exception.SourceContext = currentSourceContext; SourceContext tmp; bool foundContext = HelperMethods.GetLastSourceContext(currentClump.Statements, out tmp); if (foundContext) currentSourceContext = tmp; } Block returnValueOfPrecondition = new Block(new StatementList(new ExpressionStatement(valueOfPrecondition))); Statement extraAssumeFalse = this.ExtraAssumeFalseOnThrow(); Block preconditionFails = new Block(new StatementList(new AssignmentStatement(valueOfPrecondition, Literal.False), extraAssumeFalse, new Branch(null, returnValueOfPrecondition, true, false, false))); //Block preconditionFails = new Block(new StatementList(new AssignmentStatement(valueOfPrecondition, Literal.False), new Branch(null, returnValueOfPrecondition, true, false, false))); currentClump.Statements.Add(preconditionFails); // replace throw statement currentClump.Statements.Add(preconditionHolds); currentClump.Statements.Add(returnValueOfPrecondition); if (!CheckClump(originalMethod, gatherLocals, currentSourceContext, currentClump)) return false; BlockExpression be = new BlockExpression(currentClump, SystemTypes.Boolean); be.SourceContext = currentSourceContext; var ro = new RequiresOtherwise(be, exception); ro.ILOffset = ILOffset; ro.SourceContext = currentSourceContext; if (postConditionFound) { HandleError(originalMethod, 1013, "Precondition found after postcondition.", currentSourceContext); return false; } validations.Add(ro); var req = new RequiresPlain(be, FindExceptionThrown.Find(exception)); req.IsFromValidation = true; req.ILOffset = ro.ILOffset; req.SourceContext = ro.SourceContext; Preconditions.Add(req); } else { if (contractNodes.IsContractMethod(calledMethod)) { // Treat calls to contract methods if (endContractFound) { HandleError(originalMethod, 1012, "Contract call found after prior EndContractBlock.", s.SourceContext); break; } if (contractNodes.IsEndContract(calledMethod)) { endContractFound = true; continue; } MethodCall mc = ((ExpressionStatement) s).Expression as MethodCall; Expression arg = mc.Operands[0]; arg.SourceContext = s.SourceContext; MethodContractElement mce; currentSourceContext = s.SourceContext; Expression condition; if (beginning == i && seginning == j) { // Deal with the simple case: the reader decompiled the call into a single statement condition = arg; } else { b.Statements[j] = new ExpressionStatement(arg); // construct a clump from // methodBody.Statements[beginning].Statements[seginning] to // methodBody.Statements[i].Statements[j] currentClump = new Block(HelperMethods.ExtractClump(stmts, beginning, seginning, i, j)); if (!currentSourceContext.IsValid) { // then a good source context has not been found yet. Grovel around in the clump // to see if there is a better one SourceContext sctx; if (HelperMethods.FindContext(currentClump, currentSourceContext, out sctx)) currentSourceContext = sctx; } if (!CheckClump(originalMethod, gatherLocals, currentSourceContext, currentClump)) return false; BlockExpression be = new BlockExpression(currentClump); condition = be; } condition.SourceContext = currentSourceContext; if (contractNodes.IsPlainPrecondition(calledMethod)) { var req = new RequiresPlain(condition); contractNodes.IsRequiresWithException(calledMethod, out req.ExceptionType); mce = req; } else if (this.contractNodes.IsPostcondition(calledMethod)) { mce = new EnsuresNormal(condition); } else if (contractNodes.IsExceptionalPostcondition(calledMethod)) { EnsuresExceptional ee = new EnsuresExceptional(condition); // Extract the type of exception. ee.Type = calledMethod.TemplateArguments[0]; mce = ee; } else { throw new InvalidOperationException("Cannot recognize contract method"); } mce.SourceContext = currentSourceContext; mce.ILOffset = mc.ILOffset; if (1 < mc.Operands.Count) { var candidate = SanitizeUserMessage(method, mc.Operands[1], currentSourceContext); mce.UserMessage = candidate; } if (2 < mc.Operands.Count) { Literal lit = mc.Operands[2] as Literal; if (lit != null) { mce.SourceConditionText = lit; } } // determine Model status mce.UsesModels = CodeInspector.UsesModel(mce.Assertion, this.contractNodes); // Check context rules switch (mce.NodeType) { case NodeType.RequiresPlain: if (postConditionFound) { this.HandleError(originalMethod, 1014, "Precondition found after postcondition.", currentSourceContext); return false; } if (mce.UsesModels) { this.HandleError(originalMethod, 1073, "Preconditions may not refer to model members.", currentSourceContext); return false; } var rp = (RequiresPlain) mce; Preconditions.Add(rp); validations.Add(rp); // also add to the internal validation list break; // TODO: check visibility of post conditions based on visibility of possible implementation case NodeType.EnsuresNormal: case NodeType.EnsuresExceptional: Ensures ensures = (Ensures) mce; if (mce.UsesModels) { if (this.IncludeModels) { modelPostconditions.Add(ensures); } } else { Postconditions.Add(ensures); } postConditionFound = true; break; } } else if (ContractNodes.IsValidatorMethod(calledMethod)) { // Treat calls to Contract validators if (endContractFound) { this.HandleError(originalMethod, 1012, "Contract call found after prior EndContractBlock.", s.SourceContext); break; } MethodCall mc = ((ExpressionStatement) s).Expression as MethodCall; var memberBinding = (MemberBinding) mc.Callee; currentSourceContext = s.SourceContext; Statement validation; Block validationPrefix; if (beginning == i && seginning == j) { // Deal with the simple case: the reader decompiled the call into a single statement validation = s; validationPrefix = null; } else { // The clump may contain multiple statements ending in the validator call. // to extract the code as Requires<E>, we need to keep the statements preceeding // the validator call, as they may contain local initialization etc. These should go // into the first Requires<E> that the validator expands to. This way, if there are // no Requires<E> expanded from the validator, then the statements can be omitted. // At the same time, the statements won't be duplicated when validations are emitted. // // If the validator call contains any pops, then the extraction must fail saying it // is too complicated. // must null out statement with call before extract clump b.Statements[j] = null; // we have a copy in mc, s validationPrefix = new Block(HelperMethods.ExtractClump(stmts, beginning, seginning, i, j)); if (!currentSourceContext.IsValid) { // then a good source context has not been found yet. Grovel around in the clump // to see if there is a better one SourceContext sctx; if (HelperMethods.FindContext(validationPrefix, currentSourceContext, out sctx)) currentSourceContext = sctx; } if (CountPopExpressions.Count(mc) > 0) { this.HandleError(method, 1071, "Arguments to contract validator call are too complicated. Please simplify.", currentSourceContext); return false; } if (!CheckClump(originalMethod, gatherLocals, currentSourceContext, validationPrefix)) return false; validation = new Block(new StatementList(validationPrefix, s)); validation.SourceContext = currentSourceContext; } var ro = new RequiresOtherwise(null, new BlockExpression(new Block(new StatementList(validation)))); validations.Add(ro); CopyValidatorContracts( method, calledMethod, memberBinding.TargetObject, mc.Operands, Preconditions, currentSourceContext, validationPrefix); } else if (ContractNodes.IsAbbreviatorMethod(calledMethod)) { // Treat calls to Contract abbreviators if (endContractFound) { this.HandleError(originalMethod, 1012, "Contract call found after prior EndContractBlock.", s.SourceContext); break; } MethodCall mc = ((ExpressionStatement) s).Expression as MethodCall; var memberBinding = (MemberBinding) mc.Callee; currentSourceContext = s.SourceContext; if (beginning == i && seginning == j) { // Deal with the simple case: the reader decompiled the call into a single statement // nothing to do. All is in the call and its arguments } else { // The clump may contain multiple statements ending in the abbreviator call. // We need to keep the statements preceeding the abbreviator call and add them to the // contract initializer block. The reason we cannot add them to the first expansion contract // of the abbreviator is that the abbreviator may give rise to closure initialization which will // be hoisted into the closure initializer block. This closure initializer may refer to the // locals initialized by the present statement sequence, so it must precede it. // // If the abbreviator call contains any pops, then the extraction must fail saying it // is too complicated. // grab prefix of clump minus last call statement. // must null out current call statement before we extract clump (ow. it stays in body) b.Statements[j] = null; currentClump = new Block(HelperMethods.ExtractClump(stmts, beginning, seginning, i, j)); if (!currentSourceContext.IsValid) { // then a good source context has not been found yet. Grovel around in the clump // to see if there is a better one SourceContext sctx; if (HelperMethods.FindContext(currentClump, currentSourceContext, out sctx)) currentSourceContext = sctx; } if (CountPopExpressions.Count(mc) > 0) { this.HandleError(method, 1070, "Arguments to contract abbreviator call are too complicated. Please simplify.", currentSourceContext); return false; } if (!CheckClump(originalMethod, gatherLocals, currentSourceContext, currentClump)) return false; if (HelperMethods.IsNonTrivial(currentClump)) { contractInitializer.Statements.Add(currentClump); } } CopyAbbreviatorContracts(method, calledMethod, memberBinding.TargetObject, mc.Operands, Preconditions, Postconditions, currentSourceContext, validations, contractInitializer); } else { // important to continue here and accumulate blocks/statements for next contract! if (i == beginning && j == seginning && s.NodeType == NodeType.Nop) { // nop following contract is often associated with previous code, so skip it seginning = j + 1; } continue; } } // Re-initialize current state after contract has been found beginning = i; seginning = j + 1; //seginning = HelperMethods.FindNextRealStatement(((Block)stmts[i]).Statements, j + 1); if (seginning < 0) seginning = 0; //b = (Block)stmts[i]; // IMPORTANT! Need this to keep "b" in sync } } if (this.verbose) { Console.WriteLine("\tNumber of Preconditions: " + Preconditions.Count); Console.WriteLine("\tNumber of Postconditions: " + Postconditions.Count); } return true; }
public virtual Expression VisitBlockExpression(BlockExpression blockExpression) { if (blockExpression == null) return null; blockExpression.Block = this.VisitBlock(blockExpression.Block); return blockExpression; }
private void ExtractIndividualInvariants(TypeNode type, InvariantList result, Method invariantMethod) { if (invariantMethod == null || invariantMethod.Body == null || invariantMethod.Body.Statements == null || invariantMethod.Body.Statements.Count == 0) { return; } Block invariantMethodBody = invariantMethod.Body; int n = invariantMethodBody.Statements.Count; int beginning = 0; while (beginning < invariantMethodBody.Statements.Count && invariantMethodBody.Statements[beginning] is PreambleBlock) { beginning++; } for (int i = beginning; i < n; i++) { Block b = (Block) invariantMethodBody.Statements[i]; int seginning = 0; for (int j = 0, m = b.Statements == null ? 0 : b.Statements.Count; j < m; j++) { ExpressionStatement s = b.Statements[j] as ExpressionStatement; if (s == null) continue; Literal invariantName; Literal sourceText; Expression invariantCondition = this.contractNodes.IsInvariant(s, out invariantName, out sourceText); if (invariantCondition == null) { Method called = HelperMethods.IsMethodCall(s); if (called != null) { if (HelperMethods.IsVoidType(called.ReturnType)) { this.CallErrorFound(new Error(1045, "Invariant methods must be a sequence of calls to Contract.Invariant(...)", s.SourceContext)); return; } } continue; } // construct a clump from // invariantMethodBody.Statements[beginning].Statements[seginning] to // invariantMethodBody.Statements[i].Statements[j] Block currentClump = new Block(HelperMethods.ExtractClump(invariantMethodBody.Statements, beginning, seginning, i, j)); BlockExpression be = new BlockExpression(currentClump, SystemTypes.Void); Invariant inv = new Invariant(type, be, invariantMethod.Name.Name); inv.UserMessage = invariantName; inv.SourceConditionText = sourceText; SourceContext sctx; if (HelperMethods.FindContext(currentClump, s.SourceContext, out sctx)) { inv.SourceContext = sctx; inv.Condition.SourceContext = sctx; } inv.ILOffset = s.ILOffset; inv.UsesModels = CodeInspector.UsesModel(inv.Condition, this.contractNodes); if (inv.UsesModels) { this.HandleError(invariantMethod, 1072, "Invariants cannot refer to model members.", sctx); } else { result.Add(inv); } // Re-initialize current state beginning = i; seginning = j + 1; b = (Block) invariantMethodBody.Statements[i]; // IMPORTANT! Need this to keep "b" in sync } } }
public override Expression VisitBlockExpression(BlockExpression blockExpression) { if (blockExpression == null) return null; return base.VisitBlockExpression((BlockExpression)blockExpression.Clone()); }
private Method MakeRequiresWithExceptionMethod(string name) { Parameter conditionParameter = new Parameter(Identifier.For("condition"), SystemTypes.Boolean); Parameter messageParameter = new Parameter(Identifier.For("msg"), SystemTypes.String); Parameter conditionTextParameter = new Parameter(Identifier.For("conditionTxt"), SystemTypes.String); MethodClassParameter typeArg = new MethodClassParameter(); ParameterList pl = new ParameterList(conditionParameter, messageParameter, conditionTextParameter); Block body = new Block(new StatementList()); Method m = new Method(this.RuntimeContractType, null, Identifier.For(name), pl, SystemTypes.Void, body); m.Flags = MethodFlags.Assembly | MethodFlags.Static; m.Attributes = new AttributeList(); m.TemplateParameters = new TypeNodeList(typeArg); m.IsGeneric = true; this.RuntimeContractType.Members.Add(m); typeArg.Name = Identifier.For("TException"); typeArg.DeclaringMember = m; typeArg.BaseClass = SystemTypes.Exception; typeArg.ParameterListIndex = 0; typeArg.DeclaringModule = this.RuntimeContractType.DeclaringModule; Block returnBlock = new Block(new StatementList(new Return())); Block b = new Block(new StatementList()); b.Statements.Add(new Branch(conditionParameter, returnBlock)); // // Generate the following // // // message == null means: yes we handled it. Otherwise it is the localized failure message // var message = RaiseFailureEvent(ContractFailureKind.Precondition, userMessage, conditionString, null); // #if assertOnFailure // if (message != null) { // Assert(false, message); // } // #endif var messageLocal = new Local(Identifier.For("msg"), SystemTypes.String); ExpressionList elist = new ExpressionList(); elist.Add(this.PreconditionKind); elist.Add(messageParameter); elist.Add(conditionTextParameter); elist.Add(Literal.Null); b.Statements.Add(new AssignmentStatement(messageLocal, new MethodCall(new MemberBinding(null, this.RaiseFailureEventMethod), elist))); if (this.AssertOnFailure) { var assertMethod = GetSystemDiagnosticsAssertMethod(); if (assertMethod != null) { var skipAssert = new Block(); b.Statements.Add(new Branch(new UnaryExpression(messageLocal, NodeType.LogicalNot), skipAssert)); // emit assert call ExpressionList assertelist = new ExpressionList(); assertelist.Add(Literal.False); assertelist.Add(messageLocal); b.Statements.Add(new ExpressionStatement(new MethodCall(new MemberBinding(null, assertMethod), assertelist))); b.Statements.Add(skipAssert); } } // // construct exception // Exception obj = null; // ConstructorInfo ci = typeof(TException).GetConstructor(new[] { typeof(string), typeof(string) }); // if (ci != null) // { // if (reflection.firstArgName == "paramName") { // exceptionObject = ci.Invoke(new[] { userMessage, message }) as Exception; // } // else { // exceptionObject = ci.Invoke(new[] { message, userMessage }) as Exception; // } // } // else { // ci = typeof(TException).GetConstructor(new[] { typeof(string) }); // if (ci != null) // { // exceptionObject = ci.Invoke(new[] { message }) as Exception; // } // } var exceptionLocal = new Local(Identifier.For("obj"), SystemTypes.Exception); b.Statements.Add(new AssignmentStatement(exceptionLocal, Literal.Null)); var constructorInfoType = TypeNode.GetTypeNode(typeof(System.Reflection.ConstructorInfo)); Contract.Assume(constructorInfoType != null); var methodBaseType = TypeNode.GetTypeNode(typeof(System.Reflection.MethodBase)); Contract.Assume(methodBaseType != null); var constructorLocal = new Local(Identifier.For("ci"), constructorInfoType); Contract.Assume(SystemTypes.Type != null); var getConstructorMethod = SystemTypes.Type.GetMethod(Identifier.For("GetConstructor"), SystemTypes.Type.GetArrayType(1)); var typeofExceptionArg = GetTypeFromHandleExpression(typeArg); var typeofString = GetTypeFromHandleExpression(SystemTypes.String); var typeArrayLocal = new Local(Identifier.For("typeArray"), SystemTypes.Type.GetArrayType(1)); var typeArray2 = new ConstructArray(); typeArray2.ElementType = SystemTypes.Type; typeArray2.Rank = 1; typeArray2.Operands = new ExpressionList(Literal.Int32Two); var typeArrayInit2 = new Block(new StatementList()); typeArrayInit2.Statements.Add(new AssignmentStatement(typeArrayLocal, typeArray2)); typeArrayInit2.Statements.Add(new AssignmentStatement(new Indexer(typeArrayLocal, new ExpressionList(Literal.Int32Zero), SystemTypes.Type), typeofString)); typeArrayInit2.Statements.Add(new AssignmentStatement(new Indexer(typeArrayLocal, new ExpressionList(Literal.Int32One), SystemTypes.Type), typeofString)); typeArrayInit2.Statements.Add(new ExpressionStatement(typeArrayLocal)); var typeArrayExpression2 = new BlockExpression(typeArrayInit2); b.Statements.Add(new AssignmentStatement(constructorLocal, new MethodCall(new MemberBinding(typeofExceptionArg, getConstructorMethod), new ExpressionList(typeArrayExpression2)))); var elseBlock = new Block(); b.Statements.Add(new Branch(new UnaryExpression(constructorLocal, NodeType.LogicalNot), elseBlock)); var endifBlock2 = new Block(); var invokeMethod = constructorInfoType.GetMethod(Identifier.For("Invoke"), SystemTypes.Object.GetArrayType(1)); var argArray2 = new ConstructArray(); argArray2.ElementType = SystemTypes.Object; argArray2.Rank = 1; argArray2.Operands = new ExpressionList(Literal.Int32Two); var argArrayLocal = new Local(Identifier.For("argArray"), SystemTypes.Object.GetArrayType(1)); var parameterInfoType = TypeNode.GetTypeNode(typeof(System.Reflection.ParameterInfo)); Contract.Assume(parameterInfoType != null); var parametersMethod = methodBaseType.GetMethod(Identifier.For("GetParameters")); var get_NameMethod = parameterInfoType.GetMethod(Identifier.For("get_Name")); var string_op_EqualityMethod = SystemTypes.String.GetMethod(Identifier.For("op_Equality"), SystemTypes.String, SystemTypes.String); var elseArgMsgBlock = new Block(); var endIfArgMsgBlock = new Block(); b.Statements.Add(new Branch(new UnaryExpression(new MethodCall(new MemberBinding(null, string_op_EqualityMethod), new ExpressionList(new MethodCall(new MemberBinding(new Indexer(new MethodCall(new MemberBinding(constructorLocal, parametersMethod), new ExpressionList(), NodeType.Callvirt), new ExpressionList(Literal.Int32Zero), parameterInfoType), get_NameMethod), new ExpressionList(), NodeType.Callvirt), new Literal("paramName", SystemTypes.String))), NodeType.LogicalNot), elseArgMsgBlock)); var argArrayInit2 = new Block(new StatementList()); argArrayInit2.Statements.Add(new AssignmentStatement(argArrayLocal, argArray2)); argArrayInit2.Statements.Add(new AssignmentStatement(new Indexer(argArrayLocal, new ExpressionList(Literal.Int32Zero), SystemTypes.Object), messageParameter)); argArrayInit2.Statements.Add(new AssignmentStatement(new Indexer(argArrayLocal, new ExpressionList(Literal.Int32One), SystemTypes.Object), messageLocal)); argArrayInit2.Statements.Add(new ExpressionStatement(argArrayLocal)); var argArrayExpression2 = new BlockExpression(argArrayInit2); b.Statements.Add(new AssignmentStatement(exceptionLocal, new BinaryExpression(new MethodCall(new MemberBinding(constructorLocal, invokeMethod), new ExpressionList(argArrayExpression2)), new Literal(SystemTypes.Exception), NodeType.Isinst))); b.Statements.Add(new Branch(null, endIfArgMsgBlock)); b.Statements.Add(elseArgMsgBlock); var argArrayInit2_1 = new Block(new StatementList()); argArrayInit2_1.Statements.Add(new AssignmentStatement(argArrayLocal, argArray2)); argArrayInit2_1.Statements.Add(new AssignmentStatement(new Indexer(argArrayLocal, new ExpressionList(Literal.Int32Zero), SystemTypes.Object), messageLocal)); argArrayInit2_1.Statements.Add(new AssignmentStatement(new Indexer(argArrayLocal, new ExpressionList(Literal.Int32One), SystemTypes.Object), messageParameter)); argArrayInit2_1.Statements.Add(new ExpressionStatement(argArrayLocal)); var argArrayExpression2_1 = new BlockExpression(argArrayInit2_1); b.Statements.Add(new AssignmentStatement(exceptionLocal, new BinaryExpression(new MethodCall(new MemberBinding(constructorLocal, invokeMethod), new ExpressionList(argArrayExpression2_1)), new Literal(SystemTypes.Exception), NodeType.Isinst))); b.Statements.Add(endIfArgMsgBlock); b.Statements.Add(new Branch(null, endifBlock2)); b.Statements.Add(elseBlock); var typeArray1 = new ConstructArray(); typeArray1.ElementType = SystemTypes.Type; typeArray1.Rank = 1; typeArray1.Operands = new ExpressionList(Literal.Int32One); var typeArrayInit1 = new Block(new StatementList()); typeArrayInit1.Statements.Add(new AssignmentStatement(typeArrayLocal, typeArray1)); typeArrayInit1.Statements.Add(new AssignmentStatement(new Indexer(typeArrayLocal, new ExpressionList(Literal.Int32Zero), SystemTypes.Type), typeofString)); typeArrayInit1.Statements.Add(new ExpressionStatement(typeArrayLocal)); var typeArrayExpression1 = new BlockExpression(typeArrayInit1); b.Statements.Add(new AssignmentStatement(constructorLocal, new MethodCall(new MemberBinding(typeofExceptionArg, getConstructorMethod), new ExpressionList(typeArrayExpression1)))); b.Statements.Add(new Branch(new UnaryExpression(constructorLocal, NodeType.LogicalNot), endifBlock2)); var argArray1 = new ConstructArray(); argArray1.ElementType = SystemTypes.Object; argArray1.Rank = 1; argArray1.Operands = new ExpressionList(Literal.Int32One); var argArrayInit1 = new Block(new StatementList()); argArrayInit1.Statements.Add(new AssignmentStatement(argArrayLocal, argArray1)); argArrayInit1.Statements.Add(new AssignmentStatement(new Indexer(argArrayLocal, new ExpressionList(Literal.Int32Zero), SystemTypes.Object), messageLocal)); argArrayInit1.Statements.Add(new ExpressionStatement(argArrayLocal)); var argArrayExpression1 = new BlockExpression(argArrayInit1); b.Statements.Add(new AssignmentStatement(exceptionLocal, new BinaryExpression(new MethodCall(new MemberBinding(constructorLocal, invokeMethod), new ExpressionList(argArrayExpression1)), new Literal(SystemTypes.Exception), NodeType.Isinst))); b.Statements.Add(endifBlock2); // // throw it // if (exceptionObject == null) // { // throw new ArgumentException(displayMessage, message); // } // else // { // throw exceptionObject; // } var thenBlock3 = new Block(); b.Statements.Add(new Branch(exceptionLocal, thenBlock3)); b.Statements.Add(new Throw(new Construct(new MemberBinding(null, SystemTypes.ArgumentException.GetConstructor(SystemTypes.String, SystemTypes.String)), new ExpressionList(messageLocal, messageParameter)))); b.Statements.Add(thenBlock3); b.Statements.Add(new Throw(exceptionLocal)); b.Statements.Add(returnBlock); Contract.Assume(body.Statements != null); body.Statements.Add(b); Member constructor = null; AttributeNode attribute = null; #region Add [DebuggerNonUserCodeAttribute] if (this.HideFromDebugger) { TypeNode debuggerNonUserCode = SystemTypes.SystemAssembly.GetType(Identifier.For("System.Diagnostics"), Identifier.For("DebuggerNonUserCodeAttribute")); if (debuggerNonUserCode != null) { constructor = debuggerNonUserCode.GetConstructor(); attribute = new AttributeNode(new MemberBinding(null, constructor), null, AttributeTargets.Method); m.Attributes.Add(attribute); } } #endregion Add [DebuggerNonUserCodeAttribute] TypeNode reliabilityContract = SystemTypes.SystemAssembly.GetType(Identifier.For("System.Runtime.ConstrainedExecution"), Identifier.For("ReliabilityContractAttribute")); TypeNode consistency = SystemTypes.SystemAssembly.GetType(Identifier.For("System.Runtime.ConstrainedExecution"), Identifier.For("Consistency")); TypeNode cer = SystemTypes.SystemAssembly.GetType(Identifier.For("System.Runtime.ConstrainedExecution"), Identifier.For("Cer")); if (reliabilityContract != null && consistency != null && cer != null) { constructor = reliabilityContract.GetConstructor(consistency, cer); if (constructor != null) { attribute = new AttributeNode( new MemberBinding(null, constructor), new ExpressionList( new Literal(System.Runtime.ConstrainedExecution.Consistency.WillNotCorruptState, consistency), new Literal(System.Runtime.ConstrainedExecution.Cer.MayFail, cer)), AttributeTargets.Method ); m.Attributes.Add(attribute); } } return m; }
//TODO: get rid of stateAfterBrace private Expression ParseBlockExpression(ScannerState stateAfterBrace, object sctx, TokenSet followers){ bool savedSawReturnOrYield = this.sawReturnOrYield; this.sawReturnOrYield = false; Block block = new Block(); block.Checked = this.insideCheckedBlock; block.IsUnsafe = this.inUnsafeCode; block.SuppressCheck = this.insideUncheckedBlock; SourceContext ctx = (SourceContext)sctx; ctx.EndPos = this.scanner.CurrentSourceContext.EndPos; Debug.Assert(this.currentToken == Token.LeftBrace); // this.GetNextToken(); block.SourceContext = ctx; block.Statements = new StatementList(new ExpressionStatement(ParseComprehension(followers))); // block.Statements = this.ParseStatementsWithOptionalExpression(followers|Token.RightBrace); if (this.arrayInitializerOpeningContext != null && block.Statements == null && this.currentToken == Token.RightBrace){ this.GetNextToken(); this.sawReturnOrYield = savedSawReturnOrYield; return null; } block.SourceContext.EndPos = this.scanner.CurrentSourceContext.EndPos; this.scanner.state = stateAfterBrace; // this.ParseBracket(ctx, Token.RightBrace, followers, Error.ExpectedRightBrace); Expression result = null; if (sawReturnOrYield) result = new AnonymousNestedFunction(new ParameterList(0), block); else result = new BlockExpression(block); result.SourceContext = ctx; this.sawReturnOrYield = savedSawReturnOrYield; return result; }
private Expression ParsePrimaryExpression(TokenSet followers){ Expression expression = null; SourceContext sctx = this.scanner.CurrentSourceContext; switch(this.currentToken){ case Token.ArgList: this.GetNextToken(); expression = new ArglistExpression(sctx); break; case Token.Delegate:{ this.GetNextToken(); ParameterList parameters = null; if (this.currentToken == Token.LeftParenthesis) parameters = this.ParseParameters(Token.RightParenthesis, followers|Token.LeftBrace); Block block = null; if (this.currentToken == Token.LeftBrace) block = this.ParseBlock(this.scanner.CurrentSourceContext, followers); else this.SkipTo(followers, Error.ExpectedLeftBrace); sctx.EndPos = this.scanner.endPos; return new AnonymousNestedDelegate(parameters, block, sctx);} case Token.New: expression = this.ParseNew(followers|Token.Dot|Token.LeftBracket|Token.Arrow); break; case Token.Identifier: expression = this.scanner.GetIdentifier(); if (this.sink != null) { this.sink.StartName((Identifier)expression); } this.GetNextToken(); if (this.currentToken == Token.DoubleColon){ this.GetNextToken(); Identifier id = this.scanner.GetIdentifier(); id.Prefix = (Identifier)expression; id.SourceContext.StartPos = expression.SourceContext.StartPos; expression = id; if (this.currentToken != Token.EndOfFile) this.GetNextToken(); }else if (this.currentToken == Token.Lambda){ Parameter par = new Parameter((Identifier)expression, null); par.SourceContext = expression.SourceContext; return this.ParseLambdaExpression(par.SourceContext, new ParameterList(par), followers); } break; case Token.Null: expression = new Literal(null, null, sctx); this.GetNextToken(); break; case Token.True: expression = new Literal(true, null, sctx); this.GetNextToken(); break; case Token.False: expression = new Literal(false, null, sctx); this.GetNextToken(); break; case Token.CharLiteral: expression = new Literal(this.scanner.charLiteralValue, null, sctx); this.GetNextToken(); break; case Token.HexLiteral: expression = this.ParseHexLiteral(); break; case Token.IntegerLiteral: expression = this.ParseIntegerLiteral(); break; case Token.RealLiteral: expression = this.ParseRealLiteral(); break; case Token.StringLiteral: expression = this.scanner.GetStringLiteral(); this.GetNextToken(); break; case Token.This: expression = new This(sctx, false); if (this.sink != null) { this.sink.StartName(expression); } this.GetNextToken(); if (this.currentToken == Token.LeftParenthesis && (this.inInstanceConstructor==BaseOrThisCallKind.None || this.inInstanceConstructor==BaseOrThisCallKind.InCtorBodyThisSeen)){ QualifiedIdentifier thisCons = new QualifiedIdentifier(expression, StandardIds.Ctor, this.scanner.CurrentSourceContext); MethodCall thisConstructorCall = new MethodCall(thisCons, null, NodeType.Call); thisConstructorCall.SourceContext = sctx; SourceContext lpCtx = this.scanner.CurrentSourceContext; this.Skip(Token.LeftParenthesis); thisConstructorCall.Operands = this.ParseArgumentList(followers|Token.LeftBrace|Token.Semicolon, lpCtx, out thisConstructorCall.SourceContext.EndPos); expression = thisConstructorCall; this.inInstanceConstructor=BaseOrThisCallKind.InCtorBodyThisSeen; goto done; } break; case Token.Base: Base ba = new Base(sctx, false); expression = ba; if (this.sink != null) { this.sink.StartName(expression); } this.GetNextToken(); if (this.currentToken == Token.Semicolon && (this.inInstanceConstructor == BaseOrThisCallKind.ColonThisOrBaseSeen || this.inInstanceConstructor == BaseOrThisCallKind.None)) { // When there are non-null fields, then the base ctor call can happen only after they are // initialized. // In Spec#, we allow a base ctor call in the body of the ctor. But if someone is using // the C# comment convention, then they cannot do that. // So allow "base;" as a marker to indicate where the base ctor call should happen. // There may be an explicit "colon base call" or it may be implicit. // // Just leave expression as a bare "Base" node; later pipeline stages will all have // to ignore it. Mark the current ctor as having (at least) one of these bad boys // in it. ba.UsedAsMarker = true; this.currentCtor.ContainsBaseMarkerBecauseOfNonNullFields = true; goto done; } if (this.currentToken == Token.LeftParenthesis && (this.inInstanceConstructor==BaseOrThisCallKind.None || this.inInstanceConstructor==BaseOrThisCallKind.InCtorBodyBaseSeen)){ QualifiedIdentifier supCons = new QualifiedIdentifier(expression, StandardIds.Ctor, this.scanner.CurrentSourceContext); MethodCall superConstructorCall = new MethodCall(supCons, null, NodeType.Call); superConstructorCall.SourceContext = sctx; SourceContext lpCtx = this.scanner.CurrentSourceContext; this.Skip(Token.LeftParenthesis); superConstructorCall.Operands = this.ParseArgumentList(followers|Token.LeftBrace|Token.Semicolon, lpCtx, out superConstructorCall.SourceContext.EndPos); expression = superConstructorCall; this.inInstanceConstructor=BaseOrThisCallKind.InCtorBodyBaseSeen; goto done; } break; case Token.Typeof: case Token.Sizeof: case Token.Default:{ //if (this.currentToken == Token.Sizeof && !this.inUnsafeCode) //this.HandleError(Error.SizeofUnsafe); UnaryExpression uex = new UnaryExpression(null, this.currentToken == Token.Typeof ? NodeType.Typeof : this.currentToken == Token.Sizeof ? NodeType.Sizeof : NodeType.DefaultValue); uex.SourceContext = sctx; this.GetNextToken(); this.Skip(Token.LeftParenthesis); TypeNode t = null; if (this.currentToken == Token.Void && uex.NodeType == NodeType.Typeof){ t = this.TypeExpressionFor(Token.Void); this.GetNextToken(); }else t = this.ParseTypeExpression(null, followers|Token.RightParenthesis, false, false, uex.NodeType == NodeType.Typeof); if (t == null){this.SkipTo(followers); return null;} uex.Operand = new MemberBinding(null, t, t.SourceContext, null); uex.Operand.SourceContext = t.SourceContext; uex.SourceContext.EndPos = this.scanner.endPos; this.Skip(Token.RightParenthesis); expression = uex; break;} case Token.Stackalloc:{ this.GetNextToken(); TypeNode elementType = this.ParseBaseTypeExpression(null, followers|Token.LeftBracket, false, false); if (elementType == null){this.SkipTo(followers); return null;} Token openingDelimiter = this.currentToken; if (this.currentToken != Token.LeftBracket){ this.HandleError(Error.BadStackAllocExpr); if (this.currentToken == Token.LeftParenthesis) this.GetNextToken(); }else this.GetNextToken(); Expression numElements = this.ParseExpression(followers|Token.RightBracket|Token.RightParenthesis); sctx.EndPos = this.scanner.endPos; if (this.currentToken == Token.RightParenthesis && openingDelimiter == Token.LeftParenthesis) this.GetNextToken(); else this.Skip(Token.RightBracket); this.SkipTo(followers); return new StackAlloc(elementType, numElements, sctx);} case Token.Checked: case Token.Unchecked: //TODO: use NodeType.SkipCheck and NodeType.EnforceCheck Block b = new Block(new StatementList(1), this.currentToken == Token.Checked, this.currentToken == Token.Unchecked, this.inUnsafeCode); b.SourceContext = sctx; this.GetNextToken(); this.Skip(Token.LeftParenthesis); b.Statements.Add(new ExpressionStatement(this.ParseExpression(followers|Token.RightParenthesis))); this.Skip(Token.RightParenthesis); expression = new BlockExpression(b); expression.SourceContext = b.SourceContext; break; case Token.RefType:{ this.GetNextToken(); this.Skip(Token.LeftParenthesis); Expression e = this.ParseExpression(followers|Token.RightParenthesis); this.Skip(Token.RightParenthesis); expression = new RefTypeExpression(e, sctx); break; } case Token.RefValue:{ this.GetNextToken(); this.Skip(Token.LeftParenthesis); Expression e = this.ParseExpression(followers|Token.Comma); this.Skip(Token.Comma); TypeNode te = this.ParseTypeOrFunctionTypeExpression(followers|Token.RightParenthesis, false, true); Expression operand2 = new MemberBinding(null, te); if (te is TypeExpression) operand2.SourceContext = te.SourceContext; else operand2.SourceContext = sctx; this.Skip(Token.RightParenthesis); expression = new RefValueExpression(e, operand2, sctx); break; } case Token.Bool: case Token.Decimal: case Token.Sbyte: case Token.Byte: case Token.Short: case Token.Ushort: case Token.Int: case Token.Uint: case Token.Long: case Token.Ulong: case Token.Char: case Token.Float: case Token.Double: case Token.Object: case Token.String: MemberBinding mb = new MemberBinding(null, this.TypeExpressionFor(this.currentToken), sctx); this.GetNextToken(); expression = this.ParseIndexerCallOrSelector(mb, followers); goto done; case Token.LeftParenthesis: expression = this.ParseParenthesizedExpression(followers|Token.Dot|Token.LeftBracket|Token.Arrow, true); break; default: if (Parser.IdentifierOrNonReservedKeyword[this.currentToken]) goto case Token.Identifier; if (Parser.InfixOperators[this.currentToken]){ this.HandleError(Error.InvalidExprTerm, this.scanner.GetTokenSource()); this.GetNextToken(); }else this.SkipTo(followers|Parser.PrimaryStart, Error.InvalidExprTerm, this.scanner.GetTokenSource()); if (Parser.PrimaryStart[this.currentToken]) return this.ParsePrimaryExpression(followers); goto done; } if (expression is Base && this.currentToken != Token.Dot && this.currentToken != Token.LeftBracket){ this.HandleError(expression.SourceContext, Error.BaseIllegal); expression = null; } expression = this.ParseIndexerCallOrSelector(expression, followers|Token.AddOne|Token.SubtractOne); for(;;){ switch(this.currentToken){ case Token.AddOne: case Token.SubtractOne: SourceContext ctx = expression.SourceContext; ctx.EndPos = this.scanner.endPos; PostfixExpression pex = new PostfixExpression(expression, Parser.ConvertToBinaryNodeType(this.currentToken), ctx); this.GetNextToken(); expression = pex; break; case Token.Dot: expression = this.ParseIndexerCallOrSelector(expression, followers|Token.AddOne|Token.SubtractOne); break; default: goto done; } } done: this.SkipTo(followers); return expression; }
public override Expression VisitBlockExpression(BlockExpression blockExpression) { // recursively flatten the block(s) this.FlattenBlock(blockExpression.Block); // the code generated from the blocks leaves the expression value on the evaluation stack // So we return a pop expression here. return Pop(blockExpression.Type); }
public override Expression VisitBlockExpression(BlockExpression blockExpression) { Block block = blockExpression.Block; if (block == null) return blockExpression; StatementList sl = block.Statements; if (sl == null) return blockExpression; if (sl.Count == 2 && this.Eliminate(sl[0])) { // the entire expression turns into the expression of the expression statement at sl[1] ExpressionStatement es = (ExpressionStatement)sl[1]; WarnIfExplicit(sl[0] as ExpressionStatement); return VisitExpression(es.Expression); } if (sl.Count == 3 && this.Eliminate(sl[1])) { // the entire expression turns into the Source of the assignment at sl[0] AssignmentStatement asg = (AssignmentStatement)sl[0]; WarnIfExplicit(sl[1] as ExpressionStatement); return VisitExpression(asg.Source); } return base.VisitBlockExpression(blockExpression); }
public override Expression VisitBlockExpression(BlockExpression blockExpression) { throw new NotImplementedException("Node type not yet supported"); }
public EventingVisitor(Action<BlockExpression> visitBlockExpression) { VisitedBlockExpression += visitBlockExpression; } public event Action<BlockExpression> VisitedBlockExpression; public override Expression VisitBlockExpression(BlockExpression blockExpression) { if (VisitedBlockExpression != null) VisitedBlockExpression(blockExpression); return base.VisitBlockExpression(blockExpression); }
private Expression ExtractOldExpression(MethodCall call) { var cand = call.Operands[0]; if (this.currentSL != null) { var locs = FindLocals.Get(cand); if (locs.Count > 0) { // find the instructions that set these locals var assignments = new List<Statement>(); for (int i = this.currentSLindex - 1; i >= 0; i--) { var a = this.currentSL[i] as AssignmentStatement; if (a == null) continue; var loc = a.Target as Local; if (loc == null) continue; if (locs.Contains(loc)) { assignments.Add(a); this.currentSL[i] = null; locs.Remove(loc); } if (locs.Count == 0) break; } assignments.Reverse(); var be = new StatementList(); assignments.ForEach(astmt => be.Add(astmt)); be.Add(new ExpressionStatement(cand)); var sc = cand.SourceContext; cand = new BlockExpression(new Block(be)); cand.SourceContext = sc; if (locs.Count > 0) { // warn that we couldn't extract the local } } } return cand; }