On Apr 9, 8:42 pm, Eduardo Cavazos <[email protected]> wrote:
> Hello,
>
> I've mentioned the idea of "programmable delimiters" here before.
>
> My 'define-record-type++' code (ab)uses the popular "dot" syntax for
> method invocation (and field access). In the spirit of "programmable
> delimiters", I'm now wondering about a "programmable dot". Right now,
> the dot syntax indicates a literal pair. With a programmable dot, you'd
> get an expansion into:
>
>      (dot LEFT-EXPR RIGHT-EXPR)
>
> And the default binding of the 'dot' macro would be to call 'cons'.
>
> Of course, for this to work with things like method invocation:
>
>      (num.sqrt)
>
> the dot would have to be recognized even when not whitespace delimited.
> Still, in certain libraries, I'd be happy to exchange literal pair
> syntax for a 'dot' macro.
>
> Ed

Hi!

I experimented with something similar a while ago and this macro came
out of it:

#!r6rs
(library (my syntax-walker)
  (export with-special-syntax)
  (import (rnrs))

  (define-syntax with-special-syntax
    (lambda (stx)
      (syntax-case stx ()
        ((_ transformer body0 body ...)
         #'(begin
             (define-syntax walker
               (lambda (stx)
                 (define transform transformer)
                 (define (walk stx)
                   (let ((stx2 (guard
                                (con ((syntax-violation? con) stx))
                                (transform stx))))
                     (if (eq? stx2 stx)
                         (syntax-case stx2 (quote quasiquote)
                           ; quoted expressions
                           ((quote x) #'(quote x))
                           ; quasiquoted expressions
                           ((quasiquote x)
                            #`(quasiquote #,(walk-quasiquote #'x)))
                           ; lists
                           ((x y (... ...) . r)
                            #`(#,@(map walk #'(x y (... ...))) . #,
(walk #'r)))
                           ; unquoted vectors
                           (#(x (... ...))
                            #`#(#,@(map walk #'(x (... ...)))))
                           ; everything else
                           (x #'x))
                         (walk stx2))))
                 (define (walk-quasiquote stx)
                   (syntax-case stx (unquote unquote-splicing)
                     ((unquote x)
                      #`(unquote #,(walk #'x)))
                     ((unquote-splicing x)
                      #`(unquote-splicing #,(walk #'x)))
                     ((x y (... ...) . r)
                      #`(#,@(map walk-quasiquote #'(x y (... ...))) .
#,(walk-quasiquote #'r)))
                     (x #'x)))
                 (syntax-case stx ()
                   ((_ a) (walk #'a)))))
             (walker body0)
             (walker body) ...))))))



With this you can do some nifty stuff:

#!r6rs
(import (rnrs)
        (for (rnrs mutable-pairs) expand)
        (my syntax-walker))

(with-special-syntax ; dot
 (lambda (stx)
   (define (split-symbol x)
     (let* ((s (symbol->string x))
            (l (string-length s)))
       (let loop ((i (- l 2)))
         (cond
           ((< i 1) #f)
           ((char=? (string-ref s i) #\.)
            (cons (string->symbol (substring s 0 i))
                  (string->symbol (substring s (+ i 1) l))))
           (else (loop (- i 1)))))))
   (syntax-case stx ()
     ((x y ...)
      (identifier? #'x)
      (let ((v (split-symbol (syntax->datum #'x))))
        (if (pair? v)
            (cons* (datum->syntax #'x (cdr v))
                   (datum->syntax #'x (car v)) #'(y ...))
            stx)))
     (x
      (identifier? #'x)
      (let ((v (split-symbol (syntax->datum #'x))))
        (if (pair? v)
            (list (datum->syntax #'x (cdr v))
                  (datum->syntax #'x (car v)))
            stx)))))

 (define l '(1 2 3))
 (display l.car)
 (newline)
 (display l.cdr)
 (newline)
 (display l.length)
 (newline)
 l.null?.display
 (newline))

;=> 1
;=> (2 3)
;=> 3
;=> #f

(with-special-syntax ; keyword
 (lambda (stx)
   (syntax-case stx ()
     (x
      (and (identifier? #'x)
           (char=?
             (string-ref (symbol->string (syntax->datum #'x)) 0) #\:))
      #'(quote x))))

 (display :keyword)
 (newline)
 (display (symbol? :keyword))
 (newline))

;=> :keyword
;=> #t

(with-special-syntax ; list-ref (ok this is dumb, but whatever)
 (lambda (stx)
   (syntax-case stx (in)
     ((a in b)
      #'(list-ref b a))))

 (display (2 in '(1 2 3 4)))
 (newline))

;=> 3

(with-special-syntax ; unquoted vector
 (let ((counter 345734817))
   (lambda (stx)
     (define (gensym)
       (set! counter (+ counter 1))
       (string->symbol (string-append "partial-app-gensym-"
                                      (number->string counter))))
     (define (last-pair ls)
       (if (null? (cdr ls))
           ls
           (last-pair (cdr ls))))
     (syntax-case stx ()
       (#(f args ...)
        (identifier? #'f)
        (let loop ((oldargs #'(args ...))
                   (newargs '())
                   (lambdalist '()))
          (syntax-case oldargs ()
            ((x)
             (let ((lambdalist (reverse lambdalist)))
               (if (eq? (syntax->datum #'x) '_)
                   (let ((sym (gensym)))
                     (if (null? lambdalist)
                         (set! lambdalist sym)
                         (set-cdr! (last-pair lambdalist) sym))
                     #`(lambda #,lambdalist
                         (apply f #,@(reverse newargs) #,sym)))
                   #`(lambda #,lambdalist
                       (f #,@(reverse (cons #'x newargs)))))))
            ((x y ...)
             (if (eq? (syntax->datum #'x) '_)
                 (let ((sym (gensym)))
                   (loop #'(y ...)
                         (cons sym newargs)
                         (cons sym lambdalist)))
                 (loop #'(y ...)
                       (cons #'x newargs)
                       lambdalist)))))))))

 (display (map #(+ _ 1) '(1 2 3 4)))
 (newline)
 (display (map #(* _ _) '(1 2 3 4) '(2 3 4 5)))
 (newline)
 (display (#(list _) 1 2 3 4))
 (newline))

;=> (2 3 4 5)
;=> (2 6 12 20)
;=> (1 2 3 4)

In case you're wondering about the guard expression in the
with-special-syntax macro, it's there so I don't have to put
(_ stx) as default clause into all the transformer procedures.

If you like it, feel free to use it however you like.

Greetings,
Juergen

Reply via email to