Match is fantastic, and sometimes you want finer control over the error 
messages. This morning I whipped up a "match/fail*" macro, which successively 
matches against a sequence of patterns, and allows you to specify a separate 
fail message for each "layer".

It's a simple macro, and I give a use of it  (my use of it) below, followed by 
its simple definition.

FWIW, I *love* how check syntax shows the binding arrows from the pattern 
variables to the uses, outside of the defining clause.  

Is there something like this already in an existing library? If not, would this 
be useful to anyone?

John

p.s.: the use of syntax-parse in the definition of the macro was awesome, and 
produced at least one really nice error message for me.


;; first-line-checker : string -> (or/c string symbol)
;; returns a string, indicating an error message, or 'success,
;; indicating success.
(provide first-line-checker)
(define (first-line-checker first-line)
  (match/fail* 'success
    [(tokenize-string first-line) `("public" ,rest ...) "This function 
signature must begin with the word \"public\"."]
    [rest `(,(? type-name? ty) ,rest ...) (format "After the word public, you 
need a type name.")]
    [ty "int" "This function's return type must be \"int\"."]
    [rest `(,pre ... "(" ,args ... ")" ,leftover ...) "A function header must 
contain a pair of parentheses around the argument list."]
    [leftover `() "There shouldn't be anything after the right-paren (\")\")."]
    [pre `(,name) (if (empty? pre)
                      "There must be a function name between the type of the 
function and the argument list."
                      "The function name (a single word) is the only thing that 
comes between the type of the function and the argument list.")]
    [name "getApproxAge" "The name of the function should be \"getApproxAge\"."]
    [args `(,arg1 ... "," ,arg2 ...) "You need a comma in the argument list to 
separate the two arguments."]
    [arg1 `(,arg1ty ,arg1name) "The first argument should consist of a type and 
a name (exactly two words)."]
    [arg1ty (? type-name? _) "The first part of the first argument must be a 
type."]
    [arg1ty "int" "The first argument should be of type \"int\"."]
    [arg1name "birthYear" "The name of the first argument should be 
\"birthYear\"."]
    [arg2 `(,arg2ty ,arg2name) "The second argument should consist of a type 
and a name."]
    [arg2ty (? type-name? _) "The first part of the second argument must be a 
type."]
    [arg2ty "int" "The second argument should be of type \"int\"."]
    [arg2name "birthYear" "The name of the second argument should be 
\"birthYear\"."]))

;; the match/fail macro.  
;; A use of match/fail contains a single 'success' value
;; followed by a bunch of fail clauses.  Each fail clause
;; matches a value against a pattern and signals the given
;; error if it fails.  If it succeeds, it goes on to the 
;; next clause.  Note that pattern variables bound in each
;; pattern may be used in the remaining clauses.
(define-syntax (match/fail* stx)
  (define-syntax-class match/fail-clause
    #:description "match/fail clause"
    ;; pat:expr *can't* be right here...
    (pattern (val:expr pat:expr fail:expr)))
  
  (syntax-parse stx
    [(_ retval) #'retval]
    [(_ retval:expr clause:match/fail-clause more-clauses ...)
     #`(match clause.val 
         [clause.pat (match/fail* retval more-clauses ...)]
         [fail clause.fail])]))

Attachment: smime.p7s
Description: S/MIME cryptographic signature

_________________________________________________
  For list-related administrative tasks:
  http://lists.racket-lang.org/listinfo/dev

Reply via email to