Implements and provides prop:template-metafunction
This commit is contained in:
parent
cb959879de
commit
f6eee5eb33
|
@ -347,4 +347,37 @@ the context above; instead, @racket[let-values] would report an
|
||||||
invalid binding list.
|
invalid binding list.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@deftogether[
|
||||||
|
((defthing prop:template-metafunction struct-type-property?)
|
||||||
|
(defthing template-metafunction? (-> any/c boolean?))
|
||||||
|
(defthing template-metafunction-accessor (-> template-metafunction? identifier?)))]{
|
||||||
|
|
||||||
|
A structure type property, and the associated predicate and accessor. The
|
||||||
|
property value is either an identifier, or the index of a field containing an
|
||||||
|
identifier. The identifier should be bound to the run-time metafunction. The
|
||||||
|
run-time metafunction should accept a syntax object representing its use, and
|
||||||
|
produce a new syntax object as a result.
|
||||||
|
|
||||||
|
When an identifier is bound as syntax to a structure instance with this
|
||||||
|
property, it is treated as a template metafunction as if the identifier had
|
||||||
|
been declared with define-template-metafunction.
|
||||||
|
|
||||||
|
@examples[#:eval the-eval
|
||||||
|
(define (my-metafunction-proc stx)
|
||||||
|
(syntax-case stx ()
|
||||||
|
[(_ n) (datum->syntax #'n (add1 (syntax-e #'n)))]))
|
||||||
|
|
||||||
|
(begin-for-syntax
|
||||||
|
(struct mf-struct (proc-id)
|
||||||
|
#:property prop:template-metafunction
|
||||||
|
(struct-field-index proc-id)))
|
||||||
|
|
||||||
|
(define-syntax mf (mf-struct #'my-metafunction-proc))
|
||||||
|
|
||||||
|
(template (mf 3))
|
||||||
|
(with-syntax ([(x ...) #'(1 2 3)])
|
||||||
|
(template ((mf x) ...)))]
|
||||||
|
|
||||||
|
@history[#:added 6.9]}
|
||||||
|
|
||||||
@(close-eval the-eval)
|
@(close-eval the-eval)
|
||||||
|
|
|
@ -66,3 +66,66 @@
|
||||||
|
|
||||||
(terx (template (bad-mf))
|
(terx (template (bad-mf))
|
||||||
#rx"result of template metafunction was not syntax")
|
#rx"result of template metafunction was not syntax")
|
||||||
|
|
||||||
|
;; ============================================================
|
||||||
|
|
||||||
|
;; Test prop:template-metafunction and template-metafunction?
|
||||||
|
|
||||||
|
(define-syntax (is-metafunction? stx)
|
||||||
|
(syntax-case stx ()
|
||||||
|
[(_ id)
|
||||||
|
#`#,(template-metafunction? (syntax-local-value #'id))]))
|
||||||
|
|
||||||
|
(test-case "template-metafunction? on define-template-metafunction"
|
||||||
|
(define-template-metafunction (mf1 stx)
|
||||||
|
#'1)
|
||||||
|
|
||||||
|
(check-true (is-metafunction? mf1)))
|
||||||
|
|
||||||
|
(begin-for-syntax
|
||||||
|
(struct my-template-metafunction2 (proc-id)
|
||||||
|
#:property prop:template-metafunction (struct-field-index proc-id)))
|
||||||
|
(test-case
|
||||||
|
"template-metafunction? on custom prop:template-metafunction with field"
|
||||||
|
(define (myproc2 stx) #'2)
|
||||||
|
(define-syntax mf2 (my-template-metafunction2 (quote-syntax myproc2)))
|
||||||
|
|
||||||
|
(check-true (is-metafunction? mf2)))
|
||||||
|
|
||||||
|
|
||||||
|
;; must be before the definition of my-template-metafunction3
|
||||||
|
(define (myproc3 stx) #'3)
|
||||||
|
;; must be outside of the (test-case …) form
|
||||||
|
(begin-for-syntax
|
||||||
|
(struct my-template-metafunction3 ()
|
||||||
|
#:property prop:template-metafunction (quote-syntax myproc3)))
|
||||||
|
(test-case "template-metafunction? on custom prop:template-metafunction with id"
|
||||||
|
(define-syntax mf3 (my-template-metafunction3))
|
||||||
|
|
||||||
|
(check-true (is-metafunction? mf3)))
|
||||||
|
|
||||||
|
(begin-for-syntax
|
||||||
|
(struct my-template-metafunction4 (proc-id)
|
||||||
|
#:property prop:template-metafunction (struct-field-index proc-id)))
|
||||||
|
(test-case "use custom prop:template-metafunction with field"
|
||||||
|
(define (myproc4 stx)
|
||||||
|
(syntax-case stx ()
|
||||||
|
[(_ n) #`#,(add1 (syntax-e #'n))]))
|
||||||
|
(define-syntax mf4 (my-template-metafunction4 (quote-syntax myproc4)))
|
||||||
|
|
||||||
|
(check-equal? (syntax->datum (template (x (mf4 3) z)))
|
||||||
|
'(x 4 z)))
|
||||||
|
|
||||||
|
;; must be before the definition of my-template-metafunction5
|
||||||
|
(define (myproc5 stx)
|
||||||
|
(syntax-case stx ()
|
||||||
|
[(_ n) #`#,(* (syntax-e #'n) 2)]))
|
||||||
|
;; must be outside of the (test-case …) form
|
||||||
|
(begin-for-syntax
|
||||||
|
(struct my-template-metafunction5 ()
|
||||||
|
#:property prop:template-metafunction (quote-syntax myproc5)))
|
||||||
|
(test-case "use custom prop:template-metafunction with id"
|
||||||
|
(define-syntax mf5 (my-template-metafunction5))
|
||||||
|
|
||||||
|
(check-equal? (syntax->datum (template (x (mf5 3) z)))
|
||||||
|
'(x 6 z)))
|
|
@ -0,0 +1,69 @@
|
||||||
|
(module prop-template-metafunction '#%kernel
|
||||||
|
(#%provide (protect metafunction
|
||||||
|
prop:metafunction
|
||||||
|
(rename prop:metafunction? metafunction?)
|
||||||
|
metafunction-accessor))
|
||||||
|
|
||||||
|
;; The prop:metafunction structure type property can contain an
|
||||||
|
;; identifier bound to the run-time metafunction procedure, or the index of a
|
||||||
|
;; field containing such an identifier.
|
||||||
|
;; At run-time, when processing the template, the syntax object whose first
|
||||||
|
;; element is a metafunction identifiers is passed to this metafunction
|
||||||
|
;; procedure.
|
||||||
|
|
||||||
|
(define-values (prop:metafunction-guard)
|
||||||
|
(lambda (val struct-type-info-list)
|
||||||
|
(if (exact-nonnegative-integer? val)
|
||||||
|
;; Field index, the field must contain an identifier bound to the run-time
|
||||||
|
;; metafunction procedure.
|
||||||
|
(let-values ([(make-struct-accessor) (cadddr struct-type-info-list)])
|
||||||
|
(let-values ([(accessor) (make-struct-field-accessor make-struct-accessor val)])
|
||||||
|
(λ (instance)
|
||||||
|
(let-values ([(metafunction-internal-id) (accessor instance)])
|
||||||
|
;; Check that the value contained in the field is correct
|
||||||
|
;; (if (identifier? metafunction-internal-id) ...)
|
||||||
|
(if (if (syntax? metafunction-internal-id)
|
||||||
|
(symbol? (syntax-e metafunction-internal-id))
|
||||||
|
#f)
|
||||||
|
metafunction-internal-id
|
||||||
|
(raise-argument-error
|
||||||
|
'prop:metafunction-guard
|
||||||
|
(format (string-append "the value of the ~a-th field should be"
|
||||||
|
" an identifier")
|
||||||
|
val)
|
||||||
|
metafunction-internal-id))))))
|
||||||
|
;;(if (identifier? val)
|
||||||
|
(if (if (syntax? val) (symbol? (syntax-e val)) #f)
|
||||||
|
;; Identifier bound to the run-time metafunction procedure.
|
||||||
|
(λ (_instance) val)
|
||||||
|
;; Otherwise, raise an error.
|
||||||
|
(raise-argument-error
|
||||||
|
'prop:metafunction-guard
|
||||||
|
(string-append "an identifier, or an exact non-negative integer designating"
|
||||||
|
" a field index within the structure that should contain an"
|
||||||
|
" identifier.")
|
||||||
|
val)))))
|
||||||
|
|
||||||
|
(define-values (prop:metafunction
|
||||||
|
prop:metafunction?
|
||||||
|
metafunction-raw-accessor)
|
||||||
|
(make-struct-type-property 'metafunction
|
||||||
|
prop:metafunction-guard))
|
||||||
|
|
||||||
|
(define-values (metafunction-accessor)
|
||||||
|
(lambda (instance . more-args)
|
||||||
|
(let-values ([(raw) (if (null? more-args) ;; no failure-result given
|
||||||
|
(metafunction-raw-accessor instance)
|
||||||
|
(if (null? (cdr more-args))
|
||||||
|
(let-values ([(failure-result) (car more-args)])
|
||||||
|
(metafunction-raw-accessor instance failure-result))
|
||||||
|
(error "invalid number of arguments [TODO]")))])
|
||||||
|
(raw instance))))
|
||||||
|
|
||||||
|
;; A default struct type with prop:metafunction.
|
||||||
|
;; (struct template-metafunction (proc-id)
|
||||||
|
;; #:property prop:template-metafunction (struct-field-index proc-id))
|
||||||
|
(define-values (struct:metafunction metafunction metafunction? metafunction-ref _mf-set!)
|
||||||
|
(make-struct-type 'syntax-metafunction #f 1 0 #f
|
||||||
|
(list (cons prop:metafunction 0))
|
||||||
|
(current-inspector))))
|
|
@ -4,6 +4,7 @@
|
||||||
(rename "define-et-al.rkt" define-syntax -define-syntax)
|
(rename "define-et-al.rkt" define-syntax -define-syntax)
|
||||||
"ellipses.rkt"
|
"ellipses.rkt"
|
||||||
(for-syntax "stx.rkt" "define-et-al.rkt" "qq-and-or.rkt" "cond.rkt"
|
(for-syntax "stx.rkt" "define-et-al.rkt" "qq-and-or.rkt" "cond.rkt"
|
||||||
|
"prop-template-metafunction.rkt"
|
||||||
(rename "define-et-al.rkt" define -define)
|
(rename "define-et-al.rkt" define -define)
|
||||||
(rename "define-et-al.rkt" define-syntax -define-syntax)
|
(rename "define-et-al.rkt" define-syntax -define-syntax)
|
||||||
#;"member.rkt" "sc.rkt" '#%kernel))
|
#;"member.rkt" "sc.rkt" '#%kernel))
|
||||||
|
@ -12,14 +13,17 @@
|
||||||
datum
|
datum
|
||||||
~? ~@
|
~? ~@
|
||||||
~@! signal-absent-pvar
|
~@! signal-absent-pvar
|
||||||
|
(for-syntax prop:metafunction
|
||||||
|
metafunction
|
||||||
|
metafunction-accessor
|
||||||
|
metafunction?)
|
||||||
(protect
|
(protect
|
||||||
(for-syntax attribute-mapping
|
(for-syntax attribute-mapping
|
||||||
attribute-mapping?
|
attribute-mapping?
|
||||||
attribute-mapping-name
|
attribute-mapping-name
|
||||||
attribute-mapping-var
|
attribute-mapping-var
|
||||||
attribute-mapping-depth
|
attribute-mapping-depth
|
||||||
attribute-mapping-check
|
attribute-mapping-check)))
|
||||||
metafunction metafunction?)))
|
|
||||||
|
|
||||||
;; ============================================================
|
;; ============================================================
|
||||||
;; Syntax of templates
|
;; Syntax of templates
|
||||||
|
@ -111,11 +115,6 @@
|
||||||
(define (attribute-mapping-depth a) (attribute-mapping-ref a 2))
|
(define (attribute-mapping-depth a) (attribute-mapping-ref a 2))
|
||||||
(define (attribute-mapping-check a) (attribute-mapping-ref a 3))
|
(define (attribute-mapping-check a) (attribute-mapping-ref a 3))
|
||||||
|
|
||||||
;; (struct metafunction (var))
|
|
||||||
(define-values (struct:metafunction metafunction metafunction? metafunction-ref _mf-set!)
|
|
||||||
(make-struct-type 'syntax-metafunction #f 1 0 #f null (current-inspector)))
|
|
||||||
(define (metafunction-var mf) (metafunction-ref mf 0))
|
|
||||||
|
|
||||||
(define (guide-is? x tag) (and (pair? x) (eq? (car x) tag)))
|
(define (guide-is? x tag) (and (pair? x) (eq? (car x) tag)))
|
||||||
|
|
||||||
(define (ht-guide? x) (guide-is? x 'h-t))
|
(define (ht-guide? x) (guide-is? x 'h-t))
|
||||||
|
@ -275,7 +274,7 @@
|
||||||
(unless stx? (wrong-syntax (stx-car t) "metafunctions are not supported"))
|
(unless stx? (wrong-syntax (stx-car t) "metafunctions are not supported"))
|
||||||
(disappeared! (stx-car t))
|
(disappeared! (stx-car t))
|
||||||
(define guide (parse-t (stx-cdr t) depth esc?))
|
(define guide (parse-t (stx-cdr t) depth esc?))
|
||||||
`(t-metafun ,(metafunction-var mf) ,guide
|
`(t-metafun ,(metafunction-accessor mf) ,guide
|
||||||
(quote-syntax
|
(quote-syntax
|
||||||
,(let ([tstx (and (syntax? t) t)])
|
,(let ([tstx (and (syntax? t) t)])
|
||||||
(datum->syntax tstx (cons (stx-car t) #f) tstx tstx)))))]
|
(datum->syntax tstx (cons (stx-car t) #f) tstx tstx)))))]
|
||||||
|
|
Loading…
Reference in New Issue
Block a user