/*----------------------------------------------------------------------------- // // Copyright (C) Microsoft Corporation. All Rights Reserved. // //-----------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------- // Dafny // Rustan Leino, first created 25 January 2008 //--------------------------------------------------------------------------*/ using System.Collections.Generic; using System.Numerics; using Microsoft.Boogie; using System.IO; using System.Text; COMPILER Dafny /*--------------------------------------------------------------------------*/ readonly Expression/*!*/ dummyExpr; readonly AssignmentRhs/*!*/ dummyRhs; readonly FrameExpression/*!*/ dummyFrameExpr; readonly Statement/*!*/ dummyStmt; readonly Attributes.Argument/*!*/ dummyAttrArg; readonly ModuleDecl theModule; readonly BuiltIns theBuiltIns; int anonymousIds = 0; struct MemberModifiers { public bool IsGhost; public bool IsStatic; } // helper routine for parsing call statements /// /// Parses top-level things (modules, classes, datatypes, class members) from "filename" /// and appends them in appropriate form to "module". /// Returns the number of parsing errors encountered. /// Note: first initialize the Scanner. /// public static int Parse (string/*!*/ filename, ModuleDecl module, BuiltIns builtIns) /* throws System.IO.IOException */ { Contract.Requires(filename != null); Contract.Requires(module != null); string s; if (filename == "stdin.dfy") { s = Microsoft.Boogie.ParserHelper.Fill(System.Console.In, new List()); return Parse(s, filename, module, builtIns); } else { using (System.IO.StreamReader reader = new System.IO.StreamReader(filename)) { s = Microsoft.Boogie.ParserHelper.Fill(reader, new List()); return Parse(s, filename, module, builtIns); } } } /// /// Parses top-level things (modules, classes, datatypes, class members) /// and appends them in appropriate form to "module". /// Returns the number of parsing errors encountered. /// Note: first initialize the Scanner. /// public static int Parse (string/*!*/ s, string/*!*/ filename, ModuleDecl module, BuiltIns builtIns) { Contract.Requires(s != null); Contract.Requires(filename != null); Contract.Requires(module != null); Errors errors = new Errors(); return Parse(s, filename, module, builtIns, errors); } /// /// Parses top-level things (modules, classes, datatypes, class members) /// and appends them in appropriate form to "module". /// Returns the number of parsing errors encountered. /// Note: first initialize the Scanner with the given Errors sink. /// public static int Parse (string/*!*/ s, string/*!*/ filename, ModuleDecl module, BuiltIns builtIns, Errors/*!*/ errors) { Contract.Requires(s != null); Contract.Requires(filename != null); Contract.Requires(module != null); Contract.Requires(errors != null); byte[]/*!*/ buffer = cce.NonNull( UTF8Encoding.Default.GetBytes(s)); MemoryStream ms = new MemoryStream(buffer,false); Scanner scanner = new Scanner(ms, errors, filename); Parser parser = new Parser(scanner, errors, module, builtIns); parser.Parse(); return parser.errors.count; } public Parser(Scanner/*!*/ scanner, Errors/*!*/ errors, ModuleDecl module, BuiltIns builtIns) : this(scanner, errors) // the real work { // initialize readonly fields dummyExpr = new LiteralExpr(Token.NoToken); dummyRhs = new ExprRhs(dummyExpr, null); dummyFrameExpr = new FrameExpression(dummyExpr.tok, dummyExpr, null); dummyStmt = new ReturnStmt(Token.NoToken, null); dummyAttrArg = new Attributes.Argument(Token.NoToken, "dummyAttrArg"); theModule = module; theBuiltIns = builtIns; } bool IsAttribute() { Token x = scanner.Peek(); return la.kind == _lbrace && x.kind == _colon; } /*--------------------------------------------------------------------------*/ CHARACTERS letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz". digit = "0123456789". posDigit = "123456789". special = "'_?\\". glyph = "`~!@#$%^&*()-_=+[{]}|;:',<.>/?\\". cr = '\r'. lf = '\n'. tab = '\t'. space = ' '. quote = '"'. nondigit = letter + special. idchar = nondigit + digit. nonquote = letter + digit + space + glyph. /* exclude the characters in 'array' */ nondigitMinusA = nondigit - 'a'. idcharMinusA = idchar - 'a'. idcharMinusR = idchar - 'r'. idcharMinusY = idchar - 'y'. idcharMinusPosDigit = idchar - posDigit. /*------------------------------------------------------------------------*/ TOKENS ident = nondigitMinusA {idchar} /* if char 0 is not an 'a', then anything else is fine */ | 'a' [ idcharMinusR {idchar} ] /* if char 0 is an 'a', then either there is no char 1 or char 1 is not an 'r' */ | 'a' 'r' [ idcharMinusR {idchar} ] /* etc. */ | 'a' 'r' 'r' [ idcharMinusA {idchar} ] | 'a' 'r' 'r' 'a' [ idcharMinusY {idchar} ] | 'a' 'r' 'r' 'a' 'y' idcharMinusPosDigit {idchar} | 'a' 'r' 'r' 'a' 'y' posDigit {idchar} nondigit {idchar}. digits = digit {digit}. arrayToken = 'a' 'r' 'r' 'a' 'y' [posDigit {digit}]. string = quote {nonquote} quote. colon = ':'. lbrace = '{'. rbrace = '}'. COMMENTS FROM "/*" TO "*/" NESTED COMMENTS FROM "//" TO lf IGNORE cr + lf + tab /*------------------------------------------------------------------------*/ PRODUCTIONS Dafny = (. ClassDecl/*!*/ c; DatatypeDecl/*!*/ dt; ArbitraryTypeDecl at; List membersDefaultClass = new List(); ModuleDecl submodule; // to support multiple files, create a default module only if theModule is null DefaultModuleDecl defaultModule = (DefaultModuleDecl)((LiteralModuleDecl)theModule).ModuleDef; // theModule should be a DefaultModuleDecl (actually, the singular DefaultModuleDecl) Contract.Assert(defaultModule != null); bool isGhost; .) { (. isGhost = false; .) [ "ghost" (. isGhost = true; .) ] ( SubModuleDecl (. defaultModule.TopLevelDecls.Add(submodule); .) | (. if (isGhost) { SemErr(t, "a class is not allowed to be declared as 'ghost'"); } .) ClassDecl (. defaultModule.TopLevelDecls.Add(c); .) | (. if (isGhost) { SemErr(t, "a datatype/codatatype is not allowed to be declared as 'ghost'"); } .) DatatypeDecl (. defaultModule.TopLevelDecls.Add(dt); .) | (. if (isGhost) { SemErr(t, "a type is not allowed to be declared as 'ghost'"); } .) ArbitraryTypeDecl (. defaultModule.TopLevelDecls.Add(at); .) | ClassMemberDecl ) } (. // find the default class in the default module, then append membersDefaultClass to its member list DefaultClassDecl defaultClass = null; foreach (TopLevelDecl topleveldecl in defaultModule.TopLevelDecls) { defaultClass = topleveldecl as DefaultClassDecl; if (defaultClass != null) { defaultClass.Members.AddRange(membersDefaultClass); break; } } if (defaultClass == null) { // create the default class here, because it wasn't found defaultClass = new DefaultClassDecl(defaultModule, membersDefaultClass); defaultModule.TopLevelDecls.Add(defaultClass); } .) EOF . SubModuleDecl = (. ClassDecl/*!*/ c; DatatypeDecl/*!*/ dt; ArbitraryTypeDecl at; Attributes attrs = null; IToken/*!*/ id; List namedModuleDefaultClassMembers = new List();; List idRefined = null, idPath = null, idAssignment = null; bool isGhost = false; ModuleDefinition module; ModuleDecl sm; submodule = null; // appease compiler bool opened = false; .) ( "module" { Attribute } NoUSIdent [ "refines" QualifiedName ] (. module = new ModuleDefinition(id, id.val, isOverallModuleGhost, false, idRefined == null ? null : idRefined, attrs, false); .) "{" (. module.BodyStartTok = t; .) { (. isGhost = false; .) [ "ghost" (. isGhost = true; .) ] ( SubModuleDecl (. module.TopLevelDecls.Add(sm); .) | (. if (isGhost) { SemErr(t, "a class is not allowed to be declared as 'ghost'"); } .) ClassDecl (. module.TopLevelDecls.Add(c); .) | (. if (isGhost) { SemErr(t, "a datatype/codatatype is not allowed to be declared as 'ghost'"); } .) DatatypeDecl (. module.TopLevelDecls.Add(dt); .) | (. if (isGhost) { SemErr(t, "a type is not allowed to be declared as 'ghost'"); } .) ArbitraryTypeDecl (. module.TopLevelDecls.Add(at); .) | ClassMemberDecl ) } "}" (. module.BodyEndTok = t; module.TopLevelDecls.Add(new DefaultClassDecl(module, namedModuleDefaultClassMembers)); submodule = new LiteralModuleDecl(module, parent); .) | "import" ["opened" (.opened = true;.)] ( NoUSIdent ( "=" QualifiedName ";" (. submodule = new AliasModuleDecl(idPath, id, parent, opened); .) | ";" (. idPath = new List(); idPath.Add(id); submodule = new AliasModuleDecl(idPath, id, parent, opened); .) | "as" QualifiedName ["default" QualifiedName ] ";" (.submodule = new AbstractModuleDecl(idPath, id, parent, idAssignment, opened); .) ) ) ) . QualifiedName<.out List ids.> = (. IToken id; ids = new List(); .) Ident (. ids.Add(id); .) { "." Ident (. ids.Add(id); .) } . ClassDecl = (. Contract.Requires(module != null); Contract.Ensures(Contract.ValueAtReturn(out c) != null); IToken/*!*/ id; Attributes attrs = null; List typeArgs = new List(); List members = new List(); IToken bodyStart; .) SYNC "class" { Attribute } NoUSIdent [ GenericParameters ] "{" (. bodyStart = t; .) { ClassMemberDecl } "}" (. c = new ClassDecl(id, id.val, module, typeArgs, members, attrs); c.BodyStartTok = bodyStart; c.BodyEndTok = t; .) . ClassMemberDecl<.List/*!*/ mm, bool isAlreadyGhost, bool allowConstructors.> = (. Contract.Requires(cce.NonNullElements(mm)); Method/*!*/ m; Function/*!*/ f; MemberModifiers mmod = new MemberModifiers(); mmod.IsGhost = isAlreadyGhost; .) { "ghost" (. mmod.IsGhost = true; .) | "static" (. mmod.IsStatic = true; .) } ( FieldDecl | FunctionDecl (. mm.Add(f); .) | MethodDecl (. mm.Add(m); .) ) . DatatypeDecl = (. Contract.Requires(module != null); Contract.Ensures(Contract.ValueAtReturn(out dt)!=null); IToken/*!*/ id; Attributes attrs = null; List typeArgs = new List(); List ctors = new List(); IToken bodyStart = Token.NoToken; // dummy assignment bool co = false; .) SYNC ( "datatype" | "codatatype" (. co = true; .) ) { Attribute } NoUSIdent [ GenericParameters ] "=" (. bodyStart = t; .) DatatypeMemberDecl { "|" DatatypeMemberDecl } SYNC ";" (. if (co) { dt = new CoDatatypeDecl(id, id.val, module, typeArgs, ctors, attrs); } else { dt = new IndDatatypeDecl(id, id.val, module, typeArgs, ctors, attrs); } dt.BodyStartTok = bodyStart; dt.BodyEndTok = t; .) . DatatypeMemberDecl<.List/*!*/ ctors.> = (. Contract.Requires(cce.NonNullElements(ctors)); Attributes attrs = null; IToken/*!*/ id; List formals = new List(); .) { Attribute } NoUSIdent [ FormalsOptionalIds ] (. ctors.Add(new DatatypeCtor(id, id.val, formals, attrs)); .) . FieldDecl<.MemberModifiers mmod, List/*!*/ mm.> = (. Contract.Requires(cce.NonNullElements(mm)); Attributes attrs = null; IToken/*!*/ id; Type/*!*/ ty; .) SYNC "var" (. if (mmod.IsStatic) { SemErr(t, "fields cannot be declared 'static'"); } .) { Attribute } IdentType (. mm.Add(new Field(id, id.val, mmod.IsGhost, ty, attrs)); .) { "," IdentType (. mm.Add(new Field(id, id.val, mmod.IsGhost, ty, attrs)); .) } SYNC ";" . ArbitraryTypeDecl = (. IToken/*!*/ id; Attributes attrs = null; var eqSupport = TypeParameter.EqualitySupportValue.Unspecified; .) "type" { Attribute } NoUSIdent [ "(" "==" ")" (. eqSupport = TypeParameter.EqualitySupportValue.Required; .) ] (. at = new ArbitraryTypeDecl(id, id.val, module, eqSupport, attrs); .) SYNC ";" . GIdentType /* isGhost always returns as false if allowGhostKeyword is false */ = (. Contract.Ensures(Contract.ValueAtReturn(out id)!=null); Contract.Ensures(Contract.ValueAtReturn(out ty)!=null); isGhost = false; .) [ "ghost" (. if (allowGhostKeyword) { isGhost = true; } else { SemErr(t, "formal cannot be declared 'ghost' in this context"); } .) ] IdentType . IdentType = (.Contract.Ensures(Contract.ValueAtReturn(out id) != null); Contract.Ensures(Contract.ValueAtReturn(out ty) != null);.) WildIdent ":" Type . LocalIdentTypeOptional = (. IToken/*!*/ id; Type/*!*/ ty; Type optType = null; .) WildIdent [ ":" Type (. optType = ty; .) ] (. var = new VarDecl(id, id.val, optType == null ? new InferredTypeProxy() : optType, isGhost); .) . IdentTypeOptional = (. Contract.Ensures(Contract.ValueAtReturn(out var)!=null); IToken/*!*/ id; Type/*!*/ ty; Type optType = null; .) WildIdent [ ":" Type (. optType = ty; .) ] (. var = new BoundVar(id, id.val, optType == null ? new InferredTypeProxy() : optType); .) . TypeIdentOptional = (.Contract.Ensures(Contract.ValueAtReturn(out id)!=null); Contract.Ensures(Contract.ValueAtReturn(out ty)!=null); Contract.Ensures(Contract.ValueAtReturn(out identName)!=null); string name = null; isGhost = false; .) [ "ghost" (. isGhost = true; .) ] TypeAndToken [ ":" (. /* try to convert ty to an identifier */ UserDefinedType udt = ty as UserDefinedType; if (udt != null && udt.TypeArgs.Count == 0) { name = udt.Name; } else { SemErr(id, "invalid formal-parameter name in datatype constructor"); } .) Type ] (. if (name != null) { identName = name; } else { identName = "#" + anonymousIds++; } .) . /*------------------------------------------------------------------------*/ GenericParameters<.List/*!*/ typeArgs.> = (. Contract.Requires(cce.NonNullElements(typeArgs)); IToken/*!*/ id; TypeParameter.EqualitySupportValue eqSupport; .) "<" NoUSIdent (. eqSupport = TypeParameter.EqualitySupportValue.Unspecified; .) [ "(" "==" ")" (. eqSupport = TypeParameter.EqualitySupportValue.Required; .) ] (. typeArgs.Add(new TypeParameter(id, id.val, eqSupport)); .) { "," NoUSIdent (. eqSupport = TypeParameter.EqualitySupportValue.Unspecified; .) [ "(" "==" ")" (. eqSupport = TypeParameter.EqualitySupportValue.Required; .) ] (. typeArgs.Add(new TypeParameter(id, id.val, eqSupport)); .) } ">" . /*------------------------------------------------------------------------*/ MethodDecl = (. Contract.Ensures(Contract.ValueAtReturn(out m) !=null); IToken/*!*/ id; Attributes attrs = null; List/*!*/ typeArgs = new List(); IToken openParen; List ins = new List(); List outs = new List(); List req = new List(); List mod = new List(); List ens = new List(); List dec = new List(); Attributes decAttrs = null; Attributes modAttrs = null; BlockStmt body = null; bool isConstructor = false; bool signatureOmitted = false; IToken bodyStart = Token.NoToken; IToken bodyEnd = Token.NoToken; .) SYNC ( "method" | "constructor" (. if (allowConstructor) { isConstructor = true; } else { SemErr(t, "constructors are only allowed in classes"); } .) ) (. if (isConstructor) { if (mmod.IsGhost) { SemErr(t, "constructors cannot be declared 'ghost'"); } if (mmod.IsStatic) { SemErr(t, "constructors cannot be declared 'static'"); } } .) { Attribute } NoUSIdent ( [ GenericParameters ] Formals [ "returns" (. if (isConstructor) { SemErr(t, "constructors cannot have out-parameters"); } .) Formals ] | "..." (. signatureOmitted = true; openParen = Token.NoToken; .) ) { MethodSpec } [ BlockStmt ] (. if (isConstructor) { m = new Constructor(id, id.val, typeArgs, ins, req, new Specification(mod, modAttrs), ens, new Specification(dec, decAttrs), body, attrs, signatureOmitted); } else { m = new Method(id, id.val, mmod.IsStatic, mmod.IsGhost, typeArgs, ins, outs, req, new Specification(mod, modAttrs), ens, new Specification(dec, decAttrs), body, attrs, signatureOmitted); } m.BodyStartTok = bodyStart; m.BodyEndTok = bodyEnd; .) . MethodSpec<.List/*!*/ req, List/*!*/ mod, List/*!*/ ens, List/*!*/ decreases, ref Attributes decAttrs, ref Attributes modAttrs.> = (. Contract.Requires(cce.NonNullElements(req)); Contract.Requires(cce.NonNullElements(mod)); Contract.Requires(cce.NonNullElements(ens)); Contract.Requires(cce.NonNullElements(decreases)); Expression/*!*/ e; FrameExpression/*!*/ fe; bool isFree = false; Attributes ensAttrs = null; .) SYNC ( "modifies" { IF(IsAttribute()) Attribute } [ FrameExpression (. mod.Add(fe); .) { "," FrameExpression (. mod.Add(fe); .) } ] SYNC ";" | [ "free" (. isFree = true; .) ] ( "requires" Expression SYNC ";" (. req.Add(new MaybeFreeExpression(e, isFree)); .) | "ensures" { IF(IsAttribute()) Attribute } Expression SYNC ";" (. ens.Add(new MaybeFreeExpression(e, isFree, ensAttrs)); .) ) | "decreases" { IF(IsAttribute()) Attribute } DecreasesList SYNC ";" ) . Formals<.bool incoming, bool allowGhostKeyword, List/*!*/ formals, out IToken openParen.> = (. Contract.Requires(cce.NonNullElements(formals)); IToken/*!*/ id; Type/*!*/ ty; bool isGhost; .) "(" (. openParen = t; .) [ GIdentType (. formals.Add(new Formal(id, id.val, ty, incoming, isGhost)); .) { "," GIdentType (. formals.Add(new Formal(id, id.val, ty, incoming, isGhost)); .) } ] ")" . FormalsOptionalIds<.List/*!*/ formals.> = (. Contract.Requires(cce.NonNullElements(formals)); IToken/*!*/ id; Type/*!*/ ty; string/*!*/ name; bool isGhost; .) "(" [ TypeIdentOptional (. formals.Add(new Formal(id, name, ty, true, isGhost)); .) { "," TypeIdentOptional (. formals.Add(new Formal(id, name, ty, true, isGhost)); .) } ] ")" . /*------------------------------------------------------------------------*/ Type = (. Contract.Ensures(Contract.ValueAtReturn(out ty) != null); IToken/*!*/ tok; .) TypeAndToken . TypeAndToken = (. Contract.Ensures(Contract.ValueAtReturn(out tok)!=null); Contract.Ensures(Contract.ValueAtReturn(out ty) != null); tok = Token.NoToken; ty = new BoolType(); /*keep compiler happy*/ List/*!*/ gt; .) ( "bool" (. tok = t; .) | "nat" (. tok = t; ty = new NatType(); .) | "int" (. tok = t; ty = new IntType(); .) | "set" (. tok = t; gt = new List(); .) GenericInstantiation (. if (gt.Count != 1) { SemErr("set type expects exactly one type argument"); } ty = new SetType(gt[0]); .) | "multiset" (. tok = t; gt = new List(); .) GenericInstantiation (. if (gt.Count != 1) { SemErr("multiset type expects exactly one type argument"); } ty = new MultiSetType(gt[0]); .) | "seq" (. tok = t; gt = new List(); .) GenericInstantiation (. if (gt.Count != 1) { SemErr("seq type expects exactly one type argument"); } ty = new SeqType(gt[0]); .) | "map" (. tok = t; gt = new List(); .) GenericInstantiation (. if (gt.Count != 2) { SemErr("map type expects exactly two type arguments"); } else { ty = new MapType(gt[0], gt[1]); } .) | ReferenceType ) . ReferenceType = (. Contract.Ensures(Contract.ValueAtReturn(out tok) != null); Contract.Ensures(Contract.ValueAtReturn(out ty) != null); tok = Token.NoToken; ty = new BoolType(); /*keep compiler happy*/ List/*!*/ gt; List path; .) ( "object" (. tok = t; ty = new ObjectType(); .) | arrayToken (. tok = t; gt = new List(); .) GenericInstantiation (. if (gt.Count != 1) { SemErr("array type expects exactly one type argument"); } int dims = 1; if (tok.val.Length != 5) { dims = int.Parse(tok.val.Substring(5)); } ty = theBuiltIns.ArrayType(tok, dims, gt[0], true); .) | Ident (. gt = new List(); path = new List(); .) { (. path.Add(tok); .) "." Ident } [ GenericInstantiation ] (. ty = new UserDefinedType(tok, tok.val, gt, path); .) ) . GenericInstantiation<.List/*!*/ gt.> = (. Contract.Requires(cce.NonNullElements(gt)); Type/*!*/ ty; .) "<" Type (. gt.Add(ty); .) { "," Type (. gt.Add(ty); .) } ">" . /*------------------------------------------------------------------------*/ FunctionDecl = (. Contract.Ensures(Contract.ValueAtReturn(out f)!=null); Attributes attrs = null; IToken/*!*/ id = Token.NoToken; // to please compiler List typeArgs = new List(); List formals = new List(); Type/*!*/ returnType = new BoolType(); List reqs = new List(); List ens = new List(); List reads = new List(); List decreases; Expression body = null; bool isPredicate = false; bool isCoPredicate = false; bool isFunctionMethod = false; IToken openParen = null; IToken bodyStart = Token.NoToken; IToken bodyEnd = Token.NoToken; bool signatureOmitted = false; .) /* ----- function ----- */ ( "function" [ "method" (. isFunctionMethod = true; .) ] (. if (mmod.IsGhost) { SemErr(t, "functions cannot be declared 'ghost' (they are ghost by default)"); } .) { Attribute } NoUSIdent ( [ GenericParameters ] Formals ":" Type | "..." (. signatureOmitted = true; openParen = Token.NoToken; .) ) /* ----- predicate ----- */ | "predicate" (. isPredicate = true; .) [ "method" (. isFunctionMethod = true; .) ] (. if (mmod.IsGhost) { SemErr(t, "predicates cannot be declared 'ghost' (they are ghost by default)"); } .) { Attribute } NoUSIdent ( [ GenericParameters ] [ Formals [ ":" (. SemErr(t, "predicates do not have an explicitly declared return type; it is always bool"); .) ] ] | "..." (. signatureOmitted = true; openParen = Token.NoToken; .) ) /* ----- copredicate ----- */ | "copredicate" (. isCoPredicate = true; .) (. if (mmod.IsGhost) { SemErr(t, "copredicates cannot be declared 'ghost' (they are ghost by default)"); } .) { Attribute } NoUSIdent ( [ GenericParameters ] [ Formals [ ":" (. SemErr(t, "copredicates do not have an explicitly declared return type; it is always bool"); .) ] ] | "..." (. signatureOmitted = true; openParen = Token.NoToken; .) ) ) (. decreases = isCoPredicate ? null : new List(); .) { FunctionSpec } [ FunctionBody ] (. if (isPredicate) { f = new Predicate(id, id.val, mmod.IsStatic, !isFunctionMethod, typeArgs, openParen, formals, reqs, reads, ens, new Specification(decreases, null), body, Predicate.BodyOriginKind.OriginalOrInherited, attrs, signatureOmitted); } else if (isCoPredicate) { f = new CoPredicate(id, id.val, mmod.IsStatic, typeArgs, openParen, formals, reqs, reads, ens, body, attrs, signatureOmitted); } else { f = new Function(id, id.val, mmod.IsStatic, !isFunctionMethod, typeArgs, openParen, formals, returnType, reqs, reads, ens, new Specification(decreases, null), body, attrs, signatureOmitted); } f.BodyStartTok = bodyStart; f.BodyEndTok = bodyEnd; .) . FunctionSpec<.List/*!*/ reqs, List/*!*/ reads, List/*!*/ ens, List decreases.> = (. Contract.Requires(cce.NonNullElements(reqs)); Contract.Requires(cce.NonNullElements(reads)); Contract.Requires(decreases == null || cce.NonNullElements(decreases)); Expression/*!*/ e; FrameExpression/*!*/ fe; .) ( SYNC "requires" Expression SYNC ";" (. reqs.Add(e); .) | "reads" [ PossiblyWildFrameExpression (. reads.Add(fe); .) { "," PossiblyWildFrameExpression (. reads.Add(fe); .) } ] SYNC ";" | "ensures" Expression SYNC ";" (. ens.Add(e); .) | "decreases" (. if (decreases == null) { SemErr(t, "'decreases' clauses are meaningless for copredicates, so they are not allowed"); decreases = new List(); } .) DecreasesList SYNC ";" ) . PossiblyWildExpression = (. Contract.Ensures(Contract.ValueAtReturn(out e)!=null); e = dummyExpr; .) /* A decreases clause on a loop asks that no termination check be performed. * Use of this feature is sound only with respect to partial correctness. */ ( "*" (. e = new WildcardExpr(t); .) | Expression ) . PossiblyWildFrameExpression = (. Contract.Ensures(Contract.ValueAtReturn(out fe) != null); fe = dummyFrameExpr; .) /* A reads clause can list a wildcard, which allows the enclosing function to * read anything. In many cases, and in particular in all cases where * the function is defined recursively, this makes it next to impossible to make * any use of the function. Nevertheless, as an experimental feature, the * language allows it (and it is sound). */ ( "*" (. fe = new FrameExpression(t, new WildcardExpr(t), null); .) | FrameExpression ) . FrameExpression = (. Contract.Ensures(Contract.ValueAtReturn(out fe) != null); Expression/*!*/ e; IToken/*!*/ id; string fieldName = null; IToken feTok = null; fe = null; .) (( Expression (. feTok = e.tok; .) [ "`" Ident (. fieldName = id.val; feTok = id; .) ] (. fe = new FrameExpression(feTok, e, fieldName); .) ) | ( "`" Ident (. fieldName = id.val; .) (. fe = new FrameExpression(id, new ImplicitThisExpr(id), fieldName); .) )) . FunctionBody = (. Contract.Ensures(Contract.ValueAtReturn(out e) != null); e = dummyExpr; .) "{" (. bodyStart = t; .) Expression "}" (. bodyEnd = t; .) . /*------------------------------------------------------------------------*/ BlockStmt = (. Contract.Ensures(Contract.ValueAtReturn(out block) != null); List body = new List(); .) "{" (. bodyStart = t; .) { Stmt } "}" (. bodyEnd = t; block = new BlockStmt(bodyStart, body); .) . Stmt<.List/*!*/ ss.> = (. Statement/*!*/ s; .) OneStmt (. ss.Add(s); .) . OneStmt = (. Contract.Ensures(Contract.ValueAtReturn(out s) != null); IToken/*!*/ x; IToken/*!*/ id; string label = null; s = dummyStmt; /* to please the compiler */ BlockStmt bs; IToken bodyStart, bodyEnd; int breakCount; .) SYNC ( BlockStmt (. s = bs; .) | AssertStmt | AssumeStmt | PrintStmt | UpdateStmt | VarDeclStatement | IfStmt | WhileStmt | MatchStmt | ParallelStmt | CalcStmt | "label" (. x = t; .) NoUSIdent ":" OneStmt (. s.Labels = new LList