/*----------------------------------------------------------------------------- // // 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; COMPILER Dafny /*--------------------------------------------------------------------------*/ static List! theModules = new List(); static Expression! dummyExpr = new LiteralExpr(Token.NoToken); static Statement! dummyStmt = new ReturnStmt(Token.NoToken); static Attributes.Argument! dummyAttrArg = new Attributes.Argument("dummyAttrArg"); static Scope! parseVarScope = new Scope(); static int anonymousIds = 0; struct MemberModifiers { public bool IsGhost; public bool IsStatic; public bool IsUnlimited; } // helper routine for parsing call statements private static void RecordCallLhs(IdentifierExpr! e, List! lhs, List! newVars) { int index = lhs.Count; lhs.Add(e); if (parseVarScope.Find(e.Name) == null) { AutoVarDecl d = new AutoVarDecl(e.tok, e.Name, new InferredTypeProxy(), index); newVars.Add(d); parseVarScope.Push(e.Name, e.Name); } } // helper routine for parsing call statements private static Expression! ConvertToLocal(Expression! e) { FieldSelectExpr fse = e as FieldSelectExpr; if (fse != null && fse.Obj is ImplicitThisExpr) { return new IdentifierExpr(fse.tok, fse.FieldName); } return e; // cannot convert to IdentifierExpr (or is already an IdentifierExpr) } /// /// Parses top-level things (modules, classes, datatypes, class members) from "filename" /// and appends them in appropriate form to "modules". /// Returns the number of parsing errors encountered. /// Note: first initialize the Scanner. /// public static int Parse (string! filename, List! modules) /* throws System.IO.IOException */ { if (filename == "stdin.dfy") { BoogiePL.Buffer.Fill(System.Console.In); Scanner.Init(filename); return Parse(modules); } else { using (System.IO.StreamReader reader = new System.IO.StreamReader(filename)) { BoogiePL.Buffer.Fill(reader); Scanner.Init(filename); return Parse(modules); } } } /// /// Parses top-level things (modules, classes, datatypes, class members) /// and appends them in appropriate form to "modules". /// Returns the number of parsing errors encountered. /// Note: first initialize the Scanner. /// public static int Parse (List! modules) { List oldModules = theModules; theModules = modules; Parse(); theModules = oldModules; return Errors.count; } /*--------------------------------------------------------------------------*/ CHARACTERS letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz". digit = "0123456789". special = "'_?`\\". glyph = "`~!@#$%^&*()-_=+[{]}|;:',<.>/?\\". cr = '\r'. lf = '\n'. tab = '\t'. space = ' '. quote = '"'. nondigit = letter + special. nonquote = letter + digit + space + glyph. /*------------------------------------------------------------------------*/ TOKENS ident = nondigit {nondigit | digit}. digits = digit {digit}. string = quote {nonquote} quote. COMMENTS FROM "/*" TO "*/" NESTED COMMENTS FROM "//" TO lf IGNORE cr + lf + tab /*------------------------------------------------------------------------*/ PRODUCTIONS Dafny = (. ClassDecl! c; DatatypeDecl! dt; Attributes attrs; Token! id; List theImports; List membersDefaultClass = new List(); ModuleDecl module; DefaultModuleDecl defaultModule = new DefaultModuleDecl(); .) { "module" (. attrs = null; theImports = new List(); .) { Attribute } Ident [ "imports" Idents ] (. module = new ModuleDecl(id, id.val, theImports, attrs); .) "{" { ClassDecl (. module.TopLevelDecls.Add(c); .) | DatatypeDecl (. module.TopLevelDecls.Add(dt); .) } (. theModules.Add(module); .) "}" | ClassDecl (. defaultModule.TopLevelDecls.Add(c); .) | DatatypeDecl (. defaultModule.TopLevelDecls.Add(dt); .) | ClassMemberDecl } (. defaultModule.TopLevelDecls.Add(new DefaultClassDecl(defaultModule, membersDefaultClass)); theModules.Add(defaultModule); .) EOF . ClassDecl = (. Token! id; Attributes attrs = null; List typeArgs = new List(); List members = new List(); .) "class" { Attribute } Ident [ GenericParameters ] "{" { ClassMemberDecl } "}" (. c = new ClassDecl(id, id.val, module, typeArgs, members, attrs); .) . ClassMemberDecl! mm> = (. Method! m; Function! f; MemberModifiers mmod = new MemberModifiers(); .) { "ghost" (. mmod.IsGhost = true; .) | "static" (. mmod.IsStatic = true; .) | "unlimited" (. mmod.IsUnlimited = true; .) } ( FieldDecl | FunctionDecl (. mm.Add(f); .) | MethodDecl (. mm.Add(m); .) ) . DatatypeDecl = (. Token! id; Attributes attrs = null; List typeArgs = new List(); List ctors = new List(); .) "datatype" { Attribute } Ident [ GenericParameters ] "{" { DatatypeMemberDecl } "}" (. dt = new DatatypeDecl(id, id.val, module, typeArgs, ctors, attrs); .) . DatatypeMemberDecl! ctors> = (. Attributes attrs = null; Token! id; List typeArgs = new List(); List formals = new List(); .) { Attribute } Ident [ GenericParameters ] (. parseVarScope.PushMarker(); .) [ FormalsOptionalIds ] (. parseVarScope.PopMarker(); ctors.Add(new DatatypeCtor(id, id.val, typeArgs, formals, attrs)); .) ";" . FieldDecl! mm> = (. Attributes attrs = null; Token! id; Type! ty; .) "var" (. if (mmod.IsUnlimited) { SemErr(token, "fields cannot be declared 'unlimited'"); } if (mmod.IsStatic) { SemErr(token, "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)); .) } ";" . GIdentType /* isGhost always returns as false if allowGhost is false */ = (. isGhost = false; .) [ "ghost" (. if (allowGhost) { isGhost = true; } else { SemErr(token, "formal cannot be declared 'ghost' in this context"); } .) ] IdentType . IdentType = Ident ":" Type . IdentTypeOptional = (. Token! id; Type! ty; Type optType = null; .) Ident [ ":" Type (. optType = ty; .) ] (. var = new BoundVar(id, id.val, optType == null ? new InferredTypeProxy() : optType); .) . TypeIdentOptional = (. 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! typeArgs> = (. Token! id; .) "<" Ident (. typeArgs.Add(new TypeParameter(id, id.val)); .) { "," Ident (. typeArgs.Add(new TypeParameter(id, id.val)); .) } ">" . /*------------------------------------------------------------------------*/ MethodDecl = (. Token! id; 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(); Statement! bb; BlockStmt body = null; .) "method" (. if (mmod.IsUnlimited) { SemErr(token, "methods cannot be declared 'unlimited'"); } .) { Attribute } Ident [ GenericParameters ] (. parseVarScope.PushMarker(); .) Formals [ "returns" Formals ] ( ";" { MethodSpec } | { MethodSpec } BlockStmt (. body = (BlockStmt)bb; .) ) (. parseVarScope.PopMarker(); m = new Method(id, id.val, mmod.IsStatic, mmod.IsGhost, typeArgs, ins, outs, req, mod, ens, dec, body, attrs); .) . MethodSpec! req, List! mod, List! ens, List! decreases> = (. Expression! e; bool isFree = false; .) ( "modifies" [ Expression (. mod.Add(e); .) { "," Expression (. mod.Add(e); .) } ] ";" | [ "free" (. isFree = true; .) ] ( "requires" Expression ";" (. req.Add(new MaybeFreeExpression(e, isFree)); .) | "ensures" Expression ";" (. ens.Add(new MaybeFreeExpression(e, isFree)); .) ) | "decreases" Expressions ";" ) . Formals! formals> = (. Token! id; Type! ty; bool isGhost; .) "(" [ GIdentType (. formals.Add(new Formal(id, id.val, ty, incoming, isGhost)); parseVarScope.Push(id.val, id.val); .) { "," GIdentType (. formals.Add(new Formal(id, id.val, ty, incoming, isGhost)); parseVarScope.Push(id.val, id.val); .) } ] ")" . FormalsOptionalIds! formals> = (. Token! id; Type! ty; string! name; bool isGhost; .) "(" [ TypeIdentOptional (. formals.Add(new Formal(id, name, ty, true, isGhost)); parseVarScope.Push(name, name); .) { "," TypeIdentOptional (. formals.Add(new Formal(id, name, ty, true, isGhost)); parseVarScope.Push(name, name); .) } ] ")" . /*------------------------------------------------------------------------*/ Type = (. Token! tok; .) TypeAndToken . TypeAndToken = (. tok = Token.NoToken; ty = new BoolType(); /*keep compiler happy*/ List! gt; .) ( "bool" (. tok = token; .) | "int" (. tok = token; ty = new IntType(); .) | "set" (. tok = token; gt = new List(); .) GenericInstantiation (. if (gt.Count != 1) { SemErr("set type expects exactly one type argument"); } ty = new SetType(gt[0]); .) | "seq" (. tok = token; gt = new List(); .) GenericInstantiation (. if (gt.Count != 1) { SemErr("seq type expects exactly one type argument"); } ty = new SeqType(gt[0]); .) | ReferenceType ) . ReferenceType = (. tok = Token.NoToken; ty = new BoolType(); /*keep compiler happy*/ List! gt; .) ( "object" (. tok = token; ty = new ObjectType(); .) | Ident (. gt = new List(); .) [ GenericInstantiation ] (. ty = new UserDefinedType(tok, tok.val, gt); .) ) . GenericInstantiation! gt> = (. Type! ty; .) "<" Type (. gt.Add(ty); .) { "," Type (. gt.Add(ty); .) } ">" . /*------------------------------------------------------------------------*/ FunctionDecl = (. Attributes attrs = null; Token! id; List typeArgs = new List(); List formals = new List(); Type! returnType; List reqs = new List(); List reads = new List(); List decreases = new List(); Expression! bb; Expression body = null; bool isFunctionMethod = false; .) "function" [ "method" (. isFunctionMethod = true; .) ] (. if (mmod.IsGhost) { SemErr(token, "functions cannot be declared 'ghost' (they are ghost by default)"); } .) { Attribute } Ident [ GenericParameters ] (. parseVarScope.PushMarker(); .) Formals ":" Type ( ";" { FunctionSpec } | { FunctionSpec } FunctionBody (. body = bb; .) ) (. parseVarScope.PopMarker(); f = new Function(id, id.val, mmod.IsStatic, !isFunctionMethod, mmod.IsUnlimited, typeArgs, formals, returnType, reqs, reads, decreases, body, attrs); .) . FunctionSpec! reqs, List! reads, List! decreases> = (. Expression! e; .) ( "requires" Expression ";" (. reqs.Add(e); .) | "reads" [ PossiblyWildExpressions ] ";" | "decreases" Expressions ";" ) . PossiblyWildExpressions! args> = (. Expression! e; .) PossiblyWildExpression (. args.Add(e); .) { "," PossiblyWildExpression (. args.Add(e); .) } . PossiblyWildExpression = (. e = dummyExpr; .) /* 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). */ /* 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(token); .) | Expression ) . FunctionBody = (. e = dummyExpr; .) "{" ( MatchExpression | Expression ) "}" . MatchExpression = (. Token! x; MatchCaseExpr! c; List cases = new List(); .) "match" (. x = token; .) Expression { CaseExpression (. cases.Add(c); .) } (. e = new MatchExpr(x, e, cases); .) . CaseExpression = (. Token! x, id, arg; List arguments = new List(); Expression! body; .) "case" (. x = token; parseVarScope.PushMarker(); .) Ident [ "(" Ident (. arguments.Add(new BoundVar(arg, arg.val, new InferredTypeProxy())); parseVarScope.Push(arg.val, arg.val); .) { "," Ident (. arguments.Add(new BoundVar(arg, arg.val, new InferredTypeProxy())); parseVarScope.Push(arg.val, arg.val); .) } ")" ] "=>" Expression (. c = new MatchCaseExpr(x, id.val, arguments, body); parseVarScope.PopMarker(); .) . /*------------------------------------------------------------------------*/ BlockStmt = (. Token! x; List body = new List(); Statement! s; .) (. parseVarScope.PushMarker(); .) "{" (. x = token; .) { Stmt } "}" (. block = new BlockStmt(x, body); .) (. parseVarScope.PopMarker(); .) . Stmt! ss> = (. Statement! s; .) /* By first reading a sequence of block statements, we avoid problems in the generated parser, despite the ambiguity in the grammar. See Note in ConstAtomExpression production. */ { BlockStmt (. ss.Add(s); .) } ( OneStmt (. ss.Add(s); .) | VarDeclStmts ) . OneStmt = (. Token! x; Token! id; string label = null; s = dummyStmt; /* to please the compiler */ .) /* This list does not contain BlockStmt, see comment above in Stmt production. */ ( AssertStmt | AssumeStmt | UseStmt | PrintStmt | AssignStmt | HavocStmt | CallStmt | IfStmt | WhileStmt | MatchStmt | ForeachStmt | "label" (. x = token; .) Ident ":" (. s = new LabelStmt(x, id.val); .) | "break" (. x = token; .) [ Ident (. label = id.val; .) ] ";" (. s = new BreakStmt(x, label); .) | "return" (. x = token; .) ";" (. s = new ReturnStmt(x); .) ) . AssignStmt = (. Token! x; Expression! lhs; Expression rhs; Type ty; s = dummyStmt; .) LhsExpr ":=" (. x = token; .) AssignRhs (. if (rhs != null) { s = new AssignStmt(x, lhs, rhs); } else { assert ty != null; s = new AssignStmt(x, lhs, ty); } .) ";" . AssignRhs /* ensures e == null <==> ty == null; */ = (. Token! x; Expression! ee; Type! tt; e = null; ty = null; .) ( "new" ReferenceType (. ty = tt; .) | Expression (. e = ee; .) ) (. if (e == null && ty == null) { e = dummyExpr; } .) . HavocStmt = (. Token! x; Expression! lhs; .) "havoc" (. x = token; .) LhsExpr ";" (. s = new AssignStmt(x, lhs); .) . LhsExpr = SelectExpression . VarDeclStmts! ss> = (. VarDecl! d; bool isGhost = false; .) [ "ghost" (. isGhost = true; .) ] "var" IdentTypeRhs (. ss.Add(d); parseVarScope.Push(d.Name, d.Name); .) { "," IdentTypeRhs (. ss.Add(d); parseVarScope.Push(d.Name, d.Name); .) } ";" . IdentTypeRhs = (. Token! id; Type! ty; Expression! e; Expression rhs = null; Type newType = null; Type optionalType = null; DeterminedAssignmentRhs optionalRhs = null; .) Ident [ ":" Type (. optionalType = ty; .) ] [ ":=" AssignRhs ] (. if (rhs != null) { assert newType == null; optionalRhs = new ExprRhs(rhs); } else if (newType != null) { optionalRhs = new TypeRhs(newType); } else if (optionalType == null) { optionalType = new InferredTypeProxy(); } d = new VarDecl(id, id.val, optionalType, isGhost, optionalRhs); .) . IfStmt = (. Token! x; Expression guard; Statement! thn; Statement! s; Statement els = null; .) "if" (. x = token; .) Guard BlockStmt [ "else" ( IfStmt (. els = s; .) | BlockStmt (. els = s; .) ) ] (. ifStmt = new IfStmt(x, guard, thn, els); .) . WhileStmt = (. Token! x; Expression guard; bool isFree; Expression! e; List invariants = new List(); List decreases = new List(); Statement! body; .) "while" (. x = token; .) Guard (. assume guard == null || Owner.None(guard); .) { (. isFree = false; .) [ "free" (. isFree = true; .) ] "invariant" Expression (. invariants.Add(new MaybeFreeExpression(e, isFree)); .) ";" | "decreases" PossiblyWildExpressions ";" } BlockStmt (. stmt = new WhileStmt(x, guard, invariants, decreases, body); .) . Guard /* null represents demonic-choice */ = (. Expression! ee; e = null; .) "(" ( "*" (. e = null; .) | Expression (. e = ee; .) ) ")" . MatchStmt = (. Token x; Expression! e; MatchCaseStmt! c; List cases = new List(); .) "match" (. x = token; .) Expression "{" { CaseStatement (. cases.Add(c); .) } "}" (. s = new MatchStmt(x, e, cases); .) . CaseStatement = (. Token! x, id, arg; List arguments = new List(); List body = new List(); .) "case" (. x = token; parseVarScope.PushMarker(); .) Ident [ "(" Ident (. arguments.Add(new BoundVar(arg, arg.val, new InferredTypeProxy())); parseVarScope.Push(arg.val, arg.val); .) { "," Ident (. arguments.Add(new BoundVar(arg, arg.val, new InferredTypeProxy())); parseVarScope.Push(arg.val, arg.val); .) } ")" ] "=>" (. parseVarScope.PushMarker(); .) { Stmt } (. parseVarScope.PopMarker(); .) (. c = new MatchCaseStmt(x, id.val, arguments, body); .) (. parseVarScope.PopMarker(); .) . CallStmt = (. Token! x, id; Expression! e; List lhs = new List(); List newVars = new List(); .) "call" (. x = token; .) CallStmtSubExpr [ "," /* call a,b,c,... := ... */ (. e = ConvertToLocal(e); if (e is IdentifierExpr) { RecordCallLhs((IdentifierExpr)e, lhs, newVars); } else if (e is FieldSelectExpr) { SemErr(e.tok, "each LHS of call statement must be a variable, not a field"); } else { SemErr(e.tok, "each LHS of call statement must be a variable"); } .) Ident (. RecordCallLhs(new IdentifierExpr(id, id.val), lhs, newVars); .) { "," Ident (. RecordCallLhs(new IdentifierExpr(id, id.val), lhs, newVars); .) } ":=" CallStmtSubExpr | ":=" /* call a := ... */ (. e = ConvertToLocal(e); if (e is IdentifierExpr) { RecordCallLhs((IdentifierExpr)e, lhs, newVars); } else if (e is FieldSelectExpr) { SemErr(e.tok, "each LHS of call statement must be a variable, not a field"); } else { SemErr(e.tok, "each LHS of call statement must be a variable"); } .) CallStmtSubExpr ] ";" /* "e" has now been parsed as one of: IdentifierExpr, FunctionCallExpr, FieldSelectExpr. It denotes the RHS, so to be legal it must be a FunctionCallExpr. */ (. if (e is FunctionCallExpr) { FunctionCallExpr fce = (FunctionCallExpr)e; s = new CallStmt(x, newVars, lhs, fce.Receiver, fce.Name, fce.Args); // this actually does an ownership transfer of fce.Args } else { SemErr("RHS of call statement must denote a method invocation"); s = new CallStmt(x, newVars, lhs, dummyExpr, "dummyMethodName", new List()); } .) . /*------------------------------------------------------------------------*/ ForeachStmt = (. Token! x, boundVar; Type! ty; Expression! collection; Expression! range; List bodyPrefix = new List(); AssignStmt bodyAssign = null; .) (. parseVarScope.PushMarker(); .) "foreach" (. x = token; range = new LiteralExpr(x, true); ty = new InferredTypeProxy(); .) "(" Ident [ ":" Type ] "in" Expression (. parseVarScope.Push(boundVar.val, boundVar.val); .) [ "|" Expression ] ")" "{" { AssertStmt (. if (s is PredicateStmt) { bodyPrefix.Add((PredicateStmt)s); } .) | AssumeStmt (. if (s is PredicateStmt) { bodyPrefix.Add((PredicateStmt)s); } .) | UseStmt (. if (s is PredicateStmt) { bodyPrefix.Add((PredicateStmt)s); } .) } ( AssignStmt (. if (s is AssignStmt) { bodyAssign = (AssignStmt)s; } .) | HavocStmt (. if (s is AssignStmt) { bodyAssign = (AssignStmt)s; } .) ) "}" (. if (bodyAssign != null) { s = new ForeachStmt(x, new BoundVar(boundVar, boundVar.val, ty), collection, range, bodyPrefix, bodyAssign); } else { s = dummyStmt; // some error occurred in parsing the bodyAssign } .) (. parseVarScope.PopMarker(); .) . AssertStmt = (. Token! x; Expression! e; .) "assert" (. x = token; .) Expression ";" (. s = new AssertStmt(x, e); .) . AssumeStmt = (. Token! x; Expression! e; .) "assume" (. x = token; .) Expression ";" (. s = new AssumeStmt(x, e); .) . UseStmt = (. Token! x; Expression! e; .) "use" (. x = token; .) Expression ";" (. s = new UseStmt(x, e); .) . PrintStmt = (. Token! x; Attributes.Argument! arg; List args = new List(); .) "print" (. x = token; .) AttributeArg (. args.Add(arg); .) { "," AttributeArg (. args.Add(arg); .) } ";" (. s = new PrintStmt(x, args); .) . /*------------------------------------------------------------------------*/ Expression = (. Token! x; Expression! e0; Expression! e1 = dummyExpr; e = dummyExpr; .) ( "if" (. x = token; .) Expression "then" Expression "else" Expression (. e = new ITEExpr(x, e, e0, e1); .) | EquivExpression ) . /*------------------------------------------------------------------------*/ EquivExpression = (. Token! x; Expression! e1; .) ImpliesExpression { EquivOp (. x = token; .) ImpliesExpression (. e0 = new BinaryExpr(x, BinaryExpr.Opcode.Iff, e0, e1); .) } . EquivOp = "<==>" | '\u21d4'. /*------------------------------------------------------------------------*/ ImpliesExpression = (. Token! x; Expression! e1; .) LogicalExpression [ ImpliesOp (. x = token; .) ImpliesExpression (. e0 = new BinaryExpr(x, BinaryExpr.Opcode.Imp, e0, e1); .) ] . ImpliesOp = "==>" | '\u21d2'. /*------------------------------------------------------------------------*/ LogicalExpression = (. Token! x; Expression! e1; .) RelationalExpression [ AndOp (. x = token; .) RelationalExpression (. e0 = new BinaryExpr(x, BinaryExpr.Opcode.And, e0, e1); .) { AndOp (. x = token; .) RelationalExpression (. e0 = new BinaryExpr(x, BinaryExpr.Opcode.And, e0, e1); .) } | OrOp (. x = token; .) RelationalExpression (. e0 = new BinaryExpr(x, BinaryExpr.Opcode.Or, e0, e1); .) { OrOp (. x = token; .) RelationalExpression (. e0 = new BinaryExpr(x, BinaryExpr.Opcode.Or, e0, e1); .) } ] . AndOp = "&&" | '\u2227'. OrOp = "||" | '\u2228'. /*------------------------------------------------------------------------*/ RelationalExpression = (. Token! x; Expression! e1; BinaryExpr.Opcode op; .) Term [ RelOp Term (. e0 = new BinaryExpr(x, op, e0, e1); .) ] . RelOp = (. x = Token.NoToken; op = BinaryExpr.Opcode.Add/*(dummy)*/; .) ( "==" (. x = token; op = BinaryExpr.Opcode.Eq; .) | "<" (. x = token; op = BinaryExpr.Opcode.Lt; .) | ">" (. x = token; op = BinaryExpr.Opcode.Gt; .) | "<=" (. x = token; op = BinaryExpr.Opcode.Le; .) | ">=" (. x = token; op = BinaryExpr.Opcode.Ge; .) | "!=" (. x = token; op = BinaryExpr.Opcode.Neq; .) | "!!" (. x = token; op = BinaryExpr.Opcode.Disjoint; .) | "in" (. x = token; op = BinaryExpr.Opcode.In; .) | "!in" (. x = token; op = BinaryExpr.Opcode.NotIn; .) | '\u2260' (. x = token; op = BinaryExpr.Opcode.Neq; .) | '\u2264' (. x = token; op = BinaryExpr.Opcode.Le; .) | '\u2265' (. x = token; op = BinaryExpr.Opcode.Ge; .) ) . /*------------------------------------------------------------------------*/ Term = (. Token! x; Expression! e1; BinaryExpr.Opcode op; .) Factor { AddOp Factor (. e0 = new BinaryExpr(x, op, e0, e1); .) } . AddOp = (. x = Token.NoToken; op=BinaryExpr.Opcode.Add/*(dummy)*/; .) ( "+" (. x = token; op = BinaryExpr.Opcode.Add; .) | "-" (. x = token; op = BinaryExpr.Opcode.Sub; .) ) . /*------------------------------------------------------------------------*/ Factor = (. Token! x; Expression! e1; BinaryExpr.Opcode op; .) UnaryExpression { MulOp UnaryExpression (. e0 = new BinaryExpr(x, op, e0, e1); .) } . MulOp = (. x = Token.NoToken; op = BinaryExpr.Opcode.Add/*(dummy)*/; .) ( "*" (. x = token; op = BinaryExpr.Opcode.Mul; .) | "/" (. x = token; op = BinaryExpr.Opcode.Div; .) | "%" (. x = token; op = BinaryExpr.Opcode.Mod; .) ) . /*------------------------------------------------------------------------*/ UnaryExpression = (. Token! x; e = dummyExpr; .) ( "-" (. x = token; .) UnaryExpression (. e = new BinaryExpr(x, BinaryExpr.Opcode.Sub, new LiteralExpr(x, 0), e); .) | NegOp (. x = token; .) UnaryExpression (. e = new UnaryExpr(x, UnaryExpr.Opcode.Not, e); .) | SelectExpression | ConstAtomExpression ) . NegOp = "!" | '\u00ac'. ConstAtomExpression = (. Token! x, dtName, id; BigInteger n; List! elements; e = dummyExpr; .) ( "false" (. e = new LiteralExpr(token, false); .) | "true" (. e = new LiteralExpr(token, true); .) | "null" (. e = new LiteralExpr(token); .) | Nat (. e = new LiteralExpr(token, n); .) | "#" (. x = token; .) Ident "." Ident (. elements = new List(); .) [ "(" [ Expressions ] ")" ] (. e = new DatatypeValue(token, dtName.val, id.val, elements); .) | "fresh" (. x = token; .) "(" Expression ")" (. e = new FreshExpr(x, e); .) | "|" (. x = token; .) Expression (. e = new UnaryExpr(x, UnaryExpr.Opcode.SeqLength, e); .) "|" | "{" (. x = token; elements = new List(); .) [ Expressions ] (. e = new SetDisplayExpr(x, elements); .) "}" | "[" (. x = token; elements = new List(); .) [ Expressions ] (. e = new SeqDisplayExpr(x, elements); .) "]" ) . /*------------------------------------------------------------------------*/ /* returns one of: -- IdentifierExpr -- FunctionCallExpr -- FieldSelectExpr */ CallStmtSubExpr = (. e = dummyExpr; .) ( IdentOrFuncExpression | ObjectExpression SelectOrCallSuffix ) { SelectOrCallSuffix } . SelectExpression = (. Token! id; e = dummyExpr; .) ( IdentOrFuncExpression | ObjectExpression ) { SelectOrCallSuffix } . IdentOrFuncExpression = (. Token! id; e = dummyExpr; List! args; .) Ident [ "(" (. args = new List(); .) [ Expressions ] ")" (. e = new FunctionCallExpr(id, id.val, new ImplicitThisExpr(id), args); .) ] (. if (e == dummyExpr) { if (parseVarScope.Find(id.val) != null) { e = new IdentifierExpr(id, id.val); } else { e = new FieldSelectExpr(id, new ImplicitThisExpr(id), id.val); } } .) . SelectOrCallSuffix = (. Token! id, x; List! args; Expression e0 = null; Expression e1 = null; Expression! ee; bool anyDots = false; bool func = false; .) ( "." Ident [ "(" (. args = new List(); func = true; .) [ Expressions ] ")" (. e = new FunctionCallExpr(id, id.val, e, args); .) ] (. if (!func) { e = new FieldSelectExpr(id, e, id.val); } .) | "[" (. x = token; .) ( Expression (. e0 = ee; .) [ ".." (. anyDots = true; .) [ Expression (. e1 = ee; .) ] | ":=" Expression (. e1 = ee; .) ] | ".." Expression (. anyDots = true; e1 = ee; .) ) (. assert !anyDots ==> e0 != null; if (anyDots) { assert e0 != null || e1 != null; e = new SeqSelectExpr(x, false, e, e0, e1); } else if (e1 == null) { assert e0 != null; e = new SeqSelectExpr(x, true, e, e0, null); } else { assert e0 != null; e = new SeqUpdateExpr(x, e, e0, e1); } .) "]" ) . /* ObjectExpression represents those expressions E that could possibly be used in E.f or E(...), except Ident. Since the lookahead is just 1, quantifier expressions are also parsed here. The expression returned is never an lvalue. */ ObjectExpression = (. Token! x; e = dummyExpr; .) ( "this" (. e = new ThisExpr(token); .) | "old" (. x = token; .) "(" Expression ")" (. e = new OldExpr(x, e); .) | "(" ( QuantifierGuts | Expression ) ")" ) . /*------------------------------------------------------------------------*/ QuantifierGuts = (. Token! x = Token.NoToken; bool univ = false; BoundVar! bv; List bvars = new List(); Token! tok; Expr! e; ExprSeq! es; Attributes attrs = null; Triggers trigs = null; Expression! body; .) ( Forall (. x = token; univ = true; .) | Exists (. x = token; .) ) (. parseVarScope.PushMarker(); .) IdentTypeOptional (. bvars.Add(bv); parseVarScope.Push(bv.Name, bv.Name); .) { "," IdentTypeOptional (. bvars.Add(bv); parseVarScope.Push(bv.Name, bv.Name); .) } { AttributeOrTrigger } QSep Expression (. if (univ) { q = new ForallExpr(x, bvars, body, trigs, attrs); } else { q = new ExistsExpr(x, bvars, body, trigs, attrs); } parseVarScope.PopMarker(); .) . Forall = "forall" | '\u2200'. Exists = "exists" | '\u2203'. QSep = "::" | '\u2022'. Expressions! args> = (. Expression! e; .) Expression (. args.Add(e); .) { "," Expression (. args.Add(e); .) } . /*------------------------------------------------------------------------*/ Attribute = "{" AttributeBody "}" . AttributeBody = (. string aName; List aArgs = new List(); Attributes.Argument! aArg; .) ":" ident (. aName = token.val; .) [ AttributeArg (. aArgs.Add(aArg); .) { "," AttributeArg (. aArgs.Add(aArg); .) } ] (. attrs = new Attributes(aName, aArgs, attrs); .) . AttributeArg = (. Expression! e; arg = dummyAttrArg; .) ( string (. arg = new Attributes.Argument(token.val.Substring(1, token.val.Length-2)); .) | Expression (. arg = new Attributes.Argument(e); .) ) . AttributeOrTrigger = (. List es = new List(); .) "{" ( AttributeBody | (. es = new List(); .) Expressions (. trigs = new Triggers(es, trigs); .) ) "}" . /*------------------------------------------------------------------------*/ Idents! ids> = (. Token! id; .) Ident (. ids.Add(id.val); .) { "," Ident (. ids.Add(id.val); .) } . Ident = ident (. x = token; .) . Nat = digits (. try { n = BigInteger.Parse(token.val); } catch (System.FormatException) { SemErr("incorrectly formatted number"); n = BigInteger.Zero; } .) . END Dafny.