diff options
Diffstat (limited to '')
-rw-r--r-- | stdlib/source/library/lux/tool/compiler/language/lux/phase/analysis/module.lux | 275 |
1 files changed, 275 insertions, 0 deletions
diff --git a/stdlib/source/library/lux/tool/compiler/language/lux/phase/analysis/module.lux b/stdlib/source/library/lux/tool/compiler/language/lux/phase/analysis/module.lux new file mode 100644 index 000000000..94b289a08 --- /dev/null +++ b/stdlib/source/library/lux/tool/compiler/language/lux/phase/analysis/module.lux @@ -0,0 +1,275 @@ +(.module: + [library + [lux #* + [abstract + ["." monad (#+ do)]] + [control + pipe + ["." try] + ["." exception (#+ exception:)]] + [data + ["." text ("#\." equivalence) + ["%" format (#+ format)]] + [collection + ["." list ("#\." fold functor)] + [dictionary + ["." plist]]]] + ["." meta]]] + ["." /// #_ + ["#." extension] + [// + ["/" analysis (#+ Operation)] + [/// + ["#" phase]]]]) + +(type: #export Tag Text) + +(exception: #export (unknown_module {module Text}) + (exception.report + ["Module" module])) + +(exception: #export (cannot_declare_tag_twice {module Text} {tag Text}) + (exception.report + ["Module" module] + ["Tag" tag])) + +(template [<name>] + [(exception: #export (<name> {tags (List Text)} {owner Type}) + (exception.report + ["Tags" (text.join_with " " tags)] + ["Type" (%.type owner)]))] + + [cannot_declare_tags_for_unnamed_type] + [cannot_declare_tags_for_foreign_type] + ) + +(exception: #export (cannot_define_more_than_once {name Name} {already_existing Global}) + (exception.report + ["Definition" (%.name name)] + ["Original" (case already_existing + (#.Alias alias) + (format "alias " (%.name alias)) + + (#.Definition definition) + (format "definition " (%.name name)))])) + +(exception: #export (can_only_change_state_of_active_module {module Text} {state Module_State}) + (exception.report + ["Module" module] + ["Desired state" (case state + #.Active "Active" + #.Compiled "Compiled" + #.Cached "Cached")])) + +(exception: #export (cannot_set_module_annotations_more_than_once {module Text} {old Code} {new Code}) + (exception.report + ["Module" module] + ["Old annotations" (%.code old)] + ["New annotations" (%.code new)])) + +(def: #export (new hash) + (-> Nat Module) + {#.module_hash hash + #.module_aliases (list) + #.definitions (list) + #.imports (list) + #.tags (list) + #.types (list) + #.module_annotations #.None + #.module_state #.Active}) + +(def: #export (set_annotations annotations) + (-> Code (Operation Any)) + (///extension.lift + (do ///.monad + [self_name meta.current_module_name + self meta.current_module] + (case (get@ #.module_annotations self) + #.None + (function (_ state) + (#try.Success [(update@ #.modules + (plist.put self_name (set@ #.module_annotations (#.Some annotations) self)) + state) + []])) + + (#.Some old) + (/.throw' cannot_set_module_annotations_more_than_once [self_name old annotations]))))) + +(def: #export (import module) + (-> Text (Operation Any)) + (///extension.lift + (do ///.monad + [self_name meta.current_module_name] + (function (_ state) + (#try.Success [(update@ #.modules + (plist.update self_name (update@ #.imports (function (_ current) + (if (list.any? (text\= module) + current) + current + (#.Cons module current))))) + state) + []]))))) + +(def: #export (alias alias module) + (-> Text Text (Operation Any)) + (///extension.lift + (do ///.monad + [self_name meta.current_module_name] + (function (_ state) + (#try.Success [(update@ #.modules + (plist.update self_name (update@ #.module_aliases (: (-> (List [Text Text]) (List [Text Text])) + (|>> (#.Cons [alias module]))))) + state) + []]))))) + +(def: #export (exists? module) + (-> Text (Operation Bit)) + (///extension.lift + (function (_ state) + (|> state + (get@ #.modules) + (plist.get module) + (case> (#.Some _) #1 #.None #0) + [state] #try.Success)))) + +(def: #export (define name definition) + (-> Text Global (Operation Any)) + (///extension.lift + (do ///.monad + [self_name meta.current_module_name + self meta.current_module] + (function (_ state) + (case (plist.get name (get@ #.definitions self)) + #.None + (#try.Success [(update@ #.modules + (plist.put self_name + (update@ #.definitions + (: (-> (List [Text Global]) (List [Text Global])) + (|>> (#.Cons [name definition]))) + self)) + state) + []]) + + (#.Some already_existing) + ((/.throw' ..cannot_define_more_than_once [[self_name name] already_existing]) state)))))) + +(def: #export (create hash name) + (-> Nat Text (Operation Any)) + (///extension.lift + (function (_ state) + (#try.Success [(update@ #.modules + (plist.put name (new hash)) + state) + []])))) + +(def: #export (with_module hash name action) + (All [a] (-> Nat Text (Operation a) (Operation [Module a]))) + (do ///.monad + [_ (create hash name) + output (/.with_current_module name + action) + module (///extension.lift (meta.find_module name))] + (wrap [module output]))) + +(template [<setter> <asker> <tag>] + [(def: #export (<setter> module_name) + (-> Text (Operation Any)) + (///extension.lift + (function (_ state) + (case (|> state (get@ #.modules) (plist.get module_name)) + (#.Some module) + (let [active? (case (get@ #.module_state module) + #.Active #1 + _ #0)] + (if active? + (#try.Success [(update@ #.modules + (plist.put module_name (set@ #.module_state <tag> module)) + state) + []]) + ((/.throw' can_only_change_state_of_active_module [module_name <tag>]) + state))) + + #.None + ((/.throw' unknown_module module_name) state))))) + + (def: #export (<asker> module_name) + (-> Text (Operation Bit)) + (///extension.lift + (function (_ state) + (case (|> state (get@ #.modules) (plist.get module_name)) + (#.Some module) + (#try.Success [state + (case (get@ #.module_state module) + <tag> #1 + _ #0)]) + + #.None + ((/.throw' unknown_module module_name) state)))))] + + [set_active active? #.Active] + [set_compiled compiled? #.Compiled] + [set_cached cached? #.Cached] + ) + +(template [<name> <tag> <type>] + [(def: (<name> module_name) + (-> Text (Operation <type>)) + (///extension.lift + (function (_ state) + (case (|> state (get@ #.modules) (plist.get module_name)) + (#.Some module) + (#try.Success [state (get@ <tag> module)]) + + #.None + ((/.throw' unknown_module module_name) state)))))] + + [tags #.tags (List [Text [Nat (List Name) Bit Type]])] + [types #.types (List [Text [(List Name) Bit Type]])] + [hash #.module_hash Nat] + ) + +(def: (ensure_undeclared_tags module_name tags) + (-> Text (List Tag) (Operation Any)) + (do {! ///.monad} + [bindings (..tags module_name) + _ (monad.map ! + (function (_ tag) + (case (plist.get tag bindings) + #.None + (wrap []) + + (#.Some _) + (/.throw ..cannot_declare_tag_twice [module_name tag]))) + tags)] + (wrap []))) + +(def: #export (declare_tags tags exported? type) + (-> (List Tag) Bit Type (Operation Any)) + (do ///.monad + [self_name (///extension.lift meta.current_module_name) + [type_module type_name] (case type + (#.Named type_name _) + (wrap type_name) + + _ + (/.throw ..cannot_declare_tags_for_unnamed_type [tags type])) + _ (ensure_undeclared_tags self_name tags) + _ (///.assert cannot_declare_tags_for_foreign_type [tags type] + (text\= self_name type_module))] + (///extension.lift + (function (_ state) + (case (|> state (get@ #.modules) (plist.get self_name)) + (#.Some module) + (let [namespaced_tags (list\map (|>> [self_name]) tags)] + (#try.Success [(update@ #.modules + (plist.update self_name + (|>> (update@ #.tags (function (_ tag_bindings) + (list\fold (function (_ [idx tag] table) + (plist.put tag [idx namespaced_tags exported? type] table)) + tag_bindings + (list.enumeration tags)))) + (update@ #.types (plist.put type_name [namespaced_tags exported? type])))) + state) + []])) + #.None + ((/.throw' unknown_module self_name) state)))))) |