Skip to content

Instantly share code, notes, and snippets.

@dnadlinger
Created September 30, 2009 19:33
Show Gist options
  • Save dnadlinger/198377 to your computer and use it in GitHub Desktop.
Save dnadlinger/198377 to your computer and use it in GitHub Desktop.
module redimple;
import tools.mersenne, tools.compat : logf = log;
import Float = tango.text.convert.Float;
import Integer = tango.text.convert.Integer;
import tango.io.Console;
alias char[] string;
bool equal( T )( T a, T b ) {
static if ( is( T : Object ) )
return a is b;
else
return a == b;
}
bool has( T )( T[] array, T elem ) {
foreach ( e; array )
if ( equal( e, elem ) )
return true;
return false;
}
int search( T )( T[] array, T[] match ) {
if ( array.length < match.length )
return -1;
foreach ( id, elem; array[ 0 .. $ - match.length + 1 ] )
if ( array[ id .. id + match.length ] == match )
return id;
return -1;
}
void remove( T )( ref T[] array, T match ) {
if ( array.length == 1 ) {
array.length = 0;
return;
}
size_t pos = size_t.max;
foreach ( i, elem; array )
if ( elem == match )
pos = i;
if ( pos == size_t.max ) {
Cerr( "Can't remove - not in array!" ).newline;
asm { int 3; }
}
array[ pos ] = array[ $ - 1 ];
array.length = array.length - 1;
}
T pop( T )( ref T[] array ) {
T res = array[ $ - 1 ];
array = array[ 0 .. $ - 1 ];
return res;
}
typeof ( T + U ) max( T, U )( T a, U b ) {
return a > b ? a : b;
}
import tools.base : stuple, Stuple, startsWith;
class Graph ( T ) {
T[] nodes;
T[][ T ] edges;
size_t _incoming[ T ];
void addNode( T node ) {
nodes ~= node;
}
void addEdge( T src, T dest ) {
if ( !( dest in _incoming ) )
_incoming[ dest ] = 1;
_incoming[ dest ]++;
if ( !nodes.has( src ) )
addNode( src );
if ( !nodes.has( dest ) )
addNode( dest );
if ( !( src in edges ) )
edges[ src ] = [ ];
if ( !edges[ src ].has( dest ) )
edges[ src ] ~= dest;
}
string[ Stuple!( T, T ) ] annotate;
void addEdge( T src, T dest, string anno ) {
addEdge( src, dest );
annotate[ stuple( src, dest ) ] = anno;
}
Graph dup() {
auto res = new Graph;
res.nodes = nodes.dup;
foreach ( id, entry; edges ) {
res.edges[ id ] = entry.dup;
}
return res;
}
void rmEdge( T src, T dest ) {
_incoming[ dest ]--;
if ( !edges[ src ].length )
return;
edges[ src ][ edges[ src ].search( [ dest ] ) ] = edges[ src ][ $ - 1 ];
edges[ src ] = edges[ src ][ 0 .. $ - 1 ];
}
size_t incoming( T node ) {
if ( !( node in _incoming ) )
return 0;
return _incoming[ node ];
}
size_t outgoing( T node ) {
return edges[ node ].length;
}
}
alias Graph!( string ) G;
/// Tarjan algorithm copied from Wikipedia. Thanks guys :)
T[][] tarjan( T )( Graph!( T ) G, T start ) {
auto max_dfs = 0; // counter for dfs
T[] stack;
T[][] res;
size_t[ T ] dfs, lowlink;
void _tarjan( T v ) {
dfs[ v ] = lowlink[ v ] = max_dfs++;
stack ~= v;
T[] dests = [ ];
if ( auto p = v in G.edges )
dests = *p;
foreach ( dest; dests ) {
if ( dest / notin / dfs ) {
_tarjan( dest );
if ( lowlink[ dest ] < lowlink[ v ] )
lowlink[ v ] = lowlink[ dest ];
} else if ( stack.has( dest ) )
//if (dfs[dest]<lowlink[v]) lowlink[v]=dfs[dest];
if ( lowlink[ dest ] < lowlink[ v ] )
lowlink[ v ] = lowlink[ dest ];
}
if ( lowlink[ v ] == dfs[ v ] ) { // the root of a strongly connected component
res.length = res.length + 1;
T _v;
do {
_v = stack.pop();
res[ $ - 1 ] ~= _v;
} while ( v != _v );
}
}
_tarjan( start );
return res;
}
import tools.functional;
interface excluder {
bool opCall( string from, string to );
}
struct Import {
string mod, what;
}
Import[] imports( string mod, excluder xc ) {
auto filename = modToFile( mod );
if ( !filename.exists() )
throw new Exception( "File " ~ filename ~ " cannot be found" );
char[] rid = Integer.toString( rand() );
Import[][] list;
char[] contents = cast( char[] ) filename.read();
char[][] lines = contents.split( ";" );
foreach ( line; lines ) {
line = line.strip();
if ( !( line.startsWith( "import" ) || line.find( " import " ) != -1 ) ) {
continue;
}
bool pub = line.startsWith( "public " ) !is null;
line = line[ line.find( "import" ) + 6 .. $ ];
Import[] currentImports;
auto sel = line.find( ":" );
string what;
if ( sel != -1 ) {
what = line[ sel + 1 .. $ ];
line = line[ 0 .. sel ];
}
foreach ( part; line.split( "," ) )
currentImports ~= Import( part.strip(), pub ? "#"[] : ""[] );
currentImports[ $ - 1 ].what ~= what.strip();
list ~= currentImports;
}
Import[] foo;
foreach ( sub; list )
foreach ( i; sub ) {
if ( !i.mod.length )
continue;
if ( !xc( mod, i.mod ) )
continue;
foo ~= i;
}
return foo;
}
string modToFile( string mod ) {
return mod.replace( ".", "/" ) ~ ".d";
}
void log( char[] l ) {
}
G genImportsGraph( string mod, excluder xc, bool incExtNodes = false ) {
auto res = new G;
string[] scanned;
int depth = 0;
void recurse( string mod ) {
depth++;
scope ( exit )
depth--;
log( "recurse into " ~ mod ~ " at level " ~ Integer.toString( depth ) );
scope ( exit )
log( "done" );
if ( scanned.has( mod ) )
return;
scanned ~= mod;
res.addNode( mod );
foreach ( entry; mod.imports( xc ) ) {
if ( mod == entry.mod )
continue;
if ( modToFile( entry.mod ).exists() ) {
log( " " ~ mod ~ " -> " ~ entry.mod );
res.addEdge( mod, entry.mod, entry.what );
recurse( entry.mod );
} else {
log( modToFile( entry.mod ) ~ " doesn't exist" );
if ( incExtNodes )
res.addEdge( mod, entry.mod, entry.what );
}
}
}
mod.recurse();
log( "Graph generated" );
return res;
}
class Package {
string name;
Package[ string ] pkgs;
string[] modules;
this( string name, G graph ) {
log( "Creating package " ~ name );
this.name = name;
foreach ( entry; graph.nodes ) {
if ( entry.length !> name.length )
continue;
if ( entry[ 0 .. name.length ] != name )
continue;
char[] subname = entry[ name.length .. $ ];
if ( subname[ 0 ] == '.' )
subname = subname[ 1 .. $ ];
auto dotpos = subname.find( "." );
if ( ( dotpos != -1 ) && !( subname[ 0 .. dotpos ] in pkgs ) )
pkgs[ subname[ 0 .. dotpos ] ] = new Package(
( name.length ? name ~ "." : "" ) ~ subname[ 0 .. dotpos ],
graph );
else if ( name.length || ( dotpos == -1 ) )
modules ~= entry;
}
}
}
char[] quote( char[] e ) {
return '"' ~ e ~ '"';
}
char[] rmPkg( char[] inp ) {
if ( inp.find( "." ) == -1 )
return inp;
return inp[ inp.rfind( "." ) + 1 .. $ ];
}
bool leftright = false;
string getsettings( string mod ) {
string rmvStrings( string inp ) {
bool inString = false;
string res;
char mode;
int skip = 0;
foreach ( ch; inp ) {
if ( skip ) {
skip--;
continue;
}
if ( !inString ) {
res ~= ch;
if ( ( ch == '"' ) || ( ch == '\'' ) ) {
inString = true;
mode = ch;
continue;
}
}
if ( ch == '\\' ) {
skip = 1;
continue;
}
if ( ch == mode )
inString = false;
}
return res;
}
auto
preparts = ( ( cast( string ) mod.modToFile().read() ) ).rmvStrings().split(
"\n" ) / map / ( string s ) {
if ( s.find( "//" ) != -1 )
return s[ 0 .. s.find( "//" ) ];
return s;
} / reduce( ""[] ) / ex!( "a, b -> a~b" );
string s;
bool inComment = false;
foreach ( pos, ch; preparts[ 0 .. $ - 1 ] ) {
if ( !inComment )
s ~= ch;
if ( preparts[ pos .. pos + 2 ] == "/*" ) {
s ~= "*";
inComment = true;
}
if ( preparts[ pos .. pos + 2 ] == "*/" ) {
s ~= "/";
inComment = false;
}
}
auto parts = s.replace( "\n", "" ).replace( "\r", "" ).split( "{" );
auto
classes = parts / select / ( string s ) {
auto pos = s.find( "class " );
if ( pos == -1 )
return false;
return ( "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz1234567890_" ).find(
s[ pos - 1 ] ) == -1;
} / map / ( string s ) {
return s[ s.find( "class " ) + 6 .. $ ].strip();
} / uniq;
char[] res;
bool skipName;
foreach ( entry; classes )
if ( entry.find( mod.rmPkg() ) != -1 )
skipName = true;
/+if (classes.length) res="shape=record, style="~quote(/*"rounded, filled"*/"filled")~", label="~'"'~
(leftright?"{":"")~"{ "~(skipName?"":("{ "~mod.rmPkg()~" } "));
// else res="shape=record, style="~quote(/*"rounded, filled"*/"filled")~", label=\""~mod.rmPkg();
else +/res = "label=\"" ~ mod.rmPkg();
/+string[] splitSkipBrackets(string inp, char sep) {
size_t bracketlevel=0;
string[] res; string buf;
foreach (ch; inp) {
buf~=ch;
if (!bracketlevel) {
if (ch=='(') { ++bracketlevel; continue; }
if (ch==sep) { res~=buf[0..$-1]; buf=""; }
} else { if (ch=='(') ++bracketlevel; else if (ch==')') --bracketlevel; }
}
if (buf.length) res~=buf; return res;
}
foreach (entry; classes) {
string[] supers;
auto ddp = entry.find(":");
if (ddp!=-1) {
supers=entry[ddp+1..$].replace("\"", "_").splitSkipBrackets(',');
entry=entry[0..ddp];
}
auto ep = entry.find(" extends ");
if (ep != -1) {
supers = entry[ep+9 .. %2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment