File machine.h
File List > jac > machine > machine.h
Go to the documentation of this file
#pragma once
#include <quickjs.h>
#include <chrono>
#include <functional>
#include <stdexcept>
#include <string>
#include <unordered_map>
#include <vector>
#include "values.h"
namespace jac {
template<class Base, template<class> class... MFeatures>
struct ComposeMachine;
template<class Base, template<class> class FirstFeature, template<class> class... MFeatures>
struct ComposeMachine<Base, FirstFeature, MFeatures...> : public ComposeMachine<FirstFeature<Base>, MFeatures...> {};
template<class Base>
struct ComposeMachine<Base> : public Base {};
enum class EvalFlags : int {
Global = JS_EVAL_TYPE_GLOBAL,
Module = JS_EVAL_TYPE_MODULE,
Strict = JS_EVAL_FLAG_STRICT,
CompileOnly = JS_EVAL_FLAG_COMPILE_ONLY,
BacktraceBarrier = JS_EVAL_FLAG_BACKTRACE_BARRIER
};
inline constexpr EvalFlags operator|(EvalFlags a, EvalFlags b) {
int res = static_cast<int>(a) | static_cast<int>(b);
if (res & JS_EVAL_TYPE_GLOBAL && res & JS_EVAL_TYPE_MODULE) {
throw std::runtime_error("Cannot use both global and module eval flags");
}
return static_cast<EvalFlags>(res);
}
inline constexpr EvalFlags operator&(EvalFlags a, EvalFlags b) {
return static_cast<EvalFlags>(static_cast<int>(a) & static_cast<int>(b));
}
class MachineBase;
class Module {
ContextRef _ctx;
JSModuleDef *_def;
Object _exports;
void finalize();
friend class MachineBase;
public:
Module(ContextRef ctx, std::string name);
Module& operator=(const Module&) = delete;
Module(const Module&) = delete;
Module& operator=(Module&&) = delete;
Module(Module&&) = delete;
void addExport(std::string name, Value val);
JSModuleDef *get() {
return _def;
}
};
class MachineBase {
public:
using ModuleBuilder = std::function<void(Module&)>;
using FileModuleLoader = std::function<JSModuleDef*(JSContext* ctx, const char* name, JSValueConst attributes)>;
private:
std::unordered_map<std::string, ModuleBuilder> _moduleBuilders;
FileModuleLoader _fileModuleLoader;
static JSModuleDef* loadModule(JSContext* ctx, const char* name, void* opaque, JSValueConst attributes);
bool _interrupt = false;
std::chrono::milliseconds _watchdogTimeout = std::chrono::milliseconds(0);
std::chrono::time_point<std::chrono::steady_clock> _watchdogNext;
std::function<bool()> _wathdogCallback;
const JSMallocFunctions* mallocFunctions = nullptr;
JSRuntime* _runtime = nullptr;
ContextRef _context = nullptr;
public:
JSRuntime* runtime() {
return _runtime;
}
ContextRef context() {
return _context;
}
void initialize();
MachineBase() = default;
MachineBase(const MachineBase&) = delete;
MachineBase(MachineBase&&) = delete;
MachineBase& operator=(const MachineBase&) = delete;
MachineBase& operator=(MachineBase&&) = delete;
virtual ~MachineBase() {
if (_context) {
JS_FreeContext(_context);
}
if (_runtime) {
JS_FreeRuntime(_runtime);
}
}
Value eval(std::string code, std::string filename, EvalFlags flags = EvalFlags::Global);
void newModule(std::string name, ModuleBuilder builder);
void interruptRuntime() {
_interrupt = true;
}
void resetWatchdog() {
_watchdogNext = std::chrono::steady_clock::now() + _watchdogTimeout;
}
void setWatchdogTimeout(std::chrono::milliseconds timeout) {
_watchdogTimeout = timeout;
}
void setWatchdogHandler(std::function<bool()> callback) {
_wathdogCallback = callback;
}
void setMallocFunctions(const JSMallocFunctions* fns) {
mallocFunctions = fns;
}
protected:
void setFileModuleLoader(FileModuleLoader loader) {
_fileModuleLoader = std::move(loader);
}
};
} // namespace jac