<commit_before>#lang racket/base

(require "../../parse.rkt"
         "../experimental/template.rkt"
         racket/dict)

(provide function-header arg args)

(define-syntax-class function-header
  (pattern ((~or header:function-header name:id) . args:args)
           #:attr params
           (template ((?@ . (?? header.params ()))
                      . args.params))))

(define-syntax-class args
  #:attributes (params)
  (pattern (arg:arg ...)
           #:attr params #'(arg.name ...)
           #:fail-when (check-duplicate-identifier (syntax->list #'params))
           "duplicate argument name"
           #:fail-when (check-duplicate (syntax->list #'(arg.kw ...))
                                        #:key (λ (x)
                                                (syntax->datum x))
                                        #:same? (λ (x y)
                                                  (and x y (equal? x y))))
           "duplicate keyword for argument"
           #:fail-when (invalid-option-placement
                        (syntax->list #'((arg.name arg.default) ...)))
           "default-value expression missing")
  (pattern (arg:arg ... . rest:id)
           #:attr params #'(arg.name ... rest)
           #:fail-when (check-duplicate-identifier (syntax->list #'params))
           "duplicate argument name"
           #:fail-when (check-duplicate (syntax->list #'(arg.kw ...))
                                        #:key (λ (x)
                                                (syntax->datum x))
                                        #:same? (λ (x y)
                                                  (and x y (equal? x y))))
           "duplicate keyword for argument"
           #:fail-when (invalid-option-placement
                        (syntax->list #'((arg.name arg.default) ...)))
           "default-value expression missing"))

(define-splicing-syntax-class arg
  #:attributes (name kw default)
  (pattern name:id
           #:attr kw #'#f
           #:attr default #'#f)
  (pattern [name:id default]
           #:attr kw #'#f)
  (pattern (~seq kw:keyword name:id)
           #:attr default #'#f)
  (pattern (~seq kw:keyword [name:id default])))

(define (invalid-option-placement optional-list)
  (define iop
    (for/fold ([status      'required])
              ([i optional-list]
               #:break (syntax? status))
      (define i* (syntax->list i))
      ;(match* (status (syntax->datum (cadr i*)))
      (cond [(eq? status 'required)
             (cond [(syntax->datum (cadr i*)) 'optional]
                   [else                      'required])]
            [else
             (cond [(syntax->datum (cadr i*)) 'optional]
                   [else                      (car i*)])])))
  (if (syntax? iop) iop #f))

;; Copied from unstable/list
;; check-duplicate : (listof X)
;;                   #:key (X -> K)
;;                   #:same? (or/c (K K -> bool) dict?)
;;                -> X or #f
(define (check-duplicate items
                        #:key [key values]
                        #:same? [same? equal?])
  (cond [(procedure? same?)
         (cond [(eq? same? equal?)
                (check-duplicate/t items key (make-hash) #t)]
               [(eq? same? eq?)
                (check-duplicate/t items key (make-hasheq) #t)]
               [(eq? same? eqv?)
                (check-duplicate/t items key (make-hasheqv) #t)]
               [else
                (check-duplicate/list items key same?)])]
        [(dict? same?)
         (let ([dict same?])
           (if (dict-mutable? dict)
               (check-duplicate/t items key dict #t)
               (check-duplicate/t items key dict #f)))]))<commit_msg>Use #f for no default or keyword (opposed to #'#f)<commit_after>#lang racket/base

(require "../../parse.rkt"
         "../experimental/template.rkt"
         racket/dict)

(provide function-header formal formals)

(define-syntax-class function-header
  (pattern ((~or header:function-header name:id) . args:formals)
           #:attr params
           (template ((?@ . (?? header.params ()))
                      . args.params))))

(define-syntax-class formals
  #:attributes (params)
  (pattern (arg:formal ...)
           #:attr params #'(arg.name ...)
           #:fail-when (check-duplicate-identifier (syntax->list #'params))
                       "duplicate argument name"
           #:fail-when (check-duplicate (attribute arg.kw)
                                        #:same? (λ (x y)
                                                  (and x y (equal? (syntax-e x)
                                                                   (syntax-e y)))))
                       "duplicate keyword for argument"
           #:fail-when (invalid-option-placement
                        (map list (attribute arg.name) (attribute arg.default)))
                       "default-value expression missing")
  (pattern (arg:formal ... . rest:id)
           #:attr params #'(arg.name ... rest)
           #:fail-when (check-duplicate-identifier (syntax->list #'params))
                       "duplicate argument name"
           #:fail-when (check-duplicate (attribute arg.kw)
                                        #:same? (λ (x y)
                                                  (and x y (equal? (syntax-e x)
                                                                   (syntax-e y)))))
                       "duplicate keyword for argument"
           #:fail-when (invalid-option-placement
                        (map list (attribute arg.name) (attribute arg.default)))
                       "default-value expression missing"))

(define-splicing-syntax-class formal
  #:attributes (name kw default)
  (pattern name:id
           #:attr kw #f
           #:attr default #f)
  (pattern [name:id default]
           #:attr kw #f)
  (pattern (~seq kw:keyword name:id)
           #:attr default #f)
  (pattern (~seq kw:keyword [name:id default])))

(define (invalid-option-placement optional-list)
  (define iop
    (for/fold ([status 'required])
              ([i optional-list]
               #:break (syntax? status))
      (cond [(eq? status 'required)
             (cond [(not i)    'optional]
                   [else       'required])]
            [else
             (cond [(not i)    'optional]
                   [else       (car i)])])))
  (if (syntax? iop) iop #f))

;; Copied from unstable/list
;; check-duplicate : (listof X)
;;                   #:key (X -> K)
;;                   #:same? (or/c (K K -> bool) dict?)
;;                -> X or #f
(define (check-duplicate items
                        #:key [key values]
                        #:same? [same? equal?])
  (cond [(procedure? same?)
         (cond [(eq? same? equal?)
                (check-duplicate/t items key (make-hash) #t)]
               [(eq? same? eq?)
                (check-duplicate/t items key (make-hasheq) #t)]
               [(eq? same? eqv?)
                (check-duplicate/t items key (make-hasheqv) #t)]
               [else
                (check-duplicate/list items key same?)])]
        [(dict? same?)
         (let ([dict same?])
           (if (dict-mutable? dict)
               (check-duplicate/t items key dict #t)
               (check-duplicate/t items key dict #f)))]))
{'fraction_non_alphanumeric': 0.14503921838447778, 'fraction_numerical': 0.0, 'mean_word_length': 1.3582089552238805, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 22, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7145498', 'n_tokens_mistral': 2062, 'n_tokens_neox': 1924, 'n_words': 539}