Skip to content

Commit

Permalink
feat: Semantics for dots in {:extern} module names in Python (#3919)
Browse files Browse the repository at this point in the history
Fixes #2963.

<small>By submitting this pull request, I confirm that my contribution
is made under the terms of the [MIT
license](https://github.com/dafny-lang/dafny/blob/master/LICENSE.txt).</small>
  • Loading branch information
fabiomadge authored May 2, 2023
1 parent a553b86 commit 89786a2
Show file tree
Hide file tree
Showing 8 changed files with 51 additions and 8 deletions.
7 changes: 5 additions & 2 deletions Source/DafnyCore/Compilers/Python/Compiler-python.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@ protected override ConcreteSyntaxTree CreateStaticMain(IClassWriter cw, string a
protected override ConcreteSyntaxTree CreateModule(string moduleName, bool isDefault, bool isExtern,
string libraryName, ConcreteSyntaxTree wr) {
moduleName = IdProtect(moduleName);
var file = wr.NewFile($"{moduleName}.py");
var modulePath = moduleName.Replace('.', Path.DirectorySeparatorChar);
var file = wr.NewFile($"{modulePath}.py");
EmitImports(moduleName, file);
return file;
}
Expand All @@ -104,7 +105,9 @@ private void EmitImports(string moduleName, ConcreteSyntaxTree wr) {
if (moduleName != null) {
wr.WriteLine();
wr.WriteLine($"assert \"{moduleName}\" == __name__");
wr.WriteLine($"{moduleName} = sys.modules[__name__]");
if (!moduleName.Contains('.')) {
wr.WriteLine($"{moduleName} = sys.modules[__name__]");
}

Imports.Add(moduleName);
}
Expand Down
8 changes: 5 additions & 3 deletions Source/DafnyCore/Compilers/Python/PythonBackend.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ protected override SinglePassCompiler CreateCompiler() {
return new PythonCompiler(Options, Reporter);
}

private static readonly Regex ModuleLine = new(@"^\s*assert\s+""([a-zA-Z0-9_]+)""\s*==\s*__name__\s*$");
private static readonly Regex ModuleLine = new(@"^\s*assert\s+""([a-zA-Z0-9_]+(.[a-zA-Z0-9_]+)*)""\s*==\s*__name__\s*$");

private static string FindModuleName(string externFilename) {
using var rd = new StreamReader(new FileStream(externFilename, FileMode.Open, FileAccess.Read));
Expand All @@ -40,7 +40,7 @@ private static string FindModuleName(string externFilename) {
}
}
rd.Close();
return externFilename.EndsWith(".py") ? externFilename[..^3] : null;
return Path.GetExtension(externFilename) == ".py" ? Path.GetFileNameWithoutExtension(externFilename) : null;
}

bool CopyExternLibraryIntoPlace(string externFilename, string mainProgram, TextWriter outputWriter) {
Expand All @@ -52,8 +52,10 @@ bool CopyExternLibraryIntoPlace(string externFilename, string mainProgram, TextW
}
var mainDir = Path.GetDirectoryName(mainProgram);
Contract.Assert(mainDir != null);
var tgtFilename = Path.Combine(mainDir, moduleName + ".py");
var modulePath = moduleName.Replace('.', Path.DirectorySeparatorChar);
var tgtFilename = Path.Combine(mainDir, $"{modulePath}.py");
var file = new FileInfo(externFilename);
Directory.CreateDirectory(Path.GetDirectoryName(tgtFilename)!);
file.CopyTo(tgtFilename, true);
if (Options.CompileVerbose) {
outputWriter.WriteLine($"Additional input {externFilename} copied to {tgtFilename}");
Expand Down
8 changes: 6 additions & 2 deletions Source/DafnyCore/ConcreteSyntax/ConcreteSyntaxTree.cs
Original file line number Diff line number Diff line change
Expand Up @@ -200,13 +200,17 @@ public ConcreteSyntaxTree NewFile(string filename) {
// ----- Collection ------------------------------

public override string ToString() {
return MakeString();
}

public string MakeString(int indentSize = 2) {
var sw = new StringWriter();
var files = new Queue<FileSyntax>();
Render(sw, 0, new WriterState(), files);
Render(sw, 0, new WriterState(), files, indentSize);
while (files.Count != 0) {
var ftw = files.Dequeue();
sw.WriteLine("#file {0}", ftw.Filename);
ftw.Render(sw, 0, new WriterState(), files);
ftw.Render(sw, 0, new WriterState(), files, indentSize);
}

return sw.ToString();
Expand Down
2 changes: 1 addition & 1 deletion Source/DafnyDriver/DafnyDriver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -875,7 +875,7 @@ public static bool CompileDafnyProgram(Dafny.Program dafnyProgram, string dafnyP
var callToMainTree = new ConcreteSyntaxTree();
string baseName = Path.GetFileNameWithoutExtension(dafnyProgramName);
compiler.EmitCallToMain(mainMethod, baseName, callToMainTree);
callToMain = callToMainTree.ToString(); // assume there aren't multiple files just to call main
callToMain = callToMainTree.MakeString(compiler.TargetIndentSize); // assume there aren't multiple files just to call main
}
Contract.Assert(hasMain == (callToMain != null));
bool targetProgramHasErrors = dafnyProgram.Reporter.Count(ErrorLevel.Error) != oldErrorCount;
Expand Down
11 changes: 11 additions & 0 deletions Test/comp/ExternNestedModule.dfy
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// RUN: %dafny /compile:4 /spillTargetCode:2 /compileTarget:py %S/ExternNestedModule.py "%s" > "%t"
// RUN: %diff "%s.expect" "%t"

method Main(){
print Library.THREE, "\n";
}

module {:extern "Nested.Library"} Library {
const THREE := TWO + 1;
const TWO: int
}
3 changes: 3 additions & 0 deletions Test/comp/ExternNestedModule.dfy.expect
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@

Dafny program verifier finished with 0 verified, 0 errors
3
19 changes: 19 additions & 0 deletions Test/comp/ExternNestedModule.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import sys
import _dafny

assert "Nested.Library" == __name__

class default__:
def __init__(self):
pass

def __dafnystr__(self) -> str:
return "Nested.Library_Compile._default"

@_dafny.classproperty
def TWO(instance):
return 2

@_dafny.classproperty
def THREE(instance):
return default__.TWO + 1
1 change: 1 addition & 0 deletions docs/dev/news/3919.feat
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Semantic interpretation of dots in names for `{:extern}` modules when compiling to Python

0 comments on commit 89786a2

Please sign in to comment.