Skip to content
Draft
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ fn main() {
.flag("-diag-suppress=177") // variable was declared but never referenced
.flag("-diag-suppress=550") // variable was set but never used
.flag("-diag-suppress=20039") // a __host__ function redeclared with __device__, hence treated as a __host__ __device__ function
.flag("-diag-suppress=68") // integer conversion resulted in a change of sign
.flag("-diag-suppress=2464") // conversion from a string literal to "char *" is deprecated
.compile("hvm-cu");

println!("cargo:rustc-cfg=feature=\"cuda\"");
Expand Down
4 changes: 2 additions & 2 deletions src/hvm.c
Original file line number Diff line number Diff line change
Expand Up @@ -809,7 +809,7 @@ static inline Port enter(Net* net, Port var) {
}

// Atomically Links `A ~ B`.
static inline void link(Net* net, TM* tm, Port A, Port B) {
static inline void link_ports(Net* net, TM* tm, Port A, Port B) {
// Attempts to directionally point `A ~> B`
while (true) {
// If `A` is NODE: swap `A` and `B`, and continue
Expand Down Expand Up @@ -842,7 +842,7 @@ static inline void link(Net* net, TM* tm, Port A, Port B) {

// Links `A ~ B` (as a pair).
static inline void link_pair(Net* net, TM* tm, Pair AB) {
link(net, tm, get_fst(AB), get_snd(AB));
link_ports(net, tm, get_fst(AB), get_snd(AB));
}

// Interactions
Expand Down
76 changes: 76 additions & 0 deletions src/run.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#include <dlfcn.h>
#include <errno.h>
#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
#include <ftw.h>
#include "hvm.c"

// Readback: λ-Encoded Ctr
Expand Down Expand Up @@ -716,6 +719,76 @@ Port io_dl_close(Net* net, Book* book, Port argm) {
return inject_ok(net, new_port(ERA, 0));
}

// Deletes a single file or an empty directory at the specified path.
// Returns Ok(None) if successful, or Err(reason) if an error occurs.
// This function attempts to remove both files and empty directories without
// first checking the type of the path.
// Returns: Result<*, IOError<i24>>
Port io_remove(Net* net, Book* book, Port argm) {
Str path = readback_str(net, book, argm);

int result = remove(path.buf);
free(path.buf);

if (result == 0) {
return inject_ok(net, new_port(ERA, 0));
} else {
return inject_io_err_inner(net, new_port(NUM, new_i24(errno)));
}
}

int remove_all_aux(const char* path, const struct stat* stat, int flags, struct FTW* ftw) {
return remove(path);
}

int remove_all(const char* path) {
struct stat st;
if (stat(path, &st) != 0) {
return remove(path);
}
if (S_ISDIR(st.st_mode)) {
return nftw(path, remove_all_aux, 32, FTW_DEPTH | FTW_PHYS);
} else {
return remove(path);
}
}

// Removes any file or directory recursively at the specified path.
// it will delete the directory and all its contents.
// Returns Ok(None) if successful, or Err(reason) if an error occurs.
// Note: For non-recursive deletion of an empty directory,
// this function behaves the same as delete_file(path).
// Returns: Result<*, IOError<i24>>
Port io_remove_all(Net* net, Book* book, Port argm) {
Str path = readback_str(net, book, argm);

int res = remove_all(path.buf);
free(path.buf);

if (0 == res) {
return inject_ok(net, new_port(ERA, 0));
} else {
return inject_io_err_inner(net, new_port(NUM, new_i24(errno)));
}
}

// Creates a new directory with the given path.
// Returns Ok(None) if sucessfull, or Err(reason) if an error occurs.
// Returns: Result<*, IOError<i24>>
Port io_mkdir(Net* net, Book* book, Port argm) {
Str name = readback_str(net, book, argm);

const mode_t mode = 0777;
int status = mkdir(name.buf, mode);
free(name.buf);

if (status) {
return inject_io_err_inner(net, new_port(NUM, new_i24(errno)));
} else {
return inject_ok(net, new_port(ERA, 0));
}
}

// Book Loader
// -----------

Expand All @@ -731,6 +804,9 @@ void book_init(Book* book) {
book->ffns_buf[book->ffns_len++] = (FFn){"DL_OPEN", io_dl_open};
book->ffns_buf[book->ffns_len++] = (FFn){"DL_CALL", io_dl_call};
book->ffns_buf[book->ffns_len++] = (FFn){"DL_CLOSE", io_dl_open};
book->ffns_buf[book->ffns_len++] = (FFn){"RM", io_remove};
book->ffns_buf[book->ffns_len++] = (FFn){"RM_ALL", io_remove_all};
book->ffns_buf[book->ffns_len++] = (FFn){"MKDIR", io_mkdir};
}

// Monadic IO Evaluator
Expand Down
77 changes: 77 additions & 0 deletions src/run.cu
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
#include <dlfcn.h>
#include <errno.h>
#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
#include <string.h>
#include <ftw.h>
#include "hvm.cu"

// Readback: λ-Encoded Ctr
Expand Down Expand Up @@ -834,6 +838,76 @@ Port io_dl_close(GNet* gnet, Book* book, Port argm) {
return gnet_inject_ok(gnet, new_port(ERA, 0));
}

// Removes a single file or an empty directory at the specified path.
// Returns Ok(None) if successful, or Err(reason) if an error occurs.
// This function attempts to remove both files and empty directories without
// first checking the type of the path.
// Returns: Result<*, IOError<i24>>
Port io_remove(GNet* gnet, Port argm) {
Str s = gnet_readback_str(gnet, argm);

int result = remove(s.buf);
free(s.buf);

if (result == 0) {
return gnet_inject_ok(gnet, new_port(ERA, 0));
} else {
return gnet_inject_io_err_inner(gnet, new_port(NUM, new_i24(errno)));
}
}

int remove_all_aux(const char* path, const struct stat* stat, int flags, struct FTW* ftw) {
return remove(path);
}

int remove_all(const char* path) {
struct stat st;
if (stat(path, &st) != 0) {
return remove(path);
}
if (S_ISDIR(st.st_mode)) {
return nftw(path, remove_all_aux, 32, FTW_DEPTH | FTW_PHYS);
} else {
return remove(path);
}
}

// Removes any file or directory recursively at the specified path.
// it will delete the directory and all its contents.
// Returns Ok(None) if successful, or Err(reason) if an error occurs.
// Note: For non-recursive deletion of an empty directory,
// this function behaves the same as delete_file(path).
// Returns: Result<*, IOError<i24>>
Port io_remove_all(GNet* gnet, Port argm) {
Str path = gnet_readback_str(gnet, argm);

int res = remove_all(path.buf);
free(path.buf);

if (0 == res) {
return gnet_inject_ok(gnet, new_port(ERA, 0));
} else {
return gnet_inject_io_err_inner(gnet, new_port(NUM, new_i24(errno)));
}
}

// Creates a new directory with the given path.
// Returns Ok(None) if sucessfull, or Err(reason) if an error occurs.
// Returns: Result<*, IOError<i24>>
Port io_mkdir(GNet* gnet, Port argm) {
Str name = gnet_readback_str(gnet, argm);

const mode_t mode = 0777;
int status = mkdir(name.buf, mode);
free(name.buf);

if (status) {
return gnet_inject_io_err_inner(gnet, new_port(NUM, new_i24(errno)));
} else {
return gnet_inject_ok(gnet, new_port(ERA, 0));
}
}

void book_init(Book* book) {
book->ffns_buf[book->ffns_len++] = (FFn){"READ", io_read};
book->ffns_buf[book->ffns_len++] = (FFn){"OPEN", io_open};
Expand All @@ -846,6 +920,9 @@ void book_init(Book* book) {
book->ffns_buf[book->ffns_len++] = (FFn){"DL_OPEN", io_dl_open};
book->ffns_buf[book->ffns_len++] = (FFn){"DL_CALL", io_dl_call};
book->ffns_buf[book->ffns_len++] = (FFn){"DL_CLOSE", io_dl_open};
book->ffns_buf[book->ffns_len++] = (FFn){"RM", io_remove};
book->ffns_buf[book->ffns_len++] = (FFn){"RM_ALL", io_remove_all};
book->ffns_buf[book->ffns_len++] = (FFn){"MKDIR", io_mkdir};

cudaMemcpyToSymbol(BOOK, book, sizeof(Book));
}
Expand Down
19 changes: 19 additions & 0 deletions tests/programs/io/mkdir.bend
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#{
Creates the batata directory and then removes it.
#}

test-io = 1

mkdir path =
(call "MKDIR" path)

rm_all path =
(call "RM_ALL" path)

main =
let path = "./batata"
with IO {
ask * = (mkdir path)
ask s = (rm_all path)
(wrap s)
}
16 changes: 16 additions & 0 deletions tests/programs/io/remove_all_file.bend
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#{
Calls the rm_all function with a file path as argument.
#}

test-io = 1

rm_all path =
(call "RM_ALL" path)

main =
let temp = "./temp.txt"
with IO {
ask * = (IO/FS/write_file temp (String/encode_utf8 "Contents"))
ask s = (rm_all temp)
(wrap s)
}
35 changes: 35 additions & 0 deletions tests/programs/io/remove_all_recursive.bend
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#{
Creates the following tree structure and then removes A and its children.
A
|-- a.txt
|-- AA
| `-- aa.txt
`-- AB
`-- ab.txt
#}

test-io = 1

mkdir path =
(call "MKDIR" path)

rm_all path =
(call "RM_ALL" path)

test =
with IO {
ask * = (mkdir "A")
ask * = (mkdir "A/AA")
ask * = (mkdir "A/AB")
ask * = (IO/FS/write_file "A/a.txt" (String/encode_utf8 "a"))
ask * = (IO/FS/write_file "A/AA/aa.txt" (String/encode_utf8 "aa"))
ask * = (IO/FS/write_file "A/AB/ab.txt" (String/encode_utf8 "ab"))
ask s = (rm_all "./A")
(wrap s)
}

main =
with IO {
ask res = (test)
(wrap res)
}
18 changes: 18 additions & 0 deletions tests/programs/io/remove_empty_dir.bend
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#{
Uses the rm function to remove an empty directory.
#}

test-io = 1

mkdir path =
(call "MKDIR" path)

rm path =
(call "RM" path)

main =
with IO {
ask * = (mkdir "temp")
ask s = (rm "temp")
(wrap s)
}
16 changes: 16 additions & 0 deletions tests/programs/io/remove_file.bend
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#{
Creates a temporary file and then removes it.
#}

test-io = 1

rm path =
(call "RM" path)

main =
let path = "./temp.txt"
with IO {
ask * = (IO/FS/write_file path (String/encode_utf8 "Contents"))
ask s = (rm path)
(wrap s)
}
15 changes: 15 additions & 0 deletions tests/programs/io/remove_non_existing_file.bend
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#{
Tries to remove a non existing file.
#}

test-io = 1

rm path =
(call "RM" path)

main =
use path = "./non_existing.txt"
with IO {
ask s = (rm path)
(wrap s)
}