aboutsummaryrefslogtreecommitdiff
path: root/new-luxc/source/luxc/lang/translation/jvm/loop.jvm.lux
blob: 120a3e384c0ac6ab6298435c0613ed2f4ffd2332 (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
(.module:
  lux
  (lux (control [monad #+ do])
       (data [text]
             text/format
             (coll [list "list/" Functor<List> Monoid<List>]))
       [macro])
  (luxc ["&" lang]
        (lang [".L" host]
              (host ["$" jvm]
                    (jvm ["$t" type]
                         ["$d" def]
                         ["$i" inst]))
              ["la" analysis]
              ["ls" synthesis]
              [".L" variable #+ Variable Register]))
  (// [".T" common]
      [".T" runtime]
      [".T" reference]))

(def: (constant? register changeS)
  (-> Register ls.Synthesis Bit)
  (case changeS
    (^multi (^code ((~ [_ (#.Int var)])))
            (i/= (variableL.local register)
                 var))
    true

    _
    false))

(def: #export (translate-recur translate argsS)
  (-> (-> ls.Synthesis (Meta $.Inst))
      (List ls.Synthesis)
      (Meta $.Inst))
  (do macro.Monad<Meta>
    [[@begin offset] hostL.anchor
     #let [pairs (list.zip2 (list.n/range offset (|> (list.size argsS) dec (n/+ offset)))
                            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
     ## must be the case.
     valuesI+ (monad.map @ (function (_ [register argS])
                             (: (Meta $.Inst)
                                (if (constant? register argS)
                                  (wrap id)
                                  (translate argS))))
                         pairs)
     #let [storesI+ (list/map (function (_ [register argS])
                                (: $.Inst
                                   (if (constant? register argS)
                                     id
                                     ($i.ASTORE register))))
                              (list.reverse pairs))]]
    (wrap (|>> ($i.fuse valuesI+)
               ($i.fuse storesI+)
               ($i.GOTO @begin)))))

(def: #export (translate-loop translate offset initsS+ bodyS)
  (-> (-> ls.Synthesis (Meta $.Inst))
      Nat (List ls.Synthesis) ls.Synthesis
      (Meta $.Inst))
  (do macro.Monad<Meta>
    [@begin $i.make-label
     initsI+ (monad.map @ translate initsS+)
     bodyI (hostL.with-anchor [@begin offset]
             (translate bodyS))
     #let [initializationI (|> (list.enumerate initsI+)
                               (list/map (function (_ [register initI])
                                           (|>> initI
                                                ($i.ASTORE (n/+ offset register)))))
                               $i.fuse)]]
    (wrap (|>> initializationI
               ($i.label @begin)
               bodyI))))