quickjs 0.2.1 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +25 -0
- data/ext/quickjsrb/quickjs/qjs.c +2 -2
- data/ext/quickjsrb/quickjs/quickjs-libc.c +6 -2
- data/ext/quickjsrb/quickjs/quickjs.c +10 -8
- data/ext/quickjsrb/quickjsrb.c +115 -226
- data/ext/quickjsrb/quickjsrb.h +203 -0
- data/lib/quickjs/version.rb +1 -1
- data/lib/quickjs.rb +2 -3
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5f57f31bd8921f897f9d1c81d1c50d24774bbfba5d31a99528b138e82d3fad58
|
4
|
+
data.tar.gz: 28216a7b1711fe08ad3e2a5b021abebaadd2b5d3808584ff259d0129abf0adf6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 355b53297b3c27269b71dca93e057ecfe02eac70755b5bd336b212092fb6da3c14ff3b2dd2f77214a62891b28d860e33f961329374ddef485e168dea41b50097
|
7
|
+
data.tar.gz: 7ff16986a8ef0efeff790389805fa6d36f6b03b5983e8f8131ff33f8369514344cc9f9b9f103f036ad305441e06dfdfdacd125bdb8b061967337235d4913c525
|
data/README.md
CHANGED
@@ -114,10 +114,21 @@ vm = Quickjs::VM.new(timeout_msec: 1_000)
|
|
114
114
|
|
115
115
|
```rb
|
116
116
|
vm = Quickjs::VM.new
|
117
|
+
|
118
|
+
# Equivalent to `import { default: aliasedDefault, member: member } from './exports.esm.js';`
|
117
119
|
vm.import({ default: 'aliasedDefault', member: 'member' }, from: File.read('exports.esm.js'))
|
118
120
|
|
119
121
|
vm.eval_code("aliasedDefault()") #=> Exported `default` of the ESM is called
|
120
122
|
vm.eval_code("member()") #=> Exported `member` of the ESM is called
|
123
|
+
|
124
|
+
# import { member, defaultMember } from './exports.esm.js';
|
125
|
+
vm.import(['member', 'defaultMember'], from: File.read('exports.esm.js'))
|
126
|
+
|
127
|
+
# import DefaultExport from './exports.esm.js';
|
128
|
+
vm.import('DefaultExport', from: File.read('exports.esm.js'))
|
129
|
+
|
130
|
+
# import * as all from './exports.esm.js';
|
131
|
+
vm.import('* as all', from: File.read('exports.esm.js'))
|
121
132
|
```
|
122
133
|
|
123
134
|
#### `Quickjs::VM#define_function`: 💎 Define a global function for JS by Ruby
|
@@ -131,6 +142,20 @@ end
|
|
131
142
|
vm.eval_code("greetingTo('Rick')") #=> 'Hello! Rick'
|
132
143
|
```
|
133
144
|
|
145
|
+
#### `Quickjs::VM#logs`: 💾 Capture console logs
|
146
|
+
|
147
|
+
All logs by `console.(log|info|debug|warn|error)` on VM are recorded and inspectable.
|
148
|
+
|
149
|
+
```rb
|
150
|
+
vm = Quickjs::VM.new
|
151
|
+
vm.eval_code('console.log("log me", null)')
|
152
|
+
|
153
|
+
vm.logs #=> Array of Quickjs::VM::Log
|
154
|
+
vm.logs.last.severity #=> :info
|
155
|
+
vm.logs.last.to_s #=> 'log me null'
|
156
|
+
vm,logs.last.raw #=> ['log me', nil]
|
157
|
+
```
|
158
|
+
|
134
159
|
## License
|
135
160
|
|
136
161
|
Every file in `ext/quickjsrb/quickjs` is licensed under [the MIT License Copyright 2017-2021 by Fabrice Bellard and Charlie Goron](/ext/quickjsrb/quickjs/LICENSE).
|
data/ext/quickjsrb/quickjs/qjs.c
CHANGED
@@ -34,7 +34,7 @@
|
|
34
34
|
#include <time.h>
|
35
35
|
#if defined(__APPLE__)
|
36
36
|
#include <malloc/malloc.h>
|
37
|
-
#elif defined(__linux__)
|
37
|
+
#elif defined(__linux__) || defined(__GLIBC__)
|
38
38
|
#include <malloc.h>
|
39
39
|
#elif defined(__FreeBSD__)
|
40
40
|
#include <malloc_np.h>
|
@@ -151,7 +151,7 @@ static size_t js_trace_malloc_usable_size(const void *ptr)
|
|
151
151
|
return _msize((void *)ptr);
|
152
152
|
#elif defined(EMSCRIPTEN)
|
153
153
|
return 0;
|
154
|
-
#elif defined(__linux__)
|
154
|
+
#elif defined(__linux__) || defined(__GLIBC__)
|
155
155
|
return malloc_usable_size((void *)ptr);
|
156
156
|
#else
|
157
157
|
/* change this to `return 0;` if compilation fails */
|
@@ -78,6 +78,10 @@ typedef sig_t sighandler_t;
|
|
78
78
|
#include "list.h"
|
79
79
|
#include "quickjs-libc.h"
|
80
80
|
|
81
|
+
#if !defined(PATH_MAX)
|
82
|
+
#define PATH_MAX 4096
|
83
|
+
#endif
|
84
|
+
|
81
85
|
/* TODO:
|
82
86
|
- add socket calls
|
83
87
|
*/
|
@@ -1090,7 +1094,7 @@ static JSValue js_std_file_tell(JSContext *ctx, JSValueConst this_val,
|
|
1090
1094
|
int64_t pos;
|
1091
1095
|
if (!f)
|
1092
1096
|
return JS_EXCEPTION;
|
1093
|
-
#if defined(__linux__)
|
1097
|
+
#if defined(__linux__) || defined(__GLIBC__)
|
1094
1098
|
pos = ftello(f);
|
1095
1099
|
#else
|
1096
1100
|
pos = ftell(f);
|
@@ -1113,7 +1117,7 @@ static JSValue js_std_file_seek(JSContext *ctx, JSValueConst this_val,
|
|
1113
1117
|
return JS_EXCEPTION;
|
1114
1118
|
if (JS_ToInt32(ctx, &whence, argv[1]))
|
1115
1119
|
return JS_EXCEPTION;
|
1116
|
-
#if defined(__linux__)
|
1120
|
+
#if defined(__linux__) || defined(__GLIBC__)
|
1117
1121
|
ret = fseeko(f, pos, whence);
|
1118
1122
|
#else
|
1119
1123
|
ret = fseek(f, pos, whence);
|
@@ -34,7 +34,7 @@
|
|
34
34
|
#include <math.h>
|
35
35
|
#if defined(__APPLE__)
|
36
36
|
#include <malloc/malloc.h>
|
37
|
-
#elif defined(__linux__)
|
37
|
+
#elif defined(__linux__) || defined(__GLIBC__)
|
38
38
|
#include <malloc.h>
|
39
39
|
#elif defined(__FreeBSD__)
|
40
40
|
#include <malloc_np.h>
|
@@ -1681,7 +1681,7 @@ JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque)
|
|
1681
1681
|
rt->stack_size = JS_DEFAULT_STACK_SIZE;
|
1682
1682
|
JS_UpdateStackTop(rt);
|
1683
1683
|
|
1684
|
-
rt->current_exception =
|
1684
|
+
rt->current_exception = JS_UNINITIALIZED;
|
1685
1685
|
|
1686
1686
|
return rt;
|
1687
1687
|
fail:
|
@@ -1708,7 +1708,7 @@ static size_t js_def_malloc_usable_size(const void *ptr)
|
|
1708
1708
|
return _msize((void *)ptr);
|
1709
1709
|
#elif defined(EMSCRIPTEN)
|
1710
1710
|
return 0;
|
1711
|
-
#elif defined(__linux__)
|
1711
|
+
#elif defined(__linux__) || defined(__GLIBC__)
|
1712
1712
|
return malloc_usable_size((void *)ptr);
|
1713
1713
|
#else
|
1714
1714
|
/* change this to `return 0;` if compilation fails */
|
@@ -6398,13 +6398,13 @@ JSValue JS_GetException(JSContext *ctx)
|
|
6398
6398
|
JSValue val;
|
6399
6399
|
JSRuntime *rt = ctx->rt;
|
6400
6400
|
val = rt->current_exception;
|
6401
|
-
rt->current_exception =
|
6401
|
+
rt->current_exception = JS_UNINITIALIZED;
|
6402
6402
|
return val;
|
6403
6403
|
}
|
6404
6404
|
|
6405
6405
|
JS_BOOL JS_HasException(JSContext *ctx)
|
6406
6406
|
{
|
6407
|
-
return !
|
6407
|
+
return !JS_IsUninitialized(ctx->rt->current_exception);
|
6408
6408
|
}
|
6409
6409
|
|
6410
6410
|
static void dbuf_put_leb128(DynBuf *s, uint32_t v)
|
@@ -15321,7 +15321,7 @@ static int JS_IteratorClose(JSContext *ctx, JSValueConst enum_obj,
|
|
15321
15321
|
|
15322
15322
|
if (is_exception_pending) {
|
15323
15323
|
ex_obj = ctx->rt->current_exception;
|
15324
|
-
ctx->rt->current_exception =
|
15324
|
+
ctx->rt->current_exception = JS_UNINITIALIZED;
|
15325
15325
|
res = -1;
|
15326
15326
|
} else {
|
15327
15327
|
ex_obj = JS_UNDEFINED;
|
@@ -18674,7 +18674,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
|
|
18674
18674
|
JS_IteratorClose(ctx, sp[-1], TRUE);
|
18675
18675
|
} else {
|
18676
18676
|
*sp++ = rt->current_exception;
|
18677
|
-
rt->current_exception =
|
18677
|
+
rt->current_exception = JS_UNINITIALIZED;
|
18678
18678
|
pc = b->byte_code_buf + pos;
|
18679
18679
|
goto restart;
|
18680
18680
|
}
|
@@ -46151,8 +46151,10 @@ static JSValue js_proxy_get(JSContext *ctx, JSValueConst obj, JSAtom atom,
|
|
46151
46151
|
if (JS_IsException(ret))
|
46152
46152
|
return JS_EXCEPTION;
|
46153
46153
|
res = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(s->target), atom);
|
46154
|
-
if (res < 0)
|
46154
|
+
if (res < 0) {
|
46155
|
+
JS_FreeValue(ctx, ret);
|
46155
46156
|
return JS_EXCEPTION;
|
46157
|
+
}
|
46156
46158
|
if (res) {
|
46157
46159
|
if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0) {
|
46158
46160
|
if (!js_same_value(ctx, desc.value, ret)) {
|
data/ext/quickjsrb/quickjsrb.c
CHANGED
@@ -1,79 +1,5 @@
|
|
1
1
|
#include "quickjsrb.h"
|
2
2
|
|
3
|
-
typedef struct EvalTime
|
4
|
-
{
|
5
|
-
clock_t limit;
|
6
|
-
clock_t started_at;
|
7
|
-
} EvalTime;
|
8
|
-
|
9
|
-
typedef struct VMData
|
10
|
-
{
|
11
|
-
struct JSContext *context;
|
12
|
-
VALUE defined_functions;
|
13
|
-
struct EvalTime *eval_time;
|
14
|
-
VALUE logs;
|
15
|
-
} VMData;
|
16
|
-
|
17
|
-
static void vm_free(void *ptr)
|
18
|
-
{
|
19
|
-
VMData *data = (VMData *)ptr;
|
20
|
-
free(data->eval_time);
|
21
|
-
|
22
|
-
JSRuntime *runtime = JS_GetRuntime(data->context);
|
23
|
-
JS_SetInterruptHandler(runtime, NULL, NULL);
|
24
|
-
js_std_free_handlers(runtime);
|
25
|
-
JS_FreeContext(data->context);
|
26
|
-
JS_FreeRuntime(runtime);
|
27
|
-
|
28
|
-
xfree(ptr);
|
29
|
-
}
|
30
|
-
|
31
|
-
size_t vm_size(const void *data)
|
32
|
-
{
|
33
|
-
return sizeof(VMData);
|
34
|
-
}
|
35
|
-
|
36
|
-
static void vm_mark(void *ptr)
|
37
|
-
{
|
38
|
-
VMData *data = (VMData *)ptr;
|
39
|
-
rb_gc_mark_movable(data->defined_functions);
|
40
|
-
rb_gc_mark_movable(data->logs);
|
41
|
-
}
|
42
|
-
|
43
|
-
static const rb_data_type_t vm_type = {
|
44
|
-
.wrap_struct_name = "quickjsvm",
|
45
|
-
.function = {
|
46
|
-
.dmark = vm_mark,
|
47
|
-
.dfree = vm_free,
|
48
|
-
.dsize = vm_size,
|
49
|
-
},
|
50
|
-
.flags = RUBY_TYPED_FREE_IMMEDIATELY,
|
51
|
-
};
|
52
|
-
|
53
|
-
static VALUE vm_alloc(VALUE r_self)
|
54
|
-
{
|
55
|
-
VMData *data;
|
56
|
-
VALUE obj = TypedData_Make_Struct(r_self, VMData, &vm_type, data);
|
57
|
-
data->defined_functions = rb_hash_new();
|
58
|
-
data->logs = rb_ary_new();
|
59
|
-
|
60
|
-
EvalTime *eval_time = malloc(sizeof(EvalTime));
|
61
|
-
data->eval_time = eval_time;
|
62
|
-
|
63
|
-
JSRuntime *runtime = JS_NewRuntime();
|
64
|
-
data->context = JS_NewContext(runtime);
|
65
|
-
|
66
|
-
return obj;
|
67
|
-
}
|
68
|
-
|
69
|
-
VALUE rb_cQuickjsVMLog, rb_cQuickjsSyntaxError, rb_cQuickjsRuntimeError, rb_cQuickjsInterruptedError, rb_cQuickjsNoAwaitError, rb_cQuickjsTypeError, rb_cQuickjsReferenceError, rb_cQuickjsRangeError, rb_cQuickjsEvalError, rb_cQuickjsURIError, rb_cQuickjsAggregateError;
|
70
|
-
const char *undefinedId = "undefined";
|
71
|
-
const char *nanId = "NaN";
|
72
|
-
|
73
|
-
const char *featureStdId = "feature_std";
|
74
|
-
const char *featureOsId = "feature_os";
|
75
|
-
const char *featureOsTimeoutId = "feature_os_timeout";
|
76
|
-
|
77
3
|
JSValue to_js_value(JSContext *ctx, VALUE r_value)
|
78
4
|
{
|
79
5
|
if (RTEST(rb_funcall(
|
@@ -168,7 +94,7 @@ VALUE to_rb_value(JSContext *ctx, JSValue j_val)
|
|
168
94
|
{
|
169
95
|
if (JS_VALUE_IS_NAN(j_val))
|
170
96
|
{
|
171
|
-
return
|
97
|
+
return QUICKJSRB_SYM(nanId);
|
172
98
|
}
|
173
99
|
double double_res;
|
174
100
|
JS_ToFloat64(ctx, &double_res, j_val);
|
@@ -191,7 +117,7 @@ VALUE to_rb_value(JSContext *ctx, JSValue j_val)
|
|
191
117
|
if (promiseState != -1)
|
192
118
|
{
|
193
119
|
VALUE r_error_message = rb_str_new2("cannot translate a Promise to Ruby. await within JavaScript's end");
|
194
|
-
rb_exc_raise(rb_funcall(
|
120
|
+
rb_exc_raise(rb_funcall(QUICKJSRB_ERROR_FOR(QUICKJSRB_ROOT_RUNTIME_ERROR), rb_intern("new"), 2, r_error_message, Qnil));
|
195
121
|
return Qnil;
|
196
122
|
}
|
197
123
|
|
@@ -204,17 +130,17 @@ VALUE to_rb_value(JSContext *ctx, JSValue j_val)
|
|
204
130
|
VALUE r_str = rb_str_new2(msg);
|
205
131
|
JS_FreeCString(ctx, msg);
|
206
132
|
|
207
|
-
JS_FreeValue(ctx, j_global);
|
208
133
|
JS_FreeValue(ctx, j_strigified);
|
209
134
|
JS_FreeValue(ctx, j_stringifyFunc);
|
210
135
|
JS_FreeValue(ctx, j_jsonClass);
|
136
|
+
JS_FreeValue(ctx, j_global);
|
211
137
|
|
212
138
|
return rb_funcall(rb_const_get(rb_cClass, rb_intern("JSON")), rb_intern("parse"), 1, r_str);
|
213
139
|
}
|
214
140
|
case JS_TAG_NULL:
|
215
141
|
return Qnil;
|
216
142
|
case JS_TAG_UNDEFINED:
|
217
|
-
return
|
143
|
+
return QUICKJSRB_SYM(undefinedId);
|
218
144
|
case JS_TAG_EXCEPTION:
|
219
145
|
{
|
220
146
|
JSValue j_exceptionVal = JS_GetException(ctx);
|
@@ -230,47 +156,27 @@ VALUE to_rb_value(JSContext *ctx, JSValue j_val)
|
|
230
156
|
JS_FreeValue(ctx, j_errorClassName);
|
231
157
|
|
232
158
|
VALUE r_error_class, r_error_message = rb_str_new2(errorClassMessage);
|
233
|
-
|
234
|
-
if (strcmp(errorClassName, "SyntaxError") == 0)
|
235
|
-
{
|
236
|
-
r_error_class = rb_cQuickjsSyntaxError;
|
237
|
-
}
|
238
|
-
else if (strcmp(errorClassName, "TypeError") == 0)
|
239
|
-
{
|
240
|
-
r_error_class = rb_cQuickjsTypeError;
|
241
|
-
}
|
242
|
-
else if (strcmp(errorClassName, "ReferenceError") == 0)
|
243
|
-
{
|
244
|
-
r_error_class = rb_cQuickjsReferenceError;
|
245
|
-
}
|
246
|
-
else if (strcmp(errorClassName, "RangeError") == 0)
|
247
|
-
{
|
248
|
-
r_error_class = rb_cQuickjsRangeError;
|
249
|
-
}
|
250
|
-
else if (strcmp(errorClassName, "EvalError") == 0)
|
251
|
-
{
|
252
|
-
r_error_class = rb_cQuickjsEvalError;
|
253
|
-
}
|
254
|
-
else if (strcmp(errorClassName, "URIError") == 0)
|
159
|
+
if (is_native_error_name(errorClassName))
|
255
160
|
{
|
256
|
-
r_error_class =
|
257
|
-
}
|
258
|
-
else if (strcmp(errorClassName, "AggregateError") == 0)
|
259
|
-
{
|
260
|
-
r_error_class = rb_cQuickjsAggregateError;
|
161
|
+
r_error_class = QUICKJSRB_ERROR_FOR(errorClassName);
|
261
162
|
}
|
262
163
|
else if (strcmp(errorClassName, "InternalError") == 0 && strstr(errorClassMessage, "interrupted") != NULL)
|
263
164
|
{
|
264
|
-
r_error_class =
|
165
|
+
r_error_class = QUICKJSRB_ERROR_FOR(QUICKJSRB_INTERRUPTED_ERROR);
|
265
166
|
r_error_message = rb_str_new2("Code evaluation is interrupted by the timeout or something");
|
266
167
|
}
|
168
|
+
else if (strcmp(errorClassName, "InternalError") == 0 && strstr(errorClassMessage, "Ruby") != NULL)
|
169
|
+
{
|
170
|
+
r_error_class = QUICKJSRB_ERROR_FOR(QUICKJSRB_RUBY_FUNCTION_ERROR);
|
171
|
+
}
|
172
|
+
|
267
173
|
else if (strcmp(errorClassName, "Quickjs::InterruptedError") == 0)
|
268
174
|
{
|
269
|
-
r_error_class =
|
175
|
+
r_error_class = QUICKJSRB_ERROR_FOR(QUICKJSRB_INTERRUPTED_ERROR);
|
270
176
|
}
|
271
177
|
else
|
272
178
|
{
|
273
|
-
r_error_class =
|
179
|
+
r_error_class = QUICKJSRB_ERROR_FOR(QUICKJSRB_ROOT_RUNTIME_ERROR);
|
274
180
|
}
|
275
181
|
JS_FreeCString(ctx, errorClassName);
|
276
182
|
JS_FreeCString(ctx, errorClassMessage);
|
@@ -285,7 +191,7 @@ VALUE to_rb_value(JSContext *ctx, JSValue j_val)
|
|
285
191
|
|
286
192
|
JS_FreeCString(ctx, errorMessage);
|
287
193
|
JS_FreeValue(ctx, j_exceptionVal);
|
288
|
-
rb_exc_raise(rb_funcall(
|
194
|
+
rb_exc_raise(rb_funcall(QUICKJSRB_ERROR_FOR(QUICKJSRB_ROOT_RUNTIME_ERROR), rb_intern("new"), 2, r_error_message, Qnil));
|
289
195
|
}
|
290
196
|
return Qnil;
|
291
197
|
}
|
@@ -310,6 +216,18 @@ VALUE to_rb_value(JSContext *ctx, JSValue j_val)
|
|
310
216
|
}
|
311
217
|
}
|
312
218
|
|
219
|
+
static VALUE r_try_call_proc(VALUE r_try_args)
|
220
|
+
{
|
221
|
+
return rb_funcall(
|
222
|
+
rb_const_get(rb_cClass, rb_intern("Quickjs")),
|
223
|
+
rb_intern("_with_timeout"),
|
224
|
+
3,
|
225
|
+
RARRAY_AREF(r_try_args, 2), // timeout
|
226
|
+
RARRAY_AREF(r_try_args, 0), // proc
|
227
|
+
RARRAY_AREF(r_try_args, 1) // args for proc
|
228
|
+
);
|
229
|
+
}
|
230
|
+
|
313
231
|
static JSValue js_quickjsrb_call_global(JSContext *ctx, JSValueConst _this, int _argc, JSValueConst *argv)
|
314
232
|
{
|
315
233
|
VMData *data = JS_GetContextOpaque(ctx);
|
@@ -322,17 +240,25 @@ static JSValue js_quickjsrb_call_global(JSContext *ctx, JSValueConst _this, int
|
|
322
240
|
{ // Shouldn't happen
|
323
241
|
return JS_ThrowReferenceError(ctx, "Proc `%s` is not defined", funcName);
|
324
242
|
}
|
325
|
-
JS_FreeCString(ctx, funcName);
|
326
243
|
|
327
|
-
VALUE
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
ULONG2NUM(data->eval_time->limit * 1000 / CLOCKS_PER_SEC),
|
332
|
-
r_proc,
|
333
|
-
to_rb_value(ctx, argv[1]));
|
244
|
+
VALUE r_call_args = rb_ary_new();
|
245
|
+
rb_ary_push(r_call_args, r_proc);
|
246
|
+
rb_ary_push(r_call_args, to_rb_value(ctx, argv[1]));
|
247
|
+
rb_ary_push(r_call_args, ULONG2NUM(data->eval_time->limit * 1000 / CLOCKS_PER_SEC));
|
334
248
|
|
335
|
-
|
249
|
+
int sadnessHappened;
|
250
|
+
VALUE r_result = rb_protect(r_try_call_proc, r_call_args, &sadnessHappened);
|
251
|
+
JSValue j_result;
|
252
|
+
if (sadnessHappened)
|
253
|
+
{
|
254
|
+
j_result = JS_ThrowInternalError(ctx, "unintentional error is raised while executing the function by Ruby: `%s`", funcName);
|
255
|
+
}
|
256
|
+
else
|
257
|
+
{
|
258
|
+
j_result = to_js_value(ctx, r_result);
|
259
|
+
}
|
260
|
+
JS_FreeCString(ctx, funcName);
|
261
|
+
return j_result;
|
336
262
|
}
|
337
263
|
|
338
264
|
static JSValue js_quickjsrb_log(JSContext *ctx, JSValueConst _this, int _argc, JSValueConst *argv)
|
@@ -342,8 +268,10 @@ static JSValue js_quickjsrb_log(JSContext *ctx, JSValueConst _this, int _argc, J
|
|
342
268
|
const char *severity = JS_ToCString(ctx, j_severity);
|
343
269
|
JS_FreeValue(ctx, j_severity);
|
344
270
|
|
345
|
-
VALUE
|
271
|
+
VALUE r_log_class = rb_const_get(rb_const_get(rb_const_get(rb_cClass, rb_intern("Quickjs")), rb_intern("VM")), rb_intern("Log"));
|
272
|
+
VALUE r_log = rb_funcall(r_log_class, rb_intern("new"), 0);
|
346
273
|
rb_iv_set(r_log, "@severity", ID2SYM(rb_intern(severity)));
|
274
|
+
JS_FreeCString(ctx, severity);
|
347
275
|
|
348
276
|
VALUE r_row = rb_ary_new();
|
349
277
|
int i;
|
@@ -351,22 +279,28 @@ static JSValue js_quickjsrb_log(JSContext *ctx, JSValueConst _this, int _argc, J
|
|
351
279
|
int count;
|
352
280
|
JS_ToInt32(ctx, &count, j_length);
|
353
281
|
JS_FreeValue(ctx, j_length);
|
282
|
+
|
354
283
|
for (i = 0; i < count; i++)
|
355
284
|
{
|
285
|
+
VALUE r_loghash = rb_hash_new();
|
356
286
|
JSValue j_logged = JS_GetPropertyUint32(ctx, argv[1], i);
|
287
|
+
if (JS_VALUE_GET_NORM_TAG(j_logged) == JS_TAG_OBJECT && JS_PromiseState(ctx, j_logged) != -1)
|
288
|
+
{
|
289
|
+
rb_hash_aset(r_loghash, ID2SYM(rb_intern("raw")), rb_str_new2("Promise"));
|
290
|
+
}
|
291
|
+
else
|
292
|
+
{
|
293
|
+
rb_hash_aset(r_loghash, ID2SYM(rb_intern("raw")), to_rb_value(ctx, j_logged));
|
294
|
+
}
|
357
295
|
const char *body = JS_ToCString(ctx, j_logged);
|
358
|
-
VALUE r_loghash = rb_hash_new();
|
359
|
-
rb_hash_aset(r_loghash, ID2SYM(rb_intern("c")), rb_str_new2(body));
|
360
|
-
rb_hash_aset(r_loghash, ID2SYM(rb_intern("raw")), to_rb_value(ctx, j_logged));
|
361
|
-
rb_ary_push(r_row, r_loghash);
|
362
296
|
JS_FreeValue(ctx, j_logged);
|
297
|
+
rb_hash_aset(r_loghash, ID2SYM(rb_intern("c")), rb_str_new2(body));
|
363
298
|
JS_FreeCString(ctx, body);
|
299
|
+
rb_ary_push(r_row, r_loghash);
|
364
300
|
}
|
365
301
|
|
366
302
|
rb_iv_set(r_log, "@row", r_row);
|
367
303
|
rb_ary_push(data->logs, r_log);
|
368
|
-
JS_FreeCString(ctx, severity);
|
369
|
-
|
370
304
|
return JS_UNDEFINED;
|
371
305
|
}
|
372
306
|
|
@@ -408,7 +342,7 @@ static VALUE vm_m_initialize(int argc, VALUE *argv, VALUE r_self)
|
|
408
342
|
JS_SetModuleLoaderFunc(runtime, NULL, js_module_loader, NULL);
|
409
343
|
js_std_init_handlers(runtime);
|
410
344
|
|
411
|
-
if (RTEST(rb_funcall(r_features, rb_intern("include?"), 1,
|
345
|
+
if (RTEST(rb_funcall(r_features, rb_intern("include?"), 1, QUICKJSRB_SYM(featureStdId))))
|
412
346
|
{
|
413
347
|
js_init_module_std(data->context, "std");
|
414
348
|
const char *enableStd = "import * as std from 'std';\n"
|
@@ -417,7 +351,7 @@ static VALUE vm_m_initialize(int argc, VALUE *argv, VALUE r_self)
|
|
417
351
|
JS_FreeValue(data->context, j_stdEval);
|
418
352
|
}
|
419
353
|
|
420
|
-
if (RTEST(rb_funcall(r_features, rb_intern("include?"), 1,
|
354
|
+
if (RTEST(rb_funcall(r_features, rb_intern("include?"), 1, QUICKJSRB_SYM(featureOsId))))
|
421
355
|
{
|
422
356
|
js_init_module_os(data->context, "os");
|
423
357
|
const char *enableOs = "import * as os from 'os';\n"
|
@@ -425,13 +359,19 @@ static VALUE vm_m_initialize(int argc, VALUE *argv, VALUE r_self)
|
|
425
359
|
JSValue j_osEval = JS_Eval(data->context, enableOs, strlen(enableOs), "<vm>", JS_EVAL_TYPE_MODULE);
|
426
360
|
JS_FreeValue(data->context, j_osEval);
|
427
361
|
}
|
428
|
-
else if (RTEST(rb_funcall(r_features, rb_intern("include?"), 1,
|
362
|
+
else if (RTEST(rb_funcall(r_features, rb_intern("include?"), 1, QUICKJSRB_SYM(featureOsTimeoutId))))
|
429
363
|
{
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
364
|
+
char *filename = random_string();
|
365
|
+
js_init_module_os(data->context, filename); // Better if this is limited just only for setTimeout and clearTimeout
|
366
|
+
const char *enableTimeoutTemplate = "import * as _os from '%s';\n"
|
367
|
+
"globalThis.setTimeout = _os.setTimeout;\n"
|
368
|
+
"globalThis.clearTimeout = _os.clearTimeout;\n";
|
369
|
+
int length = snprintf(NULL, 0, enableTimeoutTemplate, filename);
|
370
|
+
char *enableTimeout = (char *)malloc(length + 1);
|
371
|
+
snprintf(enableTimeout, length + 1, enableTimeoutTemplate, filename);
|
372
|
+
|
434
373
|
JSValue j_timeoutEval = JS_Eval(data->context, enableTimeout, strlen(enableTimeout), "<vm>", JS_EVAL_TYPE_MODULE);
|
374
|
+
free(enableTimeout);
|
435
375
|
JS_FreeValue(data->context, j_timeoutEval);
|
436
376
|
}
|
437
377
|
|
@@ -477,7 +417,7 @@ static VALUE vm_m_evalCode(VALUE r_self, VALUE r_code)
|
|
477
417
|
|
478
418
|
char *code = StringValueCStr(r_code);
|
479
419
|
JSValue j_codeResult = JS_Eval(data->context, code, strlen(code), "<code>", JS_EVAL_TYPE_GLOBAL | JS_EVAL_FLAG_ASYNC);
|
480
|
-
JSValue j_awaitedResult = js_std_await(data->context, j_codeResult);
|
420
|
+
JSValue j_awaitedResult = js_std_await(data->context, j_codeResult); // This frees j_codeResult
|
481
421
|
JSValue j_returnedValue = JS_GetPropertyStr(data->context, j_awaitedResult, "value");
|
482
422
|
// Do this by rescuing to_rb_value
|
483
423
|
if (JS_VALUE_GET_NORM_TAG(j_returnedValue) == JS_TAG_OBJECT && JS_PromiseState(data->context, j_returnedValue) != -1)
|
@@ -485,7 +425,7 @@ static VALUE vm_m_evalCode(VALUE r_self, VALUE r_code)
|
|
485
425
|
JS_FreeValue(data->context, j_returnedValue);
|
486
426
|
JS_FreeValue(data->context, j_awaitedResult);
|
487
427
|
VALUE r_error_message = rb_str_new2("An unawaited Promise was returned to the top-level");
|
488
|
-
rb_exc_raise(rb_funcall(
|
428
|
+
rb_exc_raise(rb_funcall(QUICKJSRB_ERROR_FOR(QUICKJSRB_NO_AWAIT_ERROR), rb_intern("new"), 2, r_error_message, Qnil));
|
489
429
|
return Qnil;
|
490
430
|
}
|
491
431
|
else
|
@@ -497,30 +437,34 @@ static VALUE vm_m_evalCode(VALUE r_self, VALUE r_code)
|
|
497
437
|
}
|
498
438
|
}
|
499
439
|
|
500
|
-
static VALUE vm_m_defineGlobalFunction(VALUE
|
440
|
+
static VALUE vm_m_defineGlobalFunction(int argc, VALUE *argv, VALUE r_self)
|
501
441
|
{
|
502
442
|
rb_need_block();
|
503
443
|
|
444
|
+
VALUE r_name;
|
445
|
+
VALUE r_flags;
|
446
|
+
VALUE r_block;
|
447
|
+
rb_scan_args(argc, argv, "10*&", &r_name, &r_flags, &r_block);
|
448
|
+
|
449
|
+
const char *asyncKeyword =
|
450
|
+
RTEST(rb_funcall(r_flags, rb_intern("include?"), 1, ID2SYM(rb_intern("async")))) ? "async " : "";
|
451
|
+
|
504
452
|
VMData *data;
|
505
453
|
TypedData_Get_Struct(r_self, VMData, &vm_type, data);
|
506
454
|
|
507
|
-
|
508
|
-
|
509
|
-
VALUE r_proc = rb_block_proc();
|
510
|
-
rb_hash_aset(data->defined_functions, r_name, r_proc);
|
511
|
-
char *funcName = StringValueCStr(r_name);
|
455
|
+
rb_hash_aset(data->defined_functions, r_name, r_block);
|
456
|
+
char *funcName = StringValueCStr(r_name);
|
512
457
|
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
458
|
+
const char *template = "globalThis['%s'] = %s(...args) => __quickjsrb.runRubyMethod('%s', args);\n";
|
459
|
+
int length = snprintf(NULL, 0, template, funcName, asyncKeyword, funcName);
|
460
|
+
char *result = (char *)malloc(length + 1);
|
461
|
+
snprintf(result, length + 1, template, funcName, asyncKeyword, funcName);
|
517
462
|
|
518
|
-
|
463
|
+
JSValue j_codeResult = JS_Eval(data->context, result, strlen(result), "<vm>", JS_EVAL_TYPE_MODULE);
|
519
464
|
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
}
|
465
|
+
free(result);
|
466
|
+
JS_FreeValue(data->context, j_codeResult);
|
467
|
+
return rb_funcall(r_name, rb_intern("to_sym"), 0, NULL);
|
524
468
|
|
525
469
|
return Qnil;
|
526
470
|
}
|
@@ -535,15 +479,16 @@ static VALUE vm_m_import(int argc, VALUE *argv, VALUE r_self)
|
|
535
479
|
if (NIL_P(r_from))
|
536
480
|
{
|
537
481
|
VALUE r_error_message = rb_str_new2("missing import source");
|
538
|
-
rb_exc_raise(rb_funcall(
|
482
|
+
rb_exc_raise(rb_funcall(QUICKJSRB_ERROR_FOR(QUICKJSRB_ROOT_RUNTIME_ERROR), rb_intern("new"), 2, r_error_message, Qnil));
|
539
483
|
return Qnil;
|
540
484
|
}
|
541
485
|
|
542
486
|
VMData *data;
|
543
487
|
TypedData_Get_Struct(r_self, VMData, &vm_type, data);
|
544
488
|
|
489
|
+
char *filename = random_string();
|
545
490
|
char *source = StringValueCStr(r_from);
|
546
|
-
JSValue func = JS_Eval(data->context, source, strlen(source),
|
491
|
+
JSValue func = JS_Eval(data->context, source, strlen(source), filename, JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY);
|
547
492
|
js_module_set_import_meta(data->context, func, TRUE, FALSE);
|
548
493
|
JS_FreeValue(data->context, func);
|
549
494
|
|
@@ -557,11 +502,11 @@ static VALUE vm_m_import(int argc, VALUE *argv, VALUE r_self)
|
|
557
502
|
VALUE r_globalize = rb_ary_entry(r_import_settings, 1);
|
558
503
|
char *globalize = StringValueCStr(r_globalize);
|
559
504
|
|
560
|
-
const char *importAndGlobalizeModule = "import %s from '
|
505
|
+
const char *importAndGlobalizeModule = "import %s from '%s';\n"
|
561
506
|
"%s\n";
|
562
|
-
int length = snprintf(NULL, 0, importAndGlobalizeModule, import_name, globalize);
|
507
|
+
int length = snprintf(NULL, 0, importAndGlobalizeModule, import_name, filename, globalize);
|
563
508
|
char *result = (char *)malloc(length + 1);
|
564
|
-
snprintf(result, length + 1, importAndGlobalizeModule, import_name, globalize);
|
509
|
+
snprintf(result, length + 1, importAndGlobalizeModule, import_name, filename, globalize);
|
565
510
|
|
566
511
|
JSValue j_codeResult = JS_Eval(data->context, result, strlen(result), "<vm>", JS_EVAL_TYPE_MODULE);
|
567
512
|
free(result);
|
@@ -570,7 +515,7 @@ static VALUE vm_m_import(int argc, VALUE *argv, VALUE r_self)
|
|
570
515
|
return Qtrue;
|
571
516
|
}
|
572
517
|
|
573
|
-
static VALUE
|
518
|
+
static VALUE vm_m_logs(VALUE r_self)
|
574
519
|
{
|
575
520
|
VMData *data;
|
576
521
|
TypedData_Get_Struct(r_self, VMData, &vm_type, data);
|
@@ -578,77 +523,21 @@ static VALUE vm_m_getLogs(VALUE r_self)
|
|
578
523
|
return data->logs;
|
579
524
|
}
|
580
525
|
|
581
|
-
static VALUE pick_raw(VALUE block_arg, VALUE data, int argc, const VALUE *argv, VALUE blockarg)
|
582
|
-
{
|
583
|
-
return rb_hash_aref(block_arg, ID2SYM(rb_intern("raw")));
|
584
|
-
}
|
585
|
-
|
586
|
-
static VALUE vm_m_raw(VALUE r_self)
|
587
|
-
{
|
588
|
-
VALUE row = rb_iv_get(r_self, "@row");
|
589
|
-
VALUE r_ary = rb_block_call(row, rb_intern("map"), 0, NULL, pick_raw, Qnil);
|
590
|
-
|
591
|
-
return r_ary;
|
592
|
-
}
|
593
|
-
|
594
|
-
static VALUE pick_c(VALUE block_arg, VALUE data, int argc, const VALUE *argv, VALUE blockarg)
|
595
|
-
{
|
596
|
-
return rb_hash_aref(block_arg, ID2SYM(rb_intern("c")));
|
597
|
-
}
|
598
|
-
|
599
|
-
static VALUE vm_m_to_s(VALUE r_self)
|
600
|
-
{
|
601
|
-
VALUE row = rb_iv_get(r_self, "@row");
|
602
|
-
VALUE r_ary = rb_block_call(row, rb_intern("map"), 0, NULL, pick_c, Qnil);
|
603
|
-
|
604
|
-
return rb_funcall(r_ary, rb_intern("join"), 1, rb_str_new2(" "));
|
605
|
-
}
|
606
|
-
|
607
|
-
VALUE vm_m_initialize_quickjs_error(VALUE self, VALUE r_message, VALUE r_js_name)
|
608
|
-
{
|
609
|
-
rb_call_super(1, &r_message);
|
610
|
-
rb_iv_set(self, "@js_name", r_js_name);
|
611
|
-
|
612
|
-
return self;
|
613
|
-
}
|
614
|
-
|
615
526
|
RUBY_FUNC_EXPORTED void Init_quickjsrb(void)
|
616
527
|
{
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
rb_define_method(
|
629
|
-
rb_define_method(
|
630
|
-
rb_define_method(
|
631
|
-
|
632
|
-
rb_define_method(rb_cQuickjsVM, "logs", vm_m_getLogs, 0);
|
633
|
-
|
634
|
-
rb_cQuickjsVMLog = rb_define_class_under(rb_cQuickjsVM, "Log", rb_cObject);
|
635
|
-
rb_define_attr(rb_cQuickjsVMLog, "severity", 1, 0);
|
636
|
-
rb_define_method(rb_cQuickjsVMLog, "raw", vm_m_raw, 0);
|
637
|
-
rb_define_method(rb_cQuickjsVMLog, "to_s", vm_m_to_s, 0);
|
638
|
-
rb_define_method(rb_cQuickjsVMLog, "inspect", vm_m_to_s, 0);
|
639
|
-
|
640
|
-
rb_cQuickjsRuntimeError = rb_define_class_under(rb_mQuickjs, "RuntimeError", rb_eRuntimeError);
|
641
|
-
rb_define_method(rb_cQuickjsRuntimeError, "initialize", vm_m_initialize_quickjs_error, 2);
|
642
|
-
rb_define_attr(rb_cQuickjsRuntimeError, "js_name", 1, 0);
|
643
|
-
|
644
|
-
rb_cQuickjsSyntaxError = rb_define_class_under(rb_mQuickjs, "SyntaxError", rb_cQuickjsRuntimeError);
|
645
|
-
rb_cQuickjsTypeError = rb_define_class_under(rb_mQuickjs, "TypeError", rb_cQuickjsRuntimeError);
|
646
|
-
rb_cQuickjsRangeError = rb_define_class_under(rb_mQuickjs, "RangeError", rb_cQuickjsRuntimeError);
|
647
|
-
rb_cQuickjsReferenceError = rb_define_class_under(rb_mQuickjs, "ReferenceError", rb_cQuickjsRuntimeError);
|
648
|
-
rb_cQuickjsURIError = rb_define_class_under(rb_mQuickjs, "URIError", rb_cQuickjsRuntimeError);
|
649
|
-
rb_cQuickjsEvalError = rb_define_class_under(rb_mQuickjs, "EvalError", rb_cQuickjsRuntimeError);
|
650
|
-
rb_cQuickjsAggregateError = rb_define_class_under(rb_mQuickjs, "AggregateError", rb_cQuickjsRuntimeError);
|
651
|
-
|
652
|
-
rb_cQuickjsInterruptedError = rb_define_class_under(rb_mQuickjs, "InterruptedError", rb_cQuickjsRuntimeError);
|
653
|
-
rb_cQuickjsNoAwaitError = rb_define_class_under(rb_mQuickjs, "NoAwaitError", rb_cQuickjsRuntimeError);
|
528
|
+
rb_require("json");
|
529
|
+
rb_require("securerandom");
|
530
|
+
|
531
|
+
VALUE r_module_quickjs = rb_define_module("Quickjs");
|
532
|
+
r_define_constants(r_module_quickjs);
|
533
|
+
r_define_exception_classes(r_module_quickjs);
|
534
|
+
|
535
|
+
VALUE r_class_vm = rb_define_class_under(r_module_quickjs, "VM", rb_cObject);
|
536
|
+
rb_define_alloc_func(r_class_vm, vm_alloc);
|
537
|
+
rb_define_method(r_class_vm, "initialize", vm_m_initialize, -1);
|
538
|
+
rb_define_method(r_class_vm, "eval_code", vm_m_evalCode, 1);
|
539
|
+
rb_define_method(r_class_vm, "define_function", vm_m_defineGlobalFunction, -1);
|
540
|
+
rb_define_method(r_class_vm, "import", vm_m_import, -1);
|
541
|
+
rb_define_method(r_class_vm, "logs", vm_m_logs, 0);
|
542
|
+
r_define_log_class(r_class_vm);
|
654
543
|
}
|
data/ext/quickjsrb/quickjsrb.h
CHANGED
@@ -12,4 +12,207 @@
|
|
12
12
|
#include <string.h>
|
13
13
|
#include <time.h>
|
14
14
|
|
15
|
+
const char *featureStdId = "feature_std";
|
16
|
+
const char *featureOsId = "feature_os";
|
17
|
+
const char *featureOsTimeoutId = "feature_os_timeout";
|
18
|
+
|
19
|
+
const char *undefinedId = "undefined";
|
20
|
+
const char *nanId = "NaN";
|
21
|
+
|
22
|
+
const char *native_errors[] = {
|
23
|
+
"SyntaxError",
|
24
|
+
"TypeError",
|
25
|
+
"ReferenceError",
|
26
|
+
"RangeError",
|
27
|
+
"EvalError",
|
28
|
+
"URIError",
|
29
|
+
"AggregateError"};
|
30
|
+
|
31
|
+
#define QUICKJSRB_SYM(id) \
|
32
|
+
(VALUE) { ID2SYM(rb_intern(id)) }
|
33
|
+
|
34
|
+
// VM data structure
|
35
|
+
|
36
|
+
typedef struct EvalTime
|
37
|
+
{
|
38
|
+
clock_t limit;
|
39
|
+
clock_t started_at;
|
40
|
+
} EvalTime;
|
41
|
+
|
42
|
+
typedef struct VMData
|
43
|
+
{
|
44
|
+
struct JSContext *context;
|
45
|
+
VALUE defined_functions;
|
46
|
+
struct EvalTime *eval_time;
|
47
|
+
VALUE logs;
|
48
|
+
} VMData;
|
49
|
+
|
50
|
+
static void vm_free(void *ptr)
|
51
|
+
{
|
52
|
+
VMData *data = (VMData *)ptr;
|
53
|
+
free(data->eval_time);
|
54
|
+
|
55
|
+
JSRuntime *runtime = JS_GetRuntime(data->context);
|
56
|
+
JS_SetInterruptHandler(runtime, NULL, NULL);
|
57
|
+
js_std_free_handlers(runtime);
|
58
|
+
JS_FreeContext(data->context);
|
59
|
+
JS_FreeRuntime(runtime);
|
60
|
+
|
61
|
+
xfree(ptr);
|
62
|
+
}
|
63
|
+
|
64
|
+
size_t vm_size(const void *data)
|
65
|
+
{
|
66
|
+
return sizeof(VMData);
|
67
|
+
}
|
68
|
+
|
69
|
+
static void vm_mark(void *ptr)
|
70
|
+
{
|
71
|
+
VMData *data = (VMData *)ptr;
|
72
|
+
rb_gc_mark_movable(data->defined_functions);
|
73
|
+
rb_gc_mark_movable(data->logs);
|
74
|
+
}
|
75
|
+
|
76
|
+
static const rb_data_type_t vm_type = {
|
77
|
+
.wrap_struct_name = "quickjsvm",
|
78
|
+
.function = {
|
79
|
+
.dmark = vm_mark,
|
80
|
+
.dfree = vm_free,
|
81
|
+
.dsize = vm_size,
|
82
|
+
},
|
83
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY,
|
84
|
+
};
|
85
|
+
|
86
|
+
static VALUE vm_alloc(VALUE r_self)
|
87
|
+
{
|
88
|
+
VMData *data;
|
89
|
+
VALUE obj = TypedData_Make_Struct(r_self, VMData, &vm_type, data);
|
90
|
+
data->defined_functions = rb_hash_new();
|
91
|
+
data->logs = rb_ary_new();
|
92
|
+
|
93
|
+
EvalTime *eval_time = malloc(sizeof(EvalTime));
|
94
|
+
data->eval_time = eval_time;
|
95
|
+
|
96
|
+
JSRuntime *runtime = JS_NewRuntime();
|
97
|
+
data->context = JS_NewContext(runtime);
|
98
|
+
|
99
|
+
return obj;
|
100
|
+
}
|
101
|
+
|
102
|
+
// Utils
|
103
|
+
|
104
|
+
static char *random_string()
|
105
|
+
{
|
106
|
+
VALUE r_rand = rb_funcall(
|
107
|
+
rb_const_get(rb_cClass, rb_intern("SecureRandom")),
|
108
|
+
rb_intern("alphanumeric"),
|
109
|
+
1,
|
110
|
+
INT2NUM(12));
|
111
|
+
return StringValueCStr(r_rand);
|
112
|
+
}
|
113
|
+
|
114
|
+
static bool is_native_error_name(const char *error_name)
|
115
|
+
{
|
116
|
+
bool is_native_error = false;
|
117
|
+
int numStrings = sizeof(native_errors) / sizeof(native_errors[0]);
|
118
|
+
for (int i = 0; i < numStrings; i++)
|
119
|
+
{
|
120
|
+
if (strcmp(native_errors[i], error_name) == 0)
|
121
|
+
{
|
122
|
+
is_native_error = true;
|
123
|
+
break;
|
124
|
+
}
|
125
|
+
}
|
126
|
+
return is_native_error;
|
127
|
+
}
|
128
|
+
|
129
|
+
// Constants
|
130
|
+
|
131
|
+
static void r_define_constants(VALUE r_parent_class)
|
132
|
+
{
|
133
|
+
rb_define_const(r_parent_class, "MODULE_STD", QUICKJSRB_SYM(featureStdId));
|
134
|
+
rb_define_const(r_parent_class, "MODULE_OS", QUICKJSRB_SYM(featureOsId));
|
135
|
+
rb_define_const(r_parent_class, "FEATURES_TIMEOUT", QUICKJSRB_SYM(featureOsTimeoutId));
|
136
|
+
|
137
|
+
VALUE rb_cQuickjsValue = rb_define_class_under(r_parent_class, "Value", rb_cObject);
|
138
|
+
rb_define_const(rb_cQuickjsValue, "UNDEFINED", QUICKJSRB_SYM(undefinedId));
|
139
|
+
rb_define_const(rb_cQuickjsValue, "NAN", QUICKJSRB_SYM(nanId));
|
140
|
+
}
|
141
|
+
|
142
|
+
// Log class
|
143
|
+
|
144
|
+
static VALUE r_proc_pick_raw(VALUE block_arg, VALUE data, int argc, const VALUE *argv, VALUE blockarg)
|
145
|
+
{
|
146
|
+
return rb_hash_aref(block_arg, ID2SYM(rb_intern("raw")));
|
147
|
+
}
|
148
|
+
|
149
|
+
static VALUE r_log_m_raw(VALUE r_self)
|
150
|
+
{
|
151
|
+
VALUE row = rb_iv_get(r_self, "@row");
|
152
|
+
VALUE r_ary = rb_block_call(row, rb_intern("map"), 0, NULL, r_proc_pick_raw, Qnil);
|
153
|
+
|
154
|
+
return r_ary;
|
155
|
+
}
|
156
|
+
|
157
|
+
static VALUE r_proc_pick_c(VALUE block_arg, VALUE data, int argc, const VALUE *argv, VALUE blockarg)
|
158
|
+
{
|
159
|
+
return rb_hash_aref(block_arg, ID2SYM(rb_intern("c")));
|
160
|
+
}
|
161
|
+
|
162
|
+
static VALUE r_log_m_to_s(VALUE r_self)
|
163
|
+
{
|
164
|
+
VALUE row = rb_iv_get(r_self, "@row");
|
165
|
+
VALUE r_ary = rb_block_call(row, rb_intern("map"), 0, NULL, r_proc_pick_c, Qnil);
|
166
|
+
|
167
|
+
return rb_funcall(r_ary, rb_intern("join"), 1, rb_str_new2(" "));
|
168
|
+
}
|
169
|
+
|
170
|
+
static VALUE r_define_log_class(VALUE r_parent_class)
|
171
|
+
{
|
172
|
+
VALUE r_log_class = rb_define_class_under(r_parent_class, "Log", rb_cObject);
|
173
|
+
rb_define_attr(r_log_class, "severity", 1, 0);
|
174
|
+
rb_define_method(r_log_class, "raw", r_log_m_raw, 0);
|
175
|
+
rb_define_method(r_log_class, "to_s", r_log_m_to_s, 0);
|
176
|
+
rb_define_method(r_log_class, "inspect", r_log_m_to_s, 0);
|
177
|
+
|
178
|
+
return r_log_class;
|
179
|
+
}
|
180
|
+
|
181
|
+
// Exceptions
|
182
|
+
|
183
|
+
#define QUICKJSRB_ROOT_RUNTIME_ERROR "RuntimeError"
|
184
|
+
#define QUICKJSRB_INTERRUPTED_ERROR "InterruptedError"
|
185
|
+
#define QUICKJSRB_NO_AWAIT_ERROR "NoAwaitError"
|
186
|
+
#define QUICKJSRB_RUBY_FUNCTION_ERROR "RubyFunctionError"
|
187
|
+
|
188
|
+
#define QUICKJSRB_ERROR_FOR(name) \
|
189
|
+
(VALUE) { rb_const_get(rb_const_get(rb_cClass, rb_intern("Quickjs")), rb_intern(name)) }
|
190
|
+
|
191
|
+
VALUE vm_m_initialize_quickjs_error(VALUE self, VALUE r_message, VALUE r_js_name)
|
192
|
+
{
|
193
|
+
rb_call_super(1, &r_message);
|
194
|
+
rb_iv_set(self, "@js_name", r_js_name);
|
195
|
+
|
196
|
+
return self;
|
197
|
+
}
|
198
|
+
|
199
|
+
static void r_define_exception_classes(VALUE r_parent_class)
|
200
|
+
{
|
201
|
+
VALUE r_runtime_error = rb_define_class_under(r_parent_class, QUICKJSRB_ROOT_RUNTIME_ERROR, rb_eRuntimeError);
|
202
|
+
rb_define_method(r_runtime_error, "initialize", vm_m_initialize_quickjs_error, 2);
|
203
|
+
rb_define_attr(r_runtime_error, "js_name", 1, 0);
|
204
|
+
|
205
|
+
// JS native errors
|
206
|
+
int numStrings = sizeof(native_errors) / sizeof(native_errors[0]);
|
207
|
+
for (int i = 0; i < numStrings; i++)
|
208
|
+
{
|
209
|
+
rb_define_class_under(r_parent_class, native_errors[i], r_runtime_error);
|
210
|
+
}
|
211
|
+
|
212
|
+
// quickjsrb specific errors
|
213
|
+
rb_define_class_under(r_parent_class, QUICKJSRB_INTERRUPTED_ERROR, r_runtime_error);
|
214
|
+
rb_define_class_under(r_parent_class, QUICKJSRB_NO_AWAIT_ERROR, r_runtime_error);
|
215
|
+
rb_define_class_under(r_parent_class, QUICKJSRB_RUBY_FUNCTION_ERROR, r_runtime_error);
|
216
|
+
}
|
217
|
+
|
15
218
|
#endif /* QUICKJSRB_H */
|
data/lib/quickjs/version.rb
CHANGED
data/lib/quickjs.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "timeout"
|
4
|
-
require "json"
|
5
4
|
require_relative "quickjs/version"
|
6
5
|
require_relative "quickjs/quickjsrb"
|
7
6
|
|
@@ -18,8 +17,8 @@ module Quickjs
|
|
18
17
|
Timeout.timeout(msec / 1_000.0) { proc.call(*args) }
|
19
18
|
rescue Timeout::Error
|
20
19
|
Quickjs::InterruptedError.new('Ruby runtime got timeout', nil)
|
21
|
-
rescue
|
22
|
-
|
20
|
+
rescue
|
21
|
+
raise
|
23
22
|
end
|
24
23
|
module_function :_with_timeout
|
25
24
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: quickjs
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- hmsk
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-10-
|
11
|
+
date: 2024-10-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: json
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: securerandom
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
27
41
|
description: A native wrapper to run QuickJS in Ruby
|
28
42
|
email:
|
29
43
|
- k.hamasaki@gmail.com
|