From e25e7a109851e1c64273ad8fb0a69d5075e7b15d Mon Sep 17 00:00:00 2001 From: Matthew Flatt Date: Tue, 22 Apr 2008 18:00:04 +0000 Subject: [PATCH] keyword in methods and apply; procedure-reduce-keyword-arity svn: r9396 --- collects/compiler/compiler-unit.ss | 9 +- collects/mysterx/installer.ss | 3 +- collects/mzscheme/mzscheme.scrbl | 10 +- collects/scheme/private/class-internal.ss | 70 +++++- collects/scheme/private/classidmap.ss | 83 +++---- collects/scheme/private/kw.ss | 154 ++++++++++--- collects/scheme/private/pre-base.ss | 36 ++- collects/scribblings/reference/class.scrbl | 65 +++--- .../scribblings/reference/procedures.scrbl | 93 ++++++-- collects/scribblings/scribble/how-to.scrbl | 55 +++-- collects/tests/mzscheme/mz.ss | 1 + collects/tests/mzscheme/procs.ss | 218 ++++++++++++++++++ collects/tests/mzscheme/scheme.ss | 1 + src/mzscheme/src/fun.c | 37 +-- src/mzscheme/src/module.c | 15 +- src/mzscheme/src/schpriv.h | 2 + src/mzscheme/src/struct.c | 5 + 17 files changed, 680 insertions(+), 177 deletions(-) create mode 100644 collects/tests/mzscheme/procs.ss diff --git a/collects/compiler/compiler-unit.ss b/collects/compiler/compiler-unit.ss index b5902d0a03..db11456a4b 100644 --- a/collects/compiler/compiler-unit.ss +++ b/collects/compiler/compiler-unit.ss @@ -137,7 +137,7 @@ (let ([zo (append-zo-suffix f)]) (compile-to-zo f zo n prefix))))) - (define (compile-directory dir info) + (define (compile-directory dir info #:verbose [verbose? #t]) (define info* (or info (lambda (key mk-default) (mk-default)))) (define make (c-dynamic-require 'make/make-unit 'make@)) (define coll (c-dynamic-require 'make/collection-unit 'make:collection@)) @@ -161,7 +161,9 @@ (parameterize ([current-directory dir] [current-load-relative-directory dir] ;; Verbose compilation manager: - ;; [manager-trace-handler (lambda (s) (printf "~a\n" s))] + [manager-trace-handler (if verbose? + (lambda (s) (printf "~a\n" s)) + (manager-trace-handler))] [manager-compile-notify-handler (lambda (path) ((compile-notify-handler) path))]) ;; Compile the collection files via make-collection @@ -189,7 +191,8 @@ (define (compile-collection-zos collection . cp) (compile-directory (apply collection-path collection cp) - (c-get-info (cons collection cp)))) + (c-get-info (cons collection cp)) + #:verbose #f)) (define compile-directory-zos compile-directory) diff --git a/collects/mysterx/installer.ss b/collects/mysterx/installer.ss index e1b816d4ff..cd4db1ef61 100644 --- a/collects/mysterx/installer.ss +++ b/collects/mysterx/installer.ss @@ -13,7 +13,8 @@ [regsvr (and winsys-dir (build-path winsys-dir "REGSVR32.EXE"))]) (cond [(not (eq? (system-type) 'windows)) - (printf "Warning: can't install MysterX on non-Windows machine\n")] + ;; (printf "Warning: can't install MysterX on non-Windows machine\n") + (void)] [(not (andmap file-exists? dll-paths)) (printf "Warning: MysterX binaries not installed\n")] [(not winsys-dir) diff --git a/collects/mzscheme/mzscheme.scrbl b/collects/mzscheme/mzscheme.scrbl index b2ba16b48c..626cf2578f 100644 --- a/collects/mzscheme/mzscheme.scrbl +++ b/collects/mzscheme/mzscheme.scrbl @@ -16,7 +16,7 @@ @(define-syntax-rule (def-base base-define base-define-struct base-if base-cond base-case base-top-interaction - base-open-input-file + base-open-input-file base-apply base-free-identifier=? base-free-template-identifier=? base-free-transformer-identifier=? base-free-label-identifier=?) (begin @@ -28,13 +28,14 @@ (define base-case (scheme case)) (define base-top-interaction (scheme #%top-interaction)) (define base-open-input-file (scheme open-input-file)) + (define base-apply (scheme apply)) (define base-free-identifier=? (scheme free-identifier=?)) (define base-free-template-identifier=? (scheme free-template-identifier=?)) (define base-free-transformer-identifier=? (scheme free-transformer-identifier=?)) (define base-free-label-identifier=? (scheme free-label-identifier=?)))) @(def-base base-define base-define-struct base-if base-cond base-case base-top-interaction - base-open-input-file + base-open-input-file base-apply base-free-identifier=? base-free-template-identifier=? base-free-transformer-identifier=? base-free-label-identifier=?) @@ -195,6 +196,11 @@ The same as @|base-top-interaction| in @schememodname[scheme/base].} @section{Old Functions} +@defproc[(apply [proc procedure?] [v any/c] ... [lst list?]) any]{ + +Like @base-apply from @schememodname[scheme/base], but without support +for keyword arguments.} + @deftogether[( @defproc[(open-input-file [file path-string?] [mode (one-of/c 'text 'binary) 'binary]) input-port?] diff --git a/collects/scheme/private/class-internal.ss b/collects/scheme/private/class-internal.ss index ad57672b3a..dcacd26b86 100644 --- a/collects/scheme/private/class-internal.ss +++ b/collects/scheme/private/class-internal.ss @@ -179,6 +179,7 @@ (kernel-form-identifier-list) (list (quote-syntax #%app) ; scheme/base app, as opposed to #%plain-app + (quote-syntax lambda) ; scheme/base lambda, as opposed to #%plain-lambda (quote-syntax -init) (quote-syntax init-rest) (quote-syntax -field) @@ -317,6 +318,24 @@ (and (stx-pair? vars) (identifier? (stx-car vars)) (vars-ok? (stx-cdr vars))))) + (define (kw-vars-ok? vars) + (or (identifier? vars) + (stx-null? vars) + (and (stx-pair? vars) + (let ([a (stx-car vars)] + [opt-arg-ok? + (lambda (a) + (or (identifier? a) + (and (stx-pair? a) + (identifier? (stx-car a)) + (stx-pair? (stx-cdr a)) + (stx-null? (stx-cdr (stx-cdr a))))))]) + (or (and (opt-arg-ok? a) + (kw-vars-ok? (stx-cdr vars))) + (and (keyword? (syntax-e a)) + (stx-pair? (stx-cdr vars)) + (opt-arg-ok? (stx-car (stx-cdr vars))) + (kw-vars-ok? (stx-cdr (stx-cdr vars))))))))) ;; mk-name: constructs a method name ;; for error reporting, etc. (define (mk-name name) @@ -332,23 +351,52 @@ #f)) ;; -- tranform loop starts here -- (let loop ([stx orig-stx][can-expand? #t][name name][locals null]) - (syntax-case stx (#%plain-lambda case-lambda letrec-values let-values) - [(#%plain-lambda vars body1 body ...) - (vars-ok? (syntax vars)) + (syntax-case stx (#%plain-lambda lambda case-lambda letrec-values let-values) + [(lam vars body1 body ...) + (or (and (free-identifier=? #'lam #'#%plain-lambda) + (vars-ok? (syntax vars))) + (and (free-identifier=? #'lam #'lambda) + (kw-vars-ok? (syntax vars)))) (if xform? (with-syntax ([the-obj the-obj] [the-finder the-finder] [name (mk-name name)]) - (let ([l (syntax/loc stx - (lambda (the-obj . vars) - (let-syntax ([the-finder (quote-syntax the-obj)]) - body1 body ...)))]) - (with-syntax ([l (recertify (add-method-property l) stx)]) - (syntax/loc stx - (let ([name l]) name))))) - stx)] + (with-syntax ([vars (if (free-identifier=? #'lam #'lambda) + (let loop ([vars #'vars]) + (cond + [(identifier? vars) vars] + [(syntax? vars) + (datum->syntax vars + (loop (syntax-e vars)) + vars + vars)] + [(pair? vars) + (syntax-case (car vars) () + [(id expr) + (identifier? #'id) + ;; optional argument; need to wrap arg expression + (cons + (with-syntax ([expr (syntax/loc #'expr + (let-syntax ([the-finder (quote-syntax the-obj)]) + (#%expression expr)))]) + (syntax/loc (car vars) + (id expr))) + (loop (cdr vars)))] + [_ (cons (car vars) (loop (cdr vars)))])] + [else vars])) + #'vars)]) + (let ([l (syntax/loc stx + (lambda (the-obj . vars) + (let-syntax ([the-finder (quote-syntax the-obj)]) + body1 body ...)))]) + (with-syntax ([l (recertify (add-method-property l) stx)]) + (syntax/loc stx + (let ([name l]) name)))))) + stx)] [(#%plain-lambda . _) (bad "ill-formed lambda expression for method" stx)] + [(lambda . _) + (bad "ill-formed lambda expression for method" stx)] [(case-lambda [vars body1 body ...] ...) (andmap vars-ok? (syntax->list (syntax (vars ...)))) (if xform? diff --git a/collects/scheme/private/classidmap.ss b/collects/scheme/private/classidmap.ss index 8358797c7d..f46886cf2f 100644 --- a/collects/scheme/private/classidmap.ss +++ b/collects/scheme/private/classidmap.ss @@ -1,7 +1,8 @@ -(module classidmap mzscheme - (require syntax/stx) - (require-for-template mzscheme "class-events.ss") +(module classidmap scheme/base + (require syntax/stx + (for-syntax scheme/base) + (for-template scheme/base "class-events.ss")) (define-values (struct:s!t make-s!t s!t? s!t-ref s!t-set!) (make-struct-type 'set!-transformer #f 2 0 #f null (current-inspector) 0)) @@ -21,7 +22,7 @@ (define (find the-finder name src) (let ([this-id (syntax-local-value (syntax-local-get-shadower the-finder))]) - (datum->syntax-object this-id name src))) + (datum->syntax this-id name src))) ;; Check Syntax binding info: (define (binding from to stx) @@ -29,16 +30,16 @@ (define (make-this-map orig-id the-finder the-obj) - (let ([set!-stx (datum->syntax-object the-finder 'set!)]) + (let ([set!-stx (datum->syntax the-finder 'set!)]) (mk-set!-trans orig-id (lambda (stx) (syntax-case stx () [(set! id expr) - (module-identifier=? (syntax set!) set!-stx) + (free-identifier=? (syntax set!) set!-stx) (raise-syntax-error 'class "cannot mutate object identifier" stx)] [(id . args) - (datum->syntax-object + (datum->syntax stx (cons (find the-finder the-obj stx) (syntax args)) stx)] @@ -46,14 +47,14 @@ (define (make-field-map trace-flag the-finder the-obj the-binder the-binder-localized field-accessor field-mutator field-pos/null) - (let ([set!-stx (datum->syntax-object the-finder 'set!)]) + (let ([set!-stx (datum->syntax the-finder 'set!)]) (mk-set!-trans the-binder-localized (lambda (stx) (with-syntax ([obj-expr (find the-finder the-obj stx)]) (syntax-case stx () [(set! id expr) - (module-identifier=? (syntax set!) set!-stx) + (free-identifier=? (syntax set!) set!-stx) (with-syntax ([bindings (syntax/loc stx ([obj obj-expr] [id expr]))] [trace (syntax/loc stx (set-event obj (quote id) id))] [set (quasisyntax/loc stx @@ -82,18 +83,18 @@ (syntax/loc stx (let* bindings get))))])))))) (define (make-method-map the-finder the-obj the-binder the-binder-localized method-accessor) - (let ([set!-stx (datum->syntax-object the-finder 'set!)]) + (let ([set!-stx (datum->syntax the-finder 'set!)]) (mk-set!-trans the-binder-localized (lambda (stx) (syntax-case stx () [(set! id expr) - (module-identifier=? (syntax set!) set!-stx) + (free-identifier=? (syntax set!) set!-stx) (raise-syntax-error 'class "cannot mutate method" stx)] [(id . args) (binding the-binder (syntax id) - (datum->syntax-object + (datum->syntax the-finder (make-method-apply (list method-accessor (find the-finder the-obj stx)) @@ -109,18 +110,18 @@ ;; For methods that are dirrectly available via their names ;; (e.g., private methods) (define (make-direct-method-map the-finder the-obj the-binder the-binder-localized new-name) - (let ([set!-stx (datum->syntax-object the-finder 'set!)]) + (let ([set!-stx (datum->syntax the-finder 'set!)]) (mk-set!-trans the-binder-localized (lambda (stx) (syntax-case stx () [(set! id expr) - (module-identifier=? (syntax set!) set!-stx) + (free-identifier=? (syntax set!) set!-stx) (raise-syntax-error 'class "cannot mutate method" stx)] [(id . args) (binding the-binder (syntax id) - (datum->syntax-object + (datum->syntax the-finder (make-method-apply (find the-finder new-name stx) (find the-finder the-obj stx) (syntax args)) stx))] @@ -131,18 +132,18 @@ stx)]))))) (define (make-rename-super-map the-finder the-obj the-binder the-binder-localized rename-temp) - (let ([set!-stx (datum->syntax-object the-finder 'set!)]) + (let ([set!-stx (datum->syntax the-finder 'set!)]) (mk-set!-trans the-binder-localized (lambda (stx) (syntax-case stx () [(set! id expr) - (module-identifier=? (syntax set!) set!-stx) + (free-identifier=? (syntax set!) set!-stx) (raise-syntax-error 'class "cannot mutate super method" stx)] [(id . args) (binding the-binder (syntax id) - (datum->syntax-object + (datum->syntax the-finder (make-method-apply (find the-finder rename-temp stx) (find the-finder the-obj stx) (syntax args)) stx))] @@ -153,33 +154,33 @@ stx)]))))) (define (make-rename-inner-map the-finder the-obj the-binder the-binder-localized rename-temp) - (let ([set!-stx (datum->syntax-object the-finder 'set!)] - [lambda-stx (datum->syntax-object the-finder 'lambda)]) + (let ([set!-stx (datum->syntax the-finder 'set!)] + [lambda-stx (datum->syntax the-finder 'lambda)]) (mk-set!-trans the-binder-localized (lambda (stx) (syntax-case stx () [(set! id expr) - (module-identifier=? (syntax set!) set!-stx) + (free-identifier=? (syntax set!) set!-stx) (raise-syntax-error 'class "cannot mutate inner method" stx)] [(id (lambda () default) . args) - (module-identifier=? (syntax lambda) lambda-stx) + (free-identifier=? (syntax lambda) lambda-stx) (let ([target (find the-finder the-obj stx)]) (binding the-binder (syntax id) - (datum->syntax-object + (datum->syntax the-finder (make-method-apply (list (find the-finder rename-temp stx) target #'default) target (syntax args)) stx)))] [(id (lambda largs default) . args) - (module-identifier=? (syntax lambda) lambda-stx) + (free-identifier=? (syntax lambda) lambda-stx) (raise-syntax-error 'class "misuse of inner method (lambda for default does not take zero arguments)" stx)] [(id (lambda . rest) . args) - (module-identifier=? (syntax lambda) lambda-stx) + (free-identifier=? (syntax lambda) lambda-stx) (raise-syntax-error 'class "misuse of inner method (ill-formed lambda for default)" @@ -196,7 +197,7 @@ stx)]))))) (define (generate-super-call stx the-finder the-obj rename-temp args) - (datum->syntax-object + (datum->syntax the-finder (make-method-apply (find the-finder rename-temp stx) (find the-finder the-obj stx) @@ -204,10 +205,10 @@ stx)) (define (generate-inner-call stx the-finder the-obj default-expr rename-temp args) - (datum->syntax-object + (datum->syntax the-finder (let ([target (find the-finder the-obj stx)]) - (datum->syntax-object + (datum->syntax the-finder `(let ([i (,(find the-finder rename-temp stx) ,target)]) (if i @@ -231,14 +232,14 @@ (lambda (stx) (syntax-case stx () [(set! id expr) - (module-identifier=? (syntax set!) set!-stx) + (free-identifier=? (syntax set!) set!-stx) (with-syntax ([local-id local-id]) (syntax/loc stx (set! local-id expr)))] [(id . args) (with-syntax ([local-id local-id] [#%app #%app-stx]) (syntax/loc stx (#%app local-id . args)))] - [_else (datum->syntax-object + [_else (datum->syntax local-id (syntax-e local-id) stx @@ -258,7 +259,7 @@ (syntax-case stx () [(set! id expr) (and (identifier? (syntax id)) - (module-identifier=? (syntax set!) set!-stx)) + (free-identifier=? (syntax set!) set!-stx)) (raise-syntax-error 'with-method "cannot mutate method" stx)] [(id . args) (identifier? (syntax id)) @@ -328,7 +329,7 @@ (with-syntax ([object object-stx] [method method-proc-stx] - [app (if rest-arg? (qstx apply) (qstx #%plain-app))] + [app (if rest-arg? (qstx apply) (qstx #%app))] [args args-stx]) (if traced? (with-syntax ([(mth obj) (generate-temporaries @@ -346,12 +347,12 @@ finalize-call-event)))) (qstx (app method object . args))))) - (provide (protect make-this-map make-field-map make-method-map - make-direct-method-map - make-rename-super-map make-rename-inner-map - make-init-error-map make-init-redirect super-error-map - make-with-method-map - flatten-args make-method-call - make-private-name localize - generate-super-call generate-inner-call - generate-class-expand-context class-top-level-context?))) + (provide (protect-out make-this-map make-field-map make-method-map + make-direct-method-map + make-rename-super-map make-rename-inner-map + make-init-error-map make-init-redirect super-error-map + make-with-method-map + flatten-args make-method-call + make-private-name localize + generate-super-call generate-inner-call + generate-class-expand-context class-top-level-context?))) diff --git a/collects/scheme/private/kw.ss b/collects/scheme/private/kw.ss index c65f1a3a67..97d718218a 100644 --- a/collects/scheme/private/kw.ss +++ b/collects/scheme/private/kw.ss @@ -16,11 +16,16 @@ new-app (rename *make-keyword-procedure make-keyword-procedure) keyword-apply - procedure-keywords) + procedure-keywords + procedure-reduce-keyword-arity) ;; ---------------------------------------- (-define-struct keyword-procedure (proc required allowed)) + (define-values (struct:keyword-method make-km keyword-method? km-ref km-set!) + (make-struct-type 'procedure + struct:keyword-procedure + 0 0 #f)) (define (generate-arity-string proc) (let-values ([(req allowed) (procedure-keywords proc)] @@ -42,29 +47,40 @@ (if (null? (cdr req)) (format " and ~a" (car req)) (format " ~a,~a" (car req) - (loop (cdr req)))))])))]) + (loop (cdr req)))))])))] + [(method-adjust) + (lambda (a) + (if (or (okm? proc) + (keyword-method? proc)) + (if (zero? a) 0 (sub1 a)) + a))]) + (string-append (cond - [(number? a) (format "~a argument~a" a (if (= a 1) "" "s"))] + [(number? a) + (let ([a (method-adjust a)]) + (format "~a argument~a" a (if (= a 1) "" "s")))] [(arity-at-least? a) - (let ([a (arity-at-least-value a)]) + (let ([a (method-adjust (arity-at-least-value a))]) (format "at least ~a argument~a" a (if (= a 1) "" "s")))] [else "a different number of arguments"]) (if (null? req) "" (format " plus ~a" (keywords-desc "" req))) - (let ([others (let loop ([req req][allowed allowed]) - (cond - [(null? req) allowed] - [(eq? (car req) (car allowed)) - (loop (cdr req) (cdr allowed))] - [else - (cons (car allowed) (loop req (cdr allowed)))]))]) - (if (null? others) - "" - (format " plus ~a" - (keywords-desc "optional " others))))))) + (if allowed + (let ([others (let loop ([req req][allowed allowed]) + (cond + [(null? req) allowed] + [(eq? (car req) (car allowed)) + (loop (cdr req) (cdr allowed))] + [else + (cons (car allowed) (loop req (cdr allowed)))]))]) + (if (null? others) + "" + (format " plus ~a" + (keywords-desc "optional " others)))) + " plus arbitrary keyword arguments")))) ;; Constructor for a procedure with only optional keywords. ;; The `procedure' property dispatches to a procedure in the @@ -75,16 +91,24 @@ 1 0 #f (list (cons prop:arity-string generate-arity-string)) (current-inspector) 0)) + + ;; A ``method'' (for arity reporting) + (define-values (struct:okm make-optional-keyword-method okm? okm-ref okm-set!) + (make-struct-type 'procedure + struct:okp + 0 0 #f)) ;; Constructor generator for a procedure with a required keyword. ;; (This is used with lift-expression, so that the same constructor ;; is used for each evaluation of a keyword lambda.) ;; The `procedure' property is a per-type method that has exactly ;; the right arity, and that sends all arguments to `missing-kw'. - (define (make-required name fail-proc) + (define (make-required name fail-proc method?) (let-values ([(s: mk ? -ref -set!) (make-struct-type (string->symbol (format "procedure:~a" name)) - struct:keyword-procedure + (if method? + struct:keyword-method + struct:keyword-procedure) 0 0 #f (list (cons prop:arity-string generate-arity-string)) (current-inspector) fail-proc)]) @@ -106,7 +130,7 @@ #f plain-proc)])]) make-keyword-procedure)) - + (define (keyword-apply proc kws kw-vals . normal-argss) (let ([type-error (lambda (what which) @@ -294,7 +318,8 @@ (lambda (a b) (keyword all keywords are allowed (loop (cdr kws) required #f)] [(pair? allowed) @@ -708,7 +737,12 @@ (let-values ([(missing-kw extra-kw) (if (keyword-procedure? p) (check-kw-args p kws) - (values #f (car kws)))]) + (values #f (car kws)))] + [(n) (if (and (positive? n) + (or (keyword-method? p) + (okm? p))) + (sub1 n) + n)]) (let ([args-str (if (and (null? args) (null? kws)) @@ -751,8 +785,76 @@ (format (string-append "procedure application: no case matching ~a non-keyword" - " arguments for: ~e; ~a") + " argument~a for: ~e; ~a") (- n 2) + (if (= 1 (- n 2)) "" "s") p args-str))) - (current-continuation-marks))))))))))) + (current-continuation-marks)))))))))) + + ;; setting procedure arity + (define (procedure-reduce-keyword-arity proc arity req-kw allowed-kw) + (let ([plain-proc (procedure-reduce-arity (if (okp? proc) + (okp-ref proc 0) + proc) + arity)]) + (define (sorted? kws) + (let loop ([kws kws]) + (cond + [(null? kws) #t] + [(null? (cdr kws)) #t] + [(keywordsyntax stx (cdr (syntax-e stx)) stx stx))) + (define-values (new-apply) + (make-keyword-procedure + (lambda (kws kw-args proc args . rest) + (keyword-apply proc kws kw-args (apply list* args rest))) + apply)) + + (define-values (new-keyword-apply) + (make-keyword-procedure + (lambda (kws kw-args proc orig-kws orig-kw-args args . rest) + (let-values ([(kws kw-args) + (let loop ([kws kws] [kw-args kw-args] + [kws2 orig-kws] [kw-args2 orig-kw-args] + [swapped? #f]) + (cond + [(null? kws) (values kws2 kw-args2)] + [(null? kws2) (values kws kw-args)] + [(keywordinterface object%)], and is transparent public pubment public-final override override-final overment augment augride augment-final private inherit inherit/super inherit/inner rename-super rename-inner begin lambda case-lambda let-values letrec-values - define-values) + define-values #%plain-lambda) (class* superclass-expr (interface-expr ...) class-clause ...) @@ -252,8 +252,9 @@ interface @scheme[(class->interface object%)], and is transparent (define-values (id) method-procedure)] [method-procedure - (lambda formals expr ...+) + (lambda kw-formals expr ...+) (case-lambda (formals expr ...+) ...) + (#%plain-lambda formals expr ...+) (let-values (((id) method-procedure) ...) method-procedure) (letrec-values (((id) method-procedure) ...) @@ -616,24 +617,26 @@ using the @scheme[inner] form. The only difference between @scheme[inner] is that @scheme[public-final] prevents the declaration of augmenting methods that would be ignored. -@defform*[[(super id arg-expr ...) - (super id arg-expr ... . arg-list-expr)]]{ +@defform*[[(super id arg ...) + (super id arg ... . arg-list-expr)]]{ Always accesses the superclass method, independent of whether the method is overridden again in subclasses. Using the @scheme[super] -form outside of @scheme[class*] is an syntax error. +form outside of @scheme[class*] is an syntax error. Each @scheme[arg] +is as for @scheme[#%app]: either @scheme[_arg-expr] or +@scheme[_keyword _arg-expr]. The second form is analogous to using @scheme[apply] with a procedure; the @scheme[arg-list-expr] must not be a parenthesized expression.} -@defform*[[(inner default-expr id arg-expr ...) - (inner default-expr id arg-expr ... . arg-list-expr)]]{ +@defform*[[(inner default-expr id arg ...) + (inner default-expr id arg ... . arg-list-expr)]]{ If the object's class does not supply an augmenting method, then -@scheme[default-expr] is evaluated, and the @scheme[arg-expr]s are not -evaluated. Otherwise, the augmenting method is called with the -@scheme[arg-expr] results as arguments, and @scheme[default-expr] is -not evaluated. If no @scheme[inner] call is evaluated for a particular +@scheme[default-expr] is evaluated, and the @scheme[arg] expressions +are not evaluated. Otherwise, the augmenting method is called with the +@scheme[arg] results as arguments, and @scheme[default-expr] is not +evaluated. If no @scheme[inner] call is evaluated for a particular method, then augmenting methods supplied by subclasses are never used. Using the @scheme[inner] form outside of @scheme[class*] is an syntax error. @@ -670,14 +673,14 @@ superclass's implementation at run-time. Methods declared with and must be called with the form @schemeblock[ -(_id (lambda () _default-expr) _arg-expr ...) +(_id (lambda () _default-expr) _arg ...) ] so that a @scheme[default-expr] is available to evaluate when no augmenting method is available. In such a form, @scheme[lambda] is a -keyword to separate the @scheme[default-expr] from the -@scheme[arg-expr]. When an augmenting method is available, it receives -the results of the @scheme[arg-expr]s as arguments. +literal identifier to separate the @scheme[default-expr] from the +@scheme[arg]. When an augmenting method is available, it receives the +results of the @scheme[arg] expressions as arguments. Methods that are present in the superclass but not declared with @scheme[inherit], @scheme[inherit/super], or @scheme[inherit/inner] or @@ -977,37 +980,39 @@ To allow methods to be applied to lists of arguments, a method application can have the following form: @specsubform[ -(method-id arg-expr ... . arg-list-expr) +(method-id arg ... . arg-list-expr) ] This form calls the method in a way analogous to @scheme[(apply -_method-id _arg-expr ... _arg-list-expr)]. The @scheme[arg-list-expr] +_method-id _arg ... _arg-list-expr)]. The @scheme[arg-list-expr] must not be a parenthesized expression. Methods are called from outside a class with the @scheme[send] and @scheme[send/apply] forms. -@defform*[[(send obj-expr method-id arg-expr ...) - (send obj-expr method-id arg-expr ... . arg-list-expr)]]{ +@defform*[[(send obj-expr method-id arg ...) + (send obj-expr method-id arg ... . arg-list-expr)]]{ Evaluates @scheme[obj-expr] to obtain an object, and calls the method with (external) name @scheme[method-id] on the object, providing the -@scheme[arg-expr] results as arguments. In the second form, -@scheme[arg-list-expr] cannot be a parenthesized expression. +@scheme[arg] results as arguments. Each @scheme[arg] is as for +@scheme[#%app]: either @scheme[_arg-expr] or @scheme[_keyword +_arg-expr]. In the second form, @scheme[arg-list-expr] cannot be a +parenthesized expression. If @scheme[obj-expr] does not produce an object, the @exnraise[exn:fail:contract]. If the object has no public method named @scheme[method-id], the @exnraise[exn:fail:object].} -@defform[(send/apply obj-expr method-id arg-expr ... arg-list-expr)]{ +@defform[(send/apply obj-expr method-id arg ... arg-list-expr)]{ Like the dotted form of @scheme[send], but @scheme[arg-list-expr] can be any expression.} @defform/subs[(send* obj-expr msg ...) - ([msg (method-id arg-expr ...) - (method-id arg-expr ... . arg-list-expr)])]{ + ([msg (method-id arg ...) + (method-id arg ... . arg-list-expr)])]{ Calls multiple methods (in order) of the same object. Each @scheme[msg] corresponds to a use of @scheme[send]. @@ -1122,13 +1127,15 @@ interface, the @exnraise[exn:fail:contract]. If the resulting class or interface does not contain a method named @scheme[id], the @exnraise[exn:fail:object].} -@defform*[[(send-generic obj-expr generic-expr arg-expr ...) - (send-generic obj-expr generic-expr arg-expr ... . arg-list-expr)]]{ +@defform*[[(send-generic obj-expr generic-expr arg ...) + (send-generic obj-expr generic-expr arg ... . arg-list-expr)]]{ Calls a method of the object produced by @scheme[obj-expr] as -indicated by the generic produced by @scheme[generic-expr]. The second -form is analogous to calling a procedure with @scheme[apply], where -@scheme[arg-list-expr] is not a parenthesized expression. +indicated by the generic produced by @scheme[generic-expr]. Each +@scheme[arg] is as for @scheme[#%app]: either @scheme[_arg-expr] or +@scheme[_keyword _arg-expr]. The second form is analogous to calling a +procedure with @scheme[apply], where @scheme[arg-list-expr] is not a +parenthesized expression. If @scheme[obj-expr] does not produce a object, or if @scheme[generic-expr] does not produce a generic, the diff --git a/collects/scribblings/reference/procedures.scrbl b/collects/scribblings/reference/procedures.scrbl index dc0c3c4fcc..f0e1a9449c 100644 --- a/collects/scribblings/reference/procedures.scrbl +++ b/collects/scribblings/reference/procedures.scrbl @@ -7,21 +7,29 @@ @scheme[v] is a procedure, @scheme[#f] otherwise.} -@defproc[(apply [proc procedure?] [v any/c] ... [lst list?]) any]{ +@defproc[(apply [proc procedure?] + [v any/c] ... [lst list?] + [#: kw-arg any/c] ...) any]{ @guideintro["apply"]{@scheme[apply]} Applies @scheme[proc] using the content of @scheme[(list* v ... lst)] -as the (by-position) arguments. The given @scheme[proc] must accept as -many arguments as the number of @scheme[v]s plus length of -@scheme[lst], and it must not require any keyword arguments; -otherwise, the @exnraise[exn:fail:contract]. The given @scheme[proc] -is called in tail position with respect to the @scheme[apply] call. +as the (by-position) arguments. The @scheme[#: kw-arg] sequence is +also supplied as keyword arguments to @scheme[proc], where +@scheme[#:] stands for any keyword. + +The given @scheme[proc] must accept as many arguments as the number of +@scheme[v]s plus length of @scheme[lst], it must accept the supplied +keyword arguments, and it must not require any other keyword +arguments; otherwise, the @exnraise[exn:fail:contract]. The given +@scheme[proc] is called in tail position with respect to the +@scheme[apply] call. @examples[ (apply + '(1 2 3)) (apply + 1 2 '(3)) (apply + '()) +(apply sort (list (list '(2) '(1)) <) #:key car) ]} @defproc[(compose [proc procedure?] ...) procedure?]{ @@ -45,28 +53,35 @@ function consumes. [kw-lst (listof keyword?)] [kw-val-lst list?] [v any/c] ... - [lst list?]) + [lst list?] + [#: kw-arg any/c] ...) any]{ @guideintro["apply"]{@scheme[keyword-apply]} Like @scheme[apply], but @scheme[kw-lst] and @scheme[kw-val-lst] supply by-keyword arguments in addition to the by-position arguments -of the @scheme[v]s and @scheme[lst]. The given @scheme[kw-lst] must be -sorted using @scheme[keyword kw-arg] sequence, +where @scheme[#:] stands for any keyword. + +The given @scheme[kw-lst] must be sorted using @scheme[keyword], otherwise, the +@exnraise[exn:fail:contract]. The given @scheme[kw-val-lst] must have +the same length as @scheme[kw-lst], otherwise, the +@exnraise[exn:fail:contract]. The given @scheme[proc] must accept all +of the keywords in @scheme[kw-lst] plus the @scheme[#:]s, it must +not require any other keywords, and it must accept as many by-position +arguments as supplied via the @scheme[v]s and @scheme[lst]; otherwise, +the @exnraise[exn:fail:contract]. @defexamples[ (define (f x #:y y #:z [z 10]) (list x y z)) (keyword-apply f '(#:y) '(2) '(1)) (keyword-apply f '(#:y #:z) '(2 3) '(1)) +(keyword-apply f #:z 7 '(#:y) '(2) '(1)) ]} @defproc[(procedure-arity [proc procedure?]) @@ -126,7 +141,13 @@ procedure, it returns a value that is @scheme[equal?] to @scheme[arity]. If the @scheme[arity] specification allows arguments that are not -in @scheme[(procedure-arity proc)], the @exnraise[exn:fail:contract].} +in @scheme[(procedure-arity proc)], the @exnraise[exn:fail:contract]. + +@examples[ +(define my+ (procedure-reduce-arity + 2)) +(my+ 1 2) +(my+ 1 2 3) +]} @defproc[(procedure-keywords [proc procedure?]) (values @@ -154,7 +175,8 @@ list is also in the second list. procedure?]{ Returns a procedure that accepts all keyword arguments (without -requiring any keyword arguments). +requiring any keyword arguments). See also +@scheme[procedure-reduce-keyword-arity]. When the result is called with keyword arguments, then @scheme[proc] is called; the first argument is a list of keywords sorted by @@ -175,6 +197,34 @@ obtains its result from @scheme[plain-proc]. (show #:init 0 1 2 3 #:extra 4) ]} +@defproc[(procedure-reduce-keyword-arity [proc procedure?] + [arity procedure-arity?] + [required-kws (listof keyword?)] + [allowed-kws (or/c (listof keyword?) + false/c)]) + procedure?]{ + +Like @scheme[procedure-reduce-arity], but constrains the keyword +arguments according to @scheme[required-kws] and @scheme[allowed-kws], +which must be sorted using @scheme[keyword= 0) bign = scheme_make_integer(a); if (a == -1) @@ -2793,6 +2793,8 @@ static Scheme_Object *get_or_check_arity(Scheme_Object *p, long a, Scheme_Object v = SCHEME_CDR(v); } return scheme_false; + } else if (SCHEME_NULLP(v)) { + return scheme_false; } else { return (scheme_bin_eq(v, bign) ? scheme_true @@ -3390,20 +3392,20 @@ static Scheme_Object *procedure_reduce_arity(int argc, Scheme_Object *argv[]) scheme_wrong_type("procedure-reduce-arity", "arity", 1, argc, argv); } - if (!reduced_procedure_struct) { - REGISTER_SO(reduced_procedure_struct); + if (!scheme_reduced_procedure_struct) { + REGISTER_SO(scheme_reduced_procedure_struct); pr = scheme_get_param(scheme_current_config(), MZCONFIG_INSPECTOR); while (((Scheme_Inspector *)pr)->superior->superior) { pr = (Scheme_Object *)((Scheme_Inspector *)pr)->superior; } orig = scheme_builtin_value("prop:procedure"); - reduced_procedure_struct = scheme_make_proc_struct_type(NULL, - NULL, - pr, - 2, 0, - scheme_false, - scheme_make_integer(0), - NULL); + scheme_reduced_procedure_struct = scheme_make_proc_struct_type(NULL, + NULL, + pr, + 2, 0, + scheme_false, + scheme_make_integer(0), + NULL); } /* Check whether current arity covers the requested arity. This is @@ -3525,11 +3527,10 @@ static Scheme_Object *procedure_reduce_arity(int argc, Scheme_Object *argv[]) if (SCHEME_NULLP(ol)) { scheme_raise_exn(MZEXN_FAIL_CONTRACT_CONTINUATION, - "procedure-reduce-arity: arity of procedre: %V" - " does not include requested arity: %V : %V", + "procedure-reduce-arity: arity of procedure: %V" + " does not include requested arity: %V", argv[0], - argv[1], - ra); + argv[1]); return NULL; } @@ -3542,7 +3543,7 @@ static Scheme_Object *procedure_reduce_arity(int argc, Scheme_Object *argv[]) pr = clone_arity(argv[1]); a[1] = pr; - return scheme_make_struct_instance(reduced_procedure_struct, 2, a); + return scheme_make_struct_instance(scheme_reduced_procedure_struct, 2, a); } static Scheme_Object *procedure_equal_closure_p(int argc, Scheme_Object *argv[]) diff --git a/src/mzscheme/src/module.c b/src/mzscheme/src/module.c index 5fd7bac139..ea70581b7a 100644 --- a/src/mzscheme/src/module.c +++ b/src/mzscheme/src/module.c @@ -1201,7 +1201,7 @@ static Scheme_Object *namespace_attach_module(int argc, Scheme_Object *argv[]) Scheme_Hash_Table *checked, *next_checked, *prev_checked; Scheme_Object *past_checkeds, *future_checkeds, *future_todos, *past_to_modchains, *past_todos; Scheme_Module *m2; - int same_namespace, set_env_for_notify = 0, phase; + int same_namespace, set_env_for_notify = 0, phase, first_iteration; if (!SCHEME_NAMESPACEP(argv[0])) scheme_wrong_type("namespace-attach-module", "namespace", 0, argc, argv); @@ -1236,6 +1236,8 @@ static Scheme_Object *namespace_attach_module(int argc, Scheme_Object *argv[]) future_todos = scheme_null; past_to_modchains = scheme_null; + first_iteration = 1; + /* Check whether todo, or anything it needs, is already declared incompatibly. Successive iterations of the outer loop explore successive phases (i.e, for-syntax levels). */ @@ -1272,6 +1274,13 @@ static Scheme_Object *namespace_attach_module(int argc, Scheme_Object *argv[]) name); } + if (first_iteration) { + /* Run everything */ + first_iteration = 0; + start_module(menv->module, from_env, 0, menv->module->self_modidx, 1, 1, scheme_null); + } + + /* If to_modchain goes to #f, then our source check has gone deeper in phases (for-syntax levels) than the target namespace has ever gone, so there's definitely no conflict @@ -1324,7 +1333,9 @@ static Scheme_Object *namespace_attach_module(int argc, Scheme_Object *argv[]) l = SCHEME_CDR(l); } - /* Have to force laziness in source to ensure sharing: */ + /* Have to force laziness in source to ensure sharing. This + should be redundant, since we called start_module() for the + inital module, but we keep it just in case... */ if (!menv->ran) scheme_run_module(menv, 1); if (menv->lazy_syntax) diff --git a/src/mzscheme/src/schpriv.h b/src/mzscheme/src/schpriv.h index 91519d4741..fec1d5aee3 100644 --- a/src/mzscheme/src/schpriv.h +++ b/src/mzscheme/src/schpriv.h @@ -291,6 +291,8 @@ extern Scheme_Object *scheme_input_port_property, *scheme_output_port_property; extern Scheme_Object *scheme_equal_property; +extern Scheme_Object *scheme_reduced_procedure_struct; + /*========================================================================*/ /* thread state and maintenance */ /*========================================================================*/ diff --git a/src/mzscheme/src/struct.c b/src/mzscheme/src/struct.c index 96c52905fe..77a9a5d610 100644 --- a/src/mzscheme/src/struct.c +++ b/src/mzscheme/src/struct.c @@ -3453,6 +3453,11 @@ static Scheme_Object *procedure_extract_target(int argc, Scheme_Object **argv) scheme_wrong_type("procedure-extract-target", "procedure", 0, argc, argv); if (SCHEME_PROC_STRUCTP(argv[0])) { + /* Don't expose arity reducer: */ + if (scheme_reduced_procedure_struct + && scheme_is_struct_instance(scheme_reduced_procedure_struct, argv[0])) + return scheme_false; + v = scheme_extract_struct_procedure(argv[0], -1, NULL, &is_method); if (v && !is_method && SCHEME_PROCP(v)) return v;