public override Expression VisitReturnValue(ReturnValue returnValue) { // return a default value of the same type as the return value TypeNode returnType = returnValue.Type; ITypeParameter itp = returnType as ITypeParameter; if (itp != null) { Local loc = new Local(returnType); UnaryExpression loca = new UnaryExpression(loc, NodeType.AddressOf, loc.Type.GetReferenceType()); StatementList statements = new StatementList(2); statements.Add(new AssignmentStatement(new AddressDereference(loca, returnType, false, 0), new Literal(null, SystemTypes.Object))); statements.Add(new ExpressionStatement(loc)); return new BlockExpression(new Block(statements), returnType); } if (returnType.IsValueType) return new Literal(0, returnType); return new Literal(null, returnType); }
// // Our notion of "sizeof" is more flexible - the operand can be either a type or // an expression, so we don't want to use the base checker in that case. // public override Expression VisitUnaryExpression(UnaryExpression unaryExpression) { if (unaryExpression.NodeType != NodeType.Sizeof) return base.VisitUnaryExpression(unaryExpression); unaryExpression.Operand = (Expression)this.Visit(unaryExpression.Operand); if (unaryExpression.Operand == null) return null; if (unaryExpression.Operand is Literal) { // If the operand is a literal, it must be an array type reference Literal operand = (Literal)unaryExpression.Operand; if (!(operand.Value is ZArray)) { this.HandleError(unaryExpression.Operand, Error.InvalidSizeofOperand); return null; } } else { // If the operand is an expression, it must refer to an array, set, or channel. TypeNode opndType = unaryExpression.Operand.Type; if (!(opndType is ZArray) && !(opndType is Set) && !(opndType is Chan)) { this.HandleError(unaryExpression.Operand, Error.InvalidSizeofOperand); return null; } } return unaryExpression; }
public override Expression VisitUnaryExpression(UnaryExpression unaryExpression) { bool isFunctionStyle; string opString; opString = GetUnaryOperator(unaryExpression.NodeType, out isFunctionStyle); if (isFunctionStyle) { Write("{0}(", opString); this.VisitExpression(unaryExpression.Operand); Write(")"); } else { Write(opString); this.VisitExpression(unaryExpression.Operand); } return unaryExpression; }
public override Expression VisitUnaryExpression(UnaryExpression unaryExpression) { Expression result = base.VisitUnaryExpression(unaryExpression); // The result of sizeof() is always Int32. if (unaryExpression.NodeType == NodeType.Sizeof) result.Type = SystemTypes.Int32; return result; }
void AddCallDeserializer(TypeNode type, StatementList statements, Identifier reader, Expression target, Expression required, Expression result) { Class memberSerializer = this.CreateSerializerFor(type); // call the Deserialize method on it, and assign result to target object. ExpressionList args = new ExpressionList(); args.Add(reader); args.Add(required); if (result is Local) result = new UnaryExpression(result, NodeType.AddressOf); args.Add(result); MethodCall call = new MethodCall(); Method deserialize = memberSerializer.GetMethod(Identifier.For("Deserialize"), new TypeNode[3] { Runtime.XmlSerializationReader, SystemTypes.Boolean, SystemTypes.Boolean.GetReferenceType() } ); call.Callee = new MemberBinding(new MemberBinding(null, memberSerializer), deserialize); call.Operands = args; statements.Add(new AssignmentStatement(target, call)); }
public override Expression VisitUnaryExpression(UnaryExpression unaryExpression) { if (unaryExpression.NodeType == NodeType.Sizeof) { if (unaryExpression.Operand is MemberBinding) { Expression sizeofExpr = Templates.GetExpressionTemplate("Sizeof"); Replacer.Replace(sizeofExpr, "_sizeofOperand", this.VisitExpression(unaryExpression.Operand)); return sizeofExpr; } else if (unaryExpression.Operand is Literal) { // TODO: This only works for fixed-size arrays. It should be disallowed // (by the checker) for variable size arrays. Literal opLiteral = (Literal)unaryExpression.Operand; if (opLiteral.Value is ZArray) { ZArray opArrayType = (ZArray)opLiteral.Value; return new Literal(opArrayType.Sizes[0], SystemTypes.Int32); } } } return base.VisitUnaryExpression(unaryExpression); }
void EmitCheckExceptionBody(List<Ensures> asyncPostconditions) { // We emit the following method: // bool CheckException(Exception e) { // var c1 = e as C1; // if (c1 != null) { // code for handling c1 // goto Exit; // } // ... // Exit: // return true; // handled if (this.checkExceptionMethod.ExceptionHandlers == null) this.checkExceptionMethod.ExceptionHandlers = new ExceptionHandlerList(); var body = this.checkExceptionMethod.Body.Statements; var returnBlock = new Block(new StatementList()); for (int i = 0, n = asyncPostconditions.Count; i < n; i++) { // Normal postconditions are handled separately. EnsuresExceptional e = asyncPostconditions[i] as EnsuresExceptional; if (e == null) continue; // The catchBlock contains the catchBody, and then // an empty block that is used in the EH. Block catchBlock = new Block(new StatementList()); Local l = new Local(e.Type); body.Add(new AssignmentStatement(l, new BinaryExpression(this.checkExceptionMethod.Parameters[0], new MemberBinding(null, e.Type), NodeType.Isinst))); Block skipBlock = new Block(); body.Add(new Branch(new UnaryExpression(l, NodeType.LogicalNot), skipBlock)); body.Add(catchBlock); body.Add(skipBlock); // call Contract.RewriterEnsures ExpressionList args = new ExpressionList(); args.Add(e.PostCondition); if (e.UserMessage != null) args.Add(e.UserMessage); else args.Add(Literal.Null); if (e.SourceConditionText != null) { args.Add(e.SourceConditionText); } else { args.Add(Literal.Null); } args.Add(l); var checks = new StatementList(); checks.Add(new ExpressionStatement( new MethodCall(new MemberBinding(null, this.parent.runtimeContracts.EnsuresOnThrowMethod), args, NodeType.Call, SystemTypes.Void), e.SourceContext)); this.parent.cleanUpCodeCoverage.VisitStatementList(checks); parent.EmitRecursionGuardAroundChecks(this.checkExceptionMethod, catchBlock, checks); catchBlock.Statements.Add(new Branch(null, returnBlock)); } // recurse on AggregateException itself { // var ae = e as AggregateException; // if (ae != null) { // ae.Handle(this.CheckException); // } Block catchBlock = new Block(new StatementList()); var aggregateType = AggregateExceptionType.Value; Local l = new Local(aggregateType); body.Add(new AssignmentStatement(l, new BinaryExpression(this.checkExceptionMethod.Parameters[0], new MemberBinding(null, aggregateType), NodeType.Isinst))); Block skipBlock = new Block(); body.Add(new Branch(new UnaryExpression(l, NodeType.LogicalNot), skipBlock)); body.Add(catchBlock); body.Add(skipBlock); var funcType = Func2Type.Value; funcType = funcType.GetTemplateInstance(this.parent.assemblyBeingRewritten, SystemTypes.Exception, SystemTypes.Boolean); var handleMethod = aggregateType.GetMethod(Identifier.For("Handle"), funcType); var funcLocal = new Local(funcType); var ldftn = new UnaryExpression(new MemberBinding(null, this.checkExceptionMethod), NodeType.Ldftn, CoreSystemTypes.IntPtr); catchBlock.Statements.Add(new AssignmentStatement(funcLocal, new Construct(new MemberBinding(null, funcType.GetConstructor(SystemTypes.Object, SystemTypes.IntPtr)), new ExpressionList(this.checkMethod.ThisParameter, ldftn)))); catchBlock.Statements.Add(new ExpressionStatement(new MethodCall(new MemberBinding(l, handleMethod), new ExpressionList(funcLocal)))); } // add return true to CheckExceptionMethod body.Add(returnBlock); body.Add(new Return(Literal.True)); }
//[ContractVerification(true)] private void VisitMethodInternal(Method method) { if (method.IsAbstract || IsRewriterGenerated(method)) { return; } Block origBody = method.Body; if (origBody == null || origBody.Statements == null || origBody.Statements.Count == 0) return; #if DEBUG if (!RewriteHelper.PostNormalizedFormat(method)) throw new RewriteException("The method body for '" + method.FullName + "' is not structured correctly"); #endif #region Rewrite all Assert and Assume methods // Happens in-place so any modifications made are persisted even if nothing else is done to method RewriteAssertAssumeAndCallSiteRequires raa = new RewriteAssertAssumeAndCallSiteRequires(this.AssertAssumeRewriteMethodTable, this.runtimeContracts, this.contractEmitFlags, this, method); method.Body = raa.VisitBlock(method.Body); #endregion Rewrite all Assert and Assume methods (if user specified) #region Bail out early if publicSurfaceOnly and method is not visible (but not for contract validators!) or contract abbreviator if (this.runtimeContracts.PublicSurfaceOnly && !IsCallableFromOutsideAssembly(method) && !ContractNodes.IsValidatorMethod(method) || ContractNodes.IsAbbreviatorMethod(method)) return; #endregion int oldLocalUniqueNameCounter = 0; List<Block> contractInitializationBlocks = new List<Block>(); Block postPreambleBlock = null; Dictionary<TypeNode, Local> closureLocals = new Dictionary<TypeNode, Local>(); Block oldExpressionPreStateValues = new Block(new StatementList()); #region Gather pre- and postconditions from supertypes and from method contract // Create lists of unique preconditions and postconditions. List<Requires> preconditions = new List<Requires>(); List<Ensures> postconditions = new List<Ensures>(); List<Ensures> asyncPostconditions = new List<Ensures>(); RequiresList validations = null; // For postconditions, wrap all parameters within an old expression (if they are not already within one) var wrap = new WrapParametersInOldExpressions(); EmitAsyncClosure asyncBuilder = null; #region Copy the method's contracts. if (method.Contract != null && (method.Contract.RequiresCount > 0 || method.Contract.EnsuresCount > 0 || method.Contract.ValidationsCount > 0 || method.Contract.AsyncEnsuresCount > 0)) { // Use duplicate of contract because it is going to get modified from processing Old(...) and // Result(). Can't have the modified contract get inherited (or else the Old(...) processing // will not work properly.) // Can't use MethodContract.CopyFrom or HelperMethods.DuplicateMethodBodyAndContract // because they assume the new contract is in a different method. Plus the latter duplicates // any closure classes needed for anonymous delegates in the contract. MethodContract mc = HelperMethods.DuplicateContractAndClosureParts(method, method, this.runtimeContracts.ContractNodes, true); validations = mc.Validations; if (mc != null) { contractInitializationBlocks.Add(mc.ContractInitializer); postPreambleBlock = mc.PostPreamble; RecordEnsures(method, ref oldLocalUniqueNameCounter, contractInitializationBlocks, closureLocals, oldExpressionPreStateValues, postconditions, asyncPostconditions, wrap, ref asyncBuilder, mc); } } #endregion Copy the method's contracts. #region Search the class hierarchy for overridden methods to propagate their contracts. if (this.Emit(RuntimeContractEmitFlags.InheritContracts) && method.OverridesBaseClassMember && method.DeclaringType != null && method.OverriddenMethod != null) { for (TypeNode super = method.DeclaringType.BaseType; super != null; super = HelperMethods.DoesInheritContracts(super)?super.BaseType:null) { var baseMethod = super.GetImplementingMethod(method.OverriddenMethod, false); Method baseContractMethod = HelperMethods.GetContractMethod(baseMethod); if (baseContractMethod != null) { MethodContract mc = HelperMethods.DuplicateContractAndClosureParts(method, baseContractMethod, this.runtimeContracts.ContractNodes, false); RewriteHelper.ReplacePrivateFieldsThatHavePublicProperties(method.DeclaringType, super, mc, this.rewriterNodes); if (mc != null) { contractInitializationBlocks.Add(mc.ContractInitializer); // can't have post preambles in overridden methods, since they cannot be constructors. // only add requires if baseMethod is the root method if (mc.Requires != null && baseMethod.OverriddenMethod == null) { foreach (RequiresPlain requires in mc.Requires) { if (!EmitRequires(requires, this.skipQuantifiers)) continue; // Debug.Assert(!preconditions.Contains(requires)); preconditions.Add(requires); } } RecordEnsures(method, ref oldLocalUniqueNameCounter, contractInitializationBlocks, closureLocals, oldExpressionPreStateValues, postconditions, asyncPostconditions, wrap, ref asyncBuilder, mc); } } // bail out if this base type does not inherit contracts if (!HelperMethods.DoesInheritContracts(super)) break; } } #endregion Search the class hierarchy for overridden methods to propagate their contracts. #region Propagate explicit interface method contracts. if (this.Emit(RuntimeContractEmitFlags.InheritContracts) && method.ImplementedInterfaceMethods != null) { foreach (Method interfaceMethod in method.ImplementedInterfaceMethods) { if (interfaceMethod != null) { Method contractMethod = HelperMethods.GetContractMethod(interfaceMethod); if (contractMethod != null) { // if null, then no contract for this interface method // Maybe it would be easier to just duplicate the entire method and then pull the // initialization code from the duplicate? MethodContract mc=HelperMethods.DuplicateContractAndClosureParts(method, contractMethod, this.runtimeContracts.ContractNodes, false); if (mc != null) { contractInitializationBlocks.Add(mc.ContractInitializer); // can't have post preambles in interface methods (not constructors) if (mc.Requires != null) { foreach (RequiresPlain requires in mc.Requires) { if (!EmitRequires(requires, this.skipQuantifiers)) continue; // Debug.Assert(!preconditions.Contains(requires)); preconditions.Add(requires); } } RecordEnsures(method, ref oldLocalUniqueNameCounter, contractInitializationBlocks, closureLocals, oldExpressionPreStateValues, postconditions, asyncPostconditions, wrap, ref asyncBuilder, mc); } } } } } #endregion Propagate explicit interface method contracts. #region Propagate implicit interface method contracts. if (this.Emit(RuntimeContractEmitFlags.InheritContracts) && method.ImplicitlyImplementedInterfaceMethods != null) { foreach (Method interfaceMethod in method.ImplicitlyImplementedInterfaceMethods) { if (interfaceMethod != null) { Method contractMethod = HelperMethods.GetContractMethod(interfaceMethod); if (contractMethod != null) { // if null, then no contract for this method // Maybe it would be easier to just duplicate the entire method and then pull the // initialization code from the duplicate? MethodContract mc = HelperMethods.DuplicateContractAndClosureParts(method, contractMethod, this.runtimeContracts.ContractNodes, false); if (mc != null) { contractInitializationBlocks.Add(mc.ContractInitializer); // can't have post preambles in implicit interface method implementations, as they are not constructors. if (mc.Requires != null) { foreach (RequiresPlain requires in mc.Requires) { if (!EmitRequires(requires, this.skipQuantifiers)) continue; // Debug.Assert(!preconditions.Contains(requires)); preconditions.Add(requires); } } RecordEnsures(method, ref oldLocalUniqueNameCounter, contractInitializationBlocks, closureLocals, oldExpressionPreStateValues, postconditions, asyncPostconditions, wrap, ref asyncBuilder, mc); } } } } } #endregion Propagate implicit interface method contracts. #endregion Gather pre- and postconditions from supertypes and from method contract #region Return if there is nothing to do if (preconditions.Count < 1 && postconditions.Count < 1 && asyncPostconditions.Count < 1 && (validations == null || validations.Count == 0) && this.InvariantMethod == null) return; #endregion Return if there is nothing to do #region Change all short branches to long because code modifications can add code { // REVIEW: This does *not* remove any short branches in the contracts. // I think that is okay, but we should think about it. RemoveShortBranches rsb = new RemoveShortBranches(); rsb.VisitBlock(method.Body); } #endregion Change all short branches to long because code modifications can add code #region Modify method body to change all returns into assignments and branch to unified exit // now modify the method body to change all return statements // into assignments to the local "result" and a branch to a // block at the end that can check the post-condition using // "result" and then finally return it. // [MAF] we do it later once we know if the branches are leaves or just branch. Local result = null; if (!HelperMethods.IsVoidType(method.ReturnType)) { // don't write huge names. The debugger chokes on them and shows no locals at all. // result = new Local(Identifier.For("Contract.Result<" + typeName + ">()"), method.ReturnType); result = new Local(Identifier.For("Contract.Result()"), method.ReturnType); if (method.LocalList == null) { method.LocalList = new LocalList(); } method.LocalList.Add(result); } Block newExit = new Block(new StatementList()); #endregion Modify method body to change all returns into assignments and branch to unified exit #region Create the new method's body Block newBody = new Block(new StatementList()); newBody.HasLocals = true; #endregion Create the new method's body #region If there had been any closure initialization code, put it first in the new body if (0 < contractInitializationBlocks.Count) { foreach (Block b in contractInitializationBlocks) { newBody.Statements.Add(b); } } #endregion EmitInterleavedValidationsAndRequires(method, preconditions, validations, newBody); #region Turn off invariant checking until the end Local oldReEntrancyFlagLocal = null; if (MethodShouldHaveInvariantChecked(method) && this.ReentrancyFlag != null && BodyHasCalls(method.Body)) { oldReEntrancyFlagLocal = new Local(SystemTypes.Boolean); newBody.Statements.Add(new Block(new StatementList( new AssignmentStatement(oldReEntrancyFlagLocal, new MemberBinding(method.ThisParameter, this.ReentrancyFlag)), new AssignmentStatement(new MemberBinding(method.ThisParameter, this.ReentrancyFlag), Literal.True)))); } #endregion #region Put all of the collected initializations from "old" expressions into the method if (oldExpressionPreStateValues.Statements.Count > 0) { newBody.Statements.Add(oldExpressionPreStateValues); } #endregion // if there are preamble blocks we need to move them from the origBody in case we will wrap a try-catch var preambleIndex = 0; while (origBody.Statements.Count > preambleIndex && origBody.Statements[preambleIndex] is PreambleBlock) { newBody.Statements.Add(origBody.Statements[preambleIndex]); origBody.Statements[preambleIndex] = null; preambleIndex++; } Block newBodyBlock = new Block(new StatementList()); newBody.Statements.Add(newBodyBlock); // placeholder for eventual body newBody.Statements.Add(newExit); #region Replace "result" in postconditions (both for method return and out parameters) if (result != null) { foreach (Ensures e in postconditions) { if (e == null) continue; ReplaceResult repResult = new ReplaceResult(method, result, this.assemblyBeingRewritten); repResult.Visit(e); // now need to initialize closure result fields foreach (var target in repResult.NecessaryResultInitialization(closureLocals)) { newBody.Statements.Add(new AssignmentStatement(target, result)); } } } #endregion #region Emit potential post preamble block (from contract duplicate) in constructors if (postPreambleBlock != null) { newBody.Statements.Add(postPreambleBlock); } #endregion #region Emit normal postconditions SourceContext lastEnsuresSourceContext = default(SourceContext); bool hasLastEnsuresContext = false; bool containsExceptionalPostconditions = false; var ensuresChecks = new StatementList(); foreach (Ensures e in postconditions) { // Exceptional postconditions are handled separately. if (e is EnsuresExceptional) { containsExceptionalPostconditions = true; continue; } lastEnsuresSourceContext = e.SourceContext; hasLastEnsuresContext = true; // call Contract.RewriterEnsures Method ensMethod = this.runtimeContracts.EnsuresMethod; ExpressionList args = new ExpressionList(); args.Add(e.PostCondition); if (e.UserMessage != null) args.Add(e.UserMessage); else args.Add(Literal.Null); if (e.SourceConditionText != null) { args.Add(e.SourceConditionText); } else { args.Add(Literal.Null); } ensuresChecks.Add(new ExpressionStatement( new MethodCall(new MemberBinding(null, ensMethod), args, NodeType.Call, SystemTypes.Void), e.SourceContext)); } this.cleanUpCodeCoverage.VisitStatementList(ensuresChecks); EmitRecursionGuardAroundChecks(method, newBody, ensuresChecks); #endregion Normal postconditions #region Emit object invariant if (MethodShouldHaveInvariantChecked(method)) { // Now turn checking on by restoring old reentrancy flag if (this.ReentrancyFlag != null && oldReEntrancyFlagLocal != null) { newBody.Statements.Add(new AssignmentStatement(new MemberBinding(method.ThisParameter, this.ReentrancyFlag), oldReEntrancyFlagLocal)); } var callType = (method is InstanceInitializer) || this.InvariantMethod.DeclaringType.IsValueType ? NodeType.Call : NodeType.Callvirt; // just add a call to the already existing invariant method, "this.InvariantMethod();" // all of the processing needed is done as part of VisitClass newBody.Statements.Add( new ExpressionStatement( new MethodCall( new MemberBinding(method.ThisParameter, this.InvariantMethod), null, callType, SystemTypes.Void))); } #endregion Object invariant #region Emit exceptional postconditions ReplaceReturns rr; if (containsExceptionalPostconditions) { // -- The following code comes from System.Compiler.Normalizer.CreateTryCatchBlock -- // The tryCatch holds the try block, the catch blocks, and an empty block that is the // target of an unconditional branch for normal execution to go from the try block // around the catch blocks. if (method.ExceptionHandlers == null) method.ExceptionHandlers = new ExceptionHandlerList(); Block afterCatches = new Block(new StatementList()); Block tryCatch = newBodyBlock; Block tryBlock = new Block(new StatementList()); tryBlock.Statements.Add(origBody); rr = new ReplaceReturns(result, newExit, leaveExceptionBody:true); rr.Visit(origBody); tryBlock.Statements.Add(new Branch(null, afterCatches, false, true, true)); // the EH needs to have a pointer to this block so the writer can // calculate the length of the try block. So it should be the *last* // thing in the try body. Block blockAfterTryBody = new Block(null); tryBlock.Statements.Add(blockAfterTryBody); tryCatch.Statements.Add(tryBlock); for (int i = 0, n = postconditions.Count; i < n; i++) { // Normal postconditions are handled separately. EnsuresExceptional e = postconditions[i] as EnsuresExceptional; if (e == null) continue; // The catchBlock contains the catchBody, and then // an empty block that is used in the EH. Block catchBlock = new Block(new StatementList()); Local l = new Local(e.Type); Throw rethrow = new Throw(); rethrow.NodeType = NodeType.Rethrow; // call Contract.RewriterEnsures ExpressionList args = new ExpressionList(); args.Add(e.PostCondition); if (e.UserMessage != null) args.Add(e.UserMessage); else args.Add(Literal.Null); if (e.SourceConditionText != null) { args.Add(e.SourceConditionText); } else { args.Add(Literal.Null); } args.Add(l); var checks = new StatementList(); checks.Add(new ExpressionStatement( new MethodCall(new MemberBinding(null, this.runtimeContracts.EnsuresOnThrowMethod), args, NodeType.Call, SystemTypes.Void), e.SourceContext)); catchBlock.Statements.Add(new AssignmentStatement(l, new Expression(NodeType.Pop), e.SourceContext)); this.cleanUpCodeCoverage.VisitStatementList(checks); EmitRecursionGuardAroundChecks(method, catchBlock, checks); #region Emit object invariant on EnsuresOnThrow check if (MethodShouldHaveInvariantChecked(method, inExceptionCase: true)) { // Now turn checking on by restoring old reentrancy flag if (this.ReentrancyFlag != null && oldReEntrancyFlagLocal != null) { catchBlock.Statements.Add(new AssignmentStatement(new MemberBinding(method.ThisParameter, this.ReentrancyFlag), oldReEntrancyFlagLocal)); } // just add a call to the already existing invariant method, "this.InvariantMethod();" // all of the processing needed is done as part of VisitClass catchBlock.Statements.Add( new ExpressionStatement( new MethodCall( new MemberBinding(method.ThisParameter, this.InvariantMethod), null, NodeType.Call, SystemTypes.Void))); } #endregion Object invariant catchBlock.Statements.Add(rethrow); // The last thing in each catch block is an empty block that is the target of // BlockAfterHandlerEnd in each exception handler. // It is used in the writer to determine the length of each catch block // so it should be the last thing added to each catch block. Block blockAfterHandlerEnd = new Block(new StatementList()); catchBlock.Statements.Add(blockAfterHandlerEnd); tryCatch.Statements.Add(catchBlock); // add information to the ExceptionHandlers of this method ExceptionHandler exHandler = new ExceptionHandler(); exHandler.TryStartBlock = origBody; exHandler.BlockAfterTryEnd = blockAfterTryBody; exHandler.HandlerStartBlock = catchBlock; exHandler.BlockAfterHandlerEnd = blockAfterHandlerEnd; exHandler.FilterType = l.Type; exHandler.HandlerType = NodeType.Catch; method.ExceptionHandlers.Add(exHandler); } tryCatch.Statements.Add(afterCatches); } else // no exceptional post conditions { newBodyBlock.Statements.Add(origBody); rr = new ReplaceReturns(result, newExit, leaveExceptionBody: false); rr.Visit(origBody); } #endregion Exceptional and finally postconditions #region Create a block for the return statement and insert it // this is the block that contains the return statements // it is (supposed to be) the single exit from the method // that way, anything that must always be done can be done // in this block Block returnBlock = new Block(new StatementList(1)); if (asyncPostconditions != null && asyncPostconditions.Count > 0) { asyncBuilder.AddAsyncPost(asyncPostconditions); var funcLocal = new Local(asyncBuilder.FuncCtor.DeclaringType); var ldftn = new UnaryExpression(new MemberBinding(null, asyncBuilder.CheckMethod), NodeType.Ldftn, CoreSystemTypes.IntPtr); returnBlock.Statements.Add(new AssignmentStatement(funcLocal, new Construct(new MemberBinding(null, asyncBuilder.FuncCtor), new ExpressionList(asyncBuilder.ClosureLocal, ldftn)))); returnBlock.Statements.Add(new AssignmentStatement(result, new MethodCall(new MemberBinding(result, asyncBuilder.ContinueWithMethod), new ExpressionList(funcLocal)))); } Statement returnStatement; if (!HelperMethods.IsVoidType(method.ReturnType)) { returnStatement = new Return(result); } else { returnStatement = new Return(); } if (hasLastEnsuresContext) { returnStatement.SourceContext = lastEnsuresSourceContext; } else { returnStatement.SourceContext = rr.LastReturnSourceContext; } returnBlock.Statements.Add(returnStatement); newBody.Statements.Add(returnBlock); #endregion method.Body = newBody; #region Make sure InitLocals is marked for this method // 15 April 2003 // Since each method has locals added to it, need to make sure this flag is // on. Otherwise, the generated code cannot pass peverify. if (!method.InitLocals) { method.InitLocals = true; //WriteToLog("Setting InitLocals for method: {0}", method.FullName); } #endregion }
private void EmitCheckExceptionBody(Method checkExceptionMethod, List<EnsuresExceptional> exceptionalPostconditions) { Contract.Requires(checkExceptionMethod != null); Contract.Requires(exceptionalPostconditions != null); Contract.Requires(exceptionalPostconditions.Count > 0); // We emit the following method: // bool CheckException(Exception e) { // var ex = e as C1; // if (ex != null) { // EnsuresOnThrow(predicate) // } // else { // var ex2 = e as AggregateException; // if (ex2 != null) { // ex2.Handle(CheckException); // } // } // // // Method always returns true. This is by design! // // We need to check all exceptions in the AggregateException // // and fail in EnsuresOnThrow if the postcondition is not met. // return true; // handled var body = checkExceptionMethod.Body.Statements; var returnBlock = new Block(new StatementList()); foreach (var e in exceptionalPostconditions) { // The catchBlock contains the catchBody, and then // an empty block that is used in the EH. // TODO ST: name is confusing because there is no catch blocks in this method! Block catchBlock = new Block(new StatementList()); // local is: var ex1 = e as C1; Local localEx = new Local(e.Type); body.Add( new AssignmentStatement(localEx, new BinaryExpression(checkExceptionMethod.Parameters[0], new MemberBinding(null, e.Type), NodeType.Isinst))); Block skipBlock = new Block(); body.Add(new Branch(new UnaryExpression(localEx, NodeType.LogicalNot), skipBlock)); body.Add(catchBlock); body.Add(skipBlock); // call Contract.EnsuresOnThrow ExpressionList args = new ExpressionList(); args.Add(e.PostCondition); args.Add(e.UserMessage ?? Literal.Null); args.Add(e.SourceConditionText ?? Literal.Null); args.Add(localEx); var checks = new StatementList(); checks.Add( new ExpressionStatement( new MethodCall( new MemberBinding(null, this.rewriter.RuntimeContracts.EnsuresOnThrowMethod), args, NodeType.Call, SystemTypes.Void), e.SourceContext)); this.rewriter.CleanUpCodeCoverage.VisitStatementList(checks); // TODO ST: actually I can't see this recursion guard check in the resulting IL!! rewriter.EmitRecursionGuardAroundChecks(checkExceptionMethod, catchBlock, checks); catchBlock.Statements.Add(new Branch(null, returnBlock)); } // recurse on AggregateException itself { // var ae = e as AggregateException; // if (ae != null) { // ae.Handle(this.CheckException); // } Block catchBlock = new Block(new StatementList()); var aggregateType = aggregateExceptionType.Value; // var ex2 = e as AggregateException; Local localEx2 = new Local(aggregateType); body.Add( new AssignmentStatement(localEx2, new BinaryExpression( checkExceptionMethod.Parameters[0], new MemberBinding(null, aggregateType), NodeType.Isinst))); Block skipBlock = new Block(); body.Add(new Branch(new UnaryExpression(localEx2, NodeType.LogicalNot), skipBlock)); body.Add(catchBlock); body.Add(skipBlock); var funcType = func2Type.Value; funcType = funcType.GetTemplateInstance(this.rewriter.AssemblyBeingRewritten, SystemTypes.Exception, SystemTypes.Boolean); var handleMethod = aggregateType.GetMethod(Identifier.For("Handle"), funcType); var funcLocal = new Local(funcType); var ldftn = new UnaryExpression( new MemberBinding(null, checkExceptionMethod), NodeType.Ldftn, CoreSystemTypes.IntPtr); catchBlock.Statements.Add( new AssignmentStatement(funcLocal, new Construct( new MemberBinding(null, funcType.GetConstructor(SystemTypes.Object, SystemTypes.IntPtr)), new ExpressionList(checkExceptionMethod.ThisParameter, ldftn)))); catchBlock.Statements.Add( new ExpressionStatement(new MethodCall(new MemberBinding(localEx2, handleMethod), new ExpressionList(funcLocal)))); } // add return true to CheckException method body.Add(returnBlock); body.Add(new Return(Literal.True)); }
private void AddContinueWithMethodToReturnBlock(Block returnBlock, Local taskBasedResult) { Contract.Requires(returnBlock != null); Contract.Requires(taskBasedResult != null); var taskType = taskBasedResult.Type; // To find appropriate ContinueWith method task type should be unwrapped var taskTemplate = HelperMethods.Unspecialize(taskType); var continueWithMethodLocal = GetContinueWithMethod(closureClass, taskTemplate, taskType); // TODO: not sure that this is possible situation when continueWith method is null. // Maybe Contract.Assert(continueWithMethod != null) should be used instead! if (continueWithMethodLocal != null) { // We need to create delegate instance that should be passed to ContinueWith method var funcType = continueWithMethodLocal.Parameters[0].Type; var funcCtor = funcType.GetConstructor(SystemTypes.Object, SystemTypes.IntPtr); Contract.Assume(funcCtor != null); var funcLocal = new Local(funcCtor.DeclaringType); // Creating a method pointer to the AsyncClosure.CheckMethod // In this case we can't use checkMethod field. // Getting CheckMethod from clsoureClassInstance will provide correct (potentially updated) // generic arguments for enclosing type. var checkMethodFromClosureInstance = (Method) closureClassInstance.GetMembersNamed(CheckMethodId)[0]; Contract.Assume(checkMethodFromClosureInstance != null); var ldftn = new UnaryExpression( new MemberBinding(null, checkMethodFromClosureInstance), NodeType.Ldftn, CoreSystemTypes.IntPtr); // Creating delegate that would be used as a continuation for original task returnBlock.Statements.Add( new AssignmentStatement(funcLocal, new Construct(new MemberBinding(null, funcCtor), new ExpressionList(closureLocal, ldftn)))); // Wrapping continuation into TaskExtensions.Unwrap method // (this helps to preserve original exception and original result of the task, // but allows to throw postconditions violations). // Generating: result.ContinueWith(closure.CheckPost); var taskContinuationOption = new Literal(TaskContinuationOptions.ExecuteSynchronously); var continueWithCall = new MethodCall( new MemberBinding(taskBasedResult, continueWithMethodLocal), new ExpressionList(funcLocal, taskContinuationOption)); // Generating: TaskExtensions.Unwrap(result.ContinueWith(...)) var unwrapMethod = GetUnwrapMethod(checkMethodTaskType); var unwrapCall = new MethodCall( new MemberBinding(null, unwrapMethod), new ExpressionList(continueWithCall)); // Generating: result = Unwrap(...); var resultAssignment = new AssignmentStatement(taskBasedResult, unwrapCall); returnBlock.Statements.Add(resultAssignment); } }
public override Expression VisitPopExpr(UnaryExpression unex) { Expression operand = (Expression)this.Visit(unex.Operand); unex = (UnaryExpression)unex.Clone(); unex.Operand = operand; return unex; }
/// <summary> /// </summary> /// <param name="expression">Cloned</param> public override Expression VisitUnaryExpression(UnaryExpression expression) { expression = (UnaryExpression)expression.Clone(); switch(expression.NodeType) { case NodeType.Ldtoken: return expression; case NodeType.Ldftn: expression.Operand = (Expression)this.Visit(expression.Operand); return expression; case NodeType.AddressOf: case NodeType.ReadOnlyAddressOf: case NodeType.OutAddress: // alias of AddressOf case NodeType.RefAddress: // alias of AddressOf expression.Operand = simplify_addressof_operand(expression.Operand); return expression; } expression.Operand = simplify(expression.Operand); return expression; }
public override Expression VisitUnaryExpression(UnaryExpression unaryExpression) { if (unaryExpression == null) return null; unaryExpression = (UnaryExpression)unaryExpression.Clone(); unaryExpression.Operand = this.VisitExpression(unaryExpression.Operand); return unaryExpression; }
public override Expression VisitUnaryExpression(UnaryExpression unaryExpression) { var temp = base.VisitUnaryExpression(unaryExpression); if (temp.NodeType == NodeType.AddressOf) { var unary = temp as UnaryExpression; if (unary != null) { if (!IsAddressoffable(unary.Operand.NodeType)) { var newVar = new Local(unary.Operand.Type); var sl = new StatementList(); sl.Add(new AssignmentStatement(newVar, unary.Operand)); unary.Operand = newVar; sl.Add(new ExpressionStatement(unary)); return new BlockExpression(new Block(sl)); } } } return temp; }
private UnaryExpression VisitChoose(UnaryExpression expr) { if (expr == null) return null; if (!this.validChooses.Contains(expr)) { this.HandleError(expr, Error.EmbeddedChoose); return null; } return expr; }
private UnaryExpression VisitChoose(UnaryExpression expr) { if (expr == null) return null; UnaryExpression result = (UnaryExpression)base.VisitUnaryExpression(expr); return result; }
public override Expression VisitUnaryExpression(UnaryExpression unaryExpression) { if (unaryExpression == null) return null; switch (unaryExpression.NodeType) { case NodeType.AddressOf: if (unaryExpression.Type is Reference) return unaryExpression; if (!this.typeSystem.insideUnsafeCode && unaryExpression.SourceContext.Document != null) { this.HandleError(unaryExpression, Error.UnsafeNeeded); return null; } // change by drunje: you can obtain a pointer to managed structure Expression opnd = unaryExpression.Operand = this.VisitExpression(unaryExpression.Operand); if (opnd != null && this.CheckFixed(opnd) && opnd.Type != null && !opnd.Type.IsUnmanaged) { // this is not compatible with C# SpecSharpCompilerOptions options = this.currentOptions as SpecSharpCompilerOptions; if (options != null && options.AllowPointersToManagedStructures) { // pointers to all structures are allowed now if (opnd.Type.IsValueType) return unaryExpression; // we can convert a reference on any structure to a pointer as well if ((opnd.Type is Reference) && ((opnd.Type as Reference).ElementType.IsValueType)) return unaryExpression; } if ((opnd.Type is Reference) && ((opnd.Type as Reference).ElementType.IsUnmanaged)) return unaryExpression; this.HandleError(unaryExpression, Error.ManagedAddr, this.GetTypeName(opnd.Type)); return null; } // end of change by drunje return unaryExpression; default: break; } return base.VisitUnaryExpression(unaryExpression); }
private void ParseMethodContract(Method m, TokenSet followers, ref bool swallowedSemicolonAlready){ bool savedParsingStatement = this.parsingStatement; if (this.currentToken != Token.EndOfFile) this.parsingStatement = true; if (!swallowedSemicolonAlready) m.SourceContext.EndPos = this.scanner.endPos; MethodContract mc = new MethodContract(m); SourceContext initialSourceContext = this.scanner.CurrentSourceContext; while ( Parser.ContractStart[this.currentToken] ) { SourceContext ctx = this.scanner.CurrentSourceContext; Node n = null; int finalPos = 0; switch ( this.currentToken ) { case Token.Requires: { this.GetNextToken(); if (this.currentToken == Token.LeftBrace){ this.HandleError(Error.ExpectedExpression); break; // without this, the left bracket gets parsed as an anonymous nested function } Expression e = this.ParseExpression(followers|ContractStart|Token.Otherwise); if (mc.Requires == null) mc.Requires = new RequiresList(); if (this.currentToken != Token.Otherwise) { Requires r = new RequiresPlain(e); n = r; mc.Requires.Add(r); }else { this.Skip(Token.Otherwise); Expression e2 = this.ParseExpression(followers|ContractStart); Requires r = new RequiresOtherwise(e,e2); n = r; mc.Requires.Add(r); } finalPos = this.scanner.CurrentSourceContext.EndPos; swallowedSemicolonAlready= (this.currentToken == Token.Semicolon); this.SkipSemiColon(followers|ContractStart); break; } case Token.Modifies: { // modifies expressions have their source context set here within this // case, so don't use the variable "n" to hold on to the AST otherwise // it will have the wrong source context set for it at the end of the switch // statement n = null; this.insideModifiesClause = true; list : { this.GetNextToken(); // Token.Modifies or Token.Comma SourceContext sctx = this.scanner.CurrentSourceContext; Expression e = this.ParseExpression(followers | ContractStart | Token.Comma); if (mc.Modifies == null) mc.Modifies = new ExpressionList(); if (e != null) { // REVIEW: does this just silently miss errors? sctx.EndPos = e.SourceContext.EndPos; ModifiesClause modClause = e as ModifiesClause; if (modClause != null) { e.SourceContext = sctx; } else { e = new UnaryExpression(e, NodeType.RefAddress, sctx); } mc.Modifies.Add(e); } if (this.currentToken == Token.Comma) goto list; } swallowedSemicolonAlready= (this.currentToken == Token.Semicolon); finalPos = this.scanner.CurrentSourceContext.EndPos; this.SkipSemiColon(followers|ContractStart); this.insideModifiesClause = false; break; } case Token.Ensures: { InEnsuresContext = true; this.GetNextToken(); if (this.currentToken == Token.LeftBrace){ this.HandleError(Error.ExpectedExpression); break; // without this, the left bracket gets parsed as an anonymous nested function } Expression e = this.ParseExpression(followers|ContractStart); if (mc.Ensures == null) mc.Ensures = new EnsuresList(); EnsuresNormal en = new EnsuresNormal(e); n = en; mc.Ensures.Add(en); finalPos = this.scanner.CurrentSourceContext.EndPos; swallowedSemicolonAlready= (this.currentToken == Token.Semicolon); this.SkipSemiColon(followers|ContractStart); InEnsuresContext = false; break; } case Token.Throws: { this.GetNextToken(); // throws (E1) ensures P; // throws (E1 e) ensures P; // throws E1 ensures P; // throws E1, E2, ...; // Note, for constuctors, only the last of these forms is allowed. if (mc.Ensures == null) { mc.Ensures = new EnsuresList(); // Note, this list may be left empty in case of parsing errors below. } EnsuresExceptional exc = new EnsuresExceptional(); exc.SourceContext = this.scanner.CurrentSourceContext; bool hasLeftParen = false; if (this.currentToken == Token.LeftParenthesis) { hasLeftParen = true; this.Skip(Token.LeftParenthesis); } exc.Type = exc.TypeExpression = this.ParseTypeExpression(Identifier.Empty, followers|Token.Identifier|Token.RightParenthesis|ContractStart); if (hasLeftParen && Parser.IdentifierOrNonReservedKeyword[this.currentToken]) { exc.Variable = this.scanner.GetIdentifier(); exc.Variable.Type = exc.Type; this.GetNextToken(); }else{ exc.Variable = null; // need to be able to distinguish whether the source contains a variable or not } if (hasLeftParen) { this.Skip(Token.RightParenthesis); } if (hasLeftParen || this.currentToken == Token.Ensures) { // throws (E1) ensures P; // throws (E1 e) ensures P; // throws E1 ensures P; SourceContext ctxEnsures = this.scanner.CurrentSourceContext; this.Skip(Token.Ensures); InEnsuresContext = true; Expression ens = this.ParseExpression(followers|ContractStart); InEnsuresContext = false; // Do the constructor check now. This is rather late, since the whole throws...ensures // has now been parsed, but this may lead to better parse-error recovery. if (m is InstanceInitializer) { this.HandleError(ctxEnsures, Error.ThrowsEnsuresOnConstructor); // ignore what was parsed exc.PostCondition = new Literal(true, null, ctx); }else{ exc.PostCondition = ens; } mc.Ensures.Add(exc); }else{ // throws E1, E2, ...; // exc.PostCondition = new Literal(true, null, ctx); mc.Ensures.Add(exc); while (this.currentToken == Token.Comma) { this.GetNextToken(); exc = new EnsuresExceptional(); exc.SourceContext = this.scanner.CurrentSourceContext; exc.Type = exc.TypeExpression = this.ParseTypeExpression(Identifier.Empty, followers|Token.Comma|ContractStart); exc.Variable = new Local(TypeExpressionFor("System", "Exception")); exc.Variable.SourceContext = ctx; exc.PostCondition = new Literal(true, null, ctx); mc.Ensures.Add(exc); } } finalPos = this.scanner.CurrentSourceContext.EndPos; swallowedSemicolonAlready= (this.currentToken == Token.Semicolon); this.SkipSemiColon(followers|ContractStart); n = exc; break; } } if (n != null) { n.SourceContext= ctx; n.SourceContext.EndPos = finalPos ; } m.SourceContext.EndPos = finalPos; } // What error to generate here? if (!followers[this.currentToken]) this.SkipTo(followers); if (initialSourceContext.EndPos != this.scanner.CurrentSourceContext.EndPos) { // then a contract really was parsed m.Contract = mc; } if (this.currentToken != Token.EndOfFile) this.parsingStatement = savedParsingStatement; }
public void AddAsyncPost(List<Ensures> asyncPostconditions) { var origBody = new Block(this.checkBody); origBody.HasLocals = true; var newBodyBlock = new Block(new StatementList()); newBodyBlock.HasLocals = true; var methodBody = new StatementList(); var methodBodyBlock = new Block(methodBody); methodBodyBlock.HasLocals = true; checkMethod.Body = methodBodyBlock; methodBody.Add(newBodyBlock); Block newExitBlock = new Block(); methodBody.Add(newExitBlock); #region Map closure locals to fields and initialize closure fields foreach (Ensures e in asyncPostconditions) { if (e == null) continue; this.Visit(e); if (this.forwarder != null) { this.forwarder.Visit(e); } ReplaceResult repResult = new ReplaceResult(this.checkMethod, this.originalResultLocal, this.parent.assemblyBeingRewritten); repResult.Visit(e); // now need to initialize closure result fields foreach (var target in repResult.NecessaryResultInitializationAsync(this.closureLocals)) { // note: target here methodBody.Add(new AssignmentStatement(target, this.originalResultLocal)); } } #endregion #region Emit normal postconditions SourceContext lastEnsuresSourceContext = default(SourceContext); bool hasLastEnsuresContext = false; bool containsExceptionalPostconditions = false; var ensuresChecks = new StatementList(); foreach (Ensures e in asyncPostconditions) { // Exceptional postconditions are handled separately. if (e is EnsuresExceptional) { containsExceptionalPostconditions = true; continue; } if (IsVoidTask()) break; // something is wrong in the original contract lastEnsuresSourceContext = e.SourceContext; hasLastEnsuresContext = true; // call Contract.RewriterEnsures Method ensMethod = this.parent.runtimeContracts.EnsuresMethod; ExpressionList args = new ExpressionList(); args.Add(e.PostCondition); if (e.UserMessage != null) args.Add(e.UserMessage); else args.Add(Literal.Null); if (e.SourceConditionText != null) { args.Add(e.SourceConditionText); } else { args.Add(Literal.Null); } ensuresChecks.Add(new ExpressionStatement( new MethodCall(new MemberBinding(null, ensMethod), args, NodeType.Call, SystemTypes.Void), e.SourceContext)); } this.parent.cleanUpCodeCoverage.VisitStatementList(ensuresChecks); this.parent.EmitRecursionGuardAroundChecks(this.checkMethod, methodBodyBlock, ensuresChecks); #endregion Normal postconditions #region Exceptional postconditions if (containsExceptionalPostconditions) { // Because async tasks wrap exceptions into Aggregate exceptions, we have to catch AggregateException // and iterate over the internal exceptions of the Aggregate. // We thus emit the following handler: // // catch(AggregateException ae) { // ae.Handle(this.CheckException); // rethrow; // } // // alternatively, if the Task has no Result, we emit // // var ae = t.Exception as AggregateException; // if (ae != null) { // ae.Handle(this.CheckException); // throw ae; // } var aggregateType = AggregateExceptionType.Value; var exnParameter = new Parameter(Identifier.For("e"), SystemTypes.Exception); this.checkExceptionMethod = new Method(this.closureClass, null, this.checkExceptionMethodId, new ParameterList(exnParameter), SystemTypes.Boolean, new Block(new StatementList())); this.checkExceptionMethod.Body.HasLocals = true; checkExceptionMethod.CallingConvention = CallingConventionFlags.HasThis; checkExceptionMethod.Flags |= MethodFlags.Public; this.closureClass.Members.Add(checkExceptionMethod); if (this.IsVoidTask()) { var blockAfterTest = new Block(); methodBody.Add(origBody); methodBody.Add(new Branch(new UnaryExpression(this.newResultLocal, NodeType.LogicalNot), blockAfterTest)); var funcType = Func2Type.Value; funcType = funcType.GetTemplateInstance(this.parent.assemblyBeingRewritten, SystemTypes.Exception, SystemTypes.Boolean); var handleMethod = aggregateType.GetMethod(Identifier.For("Handle"), funcType); var funcLocal = new Local(funcType); var ldftn = new UnaryExpression(new MemberBinding(null, this.checkExceptionMethod), NodeType.Ldftn, CoreSystemTypes.IntPtr); methodBody.Add(new AssignmentStatement(funcLocal, new Construct(new MemberBinding(null, funcType.GetConstructor(SystemTypes.Object, SystemTypes.IntPtr)), new ExpressionList(this.checkMethod.ThisParameter, ldftn)))); methodBody.Add(new ExpressionStatement(new MethodCall(new MemberBinding(this.newResultLocal, handleMethod), new ExpressionList(funcLocal)))); methodBody.Add(new Throw(this.newResultLocal)); methodBody.Add(blockAfterTest); } else { // The tryCatch holds the try block, the catch blocks, and an empty block that is the // target of an unconditional branch for normal execution to go from the try block // around the catch blocks. if (this.checkMethod.ExceptionHandlers == null) this.checkMethod.ExceptionHandlers = new ExceptionHandlerList(); Block afterCatches = new Block(new StatementList()); Block tryCatch = newBodyBlock; Block tryBlock = new Block(new StatementList()); tryBlock.Statements.Add(origBody); tryBlock.Statements.Add(new Branch(null, afterCatches, false, true, true)); // the EH needs to have a pointer to this block so the writer can // calculate the length of the try block. So it should be the *last* // thing in the try body. Block blockAfterTryBody = new Block(null); tryBlock.Statements.Add(blockAfterTryBody); tryCatch.Statements.Add(tryBlock); // The catchBlock contains the catchBody, and then // an empty block that is used in the EH. Block catchBlock = new Block(new StatementList()); Local l = new Local(aggregateType); Throw rethrow = new Throw(); rethrow.NodeType = NodeType.Rethrow; catchBlock.Statements.Add(new AssignmentStatement(l, new Expression(NodeType.Pop))); var funcType = Func2Type.Value; funcType = funcType.GetTemplateInstance(this.parent.assemblyBeingRewritten, SystemTypes.Exception, SystemTypes.Boolean); var handleMethod = aggregateType.GetMethod(Identifier.For("Handle"), funcType); var funcLocal = new Local(funcType); var ldftn = new UnaryExpression(new MemberBinding(null, this.checkExceptionMethod), NodeType.Ldftn, CoreSystemTypes.IntPtr); catchBlock.Statements.Add(new AssignmentStatement(funcLocal, new Construct(new MemberBinding(null, funcType.GetConstructor(SystemTypes.Object, SystemTypes.IntPtr)), new ExpressionList(this.checkMethod.ThisParameter, ldftn)))); catchBlock.Statements.Add(new ExpressionStatement(new MethodCall(new MemberBinding(l, handleMethod), new ExpressionList(funcLocal)))); // Handle method should return if all passes catchBlock.Statements.Add(rethrow); // The last thing in each catch block is an empty block that is the target of // BlockAfterHandlerEnd in each exception handler. // It is used in the writer to determine the length of each catch block // so it should be the last thing added to each catch block. Block blockAfterHandlerEnd = new Block(new StatementList()); catchBlock.Statements.Add(blockAfterHandlerEnd); tryCatch.Statements.Add(catchBlock); // add information to the ExceptionHandlers of this method ExceptionHandler exHandler = new ExceptionHandler(); exHandler.TryStartBlock = origBody; exHandler.BlockAfterTryEnd = blockAfterTryBody; exHandler.HandlerStartBlock = catchBlock; exHandler.BlockAfterHandlerEnd = blockAfterHandlerEnd; exHandler.FilterType = l.Type; exHandler.HandlerType = NodeType.Catch; this.checkMethod.ExceptionHandlers.Add(exHandler); tryCatch.Statements.Add(afterCatches); } EmitCheckExceptionBody(asyncPostconditions); } else // no exceptional post conditions { newBodyBlock.Statements.Add(origBody); } #endregion Exceptional and finally postconditions #region Create a block for the return statement and insert it // this is the block that contains the return statements // it is (supposed to be) the single exit from the method // that way, anything that must always be done can be done // in this block Statement returnStatement; if (this.IsVoidTask()) { returnStatement = new Return(); } else { returnStatement = new Return(this.newResultLocal); } if (hasLastEnsuresContext) { returnStatement.SourceContext = lastEnsuresSourceContext; } Block returnBlock = new Block(new StatementList(1)); returnBlock.Statements.Add(returnStatement); methodBody.Add(returnBlock); #endregion }
private Expression ParseUnaryExpression(TokenSet followers){ if (this.currentToken == Token.EndOfFile) { if (this.returnedEmptyIdentForEOF) return null; else { this.returnedEmptyIdentForEOF = true; return this.scanner.GetIdentifier(); } } Expression expression; switch(this.currentToken){ case Token.Plus: case Token.BitwiseNot: case Token.LogicalNot: case Token.Subtract: case Token.BitwiseAnd: UnaryExpression uexpr = new UnaryExpression(); uexpr.SourceContext = this.scanner.CurrentSourceContext; uexpr.NodeType = Parser.ConvertToUnaryNodeType(this.currentToken); this.GetNextToken(); uexpr.Operand = this.ParseUnaryExpression(followers); if (uexpr.Operand == null) return null; uexpr.SourceContext.EndPos = uexpr.Operand.SourceContext.EndPos; expression = uexpr; break; case Token.Multiply: AddressDereference adref = new AddressDereference(); adref.SourceContext = this.scanner.CurrentSourceContext; adref.ExplicitOperator = AddressDereference.ExplicitOp.Star; this.GetNextToken(); adref.Address = this.ParseUnaryExpression(followers); if (adref.Address == null) return null; adref.SourceContext.EndPos = adref.Address.SourceContext.EndPos; expression = adref; break; case Token.AddOne: case Token.SubtractOne: PrefixExpression prefixExpr = new PrefixExpression(); prefixExpr.SourceContext = this.scanner.CurrentSourceContext; prefixExpr.Operator = Parser.ConvertToBinaryNodeType(this.currentToken); this.GetNextToken(); prefixExpr.Expression = this.ParseUnaryExpression(followers); if (prefixExpr.Expression == null) return null; prefixExpr.SourceContext.EndPos = prefixExpr.Expression.SourceContext.EndPos; expression = prefixExpr; break; case Token.LeftParenthesis: expression = this.ParseCastExpression(followers); break; case Token.LeftBrace: expression = this.ParseBlockExpression(ScannerState.Code, this.scanner.CurrentSourceContext, followers); break; case Token.Exists: case Token.Forall: case Token.Count: case Token.Sum: case Token.Max: case Token.Min: case Token.Product: Quantifier q = new Quantifier(); q.SourceContext = this.scanner.CurrentSourceContext; ScannerState ss = this.scanner.state; Token quantType = this.currentToken; SourceContext sctx = this.scanner.CurrentSourceContext; this.GetNextToken(); if (this.currentToken == Token.Unique){ quantType = this.currentToken; this.GetNextToken(); } // not necessarily a quantifier unless there is an open curly!! // REVIEW: Is that enough of a test? Or do we need to try parsing the comprehension? if (this.currentToken != Token.LeftBrace) { //Restore prior state and reparse as expression this.scanner.endPos = q.SourceContext.StartPos; this.scanner.state = ss; this.currentToken = Token.None; this.GetNextToken(); goto default; } q.QuantifierType = Parser.ConvertToQuantifierType(quantType); this.Skip(Token.LeftBrace); Comprehension c = this.ParseComprehension(followers, sctx); if (c == null) { return null; } q.Comprehension = c; q.SourceContext.EndPos = c.SourceContext.EndPos; expression = q; break; default: expression = this.ParsePrimaryExpression(followers); break; } return expression; }
public virtual Expression VisitUnaryExpression(UnaryExpression unaryExpression) { if (unaryExpression == null) return null; unaryExpression.Operand = this.VisitExpression(unaryExpression.Operand); return unaryExpression; }
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 VisitUnaryExpression(UnaryExpression unaryExpression){ if (unaryExpression == null) return null; if (unaryExpression.NodeType == NodeType.Typeof) this.AbstractSealedUsedAsType = Cci.Error.None; Expression result = base.VisitUnaryExpression(unaryExpression); this.AbstractSealedUsedAsType = Cci.Error.NotAType; return result; }
public override Expression VisitUnaryExpression(UnaryExpression unaryExpression) { if ((unaryExpression.NodeType != NodeType.Sizeof && ((ZingNodeType)unaryExpression.NodeType) != ZingNodeType.Choose) || !(unaryExpression.Operand is MemberBinding)) return base.VisitUnaryExpression(unaryExpression); Debug.Assert(unaryExpression.Operand is MemberBinding); MemberBinding mb = (MemberBinding)unaryExpression.Operand; Debug.Assert(mb.BoundMember is TypeExpression); TypeExpression te = (TypeExpression)mb.BoundMember; if (te.Expression is Identifier) { Identifier id = (Identifier)te.Expression; this.encounteredTypeRefError = false; this.ignoreTypeRefErrors = true; unaryExpression.Operand = this.VisitExpression(unaryExpression.Operand); this.ignoreTypeRefErrors = false; if (encounteredTypeRefError) { // If this didn't resolve to a type, then treat it as an expression and let // the resolver deal with it (or report an error). unaryExpression.Operand = this.VisitExpression(id); NameBinding nb = unaryExpression.Operand as NameBinding; if (nb != null && nb.BoundMembers.Count == 0) { this.HandleTypeExpected(nb.Identifier); return null; } } } return unaryExpression; }
Expression GetConvertFromString(TypeNode targetType, Expression src, bool always) { if (targetType == SystemTypes.String) return src;// nothing to do! if (targetType is EnumNode) { // e.g. return (DayOfWeek)Enum.Parse(typeof(DayOfWeek),"Sunday"); Method method = SystemTypes.Enum.GetMethod(Identifier.For("Parse"), new TypeNode[2]{ SystemTypes.Type, SystemTypes.String}); UnaryExpression typeOfEnum = new UnaryExpression(new MemberBinding(null, targetType), NodeType.Typeof); MethodCall call = new MethodCall(new MemberBinding(new MemberBinding(null, targetType), method), new ExpressionList(new Expression[2]{typeOfEnum, src }), NodeType.Call, SystemTypes.Object); return CastTo(call, targetType); } // See if it has a type converter. Class converterClass = Checker.GetTypeConverter(targetType); if (converterClass != null) { TypeConverter converter = TypeDescriptor.GetConverter(targetType.GetRuntimeType()); if (converter != null) { Type converterType = converter.GetType(); AssemblyNode converterAssembly = AssemblyNode.GetAssembly(converterType.Assembly, cache, false, true); converterClass = converterAssembly.GetType(Identifier.For(converterType.Namespace), Identifier.For(converterType.Name)) as Class; Expression e = tempChecker.GetConverterFromString(converter, converterClass, SystemTypes.String, src, SystemTypes.Object); if (e != null) { //Do I need to add namespace and assembly reference for type converter? return CastTo(e, targetType); } } } if (always) { // e.g. return PointArray.Parse("10,20 30,40 50,60"); Method method = targetType.GetImplicitCoercionFromMethod(SystemTypes.String); if (method == null) { method = targetType.GetMethod(Identifier.For("Parse"), new TypeNode[1]{ SystemTypes.String}); } if (method != null) { MemberBinding typeBinding = new MemberBinding(null, targetType); MethodCall call = new MethodCall(new MemberBinding(typeBinding, method), new ExpressionList(new Expression[1]{ src }), NodeType.Call, targetType ); return call; } } return null; }
private UnaryExpression VisitChoose(UnaryExpression expr) { return (UnaryExpression)this.VisitUnaryExpression(expr); }
private UnaryExpression VisitChoose(UnaryExpression expr) { expr.Operand = this.VisitExpression(expr.Operand); if (expr.Operand.Type.FullName == "Boolean") { expr.Type = SystemTypes.Boolean; } else if (expr.Operand.Type == SystemTypes.Type) { Literal typeExpr = expr.Operand as Literal; Debug.Assert(typeExpr != null); if (typeExpr.Value is EnumNode) expr.Type = (TypeNode)typeExpr.Value; else if (typeExpr.Value is Range) expr.Type = SystemTypes.Int32; else { this.HandleError(expr.Operand, Error.InvalidChoiceType); return null; } } else { // We have a variable - must be an array or set if (expr.Operand.Type is ZArray) expr.Type = ((ZArray)expr.Operand.Type).ElementType; else if (expr.Operand.Type is Set) expr.Type = ((Set)expr.Operand.Type).SetType; else { this.HandleError(expr.Operand, Error.InvalidChoiceExpr); return null; } } return expr; }
public override Expression VisitUnaryExpression(UnaryExpression unaryExpression) { if (unaryExpression == null) return null; unaryExpression = (UnaryExpression)base.VisitUnaryExpression((UnaryExpression)unaryExpression.Clone()); return unaryExpression; }
private UnaryExpression VisitChoose(UnaryExpression expr) { Write("choose"); this.VisitParenthesizedExpression(expr.Operand); return expr; }
public EventingVisitor(Action<UnaryExpression> visitUnaryExpression) { VisitedUnaryExpression += visitUnaryExpression; } public event Action<UnaryExpression> VisitedUnaryExpression; public override Expression VisitUnaryExpression(UnaryExpression unaryExpression) { if (VisitedUnaryExpression != null) VisitedUnaryExpression(unaryExpression); return base.VisitUnaryExpression(unaryExpression); }