#include "stdlib.hpp" #include "common.hpp" #include "pod.hpp" #include "writer.hpp" typedef Result (*StdlibFunctionIdPtr)(const Array& params); struct StdlibFunctionEntry { const char* name; StdlibFunctionId fun_id; StdlibFunctionIdPtr fun_ptr; }; Result stdlib_unknown(const Array& params) { return ERROR(NotImplemented); } Result 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(); } Result 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()) { TRY(print_string(*param.to())); } else { auto s = TRY(write_one(param)); TRY(print_string(s)); } } return Value(TRY(Nil::create())); } Result stdlib_println(const Array& params) { TRY(stdlib_print(params)); std::cout << "\n"; return Value(TRY(Nil::create())); } Result stdlib_prn(const Array& params) { return ERROR(NotImplemented); } Result stdlib_assert(const Array& params) { for (uint64_t i = 0; i < params.size(); i++) { Value param = TRY(params.get(i)); if (!param.is()) return ERROR(AssertionFailed); auto v = param.to()->value(); if (!v) return ERROR(AssertionFailed); } return Value(TRY(Nil::create())); } Result stdlib_dict(const Array& params) { Value d = TRY(Dict::create(params)); return d; } Result stdlib_list(const Array& params) { Value d = TRY(Pair::create(params)); return d; } Result stdlib_array(const Array& params) { Array array_copy = TRY(params.copy()); return Value(std::move(array_copy)); } Result 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)); } #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), [(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 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 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 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; }