add "alias" and "converted-arguments-variant" properties
The properties appear in the inlining expansion of an application of a keyword-accepting function, and they're mainly intended for use by Typed Racket. The property keys are hidden, so that the property value can be trusted as originating from `racket/base'. The accessor functions are `syntax-procedure-alias-property' and `syntax-procedure-converted-arguments-property' from `racket/keyword-transform'.
This commit is contained in:
parent
aa3b849382
commit
b7d5aed8d7
5
collects/racket/keyword-transform.rkt
Normal file
5
collects/racket/keyword-transform.rkt
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
#lang racket/base
|
||||||
|
(require (for-template "private/kw.rkt"))
|
||||||
|
(provide syntax-procedure-alias-property
|
||||||
|
syntax-procedure-converted-arguments-property)
|
||||||
|
|
|
@ -24,7 +24,9 @@
|
||||||
new:procedure-rename
|
new:procedure-rename
|
||||||
new:chaperone-procedure
|
new:chaperone-procedure
|
||||||
new:impersonate-procedure
|
new:impersonate-procedure
|
||||||
(for-syntax kw-expander? kw-expander-impl kw-expander-proc))
|
(for-syntax kw-expander? kw-expander-impl kw-expander-proc
|
||||||
|
syntax-procedure-alias-property
|
||||||
|
syntax-procedure-converted-arguments-property))
|
||||||
|
|
||||||
;; ----------------------------------------
|
;; ----------------------------------------
|
||||||
|
|
||||||
|
@ -967,6 +969,16 @@
|
||||||
(define-for-syntax kw-expander-impl (make-struct-field-accessor kw-expander-ref 1 'impl))
|
(define-for-syntax kw-expander-impl (make-struct-field-accessor kw-expander-ref 1 'impl))
|
||||||
(define-for-syntax kw-expander-proc (make-struct-field-accessor kw-expander-ref 2 'proc))
|
(define-for-syntax kw-expander-proc (make-struct-field-accessor kw-expander-ref 2 'proc))
|
||||||
|
|
||||||
|
(define-for-syntax kw-alias-of (gensym 'alias-of))
|
||||||
|
(define-for-syntax kw-converted-arguments-variant-of (gensym 'converted-arguments-variant-of))
|
||||||
|
|
||||||
|
(define-for-syntax (syntax-procedure-alias-property stx)
|
||||||
|
(unless (syntax? stx) (raise-type-error 'syntax-procedure-alias "syntax" stx))
|
||||||
|
(syntax-property stx kw-alias-of))
|
||||||
|
(define-for-syntax (syntax-procedure-converted-arguments-property stx)
|
||||||
|
(unless (syntax? stx) (raise-type-error 'syntax-procedure-converted-arguments "syntax" stx))
|
||||||
|
(syntax-property stx kw-converted-arguments-variant-of))
|
||||||
|
|
||||||
(define-for-syntax (make-keyword-syntax get-ids n-req n-opt rest? req-kws all-kws)
|
(define-for-syntax (make-keyword-syntax get-ids n-req n-opt rest? req-kws all-kws)
|
||||||
(make-kw-expander
|
(make-kw-expander
|
||||||
(lambda (stx)
|
(lambda (stx)
|
||||||
|
@ -994,7 +1006,15 @@
|
||||||
""))
|
""))
|
||||||
msg
|
msg
|
||||||
(syntax-e #'self))
|
(syntax-e #'self))
|
||||||
(current-continuation-marks)))))])
|
(current-continuation-marks)))))]
|
||||||
|
[impl-id/prop
|
||||||
|
(syntax-property impl-id kw-converted-arguments-variant-of
|
||||||
|
(cons (syntax-taint (syntax-local-introduce #'self))
|
||||||
|
(syntax-taint (syntax-local-introduce impl-id))))]
|
||||||
|
[wrap-id/prop
|
||||||
|
(syntax-property wrap-id kw-alias-of
|
||||||
|
(cons (syntax-taint (syntax-local-introduce #'self))
|
||||||
|
(syntax-taint (syntax-local-introduce wrap-id))))])
|
||||||
(if (free-identifier=? #'new-app (datum->syntax stx '#%app))
|
(if (free-identifier=? #'new-app (datum->syntax stx '#%app))
|
||||||
(parse-app (datum->syntax #f (cons #'new-app stx) stx)
|
(parse-app (datum->syntax #f (cons #'new-app stx) stx)
|
||||||
(lambda (n)
|
(lambda (n)
|
||||||
|
@ -1053,7 +1073,7 @@
|
||||||
(lambda (args)
|
(lambda (args)
|
||||||
(quasisyntax/loc stx
|
(quasisyntax/loc stx
|
||||||
(if (variable-reference-constant? (#%variable-reference #,wrap-id))
|
(if (variable-reference-constant? (#%variable-reference #,wrap-id))
|
||||||
(#,impl-id
|
(#,impl-id/prop
|
||||||
;; keyword arguments:
|
;; keyword arguments:
|
||||||
#,@(let loop ([kw-args kw-args] [req-kws req-kws] [all-kws all-kws])
|
#,@(let loop ([kw-args kw-args] [req-kws req-kws] [all-kws all-kws])
|
||||||
(cond
|
(cond
|
||||||
|
@ -1097,10 +1117,12 @@
|
||||||
null))
|
null))
|
||||||
#,(if lifted?
|
#,(if lifted?
|
||||||
orig
|
orig
|
||||||
(quasisyntax/loc stx (#%app #,wrap-id . #,args)))))))))
|
(quasisyntax/loc stx (#%app #,wrap-id/prop . #,args)))))))))
|
||||||
orig))))
|
orig))))
|
||||||
(datum->syntax stx (cons wrap-id #'(arg ...)) stx stx)))]
|
(datum->syntax stx (cons wrap-id/prop #'(arg ...)) stx stx)))]
|
||||||
[_ wrap-id]))
|
[self
|
||||||
|
(syntax-property wrap-id kw-alias-of (cons (syntax-taint (syntax-local-introduce #'self))
|
||||||
|
(syntax-taint (syntax-local-introduce wrap-id))))]))
|
||||||
(lambda () (define-values (impl-id wrap-id) (get-ids)) impl-id)
|
(lambda () (define-values (impl-id wrap-id) (get-ids)) impl-id)
|
||||||
(lambda () (define-values (impl-id wrap-id) (get-ids)) wrap-id)))
|
(lambda () (define-values (impl-id wrap-id) (get-ids)) wrap-id)))
|
||||||
|
|
||||||
|
|
|
@ -1126,6 +1126,38 @@ A structure representing a single imported identifier:
|
||||||
For backward compatibility only; returns a procedure that returns its
|
For backward compatibility only; returns a procedure that returns its
|
||||||
first argument.}
|
first argument.}
|
||||||
|
|
||||||
|
@; ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
@section[#:tag "keyword-trans"]{Keyword-Argument Conversion Introspection}
|
||||||
|
|
||||||
|
@note-lib-only[racket/keyword-transform]
|
||||||
|
|
||||||
|
@deftogether[(
|
||||||
|
@defproc[(syntax-procedure-alias-property [stx syntax?])
|
||||||
|
(or/c #f
|
||||||
|
(letrec ([val? (recursive-contract
|
||||||
|
(or/c (cons/c identifier? identifier?)
|
||||||
|
(cons/c val? val?)))])
|
||||||
|
val?))]
|
||||||
|
@defproc[(syntax-procedure-converted-arguments-property [stx syntax?])
|
||||||
|
(or/c #f
|
||||||
|
(letrec ([val? (recursive-contract
|
||||||
|
(or/c (cons/c identifier? identifier?)
|
||||||
|
(cons/c val? val?)))])
|
||||||
|
val?))]
|
||||||
|
)]{
|
||||||
|
|
||||||
|
At expansion time, reports the value of a syntax property that can be
|
||||||
|
attached to an identifier by the expansion of a keyword-application
|
||||||
|
form during the same expansion time. See @racket[lambda] for more
|
||||||
|
information about the property.
|
||||||
|
|
||||||
|
The property value is normally a pair consisting of the original
|
||||||
|
identifier and an identifier that appears in the
|
||||||
|
expansion. Property-value merging via @racket[syntax-track-origin] can make
|
||||||
|
the value a pair of such values, and so on.}
|
||||||
|
|
||||||
|
|
||||||
@; ----------------------------------------------------------------------
|
@; ----------------------------------------------------------------------
|
||||||
|
|
||||||
@close-eval[stx-eval]
|
@close-eval[stx-eval]
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
racket/require
|
racket/require
|
||||||
(only-in racket/provide-transform
|
(only-in racket/provide-transform
|
||||||
make-provide-transformer)
|
make-provide-transformer)
|
||||||
|
racket/keyword-transform
|
||||||
racket/provide-syntax
|
racket/provide-syntax
|
||||||
racket/provide
|
racket/provide
|
||||||
racket/package
|
racket/package
|
||||||
|
@ -1708,7 +1709,29 @@ will hide the first argument, if one was provided. (Hiding the first
|
||||||
argument is useful when the procedure implements a method, where the
|
argument is useful when the procedure implements a method, where the
|
||||||
first argument is implicit in the original source). The property
|
first argument is implicit in the original source). The property
|
||||||
affects only the format of @racket[exn:fail:contract:arity]
|
affects only the format of @racket[exn:fail:contract:arity]
|
||||||
exceptions, not the result of @racket[procedure-arity].}
|
exceptions, not the result of @racket[procedure-arity].
|
||||||
|
|
||||||
|
When a keyword-accepting procedure is bound to an identifier in
|
||||||
|
certain ways, and when the identifier is used in the function position
|
||||||
|
of an application form, then the application form may be expanded in
|
||||||
|
such a way that the original binding is obscured as the target of the
|
||||||
|
application. To help expose the connection between the function
|
||||||
|
application and function declaration, an identifier in the expansion
|
||||||
|
of the function application is tagged with a @tech{syntax property}
|
||||||
|
accessible via @racket[syntax-procedure-alias-property] if it is effectively an alias
|
||||||
|
for the original identifier. An identifier in the expansion is tagged with a
|
||||||
|
a @tech{syntax property} accessible via @racket[syntax-procedure-converted-arguments-property] if it
|
||||||
|
is like the original identifier except that the arguments are converted to a
|
||||||
|
flattened form: keyword arguments, required by-position arguments,
|
||||||
|
by-position optional arguments, and rest arguments---all as required,
|
||||||
|
by-position arguments; the keyword arguments are sorted by keyword
|
||||||
|
name, each optional keyword argument is preceded by a boolean to
|
||||||
|
indicate whether a value is provided, and @racket[#f] is used for an
|
||||||
|
optional keyword argument whose value is not provided; optional
|
||||||
|
by-position arguments include @racket[#f] for each non-provided
|
||||||
|
argument, and then the sequence of optional-argument values is
|
||||||
|
followed by a parallel sequence of booleans to indicate whether each
|
||||||
|
optional-argument value was provided.}
|
||||||
|
|
||||||
|
|
||||||
@defform/subs[(case-lambda [formals body ...+] ...)
|
@defform/subs[(case-lambda [formals body ...+] ...)
|
||||||
|
|
|
@ -1438,6 +1438,64 @@
|
||||||
|
|
||||||
(test #\[ syntax-property (syntax/loc #'a [b c]) 'paren-shape)
|
(test #\[ syntax-property (syntax/loc #'a [b c]) 'paren-shape)
|
||||||
|
|
||||||
|
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;; Check that inlining expansion of keyword-argument calls
|
||||||
|
;; attaches 'alias-of and 'converted-arguments-variant-of
|
||||||
|
;; syntax properties:
|
||||||
|
|
||||||
|
(parameterize ([current-namespace (make-base-namespace)])
|
||||||
|
(eval '(require (for-syntax racket/base
|
||||||
|
racket/keyword-transform)))
|
||||||
|
(eval '(module m racket/base (provide f) (define (f #:x [x 2]) x)))
|
||||||
|
(eval '(require 'm))
|
||||||
|
(eval '(define-syntax (extract stx)
|
||||||
|
(syntax-case stx ()
|
||||||
|
[(_ form pattern var alias?)
|
||||||
|
(with-syntax ([e (local-expand #'form 'top-level '())])
|
||||||
|
#'(let-syntax ([m (lambda (stx)
|
||||||
|
(syntax-case (quote-syntax e) ()
|
||||||
|
[pattern
|
||||||
|
#`(quote-syntax (var
|
||||||
|
.
|
||||||
|
#,((if alias?
|
||||||
|
syntax-procedure-alias-property
|
||||||
|
syntax-procedure-converted-arguments-property)
|
||||||
|
#'var)))]))])
|
||||||
|
(define p (m))
|
||||||
|
(and (free-identifier=? (car (syntax-e p))
|
||||||
|
(cdr (syntax-e (cdr (syntax-e p)))))
|
||||||
|
(car (syntax-e (cdr (syntax-e p)))))))])))
|
||||||
|
(define f-id (eval '(quote-syntax f)))
|
||||||
|
(test
|
||||||
|
#t
|
||||||
|
free-identifier=?
|
||||||
|
f-id
|
||||||
|
(eval '(extract (f #:x 8)
|
||||||
|
(lv ([(proc) f2] . _) (if const? (app f3 . _) . _))
|
||||||
|
f3
|
||||||
|
#f)))
|
||||||
|
(test
|
||||||
|
#t
|
||||||
|
free-identifier=?
|
||||||
|
f-id
|
||||||
|
(eval '(extract (f #:x 8)
|
||||||
|
(lv ([(proc) f2] . _) (if const? (app f3 . _) . _))
|
||||||
|
f2
|
||||||
|
#t)))
|
||||||
|
(test
|
||||||
|
#t
|
||||||
|
free-identifier=?
|
||||||
|
f-id
|
||||||
|
(eval '(extract (f #:y 9)
|
||||||
|
(lv ([(proc) f2] . _) . _)
|
||||||
|
f2
|
||||||
|
#t)))
|
||||||
|
(test
|
||||||
|
#t
|
||||||
|
free-identifier=?
|
||||||
|
f-id
|
||||||
|
(eval '(extract f f2 f2 #t))))
|
||||||
|
|
||||||
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
(report-errs)
|
(report-errs)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user