aboutsummaryrefslogtreecommitdiff
path: root/new-luxc/source/luxc/lang/translation/jvm/loop.lux
blob: 1f2168fedf4cb2486d43f38b1e772480e32299b5 (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
80
81
(.module:
  [lux #*
   [abstract
    ["." monad (#+ do)]]
   [control
    ["." function]]
   [data
    [number
     ["n" nat]]
    [collection
     ["." list ("#/." functor monoid)]]]
   [tool
    [compiler
     [reference (#+ Register)]
     ["." phase]
     [language
      [lux
       ["." synthesis (#+ Synthesis)]
       ["." generation]]]]]]
  [luxc
   [lang
    [host
     [jvm (#+ Inst Operation Phase Generator)
      ["_" inst]]]]]
  ["." //])

(def: (invariant? register changeS)
  (-> Register Synthesis Bit)
  (case changeS
    (^ (synthesis.variable/local var))
    (n.= register var)

    _
    false))

(def: #export (recur translate archive argsS)
  (Generator (List Synthesis))
  (do {@ phase.monad}
    [[@begin start] generation.anchor
     #let [end (|> argsS list.size dec (n.+ start))
           pairs (list.zip2 (list.n/range start end)
                            argsS)]
     ## It may look weird that first I compile the values separately,
     ## and then I compile the stores/allocations.
     ## It must be done that way in order to avoid a potential bug.
     ## Let's say that you'll recur with 2 expressions: X and Y.
     ## If Y depends on the value of X, and you don't compile values
     ## and stores separately, then by the time Y is evaluated, it
     ## will refer to the new value of X, instead of the old value, as
     ## should be the case.
     valuesI+ (monad.map @ (function (_ [register argS])
                             (: (Operation Inst)
                                (if (invariant? register argS)
                                  (wrap function.identity)
                                  (translate archive argS))))
                         pairs)
     #let [storesI+ (list/map (function (_ [register argS])
                                (: Inst
                                   (if (invariant? register argS)
                                     function.identity
                                     (_.ASTORE register))))
                              (list.reverse pairs))]]
    (wrap (|>> (_.fuse valuesI+)
               (_.fuse storesI+)
               (_.GOTO @begin)))))

(def: #export (scope translate archive [start initsS+ iterationS])
  (Generator [Nat (List Synthesis) Synthesis])
  (do {@ phase.monad}
    [@begin _.make-label
     initsI+ (monad.map @ (translate archive) initsS+)
     iterationI (generation.with-anchor [@begin start]
                  (translate archive iterationS))
     #let [initializationI (|> (list.enumerate initsI+)
                               (list/map (function (_ [register initI])
                                           (|>> initI
                                                (_.ASTORE (n.+ start register)))))
                               _.fuse)]]
    (wrap (|>> initializationI
               (_.label @begin)
               iterationI))))