From fb2cc0b1f00e65feb1615a9dc44b43d87fe4ae38 Mon Sep 17 00:00:00 2001 From: Konstantin Nazarov Date: Sun, 29 Sep 2024 20:55:45 +0100 Subject: [PATCH] Implement "slurp" function to read files into a string --- src/common.hpp | 24 +++++++++++++++++++++--- src/fio.cpp | 28 ++++++++++++++++++++++++---- src/fio.hpp | 7 +++++-- src/stdlib.cpp | 42 ++++++++++++++++++++++++++++++++++++++++++ src/stdlib.hpp | 2 ++ src/valeri.cpp | 6 ++++-- src/vm.cpp | 8 ++++---- 7 files changed, 102 insertions(+), 15 deletions(-) diff --git a/src/common.hpp b/src/common.hpp index 16aebc3..e17180d 100644 --- a/src/common.hpp +++ b/src/common.hpp @@ -323,12 +323,15 @@ class ByteArray : public Object { return _value->data[idx]; } - Result concat(const char* rhs) { + const char* raw_bytes() const { return _value->data; } + + Result concat(const char* rhs) const { uint64_t rhs_size = strlen(rhs); uint64_t lhs_size = TRY(size()); uint64_t res_size = lhs_size + rhs_size; auto pod = TRY(arena_alloc(res_size * sizeof(char))); + pod->header.tag = Tag::ByteArray; pod->size = res_size; memcpy(pod->data, _value->data, sizeof(char) * lhs_size); memcpy(pod->data, rhs + lhs_size, sizeof(char) * rhs_size); @@ -336,11 +339,12 @@ class ByteArray : public Object { return ByteArray(TRY(MkGcRoot(pod))); } - Result concat(const char* rhs, uint64_t rhs_size) { + Result concat(const char* rhs, uint64_t rhs_size) const { uint64_t lhs_size = TRY(size()); uint64_t res_size = lhs_size + rhs_size; auto pod = TRY(arena_alloc(res_size * sizeof(char))); + pod->header.tag = Tag::ByteArray; pod->size = res_size; memcpy(pod->data, _value->data, sizeof(char) * lhs_size); memcpy(pod->data, rhs + lhs_size, sizeof(char) * rhs_size); @@ -348,12 +352,13 @@ class ByteArray : public Object { return ByteArray(TRY(MkGcRoot(pod))); } - Result concat(ByteArray& rhs) { + Result concat(ByteArray& rhs) const { uint64_t rhs_size = TRY(rhs.size()); uint64_t lhs_size = TRY(size()); uint64_t res_size = lhs_size + rhs_size; auto pod = TRY(arena_alloc(res_size * sizeof(char))); + pod->header.tag = Tag::ByteArray; pod->size = res_size; memcpy(pod->data, _value->data, sizeof(char) * lhs_size); memcpy(pod->data + lhs_size, rhs._value->data, sizeof(char) * rhs_size); @@ -365,6 +370,7 @@ class ByteArray : public Object { if (start > end) return ERROR(IndexOutOfRange); uint64_t res_size = end - start; auto pod = TRY(arena_alloc(res_size * sizeof(char))); + pod->header.tag = Tag::ByteArray; pod->size = res_size; memcpy(pod->data, _value->data + start, sizeof(char) * res_size); @@ -500,6 +506,18 @@ class String : public Object { return String(TRY(MkGcRoot(pod))); } + static Result create(const ByteArray& bytes) { + auto size = TRY(bytes.size()); + + auto pod = TRY(arena_alloc(size * sizeof(char32_t))); + pod->header.tag = Tag::String; + + for (uint64_t i = 0; i < size; i++) pod->data[i] = TRY(bytes[i]); + pod->size = size; + + return String(TRY(MkGcRoot(pod))); + } + static Result create(const Symbol& sym); static Result create(const char* str) { diff --git a/src/fio.cpp b/src/fio.cpp index d3006c6..e8629e4 100644 --- a/src/fio.cpp +++ b/src/fio.cpp @@ -4,14 +4,16 @@ #include -Result read_fh(FILE* file) { +#include "common.hpp" + +Result read_fh(FILE* file) { size_t chunk_size = 1024; const size_t buf_size = chunk_size; size_t pos = 0; char buf[chunk_size]; - String res = TRY(String::create("")); + ByteArray res = TRY(ByteArray::create("")); while (1) { size_t num_bytes = fread(&buf[pos], 1, chunk_size, file); @@ -26,7 +28,7 @@ Result read_fh(FILE* file) { return std::move(res); } -Result read_file(const char* filename) { +Result read_file(const char* filename) { FILE* fh = fopen(filename, "r"); if (!fh) { @@ -38,7 +40,25 @@ Result read_file(const char* filename) { return res; } -Result read_stdin() { return read_fh(stdin); } +Result read_file(const ByteArray& filename) { + auto filename_bytes = TRY(filename.concat("\0")); + + FILE* fh = fopen(filename_bytes.raw_bytes(), "r"); + + if (!fh) { + return ERROR(IOError); + } + + auto res = read_fh(fh); + fclose(fh); + return res; +} + +Result read_stdin() { return read_fh(stdin); } + +Result write_file(const ByteArray& filename, const ByteArray& contents) { + return ERROR(NotImplemented); +} // TODO: though unlikely, but isatty can possibly set an error. Need to check it // someday. diff --git a/src/fio.hpp b/src/fio.hpp index 91f17bf..0a20afb 100644 --- a/src/fio.hpp +++ b/src/fio.hpp @@ -2,7 +2,10 @@ #include "common.hpp" -Result read_file(const char* filename); +Result read_file(const char* filename); +Result read_file(const ByteArray& filename); -Result read_stdin(); +Result write_file(const ByteArray& filename, const ByteArray& contents); + +Result read_stdin(); bool stdin_isatty(); diff --git a/src/stdlib.cpp b/src/stdlib.cpp index 936664d..7113d4a 100644 --- a/src/stdlib.cpp +++ b/src/stdlib.cpp @@ -2,6 +2,7 @@ #include "common.hpp" #include "error.hpp" +#include "fio.hpp" #include "pod.hpp" #include "sourcerange.hpp" #include "writer.hpp" @@ -116,6 +117,22 @@ Result stdlib_prn(const StackFrame& stack) { return ERROR(NotImplemented); } +Result stdlib_slurp(const StackFrame& stack) { + auto params = TRY(stack.get(0)); + auto stack_size = TRY(stack.size()); + + if (stack_size > 1) { + return task_return(stack, 1); + } + + if (TRY(params.size()) != 1) { + return ERROR(ArgumentCountMismatch); + } + + auto fname = TRY(params.get(0)); + return raise_task(stack, StdlibTaskId::ReadFile, fname); +} + Result stdlib_assert(const StackFrame& stack) { auto params = TRY(stack.get(0)); auto size = TRY(params.size()); @@ -408,6 +425,7 @@ static StdlibFunctionEntry function_entries[] = { STDLIB_FUNCTION(print, Print), STDLIB_FUNCTION(println, PrintLn), STDLIB_FUNCTION(prn, Prn), + STDLIB_FUNCTION(slurp, Slurp), STDLIB_FUNCTION(assert, Assert), STDLIB_FUNCTION(dict, Dict), STDLIB_FUNCTION(list, List), @@ -448,12 +466,36 @@ Result stdlib_task_print(const Array& params) { return Value(TRY(Nil::create())); } +Result stdlib_task_read_file(const Array& params) { + auto size = TRY(params.size()); + + if (size != 1) { + auto err = Value(TRY( + Error::create("argument-count-mismatch", "Argument count mismatch"))); + return ERROR_OBJ(ArgumentCountMismatch, err); + } + + auto obj = TRY(params.get(0)); + + if (!obj.is()) { + auto err = Value(TRY(Error::create("type-mismatch", "Type mismatch"))); + return ERROR_OBJ(TypeMismatch, err); + } + + String& fname = *obj.to(); + ByteArray fname_bytes = TRY(ByteArray::create(fname)); + auto contents_bytes = TRY(read_file(fname_bytes)); + auto contents = Value(TRY(String::create(contents_bytes))); + return contents; +} + #define STDLIB_TASK(name, id) \ [(uint64_t)StdlibTaskId::id] = {#name, StdlibTaskId::id, stdlib_task_##name} static StdlibTaskEntry task_entries[] = { STDLIB_TASK(unknown, Unknown), STDLIB_TASK(print, Print), + STDLIB_TASK(read_file, ReadFile), [(uint64_t)StdlibTaskId::Max] = {0, StdlibTaskId::Max, stdlib_task_unknown}, }; diff --git a/src/stdlib.hpp b/src/stdlib.hpp index ae16ce4..1af10a0 100644 --- a/src/stdlib.hpp +++ b/src/stdlib.hpp @@ -9,6 +9,7 @@ enum class StdlibFunctionId : uint64_t { Print, PrintLn, Prn, + Slurp, Assert, Dict, List, @@ -27,6 +28,7 @@ enum class StdlibFunctionId : uint64_t { enum class StdlibTaskId : uint64_t { Unknown, Print, + ReadFile, Max, }; diff --git a/src/valeri.cpp b/src/valeri.cpp index 948a8e3..3391551 100644 --- a/src/valeri.cpp +++ b/src/valeri.cpp @@ -117,7 +117,8 @@ Result run(int argc, const char* argv[]) { if (stdin_isatty()) { return run_repl(); } - src = TRY(read_stdin()); + auto src_bytes = TRY(read_stdin()); + src = TRY(String::create(src_bytes)); auto fname = TRY(String::create("")); auto res = run_string(fname, src); if (res.has_error()) { @@ -125,7 +126,8 @@ Result run(int argc, const char* argv[]) { } } else { - src = TRY(read_file(argv[1])); + auto src_bytes = TRY(read_file(argv[1])); + src = TRY(String::create(src_bytes)); auto fname = TRY(String::create(argv[1])); auto res = run_string(fname, src); if (res.has_error()) { diff --git a/src/vm.cpp b/src/vm.cpp index 9d9cb7f..0b321db 100644 --- a/src/vm.cpp +++ b/src/vm.cpp @@ -333,9 +333,9 @@ Result VM::step() { auto fun = TRY(_stack.fun()); Result res; if (fun.is()) { - res = std::move(step_bytecode()); + res = step_bytecode(); } else if (fun.is()) { - res = std::move(step_native()); + res = step_native(); } else { return ERROR(NotImplemented); } @@ -351,8 +351,8 @@ Result VM::step() { } } - auto cont = Value(TRY(Continuation::create(obj, _stack))); - _stack = TRY(handle_raise(*obj.to())); + auto cont = TRY(Continuation::create(obj, _stack)); + _stack = TRY(handle_raise(cont)); return Result(); }