www

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

parse.rkt (55382B)


      1 #lang racket/base
      2 (require (for-syntax racket/base
      3                      syntax/stx
      4                      syntax/private/id-table
      5                      syntax/keyword
      6                      racket/syntax
      7                      syntax/parse/private/minimatch
      8                      syntax/parse/private/datum-to-expr
      9                      syntax/parse/private/rep-attrs
     10                      syntax/parse/private/rep-data
     11                      syntax/parse/private/rep-patterns
     12                      "rep.rkt"
     13                      syntax/parse/private/kws
     14                      "opt.rkt"
     15                      "txlift.rkt")
     16          syntax/parse/private/keywords
     17          racket/syntax
     18          racket/stxparam
     19          syntax/stx
     20          stxparse-info/parse/private/residual ;; keep abs. path
     21          "runtime.rkt"
     22          stxparse-info/parse/private/runtime-reflect) ;; keep abs. path
     23 
     24 ;; ============================================================
     25 
     26 (provide define-syntax-class
     27          define-splicing-syntax-class
     28          define-integrable-syntax-class
     29          syntax-parse
     30          syntax-parser
     31          define/syntax-parse
     32          syntax-parser/template
     33          parser/rhs
     34          define-eh-alternative-set
     35          (for-syntax rhs->parser))
     36 
     37 (begin-for-syntax
     38  ;; constant-desc : Syntax -> String/#f
     39  (define (constant-desc stx)
     40    (syntax-case stx (quote)
     41      [(quote datum)
     42       (let ([d (syntax-e #'datum)])
     43         (and (string? d) d))]
     44      [expr
     45       (let ([d (syntax-e #'expr)])
     46         (and (string? d)
     47              (free-identifier=? #'#%datum (datum->syntax #'expr '#%datum))
     48              d))]))
     49 
     50  (define (tx:define-*-syntax-class stx splicing?)
     51    (syntax-case stx ()
     52      [(_ header . rhss)
     53       (parameterize ((current-syntax-context stx))
     54         (let-values ([(name formals arity)
     55                       (let ([p (check-stxclass-header #'header stx)])
     56                         (values (car p) (cadr p) (caddr p)))])
     57           (let ([the-rhs (parse-rhs #'rhss splicing? #:context stx
     58                                     #:default-description (symbol->string (syntax-e name)))])
     59             (with-syntax ([name name]
     60                           [formals formals]
     61                           [desc (cond [(rhs-description the-rhs) => constant-desc] [else #f])]
     62                           [parser (generate-temporary (format-symbol "parse-~a" name))]
     63                           [arity arity]
     64                           [attrs (rhs-attrs the-rhs)]
     65                           [commit? (rhs-commit? the-rhs)]
     66                           [delimit-cut? (rhs-delimit-cut? the-rhs)]
     67                           [the-rhs-expr (datum->expression the-rhs)])
     68               #`(begin (define-syntax name
     69                          (stxclass 'name 'arity
     70                                    'attrs
     71                                    (quote-syntax parser)
     72                                    '#,splicing?
     73                                    (scopts (length 'attrs) 'commit? 'delimit-cut? desc)
     74                                    #f))
     75                        (define-values (parser)
     76                          (parser/rhs name formals attrs the-rhs-expr #,splicing? #,stx)))))))])))
     77 
     78 (define-syntax define-syntax-class
     79   (lambda (stx) (tx:define-*-syntax-class stx #f)))
     80 (define-syntax define-splicing-syntax-class
     81   (lambda (stx) (tx:define-*-syntax-class stx #t)))
     82 
     83 (define-syntax (define-integrable-syntax-class stx)
     84   (syntax-case stx (quote)
     85     [(_ name (quote description) predicate)
     86      (with-syntax ([parser (generate-temporary (format-symbol "parse-~a" (syntax-e #'name)))]
     87                    [no-arity no-arity])
     88        #'(begin (define-syntax name
     89                   (stxclass 'name no-arity '()
     90                             (quote-syntax parser)
     91                             #f
     92                             (scopts 0 #t #t 'description)
     93                             (quote-syntax predicate)))
     94                 (define (parser x cx pr es undos fh0 cp0 rl success)
     95                   (if (predicate x)
     96                       (success fh0 undos)
     97                       (let ([es (es-add-thing pr 'description #t rl es)])
     98                         (fh0 undos (failure* pr es)))))))]))
     99 
    100 (define-syntax (parser/rhs stx)
    101   (syntax-case stx ()
    102     [(parser/rhs name formals relsattrs the-rhs-expr splicing? ctx)
    103      (with-disappeared-uses
    104       (let ()
    105         (define the-rhs
    106           (parameterize ((current-syntax-context #'ctx))
    107             (fixup-rhs (syntax-local-eval
    108                         (syntax-local-introduce #'the-rhs-expr))
    109                        (syntax-e #'splicing?)
    110                        (syntax->datum #'relsattrs))))
    111         (rhs->parser #'name #'formals #'relsattrs the-rhs (syntax-e #'splicing?) #'ctx)))]))
    112 
    113 (begin-for-syntax
    114  (define (rhs->parser name formals relsattrs the-rhs splicing? [ctx #f])
    115    (define-values (transparent? description variants defs commit? delimit-cut?)
    116      (match the-rhs
    117        [(rhs _ transparent? description variants defs commit? delimit-cut?)
    118         (values transparent? description variants defs commit? delimit-cut?)]))
    119    (define vdefss (map variant-definitions variants))
    120    (define formals* (rewrite-formals formals #'x #'rl))
    121    (define patterns (map variant-pattern variants))
    122    (define no-fail?
    123      (and (not splicing?) ;; FIXME: commit? needed?
    124           (patterns-cannot-fail? patterns)))
    125    (when no-fail? (log-syntax-parse-debug "(stxclass) cannot fail: ~e" ctx))
    126    (define body
    127      (cond [(null? patterns)
    128             #'(fail (failure* pr es))]
    129            [splicing?
    130             (with-syntax ([(alternative ...)
    131                            (for/list ([pattern (in-list patterns)])
    132                              (with-syntax ([pattern pattern]
    133                                            [relsattrs relsattrs]
    134                                            [iattrs (pattern-attrs pattern)]
    135                                            [commit? commit?]
    136                                            [result-pr
    137                                             (if transparent?
    138                                                 #'rest-pr
    139                                                 #'(ps-pop-opaque rest-pr))])
    140                                #'(parse:H x cx rest-x rest-cx rest-pr pattern pr es
    141                                           (variant-success relsattrs iattrs (rest-x rest-cx result-pr)
    142                                                            success cp0 commit?))))])
    143               #'(try alternative ...))]
    144            [else
    145             (with-syntax ([matrix
    146                            (optimize-matrix
    147                             (for/list ([pattern (in-list patterns)])
    148                               (with-syntax ([iattrs (pattern-attrs pattern)]
    149                                             [relsattrs relsattrs]
    150                                             [commit? commit?])
    151                                 (pk1 (list pattern)
    152                                      #'(variant-success relsattrs iattrs ()
    153                                                         success cp0 commit?)))))])
    154               #'(parse:matrix ((x cx pr es)) matrix))]))
    155    (with-syntax ([formals* formals*]
    156                  [(def ...) defs]
    157                  [((vdef ...) ...) vdefss]
    158                  [description description]
    159                  [transparent? transparent?]
    160                  [delimit-cut? delimit-cut?]
    161                  [body body])
    162      #`(lambda (x cx pr es undos fh0 cp0 rl success . formals*)
    163          (with ([this-syntax x]
    164                 [this-role rl])
    165                def ...
    166                vdef ... ...
    167                (#%expression
    168                 (syntax-parameterize ((this-context-syntax
    169                                        (syntax-rules ()
    170                                          [(tbs) (ps-context-syntax pr)])))
    171                   (let ([es (es-add-thing pr description 'transparent? rl
    172                                           #,(if no-fail? #'#f #'es))]
    173                         [pr (if 'transparent? pr (ps-add-opaque pr))])
    174                     (with ([fail-handler fh0]
    175                            [cut-prompt cp0]
    176                            [undo-stack undos])
    177                       ;; Update the prompt, if required
    178                       ;; FIXME: can be optimized away if no cut exposed within variants
    179                       (with-maybe-delimit-cut delimit-cut?
    180                         body))))))))))
    181 
    182 (define-syntax (syntax-parse stx)
    183   (syntax-case stx ()
    184     [(syntax-parse stx-expr . clauses)
    185      (quasisyntax/loc stx
    186        (let ([x (datum->syntax #f stx-expr)])
    187          (with ([this-syntax x])
    188            (parse:clauses x clauses body-sequence #,((make-syntax-introducer) stx)))))]))
    189 
    190 (define-syntax (syntax-parser stx)
    191   (syntax-case stx ()
    192     [(syntax-parser . clauses)
    193      (quasisyntax/loc stx
    194        (lambda (x)
    195          (let ([x (datum->syntax #f x)])
    196            (with ([this-syntax x])
    197              (parse:clauses x clauses body-sequence #,((make-syntax-introducer) stx))))))]))
    198 
    199 (define-syntax (syntax-parser/template stx)
    200   (syntax-case stx ()
    201     [(syntax-parser/template ctx . clauses)
    202      (quasisyntax/loc stx
    203        (lambda (x)
    204          (let ([x (datum->syntax #f x)])
    205            (with ([this-syntax x])
    206              (parse:clauses x clauses one-template ctx)))))]))
    207 
    208 (define-syntax (define/syntax-parse stx)
    209   (syntax-case stx ()
    210     [(define/syntax-parse pattern . rest)
    211      (with-disappeared-uses
    212       (let-values ([(rest pattern defs)
    213                     (parse-pattern+sides #'pattern
    214                                          #'rest
    215                                          #:splicing? #f
    216                                          #:decls (new-declenv null)
    217                                          #:context stx)])
    218         (define no-fail? (patterns-cannot-fail? (list pattern)))
    219         (let ([expr
    220                (syntax-case rest ()
    221                  [( expr ) #'expr]
    222                  [_ (raise-syntax-error #f "bad syntax" stx)])]
    223               [attrs (pattern-attrs pattern)])
    224           (with-syntax ([(a ...) attrs]
    225                         [(#s(attr name _ _) ...) attrs]
    226                         [pattern pattern]
    227                         [es0 (if no-fail? #'#f #'#t)]
    228                         [(def ...) defs]
    229                         [expr expr])
    230             #'(defattrs/unpack (a ...)
    231                 (let* ([x (datum->syntax #f expr)]
    232                        [cx x]
    233                        [pr (ps-empty x x)]
    234                        [es es0]
    235                        [fh0 (syntax-patterns-fail
    236                              (normalize-context 'define/syntax-parse
    237                                                 '|define/syntax-parse pattern|
    238                                                 x))])
    239                   (parameterize ((current-syntax-context x))
    240                     def ...
    241                     (#%expression
    242                      (with ([fail-handler fh0]
    243                             [cut-prompt fh0]
    244                             [undo-stack null])
    245                            (parse:S x cx pattern pr es
    246                                     (list (attribute name) ...)))))))))))]))
    247 
    248 ;; ============================================================
    249 
    250 #|
    251 Parsing protocols:
    252 
    253 (parse:<X> <X-args> pr es success-expr) : Ans
    254 
    255   <S-args> : x cx
    256   <H-args> : x cx rest-x rest-cx rest-pr
    257   <EH-args> : x cx ???
    258   <A-args> : x cx
    259 
    260   x is term to parse, usually syntax but can be pair/null (stx-list?) in cdr patterns
    261   cx is most recent syntax object: if x must be coerced to syntax, use cx as lexctx and src
    262   pr, es are progress and expectstack, respectively
    263   rest-x, rest-cx, rest-pr are variable names to bind in context of success-expr
    264 
    265 (stxclass-parser x cx pr es undos fail-handler cut-prompt role success-proc arg ...) : Ans
    266 
    267   success-proc:
    268     for stxclass, is (fail-handler undos attr-value ... -> Ans)
    269     for splicing-stxclass, is (undos fail-handler rest-x rest-cx rest-pr attr-value -> Ans)
    270   fail-handler, cut-prompt : undos failure -> Ans
    271 
    272 Fail-handler is normally represented with stxparam 'fail-handler', but must be
    273 threaded through stxclass calls (in through stxclass-parser, out through
    274 success-proc) to support backtracking. Cut-prompt is never changed within
    275 stxclass or within alternative, so no threading needed.
    276 
    277 The undo stack is normally represented with stxparam 'undo-stack', but must be
    278 threaded through stxclass calls (like fail-handler). A failure handler closes
    279 over a base undo stack and receives an extended current undo stack; the failure
    280 handler unwinds effects by performing every action in the difference between
    281 them and then restores the saved undo stack.
    282 
    283 Usually sub-patterns processed in tail position, but *can* do non-tail calls for:
    284   - ~commit
    285   - var of stxclass with ~commit
    286 It is also safe to keep normal tail-call protocol and just adjust fail-handler.
    287 There is no real benefit to specializing ~commit, since it does not involve
    288 creating a success closure.
    289 
    290 Some optimizations:
    291   - commit protocol for stxclasses (but not ~commit, no point)
    292   - avoid continue-vs-end choice point in (EH ... . ()) by eager pair check
    293   - integrable stxclasses, specialize ellipses of integrable stxclasses
    294   - pattern lists that cannot fail set es=#f to disable ExpectStack allocation
    295 |#
    296 
    297 ;; ----
    298 
    299 (begin-for-syntax
    300  (define (wash stx)
    301    (syntax-e stx))
    302  (define (wash-list washer stx)
    303    (let ([l (stx->list stx)])
    304      (unless l (raise-type-error 'wash-list "stx-list" stx))
    305      (map washer l)))
    306  (define (wash-iattr stx)
    307    (with-syntax ([#s(attr name depth syntax?) stx])
    308      (attr #'name (wash #'depth) (wash #'syntax?))))
    309  (define (wash-sattr stx)
    310    (with-syntax ([#s(attr name depth syntax?) stx])
    311      (attr (wash #'name) (wash #'depth) (wash #'syntax?))))
    312  (define (wash-iattrs stx)
    313    (wash-list wash-iattr stx))
    314  (define (wash-sattrs stx)
    315    (wash-list wash-sattr stx))
    316  (define (generate-n-temporaries n)
    317    (generate-temporaries
    318     (for/list ([i (in-range n)])
    319       (string->symbol (format "g~sx" i))))))
    320 
    321 ;; ----
    322 
    323 #|
    324 Conventions:
    325   - rhs : RHS
    326   - iattr : IAttr
    327   - relsattr : SAttr
    328   - splicing? : bool
    329   - x : id (var)
    330   - cx : id (var, may be shadowed)
    331   - pr : id (var, may be shadowed)
    332   - es : id (var, may be shadowed)
    333   - success : var (bound to success procedure)
    334   - k : expr
    335   - rest-x, rest-cx, rest-pr : id (to be bound)
    336   - fh, cp, rl : id (var)
    337 |#
    338 
    339 (begin-for-syntax
    340  (define (rewrite-formals fstx x-id rl-id)
    341    (with-syntax ([x x-id]
    342                  [rl rl-id])
    343      (let loop ([fstx fstx])
    344        (syntax-case fstx ()
    345          [([kw arg default] . more)
    346           (keyword? (syntax-e #'kw))
    347           (cons #'(kw arg (with ([this-syntax x] [this-role rl]) default))
    348                 (loop #'more))]
    349          [([arg default] . more)
    350           (not (keyword? (syntax-e #'kw)))
    351           (cons #'(arg (with ([this-syntax x] [this-role rl]) default))
    352                 (loop #'more))]
    353          [(formal . more)
    354           (cons #'formal (loop #'more))]
    355          [_ fstx])))))
    356 
    357 ;; (with-maybe-delimit-cut bool expr)
    358 (define-syntax with-maybe-delimit-cut
    359   (syntax-rules ()
    360     [(wmdc #t k)
    361      (with ([cut-prompt fail-handler]) k)]
    362     [(wmdc #f k)
    363      k]))
    364 
    365 ;; (variant-success relsattrs variant (also:id ...) success bool) : expr[Ans]
    366 (define-syntax (variant-success stx)
    367   (syntax-case stx ()
    368     [(variant-success relsattrs iattrs (also ...) success cp0 commit?)
    369      #`(with-maybe-reset-fail commit? cp0
    370          (base-success-expr iattrs relsattrs (also ...) success))]))
    371 
    372 ;; (with-maybe-reset-fail bool id expr)
    373 (define-syntax with-maybe-reset-fail
    374   (syntax-rules ()
    375     [(wmrs #t cp0 k)
    376      (with ([fail-handler cp0]) k)]
    377     [(wmrs #f cp0 k)
    378      k]))
    379 
    380 ;; (base-success-expr iattrs relsattrs (also:id ...) success) : expr[Ans]
    381 (define-syntax (base-success-expr stx)
    382   (syntax-case stx ()
    383     [(base-success-expr iattrs relsattrs (also ...) success)
    384      (let ([reliattrs
    385             (reorder-iattrs (wash-sattrs #'relsattrs)
    386                             (wash-iattrs #'iattrs))])
    387        (with-syntax ([(#s(attr name _ _) ...) reliattrs])
    388          #'(success fail-handler undo-stack also ... (attribute name) ...)))]))
    389 
    390 ;; ----
    391 
    392 ;; (parse:clauses x clauses ctx)
    393 (define-syntax (parse:clauses stx)
    394   (syntax-case stx ()
    395     [(parse:clauses x clauses body-mode ctx)
    396      ;; if templates? is true, expect one form after kwargs in clause, wrap it with syntax
    397      ;; otherwise, expect non-empty body sequence (defs and exprs)
    398      (with-disappeared-uses
    399       (with-txlifts
    400        (lambda ()
    401         (define who
    402           (syntax-case #'ctx ()
    403             [(m . _) (identifier? #'m) #'m]
    404             [_ 'syntax-parse]))
    405         (define-values (chunks clauses-stx)
    406           (parse-keyword-options #'clauses parse-directive-table
    407                                  #:context #'ctx
    408                                  #:no-duplicates? #t))
    409         (define context
    410           (options-select-value chunks '#:context #:default #'x))
    411         (define colon-notation?
    412           (not (assq '#:disable-colon-notation chunks)))
    413         (define track-literals?
    414           (or (assq '#:track-literals chunks)
    415               (eq? (syntax-e #'body-mode) 'one-template)))
    416         (define-values (decls0 defs)
    417           (get-decls+defs chunks #:context #'ctx))
    418         ;; for-clause : stx -> (values pattern stx (listof stx))
    419         (define (for-clause clause)
    420           (syntax-case clause ()
    421             [[p . rest]
    422              (let-values ([(rest pattern defs2)
    423                            (parameterize ((stxclass-colon-notation? colon-notation?))
    424                              (parse-pattern+sides #'p #'rest
    425                                                   #:splicing? #f
    426                                                   #:decls decls0
    427                                                   #:context #'ctx))])
    428                (let ([body-expr
    429                       (case (syntax-e #'body-mode)
    430                         ((one-template)
    431                          (syntax-case rest ()
    432                            [(template)
    433                             #'(syntax template)]
    434                            [_ (raise-syntax-error #f "expected exactly one template" #'ctx)]))
    435                         ((body-sequence)
    436                          (syntax-case rest ()
    437                            [(e0 e ...)
    438                             ;; Should we use a shadower (works on the whole file, unhygienically),
    439                             ;; or use the context of the syntax-parse identifier?
    440                             (let ([the-#%intdef-begin (datum->syntax #'ctx '#%intdef-begin)])
    441                               (if (syntax-local-value the-#%intdef-begin (λ () #f)) ;; Defined as a macro
    442                                   #`(let () (#,the-#%intdef-begin e0 e ...))
    443                                   #'(let () e0 e ...)))]
    444                            [_ (raise-syntax-error #f "expected non-empty clause body"
    445                                                   #'ctx clause)]))
    446                         (else
    447                          (raise-syntax-error #f "internal error: unknown body mode" #'ctx #'body-mode)))])
    448                  (values pattern body-expr defs2)))]
    449             [_ (raise-syntax-error #f "expected clause" #'ctx clause)]))
    450         (define (wrap-track-literals stx)
    451           (if track-literals? (quasisyntax/loc stx (track-literals '#,who #,stx)) stx))
    452         (unless (stx-list? clauses-stx)
    453           (raise-syntax-error #f "expected sequence of clauses" #'ctx))
    454         (define-values (patterns body-exprs defs2s)
    455           (for/lists (patterns body-exprs defs2s) ([clause (in-list (stx->list clauses-stx))])
    456             (for-clause clause)))
    457         (define no-fail? (patterns-cannot-fail? patterns))
    458         (when no-fail? (log-syntax-parse-debug "cannot fail: ~e" #'ctx))
    459         (with-syntax ([(def ...) (apply append (get-txlifts-as-definitions) defs defs2s)])
    460           #`(let* ([ctx0 (normalize-context '#,who #,context x)]
    461                    [pr (ps-empty x (cadr ctx0))]
    462                    [es #,(if no-fail? #'#f #'#t)]
    463                    [cx x]
    464                    [fh0 (syntax-patterns-fail ctx0)])
    465               def ...
    466               (parameterize ((current-syntax-context (cadr ctx0))
    467                              (current-state '#hasheq())
    468                              (current-state-writable? #f))
    469                 #,(wrap-track-literals
    470                  #`(with ([fail-handler fh0]
    471                           [cut-prompt fh0]
    472                           [undo-stack null])
    473                      #,(cond [(pair? patterns)
    474                               (with-syntax ([matrix
    475                                              (optimize-matrix
    476                                               (for/list ([pattern (in-list patterns)]
    477                                                          [body-expr (in-list body-exprs)])
    478                                                 (pk1 (list pattern) body-expr)))])
    479                                 #'(parse:matrix ((x cx pr es)) matrix))
    480                               #|
    481                               (with-syntax ([(alternative ...)
    482                                              (for/list ([pattern (in-list patterns)]
    483                                                         [body-expr (in-list body-exprs)])
    484                                                #`(parse:S x cx #,pattern pr es #,body-expr))])
    485                                 #`(try alternative ...))
    486                               |#]
    487                              [else
    488                               #`(fail (failure* pr es))])))))))))]))
    489 
    490 ;; ----
    491 
    492 ;; (parse:matrix ((x cx pr es) ...) (PK ...)) : expr[Ans]
    493 ;; (parse:matrix (in1 ... inN) (#s(pk1 (P11 ... P1N) e1) ... #s(pk1 (PM1 ... PMN) eM)))
    494 ;; represents the matching matrix
    495 ;;   [_in1_..._inN_|____]
    496 ;;   [ P11 ... P1N | e1 ]
    497 ;;   [  :       :  |  : ]
    498 ;;   [ PM1 ... PMN | eM ]
    499 
    500 (define-syntax (parse:matrix stx)
    501   (syntax-case stx ()
    502     [(parse:matrix ins (pk ...))
    503      #'(try (parse:pk ins pk) ...)]))
    504 
    505 (define-syntax (parse:pk stx)
    506   (syntax-case stx ()
    507     [(parse:pk () #s(pk1 () k))
    508      #'k]
    509     [(parse:pk ((x cx pr es) . ins) #s(pk1 (pat1 . pats) k))
    510      #'(parse:S x cx pat1 pr es (parse:pk ins #s(pk1 pats k)))]
    511     [(parse:pk ((x cx pr es) . ins) #s(pk/same pat1 inner))
    512      #'(parse:S x cx pat1 pr es (parse:matrix ins inner))]
    513     [(parse:pk ((x cx pr es) . ins) #s(pk/pair inner))
    514      #'(let-values ([(datum tcx)
    515                      (if (syntax? x)
    516                          (values (syntax-e x) x)
    517                          (values x cx))])
    518          (if (pair? datum)
    519              (let ([hx (car datum)]
    520                    [hcx (car datum)]
    521                    [hpr (ps-add-car pr)]
    522                    [tx (cdr datum)]
    523                    [tpr (ps-add-cdr pr)])
    524                (parse:matrix ((hx hcx hpr es) (tx tcx tpr es) . ins) inner))
    525              (let ([es* (if (null? datum) (es-add-proper-pair (first-desc:matrix inner) es) es)])
    526                (fail (failure* pr es*)))))]
    527     [(parse:pk (in1 . ins) #s(pk/and inner))
    528      #'(parse:matrix (in1 in1 . ins) inner)]))
    529 
    530 (define-syntax (first-desc:matrix stx)
    531   (syntax-case stx ()
    532     [(fdm (#s(pk1 (pat1 . pats) k)))
    533      #'(first-desc:S pat1)]
    534     [(fdm (#s(pk/same pat1 pks)))
    535      #'(first-desc:S pat1)]
    536     [(fdm (pk ...)) ;; FIXME
    537      #'#f]))
    538 
    539 ;; ----
    540 
    541 ;; (parse:S x cx S-pattern pr es k) : expr[Ans]
    542 ;; In k: attrs(S-pattern) are bound.
    543 (define-syntax (parse:S stx)
    544   (syntax-case stx ()
    545     [(parse:S x cx pattern0 pr es k)
    546      (syntax-case #'pattern0 ()
    547        [#s(pat:seq-end)
    548         #`(k x cx pr)]
    549        [#s(pat:any)
    550         #'k]
    551        [#s(pat:svar name)
    552         #'(let-attributes ([#s(attr name 0 #t) (datum->syntax cx x cx)])
    553             k)]
    554        [#s(pat:var/p name parser argu (nested-a ...) role
    555                      #s(scopts attr-count commit? _delimit? _desc))
    556         (with-syntax ([(av ...) (generate-n-temporaries (syntax-e #'attr-count))]
    557                       [(name-attr ...)
    558                        (if (identifier? #'name)
    559                            #'([#s(attr name 0 #t) (datum->syntax cx x cx)])
    560                            #'())])
    561           (if (not (syntax-e #'commit?))
    562               ;; The normal protocol
    563               #'(app-argu parser x cx pr es undo-stack fail-handler cut-prompt role
    564                           (lambda (fh undos av ...)
    565                             (let-attributes (name-attr ...)
    566                               (let-attributes* ((nested-a ...) (av ...))
    567                                 (with ([fail-handler fh] [undo-stack undos])
    568                                   k))))
    569                           argu)
    570               ;; The commit protocol
    571               ;; (Avoids putting k in procedure)
    572               #'(let-values ([(fs undos av ...)
    573                               (with ([fail-handler
    574                                       (lambda (undos fs)
    575                                         (unwind-to undos undo-stack)
    576                                         (values fs undo-stack (let ([av #f]) av) ...))])
    577                                 (with ([cut-prompt fail-handler])
    578                                   (app-argu parser x cx pr es undo-stack
    579                                             fail-handler cut-prompt role
    580                                             (lambda (fh undos av ...) (values #f undos av ...))
    581                                             argu)))])
    582                   (if fs
    583                       (fail fs)
    584                       (let-attributes (name-attr ...)
    585                         (let-attributes* ((nested-a ...) (av ...))
    586                           (with ([undo-stack undos])
    587                             k)))))))]
    588        [#s(pat:reflect obj argu attr-decls name (nested-a ...))
    589         (with-syntax ([(name-attr ...)
    590                        (if (identifier? #'name)
    591                            #'([#s(attr name 0 #t) (datum->syntax cx x cx)])
    592                            #'())])
    593           (with-syntax ([arity (arguments->arity (syntax->datum #'argu))])
    594             #'(let ([parser (reflect-parser obj 'arity 'attr-decls #f)])
    595                 (app-argu parser x cx pr es undo-stack fail-handler cut-prompt #f
    596                           (lambda (fh undos . result)
    597                             (let-attributes (name-attr ...)
    598                               (let/unpack ((nested-a ...) result)
    599                                 (with ([fail-handler fh] [undo-stack undos])
    600                                   k))))
    601                           argu))))]
    602        [#s(pat:datum datum)
    603         (with-syntax ([unwrap-x
    604                        (if (atomic-datum-stx? #'datum)
    605                            #'(if (syntax? x) (syntax-e x) x)
    606                            #'(syntax->datum (datum->syntax #f x)))])
    607           #`(let ([d unwrap-x])
    608               (if (equal? d (quote datum))
    609                   k
    610                   (fail (failure* pr (es-add-atom 'datum es))))))]
    611        [#s(pat:literal literal input-phase lit-phase)
    612         #`(if (and (identifier? x)
    613                    (free-identifier=? x (quote-syntax literal) input-phase lit-phase))
    614               (with ([undo-stack (cons (current-state) undo-stack)])
    615                 (state-cons! 'literals x)
    616                 k)
    617               (fail (failure* pr (es-add-literal (quote-syntax literal) es))))]
    618        [#s(pat:action action subpattern)
    619         #'(parse:A x cx action pr es (parse:S x cx subpattern pr es k))]
    620        [#s(pat:head head tail)
    621         #`(parse:H x cx rest-x rest-cx rest-pr head pr es
    622                    (parse:S rest-x rest-cx tail rest-pr es k))]
    623        [#s(pat:dots head tail)
    624         #`(parse:dots x cx head tail pr es k)]
    625        [#s(pat:and subpatterns)
    626         (for/fold ([k #'k]) ([subpattern (in-list (reverse (syntax->list #'subpatterns)))])
    627           #`(parse:S x cx #,subpattern pr es #,k))]
    628        [#s(pat:or (a ...) (subpattern ...) (subattrs ...))
    629         (with-syntax ([(#s(attr id _ _) ...) #'(a ...)])
    630           #`(let ([success
    631                    (lambda (fh undos id ...)
    632                      (let-attributes ([a id] ...)
    633                        (with ([fail-handler fh] [undo-stack undos])
    634                          k)))])
    635               (try (parse:S x cx subpattern pr es
    636                             (disjunct subattrs success () (id ...)))
    637                    ...)))]
    638        [#s(pat:not subpattern)
    639         #`(let* ([fh0 fail-handler]
    640                  [pr0 pr]
    641                  [es0 es]
    642                  [fail-to-succeed
    643                   (lambda (undos fs) (unwind-to undos undo-stack) k)])
    644             ;; ~not implicitly prompts to be safe,
    645             ;; but ~! not allowed within ~not (unless within ~delimit-cut, etc)
    646             ;; (statically checked!)
    647             (with ([fail-handler fail-to-succeed]
    648                    [cut-prompt fail-to-succeed]) ;; to be safe
    649               (parse:S x cx subpattern pr es
    650                        (fh0 undo-stack (failure* pr0 es0)))))]
    651        [#s(pat:pair head tail)
    652         #`(let ([datum (if (syntax? x) (syntax-e x) x)]
    653                 [cx (if (syntax? x) x cx)])  ;; FIXME: shadowing cx?!
    654             (if (pair? datum)
    655                 (let ([hx (car datum)]
    656                       [hcx (car datum)]
    657                       [hpr (ps-add-car pr)]
    658                       [tx (cdr datum)]
    659                       [tpr (ps-add-cdr pr)])
    660                   (parse:S hx hcx head hpr es
    661                            (parse:S tx cx tail tpr es k)))
    662                 (let ([es* (if (null? datum) (es-add-proper-pair (first-desc:S head) es) es)])
    663                   (fail (failure* pr es*)))))]
    664        [#s(pat:vector subpattern)
    665         #`(let ([datum (if (syntax? x) (syntax-e x) x)])
    666             (if (vector? datum)
    667                 (let ([datum (vector->list datum)]
    668                       [vcx (if (syntax? x) x cx)] ;; FIXME: (vector? datum) => (syntax? x) ???
    669                       [pr* (ps-add-unvector pr)])
    670                   (parse:S datum vcx subpattern pr* es k))
    671                 (fail (failure* pr es))))]
    672        [#s(pat:box subpattern)
    673         #`(let ([datum (if (syntax? x) (syntax-e x) x)])
    674             (if (box? datum)
    675                 (let ([datum (unbox datum)]
    676                       [bcx (if (syntax? x) x cx)] ;; FIXME: (box? datum) => (syntax? x) ???
    677                       [pr* (ps-add-unbox pr)])
    678                   (parse:S datum bcx subpattern pr* es k))
    679                 (fail (failure* pr es))))]
    680        [#s(pat:pstruct key subpattern)
    681         #`(let ([datum (if (syntax? x) (syntax-e x) x)])
    682             (if (let ([xkey (prefab-struct-key datum)])
    683                   (and xkey (equal? xkey 'key)))
    684                 (let ([datum (cdr (vector->list (struct->vector datum)))]
    685                       [scx (if (syntax? x) x cx)] ;; FIXME: (struct? datum) => (syntax? x) ???
    686                       [pr* (ps-add-unpstruct pr)])
    687                   (parse:S datum scx subpattern pr* es k))
    688                 (fail (failure* pr es))))]
    689        [#s(pat:describe pattern description transparent? role)
    690         #`(let ([es* (es-add-thing pr description transparent? role es)]
    691                 [pr* (if 'transparent? pr (ps-add-opaque pr))])
    692             (parse:S x cx pattern pr* es* k))]
    693        [#s(pat:delimit pattern)
    694         #`(let ([cp0 cut-prompt])
    695             (with ([cut-prompt fail-handler])
    696               (parse:S x cx pattern pr es (with ([cut-prompt cp0]) k))))]
    697        [#s(pat:commit pattern)
    698         #`(let ([fh0 fail-handler]
    699                 [cp0 cut-prompt])
    700             (with ([cut-prompt fh0])
    701               (parse:S x cx pattern pr es
    702                        (with ([cut-prompt cp0]
    703                               [fail-handler fh0])
    704                              k))))]
    705        [#s(pat:ord pattern group index)
    706         #`(let ([pr* (ps-add pr '#s(ord group index))])
    707             (parse:S x cx pattern pr* es k))]
    708        [#s(pat:post pattern)
    709         #`(let ([pr* (ps-add-post pr)])
    710             (parse:S x cx pattern pr* es k))]
    711        [#s(pat:integrated name predicate description role)
    712         (with-syntax ([(name-attr ...)
    713                        (if (identifier? #'name)
    714                            #'([#s(attr name 0 #t) x*])
    715                            #'())])
    716           #'(let ([x* (datum->syntax cx x cx)])
    717               (if (predicate x*)
    718                   (let-attributes (name-attr ...) k)
    719                   (let ([es* (es-add-thing pr 'description #t role es)])
    720                     (fail (failure* pr es*))))))]
    721        [_ (wrong-syntax stx "internal error: bad S pattern: ~e" #'pattern0)])]))
    722 
    723 ;; (first-desc:S S-pattern) : expr[FirstDesc]
    724 (define-syntax (first-desc:S stx)
    725   (syntax-case stx ()
    726     [(fds p)
    727      (syntax-case #'p ()
    728        [#s(pat:any)
    729         #''(any)]
    730        [#s(pat:svar name)
    731         #''(any)]
    732        [#s(pat:var/p _ _ _ _ _ #s(scopts _ _ _ desc))
    733         #'(quote desc)]
    734        [#s(pat:datum d)
    735         #''(datum d)]
    736        [#s(pat:literal id _ip _lp)
    737         #''(literal id)]
    738        [#s(pat:describe _p desc _t? _role)
    739         #`(quote #,(or (constant-desc #'desc) #'#f))]
    740        [#s(pat:delimit pattern)
    741         #'(first-desc:S pattern)]
    742        [#s(pat:commit pattern)
    743         #'(first-desc:S pattern)]
    744        [#s(pat:ord pattern _ _)
    745         #'(first-desc:S pattern)]
    746        [#s(pat:post pattern)
    747         #'(first-desc:S pattern)]
    748        [#s(pat:integrated _name _pred description _role)
    749         #''description]
    750        [_ #'#f])]))
    751 
    752 ;; (first-desc:H HeadPattern) : Expr
    753 (define-syntax (first-desc:H stx)
    754   (syntax-case stx ()
    755     [(fdh hpat)
    756      (syntax-case #'hpat ()
    757        [#s(hpat:single sp) #'(first-desc:S sp)]
    758        [#s(hpat:var/p _ _ _ _ _ #s(scopts _ _ _ desc)) #'(quote desc)]
    759        [#s(hpat:seq lp) #'(first-desc:L lp)]
    760        [#s(hpat:describe _hp desc _t? _r)
    761         #`(quote #,(or (constant-desc #'desc) #'#f))]
    762        [#s(hpat:delimit hp) #'(first-desc:H hp)]
    763        [#s(hpat:commit hp) #'(first-desc:H hp)]
    764        [#s(hpat:ord hp _ _) #'(first-desc:H hp)]
    765        [#s(hpat:post hp) #'(first-desc:H hp)]
    766        [_ #'#f])]))
    767 
    768 (define-syntax (first-desc:L stx)
    769   (syntax-case stx ()
    770     [(fdl lpat)
    771      (syntax-case #'lpat ()
    772        [#s(pat:pair sp lp) #'(first-desc:S sp)]
    773        [_ #'#f])]))
    774 
    775 ;; (disjunct (iattr ...) success (pre:expr ...) (id:id ...)) : expr[Ans]
    776 (define-syntax (disjunct stx)
    777   (syntax-case stx ()
    778     [(disjunct (#s(attr sub-id _ _) ...) success (pre ...) (id ...))
    779      (with-syntax ([(alt-sub-id ...) (generate-temporaries #'(sub-id ...))])
    780        #`(let ([alt-sub-id (attribute sub-id)] ...)
    781            (let ([id #f] ...)
    782              (let ([sub-id alt-sub-id] ...)
    783                (success fail-handler undo-stack pre ... id ...)))))]))
    784 
    785 ;; (parse:A x cx A-pattern pr es k) : expr[Ans]
    786 ;; In k: attrs(A-pattern) are bound.
    787 (define-syntax (parse:A stx)
    788   (syntax-case stx ()
    789     [(parse:A x cx pattern0 pr es k)
    790      (syntax-case #'pattern0 ()
    791        [#s(action:and (action ...))
    792         (for/fold ([k #'k]) ([action (in-list (reverse (syntax->list #'(action ...))))])
    793           #`(parse:A x cx #,action pr es #,k))]
    794        [#s(action:cut)
    795         #'(with ([fail-handler cut-prompt]) k)]
    796        [#s(action:bind a expr)
    797         #'(let-attributes ([a (wrap-user-code expr)]) k)]
    798        [#s(action:fail condition message)
    799         #`(let ([c (wrap-user-code condition)])
    800             (if c
    801                 (let ([pr* (if (syntax? c) (ps-add-stx pr c) pr)]
    802                       [es* (es-add-message message es)])
    803                   (fail (failure* pr* es*)))
    804                 k))]
    805        [#s(action:parse pattern expr)
    806         #`(let* ([y (datum->syntax/with-clause (wrap-user-code expr))]
    807                  [cy y]
    808                  [pr* (ps-add-stx pr y)])
    809             (parse:S y cy pattern pr* es k))]
    810        [#s(action:do (stmt ...))
    811         #'(parameterize ((current-state-writable? #t))
    812             (let ([init-state (current-state)])
    813               (no-shadow stmt) ...
    814               (parameterize ((current-state-writable? #f))
    815                 (with ([undo-stack (maybe-add-state-undo init-state (current-state) undo-stack)])
    816                   (#%expression k)))))]
    817        [#s(action:undo (stmt ...))
    818         #'(with ([undo-stack (cons (lambda () stmt ... (void)) undo-stack)]
    819                  [cut-prompt illegal-cut-error])
    820             k)]
    821        [#s(action:ord pattern group index)
    822         #'(let ([pr* (ps-add pr '#s(ord group index))])
    823             (parse:A x cx pattern pr* es k))]
    824        [#s(action:post pattern)
    825         #'(let ([pr* (ps-add-post pr)])
    826             (parse:A x cx pattern pr* es k))]
    827        [_ (wrong-syntax stx "internal error: bad A pattern: ~e" #'pattern0)])]))
    828 
    829 ;; (parse:H x cx rest-x rest-cx rest-pr H-pattern pr es k)
    830 ;; In k: rest, rest-pr, attrs(H-pattern) are bound.
    831 (define-syntax (parse:H stx)
    832   (syntax-case stx ()
    833     [(parse:H x cx rest-x rest-cx rest-pr head pr es k)
    834      (syntax-case #'head ()
    835        [#s(hpat:single pattern)
    836         #'(parse:S x cx
    837                    ;; FIXME: consider proper-list-pattern? (yes is consistent with ~seq)
    838                    #s(pat:pair pattern #s(pat:seq-end))
    839                    pr es (lambda (rest-x rest-cx rest-pr) k))]
    840        [#s(hpat:describe pattern description transparent? role)
    841         #`(let ([es* (es-add-thing pr description transparent? role es)]
    842                 [pr* (if 'transparent? pr (ps-add-opaque pr))])
    843             (parse:H x cx rest-x rest-cx rest-pr pattern pr* es*
    844                      (let ([rest-pr (if 'transparent? rest-pr (ps-pop-opaque rest-pr))])
    845                        k)))]
    846        [#s(hpat:var/p name parser argu (nested-a ...) role
    847                       #s(scopts attr-count commit? _delimit? _desc))
    848         (with-syntax ([(av ...) (generate-n-temporaries (syntax-e #'attr-count))]
    849                       [(name-attr ...)
    850                        (if (identifier? #'name)
    851                            #'([#s(attr name 0 #t)
    852                                (stx-list-take x (ps-difference pr rest-pr))])
    853                            #'())])
    854           (if (not (syntax-e #'commit?))
    855               ;; The normal protocol
    856               #`(app-argu parser x cx pr es undo-stack fail-handler cut-prompt role
    857                           (lambda (fh undos rest-x rest-cx rest-pr av ...)
    858                             (let-attributes (name-attr ...)
    859                               (let-attributes* ((nested-a ...) (av ...))
    860                                 (with ([fail-handler fh] [undo-stack undos])
    861                                   k))))
    862                           argu)
    863               ;; The commit protocol
    864               ;; (Avoids putting k in procedure)
    865               #'(let-values ([(fs undos rest-x rest-cx rest-pr av ...)
    866                               (with ([fail-handler
    867                                       (lambda (undos fs)
    868                                         (unwind-to undos undo-stack)
    869                                         (values fs undo-stack #f #f #f (let ([av #f]) av) ...))])
    870                                 (with ([cut-prompt fail-handler])
    871                                   (app-argu parser x cx pr es undo-stack
    872                                             fail-handler cut-prompt role
    873                                             (lambda (fh undos rest-x rest-cx rest-pr av ...)
    874                                               (values #f undos rest-x rest-cx rest-pr av ...))
    875                                             argu)))])
    876                   (if fs
    877                       (fail fs)
    878                       (let-attributes (name-attr ...)
    879                         (let-attributes* ((nested-a ...) (av ...))
    880                           (with ([undo-stack undos])
    881                             k)))))))]
    882        [#s(hpat:reflect obj argu attr-decls name (nested-a ...))
    883         (with-syntax ([(name-attr ...)
    884                        (if (identifier? #'name)
    885                            #'([#s(attr name 0 #t)
    886                                (stx-list-take x (ps-difference pr rest-pr))])
    887                            #'())])
    888           (with-syntax ([arity (arguments->arity (syntax->datum #'argu))])
    889             #'(let ([parser (reflect-parser obj 'arity 'attr-decls #t)])
    890                 (app-argu parser x cx pr es undo-stack fail-handler cut-prompt #f
    891                           (lambda (fh undos rest-x rest-cx rest-pr . result)
    892                             (let-attributes (name-attr ...)
    893                               (let/unpack ((nested-a ...) result)
    894                                  (with ([fail-handler fh] [undo-stack undos])
    895                                    k))))
    896                           argu))))]
    897        [#s(hpat:and head single)
    898         #`(let ([cx0 cx])
    899             (parse:H x cx rest-x rest-cx rest-pr head pr es
    900                      (let ([lst (stx-list-take x (ps-difference pr rest-pr))])
    901                        (parse:S lst cx0 single pr es k))))]
    902        [#s(hpat:or (a ...) (subpattern ...) (subattrs ...))
    903         (with-syntax ([(#s(attr id _ _) ...) #'(a ...)])
    904           #`(let ([success
    905                    (lambda (fh undos rest-x rest-cx rest-pr id ...)
    906                      (let-attributes ([a id] ...)
    907                        (with ([fail-handler fh] [undo-stack undos])
    908                          k)))])
    909               (try (parse:H x cx rest-x rest-cx rest-pr subpattern pr es
    910                             (disjunct subattrs success (rest-x rest-cx rest-pr) (id ...)))
    911                    ...)))]
    912        [#s(hpat:seq pattern)
    913         #'(parse:S x cx pattern pr es (lambda (rest-x rest-cx rest-pr) k))]
    914        [#s(hpat:action action subpattern)
    915         #'(parse:A x cx action pr es (parse:H x cx rest-x rest-cx rest-pr subpattern pr es k))]
    916        [#s(hpat:delimit pattern)
    917         #'(let ([cp0 cut-prompt])
    918             (with ([cut-prompt fail-handler])
    919               (parse:H x cx rest-x rest-cx rest-pr pattern pr es
    920                        (with ([cut-prompt cp0]) k))))]
    921        [#s(hpat:commit pattern)
    922         #`(let ([fh0 fail-handler]
    923                 [cp0 cut-prompt])
    924             (with ([cut-prompt fh0])
    925               (parse:H x cx rest-x rest-cx rest-pr pattern pr es
    926                        (with ([cut-prompt cp0]
    927                               [fail-handler fh0])
    928                              k))))]
    929        [#s(hpat:ord pattern group index)
    930         #`(let ([pr* (ps-add pr '#s(ord group index))])
    931             (parse:H x cx rest-x rest-cx rest-pr pattern pr* es
    932                      (let ([rest-pr (ps-pop-ord rest-pr)]) k)))]
    933        [#s(hpat:post pattern)
    934         #'(let ([pr* (ps-add-post pr)])
    935             (parse:H x cx rest-x rest-cx rest-pr pattern pr* es
    936                      (let ([rest-pr (ps-pop-post rest-pr)]) k)))]
    937        [#s(hpat:peek pattern)
    938         #`(let ([saved-x x] [saved-cx cx] [saved-pr pr])
    939             (parse:H x cx dummy-x dummy-cx dummy-pr pattern pr es
    940                      (let ([rest-x saved-x] [rest-cx saved-cx] [rest-pr saved-pr])
    941                        k)))]
    942        [#s(hpat:peek-not subpattern)
    943         #`(let* ([fh0 fail-handler]
    944                  [pr0 pr]
    945                  [es0 es]
    946                  [fail-to-succeed
    947                   (lambda (undos fs)
    948                     (unwind-to undos undo-stack)
    949                     (let ([rest-x x]
    950                           [rest-cx cx]
    951                           [rest-pr pr])
    952                       k))])
    953             ;; ~not implicitly prompts to be safe,
    954             ;; but ~! not allowed within ~not (unless within ~delimit-cut, etc)
    955             ;; (statically checked!)
    956             (with ([fail-handler fail-to-succeed]
    957                    [cut-prompt fail-to-succeed]) ;; to be safe
    958               (parse:H x cx rest-x rest-cx rest-pr subpattern pr es
    959                        (fh0 undo-stack (failure* pr0 es0)))))]
    960        [_ (wrong-syntax stx "internal error: bad H pattern: ~e" #'head)])]))
    961 
    962 ;; (parse:dots x cx EH-pattern S-pattern pr es k) : expr[Ans]
    963 ;; In k: attrs(EH-pattern, S-pattern) are bound.
    964 (define-syntax (parse:dots stx)
    965   (syntax-case stx ()
    966     ;; == Specialized cases
    967     ;; -- (x ... . ())
    968     [(parse:dots x cx (#s(ehpat (attr0) #s(hpat:single #s(pat:svar name)) #f #f))
    969                  #s(pat:datum ()) pr es k)
    970      #'(let-values ([(status result) (predicate-ellipsis-parser x cx pr es void #f #f)])
    971          (case status
    972            ((ok) (let-attributes ([attr0 result]) k))
    973            (else (fail result))))]
    974     ;; -- (x:sc ... . ()) where sc is an integrable stxclass like id or expr
    975     [(parse:dots x cx (#s(ehpat (attr0) #s(hpat:single #s(pat:integrated _name pred? desc role)) #f #f))
    976                  #s(pat:datum ()) pr es k)
    977      #'(let-values ([(status result) (predicate-ellipsis-parser x cx pr es pred? desc role)])
    978          (case status
    979            ((ok) (let-attributes ([attr0 result]) k))
    980            (else (fail result))))]
    981     ;; -- (x:sc ... . ()) where sc is a stxclass with commit
    982     ;; Since head pattern does commit, no need to thread fail-handler, cut-prompt through.
    983     ;; Microbenchmark suggests this isn't a useful specialization
    984     ;; (probably try-or-pair/null-check already does the useful part)
    985     ;; == General case
    986     [(parse:dots x cx (#s(ehpat head-attrs head head-repc check-null?) ...) tail pr es k)
    987      (let ()
    988        (define repcs (wash-list wash #'(head-repc ...)))
    989        (define rep-ids (for/list ([repc (in-list repcs)])
    990                          (and repc (generate-temporary 'rep))))
    991        (define rel-repcs (filter values repcs))
    992        (define rel-rep-ids (filter values rep-ids))
    993        (define rel-heads (for/list ([head (in-list (syntax->list #'(head ...)))]
    994                                     [repc (in-list repcs)]
    995                                     #:when repc)
    996                            head))
    997        (define aattrs
    998          (for/list ([head-attrs (in-list (syntax->list #'(head-attrs ...)))]
    999                     [repc (in-list repcs)]
   1000                     #:when #t
   1001                     [a (in-list (wash-iattrs head-attrs))])
   1002            (cons a repc)))
   1003        (define attrs (map car aattrs))
   1004        (define attr-repcs (map cdr aattrs))
   1005        (define ids (map attr-name attrs))
   1006        (define tail-pattern-is-null? (equal? (syntax->datum #'tail) '#s(pat:datum ())))
   1007        (with-syntax ([(id ...) ids]
   1008                      [(alt-id ...) (generate-temporaries ids)]
   1009                      [reps rel-rep-ids]
   1010                      [(head-rep ...) rep-ids]
   1011                      [(rel-rep ...) rel-rep-ids]
   1012                      [(rel-repc ...) rel-repcs]
   1013                      [(rel-head ...) rel-heads]
   1014                      [(a ...) attrs]
   1015                      [(attr-repc ...) attr-repcs]
   1016                      [do-pair/null?
   1017                       ;; FIXME: do pair/null check only if no nullable head patterns
   1018                       ;; (and tail-pattern-is-null? (andmap not (syntax->datum #'(nullable? ...))))
   1019                       tail-pattern-is-null?])
   1020          (define/with-syntax alt-map #'((id . alt-id) ...))
   1021          (define/with-syntax loop-k
   1022            #'(dots-loop dx* dcx* loop-pr* undo-stack fail-handler rel-rep ... alt-id ...))
   1023          #`(let ()
   1024              ;; dots-loop : stx progress rel-rep ... alt-id ... -> Ans
   1025              (define (dots-loop dx dcx loop-pr undos fh rel-rep ... alt-id ...)
   1026                (with ([fail-handler fh] [undo-stack undos])
   1027                  (try-or-pair/null-check do-pair/null? dx dcx loop-pr es
   1028                    (try (parse:EH dx dcx loop-pr head-attrs check-null? head-repc dx* dcx* loop-pr* 
   1029                                   alt-map head-rep head es loop-k)
   1030                         ...)
   1031                    (cond [(< rel-rep (rep:min-number rel-repc))
   1032                           (let ([es (expectation-of-reps/too-few es rel-rep rel-repc rel-head)])
   1033                             (fail (failure* loop-pr es)))]
   1034                          ...
   1035                          [else
   1036                           (let-attributes ([a (rep:finalize a attr-repc alt-id)] ...)
   1037                             (parse:S dx dcx tail loop-pr es k))]))))
   1038              (let ([rel-rep 0] ...
   1039                    [alt-id (rep:initial-value attr-repc)] ...)
   1040                (dots-loop x cx pr undo-stack fail-handler rel-rep ... alt-id ...)))))]))
   1041 
   1042 ;; (try-or-pair/null-check bool x cx es pr pair-alt maybe-null-alt)
   1043 (define-syntax try-or-pair/null-check
   1044   (syntax-rules ()
   1045     [(topc #t x cx pr es pair-alt null-alt)
   1046      (cond [(stx-pair? x) pair-alt]
   1047            [(stx-null? x) null-alt]
   1048            [else (fail (failure* pr es))])]
   1049     [(topc _ x cx pr es alt1 alt2)
   1050      (try alt1 alt2)]))
   1051 
   1052 ;; (parse:EH x cx pr repc x* cx* pr* alts rep H-pattern es k) : expr[Ans]
   1053 ;; In k: x*, cx*, pr*, alts`attrs(H-pattern) are bound and rep is shadowed.
   1054 (define-syntax (parse:EH stx)
   1055   (syntax-case stx ()
   1056     [(parse:EH x cx pr attrs check-null? repc x* cx* pr* alts rep head es k)
   1057      (let ()
   1058        (define/with-syntax k*
   1059          (let* ([main-attrs (wash-iattrs #'attrs)]
   1060                 [ids (map attr-name main-attrs)]
   1061                 [alt-ids
   1062                  (let ([table (make-bound-id-table)])
   1063                    (for ([entry (in-list (syntax->list #'alts))])
   1064                      (let ([entry (syntax-e entry)])
   1065                        (bound-id-table-set! table (car entry) (cdr entry))))
   1066                    (for/list ([id (in-list ids)]) (bound-id-table-ref table id)))])
   1067            (with-syntax ([(id ...) ids]
   1068                          [(alt-id ...) alt-ids])
   1069              #`(let ([alt-id (rep:combine repc (attribute id) alt-id)] ...)
   1070                  #,(if (syntax->datum #'check-null?)
   1071                        #'(if (zero? (ps-difference pr pr*)) (error/null-eh-match) k)
   1072                        #'k)))))
   1073        (syntax-case #'repc ()
   1074          [#f #`(parse:H x cx x* cx* pr* head pr es k*)]
   1075          [_  #`(parse:H x cx x* cx* pr* head pr es
   1076                         (if (< rep (rep:max-number repc))
   1077                             (let ([rep (add1 rep)]) k*)
   1078                             (let ([es* (expectation-of-reps/too-many es rep repc)])
   1079                               (fail (failure* pr* es*)))))]))]))
   1080 
   1081 ;; (rep:initial-value RepConstraint) : expr
   1082 (define-syntax (rep:initial-value stx)
   1083   (syntax-case stx ()
   1084     [(_ #s(rep:once _ _ _)) #'#f]
   1085     [(_ #s(rep:optional _ _ _)) #'#f]
   1086     [(_ _) #'null]))
   1087 
   1088 ;; (rep:finalize RepConstraint expr) : expr
   1089 (define-syntax (rep:finalize stx)
   1090   (syntax-case stx ()
   1091     [(_ a #s(rep:optional _ _ defaults) v)
   1092      (with-syntax ([#s(attr name _ _) #'a]
   1093                    [(#s(action:bind da de) ...) #'defaults])
   1094        (let ([default
   1095               (for/or ([da (in-list (syntax->list #'(da ...)))]
   1096                        [de (in-list (syntax->list #'(de ...)))])
   1097                 (with-syntax ([#s(attr dname _ _) da])
   1098                   (and (bound-identifier=? #'name #'dname) de)))])
   1099          (if default
   1100              #`(or v #,default)
   1101              #'v)))]
   1102     [(_ a #s(rep:once _ _ _) v) #'v]
   1103     [(_ a _ v) #'(reverse v)]))
   1104 
   1105 ;; (rep:min-number RepConstraint) : expr
   1106 (define-syntax (rep:min-number stx)
   1107   (syntax-case stx ()
   1108     [(_ #s(rep:once _ _ _)) #'1]
   1109     [(_ #s(rep:optional _ _ _)) #'0]
   1110     [(_ #s(rep:bounds min max _ _ _)) #'min]))
   1111 
   1112 ;; (rep:max-number RepConstraint) : expr
   1113 (define-syntax (rep:max-number stx)
   1114   (syntax-case stx ()
   1115     [(_ #s(rep:once _ _ _)) #'1]
   1116     [(_ #s(rep:optional _ _ _)) #'1]
   1117     [(_ #s(rep:bounds min max _ _ _)) #'max]))
   1118 
   1119 ;; (rep:combine RepConstraint expr expr) : expr
   1120 (define-syntax (rep:combine stx)
   1121   (syntax-case stx ()
   1122     [(_ #s(rep:once _ _ _) a b) #'a]
   1123     [(_ #s(rep:optional _ _ _) a b) #'a]
   1124     [(_ _ a b) #'(cons a b)]))
   1125 
   1126 ;; ----
   1127 
   1128 (define-syntax expectation-of-reps/too-few
   1129   (syntax-rules ()
   1130     [(_ es rep #s(rep:once name too-few-msg too-many-msg) hpat)
   1131      (cond [(or too-few-msg (name->too-few/once name))
   1132             => (lambda (msg) (es-add-message msg es))]
   1133            [(first-desc:H hpat) => (lambda (fd) (es-add-proper-pair fd es))]
   1134            [else es])]
   1135     [(_ es rep #s(rep:optional name too-many-msg _) hpat)
   1136      (error 'syntax-parse "INTERNAL ERROR: impossible (too-few)")]
   1137     [(_ es rep #s(rep:bounds min max name too-few-msg too-many-msg) hpat)
   1138      (cond [(or too-few-msg (name->too-few name))
   1139             => (lambda (msg) (es-add-message msg es))]
   1140            [(first-desc:H hpat) => (lambda (fd) (es-add-proper-pair fd es))]
   1141            [else es])]))
   1142 
   1143 (define-syntax expectation-of-reps/too-many
   1144   (syntax-rules ()
   1145     [(_ es rep #s(rep:once name too-few-msg too-many-msg))
   1146      (es-add-message (or too-many-msg (name->too-many name)) es)]
   1147     [(_ es rep #s(rep:optional name too-many-msg _))
   1148      (es-add-message (or too-many-msg (name->too-many name)) es)]
   1149     [(_ es rep #s(rep:bounds min max name too-few-msg too-many-msg))
   1150      (es-add-message (or too-many-msg (name->too-many name)) es)]))
   1151 
   1152 ;; ====
   1153 
   1154 (define-syntax (define-eh-alternative-set stx)
   1155   (define (parse-alt x)
   1156     (syntax-case x (pattern)
   1157       [(pattern alt)
   1158        #'alt]
   1159       [else
   1160        (wrong-syntax x "expected eh-alternative-set alternative")]))
   1161   (parameterize ((current-syntax-context stx))
   1162     (syntax-case stx ()
   1163       [(_ name a ...)
   1164        (unless (identifier? #'name)
   1165          (wrong-syntax #'name "expected identifier"))
   1166        (let* ([alts (map parse-alt (syntax->list #'(a ...)))]
   1167               [decls (new-declenv null #:conventions null)]
   1168               [ehpat+hstx-list
   1169                (apply append
   1170                       (for/list ([alt (in-list alts)])
   1171                         (parse-EH-variant alt decls #t #:context stx)))]
   1172               [eh-alt+defs-list
   1173                (for/list ([ehpat+hstx (in-list ehpat+hstx-list)])
   1174                  (let ([ehpat (car ehpat+hstx)]
   1175                        [hstx (cadr ehpat+hstx)])
   1176                    (cond [(syntax? hstx)
   1177                           (define the-pattern (ehpat-head ehpat))
   1178                           (define attrs (iattrs->sattrs (pattern-attrs the-pattern)))
   1179                           (define the-variant (variant hstx attrs the-pattern null))
   1180                           (define the-rhs (rhs attrs #t #f (list the-variant) null #f #f))
   1181                           (with-syntax ([(parser) (generate-temporaries '(eh-alt-parser))]
   1182                                         [the-rhs-expr (datum->expression the-rhs)])
   1183                             (list (eh-alternative (ehpat-repc ehpat) attrs #'parser)
   1184                                   (list #`(define parser
   1185                                             (parser/rhs parser () #,attrs
   1186                                                         the-rhs-expr #t #,stx)))))]
   1187                          [(eh-alternative? hstx)
   1188                           (list hstx null)]
   1189                          [else
   1190                           (error 'define-eh-alternative-set "internal error: unexpected ~e"
   1191                                  hstx)])))]
   1192               [eh-alts (map car eh-alt+defs-list)]
   1193               [defs (apply append (map cadr eh-alt+defs-list))])
   1194          (with-syntax ([(def ...) defs]
   1195                        [(alt-expr ...)
   1196                         (for/list ([alt (in-list eh-alts)])
   1197                           (with-syntax ([repc-expr
   1198                                          (datum->expression (eh-alternative-repc alt))]
   1199                                         [attrs-expr
   1200                                          #`(quote #,(eh-alternative-attrs alt))]
   1201                                         [parser-expr
   1202                                          #`(quote-syntax #,(eh-alternative-parser alt))])
   1203                             #'(eh-alternative repc-expr attrs-expr parser-expr)))])
   1204            #'(begin def ...
   1205                     (define-syntax name
   1206                       (eh-alternative-set (list alt-expr ...))))))])))