//----------------------------------------------------------------------------- // // Copyright (C) Microsoft Corporation. All Rights Reserved. // //----------------------------------------------------------------------------- using System; using System.IO; using System.Collections.Generic; using System.Diagnostics.Contracts; using System.Numerics; using Bpl = Microsoft.Boogie; namespace Microsoft.Dafny { public class Printer { TextWriter wr; [ContractInvariantMethod] void ObjectInvariant() { Contract.Invariant(wr!=null); } public Printer(TextWriter wr) { Contract.Requires(wr != null); this.wr = wr; } public void PrintProgram(Program prog) { Contract.Requires(prog != null); if (Bpl.CommandLineOptions.Clo.ShowEnv != Bpl.CommandLineOptions.ShowEnvironment.Never) { wr.WriteLine("// " + Bpl.CommandLineOptions.Clo.Version); wr.WriteLine("// " + Bpl.CommandLineOptions.Clo.Environment); } wr.WriteLine("// {0}", prog.Name); wr.WriteLine(); PrintTopLevelDecls(prog.DefaultModuleDef.TopLevelDecls, 0); } public void PrintTopLevelDecls(List classes, int indent) { Contract.Requires(classes!= null); int i = 0; foreach (TopLevelDecl d in classes) { Contract.Assert(d != null); if (d is ArbitraryTypeDecl) { var at = (ArbitraryTypeDecl)d; if (i++ != 0) { wr.WriteLine(); } Indent(indent); PrintClassMethodHelper("type", at.Attributes, at.Name, new List()); if (at.EqualitySupport == TypeParameter.EqualitySupportValue.Required) { wr.Write("(==)"); } wr.WriteLine(";"); } else if (d is DatatypeDecl) { if (i++ != 0) { wr.WriteLine(); } PrintDatatype((DatatypeDecl)d, indent); } else if (d is ClassDecl) { ClassDecl cl = (ClassDecl)d; if (!cl.IsDefaultClass) { if (i++ != 0) { wr.WriteLine(); } PrintClass(cl, indent); } else if (cl.Members.Count == 0) { // print nothing } else { if (i++ != 0) { wr.WriteLine(); } PrintClass_Members(cl, indent); } } else if (d is ModuleDecl) { wr.WriteLine(); Indent(indent); if (d is LiteralModuleDecl) { ModuleDefinition module = ((LiteralModuleDecl)d).ModuleDef; wr.Write("module"); PrintAttributes(module.Attributes); wr.Write(" {0} ", module.Name); if (module.RefinementBaseName != null) { wr.Write("refines {0} ", Util.Comma(".", module.RefinementBaseName, id => id.val)); } if (module.TopLevelDecls.Count == 0) { wr.WriteLine("{ }"); } else { wr.WriteLine("{"); PrintTopLevelDecls(module.TopLevelDecls, indent + IndentAmount); Indent(indent); wr.WriteLine("}"); } } else if (d is AliasModuleDecl) { wr.Write("import"); if (((AliasModuleDecl)d).Opened) wr.Write(" opened"); wr.Write(" {0} ", ((AliasModuleDecl)d).Name); wr.WriteLine("= {0};", Util.Comma(".", ((AliasModuleDecl)d).Path, id => id.val)); } else if (d is AbstractModuleDecl) { wr.Write("import"); if (((AbstractModuleDecl)d).Opened) wr.Write(" opened"); wr.Write(" {0} ", ((AbstractModuleDecl)d).Name); wr.WriteLine("as {0};", Util.Comma(".", ((AbstractModuleDecl)d).Path, id => id.val)); } } } } public void PrintClass(ClassDecl c, int indent) { Contract.Requires(c != null); Indent(indent); PrintClassMethodHelper("class", c.Attributes, c.Name, c.TypeArgs); if (c.Members.Count == 0) { wr.WriteLine(" { }"); } else { wr.WriteLine(" {"); PrintClass_Members(c, indent + IndentAmount); Indent(indent); wr.WriteLine("}"); } } public void PrintClass_Members(ClassDecl c, int indent) { Contract.Requires(c != null); Contract.Requires( c.Members.Count != 0); int state = 0; // 0 - no members yet; 1 - previous member was a field; 2 - previous member was non-field foreach (MemberDecl m in c.Members) { if (m is Method) { if (state != 0) { wr.WriteLine(); } PrintMethod((Method)m, indent); state = 2; } else if (m is Field) { if (state == 2) { wr.WriteLine(); } PrintField((Field)m, indent); state = 1; } else if (m is Function) { if (state != 0) { wr.WriteLine(); } PrintFunction((Function)m, indent); state = 2; } else { Contract.Assert(false); throw new cce.UnreachableException(); // unexpected member } } } /// /// Prints no space before "kind", but does print a space before "attrs" and "name". /// void PrintClassMethodHelper(string kind, Attributes attrs, string name, List typeArgs) { Contract.Requires(kind != null); Contract.Requires(name != null); Contract.Requires(typeArgs != null); if (kind.Length != 0) { wr.Write(kind); } PrintAttributes(attrs); wr.Write(" {0}", name); if (typeArgs.Count != 0) { wr.Write("<" + Util.Comma(", ", typeArgs, tp => tp.Name + (tp.EqualitySupport == TypeParameter.EqualitySupportValue.Required? "(==)": "")) + ">"); } } public void PrintDatatype(DatatypeDecl dt, int indent) { Contract.Requires(dt != null); Indent(indent); PrintClassMethodHelper(dt is IndDatatypeDecl ? "datatype" : "codatatype", dt.Attributes, dt.Name, dt.TypeArgs); wr.Write(" ="); string sep = ""; foreach (DatatypeCtor ctor in dt.Ctors) { wr.Write(sep); PrintClassMethodHelper("", ctor.Attributes, ctor.Name, new List()); if (ctor.Formals.Count != 0) { PrintFormals(ctor.Formals); } sep = " |"; } wr.WriteLine(";"); } /// /// Prints a space before each attribute. /// public void PrintAttributes(Attributes a) { if (a != null) { PrintAttributes(a.Prev); wr.Write(" {{:{0}", a.Name); if (a.Args != null) { PrintAttributeArgs(a.Args); } wr.Write("}"); } } public void PrintAttributeArgs(List args) { Contract.Requires(args != null); string prefix = " "; foreach (Attributes.Argument arg in args) { Contract.Assert(arg != null); wr.Write(prefix); prefix = ", "; if (arg.S != null) { wr.Write("\"{0}\"", arg.S); } else { Contract.Assert( arg.E != null); PrintExpression(arg.E); } } } public void PrintField(Field field, int indent) { Contract.Requires(field != null); Indent(indent); if (field.IsGhost) { wr.Write("ghost "); } wr.Write("var"); PrintAttributes(field.Attributes); wr.Write(" {0}: ", field.Name); PrintType(field.Type); wr.WriteLine(";"); } public void PrintFunction(Function f, int indent) { Contract.Requires(f != null); var isPredicate = f is Predicate; Indent(indent); string k = isPredicate ? "predicate" : f is CoPredicate ? "copredicate" : "function"; if (f.IsStatic) { k = "static " + k; } if (!f.IsGhost) { k += " method"; } PrintClassMethodHelper(k, f.Attributes, f.Name, f.TypeArgs); if (f.SignatureIsOmitted) { wr.WriteLine(" ..."); } else { if (f.OpenParen != null) { PrintFormals(f.Formals); } else { Contract.Assert(isPredicate); } if (!isPredicate) { wr.Write(": "); PrintType(f.ResultType); } wr.WriteLine(); } int ind = indent + IndentAmount; PrintSpec("requires", f.Req, ind); PrintFrameSpecLine("reads", f.Reads, ind, null); PrintSpec("ensures", f.Ens, ind); PrintDecreasesSpec(f.Decreases, ind); if (f.Body != null) { Indent(indent); wr.WriteLine("{"); PrintExtendedExpr(f.Body, ind, true, false); Indent(indent); wr.WriteLine("}"); } } // ----------------------------- PrintMethod ----------------------------- const int IndentAmount = 2; // The amount of indent for each new scope const string BunchaSpaces = " "; void Indent(int amount) { Contract.Requires( 0 <= amount); while (0 < amount) { wr.Write(BunchaSpaces.Substring(0, amount)); amount -= BunchaSpaces.Length; } } public void PrintMethod(Method method, int indent) { Contract.Requires(method != null); Indent(indent); string k = method is Constructor ? "constructor" : "method"; if (method.IsStatic) { k = "static " + k; } if (method.IsGhost) { k = "ghost " + k; } PrintClassMethodHelper(k, method.Attributes, method.Name, method.TypeArgs); if (method.SignatureIsOmitted) { wr.WriteLine(" ..."); } else { PrintFormals(method.Ins); if (method.Outs.Count != 0) { if (method.Ins.Count + method.Outs.Count <= 3) { wr.Write(" returns "); } else { wr.WriteLine(); Indent(3 * IndentAmount); wr.Write("returns "); } PrintFormals(method.Outs); } wr.WriteLine(); } int ind = indent + IndentAmount; PrintSpec("requires", method.Req, ind); if (method.Mod.Expressions != null) { PrintFrameSpecLine("modifies", method.Mod.Expressions, ind, method.Mod.HasAttributes() ? method.Mod.Attributes : null); } PrintSpec("ensures", method.Ens, ind); PrintDecreasesSpec(method.Decreases, ind); if (method.Body != null) { Indent(indent); PrintStatement(method.Body, indent); wr.WriteLine(); } } void PrintFormals(List ff) { Contract.Requires(ff!=null); wr.Write("("); string sep = ""; foreach (Formal f in ff) { Contract.Assert(f != null); wr.Write(sep); sep = ", "; PrintFormal(f); } wr.Write(")"); } void PrintFormal(Formal f) { Contract.Requires(f != null); if (f.IsGhost) { wr.Write("ghost "); } if (f.HasName) { wr.Write("{0}: ", f.DisplayName); } PrintType(f.Type); } void PrintSpec(string kind, List ee, int indent) { Contract.Requires(kind != null); Contract.Requires(ee != null); foreach (Expression e in ee) { Contract.Assert(e != null); Indent(indent); wr.Write("{0} ", kind); PrintExpression(e); wr.WriteLine(";"); } } void PrintDecreasesSpec(Specification decs, int indent) { Contract.Requires(decs != null); if (decs.Expressions != null && decs.Expressions.Count != 0) { Indent(indent); wr.Write("decreases"); if (decs.HasAttributes()) { PrintAttributes(decs.Attributes); } wr.Write(" "); PrintExpressionList(decs.Expressions); wr.WriteLine(";"); } } void PrintFrameSpecLine(string kind, List ee, int indent, Attributes attrs) { Contract.Requires(kind != null); Contract.Requires(cce.NonNullElements(ee)); if (ee != null && ee.Count != 0) { Indent(indent); wr.Write("{0}", kind); if (attrs != null) { PrintAttributes(attrs); } wr.Write(" "); PrintFrameExpressionList(ee); wr.WriteLine(";"); } } void PrintSpec(string kind, List ee, int indent) { Contract.Requires(kind != null); Contract.Requires(ee != null); foreach (MaybeFreeExpression e in ee) { Contract.Assert(e != null); Indent(indent); wr.Write("{0}{1}", e.IsFree ? "free " : "", kind); if (e.HasAttributes()) { PrintAttributes(e.Attributes); } wr.Write(" "); PrintExpression(e.E); wr.WriteLine(";"); } } // ----------------------------- PrintType ----------------------------- public void PrintType(Type ty) { Contract.Requires(ty != null); wr.Write(ty.ToString()); } public void PrintType(string prefix, Type ty) { Contract.Requires(prefix != null); Contract.Requires(ty != null); string s = ty.ToString(); if (s != "?") { wr.Write("{0}{1}", prefix, s); } } // ----------------------------- PrintStatement ----------------------------- /// /// Prints from the current position of the current line. /// If the statement requires several lines, subsequent lines are indented at "indent". /// No newline is printed after the statement. /// public void PrintStatement(Statement stmt, int indent) { Contract.Requires(stmt != null); for (LList