[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Reporting unused local variables
From: |
Ludovic Courtès |
Subject: |
Reporting unused local variables |
Date: |
Mon, 29 Jun 2009 00:50:21 +0200 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/23.1.50 (gnu/linux) |
Hello,
The attached patch is an attempt to add unused variable reporting to the
compiler, at the GLIL->assembly step. It was quite simple to implement
here, and it should work with all front-ends (Scheme, ECMAScript, etc.),
which is nice.
Example:
--8<---------------cut here---------------start------------->8---
scheme@(guile-user)> (lambda () (let ((x 2)) x))
$1 = #<program 7ffae3f42b40 at <unknown port>:1:0 ()>
scheme@(guile-user)> (lambda () (let ((x 2)) 'something-else))
<stdin>:3:11: variable `x' never referenced
$2 = #<program 7ffae3f36560 at <unknown port>:2:0 ()>
--8<---------------cut here---------------end--------------->8---
It works as well on actual programs such as the compiler itself, but
leads to a stack overflow on files with lots of unused variables, such
as `language/tree-il/compile-glil.scm', although `analyze-program' is
tail-recursive AFAICS (ideas welcome).
Also, it's annoying because it reports unused bindings introduced by
`record-case', and there are lots of them in the compiler.
Is this the right place and the right way to do such things? Comments?
Thanks,
Ludo'.
diff --git a/module/language/glil/compile-assembly.scm
b/module/language/glil/compile-assembly.scm
index 0b92a4e..5d3d400 100644
--- a/module/language/glil/compile-assembly.scm
+++ b/module/language/glil/compile-assembly.scm
@@ -26,7 +26,7 @@
#:use-module (system vm instruction)
#:use-module ((system vm program) #:select (make-binding))
#:use-module (ice-9 receive)
- #:use-module ((srfi srfi-1) #:select (fold))
+ #:use-module (srfi srfi-1)
#:use-module (rnrs bytevector)
#:export (compile-assembly))
@@ -134,6 +134,54 @@
(and (not (null? objects))
(list->vector (cons #f objects))))
+(define (analyze-program program)
+ (let loop ((glil (glil-program-body program))
+ (locals '())
+ (local-refs '())
+ (location #f))
+ (if (null? glil)
+ program
+ (record-case (car glil)
+ ((<glil-bind> vars)
+ (loop (cdr glil)
+ (append (filter-map (lambda (name+type+index)
+ (and (eq? (cadr name+type+index)
+ 'local)
+ (cons (caddr name+type+index)
+ (car name+type+index))))
+ vars)
+ locals)
+ local-refs
+ location))
+ ((<glil-local> op index)
+ (loop (cdr glil)
+ locals
+ (if (eq? op 'ref)
+ (cons index local-refs)
+ local-refs)
+ location))
+ ((<glil-unbind>)
+ (let ((unused (lset-difference = (map car locals)
+ local-refs))
+ (location (if (pair? location)
+ (format #f "~a:~a:~a"
+ (or (assoc-ref location 'filename)
+ "<stdin>")
+ (1+ (assoc-ref location 'line))
+ (assoc-ref location 'column))
+ "<unknown-location>")))
+ (for-each (lambda (var)
+ (format (current-error-port)
+ "~A: variable `~A' never referenced~%"
+ location
+ (assoc-ref locals var)))
+ unused)
+ (loop (cdr glil) '() '() location)))
+ ((<glil-source> props)
+ (loop (cdr glil) locals local-refs props))
+ (else
+ (loop (cdr glil) locals local-refs location))))))
+
(define (glil->assembly glil nexts-stack bindings
source-alist label-alist object-alist addr)
(define (emit-code x)
@@ -143,6 +191,7 @@
(record-case glil
((<glil-program> nargs nrest nlocs nexts meta body closure-level)
+ (analyze-program glil)
(let ((toplevel? (null? nexts-stack)))
(define (process-body)
(let ((nexts-stack (cons nexts nexts-stack)))
- Reporting unused local variables,
Ludovic Courtès <=