//-----------------------------------------------------------------------------
//
// 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
}
}
}