//----------------------------------------------------------------------------- // // Copyright (C) Microsoft Corporation. All Rights Reserved. // //----------------------------------------------------------------------------- using System; using System.IO; using System.Collections.Generic; using System.Diagnostics.Contracts; using Bpl = Microsoft.Boogie; namespace Microsoft.Dafny { public class Main { private static void MaybePrintProgram(Program program, string filename) { if (filename != null) { TextWriter tw; if (filename == "-") { tw = System.Console.Out; } else { tw = new System.IO.StreamWriter(filename); } Printer pr = new Printer(tw, DafnyOptions.O.PrintMode); pr.PrintProgram(program); } } /// /// Returns null on success, or an error string otherwise. /// public static string ParseCheck(IList/*!*/ fileNames, string/*!*/ programName, out Program program) //modifies Bpl.CommandLineOptions.Clo.XmlSink.*; { Contract.Requires(programName != null); Contract.Requires(fileNames != null); program = null; ModuleDecl module = new LiteralModuleDecl(new DefaultModuleDecl(), null); BuiltIns builtIns = new BuiltIns(); foreach (string dafnyFileName in fileNames){ Contract.Assert(dafnyFileName != null); if (Bpl.CommandLineOptions.Clo.XmlSink != null && Bpl.CommandLineOptions.Clo.XmlSink.IsOpen) { Bpl.CommandLineOptions.Clo.XmlSink.WriteFileFragment(dafnyFileName); } if (Bpl.CommandLineOptions.Clo.Trace) { Console.WriteLine("Parsing " + dafnyFileName); } string err = ParseFile(dafnyFileName, Bpl.Token.NoToken, module, builtIns, new Errors()); if (err != null) { return err; } } if (!DafnyOptions.O.DisallowIncludes) { string errString = ParseIncludes(module, builtIns, fileNames, new Errors()); if (errString != null) { return errString; } } program = new Program(programName, module, builtIns); MaybePrintProgram(program, DafnyOptions.O.DafnyPrintFile); if (Bpl.CommandLineOptions.Clo.NoResolve || Bpl.CommandLineOptions.Clo.NoTypecheck) { return null; } Dafny.Resolver r = new Dafny.Resolver(program); r.ResolveProgram(program); MaybePrintProgram(program, DafnyOptions.O.DafnyPrintResolvedFile); if (r.ErrorCount != 0) { return string.Format("{0} resolution/type errors detected in {1}", r.ErrorCount, program.Name); } return null; // success } // Lower-case file names before comparing them, since Windows uses case-insensitive file names private class IncludeComparer : IComparer { public int Compare(Include x, Include y) { return x.fullPath.ToLower().CompareTo(y.fullPath.ToLower()); } } public static string ParseIncludes(ModuleDecl module, BuiltIns builtIns, IList excludeFiles, Errors errs) { SortedSet includes = new SortedSet(new IncludeComparer()); foreach (string fileName in excludeFiles) { includes.Add(new Include(null, fileName, Path.GetFullPath(fileName))); } bool newlyIncluded; do { newlyIncluded = false; List newFilesToInclude = new List(); foreach (Include include in ((LiteralModuleDecl)module).ModuleDef.Includes) { bool isNew = includes.Add(include); if (isNew) { newlyIncluded = true; newFilesToInclude.Add(include); } } foreach (Include include in newFilesToInclude) { string ret = ParseFile(include.filename, include.tok, module, builtIns, errs, false); if (ret != null) { return ret; } } } while (newlyIncluded); return null; // Success } private static string ParseFile(string dafnyFileName, Bpl.IToken tok, ModuleDecl module, BuiltIns builtIns, Errors errs, bool verifyThisFile = true) { var fn = DafnyOptions.Clo.UseBaseNameForFileName ? Path.GetFileName(dafnyFileName) : dafnyFileName; try { int errorCount = Dafny.Parser.Parse(dafnyFileName, module, builtIns, errs, verifyThisFile); if (errorCount != 0) { return string.Format("{0} parse errors detected in {1}", errorCount, fn); } } catch (IOException e) { errs.SemErr(tok, "Unable to open included file"); return string.Format("Error opening file \"{0}\": {1}", fn, e.Message); } return null; // Success } } }