-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathquickjs_helpers.hpp
More file actions
148 lines (127 loc) · 4.19 KB
/
Copy pathquickjs_helpers.hpp
File metadata and controls
148 lines (127 loc) · 4.19 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#ifndef QUICKJS_HELPERS_HPP
#define QUICKJS_HELPERS_HPP
#include "quickjs.h"
#include <cpp11.hpp>
#include <quickjs-libc.h>
#include <quickjsr/JS_SEXP.hpp>
/**
* These functions were adapted from the qjs.c file in the QuickJS source code.
*/
static inline int js__has_suffix(const char *str, const char *suffix)
{
size_t len = strlen(str);
size_t slen = strlen(suffix);
return (len >= slen && !memcmp(str + len - slen, suffix, slen));
}
#ifndef countof
#define countof(x) (sizeof(x) / sizeof((x)[0]))
#endif
namespace quickjsr {
static int eval_buf(JSContext *ctx, const char* buf, int buf_len,
const char *filename, int eval_flags) {
JSValue val;
int ret;
if ((eval_flags & JS_EVAL_TYPE_MASK) == JS_EVAL_TYPE_MODULE) {
/* for the modules, we compile then run to be able to set
import.meta */
val = JS_Eval(ctx, buf, buf_len, filename,
eval_flags | JS_EVAL_FLAG_COMPILE_ONLY);
if (!JS_IsException(val)) {
js_module_set_import_meta(ctx, val, TRUE, TRUE);
val = JS_EvalFunction(ctx, val);
}
} else {
val = JS_Eval(ctx, buf, buf_len, filename, eval_flags);
}
if (JS_IsException(val)) {
JSValue exc = JS_GetException(ctx);
const char* res_str = JS_ToCString(ctx, exc);
std::string msg = res_str;
JS_FreeCString(ctx, res_str);
std::string stack = "";
if (JS_IsError(exc)) {
JSValue stack_val = JS_GetPropertyStr(ctx, exc, "stack");
const char* stack_str = JS_ToCString(ctx, stack_val);
stack = stack_str;
stack = "\n" + stack;
JS_FreeCString(ctx, stack_str);
JS_FreeValue(ctx, stack_val);
}
JS_FreeValue(ctx, exc);
JS_FreeValue(ctx, val);
cpp11::stop("JavaScript Exception: \n" + msg + stack);
ret = -1;
} else {
JS_FreeValue(ctx, val);
ret = 0;
}
return ret;
}
static int eval_file(JSContext *ctx, const char *filename, int module) {
const char* buf;
int ret, eval_flags;
size_t buf_len;
buf = (const char*)js_load_file(ctx, &buf_len, filename);
if (!buf) {
cpp11::stop("Could not load '%s'\n", filename);
}
if (module < 0) {
module = js__has_suffix(filename, ".mjs");
}
if (module) {
eval_flags = JS_EVAL_TYPE_MODULE;
} else {
eval_flags = JS_EVAL_TYPE_GLOBAL;
}
ret = eval_buf(ctx, buf, buf_len, "<input>", eval_flags);
js_free(ctx, (void*)buf);
return ret;
}
/* also used to initialize the worker context */
static JSContext* JS_NewCustomContext(JSRuntime *rt) {
JSContext *ctx;
ctx = JS_NewContext(rt);
if (!ctx){
return NULL;
}
/* system modules */
js_init_module_std(ctx, "std");
js_init_module_os(ctx, "os");
JSValue proto = JS_NewObject(ctx);
JS_SetClassProto(ctx, quickjsr::js_renv_class_id, proto);
JS_SetModuleLoaderFunc2(rt, NULL, js_module_loader, js_module_check_attributes, NULL);
js_init_module_os(ctx, "os");
js_init_module_std(ctx, "std");
js_std_add_helpers(ctx, 0, (char**)"");
const char *str = "import * as std from 'std';\n"
"import * as os from 'os';\n"
"globalThis.std = std;\n"
"globalThis.os = os;\n";
eval_buf(ctx, str, strlen(str), "<input>", JS_EVAL_TYPE_MODULE);
JSValue global_obj = JS_GetGlobalObject(ctx);
JSValue r_obj = quickjsr::create_r_object(ctx);
JS_SetPropertyStr(ctx, global_obj, "R", r_obj);
JS_FreeValue(ctx, global_obj);
return ctx;
}
inline JSRuntime* JS_NewCustomRuntime(int stack_size) {
JSRuntime *rt;
rt = JS_NewRuntime();
if (!rt){
return NULL;
}
if (stack_size != -1) {
JS_SetMaxStackSize(rt, stack_size);
}
js_std_set_worker_new_context_func(JS_NewCustomContext);
js_std_init_handlers(rt);
JS_NewClassID(rt, &quickjsr::js_sexp_class_id);
JS_NewClassID(rt, &quickjsr::js_renv_class_id);
// Initialise a class which can be used for passing SEXP objects to JS
// without needing conversion
JS_NewClass(rt, quickjsr::js_sexp_class_id, &quickjsr::js_sexp_class_def);
JS_NewClass(rt, quickjsr::js_renv_class_id, &quickjsr::js_renv_class_def);
return rt;
}
}
#endif