diff options
Diffstat (limited to '')
-rw-r--r-- | stdlib/source/lux/control/pipe.lux | 5 | ||||
-rw-r--r-- | stdlib/source/lux/lang/compiler/meta/io.lux | 16 | ||||
-rw-r--r-- | stdlib/source/lux/lang/compiler/meta/io/archive.lux | 70 | ||||
-rw-r--r-- | stdlib/source/lux/lang/compiler/meta/io/context.lux | 89 | ||||
-rw-r--r-- | stdlib/source/lux/world/file.lux | 345 |
5 files changed, 408 insertions, 117 deletions
diff --git a/stdlib/source/lux/control/pipe.lux b/stdlib/source/lux/control/pipe.lux index 4cbfe3504..de058307b 100644 --- a/stdlib/source/lux/control/pipe.lux +++ b/stdlib/source/lux/control/pipe.lux @@ -59,6 +59,11 @@ (` (|> (~ g!temp) (~+ then)))))) (|> (~ g!temp) (~+ else))))))))) +(syntax: #export (if> {then body^} {else body^} prev) + (wrap (list (` (cond> [] [(new> (~+ then))] + [(new> (~+ else))] + (~ prev)))))) + (syntax: #export (loop> {test body^} {then body^} prev) diff --git a/stdlib/source/lux/lang/compiler/meta/io.lux b/stdlib/source/lux/lang/compiler/meta/io.lux new file mode 100644 index 000000000..6be4605f2 --- /dev/null +++ b/stdlib/source/lux/lang/compiler/meta/io.lux @@ -0,0 +1,16 @@ +(.module: + [lux #- Module] + (lux (control monad + ["ex" exception #+ exception:]) + (data [error] + [text] + (text format + [encoding])) + (world [file #+ File System] + [blob #+ Blob]))) + +(type: #export Module Text) + +(def: #export (sanitize system) + (All [m] (-> (System m) Text Text)) + (text.replace-all "/" (:: system separator))) diff --git a/stdlib/source/lux/lang/compiler/meta/io/archive.lux b/stdlib/source/lux/lang/compiler/meta/io/archive.lux new file mode 100644 index 000000000..534c9e20c --- /dev/null +++ b/stdlib/source/lux/lang/compiler/meta/io/archive.lux @@ -0,0 +1,70 @@ +(.module: + [lux #- Module] + (lux (control monad + ["ex" exception #+ exception:]) + (data [error] + [text] + text/format) + (world [file #+ File System] + [blob #+ Blob])) + [/////host] + [// #+ Module]) + +(type: #export Document File) + +(exception: #export (cannot-prepare {archive File} {module Module}) + (ex.report ["Archive" archive] + ["Module" module])) + +(def: #export (archive System<m> root) + (All [m] (-> (System m) File File)) + (<| (format root (:: System<m> separator)) + (`` (for {(~~ (static /////host.common-lisp)) /////host.common-lisp + (~~ (static /////host.js)) /////host.js + (~~ (static /////host.jvm)) /////host.jvm + (~~ (static /////host.lua)) /////host.lua + (~~ (static /////host.php)) /////host.php + (~~ (static /////host.python)) /////host.python + (~~ (static /////host.r)) /////host.r + (~~ (static /////host.ruby)) /////host.ruby + (~~ (static /////host.scheme)) /////host.scheme})))) + +(def: #export (document System<m> root module) + (All [m] (-> (System m) File Module Document)) + (let [archive (..archive System<m> root)] + (|> module + (//.sanitize System<m>) + (format archive (:: System<m> separator))))) + +(def: #export (prepare System<m> root module) + (All [m] (-> (System m) File Module (m Any))) + (do (:: System<m> &monad) + [#let [archive (..archive System<m> root) + document (..document System<m> root module)] + document-exists? (file.exists? System<m> document)] + (if document-exists? + (wrap []) + (do @ + [outcome (:: System<m> try (:: System<m> make-directory document))] + (case outcome + (#error.Success output) + (wrap output) + + (#error.Error _) + (:: System<m> throw cannot-prepare [archive module])))))) + +(def: #export (write System<m> root content name) + (All [m] (-> (System m) File Blob Text (m Any))) + (:: System<m> write content (..document System<m> root name))) + +(def: #export (module System<m> root document) + (All [m] (-> (System m) File Document (Maybe Module))) + (case (text.split-with (..archive System<m> root) document) + (#.Some ["" post]) + (let [raw (text.replace-all (:: System<m> separator) "/" post)] + (if (text.starts-with? "/" raw) + (text.clip' +1 raw) + (#.Some raw))) + + _ + #.None)) diff --git a/stdlib/source/lux/lang/compiler/meta/io/context.lux b/stdlib/source/lux/lang/compiler/meta/io/context.lux new file mode 100644 index 000000000..d03dcbdd8 --- /dev/null +++ b/stdlib/source/lux/lang/compiler/meta/io/context.lux @@ -0,0 +1,89 @@ +(.module: + [lux #- Module] + (lux (control monad + ["ex" exception #+ Exception exception:]) + (data [error] + (text format + [encoding])) + (world [file #+ File System] + [blob #+ Blob])) + [/////host] + [// #+ Module]) + +(type: #export Context File) + +(type: #export Extension Text) + +(def: #export (file System<m> context module) + (All [m] (-> (System m) Context Module File)) + (|> module + (//.sanitize System<m>) + (format context (:: System<m> separator)))) + +(def: host-extension + Extension + (`` (for {(~~ (static /////host.common-lisp)) ".cl" + (~~ (static /////host.js)) ".js" + (~~ (static /////host.jvm)) ".jvm" + (~~ (static /////host.lua)) ".lua" + (~~ (static /////host.php)) ".php" + (~~ (static /////host.python)) ".py" + (~~ (static /////host.r)) ".r" + (~~ (static /////host.ruby)) ".rb" + (~~ (static /////host.scheme)) ".scm"}))) + +(def: lux-extension Extension ".lux") + +(do-template [<name>] + [(exception: #export (<name> {module Module}) + (ex.report ["Module" module]))] + + [module-not-found] + [cannot-read-module] + ) + +(def: (find-source System<m> contexts module extension) + (All [m] (-> (System m) (List Context) Module Text (m (Maybe [Module File])))) + (case contexts + #.Nil + (:: (:: System<m> &monad) wrap #.None) + + (#.Cons context contexts') + (do (:: System<m> &monad) + [#let [file (format (..file System<m> context module) extension)] + ? (file.exists? System<m> file)] + (if ? + (wrap (#.Some [module file])) + (find-source System<m> contexts' module))))) + +(def: (try System<m> computations exception message) + (All [m a e] (-> (System m) (List (m (Maybe a))) (Exception e) e (m a))) + (case computations + #.Nil + (:: System<m> throw exception message) + + (#.Cons computation computations') + (do (:: System<m> &monad) + [outcome computation] + (case outcome + (#.Some output) + (wrap output) + + #.None + (try System<m> computations' exception message))))) + +(def: #export (read System<m> contexts name) + (All [m] (-> (System m) (List Context) Module (m [Module Text]))) + (let [find-source' (find-source System<m> contexts name)] + (do (:: System<m> &monad) + [[path file] (try System<m> + (list (find-source' (format host-extension lux-extension)) + (find-source' lux-extension)) + module-not-found [name]) + blob (:: System<m> read file)] + (case (encoding.from-utf8 blob) + (#error.Success code) + (wrap [path code]) + + (#error.Error _) + (:: System<m> throw cannot-read-module [name]))))) diff --git a/stdlib/source/lux/world/file.lux b/stdlib/source/lux/world/file.lux index 176f7ccf8..21f5c1d3c 100644 --- a/stdlib/source/lux/world/file.lux +++ b/stdlib/source/lux/world/file.lux @@ -1,129 +1,240 @@ (.module: lux - (lux (control [monad #+ do] - ["ex" exception #+ exception:]) - (data (coll [array])) - (time ["i" instant] - ["d" duration]) + (lux (control [monad #+ Monad do] + ["ex" exception #+ Exception exception:] + pipe) + (data [error #+ Error] + text/format + (coll [array])) + (time [instant #+ Instant] + [duration]) (world [blob #+ Blob]) [io #+ Process] - [host])) + [host #+ import:] + [lang/host])) (type: #export File Text) -(exception: #export (could-not-read-all-data {file File}) - file) - -(exception: #export (not-a-directory {file File}) - file) - -(host.import: #long java/io/File - (new [String]) - (exists [] #io #try boolean) - (mkdirs [] #io #try boolean) - (delete [] #io #try boolean) - (length [] #io #try long) - (listFiles [] #io #try #? (Array java/io/File)) - (getAbsolutePath [] #io #try String) - (renameTo [java/io/File] #io #try boolean) - (isFile [] #io #try boolean) - (isDirectory [] #io #try boolean) - (lastModified [] #io #try long) - (setLastModified [long] #io #try boolean) - (canRead [] #io #try boolean) - (canWrite [] #io #try boolean) - (canExecute [] #io #try boolean) - (#static separator String)) - -(host.import: java/lang/AutoCloseable - (close [] #io #try void)) - -(host.import: java/io/OutputStream - (write [(Array byte)] #io #try void) - (flush [] #io #try void)) - -(host.import: java/io/FileOutputStream - (new [java/io/File boolean] #io #try)) - -(host.import: java/io/InputStream - (read [(Array byte)] #io #try int)) - -(host.import: java/io/FileInputStream - (new [java/io/File] #io #try)) - -(do-template [<name> <flag>] - [(def: #export (<name> data file) - (-> Blob File (Process Any)) - (do io.Monad<Process> - [stream (FileOutputStream::new [(java/io/File::new file) <flag>]) - _ (OutputStream::write [data] stream) - _ (OutputStream::flush [] stream)] - (AutoCloseable::close [] stream)))] - - [append true] - [write false] - ) +(type: #export Permission + #Read + #Write + #Execute) -(def: #export (read file) - (-> File (Process Blob)) - (do io.Monad<Process> - [#let [file' (java/io/File::new file)] - size (java/io/File::length [] file') - #let [data (blob.create (.nat size))] - stream (FileInputStream::new [file']) - bytes-read (InputStream::read [data] stream) - _ (AutoCloseable::close [] stream)] - (if (i/= size bytes-read) - (wrap data) - (io.io (ex.throw could-not-read-all-data file))))) - -(def: #export (size file) - (-> File (Process Nat)) - (do io.Monad<Process> - [size (java/io/File::length [] (java/io/File::new file))] - (wrap (.nat size)))) - -(def: #export (files dir) - (-> File (Process (List File))) - (do io.Monad<Process> - [?files (java/io/File::listFiles [] (java/io/File::new dir))] - (case ?files - (#.Some files) - (monad.map @ (java/io/File::getAbsolutePath []) - (array.to-list files)) - - #.None - (io.throw not-a-directory dir)))) - -(do-template [<name> <method>] - [(def: #export (<name> file) - (-> File (Process Bool)) - (<method> [] (java/io/File::new file)))] - - [exists? java/io/File::exists] - [make-directory java/io/File::mkdirs] - [delete java/io/File::delete] - [file? java/io/File::isFile] - [directory? java/io/File::isDirectory] - [can-read? java/io/File::canRead] - [can-write? java/io/File::canWrite] - [can-execute? java/io/File::canExecute] - ) +(sig: #export (System m) + (: (Monad m) + &monad) + + (: (All [e a] (-> (Exception e) e (m a))) + throw) + + (: (All [a] (-> (m a) (m (Error a)))) + try) + + (do-template [<name>] + [(: (-> Blob File (m Any)) + <name>)] + + [append] [write]) + + (do-template [<name> <output>] + [(: (-> File (m <output>)) + <name>)] + + [read Blob] + [size Nat] + [files (List File)] + [last-modified Instant]) + + (do-template [<name>] + [(: (-> File (m Bool)) + <name>)] -(def: #export (move target source) - (-> File File (Process Bool)) - (java/io/File::renameTo [(java/io/File::new target)] - (java/io/File::new source))) + [file?] + [directory?] + ) -(def: #export (last-modified file) - (-> File (Process i.Instant)) - (do io.Monad<Process> - [millis (java/io/File::lastModified [] (java/io/File::new file))] - (wrap (|> millis d.from-millis i.absolute)))) + (: (-> Permission File (m Bool)) + can?) -(def: #export (modify time file) - (-> i.Instant File (Process Bool)) - (java/io/File::setLastModified [(|> time i.relative d.to-millis)] - (java/io/File::new file))) + (do-template [<name>] + [(: (-> File (m Any)) + <name>)] + + [make-directory] + [delete] + ) + + (: (-> File File (m Any)) + move) + + (: (-> Instant File (m Any)) + modify) + + (: Text + separator) + ) + +(do-template [<name>] + [(exception: #export (<name> {file File}) + (ex.report ["File" file]))] + + [cannot-read-all-data] + [not-a-directory] + [cannot-make-directory] + [cannot-delete] + ) -(def: #export separator Text java/io/File::separator) +(exception: #export (cannot-move {target File} {source File}) + (ex.report ["Source" source] + ["Target" target])) + +(exception: #export (cannot-modify {instant Instant} {file File}) + (ex.report ["Instant" (%instant instant)] + ["File" file])) + +(`` (for {(~~ (static lang/host.jvm)) + (as-is (import: #long java/io/File + (new [String]) + (exists [] #io #try boolean) + (mkdirs [] #io #try boolean) + (delete [] #io #try boolean) + (length [] #io #try long) + (listFiles [] #io #try #? (Array java/io/File)) + (getAbsolutePath [] #io #try String) + (renameTo [java/io/File] #io #try boolean) + (isFile [] #io #try boolean) + (isDirectory [] #io #try boolean) + (lastModified [] #io #try long) + (setLastModified [long] #io #try boolean) + (canRead [] #io #try boolean) + (canWrite [] #io #try boolean) + (canExecute [] #io #try boolean) + (#static separator String)) + + (import: java/lang/AutoCloseable + (close [] #io #try void)) + + (import: java/io/OutputStream + (write [(Array byte)] #io #try void) + (flush [] #io #try void)) + + (import: java/io/FileOutputStream + (new [java/io/File boolean] #io #try)) + + (import: java/io/InputStream + (read [(Array byte)] #io #try int)) + + (import: java/io/FileInputStream + (new [java/io/File] #io #try)) + + (struct: #export JVM@System (System Process) + (def: &monad io.Monad<Process>) + + (def: throw io.throw) + + (def: (try computation) + (do io.Monad<IO> + [outcome computation] + (:: io.Monad<Process> wrap outcome))) + + (do-template [<name> <flag>] + [(def: (<name> data file) + (do io.Monad<Process> + [stream (FileOutputStream::new [(java/io/File::new file) <flag>]) + _ (OutputStream::write [data] stream) + _ (OutputStream::flush [] stream)] + (AutoCloseable::close [] stream)))] + + [append true] + [write false] + ) + + (def: (read file) + (do io.Monad<Process> + [#let [file' (java/io/File::new file)] + size (java/io/File::length [] file') + #let [data (blob.create (.nat size))] + stream (FileInputStream::new [file']) + bytes-read (InputStream::read [data] stream) + _ (AutoCloseable::close [] stream)] + (if (i/= size bytes-read) + (wrap data) + (io.io (ex.throw cannot-read-all-data file))))) + + (def: size + (|>> [] java/io/File::new + (java/io/File::length []) + (:: io.Monad<Process> map .nat))) + + (def: (files dir) + (do io.Monad<Process> + [?files (java/io/File::listFiles [] (java/io/File::new dir))] + (case ?files + (#.Some files) + (monad.map @ (java/io/File::getAbsolutePath []) + (array.to-list files)) + + #.None + (io.throw not-a-directory dir)))) + + (do-template [<name> <method>] + [(def: <name> (|>> [] java/io/File::new (<method> [])))] + + [file? java/io/File::isFile] + [directory? java/io/File::isDirectory] + ) + + (def: (can? permission file) + (let [jvm-file (java/io/File::new file)] + (case permission + #Read (java/io/File::canRead [] jvm-file) + #Write (java/io/File::canWrite [] jvm-file) + #Execute (java/io/File::canExecute [] jvm-file)))) + + (def: last-modified + (|>> [] java/io/File::new + (java/io/File::lastModified []) + (:: io.Monad<Process> map (|>> duration.from-millis instant.absolute)))) + + (do-template [<name> <exception> <method>] + [(def: (<name> subject) + (do io.Monad<IO> + [outcome (<method> [] (java/io/File::new subject))] + (case outcome + (#error.Success true) + (wrap (#error.Success [])) + + _ + (io.throw <exception> [subject]))))] + + [make-directory cannot-make-directory java/io/File::mkdirs] + [delete cannot-delete java/io/File::delete] + ) + + (do-template [<name> <exception> <method> <parameter-pre>] + [(def: (<name> parameter subject) + (do io.Monad<IO> + [outcome (<method> [(|> parameter <parameter-pre>)] + (java/io/File::new subject))] + (case outcome + (#error.Success true) + (wrap (#error.Success [])) + + _ + (io.throw <exception> [parameter subject]))))] + + [move cannot-move java/io/File::renameTo java/io/File::new] + [modify cannot-modify java/io/File::setLastModified (<| duration.to-millis instant.relative)] + ) + + (def: separator java/io/File::separator) + )) + })) + +(def: #export (exists? System<m> file) + (All [m] (-> (System m) File (m Bool))) + (|> file + (do> (:: System<m> &monad) + [(:: System<m> file?)] + [(if> [(wrap true)] + [(:: System<m> directory? file)])]))) |