<commit_before>#lang racket/base
(require racket/contract/base
         racket/contract/combinator
         (rename-in "private/generic.rkt"
                    [define-generics define-generics/pre])
         (for-syntax racket/base racket/local racket/syntax))

;; Convenience layer on top of racket/private/generic.
;; To avoid circular dependencies, racket/private/generic cannot use
;; `parse-keyword-options' (which depends on racket/dict). So we do
;; keyword argument parsing here.
;; Files that use racket/private/generic _must_ pass _all_ keyword
;; arguments to define-generics _in_order_.

(provide define-generics define/generic)

(define-syntax (define-generics stx) ; allows out-of-order / optional kw args
  (syntax-case stx () ; can't use syntax-parse, since it depends on us
    [(_ name (generic . generics-args) ... #:defaults defaults)
     #'(define-generics name
         #:defined-table defined-table
         (generic . generics-args) ...
         #:defaults defaults)]
    [(_ name #:defined-table defined-table (generic . generics-args) ...)
     #'(define-generics name
         #:defined-table defined-table
         (generic . generics-args) ...
         #:defaults ())]
    [(_ name (generic . generics-args) ...)
     #'(define-generics name
         #:defined-table defined-table
         (generic . generics-args) ...
         #:defaults ())]
    [(_ name
       #:defined-table defined-table
       (generic . generics-args) ...
       #:defaults defaults)
     (local [(define name-str (symbol->string (syntax-e #'name)))
             (define (id . strs)
               (datum->syntax
                #'name (string->symbol (apply string-append strs)) #'name))]
      (with-syntax ([name? (id name-str "?")]
                    [gen:name (id "gen:" name-str)])
       #'(define-generics/pre (name gen:name prop:name name?
                                    #:defined-table defined-table
                                    #:defaults defaults
                                    ;; the following are not public
                                    #:prop-defined-already? #f
                                    #:define-contract define-generics-contract)
           (generic . generics-args) ...)))]))<commit_msg>Keyword arguments to define-generics can be in any order, before/after methods.<commit_after>#lang racket/base
(require racket/contract/base
         racket/contract/combinator
         (rename-in "private/generic.rkt"
                    [define-generics define-generics/pre])
         (for-syntax racket/base racket/local racket/syntax syntax/stx))

;; Convenience layer on top of racket/private/generic.
;; To avoid circular dependencies, racket/private/generic cannot use
;; `parse-keyword-options' (which depends on racket/dict). So we do
;; keyword argument parsing here.
;; Files that use racket/private/generic _must_ pass _all_ keyword
;; arguments to define-generics _in_order_.

(provide define-generics define/generic)

(begin-for-syntax

  (define (parse stx methods table defaults)
    (syntax-case stx ()
      [(#:defined-table name . args)
       (identifier? #'name)
       (if table
           (wrong-syntax (stx-car stx)
                         "duplicate #:defined-table specification")
           (parse #'args methods #'name defaults))]
      [(#:defined-table . other)
       (wrong-syntax (stx-car stx) "invalid #:defined-table specification")]
      [(#:defaults ([pred defn ...] ...) . args)
       (if defaults
           (wrong-syntax (stx-car stx) "duplicate #:defaults specification")
           (parse #'args methods table #'([pred defn ...] ...)))]
      [(#:defaults . other)
       (wrong-syntax (stx-car stx) "invalid #:defaults specification")]
      [(kw . args)
       (keyword? (syntax-e #'kw))
       (wrong-syntax #'kw "invalid keyword argument")]
      [((_ . _) . args)
       (if methods
           (wrong-syntax (stx-car stx) "duplicate methods list specification")
           (let loop ([methods (list (stx-car stx))] [stx #'args])
             (syntax-case stx ()
               [((_ . _) . args) (loop (cons (stx-car stx) methods) #'args)]
               [_ (parse stx (reverse methods) table defaults)])))]
      [(other . args)
       (wrong-syntax #'other
                     "expected a method identifier with formal arguments")]
      [() (values (or methods '())
                  (or table (generate-temporary 'table))
                  (or defaults '()))]
      [other
       (wrong-syntax #'other
                     "expected a list of arguments with no dotted tail")])))

(define-syntax (define-generics stx) ; allows out-of-order / optional kw args
  (syntax-case stx ()
    [(_ name . rest)
     (parameterize ([current-syntax-context stx])
       (unless (identifier? #'name)
         (wrong-syntax #'name "expected an identifier"))
       (define-values (methods table defaults)
         (parse #'rest #f #f #f))
       (define/with-syntax [default ...] defaults)
       (define/with-syntax [method ...] methods)
       (define/with-syntax pred-name (format-id #'name "~a?" #'name))
       (define/with-syntax gen-name (format-id #'name "gen:~a" #'name))
       (define/with-syntax prop-name (generate-temporary #'name))
       (define/with-syntax table-name table)
       #'(define-generics/pre (name gen-name prop-name pred-name
                                    #:defined-table table-name
                                    #:defaults [default ...]
                                    #:prop-defined-already? #f
                                    #:define-contract define-generics-contract)
           method ...))]))
{'fraction_non_alphanumeric': 0.13601702429508777, 'fraction_numerical': 0.0, 'mean_word_length': 2.0552546045503792, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 6, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 9, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3417776', 'n_tokens_mistral': 1663, 'n_tokens_neox': 1534, 'n_words': 430}