tags:

views:

47

answers:

1

So I'm playing around with a simple doc-string system as a warmup in scheme, the idea being you could do something like:

(def-with-doc (foo a b)
  (desc     "Takes two parameters and sums them")
  (param 'a "First parameter")
  (param 'b "Second parameter")
  (return   "Sum of arguments")
  (+ a b)

Which would be turned into:

(begin
  (begin
    (desc   'foo    "Takes two parameters and sums them")
    (param  'foo 'a "First parameter")
    (param  'foo 'b "Second parameter")
    (return 'foo    "Sum of arguments"))
  (begin
     (define (foo a b)
        (+ a b))))

The macro I've written:

(define doc-symbol-list '(param desc return))

(define-macro (def-with-doc arg-list #!rest body)
  ;; Loop over body, splitting into doc calls and everything else
  (let loop ((remaining body) (docs '()) (main '()))
    (if (null? remaining)
       ; Reverse accumulation order of docs and main
       ; And build re-ordered begin tree
       (let ((docs (cons 'begin (reverse docs)))
         (main (cons 'begin (reverse main))))
           (cons 'begin `(,docs ,`(define ,arg-list ,main))))

      ; Accumulate into docs list if expression is reserved
      ; Otherwise  into the body list
      (let ((sexp (car remaining)) (rest (cdr remaining)))
        (if (member (car sexp) doc-symbol-list)
        (loop rest (cons sexp docs) main)
        (loop rest  docs (cons sexp main)))))))

Takes the definition, moves the param/desc/return calls into the top level wrapped in begin statements and reconstructs the body of the function, that way the doc string calls are only executed once when the file is loaded rather than each time the function is called. I know I could manually put the doc-string stuff at the top level but I'm trying to emulate Python doc-strings.

Anyhow, the last think that I need to do is bind the function name (foo in above) into the doc-string calls, so that (param 'a "First parameter") becomes (param 'foo 'a "First parameter") so that the function each call is associated with is known. This is where I'm having trouble, every attempt I've made has failed to do what I want.

+1  A: 

I would suggest using define-syntax as it is hygienic and its syntax-rules are pretty easy to understand. syntax-rules are in a pattern-to-result format; if you can understand cond, you can understand syntax-rules.

I think this does what you want, judging by the before and after snippets.

(define-syntax def-with-doc
    (syntax-rules ()
      ;; this pattern
      [(_ (func params ...)
          (tag attributes ...)
          ...
          code)
       ;; is converted into
       (begin
         (tag (quote func) attributes ...)
         ...
         (define (func params ...)
           code))]))

Forgive my terminology because I've never used doc-strings. Basically, this matches against anything that follows that pattern of a function + params def, 0 or more tags with attributes, and a code statement.

Then, it just rearranges everything.

erjiang
I'll give this a shot, thanks!
gct