Merge branch 'stable-2.0'
[bpt/guile.git] / module / ice-9 / psyntax.scm
index 90c76d5..cfcea4b 100644 (file)
 ;;; revision control logs corresponding to this file: 2009, 2010.
 
 
+;;; This code is based on "Syntax Abstraction in Scheme"
+;;; by R. Kent Dybvig, Robert Hieb, and Carl Bruggeman.
+;;; Lisp and Symbolic Computation 5:4, 295-326, 1992.
+;;; <http://www.cs.indiana.edu/~dyb/pubs/LaSC-5-4-pp295-326.pdf>
+
+
 ;;; This file defines the syntax-case expander, macroexpand, and a set
 ;;; of associated syntactic forms and procedures.  Of these, the
 ;;; following are documented in The Scheme Programming Language,
         (lambda (symbol module)
           (if (and (not module) (current-module))
               (warn "module system is booted, we should have a module" symbol))
-          (let ((v (module-variable (if module
-                                        (resolve-module (cdr module))
-                                        (current-module))
-                                    symbol)))
-            (and v (variable-bound? v)
-                 (let ((val (variable-ref v)))
-                   (and (macro? val) (macro-type val)
-                        (cons (macro-type val)
-                              (macro-binding val)))))))))
+          (and (not (equal? module '(primitive)))
+               (let ((v (module-variable (if module
+                                             (resolve-module (cdr module))
+                                             (current-module))
+                                         symbol)))
+                 (and v (variable-bound? v)
+                      (let ((val (variable-ref v)))
+                        (and (macro? val) (macro-type val)
+                             (cons (macro-type val)
+                                   (macro-binding val))))))))))
 
 
     (define (decorate-source e s)
       (lambda (source test-exp then-exp else-exp)
         (make-conditional source test-exp then-exp else-exp)))
   
-    (define build-dynlet
-      (lambda (source fluids vals body)
-        (make-dynlet source fluids vals body)))
-  
     (define build-lexical-reference
       (lambda (type source name var)
         (make-lexical-ref source name var)))
                                   (module-variable (resolve-module mod) var))
                              (modref-cont mod var #f)
                              (bare-cont var)))
+              ((primitive)
+               (syntax-violation #f "primitive not in operator position" var))
               (else (syntax-violation #f "bad module kind" var mod))))))
 
     (define build-global-reference
     ;;    displaced-lexical      none          displaced lexical identifier
     ;;    lexical-call           name          call to lexical variable
     ;;    global-call            name          call to global variable
+    ;;    primitive-call         name          call to primitive
     ;;    call                   none          any other call
     ;;    begin-form             none          begin expression
     ;;    define-form            id            variable definition
                   ((lexical)
                    (values 'lexical-call fval e e w s mod))
                   ((global)
-                   ;; If we got here via an (@@ ...) expansion, we need to
-                   ;; make sure the fmod information is propagated back
-                   ;; correctly -- hence this consing.
-                   (values 'global-call (make-syntax-object fval w fmod)
-                           e e w s mod))
+                   (if (equal? fmod '(primitive))
+                       (values 'primitive-call fval e e w s mod)
+                       ;; If we got here via an (@@ ...) expansion, we
+                       ;; need to make sure the fmod information is
+                       ;; propagated back correctly -- hence this
+                       ;; consing.
+                       (values 'global-call (make-syntax-object fval w fmod)
+                               e e w s mod)))
                   ((macro)
                    (syntax-type (expand-macro fval e r w s rib mod)
                                 r empty-wrap s rib mod for-car?))
                   ((module-ref)
-                   (call-with-values (lambda () (fval e r w))
+                   (call-with-values (lambda () (fval e r w mod))
                      (lambda (e r w s mod)
                        (syntax-type e r w s rib mod for-car?))))
                   ((core)
            ;; apply transformer
            (value e r w s mod))
           ((module-ref)
-           (call-with-values (lambda () (value e r w))
+           (call-with-values (lambda () (value e r w mod))
              (lambda (e r w s mod)
                (expand e r w mod))))
           ((lexical-call)
                                         (syntax-object-module value)
                                         mod))
             e r w s mod))
+          ((primitive-call)
+           (syntax-case e ()
+             ((_ e ...)
+              (build-primcall s
+                              value
+                              (map (lambda (e) (expand e r w mod))
+                                   #'(e ...))))))
           ((constant) (build-data s (strip (source-wrap e w s mod) empty-wrap)))
           ((global) (build-global-reference s value mod))
           ((call) (expand-call (expand (car e) r w mod) e r w s mod))
 
     (global-extend 'core 'case-lambda
                    (lambda (e r w s mod)
+                     (define (build-it meta clauses)
+                       (call-with-values
+                           (lambda ()
+                             (expand-lambda-case e r w s mod
+                                                 lambda-formals
+                                                 clauses))
+                         (lambda (meta* lcase)
+                           (build-case-lambda s (append meta meta*) lcase))))
                      (syntax-case e ()
-                       ((_ (args e1 e2 ...) (args* e1* e2* ...) ...)
-                        (call-with-values
-                            (lambda ()
-                              (expand-lambda-case e r w s mod
-                                                  lambda-formals
-                                                  #'((args e1 e2 ...) (args* e1* e2* ...) ...)))
-                          (lambda (meta lcase)
-                            (build-case-lambda s meta lcase))))
+                       ((_ (args e1 e2 ...) ...)
+                        (build-it '() #'((args e1 e2 ...) ...)))
+                       ((_ docstring (args e1 e2 ...) ...)
+                        (string? (syntax->datum #'docstring))
+                        (build-it `((documentation
+                                     . ,(syntax->datum #'docstring)))
+                                  #'((args e1 e2 ...) ...)))
                        (_ (syntax-violation 'case-lambda "bad case-lambda" e)))))
 
     (global-extend 'core 'case-lambda*
                    (lambda (e r w s mod)
+                     (define (build-it meta clauses)
+                       (call-with-values
+                           (lambda ()
+                             (expand-lambda-case e r w s mod
+                                                 lambda*-formals
+                                                 clauses))
+                         (lambda (meta* lcase)
+                           (build-case-lambda s (append meta meta*) lcase))))
                      (syntax-case e ()
-                       ((_ (args e1 e2 ...) (args* e1* e2* ...) ...)
-                        (call-with-values
-                            (lambda ()
-                              (expand-lambda-case e r w s mod
-                                                  lambda*-formals
-                                                  #'((args e1 e2 ...) (args* e1* e2* ...) ...)))
-                          (lambda (meta lcase)
-                            (build-case-lambda s meta lcase))))
+                       ((_ (args e1 e2 ...) ...)
+                        (build-it '() #'((args e1 e2 ...) ...)))
+                       ((_ docstring (args e1 e2 ...) ...)
+                        (string? (syntax->datum #'docstring))
+                        (build-it `((documentation
+                                     . ,(syntax->datum #'docstring)))
+                                  #'((args e1 e2 ...) ...)))
                        (_ (syntax-violation 'case-lambda "bad case-lambda*" e)))))
 
     (global-extend 'core 'let
               (case type
                 ((module-ref)
                  (let ((val (expand #'val r w mod)))
-                   (call-with-values (lambda () (value #'(head tail ...) r w))
+                   (call-with-values (lambda () (value #'(head tail ...) r w mod))
                      (lambda (e r w s* mod)
                        (syntax-case e ()
                          (e (id? #'e)
          (_ (syntax-violation 'set! "bad set!" (source-wrap e w s mod))))))
 
     (global-extend 'module-ref '@
-                   (lambda (e r w)
+                   (lambda (e r w mod)
                      (syntax-case e ()
                        ((_ (mod ...) id)
                         (and (and-map id? #'(mod ...)) (id? #'id))
                                  #'(public mod ...)))))))
 
     (global-extend 'module-ref '@@
-                   (lambda (e r w)
+                   (lambda (e r w mod)
                      (define remodulate
                        (lambda (x mod)
                          (cond ((pair? x)
                                       ((fx= i n) v)
                                     (vector-set! v i (remodulate (vector-ref x i) mod)))))
                                (else x))))
-                     (syntax-case e (@@)
+                     (syntax-case e (@@ primitive)
+                       ((_ primitive id)
+                        (and (id? #'id)
+                             (equal? (cdr (if (syntax-object? #'id)
+                                              (syntax-object-module #'id)
+                                              mod))
+                                     '(guile)))
+                        ;; Strip the wrap from the identifier and return top-wrap
+                        ;; so that the identifier will not be captured by lexicals.
+                        (values (syntax->datum #'id) r top-wrap #f '(primitive)))
                        ((_ (mod ...) id)
                         (and (and-map id? #'(mod ...)) (id? #'id))
                         ;; Strip the wrap from the identifier and return top-wrap
                          (expand #'then r w mod)
                          (expand #'else r w mod))))))
 
-    (global-extend 'core 'with-fluids
-                   (lambda (e r w s mod)
-                     (syntax-case e ()
-                       ((_ ((fluid val) ...) b b* ...)
-                        (build-dynlet
-                         s
-                         (map (lambda (x) (expand x r w mod)) #'(fluid ...))
-                         (map (lambda (x) (expand x r w mod)) #'(val ...))
-                         (expand-body #'(b b* ...)
-                                      (source-wrap e w s mod) r w mod))))))
-  
     (global-extend 'begin 'begin '())
 
     (global-extend 'define 'define '())
                        (lambda (pattern keys)
                          (define cvt*
                            (lambda (p* n ids)
-                             (if (not (pair? p*)) 
-                                 (cvt p* n ids)
-                                 (call-with-values
-                                     (lambda () (cvt* (cdr p*) n ids))
+                             (syntax-case p* ()
+                               ((x . y)
+                                (call-with-values
+                                     (lambda () (cvt* #'y n ids))
                                    (lambda (y ids)
                                      (call-with-values
-                                         (lambda () (cvt (car p*) n ids))
+                                         (lambda () (cvt #'x n ids))
                                        (lambda (x ids)
-                                         (values (cons x y) ids))))))))
+                                         (values (cons x y) ids))))))
+                               (_ (cvt p* n ids)))))
                          
                          (define (v-reverse x)
                            (let loop ((r '()) (x x))
                              (lambda () (convert-pattern pat keys))
                            (lambda (p pvars)
                              (cond
-                              ((not (distinct-bound-ids? (map car pvars)))
-                               (syntax-violation 'syntax-case "duplicate pattern variable" pat))
                               ((not (and-map (lambda (x) (not (ellipsis? (car x)))) pvars))
                                (syntax-violation 'syntax-case "misplaced ellipsis" pat))
+                              ((not (distinct-bound-ids? (map car pvars)))
+                               (syntax-violation 'syntax-case "duplicate pattern variable" pat))
                               (else
                                (let ((y (gen-var 'tmp)))
                                  ;; fat finger binding and references to temp variable y
     (let ()
       (define (syntax-module id)
         (arg-check nonsymbol-id? id 'syntax-module)
-        (cdr (syntax-object-module id)))
+        (let ((mod (syntax-object-module id)))
+          (and (not (equal? mod '(primitive)))
+               (cdr mod))))
 
       (define* (syntax-local-binding id #:key (resolve-syntax-parameters? #t))
         (arg-check nonsymbol-id? id 'syntax-local-binding)
                  ((syntax-parameter) (values 'syntax-parameter (car value)))
                  ((syntax) (values 'pattern-variable value))
                  ((displaced-lexical) (values 'displaced-lexical #f))
-                 ((global) (values 'global (cons value (cdr mod))))
+                 ((global)
+                  (if (equal? mod '(primitive))
+                      (values 'primitive value)
+                      (values 'global (cons value (cdr mod)))))
                  (else (values 'other #f))))))))
 
       (define (syntax-locally-bound-identifiers id)
 
 (define-syntax include
   (lambda (x)
-    (define (absolute-path? path)
-      (string-prefix? "/" path))
-
     (define read-file
       (lambda (fn dir k)
-        (let ((p (open-input-file
-                  (if (absolute-path? fn)
-                      fn
-                      (in-vicinity dir fn)))))
+        (let* ((p (open-input-file
+                   (cond ((absolute-file-name? fn)
+                          fn)
+                         (dir
+                          (in-vicinity dir fn))
+                         (else
+                          (syntax-violation
+                           'include
+                           "relative file name only allowed when the include form is in a file"
+                           x)))))
+               (enc (file-encoding p)))
+
+          ;; Choose the input encoding deterministically.
+          (set-port-encoding! p (or enc "UTF-8"))
+
           (let f ((x (read p))
                   (result '()))
             (if (eof-object? x)