Implement "slurp" function to read files into a string

This commit is contained in:
Konstantin Nazarov 2024-09-29 20:55:45 +01:00
parent 69e2403c93
commit fb2cc0b1f0
Signed by: knazarov
GPG key ID: 4CFE0A42FA409C22
7 changed files with 102 additions and 15 deletions

View file

@ -323,12 +323,15 @@ class ByteArray : public Object {
return _value->data[idx];
}
Result<ByteArray> concat(const char* rhs) {
const char* raw_bytes() const { return _value->data; }
Result<ByteArray> 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<PodByteArray>(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<ByteArray> concat(const char* rhs, uint64_t rhs_size) {
Result<ByteArray> 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<PodByteArray>(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<ByteArray> concat(ByteArray& rhs) {
Result<ByteArray> 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<PodByteArray>(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<PodByteArray>(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<String> create(const ByteArray& bytes) {
auto size = TRY(bytes.size());
auto pod = TRY(arena_alloc<PodString>(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<String> create(const Symbol& sym);
static Result<String> create(const char* str) {

View file

@ -4,14 +4,16 @@
#include <cstdlib>
Result<String> read_fh(FILE* file) {
#include "common.hpp"
Result<ByteArray> 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<String> read_fh(FILE* file) {
return std::move(res);
}
Result<String> read_file(const char* filename) {
Result<ByteArray> read_file(const char* filename) {
FILE* fh = fopen(filename, "r");
if (!fh) {
@ -38,7 +40,25 @@ Result<String> read_file(const char* filename) {
return res;
}
Result<String> read_stdin() { return read_fh(stdin); }
Result<ByteArray> 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<ByteArray> read_stdin() { return read_fh(stdin); }
Result<void> 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.

View file

@ -2,7 +2,10 @@
#include "common.hpp"
Result<String> read_file(const char* filename);
Result<ByteArray> read_file(const char* filename);
Result<ByteArray> read_file(const ByteArray& filename);
Result<String> read_stdin();
Result<void> write_file(const ByteArray& filename, const ByteArray& contents);
Result<ByteArray> read_stdin();
bool stdin_isatty();

View file

@ -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<StackFrame> stdlib_prn(const StackFrame& stack) {
return ERROR(NotImplemented);
}
Result<StackFrame> 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<StackFrame> 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<Value> stdlib_task_print(const Array& params) {
return Value(TRY(Nil::create()));
}
Result<Value> 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<String>()) {
auto err = Value(TRY(Error::create("type-mismatch", "Type mismatch")));
return ERROR_OBJ(TypeMismatch, err);
}
String& fname = *obj.to<String>();
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},
};

View file

@ -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,
};

View file

@ -117,7 +117,8 @@ Result<void> 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("<stdin>"));
auto res = run_string(fname, src);
if (res.has_error()) {
@ -125,7 +126,8 @@ Result<void> 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()) {

View file

@ -333,9 +333,9 @@ Result<void> VM::step() {
auto fun = TRY(_stack.fun());
Result<void> res;
if (fun.is<Function>()) {
res = std::move(step_bytecode());
res = step_bytecode();
} else if (fun.is<StdlibFunction>()) {
res = std::move(step_native());
res = step_native();
} else {
return ERROR(NotImplemented);
}
@ -351,8 +351,8 @@ Result<void> VM::step() {
}
}
auto cont = Value(TRY(Continuation::create(obj, _stack)));
_stack = TRY(handle_raise(*obj.to<Continuation>()));
auto cont = TRY(Continuation::create(obj, _stack));
_stack = TRY(handle_raise(cont));
return Result<void>();
}