[plt-scheme] Some more syntax-handling fun --- trying to extract all the definitions in an arbitrary file

From: Danny Yoo (dyoo at hkn.eecs.berkeley.edu)
Date: Mon Mar 20 19:01:02 EST 2006

Hi everyone,

I know there's some code out there that does this already (DrScheme does
it of course!), but to better-understand macros and the subtleties of
module-or-top-identifier=?, I wrote a quick and dirty definition name
extractor.  Here's the code:


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(module get-definitions mzscheme
  (provide get-definitions/path
           get-definitions
           extract-definition)
  (require (lib "stx.ss" "syntax"))
  (require (lib "file.ss"))

  ;; get-definitions/path: path -> (listof symbol)
  ;;
  ;; Given a filename, opens it up and tries to extract out all the
  ;; definitions.
  (define (get-definitions/path path)
    (call-with-input-file*
     path
     (lambda (ip)
       (let ((stx (read-syntax path ip)))
         (get-definitions stx)))))


  ;; get-definitions: syntax -> (listof symbol)
  ;;
  ;; Given a syntax, tries to return all the toplevel defined names in
  ;; that syntax.
  (define (get-definitions stx)
    (syntax-case* stx (module) module-or-top-identifier=?
      ((module m-name lang s-expr ...)
       (mappend extract-definition (syntax->list (syntax (s-expr ...)))))
      ((s-expr ...)
       (mappend extract-definition (syntax->list (syntax (s-expr ...)))))))


  ;; mappend: (X -> (listof Y)) (listof X) -> (listof Y)
  ;;
  ;; mapping append.
  (define (mappend f l)
    (apply append (map f l)))


  ;; extract-definition: syntax -> (listof symbol)
  ;;
  ;; If the form looks like a define, tries to extract the toplevel
  ;; name.  Otherwise, returns the empty list.
  (define (extract-definition stx)
    (syntax-case* stx (define) module-or-top-identifier=?
      ((define (name args ...) body ...)
       (list (syntax-e (syntax name))))
      ((define name value)
       (list (syntax-e (syntax name))))
      (else
       (list)))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


Of course, I can't resist running this on itself.  *grin*

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
> (get-definitions/path "~/get-definitions.ss")
(get-definitions/path get-definitions mappend extract-definition)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

I'm really happy that this worked, but I know this is not quite robust
yet.  If I use other forms that expand out to DEFINEs, then I'm sunk at
the moment.  I need to understand how to use the expander functions.


I'm studying the reference manual about "Expanding Expressions to
Primitive Syntax", and was wondering: is EXPAND generally the right tool
to use to make sure the syntax is top-level-expr form before I start doing
the preprocessing stuff?  In what contexts might one want to use the other
expand-* functions?


Thanks a lot!



Posted on the users mailing list.