unofficial mirror of guile-user@gnu.org 
 help / color / mirror / Atom feed
* Unbound variables used within a form
@ 2012-10-13  0:12 Panicz Maciej Godek
  2012-10-13  5:42 ` Mark H Weaver
  2012-10-13 12:54 ` Ludovic Courtès
  0 siblings, 2 replies; 4+ messages in thread
From: Panicz Maciej Godek @ 2012-10-13  0:12 UTC (permalink / raw)
  To: guile-user

Hey,
I just wrote the biggest function in my life :)
It takes a scheme program and returns the list
of all variables (symbols) that are used but
unbound within that form. The code is pretty
straightforward:

(use-modules (srfi srfi-1)(ice-9 match)(srfi srfi-11))

(define (properize src . dst)
"Change an improper list into a proper list"
  (cond ((pair? src)
	 (apply properize (cdr src) (cons (car src) dst)))
	((null? src)
	 (reverse dst))
	(else
	 (reverse (cons src dst)))))

(define (used-variables form)
  (define (diff . args) (apply lset-difference equal? args))
  (define (join . args) (apply lset-union equal? args))
  (define (bound-variables bindings)
    (let-values (((names forms) (unzip2 bindings)))
      (values names (append-map used-variables forms))))
  (define (argument-name arg)
    (cond ((symbol? arg) arg)
	  ((pair? arg) (car arg))
	  (else #f)))
  (match form
    (((or 'let 'letrec 'letrec*) (bindings ...) body ...)
     (let-values (((shadowed used) (bound-variables bindings)))
       (join used (diff (append-map used-variables body) (diff
shadowed used)))))
    (('let (? symbol? name) (bindings ...) body ...)
     (let-values (((shadowed used) (bound-variables bindings)))
       (join used (diff (append-map used-variables body) (diff
shadowed used) (list name)))))
    (('begin body ...)
     (append-map used-variables body))
    (((or 'lambda 'lambda*) arg body ...)
     (cond
      ((or (pair? arg) (list? arg))
       (diff (append-map used-variables body) (filter-map
argument-name (properize arg))))
      ((symbol? arg)
       (diff (append-map used-variables body) (list arg)))))
    (((or 'define 'define*) (name ...) body ...)
     (diff (append-map used-variables body) name))
    (('define name value)
     (diff (used-variables value) name))
    (((or 'case-lambda 'case-lambda*) def ...)
     (apply join (map (match-lambda ((arg body)
				     (cond
				      ((symbol? arg)
				       (diff (append-map used-variables body) (list arg)))
				      ((or (pair? arg) (list? arg))
				       (diff (append-map used-variables body)
					     (filter-map argument-name (properize arg)))))))
		      def)))
    (((or 'if 'or 'and) expr ...)
     (append-map used-variables expr))
    (('quote data)
     '())
    (('quasiquote data)
     (letrec ((quasiquote-variables (match-lambda
				     (('unquote data) (used-variables data))
				     ((data ...) (append-map quasiquote-variables data))
				     (else '()))))
       (quasiquote-variables data)))
    (('@@ name ...)
     '())
    ((procedure ...)
     (append-map used-variables procedure))
    ((? symbol? variable)
       (list variable))
    (else
     '())))

At least for simple cases it seems to work alright.
It has been written specifically for guile, so it took into
account various primitive language constructs that
extend RnRS (like case-lambda or lambda*).

Obviously, feel free to use the code any way you like.
I just wanted to ask:
- beside lambda*, case-lambda, case-lambda*,
are there any additional extensions that guile introduced
atop the Report that should be taken into account in this code?
- is there any simpler way to achieve the same effect, ie.
to acquire all external symbols that are meaningful within
a form (assuming the core semantics, that is, that all
the macros were expanded)

Yours,
M



^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2012-10-13 12:54 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-10-13  0:12 Unbound variables used within a form Panicz Maciej Godek
2012-10-13  5:42 ` Mark H Weaver
2012-10-13 11:40   ` Panicz Maciej Godek
2012-10-13 12:54 ` Ludovic Courtès

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).