Ejemplo n.º 1
0
        public void SimpleForAllWithTrigger()
        {
            var builder  = GetSimpleBuilder();
            var freeVarX = GetVariable("x", BasicType.Int);
            var xid      = new IdentifierExpr(Token.NoToken, freeVarX);

            var fb       = new FunctionCallBuilder();
            var funcCall = fb.CreateUninterpretedFunctionCall("f", BPLType.Int, new List <BPLType>()
            {
                BPLType.Int
            });
            var body = builder.Gt(builder.UFC(funcCall, xid), xid);

            // Single trigger
            var triggers = new Microsoft.Boogie.Trigger(Token.NoToken,
                                                        /*positive=*/ true,
                                                        new List <Expr>()
            {
                builder.UFC(funcCall, xid)
            }, null);

            var result = builder.ForAll(new List <Variable>()
            {
                freeVarX
            }, body, triggers);

            Assert.AreEqual("(forall x: int :: { f(x) } f(x) > x)", result.ToString());
            CheckIsBoolType(result);
        }
Ejemplo n.º 2
0
 // Note: if the trigger is null, makes a forall without any triggers
 static Bpl.Expr BplForall(IEnumerable <Bpl.Variable> args_in, Bpl.Trigger trg, Bpl.Expr body)
 {
     if (trg == null)
     {
         return(BplForall(args_in, body)); // NO_TRIGGER
     }
     else
     {
         var args = new List <Bpl.Variable>(args_in);
         if (args.Count == 0)
         {
             return(body);
         }
         else
         {
             return(new Bpl.ForallExpr(body.tok, args, trg, body));
         }
     }
 }
Ejemplo n.º 3
0
 public ExistsExpr(IToken tok, List<Variable> dummies, Trigger triggers, Expr body, bool immutable=false)
   : base(tok, new List<TypeVariable>(), dummies, null, triggers, body, immutable) {
   Contract.Requires(body != null);
   Contract.Requires(dummies != null);
   Contract.Requires(tok != null);
   Contract.Requires(dummies.Count > 0);
 }
Ejemplo n.º 4
0
 public ExistsExpr(IToken/*!*/ tok, List<TypeVariable>/*!*/ typeParams, List<Variable>/*!*/ dummies,
                   QKeyValue kv, Trigger triggers, Expr/*!*/ body, bool immutable=false)
   : base(tok, typeParams, dummies, kv, triggers, body, immutable) {
   Contract.Requires(tok != null);
   Contract.Requires(typeParams != null);
   Contract.Requires(dummies != null);
   Contract.Requires(body != null);
   Contract.Requires(dummies.Count + typeParams.Count > 0);
 }
Ejemplo n.º 5
0
 public void AddLast(Trigger other) {
   Trigger current = this;
   while (current.Next != null) {
     current = current.Next;
   }
   current.Next = other;
 }
Ejemplo n.º 6
0
 public ForallExpr(IToken tok, List<Variable> dummies, Trigger triggers, Expr body)
     : base(tok, new List<TypeVariable>(), dummies, null, triggers, body)
 {
     Contract.Requires(body != null);
       Contract.Requires(dummies != null);
       Contract.Requires(tok != null);
       Contract.Requires(dummies.Count > 0);
 }
Ejemplo n.º 7
0
 public override QuantifierExpr VisitQuantifierExpr(QuantifierExpr node)
 {
   currentTrigger = node.Triggers;
   while (currentTrigger != null)
   {
     foreach (var e in currentTrigger.Tr)
     {
       VisitExpr(e);
     }
     currentTrigger = currentTrigger.Next;
   }
   return base.VisitQuantifierExpr(node);
 }
Ejemplo n.º 8
0
 public override Trigger VisitTrigger(Trigger node)
 {
     Contract.Ensures(Contract.Result<Trigger>() == node);
     Trigger origNext = node.Next;
     if (origNext != null)
     {
         this.VisitTrigger(origNext);
     }
     this.VisitExprSeq(node.Tr.ToList());
     return node;
 }
Ejemplo n.º 9
0
	void QuantifierBody(IToken/*!*/ q, out List<TypeVariable>/*!*/ typeParams, out List<Variable>/*!*/ ds,
out QKeyValue kv, out Trigger trig, out Expr/*!*/ body) {
		Contract.Requires(q != null); Contract.Ensures(Contract.ValueAtReturn(out typeParams) != null); Contract.Ensures(Contract.ValueAtReturn(out ds) != null); Contract.Ensures(Contract.ValueAtReturn(out body) != null);
		trig = null; typeParams = new List<TypeVariable> ();
		IToken/*!*/ tok;
		kv = null;
		ds = new List<Variable> ();
		
		if (la.kind == 20) {
			TypeParams(out tok, out typeParams);
			if (la.kind == 1 || la.kind == 28) {
				BoundVars(q, out ds);
			}
		} else if (la.kind == 1 || la.kind == 28) {
			BoundVars(q, out ds);
		} else SynErr(129);
		QSep();
		while (la.kind == 28) {
			AttributeOrTrigger(ref kv, ref trig);
		}
		Expression(out body);
	}
Ejemplo n.º 10
0
 static Bpl.Expr BplForall(Bpl.Variable arg, Bpl.Trigger trg, Bpl.Expr body)
 {
     return(BplForall(Singleton(arg), trg, body));
 }
Ejemplo n.º 11
0
      public override Expr VisitLambdaExpr(LambdaExpr lambda) {
        var baseResult = base.VisitLambdaExpr(lambda);
        lambda = baseResult as LambdaExpr;
        if (lambda == null) {
          return baseResult;  // apparently, the base visitor already turned the lambda into something else
        }

        // We start by getting rid of any use of "old" inside the lambda.  This is done as follows.
        // For each variable "g" occurring inside lambda as "old(... g ...)", create a new name "og".
        // Replace each old occurrence of "g" with "og", removing the enclosing "old" wrappers.
        var oldFinder = new OldFinder();
        oldFinder.Visit(lambda);
        var oldSubst = new Dictionary<Variable, Expr>();  // g -> g0
        var callOldMapping = new Dictionary<Variable, Expr>();  // g0 -> old(g)
        foreach (var v in oldFinder.FreeOldVars) {
          var g = v as GlobalVariable;
          if (g != null) {
            var g0 = new GlobalVariable(g.tok, new TypedIdent(g.tok, g.TypedIdent.Name + "@old", g.TypedIdent.Type));
            oldSubst.Add(g, new IdentifierExpr(g0.tok, g0));
            callOldMapping.Add(g0, new OldExpr(g0.tok, new IdentifierExpr(g.tok, g)));
          }
        }
        var lambdaBody = Substituter.ApplyReplacingOldExprs(
          Substituter.SubstitutionFromHashtable(new Dictionary<Variable,Expr>()),
          Substituter.SubstitutionFromHashtable(oldSubst),
          lambda.Body);
        var lambdaAttrs = Substituter.ApplyReplacingOldExprs(
          Substituter.SubstitutionFromHashtable(new Dictionary<Variable, Expr>()),
          Substituter.SubstitutionFromHashtable(oldSubst),
          lambda.Attributes);

        if (0 < CommandLineOptions.Clo.VerifySnapshots && QKeyValue.FindStringAttribute(lambdaAttrs, "checksum") == null)
        {
          // Attach a dummy checksum to avoid issues in the dependency analysis.
          var checksumAttr = new QKeyValue(lambda.tok, "checksum", new List<object> { "lambda expression" }, null);
          if (lambdaAttrs == null)
          {
            lambdaAttrs = checksumAttr;
          }
          else
          {
            lambdaAttrs.AddLast(checksumAttr);
          }
        }

        // this is ugly, the output will depend on hashing order
        var subst = new Dictionary<Variable, Expr>();
        var substFnAttrs = new Dictionary<Variable, Expr>();
        var formals = new List<Variable>();
        var callArgs = new List<Expr>();
        var axCallArgs = new List<Expr>();
        var dummies = new List<Variable>(lambda.Dummies);
        var freeTypeVars = new List<TypeVariable>();
        var fnTypeVarActuals = new List<Type/*!*/>();
        var freshTypeVars = new List<TypeVariable>();  // these are only used in the lambda@n function's definition

        // compute the free variables of the lambda expression, but with lambdaBody instead of lambda.Body
        Set freeVars = new Set();
        BinderExpr.ComputeBinderFreeVariables(lambda.TypeParameters, lambda.Dummies, lambdaBody, lambdaAttrs, freeVars);

        foreach (object o in freeVars) {
          // 'o' is either a Variable or a TypeVariable.
          if (o is Variable) {
            var v = o as Variable;
            var ti = new TypedIdent(v.TypedIdent.tok, v.TypedIdent.Name, v.TypedIdent.Type);
            var f = new Formal(v.tok, ti, true);
            formals.Add(f);
            substFnAttrs.Add(v, new IdentifierExpr(f.tok, f));
            var b = new BoundVariable(v.tok, ti);
            dummies.Add(b);
            if (callOldMapping.ContainsKey(v)) {
              callArgs.Add(callOldMapping[v]);
            } else {
              callArgs.Add(new IdentifierExpr(v.tok, v));
            }
            Expr id = new IdentifierExpr(b.tok, b);
            subst.Add(v, id);
            axCallArgs.Add(id);
          } else {
            var tv = (TypeVariable)o;
            freeTypeVars.Add(tv);
            fnTypeVarActuals.Add(tv);
            freshTypeVars.Add(new TypeVariable(tv.tok, tv.Name));
          }
        }

        var sw = new System.IO.StringWriter();
        var wr = new TokenTextWriter(sw, true);
        lambda.Emit(wr);
        string lam_str = sw.ToString();

        FunctionCall fcall;
        IToken tok = lambda.tok;
        Formal res = new Formal(tok, new TypedIdent(tok, TypedIdent.NoName, cce.NonNull(lambda.Type)), false);

        if (liftedLambdas.TryGetValue(lambda, out fcall)) {
          if (CommandLineOptions.Clo.TraceVerify) {
            Console.WriteLine("Old lambda: {0}", lam_str);
          }
        } else {
          if (CommandLineOptions.Clo.TraceVerify) {
            Console.WriteLine("New lambda: {0}", lam_str);
          }
          Function fn = new Function(tok, FreshLambdaFunctionName(), freshTypeVars, formals, res, "auto-generated lambda function",
            Substituter.Apply(Substituter.SubstitutionFromHashtable(substFnAttrs), lambdaAttrs));
          fn.OriginalLambdaExprAsString = lam_str;

          fcall = new FunctionCall(new IdentifierExpr(tok, fn.Name));
          fcall.Func = fn;  // resolve here
          liftedLambdas[lambda] = fcall;

          List<Expr/*!*/> selectArgs = new List<Expr/*!*/>();
          foreach (Variable/*!*/ v in lambda.Dummies) {
            Contract.Assert(v != null);
            selectArgs.Add(new IdentifierExpr(v.tok, v));
          }
          NAryExpr axcall = new NAryExpr(tok, fcall, axCallArgs);
          axcall.Type = res.TypedIdent.Type;
          axcall.TypeParameters = SimpleTypeParamInstantiation.From(freeTypeVars, fnTypeVarActuals);
          NAryExpr select = Expr.Select(axcall, selectArgs);
          select.Type = lambdaBody.Type;
          List<Type/*!*/> selectTypeParamActuals = new List<Type/*!*/>();
          List<TypeVariable> forallTypeVariables = new List<TypeVariable>();
          foreach (TypeVariable/*!*/ tp in lambda.TypeParameters) {
            Contract.Assert(tp != null);
            selectTypeParamActuals.Add(tp);
            forallTypeVariables.Add(tp);
          }
          forallTypeVariables.AddRange(freeTypeVars);
          select.TypeParameters = SimpleTypeParamInstantiation.From(lambda.TypeParameters, selectTypeParamActuals);

          Expr bb = Substituter.Apply(Substituter.SubstitutionFromHashtable(subst), lambdaBody);
          NAryExpr body = Expr.Eq(select, bb);
          body.Type = Type.Bool;
          body.TypeParameters = SimpleTypeParamInstantiation.EMPTY;
          Trigger trig = new Trigger(select.tok, true, new List<Expr> { select });

          lambdaFunctions.Add(fn);
          lambdaAxioms.Add(new ForallExpr(tok, forallTypeVariables, dummies,
            Substituter.Apply(Substituter.SubstitutionFromHashtable(subst), lambdaAttrs),
            trig, body));
        }

        NAryExpr call = new NAryExpr(tok, fcall, callArgs);
        call.Type = res.TypedIdent.Type;
        call.TypeParameters = SimpleTypeParamInstantiation.From(freeTypeVars, fnTypeVarActuals);

        return call;
      }
Ejemplo n.º 12
0
            public override Absy Visit(Absy node)
            {
                //Contract.Requires(node != null);
                Contract.Ensures(Contract.Result<Absy>() != null);
                node = base.Visit(node);

                LambdaExpr lambda = node as LambdaExpr;
                if (lambda != null) {
                  IToken/*!*/ tok = lambda.tok;
                  Contract.Assert(tok != null);

                  Set freeVars = new Set();
                  lambda.ComputeFreeVariables(freeVars);
                  // this is ugly, the output will depend on hashing order
                  Dictionary<Variable, Expr> subst = new Dictionary<Variable, Expr>();
                  List<Variable> formals = new List<Variable>();
                  List<Expr> callArgs = new List<Expr>();
                  List<Expr> axCallArgs = new List<Expr>();
                  List<Variable> dummies = new List<Variable>(lambda.Dummies);
                  List<TypeVariable> freeTypeVars = new List<TypeVariable>();
                  List<Type/*!*/> fnTypeVarActuals = new List<Type/*!*/>();
                  List<TypeVariable> freshTypeVars = new List<TypeVariable>();  // these are only used in the lambda@n function's definition
                  foreach (object o in freeVars) {
                // 'o' is either a Variable or a TypeVariable.  Since the lambda desugaring happens only
                // at the outermost level of a program (where there are no mutable variables) and, for
                // procedure bodies, after the statements have been passified (when mutable variables have
                // been replaced by immutable incarnations), we are interested only in BoundVar's and
                // TypeVariable's.
                BoundVariable v = o as BoundVariable;
                if (v != null) {
                  TypedIdent ti = new TypedIdent(v.TypedIdent.tok, v.TypedIdent.Name, v.TypedIdent.Type);
                  Formal f = new Formal(v.tok, ti, true);
                  formals.Add(f);
                  BoundVariable b = new BoundVariable(v.tok, ti);
                  dummies.Add(b);
                  callArgs.Add(new IdentifierExpr(v.tok, v));
                  Expr/*!*/ id = new IdentifierExpr(f.tok, b);
                  Contract.Assert(id != null);
                  subst.Add(v, id);
                  axCallArgs.Add(id);
                } else if (o is TypeVariable) {
                  TypeVariable tv = (TypeVariable)o;
                  freeTypeVars.Add(tv);
                  fnTypeVarActuals.Add(tv);
                  freshTypeVars.Add(new TypeVariable(tv.tok, tv.Name));
                }
                  }

                  Formal res = new Formal(tok, new TypedIdent(tok, TypedIdent.NoName, cce.NonNull(lambda.Type)), false);
                  Function fn = new Function(tok, "lambda@" + lambdaid++, freshTypeVars, formals, res, "auto-generated lambda function", lambda.Attributes);
                  lambdaFunctions.Add(fn);

                  FunctionCall fcall = new FunctionCall(new IdentifierExpr(tok, fn.Name));
                  fcall.Func = fn;  // resolve here

                  List<Expr/*!*/> selectArgs = new List<Expr/*!*/>();
                  foreach (Variable/*!*/ v in lambda.Dummies) {
                Contract.Assert(v != null);
                selectArgs.Add(new IdentifierExpr(v.tok, v));
                  }
                  NAryExpr axcall = new NAryExpr(tok, fcall, axCallArgs);
                  axcall.Type = res.TypedIdent.Type;
                  axcall.TypeParameters = SimpleTypeParamInstantiation.From(freeTypeVars, fnTypeVarActuals);
                  NAryExpr select = Expr.Select(axcall, selectArgs);
                  select.Type = lambda.Body.Type;
                  List<Type/*!*/> selectTypeParamActuals = new List<Type/*!*/>();
                  List<TypeVariable> forallTypeVariables = new List<TypeVariable>();
                  foreach (TypeVariable/*!*/ tp in lambda.TypeParameters) {
                Contract.Assert(tp != null);
                selectTypeParamActuals.Add(tp);
                forallTypeVariables.Add(tp);
                  }
                  forallTypeVariables.AddRange(freeTypeVars);
                  select.TypeParameters = SimpleTypeParamInstantiation.From(lambda.TypeParameters, selectTypeParamActuals);

                  Expr bb = Substituter.Apply(Substituter.SubstitutionFromHashtable(subst), lambda.Body);
                  NAryExpr body = Expr.Eq(select, bb);
                  body.Type = Type.Bool;
                  body.TypeParameters = SimpleTypeParamInstantiation.EMPTY;
                  Trigger trig = new Trigger(select.tok, true, new List<Expr> { select });
                  lambdaAxioms.Add(new ForallExpr(tok, forallTypeVariables, dummies, lambda.Attributes, trig, body));

                  NAryExpr call = new NAryExpr(tok, fcall, callArgs);
                  call.Type = res.TypedIdent.Type;
                  call.TypeParameters = SimpleTypeParamInstantiation.From(freeTypeVars, fnTypeVarActuals);

                  return call;
                }

                return node;
            }
Ejemplo n.º 13
0
        public static void ComputeBinderFreeVariables(List <TypeVariable> typeParameters, List <Variable> dummies, Expr body, Trigger triggers, QKeyValue attributes, Set freeVars)
        {
            Contract.Requires(dummies != null);
            Contract.Requires(body != null);

            foreach (var v in dummies)
            {
                Contract.Assert(v != null);
                Contract.Assert(!freeVars[v]);
            }
            body.ComputeFreeVariables(freeVars);
            for (var trig = triggers; trig != null; trig = trig.Next)
            {
                foreach (var e in trig.Tr)
                {
                    e.ComputeFreeVariables(freeVars);
                }
            }
            for (var a = attributes; a != null; a = a.Next)
            {
                foreach (var o in a.Params)
                {
                    var e = o as Expr;
                    if (e != null)
                    {
                        e.ComputeFreeVariables(freeVars);
                    }
                }
            }
            foreach (var v in dummies)
            {
                freeVars.AddRange(v.TypedIdent.Type.FreeVariables);
            }
            freeVars.RemoveRange(dummies);
            freeVars.RemoveRange(typeParameters);
        }
Ejemplo n.º 14
0
 public Trigger(IToken/*!*/ tok, bool pos, List<Expr>/*!*/ tr, Trigger next)
     : base(tok)
 {
     Contract.Requires(tok != null);
       Contract.Requires(tr != null);
       Contract.Requires(1 <= tr.Count);
       Contract.Requires(pos || tr.Count == 1);
       this.Pos = pos;
       this.Tr = tr;
       this.Next = next;
 }
Ejemplo n.º 15
0
    public QuantifierExpr(IToken/*!*/ tok, List<TypeVariable>/*!*/ typeParameters,
                          List<Variable>/*!*/ dummies, QKeyValue kv, Trigger triggers, Expr/*!*/ body, bool immutable)
      : base(tok, typeParameters, dummies, kv, body, immutable) {
      Contract.Requires(tok != null);
      Contract.Requires(typeParameters != null);
      Contract.Requires(dummies != null);
      Contract.Requires(body != null);
      Contract.Requires(dummies.Count + typeParameters.Count > 0);

      Contract.Assert((this is ForallExpr) || (this is ExistsExpr));

      Triggers = triggers;
      SkolemId = GetNextSkolemId();
    }
Ejemplo n.º 16
0
 // if the user says ( forall x :: forall y ::  ... ) and specifies *no* triggers, we transform it to
 // (forall x, y ::  ... ) which may help the prover to pick trigger terms
 //
 // (Note: there used to be a different criterion here, which allowed merging when triggers were specified, which could cause prover errors due to resulting unbound variables in the triggers)
 private void MergeAdjecentQuantifier() {
   QuantifierExpr qbody = Body as QuantifierExpr;
   if (!(qbody != null && (qbody is ForallExpr) == (this is ForallExpr) && Triggers == null)) {
     return;
   }
   qbody.MergeAdjecentQuantifier();
   if (this.Triggers != null || qbody.Triggers != null) {
     return;
   }
   Body = qbody.Body;
   TypeParameters.AddRange(qbody.TypeParameters);
   Dummies.AddRange(qbody.Dummies);
   Triggers = qbody.Triggers;
   if (qbody.Attributes != null) {
     if (Attributes == null) {
       Attributes = qbody.Attributes;
     } else {
       QKeyValue p = Attributes;
       while (p.Next != null) {
         p = p.Next;
       }
       p.Next = qbody.Attributes;
     }
   }
 }
Ejemplo n.º 17
0
 static Bpl.Expr BplForall(Bpl.IToken tok, List <Bpl.TypeVariable> typeParams,
                           List <Bpl.Variable> formals, Bpl.QKeyValue kv, Bpl.Trigger triggers, Bpl.Expr body, bool immutable = false)
 {
     return((typeParams.Count == 0 && formals.Count == 0) ? body
 : new Bpl.ForallExpr(tok, typeParams, formals, kv, triggers, body, immutable));
 }
Ejemplo n.º 18
0
	void AttributeOrTrigger(ref QKeyValue kv, ref Trigger trig) {
		IToken/*!*/ tok;  Expr/*!*/ e;  List<Expr>/*!*/ es;
		string key;
		List<object/*!*/> parameters;  object/*!*/ param;
		
		Expect(28);
		tok = t; 
		if (la.kind == 12) {
			Get();
			Expect(1);
			key = t.val;  parameters = new List<object/*!*/>(); 
			if (StartOf(16)) {
				AttributeParameter(out param);
				parameters.Add(param); 
				while (la.kind == 13) {
					Get();
					AttributeParameter(out param);
					parameters.Add(param); 
				}
			}
			if (key == "nopats") {
			 if (parameters.Count == 1 && parameters[0] is Expr) {
			   e = (Expr)parameters[0];
			   if(trig==null){
			     trig = new Trigger(tok, false, new List<Expr> { e }, null);
			   } else {
			     trig.AddLast(new Trigger(tok, false, new List<Expr> { e }, null));
			   }
			 } else {
			   this.SemErr("the 'nopats' quantifier attribute expects a string-literal parameter");
			 }
			} else {
			 if (kv==null) {
			   kv = new QKeyValue(tok, key, parameters, null);
			 } else {
			   kv.AddLast(new QKeyValue(tok, key, parameters, null));
			 }
			}
			
		} else if (StartOf(9)) {
			Expression(out e);
			es = new List<Expr> { e }; 
			while (la.kind == 13) {
				Get();
				Expression(out e);
				es.Add(e); 
			}
			if (trig==null) {
			 trig = new Trigger(tok, true, es, null);
			} else {
			 trig.AddLast(new Trigger(tok, true, es, null));
			}
			
		} else SynErr(133);
		Expect(29);
	}
Ejemplo n.º 19
0
 public virtual Trigger VisitTrigger(Trigger node)
 {
     Contract.Requires(node != null);
       Contract.Ensures(Contract.Result<Trigger>() != null);
       Trigger origNext = node.Next;
       if (origNext != null) {
     Trigger newNext = this.VisitTrigger(origNext);
     if (newNext != origNext) {
       node = new Trigger(node.tok, node.Pos, node.Tr);  // note: this creates sharing between the old and new Tr sequence
       node.Next = newNext;
     }
       }
       node.Tr = this.VisitExprSeq(node.Tr);
       return node;
 }
Ejemplo n.º 20
0
 public virtual Trigger VisitTrigger(Trigger node) {
   Contract.Requires(node != null);
   Contract.Ensures(Contract.Result<Trigger>() != null);
   Trigger origNext = node.Next;
   if (origNext != null) {
     Trigger newNext = this.VisitTrigger(origNext);
     if (newNext != origNext) {
       node = new Trigger(node.tok, node.Pos, node.Tr.ToList());
       node.Next = newNext;
     }
   }
   node.Tr = this.VisitExprSeq(node.Tr.ToList());
   return node;
 }
Ejemplo n.º 21
0
 public Trigger(IToken/*!*/ tok, bool pos, IEnumerable<Expr>/*!*/ tr, Trigger next = null)
   : base(tok) {
   Contract.Requires(tok != null);
   Contract.Requires(tr != null);
   Contract.Requires(tr.Count() >= 1);
   Contract.Requires(pos || tr.Count() == 1);
   this.Pos = pos;
   this.Tr = new List<Expr>(tr);
   this.Next = next;
 }
Ejemplo n.º 22
0
 public override Trigger VisitTrigger(Trigger node) {
   //Contract.Requires(node != null);
   Contract.Ensures(Contract.Result<Trigger>() != null);
   return base.VisitTrigger((Trigger)node.Clone());
 }
Ejemplo n.º 23
0
 public override Trigger VisitTrigger(Trigger node)
 {
     //Contract.Requires(node != null);
     Contract.Ensures(Contract.Result <Trigger>() != null);
     return(base.VisitTrigger((Trigger)node.Clone()));
 }