Implement "slurp" function to read files into a string
This commit is contained in:
parent
69e2403c93
commit
fb2cc0b1f0
7 changed files with 102 additions and 15 deletions
|
@ -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) {
|
||||
|
|
28
src/fio.cpp
28
src/fio.cpp
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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},
|
||||
};
|
||||
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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>();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue