diff --git a/CHANGELOG.md b/CHANGELOG.md index bdb535a9..b2964a2f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ and this project does not currently adhere to a particular versioning scheme. - Add `log` and `atan2` builtin functions. ([#583][gh-583]) - Add `to_f24`, `to_u24` and `to_i24` number casting builtin functions. ([#582][gh-582]) - Add `IO/sleep` builtin function to sleep for a given amount of seconds as a float. ([#581][gh-581]) +- Add primitive file IO functions `IO/FS/{read, write, seek, open, close}`. ([#573][gh-573]) ## [0.2.35] - 2024-06-06 @@ -344,6 +345,7 @@ and this project does not currently adhere to a particular versioning scheme. [gh-526]: https://github.com/HigherOrderCO/Bend/issues/526 [gh-528]: https://github.com/HigherOrderCO/Bend/issues/528 [gh-581]: https://github.com/HigherOrderCO/Bend/issues/581 +[gh-573]: https://github.com/HigherOrderCO/Bend/issues/573 [gh-582]: https://github.com/HigherOrderCO/Bend/issues/582 [gh-583]: https://github.com/HigherOrderCO/Bend/issues/583 [gh-586]: https://github.com/HigherOrderCO/Bend/issues/586 diff --git a/docs/builtins.md b/docs/builtins.md index d20dca4d..0f9fa60e 100644 --- a/docs/builtins.md +++ b/docs/builtins.md @@ -225,7 +225,74 @@ A Natural Number can be written with literals with a `#` before the literal numb ## IO -IO Functions are in the **next milestone**! +The basic builtin IO functions are under development and will be stable in the next milestone. + +Here is the current list of functions, but be aware that they may change in the near future. + +### File IO + +#### File open +```python +def IO/FS/open(path, mode) +``` + +Opens a file with with `path` being given as a string and `mode` being a string with the mode to open the file in. The mode should be one of the following: +- `"r"`: Read mode +- `"w"`: Write mode (write at the beginning of the file, overwriting any existing content) +- `"a"`: Append mode (write at the end of the file) +- `"r+"`: Read and write mode +- `"w+"`: Read and write mode +- `"a+"`: Read and append mode + +Returns an U24 with the file descriptor. File descriptors are not necessarily the same as the ones assigned by the operating system, but rather unique identifiers internal to Bend's runtime. + +#### File descriptors for standard files + +The standard input/output files are always open and assigned the following file descriptors: +- `IO/FS/STDIN = 0`: Standard input +- `IO/FS/STDOUT = 1`: Standard output +- `IO/FS/STDERR = 2`: Standard error + +#### File close +```python +def IO/FS/close(file) +``` + +Closes the file with the given `file` descriptor. + +#### File read +```python +def IO/FS/read(file, num_bytes) +``` + +Reads `num_bytes` bytes from the file with the given `file` descriptor. + +Returns a list of U24 with each element representing a byte read from the file. + +#### File write +```python +def IO/FS/write(file, bytes) +``` + +Writes `bytes`, a list of U24 with each element representing a byte, to the file with the given `file` descriptor. + +Returns nothing (`*`). + +Writing discards any preexisting content that came after the current position. For example, if your file contains the text `Hello, world!` and the current position is at the `,`, writing `!` will + +#### File seek +```python +def IO/FS/seek(file, offset, mode) +``` + +Moves the current position of the file with the given `file` descriptor to the given `offset`, an I24 or U24 number, in bytes. + +`mode` can be one of the following: +- `IO/FS/SEEK_SET = 0`: Seek from start of file +- `IO/FS/SEEK_CUR = 1`: Seek from current position +- `IO/FS/SEEK_END = 2`: Seek from end of file + +Returns nothing (`*`). ## Numeric operations diff --git a/src/fun/builtins.bend b/src/fun/builtins.bend index 6c8fe2cc..ab072085 100644 --- a/src/fun/builtins.bend +++ b/src/fun/builtins.bend @@ -88,13 +88,7 @@ def IO/bind(a, b): def call(func, argm): return IO/Call(IO/MAGIC, func, argm, lambda x: IO/Done(IO/MAGIC, x)) - -print text = (IO/Call IO/MAGIC "WRITE" (1, text) @x (IO/Done IO/MAGIC x)) -#input = (IO/Call IO/MAGIC "GET_TEXT" * @x (IO/Done IO/MAGIC x)) - -#read_file path = (IO/Call IO/MAGIC "GET_FILE" path @x (IO/Done IO/MAGIC x)) -#write_file path text = (IO/Call IO/MAGIC "PUT_FILE" (path, text) @x (IO/Done IO/MAGIC x)) - +## Time and sleep # Returns a monotonically increasing nanosecond timestamp as an u48 encoded as a pair of u24s. IO/get_time = (IO/Call IO/MAGIC "GET_TIME" * @x (IO/Done IO/MAGIC x)) @@ -108,6 +102,40 @@ def IO/sleep(seconds): hi = to_u24(nanos / 0x1_000_000.0) return IO/nanosleep((hi, lo)) +## File IO + +### File IO primitives +IO/FS/open path mode = (IO/Call IO/MAGIC "OPEN" (path, mode) @x (IO/Done IO/MAGIC x)) +IO/FS/close file = (IO/Call IO/MAGIC "CLOSE" file @x (IO/Done IO/MAGIC x)) +IO/FS/read file num_bytes = (IO/Call IO/MAGIC "READ" (file, num_bytes) @x (IO/Done IO/MAGIC x)) +IO/FS/write file bytes = (IO/Call IO/MAGIC "WRITE" (file, bytes) @x (IO/Done IO/MAGIC x)) +IO/FS/seek file offset mode = (IO/Call IO/MAGIC "SEEK" (file, (offset, mode)) @x (IO/Done IO/MAGIC x)) + +### Always available files +IO/FS/STDIN = 0 +IO/FS/STDOUT = 1 +IO/FS/STDERR = 2 + +### Seek modes +# Seek from start of file +IO/FS/SEEK_SET = +0 +# Seek from current position +IO/FS/SEEK_CUR = +1 +# Seek from end of file +IO/FS/SEEK_END = +2 + +### File utilities +#read_file path = (IO/Call IO/MAGIC "GET_FILE" path @x (IO/Done IO/MAGIC x)) +#write_file path text = (IO/Call IO/MAGIC "PUT_FILE" (path, text) @x (IO/Done IO/MAGIC x)) + +### Standard input and output utilities + +# TODO: Encode with utf-8 +IO/print text = (IO/FS/write IO/FS/STDOUT text) + +# TODO: Should read any length of input +IO/input = (IO/FS/read IO/FS/STDIN 1024) + # Lazy thunks # We can defer the evaluation of a function by wrapping it in a thunk # Ex: @x (x @arg1 @arg2 @arg3 (f arg1 arg2 arg3) arg1 arg2 arg3)