template: parse ellipses using stack of map environments

This is like the psyntax approach but frames are mutable
and track extra information.
This commit is contained in:
Ryan Culpepper 2019-06-14 01:16:33 +02:00
parent 7b4e757fe5
commit 2915657c27

View File

@ -73,50 +73,12 @@
;; - (list 'h-t G) ;; - (list 'h-t G)
;; - other expression (must be pair!) ;; - other expression (must be pair!)
;; A PVar is (pvar Id Id Id/#f Nat/#f)
;;
;; The first identifier (var) is from the syntax-mapping or attribute-binding.
;; The second (lvar) is a local variable name used to hold its value (or parts
;; thereof) in ellipsis iteration. The third is #f if var is trusted to have a
;; (Listof^depth Syntax) value, or an Id reference to a Checker procedure (see
;; below) if it needs to be checked.
;;
;; The depth-delta associated with a depth>0 pattern variable is the difference
;; between the pattern variable's depth and the depth at which it is used. (For
;; depth 0 pvars, it's #f.) For example, in
;;
;; (with-syntax ([x #'0]
;; [(y ...) #'(1 2)]
;; [((z ...) ...) #'((a b) (c d))])
;; (template (((x y z) ...) ...)))
;;
;; the depth-delta for x is #f, the depth-delta for y is 1, and the depth-delta
;; for z is 0. The depth-delta (or depth "delay") is also the depth of the
;; ellipsis form where the variable begins to be iterated over. That is, the
;; template above should be interpreted roughly as
;;
;; (let ([Lx (pvar-value-of x)]
;; [Ly (pvar-value-of y)]
;; [Lz (pvar-value-of z)])
;; (for/list ([Lz (in-list Lz)]) ;; depth 0
;; (for/list ([Ly (in-list Ly)] ;; depth 1
;; [Lz (in-list Lz)])
;; (___ Lx Ly Lz ___))))
(begin-for-syntax (begin-for-syntax
(define here-stx (quote-syntax here)) (define here-stx (quote-syntax here))
(define template-logger (make-logger 'template (current-logger))) (define template-logger (make-logger 'template (current-logger)))
;; (struct pvar (var lvar check dd) #:prefab)
(define-values (struct:pv pvar pvar? pvar-ref pvar-set!)
(make-struct-type 'pvar #f 4 0 #f null 'prefab #f '(0 1 2 3)))
(define (pvar-var pv) (pvar-ref pv 0))
(define (pvar-lvar pv) (pvar-ref pv 1))
(define (pvar-check pv) (pvar-ref pv 2))
(define (pvar-dd pv) (pvar-ref pv 3))
;; An Attribute is an identifier statically bound to a syntax-mapping ;; An Attribute is an identifier statically bound to a syntax-mapping
;; (see sc.rkt) whose valvar is an identifier statically bound to an ;; (see sc.rkt) whose valvar is an identifier statically bound to an
;; attribute-mapping. ;; attribute-mapping.
@ -170,14 +132,51 @@
[(eq? (car g2) 't-list*) (list* 't-list* g1 (cdr g2))] [(eq? (car g2) 't-list*) (list* 't-list* g1 (cdr g2))]
[else (list 't-list* g1 g2)])) [else (list 't-list* g1 g2)]))
;; A Depth is (Listof MapFrame)
;; A DotsFrame is (vector (Listof (cons Id Syntax)) (Hash Id => Id) Id Bool)
;; Each ellipsis in a template has a corresponding DotsFrame of the form
;; (vector env ht ellipsis-id any-vars?), where
;; -- env is (list (cons iter-id src-list-expr) ...), where src-list-expr
;; is a src-list-id either by itself or wrapped in a check
;; -- ht maps a src-list-id to the corresponding iter-id
;; -- ellipsis-id is the identifier for the ellipsis (for error reporting)
;; -- any-vars? is a flag that indicates whether any pattern variables occur
;; in this frame's subtemplate (for error reporting)
;; When a pattern variable of depth D is found, it is added to the D current
;; innermost (ie, topmost) dotsframes (see `lookup`).
(define (new-dotsframe ellipsis-stx)
(vector null (make-hasheq) ellipsis-stx #f))
(define (dotsframe-env frame) (vector-ref frame 0))
(define (dotsframe-ref frame src-id)
(hash-ref (vector-ref frame 1) src-id #f))
(define (dotsframe-add! frame iter-id src-id src-expr)
(vector-set! frame 0 (cons (cons iter-id src-expr) (vector-ref frame 0)))
(hash-set! (vector-ref frame 1) src-id iter-id))
(define (dotsframe-index-iter frame) (vector-ref frame 2))
(define (dotsframe-index-iter! frame)
(cond [(vector-ref frame 2) => (lambda (x) x)]
[else (let ([index-var (gentemp)])
(vector-set! frame 2 index-var)
index-var)]))
(define (dotsframe-ellipsis-id frame) (vector-ref frame 2))
(define (dotsframe-has-mapvars? frame) (pair? (vector-ref frame 0)))
(define (dotsframe-has-any-vars? frame) (vector-ref frame 3))
(define (frames-seen-pvar! frames)
(when (pair? frames)
(unless (vector-ref (car frames) 3)
(vector-set! (car frames) 3 #t)
(frames-seen-pvar! (cdr frames)))))
(define (ellipsis? x)
(and (identifier? x) (free-identifier=? x (quote-syntax ...))))
;; ---------------------------------------- ;; ----------------------------------------
;; Parsing templates ;; Parsing templates
;; parse-template : Syntax Syntax Boolean -> (values (listof PVar) Guide (Listof Id)) ;; parse-template : Syntax Syntax Boolean -> (values Guide (Listof Id))
(define (parse-template ctx t stx?) (define (parse-template ctx t stx?)
;; env : Hasheq[ (cons syntax-mapping Nat) => PVar ]
(define env (make-hasheq))
;; wrong-syntax : Syntax Format-String Any ... -> (error) ;; wrong-syntax : Syntax Format-String Any ... -> (error)
(define (wrong-syntax x fmt . args) (raise-syntax-error #f (apply format fmt args) ctx x)) (define (wrong-syntax x fmt . args) (raise-syntax-error #f (apply format fmt args) ctx x))
@ -186,7 +185,7 @@
;; disappeared! : Id -> Void ;; disappeared! : Id -> Void
(define (disappeared! id) (set! disappeared-uses (cons id disappeared-uses))) (define (disappeared! id) (set! disappeared-uses (cons id disappeared-uses)))
;; parse-t : Stx Nat Boolean -> (values (dsetof PVar) Guide) ;; parse-t : Stx Nat Boolean -> Guide
(define (parse-t t depth esc?) (define (parse-t t depth esc?)
(cond [(stx-pair? t) (cond [(stx-pair? t)
(if (identifier? (stx-car t)) (if (identifier? (stx-car t))
@ -202,89 +201,73 @@
[(parse-form t (quote-syntax ...) 1) [(parse-form t (quote-syntax ...) 1)
=> (lambda (t) => (lambda (t)
(disappeared! (car t)) (disappeared! (car t))
(define-values (drivers guide) (parse-t (cadr t) depth #t)) (define guide (parse-t (cadr t) depth #t))
;; Preserve t-escaped so that (t-escaped (t-const _)) != (t-const _) ;; Preserve t-escaped so that (t-escaped (t-const _)) != (t-const _)
(values drivers `(t-escaped ,guide)))] `(t-escaped ,guide))]
[(parse-form t (quote-syntax ~?) 2) [(parse-form t (quote-syntax ~?) 2)
=> (lambda (t) => (lambda (t)
(disappeared! (car t)) (disappeared! (car t))
(define t1 (cadr t)) (define t1 (cadr t))
(define t2 (caddr t)) (define t2 (caddr t))
(define-values (drivers1 guide1) (parse-t t1 depth esc?)) (define guide1 (parse-t t1 depth esc?))
(define-values (drivers2 guide2) (parse-t t2 depth esc?)) (define guide2 (parse-t t2 depth esc?))
(values (dset-union drivers1 drivers2) `(t-orelse ,guide1 ,guide2)))] `(t-orelse ,guide1 ,guide2))]
[(lookup-metafun (stx-car t)) [(lookup-metafun (stx-car t))
=> (lambda (mf) => (lambda (mf)
(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-values (drivers guide) (parse-t (stx-cdr t) depth esc?)) (define guide (parse-t (stx-cdr t) depth esc?))
(values drivers `(t-metafun ,(metafunction-var mf) ,guide
`(t-metafun ,(metafunction-var 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))))))]
[else (parse-t-pair/dots t depth esc?)])) [else (parse-t-pair/dots t depth esc?)]))
;; parse-t-pair/dots : Stx Nat Boolean -> ... ;; parse-t-pair/dots : Stx Nat Boolean -> ...
;; t is a stx pair; check for dots ;; t is a stx pair; check for dots
(define (parse-t-pair/dots t depth esc?) (define (parse-t-pair/dots t depth esc?)
(define head (stx-car t)) (define head (stx-car t))
(define-values (tail nesting) (define-values (tail frames) ;; first-in-stx = innermost is first in list
(let loop ([tail (stx-cdr t)] [nesting 0]) (let loop ([tail (stx-cdr t)] [frames null])
(if (and (not esc?) (stx-pair? tail) (cond [(and (not esc?) (stx-pair? tail) (ellipsis? (stx-car tail)))
(let ([x (stx-car tail)]) (disappeared! (stx-car tail))
(and (identifier? x) (free-identifier=? x (quote-syntax ...))))) (loop (stx-cdr tail) (cons (new-dotsframe (stx-car tail)) frames))]
(begin (disappeared! (stx-car tail)) (loop (stx-cdr tail) (add1 nesting))) [else (values tail (reverse frames))])))
(values tail nesting)))) (define at-stx (datum->syntax #f '... head))
(if (zero? nesting) (define hguide
(parse-t-pair/normal t depth esc?) (let loop ([frames frames] [hguide (parse-h head (append frames depth) esc?)])
(let-values ([(hdrivers hguide) (parse-h head (+ depth nesting) esc?)] (cond [(pair? frames)
[(tdrivers tguide) (parse-t tail depth esc?)]) (define frame (car frames))
(when (dset-empty? hdrivers) (unless (dotsframe-has-mapvars? frame)
(wrong-syntax head "no pattern variables before ellipsis in template")) (unless (dotsframe-has-any-vars? frame)
(when (dset-empty? (dset-filter hdrivers (pvar/dd<=? depth))) (wrong-syntax head "no pattern variables before ellipsis in template"))
(let ([bad-dots ;; select the nestingth (last) ellipsis as the bad one (wrong-syntax (dotsframe-ellipsis-id frame) "too many ellipses in template"))
(stx-car (stx-drop nesting t))]) (loop (cdr frames)
;; FIXME: improve error message?
(wrong-syntax bad-dots "too many ellipses in template")))
;; hdrivers is (listof (dsetof pvar))
(define hdriverss ;; per level
(let loop ([i 0])
(if (< i nesting)
(cons (dset-filter hdrivers (pvar/dd<=? (+ depth i)))
(loop (add1 i)))
null)))
(define at-stx (datum->syntax #f '... head))
(define hg
(let loop ([hdriverss hdriverss])
(cond [(null? (cdr hdriverss))
(let ([cons? (ht-guide? hguide)] (let ([cons? (ht-guide? hguide)]
[hguide (if (ht-guide? hguide) (ht-guide-t hguide) hguide)]) [hguide (if (ht-guide? hguide) (ht-guide-t hguide) hguide)]
`(t-dots ,cons? ,hguide ,(car hdriverss) [env (dotsframe-env frame)])
(quote ,head) (quote-syntax ,at-stx)))] ;; FIXME: optimize (x ...) case where x is trusted!
[else (let ([inner (loop (cdr hdriverss))]) `(t-dots ,cons? ,hguide ,(map car env) ,(map cdr env)
`(t-dots #f ,inner ,(car hdriverss) (quote ,head) (quote-syntax ,at-stx))))]
(quote ,head) (quote-syntax ,at-stx)))]))) [else hguide])))
(values (dset-union hdrivers tdrivers) (define tguide (parse-t tail depth esc?))
(if (equal? tguide '(t-list)) (cond [(equal? tguide `(t-list)) (resyntax t hguide)]
(resyntax t hg) [else (resyntax t `(t-append ,hguide ,tguide))]))
(resyntax t `(t-append ,hg ,tguide)))))))
;; parse-t-pair/normal : Stx Nat Boolean -> ... ;; parse-t-pair/normal : Stx Nat Boolean -> ...
;; t is a normal stx pair ;; t is a normal stx pair
(define (parse-t-pair/normal t depth esc?) (define (parse-t-pair/normal t depth esc?)
(define-values (hdrivers hguide) (parse-h (stx-car t) depth esc?)) (define hguide (parse-h (stx-car t) depth esc?))
(define-values (tdrivers tguide) (parse-t (stx-cdr t) depth esc?)) (define tguide (parse-t (stx-cdr t) depth esc?))
(values (dset-union hdrivers tdrivers) (resyntax t
(resyntax t (if (ht-guide? hguide)
(if (ht-guide? hguide) (let ([hguide (ht-guide-t hguide)])
(let ([hguide (ht-guide-t hguide)]) (if (and (const-guide? hguide) (const-guide? tguide))
(if (and (const-guide? hguide) (const-guide? tguide)) (const-guide t)
(const-guide t) (cons-guide hguide tguide)))
(cons-guide hguide tguide))) (if (equal? tguide '(t-list))
(if (equal? tguide '(t-list)) hguide
hguide `(t-append ,hguide ,tguide)))))
`(t-append ,hguide ,tguide))))))
;; parse-t-nonpair : Syntax Nat Boolean -> ... ;; parse-t-nonpair : Syntax Nat Boolean -> ...
;; PRE: t is not a stxpair ;; PRE: t is not a stxpair
@ -298,92 +281,89 @@
(wrong-syntax t "illegal use")] (wrong-syntax t "illegal use")]
[(lookup-metafun t) [(lookup-metafun t)
(wrong-syntax t "illegal use of syntax metafunction")] (wrong-syntax t "illegal use of syntax metafunction")]
[(lookup t depth) [(lookup t depth) => (lambda (ref) ref)]
=> (lambda (pvar) [else (const-guide t)])]
(disappeared! t)
(values (dset pvar)
(cond [(pvar-check pvar)
=> (lambda (check)
`(#%expression
(,check ,(pvar-lvar pvar) 0 #t (quote-syntax ,t))))]
[else `(t-var ,(pvar-lvar pvar))])))]
[else (values (dset) (const-guide t))])]
[(vector? td) [(vector? td)
(define-values (drivers guide) (parse-t (vector->list td) depth esc?)) (define guide (parse-t (vector->list td) depth esc?))
(values drivers (cond [(const-guide? guide) (const-guide t)]
(cond [(const-guide? guide) (const-guide t)] [else (resyntax t `(t-vector ,guide))])]
[else (resyntax t `(t-vector ,guide))]))]
[(prefab-struct-key td) [(prefab-struct-key td)
=> (lambda (key) => (lambda (key)
(define-values (drivers guide) (define guide
(let ([elems (cdr (vector->list (struct->vector td)))]) (let ([elems (cdr (vector->list (struct->vector td)))])
(parse-t elems depth esc?))) (parse-t elems depth esc?)))
(values drivers (cond [(const-guide? guide) (const-guide t)]
(cond [(const-guide? guide) (const-guide t)] [else (resyntax t `(t-struct (quote ,key) ,guide))]))]
[else (resyntax t `(t-struct (quote ,key) ,guide))])))]
[(box? td) [(box? td)
(define-values (drivers guide) (parse-t (unbox td) depth esc?)) (define guide (parse-t (unbox td) depth esc?))
(values drivers (if (const-guide? guide) (const-guide t) (resyntax t `(t-box ,guide))))] (if (const-guide? guide) (const-guide t) (resyntax t `(t-box ,guide)))]
[else (values (dset) (const-guide t))])) [else (const-guide t)]))
;; parse-h : Syntax Nat Boolean -> (values (dsetof PVar) HeadGuide) ;; parse-h : Syntax Depth Boolean -> HeadGuide
(define (parse-h h depth esc?) (define (parse-h h depth esc?)
(cond [(and (not esc?) (parse-form h (quote-syntax ~?) 1)) (cond [(and (not esc?) (parse-form h (quote-syntax ~?) 1))
=> (lambda (h) => (lambda (h)
(disappeared! (car h)) (disappeared! (car h))
(define-values (drivers guide) (parse-h (cadr h) depth esc?)) (define guide (parse-h (cadr h) depth esc?))
(values drivers `(h-orelse ,guide null)))] `(h-orelse ,guide null))]
[(and (not esc?) (parse-form h (quote-syntax ~?) 2)) [(and (not esc?) (parse-form h (quote-syntax ~?) 2))
=> (lambda (h) => (lambda (h)
(disappeared! (car h)) (disappeared! (car h))
(define-values (drivers1 guide1) (parse-h (cadr h) depth esc?)) (define guide1 (parse-h (cadr h) depth esc?))
(define-values (drivers2 guide2) (parse-h (caddr h) depth esc?)) (define guide2 (parse-h (caddr h) depth esc?))
(values (dset-union drivers1 drivers2) (if (and (ht-guide? guide1) (ht-guide? guide2))
(if (and (ht-guide? guide1) (ht-guide? guide2)) `(h-t (t-orelse ,(ht-guide-t guide1) ,(ht-guide-t guide2)))
`(h-t (t-orelse ,(ht-guide-t guide1) ,(ht-guide-t guide2))) `(h-orelse ,guide1 ,guide2)))]
`(h-orelse ,guide1 ,guide2))))]
[(and (stx-pair? h) [(and (stx-pair? h)
(let ([h-head (stx-car h)]) (let ([h-head (stx-car h)])
(and (identifier? h-head) (and (identifier? h-head)
(or (and (free-identifier=? h-head (quote-syntax ~@)) (not esc?)) (or (and (free-identifier=? h-head (quote-syntax ~@)) (not esc?))
(free-identifier=? h-head (quote-syntax ~@!)))))) (free-identifier=? h-head (quote-syntax ~@!))))))
(disappeared! (stx-car h)) (disappeared! (stx-car h))
(define-values (drivers guide) (parse-t (stx-cdr h) depth esc?)) (define guide (parse-t (stx-cdr h) depth esc?))
(values drivers `(h-splice ,guide (quote ,h) (quote-syntax ,(stx-car h))))] `(h-splice ,guide (quote ,h) (quote-syntax ,(stx-car h)))]
[else [else
(define-values (drivers guide) (parse-t h depth esc?)) (define guide (parse-t h depth esc?))
(values drivers `(h-t ,guide))])) `(h-t ,guide)]))
;; lookup : Identifier Nat -> PVar/#f ;; lookup : Identifier Depth -> Syntax/#f
(define (lookup id depth) ;; If pattern variable with depth>0, insert into depth innermost ellipsis envs.
(define (lookup id depth0)
(define (make-pvar var check pvar-depth) (define (make-pvar var check pvar-depth)
(cond [(zero? pvar-depth) (define (make-ref var)
(pvar var var check #f)] (cond [check `(t-check-var (,check ,var 0 #t (quote-syntax ,id)))]
[(>= depth pvar-depth) [else `(t-var ,var)]))
(pvar var (gentemp) check (- depth pvar-depth))] (define (make-src-ref var id)
[(zero? depth) (cond [check `(#%expression (,check ,var 1 #f (quote-syntax ,id)))]
(wrong-syntax id "missing ellipsis with pattern variable in template")] [else `(#%expression ,var)]))
[else (frames-seen-pvar! depth0)
(wrong-syntax id "too few ellipses for pattern variable in template")])) (make-ref
(define (hash-ref! h k proc) (let dloop ([depth depth0] [pvar-depth pvar-depth]) ;; ... -> Identifier
(let ([v (hash-ref h k #f)]) (if v v (let ([v* (proc)]) (hash-set! h k v*) v*)))) ;; Returns variable reference whose value has not been checked yet.
(cond [(zero? pvar-depth) var]
[(null? depth)
(if (null? depth0)
(wrong-syntax id "missing ellipsis with pattern variable in template")
(wrong-syntax id "too few ellipses for pattern variable in template"))]
[else
(define src (dloop (cdr depth) (sub1 pvar-depth)))
(or (dotsframe-ref (car depth) src)
(let ([iter (gentemp)])
(dotsframe-add! (car depth) iter src (make-src-ref src id))
iter))]))))
(let ([v (syntax-local-value id (lambda () #f))]) (let ([v (syntax-local-value id (lambda () #f))])
(cond [(syntax-pattern-variable? v) (cond [(and stx? (syntax-pattern-variable? v))
(hash-ref! env (cons v depth) (define pvar-depth (syntax-mapping-depth v))
(lambda () (define attr
(define pvar-depth (syntax-mapping-depth v)) (let ([attr (syntax-local-value (syntax-mapping-valvar v) (lambda () #f))])
(define attr (and (attribute-mapping? attr) attr)))
(let ([attr (syntax-local-value (syntax-mapping-valvar v) (lambda () #f))]) (define var (if attr (attribute-mapping-var attr) (syntax-mapping-valvar v)))
(and (attribute-mapping? attr) attr))) (define check (and attr (attribute-mapping-check attr)))
(define var (if attr (attribute-mapping-var attr) (syntax-mapping-valvar v))) (make-pvar var check pvar-depth)]
(define check (and attr (attribute-mapping-check attr))) [(and (not stx?) (s-exp-pattern-variable? v))
(make-pvar var check pvar-depth)))] (define pvar-depth (s-exp-mapping-depth v))
[(s-exp-pattern-variable? v) (define var (s-exp-mapping-valvar v))
(hash-ref! env (cons v depth) (make-pvar var #f pvar-depth)]
(lambda ()
(define pvar-depth (s-exp-mapping-depth v))
(define var (s-exp-mapping-valvar v))
(make-pvar var #f pvar-depth)))]
[else [else
;; id is a constant; check that for all x s.t. id = x.y, x is not an attribute ;; id is a constant; check that for all x s.t. id = x.y, x is not an attribute
(for-each (for-each
@ -459,8 +439,8 @@
[(syntax? x) `(t-const (quote-syntax ,x))] [(syntax? x) `(t-const (quote-syntax ,x))]
[else `(t-const (syntax-e (quote-syntax ,(datum->syntax #f x))))])) [else `(t-const (syntax-e (quote-syntax ,(datum->syntax #f x))))]))
(let-values ([(drivers guide) (parse-t t 0 #f)]) (let ([guide (parse-t t null #f)])
(values (dset->list drivers) guide disappeared-uses))) (values guide disappeared-uses)))
;; parse-form : Stx Id Nat -> (list[arity+1] Syntax) ;; parse-form : Stx Id Nat -> (list[arity+1] Syntax)
(define (parse-form stx form-id arity) (define (parse-form stx form-id arity)
@ -489,9 +469,6 @@
(map (lambda (loc) (datum->syntax id (string->symbol (substring id-string 0 loc)))) (map (lambda (loc) (datum->syntax id (string->symbol (substring id-string 0 loc))))
dot-locations))) dot-locations)))
(define (pvar/dd<=? expected-dd)
(lambda (x) (let ([dd (pvar-dd x)]) (and dd (<= dd expected-dd)))))
(define gentemp-counter 0) (define gentemp-counter 0)
(define (gentemp) (define (gentemp)
(set! gentemp-counter (add1 gentemp-counter)) (set! gentemp-counter (add1 gentemp-counter))
@ -501,29 +478,6 @@
(define (stx-drop n x) (define (stx-drop n x)
(if (zero? n) x (stx-drop (sub1 n) (stx-cdr x)))) (if (zero? n) x (stx-drop (sub1 n) (stx-cdr x))))
;; ----------------------------------------
;; Deterministic Sets
;; FIXME: detect big unions, use hash table
(define (dset . xs) xs)
(define (dset-empty? ds) (null? ds))
(define (dset-filter ds pred) (filter pred ds))
(define (dset->list ds) ds)
(define (dset-union ds1 ds2)
(if (pair? ds1)
(let ([elem (car ds1)])
(if (member elem ds2)
(dset-union (cdr ds1) ds2)
(dset-union (cdr ds1) (cons (car ds1) ds2))))
ds2))
(define (filter keep? xs)
(if (pair? xs)
(if (keep? (car xs))
(cons (car xs) (filter keep? (cdr xs)))
(filter keep? (cdr xs)))
null))
;; ---------------------------------------- ;; ----------------------------------------
;; Relocating (eg, syntax/loc) ;; Relocating (eg, syntax/loc)
@ -559,17 +513,13 @@
;; do-template : Syntax Syntax Id/#f Boolean -> Syntax ;; do-template : Syntax Syntax Id/#f Boolean -> Syntax
(define (do-template ctx tstx loc-id stx?) (define (do-template ctx tstx loc-id stx?)
(define-values (pvars pre-guide disappeared-uses) (define-values (pre-guide disappeared-uses)
(parse-template ctx tstx stx?)) (parse-template ctx tstx stx?))
(define guide (if loc-id (relocate-guide ctx pre-guide loc-id) pre-guide)) (define guide (if loc-id (relocate-guide ctx pre-guide loc-id) pre-guide))
(define ell-pvars (filter pvar-dd pvars))
(define pre-code (define pre-code
(if (const-guide? guide) (if (const-guide? guide)
(if stx? `(quote-syntax ,tstx) `(quote ,tstx)) (if stx? `(quote-syntax ,tstx) `(quote ,tstx))
(let ([lvars (map pvar-lvar ell-pvars)] guide))
[valvars (map pvar-var ell-pvars)])
`(let (,@(map list lvars valvars))
,(datum->syntax here-stx guide)))))
(define code (syntax-arm (datum->syntax here-stx pre-code ctx))) (define code (syntax-arm (datum->syntax here-stx pre-code ctx)))
(syntax-property code 'disappeared-use (map syntax-local-introduce disappeared-uses))) (syntax-property code 'disappeared-use (map syntax-local-introduce disappeared-uses)))
) )
@ -609,33 +559,22 @@
;; ============================================================ ;; ============================================================
;; Run-time support ;; Run-time support
;; (t-dots cons? hguide hdrivers) : Expr[(Listof Syntax)] ;; (t-dots cons? hguide iter-vars src-vars head-datum at-stx) : Expr[(Listof Syntax)]
(define-syntax (t-dots stx) (define-syntax (t-dots stx)
(define s (syntax->list stx)) (define s (syntax->list stx))
(define cons? (syntax-e (list-ref s 1))) (define cons? (syntax-e (list-ref s 1)))
(define head (list-ref s 2)) (define head (list-ref s 2))
(define drivers (map syntax-e (syntax->list (list-ref s 3)))) ;; (Listof PVar) (define iter-vars (syntax->list (list-ref s 3)))
(define in-stx (list-ref s 4)) (define src-exprs (syntax->list (list-ref s 4)))
(define at-stx (list-ref s 5)) (define in-stx (list-ref s 5))
(cond (define at-stx (list-ref s 6))
;; Case 1: (x ...) where x is trusted (define code
[(and cons? (let ([head-s (syntax->list head)]) `(let ,(map list iter-vars src-exprs)
(and (pair? head-s) (eq? (syntax-e (car head-s)) 't-var)))) ,(if (> (length iter-vars) 1) `(check-same-length ,in-stx ,at-stx . ,iter-vars) '(void))
head] ,(if cons?
;; General case `(map (lambda ,iter-vars ,head) . ,iter-vars)
[else `(apply append (map (lambda ,iter-vars ,head) . ,iter-vars)))))
;; var-value-expr : Id Id/#'#f -> Expr[List] (datum->syntax here-stx code stx))
(define (var-value-expr lvar check)
(if (syntax-e check) `(,check ,lvar 1 #f #f) lvar))
(define lvars (map pvar-lvar drivers))
(define checks (map pvar-check drivers))
(define code
`(let ,(map list lvars (map var-value-expr lvars checks))
,(if (> (length lvars) 1) `(check-same-length ,in-stx ,at-stx . ,lvars) '(void))
,(if cons?
`(map (lambda ,lvars ,head) . ,lvars)
`(apply append (map (lambda ,lvars ,head) . ,lvars)))))
(datum->syntax here-stx code stx)]))
(define-syntaxes (t-orelse h-orelse) (define-syntaxes (t-orelse h-orelse)
(let () (let ()
@ -647,6 +586,7 @@
(#%require (rename '#%kernel t-const #%expression) (#%require (rename '#%kernel t-const #%expression)
(rename '#%kernel t-var #%expression) (rename '#%kernel t-var #%expression)
(rename '#%kernel t-check-var #%expression)
;; (rename '#%kernel t-append append) ;; (rename '#%kernel t-append append)
(rename '#%kernel t-list list) (rename '#%kernel t-list list)
(rename '#%kernel t-list* list*) (rename '#%kernel t-list* list*)