Skip to content

Commit efc0f48

Browse files
Add deinitializeDMD function to deinitialize the front end
This is a start of being able to restore the global state initialized by `initDMD` to its original state. It only deinitializes state initialized by `initDMD`, state store directly inside functions are not restored. This is useful to invoke the compiler multiple times within the same application. This allows to write more fine grained tests for the compiler, more of a unit test style compared to the current end to end tests.
1 parent 17edda5 commit efc0f48

17 files changed

Lines changed: 526 additions & 22 deletions

download_dub.d

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
// Downloads Dub. For use in the auto-tester CI environment.
2+
module download_dub;
3+
4+
version (FreeBSD)
5+
{
6+
version (X86_64)
7+
enum platform = "freebsd-64";
8+
else version (X86)
9+
enum platform = "freebsd-32";
10+
11+
enum binDir = "bin";
12+
}
13+
else version (linux)
14+
{
15+
enum platform = "linux";
16+
17+
version (X86_64)
18+
enum binDir = "bin64";
19+
else version (X86)
20+
enum bin64 = "bin32";
21+
}
22+
else version (OSX)
23+
{
24+
enum platform = "osx";
25+
enum binDir = "bin";
26+
}
27+
else version (Windows)
28+
{
29+
enum platform = "windows";
30+
enum binDir = "bin";
31+
}
32+
33+
version (Posix)
34+
{
35+
enum archiveExtension = "tar.xz";
36+
enum exeExtension = "";
37+
}
38+
else version (Windows)
39+
{
40+
enum archiveExtension = "7z";
41+
enum exeExtension = ".exe";
42+
}
43+
44+
string resolveLatest()
45+
{
46+
import std.net.curl : get;
47+
import std.exception : assumeUnique;
48+
49+
return get("http://downloads.dlang.org/releases/LATEST").assumeUnique;
50+
}
51+
52+
string dmdUrl()
53+
{
54+
import std.format : format;
55+
56+
enum fmt = "http://downloads.dlang.org/releases/2.x/%s/dmd.%s.%s.%s";
57+
const version_ = resolveLatest;
58+
return format!fmt(version_, version_, platform, archiveExtension);
59+
}
60+
61+
void unpack(string dmdArchivePath)
62+
{
63+
import std.process : spawnProcess, wait;
64+
65+
version (Posix)
66+
const arguments = ["tar", "xf", dmdArchivePath];
67+
else version (Windows)
68+
const arguments = ["7z", "x", dmdArchivePath];
69+
70+
spawnProcess(arguments).wait();
71+
}
72+
73+
void extractDub(string path, string dest)
74+
{
75+
import std.path : buildPath;
76+
import std.file : rename;
77+
78+
enum filename = "dub" ~ exeExtension;
79+
const dubPath = buildPath(path, platform, binDir, filename);
80+
81+
rename(dubPath, buildPath(dest, filename));
82+
}
83+
84+
void cleanup(string dmdArchivePath, string dmdPath)
85+
{
86+
import std.file : rmdirRecurse;
87+
import std.file : remove;
88+
89+
rmdirRecurse(dmdPath);
90+
remove(dmdArchivePath);
91+
}
92+
93+
void main()
94+
{
95+
import std.file : getcwd;
96+
import std.net.curl : download;
97+
98+
enum dmdArchivePath = "dmd." ~ archiveExtension;
99+
enum dmdPath = "dmd2";
100+
101+
download(dmdUrl, dmdArchivePath);
102+
unpack(dmdArchivePath);
103+
extractDub(dmdPath, getcwd);
104+
cleanup(dmdArchivePath, dmdPath);
105+
}

src/dmd/builtin.d

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,17 @@ public extern (C++) void builtin_init()
425425
add_builtin("_D4core5bitop7_popcntFNaNbNiNfmZi", &eval_popcnt);
426426
}
427427

428+
/**
429+
* Deinitializes the global state of the compiler.
430+
*
431+
* This can be used to restore the state set by `builtin_init` to its original
432+
* state.
433+
*/
434+
public void builtinDeinitialize()
435+
{
436+
builtins = builtins.init;
437+
}
438+
428439
/**********************************
429440
* Determine if function is a builtin one that we can
430441
* evaluate at compile time.

src/dmd/dmodule.d

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,17 @@ extern (C++) final class Module : Package
298298
modules = new DsymbolTable();
299299
}
300300

301+
/**
302+
* Deinitializes the global state of the compiler.
303+
*
304+
* This can be used to restore the state set by `_init` to its original
305+
* state.
306+
*/
307+
static void deinitialize()
308+
{
309+
modules = modules.init;
310+
}
311+
301312
extern (C++) __gshared AggregateDeclaration moduleinfo;
302313

303314
const(char)* arg; // original argument name

src/dmd/expression.d

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,22 @@ extern (C++) abstract class Expression : RootObject
640640
CTFEExp.showcontext = new CTFEExp(TOK.showCtfeContext);
641641
}
642642

643+
/**
644+
* Deinitializes the global state of the compiler.
645+
*
646+
* This can be used to restore the state set by `_init` to its original
647+
* state.
648+
*/
649+
static void deinitialize()
650+
{
651+
CTFEExp.cantexp = CTFEExp.cantexp.init;
652+
CTFEExp.voidexp = CTFEExp.voidexp.init;
653+
CTFEExp.breakexp = CTFEExp.breakexp.init;
654+
CTFEExp.continueexp = CTFEExp.continueexp.init;
655+
CTFEExp.gotoexp = CTFEExp.gotoexp.init;
656+
CTFEExp.showcontext = CTFEExp.showcontext.init;
657+
}
658+
643659
/*********************************
644660
* Does *not* do a deep copy.
645661
*/

src/dmd/frontend.d

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,35 @@ void initDMD()
7676
FileCache._init();
7777
}
7878

79+
/**
80+
Deinitializes the global variables of the DMD compiler.
81+
82+
This can be used to restore the state set by `initDMD` to its original state.
83+
Useful if there's a need for multiple sessions of the DMD compiler in the same
84+
application.
85+
*/
86+
void deinitializeDMD()
87+
{
88+
import dmd.builtin : builtinDeinitialize;
89+
import dmd.dmodule : Module;
90+
import dmd.expression : Expression;
91+
import dmd.globals : global;
92+
import dmd.id : Id;
93+
import dmd.mtype : Type;
94+
import dmd.objc : Objc;
95+
import dmd.target : target;
96+
97+
global.deinitialize();
98+
99+
Type.deinitialize();
100+
Id.deinitialize();
101+
Module.deinitialize();
102+
target.deinitialize();
103+
Expression.deinitialize();
104+
Objc.deinitialize();
105+
builtinDeinitialize();
106+
}
107+
79108
/**
80109
Add import path to the `global.path`.
81110
Params:

src/dmd/globals.d

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,17 @@ struct Global
398398
params.color = Console.detectTerminal();
399399
}
400400

401+
/**
402+
* Deinitializes the global state of the compiler.
403+
*
404+
* This can be used to restore the state set by `_init` to its original
405+
* state.
406+
*/
407+
void deinitialize()
408+
{
409+
this = this.init;
410+
}
411+
401412
/**
402413
Returns: the version as the number that would be returned for __VERSION__
403414
*/

src/dmd/id.d

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,17 @@ struct Id
3939
{
4040
mixin(msgtable.generate(&initializer));
4141
}
42+
43+
/**
44+
* Deinitializes the global state of the compiler.
45+
*
46+
* This can be used to restore the state set by `initialize` to its original
47+
* state.
48+
*/
49+
void deinitialize()
50+
{
51+
mixin(msgtable.generate(&deinitializer));
52+
}
4253
}
4354

4455
private:
@@ -487,3 +498,9 @@ string initializer(Msgtable m)
487498
{
488499
return m.ident ~ ` = Identifier.idPool("` ~ m.name ~ `");`;
489500
}
501+
502+
// Used to generate the code for each deinitializer.
503+
string deinitializer(Msgtable m)
504+
{
505+
return m.ident ~ " = Identifier.init;";
506+
}

src/dmd/mtype.d

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -897,6 +897,17 @@ extern (C++) abstract class Type : RootObject
897897
thash_t = tsize_t;
898898
}
899899

900+
/**
901+
* Deinitializes the global state of the compiler.
902+
*
903+
* This can be used to restore the state set by `_init` to its original
904+
* state.
905+
*/
906+
static void deinitialize()
907+
{
908+
stringtable = stringtable.init;
909+
}
910+
900911
final d_uns64 size()
901912
{
902913
return size(Loc.initial);

src/dmd/objc.d

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,17 @@ extern(C++) abstract class Objc
188188
_objc = new Unsupported;
189189
}
190190

191+
/**
192+
* Deinitializes the global state of the compiler.
193+
*
194+
* This can be used to restore the state set by `_init` to its original
195+
* state.
196+
*/
197+
static void deinitialize()
198+
{
199+
_objc = _objc.init;
200+
}
201+
191202
abstract void setObjc(ClassDeclaration cd);
192203
abstract void setObjc(InterfaceDeclaration);
193204

src/dmd/target.d

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,17 @@ struct Target
180180
params.isDragonFlyBSD || params.isOSX;
181181
}
182182

183+
/**
184+
* Deinitializes the global state of the compiler.
185+
*
186+
* This can be used to restore the state set by `_init` to its original
187+
* state.
188+
*/
189+
void deinitialize()
190+
{
191+
this = this.init;
192+
}
193+
183194
/**
184195
* Requested target memory alignment size of the given type.
185196
* Params:

0 commit comments

Comments
 (0)