aboutsummaryrefslogtreecommitdiff
path: root/stdlib/source/lux/lang/compiler/meta/cache.lux
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--stdlib/source/lux/lang/compiler/meta/cache.lux163
1 files changed, 163 insertions, 0 deletions
diff --git a/stdlib/source/lux/lang/compiler/meta/cache.lux b/stdlib/source/lux/lang/compiler/meta/cache.lux
new file mode 100644
index 000000000..153679ef0
--- /dev/null
+++ b/stdlib/source/lux/lang/compiler/meta/cache.lux
@@ -0,0 +1,163 @@
+(.module:
+ [lux #- Module]
+ (lux (control [monad #+ Monad do]
+ ["ex" exception #+ exception:]
+ pipe)
+ (data [bool "bool/" Equivalence<Bool>]
+ [maybe]
+ [error]
+ [product]
+ (format [binary #+ Binary])
+ [text]
+ text/format
+ (coll [list "list/" Functor<List> Fold<List>]
+ (dictionary ["dict" unordered #+ Dict])
+ (set ["set" unordered #+ Set])))
+ (world [file #+ File System]))
+ [//io #+ Context Module]
+ [//io/context]
+ [//io/archive]
+ [//archive #+ Signature Key Document Archive]
+ [/dependency #+ Dependency Graph])
+
+(exception: #export (cannot-delete-cached-file {file File})
+ (ex.report ["File" file]))
+
+(exception: #export (stale-document {module Text} {current-hash Nat} {stale-hash Nat})
+ (ex.report ["Module" module]
+ ["Current hash" (%n current-hash)]
+ ["Stale hash" (%n stale-hash)]))
+
+(do-template [<name>]
+ [(exception: #export (<name> {message Text})
+ message)]
+
+ [cannot-load-definition]
+ )
+
+## General
+(def: #export (cached System<m> root)
+ (All [m] (-> (System m) File (m (List File))))
+ (|> root
+ (//io/archive.archive System<m>)
+ (do> (:: System<m> &monad)
+ [(:: System<m> files)]
+ [(monad.map @ (function (recur file)
+ (do @
+ [is-dir? (:: System<m> directory? file)]
+ (if is-dir?
+ (|> file
+ (do> @
+ [(:: System<m> files)]
+ [(monad.map @ recur)]
+ [list.concat
+ (list& (maybe.assume (//io/archive.module System<m> root file)))
+ wrap]))
+ (wrap (list))))))]
+ [list.concat wrap])))
+
+## Clean
+(def: (delete System<m> document)
+ (All [m] (-> (System m) File (m Any)))
+ (do (:: System<m> &monad)
+ [deleted? (:: System<m> delete document)]
+ (if deleted?
+ (wrap [])
+ (:: System<m> throw cannot-delete-cached-file document))))
+
+(def: (un-install System<m> root module)
+ (All [m] (-> (System m) File Module (m Any)))
+ (let [document (//io/archive.document System<m> root module)]
+ (|> document
+ (do> (:: System<m> &monad)
+ [(:: System<m> files)]
+ [(monad.map @ (function (_ file)
+ (do @
+ [? (:: System<m> directory? file)]
+ (if ?
+ (wrap false)
+ (do @
+ [_ (..delete System<m> file)]
+ (wrap true))))))]
+ [(list.every? (bool/= true))
+ (if> [(..delete System<m> document)]
+ [(wrap [])])]))))
+
+(def: #export (clean System<m> root wanted-modules)
+ (All [m] (-> (System m) File (Set Module) (m Any)))
+ (|> root
+ (do> (:: System<m> &monad)
+ [(..cached System<m>)]
+ [(list.filter (bool.complement (set.member? wanted-modules)))
+ (monad.map @ (un-install System<m> root))])))
+
+## Load
+(def: signature
+ (Binary Signature)
+ (let [name (binary.seq binary.text binary.text)
+ version binary.text]
+ (binary.seq name version)))
+
+(def: imports
+ (Binary (List Module))
+ (binary.list binary.text))
+
+(def: document
+ (All [a] (-> (Binary a) (Binary [Signature Nat (List Module) a])))
+ (|>> ($_ binary.seq ..signature binary.nat ..imports)))
+
+(def: (load-document System<m> contexts root key binary module)
+ (All [m d] (-> (System m) (List File) File (Key d) (Binary d) Module
+ (m (Maybe [Dependency (Document d)]))))
+ (do (:: System<m> &monad)
+ [document' (:: System<m> read (//io/archive.document System<m> root module))
+ [module' source-code] (//io/context.read System<m> contexts module)
+ #let [current-hash (:: text.Hash<Text> hash source-code)]]
+ (case (do error.Monad<Error>
+ [[signature document-hash imports content] (binary.read (..document binary) document')
+ _ (ex.assert stale-document [module current-hash document-hash]
+ (n/= current-hash document-hash))
+ document (//archive.close key signature document-hash content)]
+ (wrap [[module imports] document]))
+ (#error.Success [dependency document])
+ (wrap (#.Some [dependency document]))
+
+ (#error.Error error)
+ (do @
+ [_ (un-install System<m> root module)]
+ (wrap #.None)))))
+
+(def: #export (load-archive System<m> contexts root key binary)
+ (All [m d] (-> (System m) (List Context) File (Key d) (Binary d) (m Archive)))
+ (do (:: System<m> &monad)
+ [candidate (|> root
+ (do> @
+ [(..cached System<m>)]
+ [(monad.map @ (load-document System<m> contexts root key binary))
+ (:: @ map (list/fold (function (_ full-document archive)
+ (case full-document
+ (#.Some [[module imports] document])
+ (dict.put module [imports document] archive)
+
+ #.None
+ archive))
+ (: (Dict Text [(List Module) (Ex [d] (Document d))])
+ (dict.new text.Hash<Text>))))]))
+ #let [candidate-entries (dict.entries candidate)
+ candidate-dependencies (list/map (product.both id product.left)
+ candidate-entries)
+ candidate-archive (|> candidate-entries
+ (list/map (product.both id product.right))
+ (dict.from-list text.Hash<Text>))
+ graph (|> candidate
+ dict.entries
+ (list/map (product.both id product.left))
+ /dependency.graph
+ (/dependency.prune candidate-archive))
+ archive (list/fold (function (_ module archive)
+ (if (dict.contains? module graph)
+ archive
+ (dict.remove module archive)))
+ candidate-archive
+ (dict.keys candidate))]]
+ (wrap archive)))