#!/mfs/pkgs/chicken/4.8.0.5/bin/csi -nbq
;; Usage: plot-code file1.scm,file2.scm *.scm > plot.dot
;; dot -Tpdf plot.dot > plot.pdf
(use regex srfi-69 srfi-13)
(define targs #f)
(define files (cddddr (argv)))
(let ((targdat (cadddr (argv))))
(if (equal? targdat "-")
(set! targs files)
(set! targs (string-split targdat ","))))
(define filedat-defns (make-hash-table))
(define filedat-usages (make-hash-table))
(define defn-rx (regexp "^\\s*\\(define\\s+\\(([^\\s\\)]+).*"))
(define all-regexs (make-hash-table))
(define all-fns '())
(define (print-err . data)
(with-output-to-port (current-error-port)
(lambda ()
(apply print data))))
(print-err "Making graph for files: " (string-intersperse targs ", "))
(print-err "Looking at files: " (string-intersperse files ", "))
;; Gather the functions
;;
(for-each
(lambda (fname)
(print-err "Processing file " fname)
(with-input-from-file fname
(lambda ()
(let loop ((inl (read-line)))
(if (not (eof-object? inl))
(let ((match (string-match defn-rx inl)))
(if match
(let ((fnname (cadr match)))
;; (print " " fnname)
(set! all-fns (cons fnname all-fns))
(hash-table-set!
filedat-defns
fname
(cons fnname (hash-table-ref/default filedat-defns fname '())))
))
(loop (read-line))))))))
files)
;; fill up the regex hash
(print-err "Make the huge regex hash")
(for-each
(lambda (fnname)
(hash-table-set! all-regexs fnname (regexp (conc "^(|.*[^a-zA-Z]+)" fnname "([^a-zA-Z]+|)$"))))
(cons "toplevel" all-fns))
(define breadcrumbs (make-hash-table))
(define (have-function inl)
(let loop ((hed (car all-fns))
(tal (cdr all-fns)))
(if (string-contains inl hed)
#t
(if (null? tal)
#f
(loop (car tal)(cdr tal))))))
(define (look-for-all-calls inl fnname)
(if (have-function inl) ;; (string-search have-function-rx inl)
(let loop ((hed (car all-fns))
(tal (cdr all-fns))
(res '()))
(let ((match (string-match (hash-table-ref all-regexs hed) inl)))
(if match
(let ((newres (cons hed res)))
(if (null? tal)
newres
(loop (car tal)
(cdr tal)
newres)))
(if (null? tal)
res
(loop (car tal)(cdr tal) res)))))
'()))
;; Gather the usages
(print "digraph G {")
(define curr-cluster-num 0)
(define function-calls '())
(for-each
(lambda (fname)
(let ((last-func #f))
(print-err "Processing file " fname)
(print "subgraph cluster_" curr-cluster-num " {")
(set! curr-cluster-num (+ curr-cluster-num 1))
(with-input-from-file fname
(lambda ()
(with-output-to-port (current-error-port)
(lambda ()
(print "Analyzing file " fname)))
(print "label=\"" fname "\";")
(let loop ((inl (read-line))
(fnname "toplevel")
(allcalls '()))
(if (eof-object? inl)
(begin
(set! function-calls (cons (list fnname allcalls) function-calls))
(for-each
(lambda (call-name)
(hash-table-set! breadcrumbs call-name #t))
allcalls)
(print-err "function: " fnname " allcalls: " allcalls))
(let ((match (string-match defn-rx inl)))
(if match
(let ((func-name (cadr match)))
(if last-func
(print "\"" func-name "\" -> \"" last-func "\";")
(print "\"" func-name "\";"))
(set! last-func func-name)
(hash-table-set! breadcrumbs func-name #t)
(loop (read-line)
func-name
allcalls))
(let ((calls (look-for-all-calls inl fnname)))
(loop (read-line) fnname (append allcalls calls)))))))))
(print "}")))
targs)
(print-err "breadcrumbs: " (hash-table-keys breadcrumbs))
(print-err "function-calls: " function-calls)
(for-each
(lambda (function-call)
(print-err "function-call: " function-call)
(let ((fnname (car function-call))
(calls (cadr function-call)))
(for-each
(lambda (callname)
(print (if (hash-table-ref/default breadcrumbs callname #f) "" "// ")
"\"" fnname "\" -> \"" callname "\";"))
calls)))
function-calls)
(print "}")
(exit)