quarta-feira, 2 de julho de 2008

Contagem de definições no toplevel

Dando início a uma série de programas para geração de estatísticas inúteis, abaixo está um pequeno código para contagem de definições feitas no toplevel (em Chicken Scheme).

(use srfi-1)

(define count-defines
(let* ((definers '(define define-macro define-constant
define-inline define-syntax))
(count-defines
(lambda (file)
(cons file
(length
(filter
(lambda (form)
(and (pair? form)
(memq (car form) definers)))
(with-input-from-file
file read-file)))))))
(lambda (files)
(let ((defines-count (map count-defines files)))
(for-each (lambda (file/defcount)
(print (car file/defcount) ": "
(cdr file/defcount)))
defines-count)
(print "Total: "
(reduce + 0 (map cdr defines-count)))))))

(let ((files (command-line-arguments)))
(if (null? files)
(exit 0)
(count-defines files)))

Exemplos de uso:


$ csi -s count-defines.scm count-defines.scm
count-defines.scm: 1
Total: 1


$ csi -s count-defines.scm spiffy/trunk/*.scm
spiffy/trunk/cgi-handler.scm: 5
spiffy/trunk/simple-directory-handler.scm: 4
spiffy/trunk/spiffy-base.scm: 70
spiffy/trunk/spiffy.scm: 1
spiffy/trunk/ssp-handler.scm: 10
spiffy/trunk/web-scheme-handler.scm: 4
Total: 94

Embora este programa não diga muita coisa de útil sobre o código que analisa, serve para mostrar um dos aspectos mais interessantes de Lisp: a possibilidade de se tratar, naturalmente, código como dados. Basicamente, a contagem de definições no toplevel consiste em ler todas as expressões de um arquivo e verificar se o car de cada expressão é um dos símbolos define, define-macro, define-constant, define-inline ou define-syntax (se a expressão for um par).

Este tipo de análise não é muito útil porque, pelo menos em Chicken, é possível especificar o que deve ser "visível" ou não no código compilado. Isto pode ser feito com as declarações export e hide. Outros motivos são que este programa não consegue inferir as definições de toplevel que serão geradas através da expansão de macros (web-scheme, por exemplo, usa esta estratégia) e que não computa definições feitas dentro de blocos cond-expand.

Nenhum comentário: