Add frontend module and example

This commit is contained in:
Sebastian Wilzbach 2017-12-14 00:48:28 +01:00
parent 2f0b835f3f
commit e88073d788
3 changed files with 219 additions and 0 deletions

View file

@ -100,6 +100,7 @@ subPackage {
"src/dmd/escape.d" \
"src/dmd/expression.d" \
"src/dmd/expressionsem.d" \
"src/dmd/frontend.d" \
"src/dmd/func.d" \
"src/dmd/gluelayer.d" \
"src/dmd/hdrgen.d" \

56
src/dmd/frontend.d Normal file
View file

@ -0,0 +1,56 @@
/**
* Compiler implementation of the
* $(LINK2 http://www.dlang.org, D programming language).
*
* This module contains high-level interfaces for interacting
with DMD as a library.
*
* Copyright: Copyright (c) 1999-2017 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
* License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
* Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/id.d, _id.d)
*/
module dmd.frontend;
// Online documentation: https://dlang.org/phobos/dmd_frontend.html
/**
Initializes the DMD compiler
*/
void initDMD()
{
import dmd.dmodule : Module;
import dmd.globals : global;
import dmd.id : Id;
import dmd.mtype : Type;
import dmd.target : Target;
import dmd.expression : Expression;
import dmd.objc : Objc;
import dmd.builtin : builtin_init;
global._init;
version(linux)
global.params.isLinux = 1;
else version(OSX)
global.params.isOSX = 1;
else version(FreeBSD)
global.params.isFreeBSD = 1;
else version(Windows)
global.params.isWindows = 1;
else version(Solaris)
global.params.isSolaris = 1;
else version(OpenBSD)
global.params.isOpenBSD = 1;
else
static assert(0, "OS not supported yet.");
Type._init();
Id.initialize();
Module._init();
Target._init();
Expression._init();
Objc._init();
builtin_init();
}

162
test/dub_package/frontend.d Executable file
View file

@ -0,0 +1,162 @@
#!/usr/bin/env dub
/+dub.sdl:
dependency "dmd" path="../.."
+/
import std.stdio;
// add import paths
void addImports(T)(T path)
{
import dmd.globals : global;
import dmd.arraytypes : Strings;
stderr.writefln("addImport: %s", path);
Strings* res = new Strings();
foreach (p; path)
{
import std.string : toStringz;
Strings* a = new Strings();
a.push(p.toStringz);
res.append(a);
}
global.path = res;
}
// finds a dmd.conf and parses it for import paths
auto findImportPaths()
{
import std.file : exists, getcwd;
import std.string : fromStringz, toStringz;
import std.path : buildPath, buildNormalizedPath, dirName;
import std.process : env = environment, execute;
import dmd.dinifile : findConfFile;
import dmd.errors : fatal;
import std.algorithm, std.range, std.regex;
auto dmdEnv = env.get("DMD", "dmd");
auto whichDMD = execute(["which", dmdEnv]);
if (whichDMD.status != 0)
{
stderr.writeln("Can't find DMD.");
fatal;
}
immutable dmdFilePath = whichDMD.output;
string iniFile;
if (dmdEnv.canFind("ldmd"))
{
immutable ldcConfig = "ldc2.conf";
immutable binDir = dmdFilePath.dirName;
// https://wiki.dlang.org/Using_LDC
auto ldcConfigs = [
getcwd.buildPath(ldcConfig),
binDir.buildPath(ldcConfig),
binDir.dirName.buildPath("etc", ldcConfig),
"~/.ldc".buildPath(ldcConfig),
binDir.buildPath("etc", ldcConfig),
binDir.buildPath("etc", "ldc", ldcConfig),
"/etc".buildPath(ldcConfig),
"/etc/ldc".buildPath(ldcConfig),
].filter!exists;
assert(!ldcConfigs.empty, "No ldc2.conf found");
iniFile = ldcConfigs.front;
}
else
{
auto f = findConfFile(dmdFilePath.toStringz, "dmd.conf");
iniFile = f.fromStringz.idup;
assert(iniFile.exists, "No dmd.conf found.");
}
return File(iniFile, "r")
.byLineCopy
.map!(l => l.matchAll(`-I[^ "]+`.regex)
.joiner
.map!(a => a.drop(2)
.replace("%@P%", dmdFilePath.dirName)
.replace("%%ldcbinarypath%%", dmdFilePath.dirName)))
.joiner
.array
.sort
.uniq
.map!buildNormalizedPath;
}
// test frontend
void main()
{
import dmd.astcodegen : ASTCodegen;
import dmd.dmodule : Module;
import dmd.globals : global, Loc;
import dmd.frontend : initDMD;
import dmd.parse : Parser;
import dmd.statement : Identifier;
import dmd.tokens : TOKeof;
import dmd.id : Id;
initDMD;
findImportPaths.addImports;
auto parse(Module m, string code)
{
scope p = new Parser!ASTCodegen(m, code, false);
p.nextToken; // skip the initial token
auto members = p.parseModule;
assert(!p.errors, "Parsing error occurred.");
return members;
}
Identifier id = Identifier.idPool("test");
auto m = new Module("test.d", id, 0, 0);
m.members = parse(m, q{
void foo()
{
foreach (i; 0..10) {}
}
});
void semantic()
{
import dmd.dsymbolsem : dsymbolSemantic;
import dmd.semantic : semantic2, semantic3;
m.importedFrom = m;
m.importAll(null);
m.dsymbolSemantic(null);
m.semantic2(null);
m.semantic3(null);
}
semantic();
auto prettyPrint()
{
import dmd.root.outbuffer: OutBuffer;
import dmd.hdrgen : HdrGenState, PrettyPrintVisitor;
OutBuffer buf = { doindent: 1 };
HdrGenState hgs = { fullDump: 1 };
scope PrettyPrintVisitor ppv = new PrettyPrintVisitor(&buf, &hgs);
m.accept(ppv);
return buf;
}
auto buf = prettyPrint();
auto expected =q{import object;
void foo()
{
{
int __key3 = 0;
int __limit4 = 10;
for (; __key3 < __limit4; __key3 += 1)
{
int i = __key3;
}
}
}
};
import std.string : replace, fromStringz;
auto generated = buf.extractData.fromStringz.replace("\t", " ");
assert(expected == generated, generated);
}