quickjs 0.2.2 → 0.3.0
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/ext/quickjsrb/quickjsrb.c +137 -44
- data/lib/quickjs/version.rb +1 -1
- data/lib/quickjs.rb +3 -3
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ecc8aa4eddd6aca97baf0e773c4880b4479b4ac4597e0edf811d256eeb61aeb9
|
4
|
+
data.tar.gz: 37c8eeef2cad6e0d7773e89759c7d2d1659219247883cfd1817f2603ffbf1543
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2728bcbae59fae1138bdb5aef4e2f22290db93ce6c1e81f031e25c43108287a4f4d93d20afcfd9cb19a0e55593e1ccdadf1d83ebfbb430ee802368b73994cc2b
|
7
|
+
data.tar.gz: d06939ece851f9f4fb1311846826cad5c92e594511948ac9659bb190ebe6f905fdce15b4b9d16cf5df3b08bc5483a6f27d847f3ddf752aaa18bfcf74fec087e1
|
data/ext/quickjsrb/quickjsrb.c
CHANGED
@@ -1,22 +1,22 @@
|
|
1
1
|
#include "quickjsrb.h"
|
2
2
|
|
3
|
-
JSValue
|
3
|
+
JSValue j_error_from_ruby_error(JSContext *ctx, VALUE r_error)
|
4
4
|
{
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
return JS_Throw(ctx, j_error);
|
18
|
-
}
|
5
|
+
JSValue j_error = JS_NewError(ctx); // may wanna have custom error class to determine in JS' end
|
6
|
+
|
7
|
+
VALUE r_object_id = rb_funcall(r_error, rb_intern("object_id"), 0, NULL);
|
8
|
+
int objectId = NUM2INT(r_object_id);
|
9
|
+
JS_SetPropertyStr(ctx, j_error, "rb_object_id", JS_NewInt32(ctx, objectId));
|
10
|
+
|
11
|
+
VALUE r_exception_message = rb_funcall(r_error, rb_intern("message"), 0, NULL);
|
12
|
+
const char *errorMessage = StringValueCStr(r_exception_message);
|
13
|
+
JS_SetPropertyStr(ctx, j_error, "message", JS_NewString(ctx, errorMessage));
|
14
|
+
|
15
|
+
return j_error;
|
16
|
+
}
|
19
17
|
|
18
|
+
JSValue to_js_value(JSContext *ctx, VALUE r_value)
|
19
|
+
{
|
20
20
|
switch (TYPE(r_value))
|
21
21
|
{
|
22
22
|
case T_NIL:
|
@@ -72,6 +72,13 @@ JSValue to_js_value(JSContext *ctx, VALUE r_value)
|
|
72
72
|
}
|
73
73
|
default:
|
74
74
|
{
|
75
|
+
if (TYPE(r_value) == T_OBJECT && RTEST(rb_funcall(
|
76
|
+
r_value,
|
77
|
+
rb_intern("is_a?"),
|
78
|
+
1, rb_const_get(rb_cClass, rb_intern("Exception")))))
|
79
|
+
{
|
80
|
+
return j_error_from_ruby_error(ctx, r_value);
|
81
|
+
}
|
75
82
|
VALUE r_inspect_str = rb_funcall(r_value, rb_intern("inspect"), 0, NULL);
|
76
83
|
char *str = StringValueCStr(r_inspect_str);
|
77
84
|
|
@@ -80,6 +87,11 @@ JSValue to_js_value(JSContext *ctx, VALUE r_value)
|
|
80
87
|
}
|
81
88
|
}
|
82
89
|
|
90
|
+
VALUE r_try_json_parse(VALUE r_str)
|
91
|
+
{
|
92
|
+
return rb_funcall(rb_const_get(rb_cClass, rb_intern("JSON")), rb_intern("parse"), 1, r_str);
|
93
|
+
}
|
94
|
+
|
83
95
|
VALUE to_rb_value(JSContext *ctx, JSValue j_val)
|
84
96
|
{
|
85
97
|
switch (JS_VALUE_GET_NORM_TAG(j_val))
|
@@ -121,6 +133,23 @@ VALUE to_rb_value(JSContext *ctx, JSValue j_val)
|
|
121
133
|
return Qnil;
|
122
134
|
}
|
123
135
|
|
136
|
+
if (JS_IsError(ctx, j_val))
|
137
|
+
{
|
138
|
+
JSValue j_errorOriginalRubyObjectId = JS_GetPropertyStr(ctx, j_val, "rb_object_id");
|
139
|
+
int errorOriginalRubyObjectId = 0;
|
140
|
+
if (JS_VALUE_GET_NORM_TAG(j_errorOriginalRubyObjectId) == JS_TAG_INT)
|
141
|
+
{
|
142
|
+
JS_ToInt32(ctx, &errorOriginalRubyObjectId, j_errorOriginalRubyObjectId);
|
143
|
+
JS_FreeValue(ctx, j_errorOriginalRubyObjectId);
|
144
|
+
if (errorOriginalRubyObjectId > 0)
|
145
|
+
{
|
146
|
+
// may be nice if cover the case of object is missing
|
147
|
+
return rb_funcall(rb_const_get(rb_cClass, rb_intern("ObjectSpace")), rb_intern("_id2ref"), 1, INT2NUM(errorOriginalRubyObjectId));
|
148
|
+
}
|
149
|
+
}
|
150
|
+
// will support other errors
|
151
|
+
}
|
152
|
+
|
124
153
|
JSValue j_global = JS_GetGlobalObject(ctx);
|
125
154
|
JSValue j_jsonClass = JS_GetPropertyStr(ctx, j_global, "JSON");
|
126
155
|
JSValue j_stringifyFunc = JS_GetPropertyStr(ctx, j_jsonClass, "stringify");
|
@@ -135,7 +164,21 @@ VALUE to_rb_value(JSContext *ctx, JSValue j_val)
|
|
135
164
|
JS_FreeValue(ctx, j_jsonClass);
|
136
165
|
JS_FreeValue(ctx, j_global);
|
137
166
|
|
138
|
-
|
167
|
+
if (rb_funcall(r_str, rb_intern("=="), 1, rb_str_new2("undefined")))
|
168
|
+
{
|
169
|
+
return QUICKJSRB_SYM(undefinedId);
|
170
|
+
}
|
171
|
+
|
172
|
+
int couldntParse;
|
173
|
+
VALUE r_result = rb_protect(r_try_json_parse, r_str, &couldntParse);
|
174
|
+
if (couldntParse)
|
175
|
+
{
|
176
|
+
return Qnil;
|
177
|
+
}
|
178
|
+
else
|
179
|
+
{
|
180
|
+
return r_result;
|
181
|
+
}
|
139
182
|
}
|
140
183
|
case JS_TAG_NULL:
|
141
184
|
return Qnil;
|
@@ -146,6 +189,21 @@ VALUE to_rb_value(JSContext *ctx, JSValue j_val)
|
|
146
189
|
JSValue j_exceptionVal = JS_GetException(ctx);
|
147
190
|
if (JS_IsError(ctx, j_exceptionVal))
|
148
191
|
{
|
192
|
+
JSValue j_errorOriginalRubyObjectId = JS_GetPropertyStr(ctx, j_exceptionVal, "rb_object_id");
|
193
|
+
int errorOriginalRubyObjectId = 0;
|
194
|
+
if (JS_VALUE_GET_NORM_TAG(j_errorOriginalRubyObjectId) == JS_TAG_INT)
|
195
|
+
{
|
196
|
+
JS_ToInt32(ctx, &errorOriginalRubyObjectId, j_errorOriginalRubyObjectId);
|
197
|
+
JS_FreeValue(ctx, j_errorOriginalRubyObjectId);
|
198
|
+
if (errorOriginalRubyObjectId > 0)
|
199
|
+
{
|
200
|
+
JS_FreeValue(ctx, j_exceptionVal);
|
201
|
+
// may be nice if cover the case of object is missing
|
202
|
+
rb_exc_raise(rb_funcall(rb_const_get(rb_cClass, rb_intern("ObjectSpace")), rb_intern("_id2ref"), 1, INT2NUM(errorOriginalRubyObjectId)));
|
203
|
+
return Qnil;
|
204
|
+
}
|
205
|
+
}
|
206
|
+
|
149
207
|
JSValue j_errorClassName = JS_GetPropertyStr(ctx, j_exceptionVal, "name");
|
150
208
|
const char *errorClassName = JS_ToCString(ctx, j_errorClassName);
|
151
209
|
|
@@ -211,6 +269,18 @@ VALUE to_rb_value(JSContext *ctx, JSValue j_val)
|
|
211
269
|
}
|
212
270
|
}
|
213
271
|
|
272
|
+
static VALUE r_try_call_proc(VALUE r_try_args)
|
273
|
+
{
|
274
|
+
return rb_funcall(
|
275
|
+
rb_const_get(rb_cClass, rb_intern("Quickjs")),
|
276
|
+
rb_intern("_with_timeout"),
|
277
|
+
3,
|
278
|
+
RARRAY_AREF(r_try_args, 2), // timeout
|
279
|
+
RARRAY_AREF(r_try_args, 0), // proc
|
280
|
+
RARRAY_AREF(r_try_args, 1) // args for proc
|
281
|
+
);
|
282
|
+
}
|
283
|
+
|
214
284
|
static JSValue js_quickjsrb_call_global(JSContext *ctx, JSValueConst _this, int _argc, JSValueConst *argv)
|
215
285
|
{
|
216
286
|
VMData *data = JS_GetContextOpaque(ctx);
|
@@ -223,17 +293,27 @@ static JSValue js_quickjsrb_call_global(JSContext *ctx, JSValueConst _this, int
|
|
223
293
|
{ // Shouldn't happen
|
224
294
|
return JS_ThrowReferenceError(ctx, "Proc `%s` is not defined", funcName);
|
225
295
|
}
|
226
|
-
JS_FreeCString(ctx, funcName);
|
227
296
|
|
228
|
-
VALUE
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
ULONG2NUM(data->eval_time->limit * 1000 / CLOCKS_PER_SEC),
|
233
|
-
r_proc,
|
234
|
-
to_rb_value(ctx, argv[1]));
|
297
|
+
VALUE r_call_args = rb_ary_new();
|
298
|
+
rb_ary_push(r_call_args, r_proc);
|
299
|
+
rb_ary_push(r_call_args, to_rb_value(ctx, argv[1]));
|
300
|
+
rb_ary_push(r_call_args, ULONG2NUM(data->eval_time->limit * 1000 / CLOCKS_PER_SEC));
|
235
301
|
|
236
|
-
|
302
|
+
int sadnessHappened;
|
303
|
+
VALUE r_result = rb_protect(r_try_call_proc, r_call_args, &sadnessHappened);
|
304
|
+
JSValue j_result;
|
305
|
+
if (sadnessHappened)
|
306
|
+
{
|
307
|
+
VALUE r_error = rb_errinfo();
|
308
|
+
JSValue j_error = j_error_from_ruby_error(ctx, r_error);
|
309
|
+
return JS_Throw(ctx, j_error);
|
310
|
+
}
|
311
|
+
else
|
312
|
+
{
|
313
|
+
j_result = to_js_value(ctx, r_result);
|
314
|
+
}
|
315
|
+
JS_FreeCString(ctx, funcName);
|
316
|
+
return j_result;
|
237
317
|
}
|
238
318
|
|
239
319
|
static JSValue js_quickjsrb_log(JSContext *ctx, JSValueConst _this, int _argc, JSValueConst *argv)
|
@@ -412,30 +492,34 @@ static VALUE vm_m_evalCode(VALUE r_self, VALUE r_code)
|
|
412
492
|
}
|
413
493
|
}
|
414
494
|
|
415
|
-
static VALUE vm_m_defineGlobalFunction(VALUE
|
495
|
+
static VALUE vm_m_defineGlobalFunction(int argc, VALUE *argv, VALUE r_self)
|
416
496
|
{
|
417
497
|
rb_need_block();
|
418
498
|
|
499
|
+
VALUE r_name;
|
500
|
+
VALUE r_flags;
|
501
|
+
VALUE r_block;
|
502
|
+
rb_scan_args(argc, argv, "10*&", &r_name, &r_flags, &r_block);
|
503
|
+
|
504
|
+
const char *asyncKeyword =
|
505
|
+
RTEST(rb_funcall(r_flags, rb_intern("include?"), 1, ID2SYM(rb_intern("async")))) ? "async " : "";
|
506
|
+
|
419
507
|
VMData *data;
|
420
508
|
TypedData_Get_Struct(r_self, VMData, &vm_type, data);
|
421
509
|
|
422
|
-
|
423
|
-
|
424
|
-
VALUE r_proc = rb_block_proc();
|
425
|
-
rb_hash_aset(data->defined_functions, r_name, r_proc);
|
426
|
-
char *funcName = StringValueCStr(r_name);
|
510
|
+
rb_hash_aset(data->defined_functions, r_name, r_block);
|
511
|
+
char *funcName = StringValueCStr(r_name);
|
427
512
|
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
513
|
+
const char *template = "globalThis['%s'] = %s(...args) => __quickjsrb.runRubyMethod('%s', args);\n";
|
514
|
+
int length = snprintf(NULL, 0, template, funcName, asyncKeyword, funcName);
|
515
|
+
char *result = (char *)malloc(length + 1);
|
516
|
+
snprintf(result, length + 1, template, funcName, asyncKeyword, funcName);
|
432
517
|
|
433
|
-
|
518
|
+
JSValue j_codeResult = JS_Eval(data->context, result, strlen(result), "<vm>", JS_EVAL_TYPE_MODULE);
|
434
519
|
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
}
|
520
|
+
free(result);
|
521
|
+
JS_FreeValue(data->context, j_codeResult);
|
522
|
+
return rb_funcall(r_name, rb_intern("to_sym"), 0, NULL);
|
439
523
|
|
440
524
|
return Qnil;
|
441
525
|
}
|
@@ -446,13 +530,14 @@ static VALUE vm_m_import(int argc, VALUE *argv, VALUE r_self)
|
|
446
530
|
rb_scan_args(argc, argv, "10:", &r_import_string, &r_opts);
|
447
531
|
if (NIL_P(r_opts))
|
448
532
|
r_opts = rb_hash_new();
|
449
|
-
VALUE r_from = rb_hash_aref(r_opts, ID2SYM(rb_intern("from")));
|
533
|
+
VALUE r_from = rb_hash_aref(r_opts, ID2SYM(rb_intern("from")));
|
450
534
|
if (NIL_P(r_from))
|
451
535
|
{
|
452
536
|
VALUE r_error_message = rb_str_new2("missing import source");
|
453
537
|
rb_exc_raise(rb_funcall(QUICKJSRB_ERROR_FOR(QUICKJSRB_ROOT_RUNTIME_ERROR), rb_intern("new"), 2, r_error_message, Qnil));
|
454
538
|
return Qnil;
|
455
539
|
}
|
540
|
+
VALUE r_custom_exposure = rb_hash_aref(r_opts, ID2SYM(rb_intern("code_to_expose")));
|
456
541
|
|
457
542
|
VMData *data;
|
458
543
|
TypedData_Get_Struct(r_self, VMData, &vm_type, data);
|
@@ -470,8 +555,16 @@ static VALUE vm_m_import(int argc, VALUE *argv, VALUE r_self)
|
|
470
555
|
r_import_string);
|
471
556
|
VALUE r_import_name = rb_ary_entry(r_import_settings, 0);
|
472
557
|
char *import_name = StringValueCStr(r_import_name);
|
473
|
-
VALUE
|
474
|
-
char *globalize
|
558
|
+
VALUE r_default_exposure = rb_ary_entry(r_import_settings, 1);
|
559
|
+
char *globalize;
|
560
|
+
if (RTEST(r_custom_exposure))
|
561
|
+
{
|
562
|
+
globalize = StringValueCStr(r_custom_exposure);
|
563
|
+
}
|
564
|
+
else
|
565
|
+
{
|
566
|
+
globalize = StringValueCStr(r_default_exposure);
|
567
|
+
}
|
475
568
|
|
476
569
|
const char *importAndGlobalizeModule = "import %s from '%s';\n"
|
477
570
|
"%s\n";
|
@@ -507,7 +600,7 @@ RUBY_FUNC_EXPORTED void Init_quickjsrb(void)
|
|
507
600
|
rb_define_alloc_func(r_class_vm, vm_alloc);
|
508
601
|
rb_define_method(r_class_vm, "initialize", vm_m_initialize, -1);
|
509
602
|
rb_define_method(r_class_vm, "eval_code", vm_m_evalCode, 1);
|
510
|
-
rb_define_method(r_class_vm, "define_function", vm_m_defineGlobalFunction, 1);
|
603
|
+
rb_define_method(r_class_vm, "define_function", vm_m_defineGlobalFunction, -1);
|
511
604
|
rb_define_method(r_class_vm, "import", vm_m_import, -1);
|
512
605
|
rb_define_method(r_class_vm, "logs", vm_m_logs, 0);
|
513
606
|
r_define_log_class(r_class_vm);
|
data/lib/quickjs/version.rb
CHANGED
data/lib/quickjs.rb
CHANGED
@@ -16,9 +16,9 @@ module Quickjs
|
|
16
16
|
def _with_timeout(msec, proc, args)
|
17
17
|
Timeout.timeout(msec / 1_000.0) { proc.call(*args) }
|
18
18
|
rescue Timeout::Error
|
19
|
-
Quickjs::InterruptedError.new('Ruby runtime got timeout', nil)
|
20
|
-
rescue
|
21
|
-
|
19
|
+
raise Quickjs::InterruptedError.new('Ruby runtime got timeout', nil)
|
20
|
+
rescue
|
21
|
+
raise
|
22
22
|
end
|
23
23
|
module_function :_with_timeout
|
24
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.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- hmsk
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-11-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: json
|