(.module: lux (lux (control [monad #+ do] ["p" parser] ["ex" exception #+ exception:] pipe) (concurrency [promise #+ Promise] [stm #+ Var STM]) (data ["e" error #+ Error] [maybe] [product] [text "text/" Eq] text/format (coll [list "list/" Functor Fold] (dictionary ["dict" unordered #+ Dict]))) [macro] (macro [code] ["s" syntax]) [io #+ IO Process io] [host]) (luxc ["&" lang] (lang [".L" module]))) (do-template [] [(exception: #export ( {message Text}) message)] [Invalid-Imports] [Module-Cannot-Import-Itself] [Circular-Dependency] ) (host.import: (java/util/concurrent/Future a) (get [] #io a)) (host.import: (java/util/concurrent/CompletableFuture a) (new []) (complete [a] boolean) (#static [a] completedFuture [a] (CompletableFuture a))) (type: Import {#module Text #alias Text}) (def: import (s.Syntax Import) (s.tuple (p.seq s.text s.text))) (def: compilations (Var (Dict Text (CompletableFuture (Error Lux)))) (stm.var (dict.new text.Hash))) (def: (promise-to-future promise) (All [a] (-> (Promise a) (Future a))) (let [future (CompletableFuture::new [])] (exec (:: promise.Functor map (function (_ value) (CompletableFuture::complete [value] future)) promise) future))) (def: from-io (All [a] (-> (IO a) (Process a))) (:: io.Monad map (|>> #e.Success))) (def: (translate-dependency translate-module dependency compiler) (-> (-> Text Lux (Process Lux)) (-> Text Lux (IO (Future (Error Lux))))) (<| (Future::get []) promise-to-future (do promise.Monad [[new? future] (stm.commit (: (STM [Bit (CompletableFuture (Error Lux))]) (do stm.Monad [current-compilations (stm.read compilations)] (case (dict.get dependency current-compilations) (#.Some ongoing) (wrap [false ongoing]) #.None (do @ [#let [pending (: (CompletableFuture (Error Lux)) (CompletableFuture::new []))] _ (stm.write (dict.put dependency pending current-compilations) compilations)] (wrap [true pending]))))))] (if new? (exec (promise.future (io (CompletableFuture::complete [(io.run (translate-module dependency compiler))] future))) (wrap future)) (wrap future))))) (def: compiled? (-> Module Bit) (|>> (get@ #.module-state) (case> (^or #.Cached #.Compiled) true _ false))) (def: (merge-modules current-module from-dependency from-current) (-> Text (List [Text Module]) (List [Text Module]) (List [Text Module])) (|> from-dependency (list.filter (|>> product.right compiled?)) (list/fold (function (_ [dep-name dep-module] total) (&.pl-put dep-name dep-module total)) from-current))) (def: (merge-compilers current-module dependency total) (-> Text Lux Lux Lux) (|> total (update@ #.modules (merge-modules current-module (get@ #.modules dependency))) (set@ #.seed (get@ #.seed dependency)))) (def: #export (translate-imports translate-module annotations) (-> (-> Text Lux (Process Lux)) Code (Meta (Process Lux))) (do macro.Monad [_ (moduleL.set-annotations annotations) current-module macro.current-module-name imports (let [imports (|> (macro.get-tuple-ann (ident-for #.imports) annotations) (maybe.default (list)))] (case (s.run imports (p.some import)) (#e.Success imports) (wrap imports) (#e.Error error) (&.throw Invalid-Imports (%code (code.tuple imports))))) dependencies (monad.map @ (: (-> [Text Text] (Meta (IO (Future (Error Lux))))) (function (_ [dependency alias]) (do @ [_ (&.assert Module-Cannot-Import-Itself current-module (not (text/= current-module dependency))) already-seen? (moduleL.exists? dependency) circular-dependency? (if already-seen? (moduleL.active? dependency) (wrap false)) _ (&.assert Circular-Dependency (format "From: " current-module "\n" " To: " dependency) (not circular-dependency?)) _ (moduleL.import dependency) _ (if (text/= "" alias) (wrap []) (moduleL.alias alias dependency)) compiler macro.get-compiler] (if already-seen? (wrap (io (CompletableFuture::completedFuture [(#e.Success compiler)]))) (wrap (translate-dependency translate-module dependency compiler)))))) imports) compiler macro.get-compiler] (wrap (do io.Monad [dependencies (monad.seq io.Monad (list/map from-io dependencies)) dependencies (|> dependencies (list/map (Future::get [])) (monad.seq io.Monad))] (wrap (list/fold (merge-compilers current-module) compiler dependencies))))))