//
//
//           The Nimrod Compiler
//        (c) Copyright 2009 Andreas Rumpf
//
//    See the file "copying.txt", included in this
//    distribution, for details about the copyright.
//
unit depends;

// This module implements a dependency file generator.

interface

{$include 'config.inc'}

uses
  nsystem, nos, options, ast, astalgo, msgs, ropes, idents, passes, importer;

function genDependPass(): TPass;
procedure generateDot(const project: string);

implementation

type
  TGen = object(TPassContext)
    module: PSym;
    filename: string;
  end;
  PGen = ^TGen;

var
  gDotGraph: PRope; // the generated DOT file; we need a global variable

procedure addDependencyAux(const importing, imported: string);
begin
  appf(gDotGraph, '$1 -> $2;$n', [toRope(importing),
                                  toRope(imported)]);
  //    s1 -> s2_4 [label="[0-9]"];
end;

function addDotDependency(c: PPassContext; n: PNode): PNode;
var
  i: int;
  g: PGen;
  imported: string;
begin
  result := n;
  if n = nil then exit;
  g := PGen(c);
  case n.kind of
    nkImportStmt: begin
      for i := 0 to sonsLen(n)-1 do begin
        imported := splitFile(getModuleFile(n.sons[i])).name;
        addDependencyAux(g.module.name.s, imported);
      end
    end;
    nkFromStmt: begin
      imported := splitFile(getModuleFile(n.sons[0])).name;
      addDependencyAux(g.module.name.s, imported);
    end;
    nkStmtList, nkBlockStmt, nkStmtListExpr, nkBlockExpr: begin
      for i := 0 to sonsLen(n)-1 do {@discard} addDotDependency(c, n.sons[i]);
    end
    else begin end
  end
end;

procedure generateDot(const project: string);
begin
  writeRope(
    ropef('digraph $1 {$n$2}$n', [
      toRope(changeFileExt(extractFileName(project), '')), gDotGraph]),
    changeFileExt(project, 'dot') );
end;

function myOpen(module: PSym; const filename: string): PPassContext;
var
  g: PGen;
begin
  new(g);
{@ignore}
  fillChar(g^, sizeof(g^), 0);
{@emit}
  g.module := module;
  g.filename := filename;
  result := g;
end;

function gendependPass(): TPass;
begin
  initPass(result);
  result.open := myOpen;
  result.process := addDotDependency;
end;

end.