DMD front-end can be used as a library with Dub

Alexander Breckel via Digitalmars-d digitalmars-d at puremagic.com
Mon Aug 29 03:42:23 PDT 2016


I just tried to use the DMD frontend as a Dub package in my own 
project to parse and analyze D files and it ... just worked. The 
dub.json for dmd is fairly small and doesn't require any changes 
to the code. This might be common knowledge, but I was completely 
unprepared for this :)

Please note: This is "only" the dmd frontend (lexer, parser, 
semantic passes, CTFE). Code generation will be more complicated.

The following dub pre-generation hooks were necessary:

- run src/idgen.d to generate src/id.d
- create verstr.h and SYSCONFDIR.imp
- create and link source/ddmd/ to src/

The last point makes ddmd modules reside in its correct package. 
I'm using a symbolic link for this, which is the only reason this 
approach is currently limited to Linux. In the long run, I think 
the cleanest way would be to place all ddmd files in src/ddmd/ 
and just leave mars.d and things like idgen.d in the main src/ 
directory.

For demonstration purposes, here is a dub package to play around 
with:
http://code.dlang.org/packages/ddmd-experimental

Here is the dub.json that was used:
https://github.com/aneas/ddmd-experimental/blob/master/dub.json

And here is an example program using this API, have fun!
(run with $ chmod +x file.d; ./file.d)
---
#!/usr/bin/env dub
/+ dub.sdl:
name "ddmd-example"
dependency "ddmd-experimental" version="~>2.71.2-b2dub"
+/

import std.path;
import std.stdio;
import std.string;
import ddmd.builtin;
import ddmd.dmodule;
import ddmd.dclass;
import ddmd.dsymbol;
import ddmd.expression;
import ddmd.func;
import ddmd.globals;
import ddmd.id;
import ddmd.identifier;
import ddmd.mtype;
import ddmd.visitor;

void main(string[] args) {
	if(args.length != 2) {
		writeln("prints top-level function and class declarations");
		writeln("usage: ", args[0].baseName, " d-filepath");
		return;
	}

	// Initialization
	global._init();
	global.params.isLinux = true;
	Type._init();
	Id.initialize();
	Module._init();
	Expression._init();
	builtin_init();

	// Read and parse specified module
	auto id = Identifier.idPool(args[1].baseName.stripExtension);
	auto m = new Module(args[1].toStringz, id, false, false);
	m.read(Loc());
	m.parse();

	// Output
	m.accept(new class Visitor {
		extern(C++):
		alias visit = Visitor.visit;
		override void visit(Module m) {
			foreach(i; 0 .. m.members.dim)
				(*m.members)[i].accept(this);
		}
		override void visit(Dsymbol s) {
		}
		override void visit(FuncDeclaration fd) {
			writeln("function ", fd.ident.toString);
		}
		override void visit(ClassDeclaration cd) {
			writeln("class ", cd.ident.toString);
		}
	});
}



More information about the Digitalmars-d mailing list