aboutsummaryrefslogtreecommitdiff
path: root/stdlib/source/library/lux/control/function/variadic.lux
blob: 614b34f4090c77fab5d9a61f172f498fc081fa08 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
... This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
... If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.

... https://en.wikipedia.org/wiki/Variadic_function
(.require
 [library
  [lux (.except def)
   [abstract
    [monad (.only do)]]
   [control
    ["?" parser]
    ["[0]" exception (.only Exception)]]
   [data
    ["[0]" text (.only)
     ["%" \\format]]
    [collection
     ["[0]" list (.use "[1]#[0]" monad)]
     ["[0]" set]]]
   [math
    [number
     ["n" nat]]]
   ["[0]" meta (.only)
    ["[0]" code (.only)
     ["?[1]" \\parser]]
    [macro (.only with_symbols)
     [syntax (.only syntax)
      ["[0]" export]]]]]])

(exception.def .public (duplicate_parameters [definition parameters])
  (Exception [Symbol (List Text)])
  (exception.report
   (list ["Definition" (%.symbol definition)]
         ["Parameters" (%.list %.text parameters)])))

(exception.def .public (must_have_rest_parameter definition)
  (Exception Symbol)
  (exception.report
   (list ["Definition" (%.symbol definition)])))

(.def .public def
  (syntax (_ [[exported? [name parameters] type body]
              (export.with (all ?.and
                                (?code.form (?.and ?code.local (?.some ?code.local)))
                                ?code.any
                                ?code.any))])
    (do meta.monad
      [here meta.current_module_name]
      (if (n.= (list.size parameters)
               (set.size (set.of_list text.hash parameters)))
        (with_symbols [g!function]
          (when (list.reversed parameters)
            (list.partial &rest mandatory)
            (let [mandatory (list#each code.local (list.reversed mandatory))
                  &rest (code.local &rest)]
              (in (list (` (.def (, exported?) ((, g!function) (,* mandatory) (, &rest))
                             (, type)
                             (, body)))
                        (` (.def (, exported?) (, (code.local name))
                             (syntax ((, (code.local name)) [(,* (|> mandatory
                                                                     (list#each (function (_ parameter)
                                                                                  (list parameter (` ?code.any))))
                                                                     list#conjoint))
                                                             (, &rest) (?.some ?code.any)])
                               (of meta.monad (,' in)
                                   (list (` ((, g!function)
                                             (,* (list#each (|>> , ((,' .,)) `) mandatory))
                                             (list ((,' .,*) (, &rest)))))))))))))

            _
            (meta.failure (exception.error ..must_have_rest_parameter [[here name]]))))
        (meta.failure (exception.error ..duplicate_parameters [[here name] parameters]))))))