aboutsummaryrefslogtreecommitdiff
path: root/stdlib/source/library/lux/tool/compiler/language/lux/phase/generation/jvm/loop.lux
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--stdlib/source/library/lux/tool/compiler/language/lux/phase/generation/jvm/loop.lux90
1 files changed, 90 insertions, 0 deletions
diff --git a/stdlib/source/library/lux/tool/compiler/language/lux/phase/generation/jvm/loop.lux b/stdlib/source/library/lux/tool/compiler/language/lux/phase/generation/jvm/loop.lux
new file mode 100644
index 000000000..465e8d1af
--- /dev/null
+++ b/stdlib/source/library/lux/tool/compiler/language/lux/phase/generation/jvm/loop.lux
@@ -0,0 +1,90 @@
+(.module:
+ [library
+ [lux #*
+ [abstract
+ ["." monad (#+ do)]]
+ [control
+ ["." function]]
+ [data
+ ["." product]
+ [number
+ ["n" nat]]
+ [collection
+ ["." list ("#\." functor)]]]
+ [target
+ [jvm
+ ["_" bytecode (#+ Label Bytecode) ("#\." monad)]]]]]
+ ["." // #_
+ ["#." runtime (#+ Operation Phase Generator)]
+ ["#." value]
+ [////
+ ["." synthesis (#+ Path Synthesis)]
+ ["." generation]
+ [///
+ ["." phase]
+ [reference
+ [variable (#+ Register)]]]]])
+
+(def: (invariant? register changeS)
+ (-> Register Synthesis Bit)
+ (case changeS
+ (^ (synthesis.variable/local var))
+ (n.= register var)
+
+ _
+ false))
+
+(def: no-op
+ (_\wrap []))
+
+(def: #export (recur translate archive updatesS)
+ (Generator (List Synthesis))
+ (do {! phase.monad}
+ [[@begin offset] generation.anchor
+ updatesG (|> updatesS
+ list.enumeration
+ (list\map (function (_ [index updateS])
+ [(n.+ offset index) updateS]))
+ (monad.map ! (function (_ [register updateS])
+ (if (invariant? register updateS)
+ (wrap [..no-op
+ ..no-op])
+ (do !
+ [fetchG (translate archive updateS)
+ #let [storeG (_.astore register)]]
+ (wrap [fetchG storeG]))))))]
+ (wrap ($_ _.compose
+ ## It may look weird that first I fetch all the values separately,
+ ## and then I store them all.
+ ## 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 perform fetches
+ ## 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.
+ (|> updatesG
+ (list\map product.left)
+ (monad.seq _.monad))
+ (|> updatesG
+ list.reverse
+ (list\map product.right)
+ (monad.seq _.monad))
+ (_.goto @begin)))))
+
+(def: #export (scope translate archive [offset initsS+ iterationS])
+ (Generator [Nat (List Synthesis) Synthesis])
+ (do {! phase.monad}
+ [@begin //runtime.forge-label
+ initsI+ (monad.map ! (translate archive) initsS+)
+ iterationG (generation.with-anchor [@begin offset]
+ (translate archive iterationS))
+ #let [initializationG (|> (list.enumeration initsI+)
+ (list\map (function (_ [index initG])
+ ($_ _.compose
+ initG
+ (_.astore (n.+ offset index)))))
+ (monad.seq _.monad))]]
+ (wrap ($_ _.compose
+ initializationG
+ (_.set-label @begin)
+ iterationG))))