// ----- Statements ------------------------------------------------------------- protected override void EmitPrintStmt(TargetWriter wr, Expression arg) { wr.Indent(); wr.Write("console.log("); TrExpr(arg, wr, false); wr.WriteLine(");"); }
// ----- Statements ------------------------------------------------------------- protected override void EmitPrintStmt(TargetWriter wr, Expression arg) { wr.Indent(); wr.Write("process.stdout.write("); TrParenExpr(arg, wr, false); wr.WriteLine(".toString());"); }
protected override void EmitReturn(List <Formal> outParams, TargetWriter wr) { wr.Indent(); if (outParams.Count == 0) { wr.WriteLine("return;"); } else if (outParams.Count == 1) { wr.WriteLine("return {0};", IdName(outParams[0])); } else { wr.WriteLine("return [{0}];", Util.Comma(outParams, IdName)); } }
protected override void DeclareLocalVar(string name, Type /*?*/ type, Bpl.IToken /*?*/ tok, Expression rhs, bool inLetExprBody, TargetWriter wr) { wr.Indent(); wr.Write("let {0} = ", name); TrExpr(rhs, wr, inLetExprBody); wr.WriteLine(";"); }
protected override void EmitHeader(Program program, TargetWriter wr) { wr.WriteLine("// Dafny program {0} compiled into JavaScript", program.Name); wr.WriteLine(@" let _dafny = (function() { let $module = {}; $module.Tuple = class Tuple extends Array { constructor(...elems) { super(...elems); } toString() { return ""("" + this.join("", "") + "")""; } } $module.Seq = class Seq extends Array { constructor(...elems) { super(...elems); } toString() { return ""["" + this.join("", "") + ""]""; } } $module.areEqual = function() { return false; // TODO } $module.seqUpdate = function(s, i, v) { let t = s.slice(); t[i] = v; return t; } $module.newArray = function(initValue, ...dims) { return { dims: dims, elmts: buildArray(initValue, ...dims) }; } return $module; function buildArray(initValue, ...dims) { if (dims.length === 0) { return initValue; } else { let a = Array(dims[0]); let b = Array.from(a, (x) => buildArray(initValue, ...dims.slice(1))); return b; } } })(); "); }
protected override void DeclareLocalVar(string name, Type /*?*/ type, Bpl.IToken /*?*/ tok, bool leaveRoomForRhs, string /*?*/ rhs, TargetWriter wr) { wr.Indent(); wr.Write("let {0}", name); if (leaveRoomForRhs) { Contract.Assert(rhs == null); // follows from precondition } else if (rhs != null) { wr.WriteLine(" = {0};", rhs); } else { wr.WriteLine(";"); } }
// ----- Declarations ------------------------------------------------------------- protected override void DeclareField(string name, bool isStatic, bool isConst, Type type, Bpl.IToken tok, string rhs, TargetWriter wr) { wr.Indent(); if (isStatic) { var w = wr.NewNamedBlock("static get {0}()", name); EmitReturnExpr(rhs, w); } else { wr.WriteLine("this.{0} = {1};", name, rhs); } }
protected override void EmitHeader(Program program, TargetWriter wr) { wr.WriteLine("// Dafny program {0} compiled into C#", program.Name); wr.WriteLine("// To recompile, use 'csc' with: /r:System.Numerics.dll"); wr.WriteLine("// and choosing /target:exe or /target:library"); wr.WriteLine("// You might also want to include compiler switches like:"); wr.WriteLine("// /debug /nowarn:0164 /nowarn:0219 /nowarn:1717 /nowarn:0162 /nowarn:0168"); wr.WriteLine(); wr.WriteLine("using System;"); wr.WriteLine("using System.Numerics;"); EmitDafnySourceAttribute(program, wr); if (!DafnyOptions.O.UseRuntimeLib) { ReadRuntimeSystem(wr); } }
protected override void EmitOutParameterSplits(string outCollector, List <string> actualOutParamNames, TargetWriter wr) { if (actualOutParamNames.Count == 1) { EmitAssignment(actualOutParamNames[0], outCollector, wr); } else { for (var i = 0; i < actualOutParamNames.Count; i++) { wr.Indent(); wr.WriteLine("{0} = {1}[{2}];", actualOutParamNames[i], outCollector, i); } } }
/// <summary> /// Generate a C# program from the Dafny program and, if "invokeCompiler" is "true", invoke /// the C# compiler to compile it. /// </summary> public static bool CompileDafnyProgram(Dafny.Program dafnyProgram, string dafnyProgramName, ReadOnlyCollection <string> otherFileNames, bool invokeCompiler, TextWriter outputWriter = null) { Contract.Requires(dafnyProgram != null); Contract.Assert(dafnyProgramName != null); if (outputWriter == null) { outputWriter = Console.Out; } // Compile the Dafny program into a string that contains the target program var oldErrorCount = dafnyProgram.reporter.Count(ErrorLevel.Error); Dafny.Compiler compiler; switch (DafnyOptions.O.CompileTarget) { case DafnyOptions.CompilationTarget.Csharp: default: compiler = new Dafny.CsharpCompiler(dafnyProgram.reporter); break; case DafnyOptions.CompilationTarget.JavaScript: compiler = new Dafny.JavaScriptCompiler(dafnyProgram.reporter); break; case DafnyOptions.CompilationTarget.Go: compiler = new Dafny.GoCompiler(dafnyProgram.reporter); break; case DafnyOptions.CompilationTarget.Java: compiler = new Dafny.JavaCompiler(dafnyProgram.reporter); break; } Method mainMethod; var hasMain = compiler.HasMain(dafnyProgram, out mainMethod); string targetProgramText; var otherFiles = new Dictionary <string, string>(); { var fileQueue = new Queue <FileTargetWriter>(); using (var wr = new TargetWriter(0)) { compiler.Compile(dafnyProgram, wr); var sw = new StringWriter(); wr.Collect(sw, fileQueue); targetProgramText = sw.ToString(); } while (fileQueue.Count > 0) { var wr = fileQueue.Dequeue(); var sw = new StringWriter(); wr.Collect(sw, fileQueue); otherFiles.Add(wr.Filename, sw.ToString()); } } string baseName = Path.GetFileNameWithoutExtension(dafnyProgramName); string callToMain = null; if (hasMain) { using (var wr = new TargetWriter(0)) { if (DafnyOptions.O.CompileTarget is DafnyOptions.CompilationTarget.Java) { dafnyProgramName = dafnyProgramName.Replace('-', '_'); wr.WriteLine($"public class {baseName.Replace('-', '_')} {{"); } compiler.EmitCallToMain(mainMethod, wr); if (DafnyOptions.O.CompileTarget is DafnyOptions.CompilationTarget.Java) { wr.WriteLine("}"); } callToMain = wr.ToString(); // assume there aren't multiple files just to call main } } bool completeProgram = dafnyProgram.reporter.Count(ErrorLevel.Error) == oldErrorCount; // blurt out the code to a file, if requested, or if other files were specified for the C# command line. string targetFilename = null; if (DafnyOptions.O.SpillTargetCode > 0 || otherFileNames.Count > 0 || (invokeCompiler && !compiler.SupportsInMemoryCompilation)) { var p = callToMain == null ? targetProgramText : targetProgramText + callToMain; if (DafnyOptions.O.CompileTarget is DafnyOptions.CompilationTarget.Java && callToMain == null) { p = null; } targetFilename = WriteDafnyProgramToFiles(dafnyProgramName, p, completeProgram, otherFiles, outputWriter); } if (DafnyOptions.O.CompileTarget is DafnyOptions.CompilationTarget.Java) { string targetBaseDir = baseName; string targetDir = Path.Combine(Path.GetDirectoryName(dafnyProgramName), targetBaseDir); var assemblyLocation = System.Reflection.Assembly.GetExecutingAssembly().Location; Contract.Assert(assemblyLocation != null); var codebase = System.IO.Path.GetDirectoryName(assemblyLocation); Contract.Assert(codebase != null); string dest = targetDir + "/dafny"; Directory.CreateDirectory(dest); var jcompiler = (JavaCompiler)compiler; jcompiler.CompileTuples(dest); jcompiler.CreateFunctionInterface(dest); jcompiler.CompileDafnyArrays(dest); jcompiler.CompileArrayInits(dest); } if (!completeProgram) { return(false); } // If we got until here, compilation to C# succeeded if (!invokeCompiler) { return(true); // If we're not asked to invoke the C# to assembly compiler, we can report success } // compile the program into an assembly object compilationResult; var compiledCorrectly = compiler.CompileTargetProgram(dafnyProgramName, targetProgramText, callToMain, targetFilename, otherFileNames, hasMain, hasMain && DafnyOptions.O.RunAfterCompile, outputWriter, out compilationResult); if (compiledCorrectly && DafnyOptions.O.RunAfterCompile) { if (hasMain) { if (DafnyOptions.O.CompileVerbose) { outputWriter.WriteLine("Running..."); outputWriter.WriteLine(); } compiledCorrectly = compiler.RunTargetProgram(dafnyProgramName, targetProgramText, callToMain, targetFilename, otherFileNames, compilationResult, outputWriter); } else { // make sure to give some feedback to the user if (DafnyOptions.O.CompileVerbose) { outputWriter.WriteLine("Program compiled successfully"); } } } return(compiledCorrectly); }
protected override void EmitHeader(Program program, TargetWriter wr) { wr.WriteLine("// Dafny program {0} compiled into JavaScript", program.Name); }
protected override void EmitAbsurd(TargetWriter wr) { wr.Indent(); wr.WriteLine("throw new Error('unexpected control point');"); }
protected override void EmitYield(TargetWriter wr) { wr.Indent(); wr.WriteLine("yield null;"); }
protected override void EmitJumpToTailCallStart(TargetWriter wr) { wr.Indent(); wr.WriteLine("continue TAIL_CALL_START;"); }
/// <inheritdoc /> public override void WriteLine() { TargetWriter.WriteLine(); }
protected override void EmitBreak(string label, TargetWriter wr) { wr.Indent(); wr.WriteLine("break {0};", label); }
/// <inheritdoc /> public override void WriteLine(string value) { TargetWriter.WriteLine(value); }
protected override void DeclareDatatype(DatatypeDecl dt, TargetWriter wr) { // $module.Dt = class Dt { // constructor(tag) { // this.$tag = tag; // } // static create_Ctor0(field0, field1, ...) { // let $dt = new Dt(0); // $dt.field0 = field0; // $dt.field1 = field1; // ... // return $dt; // } // static create_Ctor1(...) { // let $dt = new Dt(1); // ... // } // ... // // get is_Ctor0 { return this.$tag == 0; } // get is_Ctor1 { return this.$tag == 1; } // ... // // toString() { // ... // } // equals(other) { // ... // } // } // TODO: need Default member (also for co-datatypes) // TODO: if HasFinitePossibleValues, need enumerator of values string DtT = dt.CompileName; string DtT_protected = IdProtect(DtT); wr.Indent(); // from here on, write everything into the new block created here: wr = wr.NewNamedBlock("$module.{0} = class {0}", DtT_protected); wr.Indent(); wr.WriteLine("constructor(tag) { this.$tag = tag; }"); // query properties var i = 0; foreach (var ctor in dt.Ctors) { // collect the names of non-ghost arguments var argNames = new List <string>(); var k = 0; foreach (var formal in ctor.Formals) { if (!formal.IsGhost) { argNames.Add(FormalName(formal, k)); k++; } } // static create_Ctor0(params) { return {$tag:0, p0: pararms0, p1: params1, ...}; } wr.Indent(); wr.Write("static create_{0}(", ctor.CompileName); wr.Write(Util.Comma(argNames, nm => nm)); var w = wr.NewBlock(")"); w.Indent(); w.WriteLine("let $dt = new {0}({1});", DtT_protected, i); foreach (var arg in argNames) { w.Indent(); w.WriteLine("$dt.{0} = {0};", arg); } w.Indent(); w.WriteLine("return $dt;"); i++; } // query properties i = 0; foreach (var ctor in dt.Ctors) { // get is_Ctor0() { return _D is Dt_Ctor0; } wr.Indent(); wr.WriteLine("get is_{0}() {{ return this.$tag === {1}; }}", ctor.CompileName, i); i++; } if (dt is IndDatatypeDecl && !(dt is TupleTypeDecl)) { // toString method wr.Indent(); var w = wr.NewBlock("toString()"); i = 0; foreach (var ctor in dt.Ctors) { var cw = EmitIf(string.Format("this.$tag == {0}", i), true, w); cw.Indent(); cw.Write("return \"{0}.{1}\"", dt.Name, ctor.Name); var sep = " + \"(\" + "; var anyFormals = false; var k = 0; foreach (var arg in ctor.Formals) { if (!arg.IsGhost) { anyFormals = true; cw.Write("{0}this.{1}.toString()", sep, FormalName(arg, k)); sep = " + \", \" + "; k++; } } if (anyFormals) { cw.Write(" + \")\""); } cw.WriteLine(";"); i++; } w = w.NewBlock(""); w.Indent(); w.WriteLine("return \"<unexpected>\";"); } // equals method wr.Indent(); using (var w = wr.NewBlock("equals(other)")) { using (var thn = EmitIf("this === other", true, w)) { EmitReturnExpr("true", thn); } i = 0; foreach (var ctor in dt.Ctors) { var thn = EmitIf(string.Format("this.$tag == {0}", i), true, w); using (var guard = new TargetWriter()) { guard.Write("other.$tag == {0}", i); var k = 0; foreach (Formal arg in ctor.Formals) { if (!arg.IsGhost) { string nm = FormalName(arg, k); if (IsDirectlyComparable(arg.Type)) { guard.Write(" && this.{0} === oth.{0}", nm); } else { guard.Write(" && _dafny.areEqual(this.{0}, other.{0})", nm); } k++; } } EmitReturnExpr(guard.ToString(), thn); } i++; } using (var els = w.NewBlock("")) { els.Indent(); els.WriteLine("return false; // unexpected"); } } }