aboutsummaryrefslogtreecommitdiff
path: root/new-luxc/source/luxc/lang/translation/loop.jvm.lux
blob: 77d43a0e5c8516f266ef93ecfddd83ad1df9e141 (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]
              (translation [";T" common]
                           [";T" runtime]
                           [";T" reference])
              [";L" variable #+ Variable Register])))

(def: (constant? register changeS)
  (-> Register ls;Synthesis Bool)
  (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) n.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))))