using System.Collections.Generic; using System.Numerics; using Microsoft.Boogie; using System.IO; using System.Text; using System; using System.Diagnostics.Contracts; namespace Microsoft.Dafny { public class Parser { public const int _EOF = 0; public const int _ident = 1; public const int _digits = 2; public const int _hexdigits = 3; public const int _decimaldigits = 4; public const int _arrayToken = 5; public const int _bool = 6; public const int _char = 7; public const int _int = 8; public const int _nat = 9; public const int _real = 10; public const int _object = 11; public const int _string = 12; public const int _set = 13; public const int _iset = 14; public const int _multiset = 15; public const int _seq = 16; public const int _map = 17; public const int _imap = 18; public const int _charToken = 19; public const int _stringToken = 20; public const int _colon = 21; public const int _comma = 22; public const int _verticalbar = 23; public const int _doublecolon = 24; public const int _boredSmiley = 25; public const int _bullet = 26; public const int _dot = 27; public const int _semi = 28; public const int _darrow = 29; public const int _arrow = 30; public const int _assume = 31; public const int _calc = 32; public const int _case = 33; public const int _then = 34; public const int _else = 35; public const int _decreases = 36; public const int _invariant = 37; public const int _function = 38; public const int _predicate = 39; public const int _inductive = 40; public const int _lemma = 41; public const int _copredicate = 42; public const int _modifies = 43; public const int _reads = 44; public const int _requires = 45; public const int _lbrace = 46; public const int _rbrace = 47; public const int _lbracket = 48; public const int _rbracket = 49; public const int _openparen = 50; public const int _closeparen = 51; public const int _openAngleBracket = 52; public const int _closeAngleBracket = 53; public const int _eq = 54; public const int _neq = 55; public const int _neqAlt = 56; public const int _star = 57; public const int _notIn = 58; public const int _ellipsis = 59; public const int maxT = 140; const bool _T = true; const bool _x = false; const int minErrDist = 2; public Scanner scanner; public Errors errors; public Token t; // last recognized token public Token la; // lookahead token int errDist = minErrDist; readonly Expression/*!*/ dummyExpr; readonly AssignmentRhs/*!*/ dummyRhs; readonly FrameExpression/*!*/ dummyFrameExpr; readonly Statement/*!*/ dummyStmt; readonly ModuleDecl theModule; readonly BuiltIns theBuiltIns; readonly bool theVerifyThisFile; int anonymousIds = 0; /// /// Holds the modifiers given for a declaration /// /// Not all modifiers are applicable to all kinds of declarations. /// Errors are given when a modify does not apply. /// We also record the tokens for the specified modifiers so that /// they can be used in error messages. /// struct DeclModifierData { public bool IsAbstract; public IToken AbstractToken; public bool IsGhost; public IToken GhostToken; public bool IsStatic; public IToken StaticToken; public bool IsProtected; public IToken ProtectedToken; public bool IsExtern; public IToken ExternToken; public StringLiteralExpr ExternName; } // Check that token has not been set, then set it. public void CheckAndSetToken(ref IToken token) { if (token != null) { SemErr(t, "Duplicate declaration modifier: " + t.val); } token = t; } /// // A flags type used to tell what declaration modifiers are allowed for a declaration. /// [Flags] enum AllowedDeclModifiers { None = 0, Abstract = 1, Ghost = 2, // Means ghost not allowed because already implicitly ghost. AlreadyGhost = 4, Static = 8, Protected = 16, Extern = 32 }; /// /// Check the declaration modifiers against those that are allowed. /// /// The 'allowed' parameter specifies which declaratio modifiers are allowed. /// The 'declCaption' parameter should be a string describing the kind of declaration. /// It is used in error messages. /// Any declaration modifiers that are present but not allowed are cleared. /// void CheckDeclModifiers(DeclModifierData dmod, string declCaption, AllowedDeclModifiers allowed) { if (dmod.IsAbstract && ((allowed & AllowedDeclModifiers.Abstract) == 0)) { SemErr(dmod.AbstractToken, declCaption + " cannot be declared 'abstract'."); dmod.IsAbstract = false; } if (dmod.IsGhost) { if ((allowed & AllowedDeclModifiers.AlreadyGhost) != 0) { SemErr(dmod.GhostToken, declCaption + " cannot be declared ghost (they are 'ghost' by default)."); dmod.IsGhost = false; } else if ((allowed & AllowedDeclModifiers.Ghost) == 0) { SemErr(dmod.GhostToken, declCaption + " cannot be declared 'ghost'."); dmod.IsGhost = false; } } if (dmod.IsStatic && ((allowed & AllowedDeclModifiers.Static) == 0)) { SemErr(dmod.StaticToken, declCaption + " cannot be declared 'static'."); dmod.IsStatic = false; } if (dmod.IsProtected && ((allowed & AllowedDeclModifiers.Protected) == 0)) { SemErr(dmod.ProtectedToken, declCaption + " cannot be declared 'protected'."); dmod.IsProtected = false; } if (dmod.IsExtern && ((allowed & AllowedDeclModifiers.Extern) == 0)) { SemErr(dmod.ExternToken, declCaption + " cannot be declared 'extern'."); dmod.IsExtern = false; } } /// /// Encode an 'extern' declaration modifier as an {:extern name} attribute. /// /// We also include an {:axiom} attribute since the specification of an /// external entity is assumed to hold, but only for methods or functions. /// static void EncodeExternAsAttribute(DeclModifierData dmod, ref Attributes attrs, IToken/*!*/ id, bool needAxiom) { if (dmod.IsExtern) { StringLiteralExpr name = dmod.ExternName; if (name == null) { bool isVerbatimString = false; name = new StringLiteralExpr(id, id.val, isVerbatimString); } var args = new List(); args.Add(name); attrs = new Attributes("extern", args, attrs); // Also 'extern' implies 'axiom' for methods or functions. if (needAxiom) { attrs = new Attributes("axiom", new List(), attrs); } } } /// /// 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, Errors/*!*/ errors, bool verifyThisFile=true) /* 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, filename, module, builtIns, errors, verifyThisFile); } else { using (System.IO.StreamReader reader = new System.IO.StreamReader(filename)) { s = Microsoft.Boogie.ParserHelper.Fill(reader, new List()); return Parse(s, filename, DafnyOptions.Clo.UseBaseNameForFileName ? Path.GetFileName(filename) : filename, module, builtIns, errors, verifyThisFile); } } } /// /// 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/*!*/ fullFilename, string/*!*/ filename, ModuleDecl module, BuiltIns builtIns, ErrorReporter reporter, bool verifyThisFile=true) { Contract.Requires(s != null); Contract.Requires(filename != null); Contract.Requires(module != null); Errors errors = new Errors(reporter); return Parse(s, fullFilename, filename, module, builtIns, errors, verifyThisFile); } /// /// 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/*!*/ fullFilename, string/*!*/ filename, ModuleDecl module, BuiltIns builtIns, Errors/*!*/ errors, bool verifyThisFile=true) { 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, fullFilename, filename); Parser parser = new Parser(scanner, errors, module, builtIns, verifyThisFile); parser.Parse(); return parser.errors.ErrorCount; } public Parser(Scanner/*!*/ scanner, Errors/*!*/ errors, ModuleDecl module, BuiltIns builtIns, bool verifyThisFile=true) : 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, Token.NoToken, null); theModule = module; theBuiltIns = builtIns; theVerifyThisFile = verifyThisFile; } bool IsAttribute() { Token x = scanner.Peek(); return la.kind == _lbrace && x.kind == _colon; } bool IsAlternative() { Token x = scanner.Peek(); return la.kind == _lbrace && x.kind == _case; } // an existential guard starts with an identifier and is then followed by // * a colon (if the first identifier is given an explicit type), // * a comma (if there's a list a bound variables and the first one is not given an explicit type), // * a start-attribute (if there's one bound variable and it is not given an explicit type and there are attributes), or // * a bored smiley (if there's one bound variable and it is not given an explicit type). bool IsExistentialGuard() { scanner.ResetPeek(); if (la.kind == _ident) { Token x = scanner.Peek(); if (x.kind == _colon || x.kind == _comma || x.kind == _boredSmiley) { return true; } else if (x.kind == _lbrace) { x = scanner.Peek(); return x.kind == _colon; } } return false; } bool IsLoopSpec() { return la.kind == _invariant | la.kind == _decreases | la.kind == _modifies; } bool IsFunctionDecl() { switch (la.kind) { case _function: case _predicate: case _copredicate: return true; case _inductive: return scanner.Peek().kind != _lemma; default: return false; } } bool IsParenStar() { scanner.ResetPeek(); Token x = scanner.Peek(); return la.kind == _openparen && x.kind == _star; } bool IsEquivOp() { return la.val == "<==>" || la.val == "\u21d4"; } bool IsImpliesOp() { return la.val == "==>" || la.val == "\u21d2"; } bool IsExpliesOp() { return la.val == "<==" || la.val == "\u21d0"; } bool IsAndOp() { return la.val == "&&" || la.val == "\u2227"; } bool IsOrOp() { return la.val == "||" || la.val == "\u2228"; } bool IsRelOp() { return la.val == "==" || la.val == "<" || la.val == ">" || la.val == "<=" || la.val == ">=" || la.val == "!=" || la.val == "in" || la.kind == _notIn || la.val =="!" || la.val == "\u2260" || la.val == "\u2264" || la.val == "\u2265"; } bool IsAddOp() { return la.val == "+" || la.val == "-"; } bool IsMulOp() { return la.kind == _star || la.val == "/" || la.val == "%"; } bool IsQSep() { return la.kind == _doublecolon || la.kind == _bullet; } bool IsNonFinalColon() { return la.kind == _colon && scanner.Peek().kind != _rbracket; } bool IsMapDisplay() { return la.kind == _map && scanner.Peek().kind == _lbracket; } bool IsIMapDisplay() { return la.kind == _imap && scanner.Peek().kind == _lbracket; } bool IsISetDisplay() { return la.kind == _iset && scanner.Peek().kind == _lbrace; } bool IsSuffix() { return la.kind == _dot || la.kind == _lbracket || la.kind == _openparen; } string UnwildIdent(string x, bool allowWildcardId) { if (x.StartsWith("_")) { if (allowWildcardId && x.Length == 1) { return "_v" + anonymousIds++; } else { SemErr("cannot declare identifier beginning with underscore"); } } return x; } bool IsLambda(bool allowLambda) { if (!allowLambda) { return false; } scanner.ResetPeek(); Token x; // peek at what might be a signature of a lambda expression if (la.kind == _ident) { // cool, that's the entire candidate signature } else if (la.kind != _openparen) { return false; // this is not a lambda expression } else { int identCount = 0; x = scanner.Peek(); while (x.kind != _closeparen) { if (identCount != 0) { if (x.kind != _comma) { return false; // not the signature of a lambda } x = scanner.Peek(); } if (x.kind != _ident) { return false; // not a lambda expression } identCount++; x = scanner.Peek(); if (x.kind == _colon) { // a colon belongs only in a lamdba signature, so this must be a lambda (or something ill-formed) return true; } } } // What we have seen so far could have been a lambda signature or could have been some // other expression (in particular, an identifier, a parenthesized identifier, or a // tuple all of whose subexpressions are identifiers). // It is a lambda expression if what follows is something that must be a lambda. x = scanner.Peek(); return x.kind == _darrow || x.kind == _arrow || x.kind == _reads || x.kind == _requires; } bool IsIdentParen() { Token x = scanner.Peek(); return la.kind == _ident && x.kind == _openparen; } bool IsIdentColonOrBar() { Token x = scanner.Peek(); return la.kind == _ident && (x.kind == _colon || x.kind == _verticalbar); } bool SemiFollowsCall(bool allowSemi, Expression e) { return allowSemi && la.kind == _semi && e is ApplySuffix; } bool CloseOptionalBrace(bool usesOptionalBrace) { return usesOptionalBrace && la.kind == _rbrace; } bool IsNotEndOfCase() { return la.kind != _EOF && la.kind != _rbrace && la.kind != _case; } /* The following is the largest lookahead there is. It needs to check if what follows * can be nothing but "<" Type { "," Type } ">". */ bool IsGenericInstantiation() { scanner.ResetPeek(); IToken pt = la; if (!IsTypeList(ref pt)) { return false; } /* There are ambiguities in the parsing. For example: * F( a < b , c > (d) ) * can either be a unary function F whose argument is a function "a" with type arguments "" and * parameter "d", or can be a binary function F with the two boolean arguments "a < b" and "c > (d)". * To make the situation a little better, we (somewhat heuristically) look at the character that * follows the ">". Note that if we, contrary to a user's intentions, pick "a" out as a function * with a type instantiation, the user can disambiguate it by making sure the ">" sits inside some * parentheses, like: * F( a < b , (c > (d)) ) */ switch (pt.kind) { case _dot: // here, we're sure it must have been a type instantiation we saw, because an expression cannot begin with dot case _openparen: // it was probably a type instantiation of a function/method case _lbracket: // it is possible that it was a type instantiation case _lbrace: // it was probably a type instantiation of a function/method // In the following cases, we're sure we must have read a type instantiation that just ended an expression case _closeparen: case _rbracket: case _rbrace: case _semi: case _then: case _else: case _case: case _eq: case _neq: case _neqAlt: case _openAngleBracket: case _closeAngleBracket: return true; default: return false; } } /* Returns true if the next thing is of the form: * "<" Type { "," Type } ">" */ bool IsTypeList(ref IToken pt) { if (pt.kind != _openAngleBracket) { return false; } pt = scanner.Peek(); return IsTypeSequence(ref pt, _closeAngleBracket); } /* Returns true if the next thing is of the form: * Type { "," Type } * followed by an endBracketKind. */ bool IsTypeSequence(ref IToken pt, int endBracketKind) { while (true) { if (!IsType(ref pt)) { return false; } if (pt.kind == endBracketKind) { // end of type list pt = scanner.Peek(); return true; } else if (pt.kind == _comma) { // type list continues pt = scanner.Peek(); } else { // not a type list return false; } } } bool IsType(ref IToken pt) { switch (pt.kind) { case _bool: case _char: case _nat: case _int: case _real: case _object: case _string: pt = scanner.Peek(); return true; case _arrayToken: case _set: case _iset: case _multiset: case _seq: case _map: case _imap: pt = scanner.Peek(); return pt.kind != _openAngleBracket || IsTypeList(ref pt); case _ident: while (true) { // invariant: next token is an ident pt = scanner.Peek(); if (pt.kind == _openAngleBracket && !IsTypeList(ref pt)) { return false; } if (pt.kind != _dot) { // end of the type return true; } pt = scanner.Peek(); // get the _dot if (pt.kind != _ident) { return false; } } case _openparen: pt = scanner.Peek(); if (pt.kind == _closeparen) { // end of type list pt = scanner.Peek(); return true; } return IsTypeSequence(ref pt, _closeparen); default: return false; } } bool IsDefaultImport() { scanner.ResetPeek(); Token x = scanner.Peek(); // lookahead token again return la.val == "default" && x.val != "export"; } /*--------------------------------------------------------------------------*/ public Parser(Scanner scanner, Errors errors) { this.scanner = scanner; this.errors = errors; Token tok = new Token(); tok.val = ""; this.la = tok; this.t = new Token(); // just to satisfy its non-null constraint } void SynErr (int n) { if (errDist >= minErrDist) errors.SynErr(la.filename, la.line, la.col, n); errDist = 0; } public void SemErr (string msg) { Contract.Requires(msg != null); if (errDist >= minErrDist) errors.SemErr(t, msg); errDist = 0; } public void SemErr(IToken tok, string msg) { Contract.Requires(tok != null); Contract.Requires(msg != null); errors.SemErr(tok, msg); } void Get () { for (;;) { t = la; la = scanner.Scan(); if (la.kind <= maxT) { ++errDist; break; } la = t; } } void Expect (int n) { if (la.kind==n) Get(); else { SynErr(n); } } bool StartOf (int s) { return set[s, la.kind]; } void ExpectWeak (int n, int follow) { if (la.kind == n) Get(); else { SynErr(n); while (!StartOf(follow)) Get(); } } bool WeakSeparator(int n, int syFol, int repFol) { int kind = la.kind; if (kind == n) {Get(); return true;} else if (StartOf(repFol)) {return false;} else { SynErr(n); while (!(set[syFol, kind] || set[repFol, kind] || set[0, kind])) { Get(); kind = la.kind; } return StartOf(syFol); } } void Dafny() { List membersDefaultClass = new List(); // 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); while (la.kind == 60) { Get(); Expect(20); { string parsedFile = scanner.FullFilename; bool isVerbatimString; string includedFile = Util.RemoveParsedStringQuotes(t.val, out isVerbatimString); includedFile = Util.RemoveEscaping(includedFile, isVerbatimString); string fullPath = includedFile; if (!Path.IsPathRooted(includedFile)) { string basePath = Path.GetDirectoryName(parsedFile); includedFile = Path.Combine(basePath, includedFile); fullPath = Path.GetFullPath(includedFile); } defaultModule.Includes.Add(new Include(t, includedFile, fullPath)); } } while (StartOf(1)) { TopDecl(defaultModule, membersDefaultClass, /* isTopLevel */ true, /* isAbstract */ false); } 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); } Expect(0); } void TopDecl(ModuleDefinition module, List membersDefaultClass, bool isTopLevel, bool isAbstract ) { DeclModifierData dmod = new DeclModifierData(); ModuleDecl submodule; ClassDecl/*!*/ c; DatatypeDecl/*!*/ dt; TopLevelDecl td; IteratorDecl iter; TraitDecl/*!*/ trait; while (StartOf(2)) { DeclModifier(ref dmod); } switch (la.kind) { case 66: case 69: case 73: case 74: { SubModuleDecl(dmod, module, out submodule); module.TopLevelDecls.Add(submodule); break; } case 77: { ClassDecl(dmod, module, out c); module.TopLevelDecls.Add(c); break; } case 79: case 80: { DatatypeDecl(dmod, module, out dt); module.TopLevelDecls.Add(dt); break; } case 82: { NewtypeDecl(dmod, module, out td); module.TopLevelDecls.Add(td); break; } case 83: { OtherTypeDecl(dmod, module, out td); module.TopLevelDecls.Add(td); break; } case 84: { IteratorDecl(dmod, module, out iter); module.TopLevelDecls.Add(iter); break; } case 78: { TraitDecl(dmod, module, out trait); module.TopLevelDecls.Add(trait); break; } case 38: case 39: case 40: case 41: case 42: case 81: case 87: case 88: case 89: case 90: { ClassMemberDecl(dmod, membersDefaultClass, false, !DafnyOptions.O.AllowGlobals, !isTopLevel && DafnyOptions.O.IronDafny && isAbstract); break; } default: SynErr(141); break; } } void DeclModifier(ref DeclModifierData dmod) { if (la.kind == 61) { Get(); dmod.IsAbstract = true; CheckAndSetToken(ref dmod.AbstractToken); } else if (la.kind == 62) { Get(); dmod.IsGhost = true; CheckAndSetToken(ref dmod.GhostToken); } else if (la.kind == 63) { Get(); dmod.IsStatic = true; CheckAndSetToken(ref dmod.StaticToken); } else if (la.kind == 64) { Get(); dmod.IsProtected = true; CheckAndSetToken(ref dmod.ProtectedToken); } else if (la.kind == 65) { Get(); dmod.IsExtern = true; CheckAndSetToken(ref dmod.ExternToken); if (la.kind == 20) { Get(); bool isVerbatimString; string s = Util.RemoveParsedStringQuotes(t.val, out isVerbatimString); dmod.ExternName = new StringLiteralExpr(t, s, isVerbatimString); } } else SynErr(142); } void SubModuleDecl(DeclModifierData dmod, ModuleDefinition parent, out ModuleDecl submodule) { Attributes attrs = null; IToken/*!*/ id; List namedModuleDefaultClassMembers = new List();; List idRefined = null, idPath = null, idAssignment = null; ModuleDefinition module; submodule = null; // appease compiler bool isAbstract = dmod.IsAbstract; bool isExclusively = false; bool opened = false; CheckDeclModifiers(dmod, "Modules", AllowedDeclModifiers.Abstract | AllowedDeclModifiers.Extern); if (la.kind == 66) { Get(); while (la.kind == 46) { Attribute(ref attrs); } NoUSIdent(out id); EncodeExternAsAttribute(dmod, ref attrs, id, /* needAxiom */ false); if (la.kind == 67 || la.kind == 68) { if (la.kind == 67) { Get(); Expect(68); QualifiedModuleName(out idRefined); isExclusively = true; } else { Get(); QualifiedModuleName(out idRefined); isExclusively = false; } } module = new ModuleDefinition(id, id.val, isAbstract, false, isExclusively, idRefined == null ? null : idRefined, parent, attrs, false, this); Expect(46); module.BodyStartTok = t; while (StartOf(1)) { TopDecl(module, namedModuleDefaultClassMembers, /* isTopLevel */ false, isAbstract); } Expect(47); module.BodyEndTok = t; module.TopLevelDecls.Add(new DefaultClassDecl(module, namedModuleDefaultClassMembers)); submodule = new LiteralModuleDecl(module, parent); } else if (la.kind == 69) { Get(); if (la.kind == 70) { Get(); opened = true; } NoUSIdent(out id); EncodeExternAsAttribute(dmod, ref attrs, id, /* needAxiom */ false); if (StartOf(3)) { if (la.kind == 71) { Get(); QualifiedModuleName(out idPath); submodule = new AliasModuleDecl(idPath, id, parent, opened); } else if (la.kind == 72) { Get(); QualifiedModuleName(out idPath); if (IsDefaultImport()) { Expect(73); QualifiedModuleName(out idAssignment); } submodule = new ModuleFacadeDecl(idPath, id, parent, idAssignment, opened); errors.Warning(t, "\"import A as B\" has been deprecated; in the new syntax, it is \"import A:B\""); } else if (la.kind == 21) { Get(); QualifiedModuleName(out idPath); submodule = new ModuleFacadeDecl(idPath, id, parent, idAssignment, opened); } else { Get(); QualifiedModuleName(out idPath); idPath.Insert(0, id); submodule = new AliasModuleDecl(idPath, id, parent, opened); } } if (la.kind == 28) { while (!(la.kind == 0 || la.kind == 28)) {SynErr(143); Get();} Get(); errors.Warning(t, "the semi-colon that used to terminate a sub-module declaration has been deprecated; in the new syntax, just leave off the semi-colon"); } if (submodule == null) { idPath = new List(); idPath.Add(id); submodule = new AliasModuleDecl(idPath, id, parent, opened); } } else if (la.kind == 73 || la.kind == 74) { bool isDefault = false; bool includeBody; IToken exportId; List exports = new List();; List extends = new List(); if (la.kind == 73) { Get(); isDefault = true; } Expect(74); NoUSIdent(out exportId); if (la.kind == 75) { Get(); NoUSIdent(out id); extends.Add(id.val); while (la.kind == 22) { Get(); NoUSIdent(out id); extends.Add(id.val); } } Expect(46); NoUSIdent(out id); includeBody = false; if (la.kind == 76) { Get(); includeBody = true; } exports.Add(new ExportSignature(id, includeBody)); while (la.kind == 22) { Get(); NoUSIdent(out id); includeBody = false; if (la.kind == 76) { Get(); includeBody = true; } exports.Add(new ExportSignature(id, includeBody)); } Expect(47); submodule = new ModuleExportDecl(exportId, parent, isDefault, exports, extends); } else SynErr(144); } void ClassDecl(DeclModifierData dmodClass, ModuleDefinition/*!*/ module, out ClassDecl/*!*/ c) { Contract.Requires(module != null); Contract.Ensures(Contract.ValueAtReturn(out c) != null); IToken/*!*/ id; Type trait = null; List/*!*/ traits = new List(); Attributes attrs = null; List typeArgs = new List(); List members = new List(); IToken bodyStart; CheckDeclModifiers(dmodClass, "Classes", AllowedDeclModifiers.Extern); DeclModifierData dmod; while (!(la.kind == 0 || la.kind == 77)) {SynErr(145); Get();} Expect(77); while (la.kind == 46) { Attribute(ref attrs); } NoUSIdent(out id); EncodeExternAsAttribute(dmodClass, ref attrs, id, /* needAxiom */ false); if (la.kind == 52) { GenericParameters(typeArgs); } if (la.kind == 75) { Get(); Type(out trait); traits.Add(trait); while (la.kind == 22) { Get(); Type(out trait); traits.Add(trait); } } Expect(46); bodyStart = t; while (StartOf(4)) { dmod = new DeclModifierData(); while (StartOf(2)) { DeclModifier(ref dmod); } ClassMemberDecl(dmod, members, true, false, false); } Expect(47); c = new ClassDecl(id, id.val, module, typeArgs, members, attrs, traits); c.BodyStartTok = bodyStart; c.BodyEndTok = t; } void DatatypeDecl(DeclModifierData dmod, ModuleDefinition/*!*/ module, out DatatypeDecl/*!*/ dt) { 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; CheckDeclModifiers(dmod, "Datatypes or codatatypes", AllowedDeclModifiers.None); while (!(la.kind == 0 || la.kind == 79 || la.kind == 80)) {SynErr(146); Get();} if (la.kind == 79) { Get(); } else if (la.kind == 80) { Get(); co = true; } else SynErr(147); while (la.kind == 46) { Attribute(ref attrs); } NoUSIdent(out id); if (la.kind == 52) { GenericParameters(typeArgs); } Expect(71); bodyStart = t; DatatypeMemberDecl(ctors); while (la.kind == 23) { Get(); DatatypeMemberDecl(ctors); } if (la.kind == 28) { while (!(la.kind == 0 || la.kind == 28)) {SynErr(148); Get();} Get(); errors.Warning(t, "the semi-colon that used to terminate a (co)datatype declaration has been deprecated; in the new syntax, just leave off the semi-colon"); } 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; } void NewtypeDecl(DeclModifierData dmod, ModuleDefinition module, out TopLevelDecl td) { IToken id, bvId; Attributes attrs = null; td = null; Type baseType = null; Expression wh; CheckDeclModifiers(dmod, "Newtypes", AllowedDeclModifiers.None); Expect(82); while (la.kind == 46) { Attribute(ref attrs); } NoUSIdent(out id); Expect(71); if (IsIdentColonOrBar()) { NoUSIdent(out bvId); if (la.kind == 21) { Get(); Type(out baseType); } if (baseType == null) { baseType = new OperationTypeProxy(true, true, false, false, false, false); } Expect(23); Expression(out wh, false, true); td = new NewtypeDecl(theVerifyThisFile ? id : new IncludeToken(id), id.val, module, new BoundVar(bvId, bvId.val, baseType), wh, attrs); } else if (StartOf(5)) { Type(out baseType); td = new NewtypeDecl(theVerifyThisFile ? id : new IncludeToken(id), id.val, module, baseType, attrs); } else SynErr(149); } void OtherTypeDecl(DeclModifierData dmod, ModuleDefinition module, out TopLevelDecl td) { IToken id; Attributes attrs = null; var eqSupport = TypeParameter.EqualitySupportValue.Unspecified; var typeArgs = new List(); td = null; Type ty; CheckDeclModifiers(dmod, "Type aliases", AllowedDeclModifiers.None); Expect(83); while (la.kind == 46) { Attribute(ref attrs); } NoUSIdent(out id); if (la.kind == 50) { Get(); Expect(54); Expect(51); eqSupport = TypeParameter.EqualitySupportValue.Required; if (la.kind == 52) { GenericParameters(typeArgs); } } else if (StartOf(6)) { if (la.kind == 52) { GenericParameters(typeArgs); } if (la.kind == 71) { Get(); Type(out ty); td = new TypeSynonymDecl(id, id.val, typeArgs, module, ty, attrs); } } else SynErr(150); if (td == null) { td = new OpaqueTypeDecl(id, id.val, module, eqSupport, typeArgs, attrs); } if (la.kind == 28) { while (!(la.kind == 0 || la.kind == 28)) {SynErr(151); Get();} Get(); errors.Warning(t, "the semi-colon that used to terminate an opaque-type declaration has been deprecated; in the new syntax, just leave off the semi-colon"); } } void IteratorDecl(DeclModifierData dmod, ModuleDefinition module, out IteratorDecl/*!*/ iter) { Contract.Ensures(Contract.ValueAtReturn(out iter) != null); IToken/*!*/ id; Attributes attrs = null; List/*!*/ typeArgs = new List(); List ins = new List(); List outs = new List(); List reads = new List(); List mod = new List(); List decreases = new List(); List req = new List(); List ens = new List(); List yieldReq = new List(); List yieldEns = new List(); List dec = new List(); Attributes readsAttrs = null; Attributes modAttrs = null; Attributes decrAttrs = null; BlockStmt body = null; IToken signatureEllipsis = null; IToken bodyStart = Token.NoToken; IToken bodyEnd = Token.NoToken; CheckDeclModifiers(dmod, "Iterators", AllowedDeclModifiers.None); while (!(la.kind == 0 || la.kind == 84)) {SynErr(152); Get();} Expect(84); while (la.kind == 46) { Attribute(ref attrs); } NoUSIdent(out id); if (la.kind == 50 || la.kind == 52) { if (la.kind == 52) { GenericParameters(typeArgs); } Formals(true, true, ins); if (la.kind == 85 || la.kind == 86) { if (la.kind == 85) { Get(); } else { Get(); SemErr(t, "iterators don't have a 'returns' clause; did you mean 'yields'?"); } Formals(false, true, outs); } } else if (la.kind == 59) { Get(); signatureEllipsis = t; } else SynErr(153); while (StartOf(7)) { IteratorSpec(reads, mod, decreases, req, ens, yieldReq, yieldEns, ref readsAttrs, ref modAttrs, ref decrAttrs); } if (la.kind == 46) { BlockStmt(out body, out bodyStart, out bodyEnd); } iter = new IteratorDecl(id, id.val, module, typeArgs, ins, outs, new Specification(reads, readsAttrs), new Specification(mod, modAttrs), new Specification(decreases, decrAttrs), req, ens, yieldReq, yieldEns, body, attrs, signatureEllipsis); iter.BodyStartTok = bodyStart; iter.BodyEndTok = bodyEnd; } void TraitDecl(DeclModifierData dmodIn, ModuleDefinition/*!*/ module, out TraitDecl/*!*/ trait) { Contract.Requires(module != null); Contract.Ensures(Contract.ValueAtReturn(out trait) != null); CheckDeclModifiers(dmodIn, "Traits", AllowedDeclModifiers.None); IToken/*!*/ id; Attributes attrs = null; List typeArgs = new List(); //traits should not support type parameters at the moment List members = new List(); IToken bodyStart; DeclModifierData dmod; while (!(la.kind == 0 || la.kind == 78)) {SynErr(154); Get();} Expect(78); while (la.kind == 46) { Attribute(ref attrs); } NoUSIdent(out id); if (la.kind == 52) { GenericParameters(typeArgs); } Expect(46); bodyStart = t; while (StartOf(4)) { dmod = new DeclModifierData(); while (StartOf(2)) { DeclModifier(ref dmod); } ClassMemberDecl(dmod, members, true, false, false); } Expect(47); trait = new TraitDecl(id, id.val, module, typeArgs, members, attrs); trait.BodyStartTok = bodyStart; trait.BodyEndTok = t; } void ClassMemberDecl(DeclModifierData dmod, List mm, bool allowConstructors, bool moduleLevelDecl, bool isWithinAbstractModule) { Contract.Requires(cce.NonNullElements(mm)); Method/*!*/ m; Function/*!*/ f; if (la.kind == 81) { if (moduleLevelDecl) { SemErr(la, "fields are not allowed to be declared at the module level; instead, wrap the field in a 'class' declaration"); dmod.IsStatic = false; } FieldDecl(dmod, mm); } else if (IsFunctionDecl()) { if (moduleLevelDecl && dmod.StaticToken != null) { errors.Warning(dmod.StaticToken, "module-level functions are always non-instance, so the 'static' keyword is not allowed here"); dmod.IsStatic = false; } FunctionDecl(dmod, isWithinAbstractModule, out f); mm.Add(f); } else if (StartOf(8)) { if (moduleLevelDecl && dmod.StaticToken != null) { errors.Warning(dmod.StaticToken, "module-level methods are always non-instance, so the 'static' keyword is not allowed here"); dmod.IsStatic = false; } MethodDecl(dmod, allowConstructors, isWithinAbstractModule, out m); mm.Add(m); } else SynErr(155); } void Attribute(ref Attributes attrs) { IToken x; string name; var args = new List(); Expect(46); Expect(21); NoUSIdent(out x); name = x.val; if (StartOf(9)) { Expressions(args); } Expect(47); attrs = new Attributes(name, args, attrs); } void NoUSIdent(out IToken/*!*/ x) { Contract.Ensures(Contract.ValueAtReturn(out x) != null); Expect(1); x = t; if (x.val.StartsWith("_")) { SemErr("cannot declare identifier beginning with underscore"); } } void QualifiedModuleName(out List ids) { IToken id; ids = new List(); Ident(out id); ids.Add(id); while (la.kind == 27) { Get(); Ident(out id); ids.Add(id); } } void Ident(out IToken/*!*/ x) { Contract.Ensures(Contract.ValueAtReturn(out x) != null); Expect(1); x = t; } void GenericParameters(List/*!*/ typeArgs) { Contract.Requires(cce.NonNullElements(typeArgs)); IToken/*!*/ id; TypeParameter.EqualitySupportValue eqSupport; Expect(52); NoUSIdent(out id); eqSupport = TypeParameter.EqualitySupportValue.Unspecified; if (la.kind == 50) { Get(); Expect(54); Expect(51); eqSupport = TypeParameter.EqualitySupportValue.Required; } typeArgs.Add(new TypeParameter(id, id.val, eqSupport)); while (la.kind == 22) { Get(); NoUSIdent(out id); eqSupport = TypeParameter.EqualitySupportValue.Unspecified; if (la.kind == 50) { Get(); Expect(54); Expect(51); eqSupport = TypeParameter.EqualitySupportValue.Required; } typeArgs.Add(new TypeParameter(id, id.val, eqSupport)); } Expect(53); } void Type(out Type ty) { Contract.Ensures(Contract.ValueAtReturn(out ty) != null); IToken/*!*/ tok; TypeAndToken(out tok, out ty); } void FieldDecl(DeclModifierData dmod, List/*!*/ mm) { Contract.Requires(cce.NonNullElements(mm)); Attributes attrs = null; IToken/*!*/ id; Type/*!*/ ty; CheckDeclModifiers(dmod, "Fields", AllowedDeclModifiers.Ghost); while (!(la.kind == 0 || la.kind == 81)) {SynErr(156); Get();} Expect(81); while (la.kind == 46) { Attribute(ref attrs); } FIdentType(out id, out ty); mm.Add(new Field(id, id.val, dmod.IsGhost, ty, attrs)); while (la.kind == 22) { Get(); FIdentType(out id, out ty); mm.Add(new Field(id, id.val, dmod.IsGhost, ty, attrs)); } OldSemi(); } void FunctionDecl(DeclModifierData dmod, bool isWithinAbstractModule, out Function/*!*/ f) { 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 isIndPredicate = false; bool isCoPredicate = false; bool isFunctionMethod = false; IToken bodyStart = Token.NoToken; IToken bodyEnd = Token.NoToken; IToken signatureEllipsis = null; bool missingOpenParen; if (la.kind == 38) { Get(); if (la.kind == 87) { Get(); isFunctionMethod = true; } AllowedDeclModifiers allowed = AllowedDeclModifiers.AlreadyGhost | AllowedDeclModifiers.Static | AllowedDeclModifiers.Protected; string caption = "Functions"; if (isFunctionMethod) { allowed |= AllowedDeclModifiers.Extern; caption = "Function methods"; } CheckDeclModifiers(dmod, caption, allowed); while (la.kind == 46) { Attribute(ref attrs); } NoUSIdent(out id); if (la.kind == 50 || la.kind == 52) { if (la.kind == 52) { GenericParameters(typeArgs); } Formals(true, isFunctionMethod, formals); Expect(21); Type(out returnType); } else if (la.kind == 59) { Get(); signatureEllipsis = t; } else SynErr(157); } else if (la.kind == 39) { Get(); isPredicate = true; if (la.kind == 87) { Get(); isFunctionMethod = true; } AllowedDeclModifiers allowed = AllowedDeclModifiers.AlreadyGhost | AllowedDeclModifiers.Static | AllowedDeclModifiers.Protected; string caption = "Predicates"; if (isFunctionMethod) { allowed |= AllowedDeclModifiers.Extern; caption = "Predicate methods"; } CheckDeclModifiers(dmod, caption, allowed); while (la.kind == 46) { Attribute(ref attrs); } NoUSIdent(out id); if (StartOf(10)) { if (la.kind == 52) { GenericParameters(typeArgs); } missingOpenParen = true; if (la.kind == 50) { Formals(true, isFunctionMethod, formals); missingOpenParen = false; } if (missingOpenParen) { errors.Warning(t, "with the new support of higher-order functions in Dafny, parentheses-less predicates are no longer supported; in the new syntax, parentheses are required for the declaration and uses of predicates, even if the predicate takes no additional arguments"); } if (la.kind == 21) { Get(); SemErr(t, "predicates do not have an explicitly declared return type; it is always bool"); } } else if (la.kind == 59) { Get(); signatureEllipsis = t; } else SynErr(158); } else if (la.kind == 40) { Get(); Expect(39); isIndPredicate = true; CheckDeclModifiers(dmod, "Inductive predicates", AllowedDeclModifiers.AlreadyGhost | AllowedDeclModifiers.Static | AllowedDeclModifiers.Protected); while (la.kind == 46) { Attribute(ref attrs); } NoUSIdent(out id); if (la.kind == 50 || la.kind == 52) { if (la.kind == 52) { GenericParameters(typeArgs); } Formals(true, isFunctionMethod, formals); if (la.kind == 21) { Get(); SemErr(t, "inductive predicates do not have an explicitly declared return type; it is always bool"); } } else if (la.kind == 59) { Get(); signatureEllipsis = t; } else SynErr(159); } else if (la.kind == 42) { Get(); isCoPredicate = true; CheckDeclModifiers(dmod, "Copredicates", AllowedDeclModifiers.AlreadyGhost | AllowedDeclModifiers.Static | AllowedDeclModifiers.Protected); while (la.kind == 46) { Attribute(ref attrs); } NoUSIdent(out id); if (la.kind == 50 || la.kind == 52) { if (la.kind == 52) { GenericParameters(typeArgs); } Formals(true, isFunctionMethod, formals); if (la.kind == 21) { Get(); SemErr(t, "copredicates do not have an explicitly declared return type; it is always bool"); } } else if (la.kind == 59) { Get(); signatureEllipsis = t; } else SynErr(160); } else SynErr(161); decreases = isIndPredicate || isCoPredicate ? null : new List(); while (StartOf(11)) { FunctionSpec(reqs, reads, ens, decreases); } if (la.kind == 46) { FunctionBody(out body, out bodyStart, out bodyEnd); } if (!isWithinAbstractModule && DafnyOptions.O.DisallowSoundnessCheating && body == null && ens.Count > 0 && !Attributes.Contains(attrs, "axiom") && !Attributes.Contains(attrs, "imported")) { SemErr(t, "a function with an ensures clause must have a body, unless given the :axiom attribute"); } EncodeExternAsAttribute(dmod, ref attrs, id, /* needAxiom */ true); IToken tok = theVerifyThisFile ? id : new IncludeToken(id); if (isPredicate) { f = new Predicate(tok, id.val, dmod.IsStatic, dmod.IsProtected, !isFunctionMethod, typeArgs, formals, reqs, reads, ens, new Specification(decreases, null), body, Predicate.BodyOriginKind.OriginalOrInherited, attrs, signatureEllipsis); } else if (isIndPredicate) { f = new InductivePredicate(tok, id.val, dmod.IsStatic, dmod.IsProtected, typeArgs, formals, reqs, reads, ens, body, attrs, signatureEllipsis); } else if (isCoPredicate) { f = new CoPredicate(tok, id.val, dmod.IsStatic, dmod.IsProtected, typeArgs, formals, reqs, reads, ens, body, attrs, signatureEllipsis); } else { f = new Function(tok, id.val, dmod.IsStatic, dmod.IsProtected, !isFunctionMethod, typeArgs, formals, returnType, reqs, reads, ens, new Specification(decreases, null), body, attrs, signatureEllipsis); } f.BodyStartTok = bodyStart; f.BodyEndTok = bodyEnd; theBuiltIns.CreateArrowTypeDecl(formals.Count); if (isIndPredicate || isCoPredicate) { // also create an arrow type for the corresponding prefix predicate theBuiltIns.CreateArrowTypeDecl(formals.Count + 1); } } void MethodDecl(DeclModifierData dmod, bool allowConstructor, bool isWithinAbstractModule, out Method/*!*/ m) { Contract.Ensures(Contract.ValueAtReturn(out m) !=null); IToken/*!*/ id = Token.NoToken; bool hasName = false; IToken keywordToken; Attributes attrs = null; List/*!*/ typeArgs = new List(); 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 isLemma = false; bool isConstructor = false; bool isIndLemma = false; bool isCoLemma = false; IToken signatureEllipsis = null; IToken bodyStart = Token.NoToken; IToken bodyEnd = Token.NoToken; AllowedDeclModifiers allowed = AllowedDeclModifiers.None; string caption = ""; while (!(StartOf(12))) {SynErr(162); Get();} switch (la.kind) { case 87: { Get(); caption = "Methods"; allowed = AllowedDeclModifiers.Ghost | AllowedDeclModifiers.Static | AllowedDeclModifiers.Extern; break; } case 41: { Get(); isLemma = true; caption = "Lemmas"; allowed = AllowedDeclModifiers.AlreadyGhost | AllowedDeclModifiers.Static | AllowedDeclModifiers.Protected; break; } case 88: { Get(); isCoLemma = true; caption = "Colemmas"; allowed = AllowedDeclModifiers.AlreadyGhost | AllowedDeclModifiers.Static | AllowedDeclModifiers.Protected; break; } case 89: { Get(); isCoLemma = true; caption = "Comethods"; allowed = AllowedDeclModifiers.AlreadyGhost | AllowedDeclModifiers.Static | AllowedDeclModifiers.Protected; errors.Warning(t, "the 'comethod' keyword has been deprecated; it has been renamed to 'colemma'"); break; } case 40: { Get(); Expect(41); isIndLemma = true; caption = "Inductive lemmas"; allowed = AllowedDeclModifiers.AlreadyGhost | AllowedDeclModifiers.Static; break; } case 90: { Get(); if (allowConstructor) { isConstructor = true; } else { SemErr(t, "constructors are allowed only in classes"); } caption = "Constructors"; allowed = AllowedDeclModifiers.None; break; } default: SynErr(163); break; } keywordToken = t; CheckDeclModifiers(dmod, caption, allowed); while (la.kind == 46) { Attribute(ref attrs); } if (la.kind == 1) { NoUSIdent(out id); hasName = true; } if (!hasName) { id = keywordToken; if (!isConstructor) { SemErr(la, "a method must be given a name (expecting identifier)"); } } EncodeExternAsAttribute(dmod, ref attrs, id, /* needAxiom */ true); if (la.kind == 50 || la.kind == 52) { if (la.kind == 52) { GenericParameters(typeArgs); } Formals(true, !dmod.IsGhost, ins); if (la.kind == 86) { Get(); if (isConstructor) { SemErr(t, "constructors cannot have out-parameters"); } Formals(false, !dmod.IsGhost, outs); } } else if (la.kind == 59) { Get(); signatureEllipsis = t; } else SynErr(164); while (StartOf(13)) { MethodSpec(req, mod, ens, dec, ref decAttrs, ref modAttrs); } if (la.kind == 46) { BlockStmt(out body, out bodyStart, out bodyEnd); } if (!isWithinAbstractModule && DafnyOptions.O.DisallowSoundnessCheating && body == null && ens.Count > 0 && !Attributes.Contains(attrs, "axiom") && !Attributes.Contains(attrs, "imported") && !Attributes.Contains(attrs, "decl") && theVerifyThisFile) { SemErr(t, "a method with an ensures clause must have a body, unless given the :axiom attribute"); } IToken tok = theVerifyThisFile ? id : new IncludeToken(id); if (isConstructor) { m = new Constructor(tok, hasName ? id.val : "_ctor", typeArgs, ins, req, new Specification(mod, modAttrs), ens, new Specification(dec, decAttrs), body, attrs, signatureEllipsis); } else if (isIndLemma) { m = new InductiveLemma(tok, id.val, dmod.IsStatic, typeArgs, ins, outs, req, new Specification(mod, modAttrs), ens, new Specification(dec, decAttrs), body, attrs, signatureEllipsis); } else if (isCoLemma) { m = new CoLemma(tok, id.val, dmod.IsStatic, typeArgs, ins, outs, req, new Specification(mod, modAttrs), ens, new Specification(dec, decAttrs), body, attrs, signatureEllipsis); } else if (isLemma) { m = new Lemma(tok, id.val, dmod.IsStatic, typeArgs, ins, outs, req, new Specification(mod, modAttrs), ens, new Specification(dec, decAttrs), body, attrs, signatureEllipsis); } else { m = new Method(tok, id.val, dmod.IsStatic, dmod.IsGhost, typeArgs, ins, outs, req, new Specification(mod, modAttrs), ens, new Specification(dec, decAttrs), body, attrs, signatureEllipsis); } m.BodyStartTok = bodyStart; m.BodyEndTok = bodyEnd; } void DatatypeMemberDecl(List/*!*/ ctors) { Contract.Requires(cce.NonNullElements(ctors)); Attributes attrs = null; IToken/*!*/ id; List formals = new List(); while (la.kind == 46) { Attribute(ref attrs); } NoUSIdent(out id); if (la.kind == 50) { FormalsOptionalIds(formals); } ctors.Add(new DatatypeCtor(id, id.val, formals, attrs)); } void FormalsOptionalIds(List/*!*/ formals) { Contract.Requires(cce.NonNullElements(formals)); IToken/*!*/ id; Type/*!*/ ty; string/*!*/ name; bool isGhost; Expect(50); if (StartOf(14)) { TypeIdentOptional(out id, out name, out ty, out isGhost); formals.Add(new Formal(id, name, ty, true, isGhost)); while (la.kind == 22) { Get(); TypeIdentOptional(out id, out name, out ty, out isGhost); formals.Add(new Formal(id, name, ty, true, isGhost)); } } Expect(51); } void FIdentType(out IToken/*!*/ id, out Type/*!*/ ty) { Contract.Ensures(Contract.ValueAtReturn(out id) != null); Contract.Ensures(Contract.ValueAtReturn(out ty) != null); id = Token.NoToken; if (la.kind == 1) { WildIdent(out id, false); } else if (la.kind == 2) { Get(); id = t; } else SynErr(165); Expect(21); Type(out ty); } void OldSemi() { if (la.kind == 28) { while (!(la.kind == 0 || la.kind == 28)) {SynErr(166); Get();} Get(); } } void Expression(out Expression e, bool allowSemi, bool allowLambda) { Expression e0; IToken endTok; EquivExpression(out e, allowSemi, allowLambda); if (SemiFollowsCall(allowSemi, e)) { Expect(28); endTok = t; Expression(out e0, allowSemi, allowLambda); e = new StmtExpr(e.tok, new UpdateStmt(e.tok, endTok, new List(), new List() { new ExprRhs(e, null) }), e0); } } void GIdentType(bool allowGhostKeyword, out IToken/*!*/ id, out Type/*!*/ ty, out bool isGhost) { Contract.Ensures(Contract.ValueAtReturn(out id)!=null); Contract.Ensures(Contract.ValueAtReturn(out ty)!=null); isGhost = false; if (la.kind == 62) { Get(); if (allowGhostKeyword) { isGhost = true; } else { SemErr(t, "formal cannot be declared 'ghost' in this context"); } } IdentType(out id, out ty, true); } void IdentType(out IToken/*!*/ id, out Type/*!*/ ty, bool allowWildcardId) { Contract.Ensures(Contract.ValueAtReturn(out id) != null); Contract.Ensures(Contract.ValueAtReturn(out ty) != null); WildIdent(out id, allowWildcardId); Expect(21); Type(out ty); } void WildIdent(out IToken x, bool allowWildcardId) { Contract.Ensures(Contract.ValueAtReturn(out x) != null); Expect(1); x = t; t.val = UnwildIdent(t.val, allowWildcardId); } void LocalIdentTypeOptional(out LocalVariable var, bool isGhost) { IToken id; Type ty; Type optType = null; WildIdent(out id, true); if (la.kind == 21) { Get(); Type(out ty); optType = ty; } var = new LocalVariable(id, id, id.val, optType == null ? new InferredTypeProxy() : optType, isGhost); } void IdentTypeOptional(out BoundVar var) { Contract.Ensures(Contract.ValueAtReturn(out var) != null); IToken id; Type ty; Type optType = null; WildIdent(out id, true); if (la.kind == 21) { Get(); Type(out ty); optType = ty; } var = new BoundVar(id, id.val, optType == null ? new InferredTypeProxy() : optType); } void TypeIdentOptional(out IToken/*!*/ id, out string/*!*/ identName, out Type/*!*/ ty, out bool isGhost) { Contract.Ensures(Contract.ValueAtReturn(out id)!=null); Contract.Ensures(Contract.ValueAtReturn(out ty)!=null); Contract.Ensures(Contract.ValueAtReturn(out identName)!=null); string name = null; id = Token.NoToken; ty = new BoolType()/*dummy*/; isGhost = false; if (la.kind == 62) { Get(); isGhost = true; } if (StartOf(5)) { TypeAndToken(out id, out ty); if (la.kind == 21) { Get(); 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(out ty); } } else if (la.kind == 2) { Get(); id = t; name = id.val; Expect(21); Type(out ty); } else SynErr(167); if (name != null) { identName = name; } else { identName = "#" + anonymousIds++; } } void TypeAndToken(out IToken tok, out Type ty) { 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 tupleArgTypes = null; switch (la.kind) { case 6: { Get(); tok = t; break; } case 7: { Get(); tok = t; ty = new CharType(); break; } case 9: { Get(); tok = t; ty = new NatType(); break; } case 8: { Get(); tok = t; ty = new IntType(); break; } case 10: { Get(); tok = t; ty = new RealType(); break; } case 11: { Get(); tok = t; ty = new ObjectType(); break; } case 13: { Get(); tok = t; gt = new List(); if (la.kind == 52) { GenericInstantiation(gt); } if (gt.Count > 1) { SemErr("set type expects only one type argument"); } ty = new SetType(true, gt.Count == 1 ? gt[0] : null); break; } case 14: { Get(); tok = t; gt = new List(); if (la.kind == 52) { GenericInstantiation(gt); } if (gt.Count > 1) { SemErr("set type expects only one type argument"); } ty = new SetType(false, gt.Count == 1 ? gt[0] : null); break; } case 15: { Get(); tok = t; gt = new List(); if (la.kind == 52) { GenericInstantiation(gt); } if (gt.Count > 1) { SemErr("multiset type expects only one type argument"); } ty = new MultiSetType(gt.Count == 1 ? gt[0] : null); break; } case 16: { Get(); tok = t; gt = new List(); if (la.kind == 52) { GenericInstantiation(gt); } if (gt.Count > 1) { SemErr("seq type expects only one type argument"); } ty = new SeqType(gt.Count == 1 ? gt[0] : null); break; } case 12: { Get(); tok = t; ty = new UserDefinedType(tok, tok.val, null); break; } case 17: { Get(); tok = t; gt = new List(); if (la.kind == 52) { GenericInstantiation(gt); } if (gt.Count == 0) { ty = new MapType(true, null, null); } else if (gt.Count != 2) { SemErr("map type expects two type arguments"); ty = new MapType(true, gt[0], gt.Count == 1 ? new InferredTypeProxy() : gt[1]); } else { ty = new MapType(true, gt[0], gt[1]); } break; } case 18: { Get(); tok = t; gt = new List(); if (la.kind == 52) { GenericInstantiation(gt); } if (gt.Count == 0) { ty = new MapType(false, null, null); } else if (gt.Count != 2) { SemErr("imap type expects two type arguments"); ty = new MapType(false, gt[0], gt.Count == 1 ? new InferredTypeProxy() : gt[1]); } else { ty = new MapType(false, gt[0], gt[1]); } break; } case 5: { Get(); tok = t; gt = null; if (la.kind == 52) { gt = new List(); GenericInstantiation(gt); } int dims = tok.val.Length == 5 ? 1 : int.Parse(tok.val.Substring(5)); ty = theBuiltIns.ArrayType(tok, dims, gt, true); break; } case 50: { Get(); tok = t; tupleArgTypes = new List(); if (StartOf(5)) { Type(out ty); tupleArgTypes.Add(ty); while (la.kind == 22) { Get(); Type(out ty); tupleArgTypes.Add(ty); } } Expect(51); if (tupleArgTypes.Count == 1) { // just return the type 'ty' } else { var dims = tupleArgTypes.Count; var tmp = theBuiltIns.TupleType(tok, dims, true); // make sure the tuple type exists ty = new UserDefinedType(tok, BuiltIns.TupleTypeName(dims), dims == 0 ? null : tupleArgTypes); } break; } case 1: { Expression e; tok = t; NameSegmentForTypeName(out e); tok = t; while (la.kind == 27) { Get(); Expect(1); tok = t; List typeArgs = null; if (la.kind == 52) { typeArgs = new List(); GenericInstantiation(typeArgs); } e = new ExprDotName(tok, e, tok.val, typeArgs); } ty = new UserDefinedType(e.tok, e); break; } default: SynErr(168); break; } if (la.kind == 30) { Type t2; Get(); tok = t; Type(out t2); if (tupleArgTypes != null) { gt = tupleArgTypes; } else { gt = new List{ ty }; } ty = new ArrowType(tok, gt, t2); theBuiltIns.CreateArrowTypeDecl(gt.Count); } } void Formals(bool incoming, bool allowGhostKeyword, List formals) { Contract.Requires(cce.NonNullElements(formals)); IToken id; Type ty; bool isGhost; Expect(50); if (la.kind == 1 || la.kind == 62) { GIdentType(allowGhostKeyword, out id, out ty, out isGhost); formals.Add(new Formal(id, id.val, ty, incoming, isGhost)); while (la.kind == 22) { Get(); GIdentType(allowGhostKeyword, out id, out ty, out isGhost); formals.Add(new Formal(id, id.val, ty, incoming, isGhost)); } } Expect(51); } void IteratorSpec(List/*!*/ reads, List/*!*/ mod, List decreases, List/*!*/ req, List/*!*/ ens, List/*!*/ yieldReq, List/*!*/ yieldEns, ref Attributes readsAttrs, ref Attributes modAttrs, ref Attributes decrAttrs) { Expression/*!*/ e; FrameExpression/*!*/ fe; bool isFree = false; bool isYield = false; Attributes ensAttrs = null; while (!(StartOf(15))) {SynErr(169); Get();} if (la.kind == 44) { Get(); while (IsAttribute()) { Attribute(ref readsAttrs); } FrameExpression(out fe, false, false); reads.Add(fe); while (la.kind == 22) { Get(); FrameExpression(out fe, false, false); reads.Add(fe); } OldSemi(); } else if (la.kind == 43) { Get(); while (IsAttribute()) { Attribute(ref modAttrs); } FrameExpression(out fe, false, false); mod.Add(fe); while (la.kind == 22) { Get(); FrameExpression(out fe, false, false); mod.Add(fe); } OldSemi(); } else if (StartOf(16)) { if (la.kind == 91) { Get(); isFree = true; errors.Warning(t, "the 'free' keyword is soon to be deprecated"); } if (la.kind == 93) { Get(); isYield = true; } if (la.kind == 45) { Get(); Expression(out e, false, false); OldSemi(); if (isYield) { yieldReq.Add(new MaybeFreeExpression(e, isFree)); } else { req.Add(new MaybeFreeExpression(e, isFree)); } } else if (la.kind == 92) { Get(); while (IsAttribute()) { Attribute(ref ensAttrs); } Expression(out e, false, false); OldSemi(); if (isYield) { yieldEns.Add(new MaybeFreeExpression(e, isFree, ensAttrs)); } else { ens.Add(new MaybeFreeExpression(e, isFree, ensAttrs)); } } else SynErr(170); } else if (la.kind == 36) { Get(); while (IsAttribute()) { Attribute(ref decrAttrs); } DecreasesList(decreases, false, false); OldSemi(); } else SynErr(171); } void BlockStmt(out BlockStmt/*!*/ block, out IToken bodyStart, out IToken bodyEnd) { Contract.Ensures(Contract.ValueAtReturn(out block) != null); List body = new List(); Expect(46); bodyStart = t; while (StartOf(17)) { Stmt(body); } Expect(47); bodyEnd = t; block = new BlockStmt(bodyStart, bodyEnd, body); } void 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; while (!(StartOf(18))) {SynErr(172); Get();} if (la.kind == 43) { Get(); while (IsAttribute()) { Attribute(ref modAttrs); } FrameExpression(out fe, false, false); mod.Add(fe); while (la.kind == 22) { Get(); FrameExpression(out fe, false, false); mod.Add(fe); } OldSemi(); } else if (la.kind == 45 || la.kind == 91 || la.kind == 92) { if (la.kind == 91) { Get(); isFree = true; errors.Warning(t, "the 'free' keyword is soon to be deprecated"); } if (la.kind == 45) { Get(); Expression(out e, false, false); OldSemi(); req.Add(new MaybeFreeExpression(e, isFree)); } else if (la.kind == 92) { Get(); while (IsAttribute()) { Attribute(ref ensAttrs); } Expression(out e, false, false); OldSemi(); ens.Add(new MaybeFreeExpression(e, isFree, ensAttrs)); } else SynErr(173); } else if (la.kind == 36) { Get(); while (IsAttribute()) { Attribute(ref decAttrs); } DecreasesList(decreases, true, false); OldSemi(); } else SynErr(174); } void FrameExpression(out FrameExpression fe, bool allowSemi, bool allowLambda) { Contract.Ensures(Contract.ValueAtReturn(out fe) != null); Expression/*!*/ e; IToken/*!*/ id; string fieldName = null; IToken feTok = null; fe = null; if (StartOf(9)) { Expression(out e, allowSemi, allowLambda); feTok = e.tok; if (la.kind == 94) { Get(); Ident(out id); fieldName = id.val; feTok = id; } fe = new FrameExpression(feTok, e, fieldName); } else if (la.kind == 94) { Get(); Ident(out id); fieldName = id.val; fe = new FrameExpression(id, new ImplicitThisExpr(id), fieldName); } else SynErr(175); } void DecreasesList(List decreases, bool allowWildcard, bool allowLambda) { Expression e; PossiblyWildExpression(out e, allowLambda); if (!allowWildcard && e is WildcardExpr) { SemErr(e.tok, "'decreases *' is allowed only on loops and tail-recursive methods"); } else { decreases.Add(e); } while (la.kind == 22) { Get(); PossiblyWildExpression(out e, allowLambda); if (!allowWildcard && e is WildcardExpr) { SemErr(e.tok, "'decreases *' is allowed only on loops and tail-recursive methods"); } else { decreases.Add(e); } } } void GenericInstantiation(List/*!*/ gt) { Contract.Requires(cce.NonNullElements(gt)); Type/*!*/ ty; Expect(52); Type(out ty); gt.Add(ty); while (la.kind == 22) { Get(); Type(out ty); gt.Add(ty); } Expect(53); } void NameSegmentForTypeName(out Expression e) { IToken id; List typeArgs = null; Ident(out id); if (la.kind == 52) { typeArgs = new List(); GenericInstantiation(typeArgs); } e = new NameSegment(id, id.val, typeArgs); } void 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; while (!(StartOf(19))) {SynErr(176); Get();} if (la.kind == 45) { Get(); Expression(out e, false, false); OldSemi(); reqs.Add(e); } else if (la.kind == 44) { Get(); PossiblyWildFrameExpression(out fe, false); reads.Add(fe); while (la.kind == 22) { Get(); PossiblyWildFrameExpression(out fe, false); reads.Add(fe); } OldSemi(); } else if (la.kind == 92) { Get(); Expression(out e, false, false); OldSemi(); ens.Add(e); } else if (la.kind == 36) { Get(); if (decreases == null) { SemErr(t, "'decreases' clauses are meaningless for copredicates, so they are not allowed"); decreases = new List(); } DecreasesList(decreases, false, false); OldSemi(); } else SynErr(177); } void FunctionBody(out Expression/*!*/ e, out IToken bodyStart, out IToken bodyEnd) { Contract.Ensures(Contract.ValueAtReturn(out e) != null); e = dummyExpr; Expect(46); bodyStart = t; Expression(out e, true, true); Expect(47); bodyEnd = t; } void PossiblyWildFrameExpression(out FrameExpression fe, bool allowSemi) { Contract.Ensures(Contract.ValueAtReturn(out fe) != null); fe = dummyFrameExpr; if (la.kind == 57) { Get(); fe = new FrameExpression(t, new WildcardExpr(t), null); } else if (StartOf(20)) { FrameExpression(out fe, allowSemi, false); } else SynErr(178); } void PossiblyWildExpression(out Expression e, bool allowLambda) { Contract.Ensures(Contract.ValueAtReturn(out e)!=null); e = dummyExpr; if (la.kind == 57) { Get(); e = new WildcardExpr(t); } else if (StartOf(9)) { Expression(out e, false, allowLambda); } else SynErr(179); } void Stmt(List/*!*/ ss) { Statement/*!*/ s; OneStmt(out s); ss.Add(s); } void OneStmt(out Statement/*!*/ s) { 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; while (!(StartOf(21))) {SynErr(180); Get();} switch (la.kind) { case 46: { BlockStmt(out bs, out bodyStart, out bodyEnd); s = bs; break; } case 104: { AssertStmt(out s); break; } case 31: { AssumeStmt(out s); break; } case 105: { PrintStmt(out s); break; } case 1: case 2: case 3: case 4: case 8: case 10: case 19: case 20: case 23: case 50: case 133: case 134: case 135: case 136: case 137: case 138: { UpdateStmt(out s); break; } case 62: case 81: { VarDeclStatement(out s); break; } case 101: { IfStmt(out s); break; } case 102: { WhileStmt(out s); break; } case 103: { MatchStmt(out s); break; } case 106: case 107: { ForallStmt(out s); break; } case 32: { CalcStmt(out s); break; } case 108: { ModifyStmt(out s); break; } case 95: { Get(); x = t; NoUSIdent(out id); Expect(21); OneStmt(out s); s.Labels = new LList