Skip to content

Commit 26b6921

Browse files
author
Dmitry Olshansky
committed
Start on normal top-down minimal parser
1 parent e6ef6ed commit 26b6921

File tree

4 files changed

+678
-87
lines changed

4 files changed

+678
-87
lines changed

source/ast.d

+46-14
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,63 @@
11
//Written in the D programming language
22
// libdparse:
3-
import std.d.lexer;
3+
import dparse.lexer;
44
// std
55
import std.format;
6-
@safe:
7-
8-
/// Symbol DAG element
9-
class Symbol {
10-
string file;
11-
string name;
12-
Token[] tokens;
13-
bool gcUsed;
6+
7+
/// Element of a DAG that represent lexical nesting.
8+
class Ast {
9+
private:
10+
string file;
11+
string name;
12+
const(Token)[] tokens;
13+
bool gcUsed;
1414
//
15-
Symbol parent;
16-
Symbol[] children;
15+
Ast parent;
16+
Ast[] children;
17+
18+
void dumpEdges(scope void delegate (const(char)[]) sink){
19+
foreach(c; children){
20+
formattedWrite(sink, `"%s" -> "%s";\n`, name, c.name);
21+
c.dumpEdges(sink);
22+
}
23+
}
24+
25+
public:
26+
this(string file, string name, const(Token)[] range, bool gc){
27+
this.file = file;
28+
this.name = name;
29+
this.tokens = range;
30+
this.gcUsed = gc;
31+
}
1732

1833
@property size_t firstLine(){
19-
return tokens[0].line
34+
return tokens[0].line;
2035
}
2136

2237
@property size_t endLine(){
23-
return tokens[0].line
38+
return tokens[0].line;
39+
}
40+
41+
/// Analyze GC usage of any of the nested symbols
42+
bool analyzeGC(){
43+
foreach(c; children){
44+
if(c.analyzeGC){
45+
gcUsed = true;
46+
break;
47+
}
48+
}
49+
return false;
2450
}
2551

2652
/// Dumps Graphviz format of this DAG
2753
void dump(scope void delegate (const(char)[]) sink){
28-
54+
formattedWrite(sink, "graph {\n");
55+
dumpEdges(sink);
56+
formattedWrite(sink, "}\n");
2957
}
3058
}
3159

60+
/// A cross-reference graph element
61+
class Symbol{
62+
63+
}

source/gchunt.d

+89-72
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@
88
module gchunt;
99

1010
import std.algorithm, std.conv, std.stdio, std.string, std.exception,
11-
std.regex, std.range, std.process;
11+
std.regex, std.range, std.process, std.getopt;
1212

1313
static import std.file;
1414

1515
// libdparse:
16-
import std.d.lexer;
16+
import dparse.lexer;
1717
// our pattern matching on D tokens
1818
import revdpattern;
1919

@@ -192,9 +192,9 @@ unittest{
192192
assert(matchPattern("aaaafdsfbbbasd", "aaaa*b*"));
193193
}
194194

195-
BlacklistEntry[] blacklist;
195+
BlacklistEntry[] blacklist; //
196196

197-
Comment[] talk; // comments
197+
// comments
198198

199199
struct Reason{
200200
string reason;
@@ -212,7 +212,8 @@ struct Artifact{
212212
Artifact[string] artifacts;
213213

214214
// load comments from wiki dump
215-
void loadComments(string path){
215+
Comment[] loadComments(string path){
216+
Comment[] talk;
216217
auto lines = File(path).byLine.map!(x => x.idup).array;
217218
string[] record;
218219
foreach(i, line; lines){
@@ -232,15 +233,18 @@ void loadComments(string path){
232233
if(m)
233234
record ~= m[1];
234235
}
236+
return talk;
235237
}
236238

237239
version(unittest) void main(){}
238-
else void main(){
239-
string fmt = "mediawiki";
240-
string gitHost = `https://github.com`;
241-
string gitHash = gitHEAD();
242-
string gitRepo = gitRemotePath();
240+
else void main(string[] args){
241+
bool graphMode = false;
242+
243243
auto re = regex(`(.*[\\/]\w+)\.d\((\d+)\):\s*vgc:\s*(.*)`);
244+
auto opts = getopt(args, "graph", &graphMode);
245+
if(opts.helpWanted){
246+
defaultGetoptPrinter("gchunt - pinpoint GC usage in D apps", opts.options);
247+
}
244248
Result[] results;
245249
foreach(line; stdin.byLine){
246250
auto m = line.idup.matchFirst(re);
@@ -251,19 +255,15 @@ else void main(){
251255
sort!((a,b) => a.file < b.file || (a.file == b.file && a.line < b.line))
252256
(results);
253257

254-
results = uniq(results).array;
258+
results = uniq(results).array; // deduplicate
259+
// Tokenize modules in question
255260
auto interned = StringCache(4096);
256261
foreach(mod;results.map!(x => x.file).uniq){
257262
auto config = LexerConfig(mod~".d", StringBehavior.compiler);
258263
auto data = cast(ubyte[])std.file.read(mod ~ ".d");
259264
tokenStreams[mod] = getTokensForParser(data, config, &interned).dup;
260265
//TODO: generate new "vgc" records for each .(i)dup
261266
}
262-
try{
263-
loadComments("talk.gchunt");
264-
stderr.writefln("talk.gchunt loaded: %d comments.", talk.length);
265-
}
266-
catch(Exception){} // was that FileException?
267267
try{
268268
auto f = File("blacklist.gchunt");
269269
stderr.writeln("Found blacklist.gchunt ...");
@@ -276,67 +276,84 @@ else void main(){
276276
stderr.writefln("blacklist.gchunt loaded: %d patterns.", blacklist.length);
277277
}
278278
catch(Exception){}
279-
foreach(r; results){
280-
//writeln(r.file, ",", r.line, ",", r.reason);
281-
auto mod = r.file.replace("/", ".");
282-
auto artifact = findArtifact(r);
283-
auto path = mod~":"~artifact;
284-
if(path !in artifacts){
285-
artifacts[path] = Artifact(artifact, mod);
279+
if(graphMode){
280+
281+
}
282+
else {
283+
string fmt = "mediawiki";
284+
string gitHost = `https://github.com`;
285+
string gitHash = gitHEAD();
286+
string gitRepo = gitRemotePath();
287+
Comment[] talk;
288+
try{
289+
talk = loadComments("talk.gchunt");
290+
stderr.writefln("talk.gchunt loaded: %d comments.", talk.length);
286291
}
287-
auto idx = artifacts[path].reasons.countUntil!(x => x.reason == r.reason);
288-
if(idx < 0) {
289-
artifacts[path].reasons ~= Reason(r.reason, [to!int(r.line)]);
292+
catch(Exception){} // was that FileException?
293+
foreach(r; results){
294+
//writeln(r.file, ",", r.line, ",", r.reason);
295+
auto mod = r.file.replace("/", ".");
296+
auto artifact = findArtifact(r);
297+
auto path = mod~":"~artifact;
298+
if(path !in artifacts){
299+
artifacts[path] = Artifact(artifact, mod);
300+
}
301+
auto idx = artifacts[path].reasons.countUntil!(x => x.reason == r.reason);
302+
if(idx < 0) {
303+
artifacts[path].reasons ~= Reason(r.reason, [to!int(r.line)]);
304+
}
305+
else
306+
artifacts[path].reasons[idx].locs ~= to!int(r.line);
290307
}
291-
else
292-
artifacts[path].reasons[idx].locs ~= to!int(r.line);
293-
}
294-
auto accum = artifacts.values();
295-
accum.sort!((a,b) => a.mod < b.mod || (a.mod == b.mod && a.id < b.id));
308+
auto accum = artifacts.values();
309+
accum.sort!((a,b) => a.mod < b.mod || (a.mod == b.mod && a.id < b.id));
296310

297-
string linkTemplate =
298-
`[%s/%s/blob/%s/%s.d#L%s %d] `;
299-
writeln(`
300-
{| class="wikitable"
301-
! Module
302-
! Artifact
303-
! Reason
304-
! Possible Fix(es)
305-
|-`);
306-
stderr.writefln("Total number of GC-happy artifacts: %s.", accum.length);
307-
int attached = 0;
308-
foreach(ref art; accum){
309-
string[] comments;
310-
foreach(i, t; talk)
311-
if(t.mod == art.mod && art.id == t.artifact){
312-
comments ~= t.comment;
311+
string linkTemplate =
312+
`[%s/%s/blob/%s/%s.d#L%s %d] `;
313+
writeln(`
314+
{| class="wikitable"
315+
! Module
316+
! Artifact
317+
! Reason
318+
! Possible Fix(es)
319+
|-`);
320+
stderr.writefln("Total number of GC-happy artifacts: %s.", accum.length);
321+
int attached = 0;
322+
foreach(ref art; accum){
323+
string[] comments;
324+
foreach(i, t; talk)
325+
if(t.mod == art.mod && art.id == t.artifact){
326+
comments ~= t.comment;
327+
}
328+
if(comments.length){
329+
attached += comments.length;
330+
art.comment = comments.sort().uniq().join(";");
313331
}
314-
if(comments.length){
315-
attached += comments.length;
316-
art.comment = comments.sort().uniq().join(";");
317-
}
318-
}
319-
if(talk.length) // talk.gchunt file was loaded
320-
stderr.writefln("Successfully attached %d comments.", attached);
321-
int filtered = 0;
322-
foreach(art; accum){
323-
if(blacklist.canFind!(black => black.match(art.mod, art.id))){
324-
filtered++;
325-
continue; // skip over if matches blacklist
326332
}
327-
art.reasons.sort!((a,b) => a.reason < b.reason);
328-
string reason = art.reasons.map!((r){
329-
string links = r.reason~":";
330-
foreach(i, loc; r.locs){
331-
links ~= format(linkTemplate, gitHost, gitRepo, gitHash,
332-
art.mod.replace(".","/"), loc, i+1);
333+
if(talk.length) // talk.gchunt file was loaded
334+
stderr.writefln("Successfully attached %d comments.", attached);
335+
int filtered = 0;
336+
foreach(art; accum){
337+
if(blacklist.canFind!(black => black.match(art.mod, art.id))){
338+
filtered++;
339+
continue; // skip over if matches blacklist
333340
}
334-
return links;
335-
}).join("\n\n");
336-
writef("|%s\n|%s\n|%s\n| %s\n|-\n", art.mod, art.id,
337-
reason, art.comment);
341+
art.reasons.sort!((a,b) => a.reason < b.reason);
342+
string reason = art.reasons.map!((r){
343+
string links = r.reason~":";
344+
foreach(i, loc; r.locs){
345+
links ~= format(linkTemplate, gitHost, gitRepo, gitHash,
346+
art.mod.replace(".","/"), loc, i+1);
347+
}
348+
return links;
349+
}).join("\n\n");
350+
writef("|%s\n|%s\n|%s\n| %s\n|-\n", art.mod, art.id,
351+
reason, art.comment);
352+
}
353+
writeln("|}");
354+
if(blacklist.length)
355+
stderr.writefln("Filtered %d artifacts.", filtered);
338356
}
339-
writeln("|}");
340-
if(blacklist.length)
341-
stderr.writefln("Filtered %d artifacts.", filtered);
357+
358+
342359
}

0 commit comments

Comments
 (0)