From b9fb9b18e983a3042322833a0a695ec04f1f019f Mon Sep 17 00:00:00 2001 From: maxonfjvipon Date: Mon, 20 Jan 2025 15:02:26 +0300 Subject: [PATCH] bug(#3481): file dir and path --- eo-runtime/src/main/eo/org/eolang/fs/dir.eo | 54 ++++---- eo-runtime/src/main/eo/org/eolang/fs/file.eo | 121 +++++++++--------- eo-runtime/src/main/eo/org/eolang/fs/path.eo | 114 +++++++++-------- .../src/main/eo/org/eolang/fs/tmpdir.eo | 60 ++++----- .../src/main/eo/org/eolang/math/random.eo | 10 +- .../src/main/eo/org/eolang/sys/posix.eo | 1 - .../src/main/eo/org/eolang/sys/win32.eo | 1 - eo-runtime/src/main/eo/org/eolang/txt/text.eo | 11 +- .../EOsys/Posix/GettimeofdaySyscall.java | 2 +- .../EOsys/Win32/GetSystemTimeFuncCall.java | 2 +- .../src/test/eo/org/eolang/fs/dir-tests.eo | 9 +- 11 files changed, 193 insertions(+), 192 deletions(-) diff --git a/eo-runtime/src/main/eo/org/eolang/fs/dir.eo b/eo-runtime/src/main/eo/org/eolang/fs/dir.eo index 26144fc9b1..c4b6453f8c 100644 --- a/eo-runtime/src/main/eo/org/eolang/fs/dir.eo +++ b/eo-runtime/src/main/eo/org/eolang/fs/dir.eo @@ -31,18 +31,20 @@ # Directory in the file system. # Apparently every directory is a file. [file] > dir + $ > as-dir $.file > @ true > is-directory # Makes a directory together with all required # parent directories and returns the created directory. [] > made - if. > @ - ^.exists - ^ - seq * - mkdir + as-dir. > @ + if. + ^.exists ^ + seq * + mkdir + ^ # Makes a directory together with all required # parent directories. @@ -59,40 +61,38 @@ # Deletes directory and all files in it, recursively. # Returns the deleted directory. [] > deleted - (^.walk "**").at.^ > walked - walked.length > len! - if. > @ - ^.exists - seq * - rec-delete walked 0 + as-dir. > @ + if. + ^.exists + seq * + rec-delete (walk "**").as-tuple + ^ ^ - ^ # Deletes files and directories in current directory recursively. # Returns `true`. # # Attention! The object is for internal usage only, please # don't use the object programmatically outside of `dir` object. - [tup index] > rec-delete + [tup] > rec-delete if. > @ - ^.len.eq index + tup.length.eq 0 true seq * - tup.value.deleted.exists - ^.rec-delete - tup.prev - index.plus 1 + tup.value.deleted + rec-delete tup.prev # Creates an empty temporary file in the current directory. [] > tmpfile - if. > @ - ^.exists - QQ.fs.file - string touch.as-bytes - error - sprintf - "Directory %s does not exist, can't create temporary file" - * ^.path + as-file. > @ + if. + ^.exists + QQ.fs.file + touch.as-bytes + error + sprintf + "Directory %s does not exist, can't create temporary file" + * path # Creates an empty temporary file in the current directory and # returns absolute path to it as `string`. @@ -107,4 +107,4 @@ error > @ sprintf "The file %s is a directory, can't open for I/O operations" - * ^.path + * path diff --git a/eo-runtime/src/main/eo/org/eolang/fs/file.eo b/eo-runtime/src/main/eo/org/eolang/fs/file.eo index c7f03426fc..f159249d90 100644 --- a/eo-runtime/src/main/eo/org/eolang/fs/file.eo +++ b/eo-runtime/src/main/eo/org/eolang/fs/file.eo @@ -31,7 +31,10 @@ # The file object in the filesystem. [path] > file + $ > as-file $.path > @ + # Convert the `file` to the `path`. + (QQ.fs.path path).determined > as-path # Returns `true` if current file is a directory, returns `false` otherwise. [] > is-directory /org.eolang.bool @@ -43,12 +46,13 @@ # If current file does not exist - create an empty file # in filesystem and returns it. [] > touched - if. > @ - ^.exists - ^ - seq * - touch + as-file. > @ + if. + exists ^ + seq * + touch + ^ # Creates new empty file. # @@ -59,12 +63,13 @@ # If current file exists - deletes it and returns it. # If current file does not exist - just returns it. [] > deleted - if. > @ - ^.exists - seq * - delete + as-file. > @ + if. + exists + seq * + delete + ^ ^ - ^ # Deletes the file and returns `true`. # @@ -77,8 +82,8 @@ # Move current file to `target`, making and returning a new `file` from it. [target] > moved - QQ.fs.file > @ - string move.as-bytes + as-file. > @ + file move # Tries to move file from `^.path` to `target` # and returns path of moved file as `string`. @@ -88,9 +93,6 @@ # don't use the object programmatically outside of `file` object. [] > move /org.eolang.string - # Convert the `file` to the `path`. - (QQ.fs.path ^.path).determined > [] > as-path - # Opens the file. # # The first argument `mode` defines the operations that are allowed on the file @@ -124,12 +126,12 @@ # closes the file stream and returns an original file object. [mode scope] > open mode > access! - access.eq "r" > read - access.eq "w" > write - access.eq "a" > append - access.eq "r+" > read-write - access.eq "w+" > write-read - access.eq "a+" > read-append + (access.eq "r").as-bool > read + (access.eq "w").as-bool > write + (access.eq "a").as-bool > append + (access.eq "r+").as-bool > read-write + (access.eq "w+").as-bool > write-read + (access.eq "a+").as-bool > read-append as-bool. > can-read or. read.or read-write @@ -144,31 +146,32 @@ read.or read-write as-bool. > truncate write.or write-read - if. > @ - can-read.not.and can-write.not - error "Wrong access mod. Only next modes are available: 'r', 'w', 'a', 'r+', 'w+', 'a+'" + as-file. > @ if. - ^.exists.not - if. - must-exists - error - sprintf - "File must exist for given access mod: '%s'" - * access - seq * - ^.touched.touch - process-file - ^ + can-read.not.and can-write.not + error "Wrong access mod. Only next modes are available: 'r', 'w', 'a', 'r+', 'w+', 'a+'" if. - truncate - seq * - ^.deleted.delete - ^.touched.touch - process-file - ^ - seq * - process-file - ^ + exists.not + if. + must-exists + error + sprintf + "File must exist for given access mod: '%s'" + * access + seq * + touched.touch + process-file + ^ + if. + truncate + seq * + deleted.delete + touched.touch + process-file + ^ + seq * + process-file + ^ # Process current file in the provided scope. # @@ -191,14 +194,14 @@ # Returns new instance of `input-block` with `buffer` read from file, or # returns `error` if access mode does not allow reading operations. [size] > read - ((input-block --).read size).self > @ + ((input-block --).read size).this > @ # File input block # # Attention! The object is for internal usage only, please # don't use the object programmatically outside of `file` object. [buffer] > input-block - $ > self + $ > this buffer > @ # Read `size` amount of bytes from file input stream. @@ -206,18 +209,18 @@ # returns `error` if provided access mode does not allow reading operations. [size] > read ^.^.read-bytes size > read-bytes! - self. > @ + this. > @ if. - ^.^.^.^.can-read.not + can-read.not [] >> - $ > self + $ > this error > @ sprintf "Can't read from file with provided access mode '%s'" - * ^.^.^.^.^.access + * access seq * read-bytes - ^.^.input-block read-bytes + input-block read-bytes # Bytes read from file input stream # @@ -231,14 +234,14 @@ # Returns new instance of `output-block` ready to write again, or # returns an error if provided access mode does not allow writing operations. [buffer] > write - (output-block.write buffer).self > @ + (output-block.write buffer).this > @ # File output block. # # Attention! The object is for internal usage only, please # don't use the object programmatically outside of `file` object. [] > output-block - $ > self + $ > this true > @ # Write given `buffer` to file output stream. @@ -247,18 +250,18 @@ # Returns new instance of `output-block` ready to write again, or # returns an error if provided access mode does not allow writing operations. [buffer] > write - self. > @ + this. > @ if. - ^.^.^.^.can-write.not + can-write.not [] >> - $ > self + $ > this error > @ sprintf "Can't write to file with provided access mode '%s'" - * ^.^.^.^.^.access + * access seq * - ^.^.written-bytes buffer - ^.^.output-block + written-bytes buffer + output-block # Bytes written to file output stream. # diff --git a/eo-runtime/src/main/eo/org/eolang/fs/path.eo b/eo-runtime/src/main/eo/org/eolang/fs/path.eo index 3aca5b214a..d067baa69e 100644 --- a/eo-runtime/src/main/eo/org/eolang/fs/path.eo +++ b/eo-runtime/src/main/eo/org/eolang/fs/path.eo @@ -20,6 +20,8 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ++alias org.eolang.fs.dir ++alias org.eolang.fs.file +alias org.eolang.sys.os +alias org.eolang.structs.list +alias org.eolang.txt.regex @@ -47,13 +49,13 @@ string > joined-path as-bytes. joined. - text ^.separator + text separator paths normalized. > @ if. os.is-windows - ^.win32 joined-path - ^.posix joined-path + win32 joined-path + posix joined-path # The system-dependent default name-separator character. # On UNIX systems the value of this field is "/"; @@ -61,30 +63,30 @@ [] > separator if. > @ os.is-windows - ^.win32.separator - ^.posix.separator + win32.separator + posix.separator # POSIX specified path. # A standardized way to represent file or directory locations in a Unix-like system. [uri] > posix $ > determined "/" > separator - (QQ.fs.file uri).size.^ > as-file - (QQ.fs.dir (QQ.fs.file uri)).made.^ > as-dir + (file uri).as-file > as-file + (dir (QQ.fs.file uri)).as-dir > as-dir uri > @ # Returns `true` if current path is absolute - starts with '/' char. [] > is-absolute and. > @ - ^.uri.length.gt 0 - (^.uri.as-bytes.slice 0 1).eq ^.separator + uri.length.gt 0 + (uri.as-bytes.slice 0 1).eq separator # Return new `path` with normalized uri. # Normalization includes: # - converting multiple slashes into a single slash. # - resolving "." (current directory) and ".." (parent directory) segments. [] > normalized - ^.uri.as-bytes > uri-as-bytes + uri > uri-as-bytes! ^.is-absolute.as-bool > is-absolute and. > has-trailing-slash uri-as-bytes.size.gt 0 @@ -92,14 +94,14 @@ uri-as-bytes.slice uri-as-bytes.size.plus -1 1 - ^.separator + separator joined. > path - text ^.separator + text separator reduced. list split. - text ^.uri - ^.separator + text uri + separator * [accum segment] >> if. > @ @@ -110,7 +112,7 @@ (accum.value.eq "..").not accum.prev if. - ^.is-absolute.not + is-absolute.not accum.with segment accum if. @@ -121,19 +123,19 @@ accum.with segment as-bytes. > normalized if. - ^.uri.length.eq 0 + uri.length.eq 0 "." concat. if. is-absolute - ^.separator.concat path + separator.concat path path if. has-trailing-slash - ^.separator + separator -- determined. > @ - ^.^.posix + posix if. normalized.eq "//" "/" @@ -157,15 +159,15 @@ [other] > resolved other.as-bytes > other-as-bytes normalized. > @ - ^.^.posix + posix string if. - (other-as-bytes.slice 0 1).eq ^.separator + (other-as-bytes.slice 0 1).eq separator other-as-bytes concat. concat. - ^.uri - ^.separator + uri + separator other-as-bytes # Takes the base name from the provided `path`, for example: @@ -184,11 +186,11 @@ # is "/" (regular slash) in Unix OS: # With the `path` "/tmp/var/hello\world" `base-name` returns `hello\world`. [] > basename - ^.uri > pth! + uri > pth! text > txt string pth plus. > slice-start-idx! - txt.last-index-of ^.separator + txt.last-index-of separator 1 string > @ if. @@ -217,7 +219,7 @@ # and returns substring after "." if it's found. # If it's not - empty string is returned. [] > extname - ^.basename > base! + basename > base! text > txt string base txt.last-index-of "." > slice-start-idx! @@ -250,10 +252,10 @@ # is "/" (regular slash) in Unix OS: # With the `path` "/tmp/v\a\r/hello" `dir-name` returns `/tmp/v\a\r`. [] > dirname - ^.uri > pth! + uri > pth! text > txt string pth - txt.last-index-of ^.separator > len! + txt.last-index-of separator > len! string > @ if. or. @@ -283,8 +285,8 @@ [uri] > validated $ > determined ^.separator > separator - (QQ.fs.file uri).size.^ > as-file - (QQ.fs.dir (QQ.fs.file uri)).made.^ > as-dir + (file uri).as-file > as-file + (dir (file uri)).as-dir > as-dir uri > @ # Returns `true` if given `uri` is drive relative which means it @@ -297,7 +299,7 @@ uri > uri-as-bytes! and. > @ uri-as-bytes.size.gt 0 - (uri-as-bytes.slice 0 1).eq ^.separator + (uri-as-bytes.slice 0 1).eq separator # Replaces slashes '/' with valid windows separator '\'. [uri] > separated-correctly @@ -306,7 +308,7 @@ string uri-as-bytes pth.replaced > replaced! regex "/\\//" - ^.separator + separator if. > @ (pth.index-of path.posix.separator).eq -1 string uri-as-bytes @@ -321,10 +323,10 @@ uri-as-bytes.size.eq 0 false or. - ^.is-root-relative uri-as-bytes + is-root-relative uri-as-bytes and. uri-as-bytes.size.gt 1 - ^.is-drive-relative uri-as-bytes + is-drive-relative uri-as-bytes # Return new `path` with normalized uri. # Normalization includes: @@ -332,7 +334,7 @@ # - resolving "." (current directory) and ".." (parent directory) segments. # - handling of drive letters in Windows. [] > normalized - ^.uri > uri-as-bytes! + uri > uri-as-bytes! (^.is-drive-relative uri-as-bytes).as-bool > is-drive-relative (^.is-root-relative uri-as-bytes).as-bool > is-root-relative if. > driveless! @@ -347,9 +349,9 @@ uri-as-bytes.slice uri-as-bytes.size.plus -1 1 - ^.separator + separator joined. > path! - text ^.separator + text separator reduced. list split. @@ -366,8 +368,8 @@ accum.prev if. and. - ^.is-root-relative.not - ^.is-drive-relative.not + is-root-relative.not + is-drive-relative.not accum.with segment accum if. @@ -385,23 +387,23 @@ if. is-drive-relative if. - (driveless.slice 0 1).eq ^.separator - ^.uri.slice 0 3 - ^.uri.slice 0 2 + (driveless.slice 0 1).eq separator + uri.slice 0 3 + uri.slice 0 2 if. is-root-relative - ^.separator + separator -- path if. has-trailing-slash - ^.separator + separator -- determined. > @ - ^.^.validated + validated if. normalized.eq "\\\\" - ^.separator + separator string normalized # Resolves `other` path against `^.uri` and returns as new `path` from it. @@ -426,12 +428,12 @@ # |--------------------|----------------|-------------------| # URI Resolution Rules. [other] > resolved - ^.uri > uri-as-bytes! - ^.separated-correctly other > valid-other! + uri > uri-as-bytes! + separated-correctly other > valid-other! (^.is-drive-relative valid-other).as-bool > other-is-drive-relative (^.is-root-relative valid-other).as-bool > other-is-root-relative normalized. > @ - ^.^.validated + validated string if. other-is-drive-relative @@ -439,7 +441,7 @@ if. other-is-root-relative if. - ^.is-drive-relative uri-as-bytes + is-drive-relative uri-as-bytes concat. uri-as-bytes.slice 0 2 valid-other @@ -447,7 +449,7 @@ concat. concat. uri-as-bytes - ^.separator + separator valid-other # Takes the base name from the provided `path`, for example: @@ -466,11 +468,11 @@ # is "/" (regular slash) in Unix OS: # With the `path` "/tmp/var/hello\world" `base-name` returns `hello\world`. [] > basename - ^.uri > pth! + uri > pth! text > txt string pth plus. > slice-start-idx! - txt.last-index-of ^.separator + txt.last-index-of separator 1 string > @ if. @@ -499,7 +501,7 @@ # and returns substring after "." if it's found. # If it's not - empty string is returned. [] > extname - ^.basename > base! + basename > base! text > txt string base txt.last-index-of "." > slice-start-idx! @@ -528,10 +530,10 @@ # |------------------------------|--------------------| # Extracting Directory Names from File Paths. [] > dirname - ^.uri > pth! + uri > pth! text > txt string pth - txt.last-index-of ^.separator > len! + txt.last-index-of separator > len! string > @ if. or. diff --git a/eo-runtime/src/main/eo/org/eolang/fs/tmpdir.eo b/eo-runtime/src/main/eo/org/eolang/fs/tmpdir.eo index 8a6081ea09..cce5dc8cc1 100644 --- a/eo-runtime/src/main/eo/org/eolang/fs/tmpdir.eo +++ b/eo-runtime/src/main/eo/org/eolang/fs/tmpdir.eo @@ -39,37 +39,39 @@ # takes the first environment variable in the list TMP, TEMP, USERPROFILE. # If none of these are found, it returns the Windows directory (C:\Windows). [] > tmpdir - dir > @ - file - string - [] > os-tmp-dir! - getenv "TMPDIR" > tmpdir! - getenv "TMP" > tmp! - getenv "TEMP" > temp! - getenv "TEMPDIR" > tempdir! - getenv "USERPROFILE" > userprofile! - if. > @ - os.is-windows - if. - tmp.eq "" + as-dir. > @ + dir + file + string + [] > os-tmp-dir! + getenv "TMPDIR" > tmpdir! + getenv "TMP" > tmp! + getenv "TEMP" > temp! + getenv "TEMPDIR" > tempdir! + getenv "USERPROFILE" > userprofile! + -- > empty + if. > @ + os.is-windows if. - temp.eq "" + tmp.eq empty if. - userprofile.eq "" - "C:\\Windows" - userprofile - temp - tmp - if. - tmpdir.eq "" - if. - tmp.eq "" - if. - temp.eq "" + temp.eq empty if. - tempdir.eq "" - "/tmp" - tempdir + userprofile.eq empty + "C:\\Windows" + userprofile temp tmp - tmpdir + if. + tmpdir.eq empty + if. + tmp.eq empty + if. + temp.eq empty + if. + tempdir.eq empty + "/tmp" + tempdir + temp + tmp + tmpdir diff --git a/eo-runtime/src/main/eo/org/eolang/math/random.eo b/eo-runtime/src/main/eo/org/eolang/math/random.eo index ccd60ceed2..d306029d73 100644 --- a/eo-runtime/src/main/eo/org/eolang/math/random.eo +++ b/eo-runtime/src/main/eo/org/eolang/math/random.eo @@ -80,15 +80,9 @@ as-i64. if. os.is-windows - milliseconds. - win32 - "GetSystemTime" - * win32.system-time + (win32 "GetSystemTime" *).milliseconds [] - output. > timeval - posix - "gettimeofday" - * posix.timeval + (posix "gettimeofday" *).output > timeval plus. > @ timeval.tv-sec.times 1000 as-number. diff --git a/eo-runtime/src/main/eo/org/eolang/sys/posix.eo b/eo-runtime/src/main/eo/org/eolang/sys/posix.eo index 0f89799645..cb90faff51 100644 --- a/eo-runtime/src/main/eo/org/eolang/sys/posix.eo +++ b/eo-runtime/src/main/eo/org/eolang/sys/posix.eo @@ -46,7 +46,6 @@ # Timeval structure for "gettimeofday" syscall. # Here `tv-sec` is seconds since Jan 1, 1970, and `tv-usec` - microseconds. [tv-sec tv-usec] > timeval - $ > self # The posix `sockaddr_in` structure. [sin-family sin-port sin-addr] > sockaddr-in diff --git a/eo-runtime/src/main/eo/org/eolang/sys/win32.eo b/eo-runtime/src/main/eo/org/eolang/sys/win32.eo index 7916134d38..2adefe1b11 100644 --- a/eo-runtime/src/main/eo/org/eolang/sys/win32.eo +++ b/eo-runtime/src/main/eo/org/eolang/sys/win32.eo @@ -52,7 +52,6 @@ # Structure for "GetSystemTime" function call. [year month day day-of-week hour minute second milliseconds] > system-time - $ > self # The win32 `sockaddr_in` structure. [sin-family sin-port sin-addr] > sockaddr-in diff --git a/eo-runtime/src/main/eo/org/eolang/txt/text.eo b/eo-runtime/src/main/eo/org/eolang/txt/text.eo index 0db491c003..1c6d9dc1e5 100644 --- a/eo-runtime/src/main/eo/org/eolang/txt/text.eo +++ b/eo-runtime/src/main/eo/org/eolang/txt/text.eo @@ -414,7 +414,7 @@ # Returns a `tuple` of `strings`, separated by a given `delimiter`. [delimiter] > split delimiter > delim! - origin.as-bytes > self-as-bytes + origin > self-as-bytes! self-as-bytes.size > len! if. > @ len.eq 0 @@ -430,17 +430,16 @@ start current.minus start if. - eq. - delim + delim.eq self-as-bytes.slice current 1 rec-split with-substr - current.plus 1 - current.plus 1 + (current.plus 1).as-number + (current.plus 1).as-number rec-split accum start - current.plus 1 + (current.plus 1).as-number # Returns concatenation of all `other` strings. # Here `others` must be a `tuple` of `strings`. diff --git a/eo-runtime/src/main/java/EOorg/EOeolang/EOsys/Posix/GettimeofdaySyscall.java b/eo-runtime/src/main/java/EOorg/EOeolang/EOsys/Posix/GettimeofdaySyscall.java index 972f585077..d139fbebe1 100644 --- a/eo-runtime/src/main/java/EOorg/EOeolang/EOsys/Posix/GettimeofdaySyscall.java +++ b/eo-runtime/src/main/java/EOorg/EOeolang/EOsys/Posix/GettimeofdaySyscall.java @@ -58,7 +58,7 @@ public Phi make(final Phi... params) { final Phi result = this.posix.take("return").copy(); final GettimeofdaySyscall.Timeval timeval = new GettimeofdaySyscall.Timeval(); result.put(0, new Data.ToPhi(CStdLib.INSTANCE.gettimeofday(timeval, null))); - final Phi struct = params[0].take("self"); + final Phi struct = this.posix.take("timeval"); struct.put(0, new Data.ToPhi(timeval.sec)); struct.put(1, new Data.ToPhi(timeval.usec)); result.put(1, struct); diff --git a/eo-runtime/src/main/java/EOorg/EOeolang/EOsys/Win32/GetSystemTimeFuncCall.java b/eo-runtime/src/main/java/EOorg/EOeolang/EOsys/Win32/GetSystemTimeFuncCall.java index d4c4e12d33..bd2fd67de7 100644 --- a/eo-runtime/src/main/java/EOorg/EOeolang/EOsys/Win32/GetSystemTimeFuncCall.java +++ b/eo-runtime/src/main/java/EOorg/EOeolang/EOsys/Win32/GetSystemTimeFuncCall.java @@ -60,7 +60,7 @@ public Phi make(final Phi... params) { final GetSystemTimeFuncCall.SystemTime time = new GetSystemTimeFuncCall.SystemTime(); Kernel32.INSTANCE.GetSystemTime(time); result.put(0, new Data.ToPhi(true)); - final Phi struct = params[0].take("self"); + final Phi struct = this.win.take("system-time"); struct.put(0, new Data.ToPhi(time.year)); struct.put(1, new Data.ToPhi(time.month)); struct.put(2, new Data.ToPhi(time.day)); diff --git a/eo-runtime/src/test/eo/org/eolang/fs/dir-tests.eo b/eo-runtime/src/test/eo/org/eolang/fs/dir-tests.eo index 21abf6ccd6..1967d3def4 100644 --- a/eo-runtime/src/test/eo/org/eolang/fs/dir-tests.eo +++ b/eo-runtime/src/test/eo/org/eolang/fs/dir-tests.eo @@ -30,10 +30,13 @@ # This unit test is supposed to check the functionality of the corresponding object. [] > bound-tmpfile-does-not-recreates-file - tmpdir.tmpfile > f - f.path.eq f.path > @ + tmpdir.tmpfile.as-file > f + QQ.io.stdout > @ + QQ.txt.sprintf + "%s %s\n" + * f.path f.path -# test. +# This unit test is supposed to check the functionality of the corresponding object. [] > makes-new-directory (tmpdir.tmpfile.deleted.as-path.resolved "foo-new").as-dir.made > d and. > @