aboutsummaryrefslogtreecommitdiff
path: root/new-luxc/source/luxc/lang/translation/ruby/function.jvm.lux
blob: 64c2bba2e63c5f87afa75a2e474ec9799314b815 (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
72
73
74
75
76
77
78
79
(.module:
  lux
  (lux (control [monad #+ do])
       (data [product]
             [text]
             text/format
             (coll [list "list/" Functor<List>]))
       [macro])
  (luxc ["&" lang]
        (lang ["ls" synthesis]
              [".L" variable #+ Variable Register]
              (host [ruby #+ Ruby Expression Statement])))
  [//]
  (// [".T" reference]
      [".T" runtime]))

(def: #export (translate-apply translate functionS argsS+)
  (-> (-> ls.Synthesis (Meta Expression)) ls.Synthesis (List ls.Synthesis) (Meta Expression))
  (do macro.Monad<Meta>
    [functionO (translate functionS)
     argsO+ (monad.map @ translate argsS+)]
    (wrap (ruby.call argsO+ functionO))))

(def: (input-declaration registers)
  (-> (List Register) Statement)
  (ruby.set! (list.concat (list (list/map (|>> inc referenceT.variable) registers)
                                (list "_")))
             "curried"))

(def: (with-closure inits function-definition)
  (-> (List Expression) Statement Expression)
  (case inits
    #.Nil
    function-definition

    _
    (ruby.call inits
               (ruby.lambda #.None
                       (|> (list.enumerate inits)
                           (list/map (|>> product.left referenceT.closure)))
                       (ruby.return! function-definition)))))

(def: #export (translate-function translate env arity bodyS)
  (-> (-> ls.Synthesis (Meta Expression))
      (List Variable) ls.Arity ls.Synthesis
      (Meta Expression))
  (do macro.Monad<Meta>
    [[function-name bodyO] (//.with-sub-context
                             (do @
                               [function-name //.context]
                               (//.with-anchor [function-name +1]
                                 (translate bodyS))))
     closureO+ (monad.map @ referenceT.translate-variable env)
     #let [args-initsO+ (input-declaration (list.n/range +0 (dec arity)))
           selfO (ruby.set! (list (referenceT.variable +0)) function-name)
           arityO (|> arity .int %i)
           limitO (|> arity dec .int %i)]]
    (wrap (with-closure closureO+
            (ruby.lambda (#.Some function-name)
                    (list (ruby.splat "curried"))
                    (ruby.block! (list (ruby.set! (list "num_args") (ruby.length "curried"))
                                       (ruby.if! (ruby.= arityO "num_args")
                                                 (ruby.block! (list selfO
                                                                    args-initsO+
                                                                    (ruby.while! (ruby.bool #1)
                                                                                 (ruby.return! bodyO))))
                                                 (ruby.return! (let [recur (function (_ args) (ruby.call (list args) function-name))]
                                                                 (ruby.? (ruby.> arityO "num_args")
                                                                         (let [slice (function (_ from to)
                                                                                       (ruby.array-range from to "curried"))
                                                                               arity-args (ruby.splat (slice (ruby.int 0) limitO))
                                                                               output-func-args (ruby.splat (slice arityO "num_args"))]
                                                                           (ruby.call (list output-func-args)
                                                                                      (recur arity-args)))
                                                                         (ruby.lambda #.None
                                                                                 (list (ruby.splat "extra"))
                                                                                 (recur (ruby.splat (|> (ruby.array (list))
                                                                                                        (ruby.send "concat" (list "curried"))
                                                                                                        (ruby.send "concat" (list "extra")))))))))))))))))