valeri/src/stdlib.cpp

193 lines
5 KiB
C++

#include "stdlib.hpp"
#include "common.hpp"
#include "pod.hpp"
#include "sourcerange.hpp"
#include "writer.hpp"
typedef Result<Value> (*StdlibFunctionIdPtr)(const Array& params);
struct StdlibFunctionEntry {
const char* name;
StdlibFunctionId fun_id;
StdlibFunctionIdPtr fun_ptr;
};
Result<Value> stdlib_unknown(const Array& params) {
return ERROR(NotImplemented);
}
Result<void> print_string(const String& s) {
auto ba = TRY(ByteArray::create(s));
for (uint64_t i = 0; i < ba.size(); i++) {
std::cout << TRY(ba[i]);
}
return Result<void>();
}
Result<Value> stdlib_print(const Array& params) {
for (uint64_t i = 0; i < params.size(); i++) {
Value param = TRY(params.get(i));
if (i != 0) {
std::cout << " ";
}
if (param.is<String>()) {
TRY(print_string(*param.to<String>()));
} else {
auto s = TRY(write_one(param));
TRY(print_string(s));
}
}
return Value(TRY(Nil::create()));
}
Result<Value> stdlib_println(const Array& params) {
TRY(stdlib_print(params));
std::cout << "\n";
return Value(TRY(Nil::create()));
}
Result<Value> stdlib_prn(const Array& params) { return ERROR(NotImplemented); }
Result<Value> stdlib_assert(const Array& params) {
for (uint64_t i = 0; i < params.size(); i++) {
Value param = TRY(params.get(i));
if (!param.is<Bool>()) return ERROR(AssertionFailed);
auto v = param.to<Bool>()->value();
if (!v) return ERROR(AssertionFailed);
}
return Value(TRY(Nil::create()));
}
Result<Value> stdlib_dict(const Array& params) {
Value d = TRY(Dict::create(params));
return d;
}
Result<Value> stdlib_list(const Array& params) {
Value d = TRY(Pair::create(params));
return d;
}
Result<Value> stdlib_array(const Array& params) {
Array array_copy = TRY(params.copy());
return Value(std::move(array_copy));
}
Result<Value> stdlib_get(const Array& params) {
if (params.size() != 2) return ERROR(ArgumentCountMismatch);
Value collection = TRY(params.get(0));
Value key = TRY(params.get(1));
return TRY(collection.get(key));
}
Result<Value> stdlib_srcloc(const Array& params) {
Array array_copy = TRY(params.copy());
if (params.size() != 6) return ERROR(ArgumentCountMismatch);
SourceRange sr;
for (uint64_t i = 0; i < 6; i++) {
auto val = TRY(array_copy.get(i));
if (!val.is<Int64>()) return ERROR(TypeMismatch);
int64_t intval = val.to<Int64>()->value();
switch (i) {
case 0:
sr.start.line = intval;
break;
case 1:
sr.start.column = intval;
break;
case 2:
sr.start.offset = intval;
break;
case 3:
sr.end.line = intval;
break;
case 4:
sr.end.column = intval;
break;
case 5:
sr.end.offset = intval;
break;
default:
break;
}
}
return Value(TRY(SrcLoc::create(sr)));
}
#define STDLIB_FUNCTION(name, id) \
[(uint64_t)StdlibFunctionId::id] = {#name, StdlibFunctionId::id, \
stdlib_##name}
static StdlibFunctionEntry function_entries[] = {
STDLIB_FUNCTION(unknown, Unknown),
STDLIB_FUNCTION(print, Print),
STDLIB_FUNCTION(println, PrintLn),
STDLIB_FUNCTION(prn, Prn),
STDLIB_FUNCTION(assert, Assert),
STDLIB_FUNCTION(dict, Dict),
STDLIB_FUNCTION(list, List),
STDLIB_FUNCTION(array, Array),
STDLIB_FUNCTION(get, Get),
STDLIB_FUNCTION(srcloc, SrcLoc),
[(uint64_t)StdlibFunctionId::Max] = {0, StdlibFunctionId::Max,
stdlib_unknown},
};
// TODO: this just scans through the array of functions linearly every time.
// It doesn't have much effect at runtime, because such lookup is likely to
// happen on compile-time only. But anyway, this is worth speeding up
// eventually.
StdlibFunctionEntry get_function_entry(const char* name) {
for (uint64_t i = 1; i < (uint64_t)StdlibFunctionId::Max; i++) {
if (strcmp(function_entries[i].name, name) == 0) {
return function_entries[i];
}
}
return function_entries[(uint64_t)StdlibFunctionId::Unknown];
}
Result<StdlibFunctionId> get_stdlib_function(const Symbol& name) {
const uint64_t bufsize = 256;
char buf[bufsize];
if (name.size() + 1 > bufsize) {
return ERROR(KeyError);
}
for (uint64_t i = 0; i < name.size(); i++) {
buf[i] = (char)TRY(name[i]);
}
buf[name.size()] = 0;
StdlibFunctionId fun_id = get_function_entry(buf).fun_id;
if (fun_id == StdlibFunctionId::Unknown) {
return ERROR(KeyError);
}
return fun_id;
}
Result<Value> call_stdlib_function(StdlibFunctionId fun_id,
const Array& params) {
if (fun_id == StdlibFunctionId(0) || fun_id >= StdlibFunctionId::Max) {
return ERROR(KeyError);
}
return function_entries[(uint64_t)fun_id].fun_ptr(params);
}
Result<const char*> get_stdlib_function_name(StdlibFunctionId fun_id) {
if (fun_id == StdlibFunctionId(0) || fun_id >= StdlibFunctionId::Max) {
return ERROR(KeyError);
}
return function_entries[(uint64_t)fun_id].name;
}