#| Copyright (c) 2006 Cadence Research Systems Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |# #| ------------------------------------------------------------------------ Acknowledgements: This code is derived from the portable implementation of syntax-case extracted from Chez Scheme Version 7.0 (Sep 02, 2005), written by Kent Dybvig, Oscar Waddell, Bob Hieb, and Carl Bruggeman. |# #| ------------------------------------------------------------------------ Compatibility notes: - makes use of #'x abbreviation for (syntax x) - makes use of [ ] alternative for ( ) - bodies with internal variable definitions expand into letrec* - the quasiquote transformer supports Alan Bawden's PEPM '99 nested quasiquote extensions - implements (define id) syntax - implements when and unless - implements fresh-syntax form mentioned in SRFI issues section - should use R6RS exception/condition facilities rather than implementation-dependent error hook - should use and define when, unless, and let-values instead of using internally defined when, unless, and (simplified) let-values. - should support R6RS libraries - should use R6RS records in place of vector-based structures - should use R6RS (unspecified) instead of (void) - should add support for R6RS case-lambda |# #| ------------------------------------------------------------------------ Porting notes: To port this code to a new Scheme implementation, load syntax.pp (the expanded version of syntax.ss), and register sc-expand as the current expander (how this is done depends upon the implementation of Scheme). The hooks and constructors defined toward the beginning of the code below should also be changed to accommodate the requirements of the Scheme implementation. |# ; ------------------------------------------------------------------------- (let () ;; target implementation customization (begin (define eval-hook (lambda (x) (eval x))) (define error-hook (lambda (who why what) (error who "~a ~s" why what))) (define gensym-hook gensym) (define no-source #f) (define annotation? (lambda (x) #f)) (define annotation-expression (lambda (x) x)) (define annotation-source (lambda (x) no-source)) (define strip-annotation (lambda (x) x)) (define globals '()) (define global-extend (lambda (type sym value) (set! globals (cons (cons sym (make-binding type value)) globals)))) (define global-lookup (lambda (sym) (cond [(assq sym globals) => cdr] [else (cons 'global sym)]))) (define build-application (lambda (src proc-expr arg-expr*) (cons proc-expr arg-expr*))) (define-syntax build-conditional (syntax-rules () [(_ src test-expr then-expr else-expr) `(if ,test-expr ,then-expr ,else-expr)] [(_ src test-expr then-expr) `(if ,test-expr ,then-expr (void))])) (define build-global-reference (lambda (src var) var)) (define build-lexical-reference (lambda (src var) var)) (define build-lexical-assignment (lambda (src var expr) `(set! ,var ,expr))) (define build-global-assignment (lambda (src var expr) `(set! ,var ,expr))) (define build-lambda (lambda (src var* rest? expr) `(lambda ,(if rest? (let f ([var (car var*)] [var* (cdr var*)]) (if (pair? var*) (cons var (f (car var*) (cdr var*))) var)) var*) ,expr))) (define build-primref (lambda (src name) name)) (define build-data (lambda (src datum) `(quote ,datum))) (define build-sequence (lambda (src expr*) (let loop ([expr* expr*]) (if (null? (cdr expr*)) (car expr*) `(begin ,@expr*))))) (define build-letrec (lambda (src var* rhs-expr* body-expr) (if (null? var*) body-expr `(letrec ,(map list var* rhs-expr*) ,body-expr)))) (define build-letrec* (lambda (src var* rhs-expr* body-expr) (if (null? var*) body-expr `(letrec* ,(map list var* rhs-expr*) ,body-expr)))) (define build-lexical-var (lambda (src id) (gensym))) (define self-evaluating? (lambda (x) (or (boolean? x) (number? x) (string? x) (char? x)))) ) ;; generic procedures and syntax used within expander code only (define andmap (lambda (f ls . more) (let andmap ([ls ls] [more more] [a #t]) (if (null? ls) a (let ([a (apply f (car ls) (map car more))]) (and a (andmap (cdr ls) (map cdr more) a))))))) (define-syntax define-structure (lambda (x) (define construct-name (lambda (template-identifier . arg*) (datum->syntax template-identifier (string->symbol (apply string-append (map (lambda (x) (if (string? x) x (symbol->string (syntax->datum x)))) arg*)))))) (syntax-case x () [(_ (name id ...)) (let ([id* #'(id ...)]) (with-syntax ([constructor (construct-name #'name "make-" #'name)] [predicate (construct-name #'name #'name "?")] [(access ...) (map (lambda (x) (construct-name x #'name "-" x)) id*)] [(assign ...) (map (lambda (x) (construct-name x "set-" #'name "-" x "!")) id*)] [structure-length (+ (length id*) 1)] [(index ...) (let f ([i 1] [id* id*]) (if (null? id*) '() (cons i (f (+ i 1) (cdr id*)))))]) #'(begin (define constructor (lambda (id ...) (vector 'name id ... ))) (define predicate (lambda (x) (and (vector? x) (= (vector-length x) structure-length) (eq? (vector-ref x 0) 'name)))) (define access (lambda (x) (vector-ref x index))) ... (define assign (lambda (x update) (vector-set! x index update))) ...)))]))) (define-syntax let-values ; single-clause version (syntax-rules () ((_ ((formals expr)) form1 form2 ...) (call-with-values (lambda () expr) (lambda formals form1 form2 ...))))) ;; start of expander-specific code ;; syntax objects consist of an expression and a wrap comprised of a ;; list of marks and list of substitutions. (define-structure (syntax-object expression mark* subst*)) ;; strip strips away syntax-object and annotation wrappers (define strip (lambda (x m*) (if (top-marked? m*) (strip-annotation x) (let f ([x x]) (cond [(syntax-object? x) (strip (syntax-object-expression x) (syntax-object-mark* x))] [(pair? x) (let ([a (f (car x))] [d (f (cdr x))]) (if (and (eq? a (car x)) (eq? d (cdr x))) x (cons a d)))] [(vector? x) (let ([old (vector->list x)]) (let ([new (map f old)]) (if (andmap eq? old new) x (list->vector new))))] [else x]))))) ;; source returns the source, if any, associated with a syntax object (define source (lambda (e) (if (syntax-object? e) (source (syntax-object-expression e)) (if (annotation? e) (annotation-source e) no-source)))) ;; unannotate removes top level of annotation, if any (define unannotate (lambda (x) (if (annotation? x) (annotation-expression x) x))) ;; compile-time environments ;; wrap and environment comprise two level mapping. ;; ;; : id --> label ;; : label --> ;; marks must be comparable with "eq?" and distinct from pairs and ;; the symbol top. (define top-mark* '(top)) (define top-marked? (lambda (m*) (memq (car top-mark*) m*))) (define gen-mark (lambda () (string #\m))) (define anti-mark #f) (define add-mark (lambda (m e) (syntax-object e (list m) '(shift)))) (define same-marks? (lambda (x y) (or (eq? x y) (and (and (not (null? x)) (not (null? y))) (eq? (car x) (car y)) (same-marks? (cdr x) (cdr y)))))) ;; substs are ribs or the special subst shift. a shift is added into ;; a subst list whenever a mark is added. its presence tells the lookup ;; routine (id->label) to shift (cdr) the marks ;; ;; ::= | shift ;; ::= #(( ...) (( ...) ...) (