;; -*-scheme-*- ;;; Taken from scheme48-0-21/alt/syntax.scm -- the file itself ;;; mentions no license or copyright, but this is in COPYING ;; Copyright (c) 1993 by Richard Kelsey and Jonathan Rees. ;; Use of this program for non-commercial purposes is permitted provided ;; that such use is acknowledged both in the software itself and in ;; accompanying documentation. ;; Use of this program for commercial purposes is also permitted, but ;; only if, in addition to the acknowledgement required for ;; non-commercial users, written notification of such use is provided by ;; the commercial user to the authors prior to the fabrication and ;; distribution of the resulting software. (define (syntax-error message thing) (display "syntax-error:") (display message) (display ":") ;;(display thing) (newline)) (display "mes:define-syntax...") (define-macro (mes:define-syntax macro-name transformer . stuff) `(define-macro (,macro-name . args) (,transformer (cons ',macro-name args) (lambda (x) x) eq?))) ;; Rewrite-rule compiler (a.k.a. "extend-syntax") ;; Example: ;; ;; (define-syntax or ;; (syntax-rules () ;; ((or) #f) ;; ((or e) e) ;; ((or e1 e ...) (let ((temp e1)) ;; (if temp temp (or e ...)))))) (newline) (display "mes:define-syntax syntax-rules...") (newline) (mes:define-syntax syntax-rules (let () (define name? symbol?) (define (segment-pattern? pattern) (and (segment-template? pattern) (or (null? (cddr pattern)) (syntax-error "segment matching not implemented" pattern)))) (define (segment-template? pattern) (and (pair? pattern) (pair? (cdr pattern)) (memq (cadr pattern) indicators-for-zero-or-more))) (define indicators-for-zero-or-more (list (string->symbol "...") '---)) (lambda (exp r c) (define %input (r '%input)) ;Gensym these, if you like. (define %compare (r '%compare)) (define %rename (r '%rename)) (define %tail (r '%tail)) (define %temp (r '%temp)) (define rules (cddr exp)) (define subkeywords (cadr exp)) (define (make-transformer rules) `(lambda (,%input ,%rename ,%compare) (let ((,%tail (cdr ,%input))) (cond ,@(map process-rule rules) (else (syntax-error "use of macro doesn't match definition" ,%input)))))) (define (process-rule rule) (cond ((and (pair? rule) (pair? (cdr rule)) (null? (cddr rule))) (let ((pattern (cdar rule)) (template (cadr rule))) `((and ,@(process-match %tail pattern)) (let* ,(process-pattern pattern %tail (lambda (x) x)) ,(process-template template 0 (meta-variables pattern 0 '())))))) (syntax-error "ill-formed syntax rule" rule))) ;; Generate code to test whether input expression matches pattern (define (process-match input pattern) (cond ((name? pattern) (cond ((member pattern subkeywords) `((,%compare ,input (,%rename ',pattern)))) (#t `()))) ((segment-pattern? pattern) (process-segment-match input (car pattern))) ((pair? pattern) `((let ((,%temp ,input)) (and (pair? ,%temp) ,@(process-match `(car ,%temp) (car pattern)) ,@(process-match `(cdr ,%temp) (cdr pattern)))))) ((or (null? pattern) (boolean? pattern) (char? pattern)) `((eq? ,input ',pattern))) (else `((equal? ,input ',pattern))))) (define (process-segment-match input pattern) (let ((conjuncts (process-match '(car l) pattern))) (cond ((null? conjuncts) `((list? ,input))) ;+++ (#t `((let loop ((l ,input)) (or (null? l) (and (pair? l) ,@conjuncts (loop (cdr l)))))))))) ;; Generate code to take apart the input expression ;; This is pretty bad, but it seems to work (can't say why). (define (process-pattern pattern path mapit) (cond ((name? pattern) (cond ((memq pattern subkeywords) '()) (#t (list (list pattern (mapit path)))))) ((segment-pattern? pattern) (process-pattern (car pattern) %temp (lambda (x) ;temp is free in x (mapit (cond ((eq? %temp x) path) ;+++ (#t `(map (lambda (,%temp) ,x) ,path))))))) ((pair? pattern) (append (process-pattern (car pattern) `(car ,path) mapit) (process-pattern (cdr pattern) `(cdr ,path) mapit))) (else '()))) ;; Generate code to compose the output expression according to template (define (process-template template rank env) (cond ((name? template) (let ((probe (assq template env))) (cond (probe (cond ((<= (cdr probe) rank) template) (#t (syntax-error "template rank error (too few ...'s?)" template)))) (#t `(,%rename ',template))))) ((segment-template? template) (let ((vars (free-meta-variables (car template) (+ rank 1) env '()))) (cond ((null? vars) (syntax-error "too many ...'s" template)) (#t (let* ((x (process-template (car template) (+ rank 1) env)) (gen (cond ((equal? (list x) vars) x) ;+++ (#t `(map (lambda ,vars ,x) ,@vars))))) (cond ((null? (cddr template)) gen) ;+++ (else `(append ,gen ,(process-template (cddr template) rank env))))))))) ((pair? template) `(cons ,(process-template (car template) rank env) ,(process-template (cdr template) rank env))) (else `(quote ,template)))) ;; Return an association list of (var . rank) (define (meta-variables pattern rank vars) (cond ((name? pattern) (cond ((memq pattern subkeywords) vars) (else (cons (cons pattern rank) vars)))) ((segment-pattern? pattern) (meta-variables (car pattern) (+ rank 1) vars)) ((pair? pattern) (meta-variables (car pattern) rank (meta-variables (cdr pattern) rank vars))) (else vars))) ;; Return a list of meta-variables of given higher rank (define (free-meta-variables template rank env free) (cond ((name? template) (cond ((and (not (memq template free)) (let ((probe (assq template env))) (and probe (>= (cdr probe) rank)))) (cons template free)) (else free))) ((segment-template? template) (free-meta-variables (car template) rank env (free-meta-variables (cddr template) rank env free))) ((pair? template) (free-meta-variables (car template) rank env (free-meta-variables (cdr template) rank env free))) (else free))) c ;ignored ;; Kludge for Scheme48 linker. ;; `(cons ,(make-transformer rules) ;; ',(find-free-names-in-syntax-rules subkeywords rules)) (make-transformer rules)))) (mes:define-syntax mes:or (syntax-rules () ((mes:or) #f) ((mes:or e) e) ((mes:or e1 e ...) (let ((temp e1)) (cond (temp temp) (#t (or e ...))))))) (display "(mes:or #f (= 0 1) 'hello-syntax-world): ") (display (mes:or #f (= 0 1) 'hello-syntax-world)) (display (mes:or #f '==>baaa)) (newline) (mes:define-syntax mes:when (syntax-rules () ((when condition exp ...) (if condition (begin exp ...))))) (display (mes:when #t "when:hello syntax world")) (newline) 'syntax-dun