diff --git a/collects/syntax/private/stxparse/rep.ss b/collects/syntax/private/stxparse/rep.ss index c95e42bede..77a3e58a8e 100644 --- a/collects/syntax/private/stxparse/rep.ss +++ b/collects/syntax/private/stxparse/rep.ss @@ -208,24 +208,23 @@ ;; parse-variant : stx boolean DeclEnv -> RHS (define (parse-variant stx splicing? decls0) - (parameterize ((current-syntax-context stx)) - (syntax-case stx (pattern) - [(pattern p . rest) - (let-values ([(rest decls defs clauses) - (parse-pattern-directives #'rest - #:allow-declare? #t - #:decls decls0)]) - (unless (stx-null? rest) - (wrong-syntax (if (pair? rest) (car rest) rest) - "unexpected terms after pattern directives")) - (let* ([pattern - (parse-whole-pattern #'p decls splicing?)] - [attrs - (append-iattrs - (cons (pattern-attrs pattern) - (side-clauses-attrss clauses)))] - [sattrs (iattrs->sattrs attrs)]) - (make variant stx sattrs pattern clauses defs)))]))) + (syntax-case stx (pattern) + [(pattern p . rest) + (let-values ([(rest decls defs clauses) + (parse-pattern-directives #'rest + #:allow-declare? #t + #:decls decls0)]) + (unless (stx-null? rest) + (wrong-syntax (if (pair? rest) (car rest) rest) + "unexpected terms after pattern directives")) + (let* ([pattern + (parse-whole-pattern #'p decls splicing?)] + [attrs + (append-iattrs + (cons (pattern-attrs pattern) + (side-clauses-attrss clauses)))] + [sattrs (iattrs->sattrs attrs)]) + (make variant stx sattrs pattern clauses defs)))])) (define (side-clauses-attrss clauses) (for/list ([c clauses] @@ -246,7 +245,7 @@ (define excess-domain (declenv-domain-difference decls pvars)) (when (pair? excess-domain) (wrong-syntax #f "declared pattern variables do not appear in pattern" - #:extras excess-domain)) + #:extra excess-domain)) pattern)) ;; ---- @@ -493,6 +492,8 @@ (begin (unless (stx-list? head) (wrong-syntax head "expected sequence of patterns")) + (unless (stx-pair? (stx-cdr head)) + (wrong-syntax head "expected at least one pattern")) (for/list ([sub (cdr (stx->list head))]) (parse-ellipsis-head-pattern sub decls)))] [_ @@ -618,11 +619,11 @@ (unless (exact-nonnegative-integer? minN) (wrong-syntax #'min "expected exact nonnegative integer")) - (unless (or (exact-nonnegative-integer? maxN) (= +inf.0 maxN)) + (unless (or (exact-nonnegative-integer? maxN) (equal? maxN +inf.0)) (wrong-syntax #'max "expected exact nonnegative integer or +inf.0")) (when (> minN maxN) - (wrong-syntax stx "minumum larger than maximum repetition constraint")) + (wrong-syntax stx "minimum larger than maximum repetition constraint")) (let ([chunks (parse-keyword-options #'options (list (list '#:too-few check-expression) (list '#:too-many check-expression) diff --git a/collects/tests/stxclass/more-tests.ss b/collects/tests/stxclass/more-tests.ss index 515fb304b5..5e54c361be 100644 --- a/collects/tests/stxclass/more-tests.ss +++ b/collects/tests/stxclass/more-tests.ss @@ -11,6 +11,14 @@ #`(error '#,(exn-message e)))]) (local-expand #'expr 'expression null))])) +(define-syntax-rule (tcerr name expr erx ...) + (test-case name + (check-exn (lambda (exn) + (define msg (exn-message exn)) + (check regexp-match? erx msg) ... + #t) + (lambda () (convert-syntax-error expr))))) + ;; Test #:auto-nested-attributes (define-syntax-class two @@ -40,13 +48,185 @@ #:declare x (static number? "identifier bound to number") #`(quote #,(attribute x.value))])) -(test-case "static: right error" - (check-exn (lambda (exn) - (regexp-match? #rx"identifier bound to number" - (exn-message exn))) - (lambda () (convert-syntax-error (m twelve))))) +(tcerr "static: right error" + (m twelve) + #rx"identifier bound to number") (test-case "static: works" (check-equal? (convert-syntax-error (m zero)) 0)) +;; Error message tests + +(tcerr "define-conventions non id" + (let () (define-conventions "foo") 0) + #rx"^define-conventions: " + #rx"expected identifier") + +(tcerr "define-literal-set non id" + (let () (define-literal-set "foo" (+ -)) 0) + #rx"^define-literal-set: " + #rx"expected identifier") + +(tcerr "parse-rhs: no variants" + (let () (define-syntax-class x) 0) + #rx"^define-syntax-class: " + #rx"expected at least one variant") + +(tcerr "parse-rhs (splicing): no variants" + (let () (define-splicing-syntax-class x) 0) + #rx"^define-splicing-syntax-class: " + #rx"expected at least one variant") + +(tcerr "parse-rhs: incompatible attrs flags" + (let () + (define-syntax-class foo + #:attributes (x) + #:auto-nested-attributes + (pattern x)) + 0) + #rx"^define-syntax-class: " + #rx"not allowed after") + +(tcerr "parse-variants: not a variant" + (let () (define-syntax-class x y) 0) + #rx"^define-syntax-class: " + #rx"expected syntax-class variant") + +(tcerr "check-literals-bound: unbound literal" + (let () (define-syntax-class x #:literals (foo) (pattern (foo))) 0) + #rx"^define-syntax-class: " + #rx"unbound identifier not allowed as literal") + + +(tcerr "append-lits+litsets: duplicate" + (let () + (define-literal-set lits1 (+)) + (define-syntax-class x + #:literals (+) + #:literal-sets (lits1) + (pattern foo)) + 0) + #rx"^define-syntax-class: " + #rx"duplicate literal declaration") + +(tcerr "parse-variant: too much" + (let () + (define-syntax-class x + (pattern y z))) + #rx"^define-syntax-class: " + #rx"unexpected terms") + +(tcerr "parse-whole-pattern: declared not used" + (syntax-parse #'1 + [x + #:declare y nat + 'ok]) + #rx"^syntax-parse: " + #rx"do not appear in pattern") + +(tcerr "parse-single-pattern: reserved" + (syntax-parse #'1 + [~and 'ok]) + #rx"^syntax-parse: " + #rx"not allowed here") + +(tcerr "parse-pat:id: splicing not allowed" + (let () + (define-splicing-syntax-class foo (pattern (~seq a b c))) + (syntax-parse #'1 + [x:foo 'ok])) + #rx"^syntax-parse: " + #rx"splicing syntax class not allowed here") + +(tcerr "parse-cdr-patterns: not list" + (syntax-parse #'1 + [(~and x . y) 'ok]) + #rx"^syntax-parse: " + #rx"expected sequence of patterns") + +(tcerr "parse-cdr-patterns: empty" + (syntax-parse #'1 + [(~and) 'ok]) + #rx"^syntax-parse: " + #rx"expected at least one pattern") + +(tcerr "parse-some-pattern: no heads" + (syntax-parse #'1 + [(~and (~seq 1 2)) 'ok]) + #rx"^syntax-parse: " + #rx"head pattern not allowed here") + +(tcerr "parse-pat:dots: or, not list" + (syntax-parser + [((~or . x) ...) 'ok]) + #rx"^syntax-parser: " + #rx"expected sequence of patterns") + +(tcerr "parse-pat:dots: or, empty" + (syntax-parser + [((~or) ...) 'ok]) + #rx"^syntax-parser: " + #rx"expected at least one pattern") + +(tcerr "parse-pat:fail: missing message" + (syntax-parser + [(~fail) 'ok]) + #rx"^syntax-parser: " + #rx"missing message expression") + +(tcerr "parse-pat:fail: bad" + (syntax-parser + [(~fail . x) 'ok]) + #rx"^syntax-parser: " + #rx"bad fail pattern") + +(tcerr "check-list-pattern" + (syntax-parser + [((~seq x . y)) 'ok]) + #rx"^syntax-parser: " + #rx"expected proper list pattern") + +(tcerr "parse-ehpat/bounds: min" + (syntax-parser + [((~bounds x 1.0 9) ...) 'ok]) + #rx"^syntax-parser: " + #rx"expected exact nonnegative integer") + +(tcerr "parse-ehpat/bounds: max" + (syntax-parser + [((~bounds x 1 "foo") ...) 'ok]) + #rx"^syntax-parser: " + #rx"expected exact nonnegative integer") + +(tcerr "parse-ehpat/bounds: min>max" + (syntax-parser + [((~bounds x 3 2) ...) 'ok]) + #rx"^syntax-parser: " + #rx"minimum larger than maximum") + +(tcerr "parse-pattern-sides: bad declare" + (syntax-parser + [x #:fail-unless #t #f #:declare x nat 'ok]) + #rx"^syntax-parser: " + #rx"#:declare can only follow") + +(tcerr "grab-decls: bad sc" + (syntax-parser + [x #:declare x 5 'ok]) + #rx"^syntax-parser: " + #rx"expected syntax class") + +;; checker procedures... bleh + +(tcerr "check-attr-arity-list" + (let () (define-syntax-class x #:attributes x (pattern x)) 'ok) + #rx"^define-syntax-class: " + #rx"expected list of attribute declarations") + +(tcerr "check-attr-arity" + (let () (define-syntax-class x #:attributes ("foo" 0) (pattern x)) 'ok) + #rx"^define-syntax-class: " + #rx"expected attribute name") +;; two more +