Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple lines comments in Scheme (RnRS)

I created this solution:

; use like this:
; (/* content ... */ <default-return>)
; or
; (/* content ... */) => #f
(define-syntax /*
  (syntax-rules (*/)
    ((/* body ... */) #f)
    ((/* body ... */ r) r)))

But is it really the best or easiest way?

like image 792
Felipe Avatar asked Dec 21 '22 23:12

Felipe


1 Answers

You can't do it this way -- it won't work for a number of contexts. Here are some examples that won't work:

(+ (/* foo */) 1 2)

(define (foo a (/* b */) c) ...)

(/* foo; bar */)

(/*x*/)

(let ((x (/* 1 */) 2))
  ...)

(let ((/* (x 1) */)
      (x 2))
  ...)

(car '((/* foo */) 1 2 3))

There is no standard multi-line comment in the Scheme reports up to R5RS, but R6RS has added a syntax that was widely used anyway: #|...|#.

But if you really want to...

Here's what I was talking about in the comment: if you're willing to wrap the whole code in a macro, then the macro can process the whole body, which can be effective in many more contexts. Pretty much all of them except for trying to comment out syntactically invalid stuffs like the semicolon example above, or an unterminated string. You can judge for yourself whether it's really worth the effort...

(Personally, as much as I enjoy such games, I still think they're pointless. But if you really enjoy these games and you think they're useful, then see the homework section below...)

(define-syntax prog (syntax-rules () [(_ x ...) (prog~ (begin x ...))]))
(define-syntax prog~
  (syntax-rules (/* */)
    [(prog~ (/* x ...) b ...)
     ;; comment start => mark it (possibly nested on top of a previous mark)
     (prog~ (x ...) /* b ...)]
    [(prog~ (*/ x ...) /* b ...)
     ;; finished eliminating a comment => continue
     (prog~ (x ...) b ...)]
    [(prog~ (*/ x ...) b ...)
     ;; a comment terminator without a marker => error
     (unexpected-comment-closing)]
    [(prog~ (x0 x ...) /* b ...)
     ;; some expression inside a comment => throw it out
     (prog~ (x ...) /* b ...)]
    [(prog~ ((y . ys) x ...) b ...)
     ;; nested expression start => save the context
     (prog~ (y . ys) prog~ ((x ...) (b ...)))]
    [(prog~ (x0 x ...) b ...)
     ;; atomic element => add it to the body
     (prog~ (x ...) b ... x0)]
    [(prog~ () prog~ ((x ...) (b ...)) nested ...)
     ;; nested expression done => restore context
     (prog~ (x ...) b ... (nested ...))]
    [(prog~ () /* b ...)
     ;; input done with an active marker => error
     (unterminated-comment-error)]
    [(prog~ () b ...)
     ;; all done, no markers, not nested => time for the burp.
     (b ...)]))

And an example:

(prog

 (define x 1)

 (display (+ x 2)) (newline)

 /*
 (display (+ x 10))
 /* nested comment! */
 (/ 5 0)
 */

 (define (show label /* a label to show in the output, before x */
               x /* display this (and a newline), then returns it */)
   (display label)
   (display x)
   (newline)
   x
   /* this comment doesn't prevent the function from returning x */)

 (let ([x 1] /* some comment here */ [y 2])
   (show "result = " /* now display the result of show... */
         (show "list = " (list x /* blah blah */ y)))
   'done /* just a value to return from the `let' expression */)

 (show "and ... " '(even works /* boo! */ inside a quote))

 )

Homework

For extra credit, extend it so you can comment out unbalanced parens. For example, make this work:

(prog
 blah blah /* junk ( junk */ blah blah /* junk ) junk */ blah blah.
 )

Obviously, the input as a whole should have balanced parens -- this means that there's not much point in implementing this kind of an extension. Even without it, what's the point in commenting out an unbalanced paren?

But if anyone got all the way here, then you must enjoy this kind of self-torture ... right?

like image 186
Eli Barzilay Avatar answered Dec 31 '22 15:12

Eli Barzilay