quickjs 0.2.3 → 0.4.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 +133 -26
- data/ext/quickjsrb/quickjsrb.h +0 -2
- data/lib/quickjs/version.rb +1 -1
- data/lib/quickjs.rb +1 -1
- 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: 49e231625e712ca98ffcab031b747d11392608eb840b2cafa6881173a5be9ac8
|
4
|
+
data.tar.gz: '099960b9c78f6f7a75990386186a0b149102d73ccbbbb7a1db7e52e120c57833'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3cad539bfe3b3a7e254ef4c1a2919c7a12afd29e67e5729acc2f8356896898eef71f1f46c35a62e351b1ac03ba0b8e9fe357c4f69781d5b8a203525068e22261
|
7
|
+
data.tar.gz: d4fcdfe872d91b0fd86bcccd9e58262b233ee99d31a529ba288583e2953ea191f4b9269dacbac9a47256f5d2111f737741fce4d5d26cba5e4fcc97bc450be96b
|
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
|
-
r_value,
|
7
|
-
rb_intern("is_a?"),
|
8
|
-
1, rb_const_get(rb_cClass, rb_intern("Exception")))))
|
9
|
-
{
|
10
|
-
JSValue j_error = JS_NewError(ctx);
|
11
|
-
VALUE r_str = rb_funcall(r_value, rb_intern("message"), 0, NULL);
|
12
|
-
char *exceptionMessage = StringValueCStr(r_str);
|
13
|
-
VALUE r_exception_name = rb_funcall(rb_funcall(r_value, rb_intern("class"), 0, NULL), rb_intern("name"), 0, NULL);
|
14
|
-
char *exceptionName = StringValueCStr(r_exception_name);
|
15
|
-
JS_SetPropertyStr(ctx, j_error, "name", JS_NewString(ctx, exceptionName));
|
16
|
-
JS_SetPropertyStr(ctx, j_error, "message", JS_NewString(ctx, exceptionMessage));
|
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
|
19
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
|
+
}
|
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,28 @@ JSValue to_js_value(JSContext *ctx, VALUE r_value)
|
|
80
87
|
}
|
81
88
|
}
|
82
89
|
|
90
|
+
VALUE find_ruby_error(JSContext *ctx, JSValue j_error)
|
91
|
+
{
|
92
|
+
JSValue j_errorOriginalRubyObjectId = JS_GetPropertyStr(ctx, j_error, "rb_object_id");
|
93
|
+
int errorOriginalRubyObjectId = 0;
|
94
|
+
if (JS_VALUE_GET_NORM_TAG(j_errorOriginalRubyObjectId) == JS_TAG_INT)
|
95
|
+
{
|
96
|
+
JS_ToInt32(ctx, &errorOriginalRubyObjectId, j_errorOriginalRubyObjectId);
|
97
|
+
JS_FreeValue(ctx, j_errorOriginalRubyObjectId);
|
98
|
+
if (errorOriginalRubyObjectId > 0)
|
99
|
+
{
|
100
|
+
// may be nice if cover the case of object is missing
|
101
|
+
return rb_funcall(rb_const_get(rb_cClass, rb_intern("ObjectSpace")), rb_intern("_id2ref"), 1, INT2NUM(errorOriginalRubyObjectId));
|
102
|
+
}
|
103
|
+
}
|
104
|
+
return Qnil;
|
105
|
+
}
|
106
|
+
|
107
|
+
VALUE r_try_json_parse(VALUE r_str)
|
108
|
+
{
|
109
|
+
return rb_funcall(rb_const_get(rb_cClass, rb_intern("JSON")), rb_intern("parse"), 1, r_str);
|
110
|
+
}
|
111
|
+
|
83
112
|
VALUE to_rb_value(JSContext *ctx, JSValue j_val)
|
84
113
|
{
|
85
114
|
switch (JS_VALUE_GET_NORM_TAG(j_val))
|
@@ -121,6 +150,16 @@ VALUE to_rb_value(JSContext *ctx, JSValue j_val)
|
|
121
150
|
return Qnil;
|
122
151
|
}
|
123
152
|
|
153
|
+
if (JS_IsError(ctx, j_val))
|
154
|
+
{
|
155
|
+
VALUE r_maybe_ruby_error = find_ruby_error(ctx, j_val);
|
156
|
+
if (!NIL_P(r_maybe_ruby_error))
|
157
|
+
{
|
158
|
+
return r_maybe_ruby_error;
|
159
|
+
}
|
160
|
+
// will support other errors like just returning an instance of Error
|
161
|
+
}
|
162
|
+
|
124
163
|
JSValue j_global = JS_GetGlobalObject(ctx);
|
125
164
|
JSValue j_jsonClass = JS_GetPropertyStr(ctx, j_global, "JSON");
|
126
165
|
JSValue j_stringifyFunc = JS_GetPropertyStr(ctx, j_jsonClass, "stringify");
|
@@ -135,7 +174,21 @@ VALUE to_rb_value(JSContext *ctx, JSValue j_val)
|
|
135
174
|
JS_FreeValue(ctx, j_jsonClass);
|
136
175
|
JS_FreeValue(ctx, j_global);
|
137
176
|
|
138
|
-
|
177
|
+
if (rb_funcall(r_str, rb_intern("=="), 1, rb_str_new2("undefined")))
|
178
|
+
{
|
179
|
+
return QUICKJSRB_SYM(undefinedId);
|
180
|
+
}
|
181
|
+
|
182
|
+
int couldntParse;
|
183
|
+
VALUE r_result = rb_protect(r_try_json_parse, r_str, &couldntParse);
|
184
|
+
if (couldntParse)
|
185
|
+
{
|
186
|
+
return Qnil;
|
187
|
+
}
|
188
|
+
else
|
189
|
+
{
|
190
|
+
return r_result;
|
191
|
+
}
|
139
192
|
}
|
140
193
|
case JS_TAG_NULL:
|
141
194
|
return Qnil;
|
@@ -146,14 +199,44 @@ VALUE to_rb_value(JSContext *ctx, JSValue j_val)
|
|
146
199
|
JSValue j_exceptionVal = JS_GetException(ctx);
|
147
200
|
if (JS_IsError(ctx, j_exceptionVal))
|
148
201
|
{
|
202
|
+
VALUE r_maybe_ruby_error = find_ruby_error(ctx, j_exceptionVal);
|
203
|
+
if (!NIL_P(r_maybe_ruby_error))
|
204
|
+
{
|
205
|
+
JS_FreeValue(ctx, j_exceptionVal);
|
206
|
+
rb_exc_raise(r_maybe_ruby_error);
|
207
|
+
return Qnil;
|
208
|
+
}
|
209
|
+
|
149
210
|
JSValue j_errorClassName = JS_GetPropertyStr(ctx, j_exceptionVal, "name");
|
150
211
|
const char *errorClassName = JS_ToCString(ctx, j_errorClassName);
|
151
212
|
|
152
213
|
JSValue j_errorClassMessage = JS_GetPropertyStr(ctx, j_exceptionVal, "message");
|
153
214
|
const char *errorClassMessage = JS_ToCString(ctx, j_errorClassMessage);
|
154
215
|
|
216
|
+
JSValue j_stackTrace = JS_GetPropertyStr(ctx, j_exceptionVal, "stack");
|
217
|
+
const char *stackTrace = JS_ToCString(ctx, j_stackTrace);
|
218
|
+
const char *headlineTemplate = "Uncaught %s: %s\n%s";
|
219
|
+
int length = snprintf(NULL, 0, headlineTemplate, errorClassName, errorClassMessage, stackTrace);
|
220
|
+
char *headline = (char *)malloc(length + 1);
|
221
|
+
snprintf(headline, length + 1, headlineTemplate, errorClassName, errorClassMessage, stackTrace);
|
222
|
+
|
223
|
+
VMData *data = JS_GetContextOpaque(ctx);
|
224
|
+
VALUE r_log_class = rb_const_get(rb_const_get(rb_const_get(rb_cClass, rb_intern("Quickjs")), rb_intern("VM")), rb_intern("Log"));
|
225
|
+
VALUE r_log = rb_funcall(r_log_class, rb_intern("new"), 0);
|
226
|
+
rb_iv_set(r_log, "@severity", ID2SYM(rb_intern("error")));
|
227
|
+
VALUE r_row = rb_ary_new();
|
228
|
+
VALUE r_loghash = rb_hash_new();
|
229
|
+
rb_hash_aset(r_loghash, ID2SYM(rb_intern("raw")), rb_str_new2(headline));
|
230
|
+
rb_hash_aset(r_loghash, ID2SYM(rb_intern("c")), rb_str_new2(headline));
|
231
|
+
rb_ary_push(r_row, r_loghash);
|
232
|
+
rb_iv_set(r_log, "@row", r_row);
|
233
|
+
rb_ary_push(data->logs, r_log);
|
234
|
+
|
155
235
|
JS_FreeValue(ctx, j_errorClassMessage);
|
156
236
|
JS_FreeValue(ctx, j_errorClassName);
|
237
|
+
JS_FreeValue(ctx, j_stackTrace);
|
238
|
+
JS_FreeCString(ctx, stackTrace);
|
239
|
+
free(headline);
|
157
240
|
|
158
241
|
VALUE r_error_class, r_error_message = rb_str_new2(errorClassMessage);
|
159
242
|
if (is_native_error_name(errorClassName))
|
@@ -165,11 +248,6 @@ VALUE to_rb_value(JSContext *ctx, JSValue j_val)
|
|
165
248
|
r_error_class = QUICKJSRB_ERROR_FOR(QUICKJSRB_INTERRUPTED_ERROR);
|
166
249
|
r_error_message = rb_str_new2("Code evaluation is interrupted by the timeout or something");
|
167
250
|
}
|
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
|
-
|
173
251
|
else if (strcmp(errorClassName, "Quickjs::InterruptedError") == 0)
|
174
252
|
{
|
175
253
|
r_error_class = QUICKJSRB_ERROR_FOR(QUICKJSRB_INTERRUPTED_ERROR);
|
@@ -187,8 +265,26 @@ VALUE to_rb_value(JSContext *ctx, JSValue j_val)
|
|
187
265
|
else // exception without Error object
|
188
266
|
{
|
189
267
|
const char *errorMessage = JS_ToCString(ctx, j_exceptionVal);
|
190
|
-
|
268
|
+
const char *headlineTemplate = "Uncaught '%s'";
|
269
|
+
int length = snprintf(NULL, 0, headlineTemplate, errorMessage);
|
270
|
+
char *headline = (char *)malloc(length + 1);
|
271
|
+
snprintf(headline, length + 1, headlineTemplate, errorMessage);
|
272
|
+
|
273
|
+
VMData *data = JS_GetContextOpaque(ctx);
|
274
|
+
VALUE r_log_class = rb_const_get(rb_const_get(rb_const_get(rb_cClass, rb_intern("Quickjs")), rb_intern("VM")), rb_intern("Log"));
|
275
|
+
VALUE r_log = rb_funcall(r_log_class, rb_intern("new"), 0);
|
276
|
+
rb_iv_set(r_log, "@severity", ID2SYM(rb_intern("error")));
|
277
|
+
VALUE r_row = rb_ary_new();
|
278
|
+
VALUE r_loghash = rb_hash_new();
|
279
|
+
rb_hash_aset(r_loghash, ID2SYM(rb_intern("raw")), rb_str_new2(headline));
|
280
|
+
rb_hash_aset(r_loghash, ID2SYM(rb_intern("c")), rb_str_new2(headline));
|
281
|
+
rb_ary_push(r_row, r_loghash);
|
282
|
+
rb_iv_set(r_log, "@row", r_row);
|
283
|
+
rb_ary_push(data->logs, r_log);
|
284
|
+
|
285
|
+
free(headline);
|
191
286
|
|
287
|
+
VALUE r_error_message = rb_sprintf("%s", errorMessage);
|
192
288
|
JS_FreeCString(ctx, errorMessage);
|
193
289
|
JS_FreeValue(ctx, j_exceptionVal);
|
194
290
|
rb_exc_raise(rb_funcall(QUICKJSRB_ERROR_FOR(QUICKJSRB_ROOT_RUNTIME_ERROR), rb_intern("new"), 2, r_error_message, Qnil));
|
@@ -251,7 +347,9 @@ static JSValue js_quickjsrb_call_global(JSContext *ctx, JSValueConst _this, int
|
|
251
347
|
JSValue j_result;
|
252
348
|
if (sadnessHappened)
|
253
349
|
{
|
254
|
-
|
350
|
+
VALUE r_error = rb_errinfo();
|
351
|
+
JSValue j_error = j_error_from_ruby_error(ctx, r_error);
|
352
|
+
return JS_Throw(ctx, j_error);
|
255
353
|
}
|
256
354
|
else
|
257
355
|
{
|
@@ -475,13 +573,14 @@ static VALUE vm_m_import(int argc, VALUE *argv, VALUE r_self)
|
|
475
573
|
rb_scan_args(argc, argv, "10:", &r_import_string, &r_opts);
|
476
574
|
if (NIL_P(r_opts))
|
477
575
|
r_opts = rb_hash_new();
|
478
|
-
VALUE r_from = rb_hash_aref(r_opts, ID2SYM(rb_intern("from")));
|
576
|
+
VALUE r_from = rb_hash_aref(r_opts, ID2SYM(rb_intern("from")));
|
479
577
|
if (NIL_P(r_from))
|
480
578
|
{
|
481
579
|
VALUE r_error_message = rb_str_new2("missing import source");
|
482
580
|
rb_exc_raise(rb_funcall(QUICKJSRB_ERROR_FOR(QUICKJSRB_ROOT_RUNTIME_ERROR), rb_intern("new"), 2, r_error_message, Qnil));
|
483
581
|
return Qnil;
|
484
582
|
}
|
583
|
+
VALUE r_custom_exposure = rb_hash_aref(r_opts, ID2SYM(rb_intern("code_to_expose")));
|
485
584
|
|
486
585
|
VMData *data;
|
487
586
|
TypedData_Get_Struct(r_self, VMData, &vm_type, data);
|
@@ -499,8 +598,16 @@ static VALUE vm_m_import(int argc, VALUE *argv, VALUE r_self)
|
|
499
598
|
r_import_string);
|
500
599
|
VALUE r_import_name = rb_ary_entry(r_import_settings, 0);
|
501
600
|
char *import_name = StringValueCStr(r_import_name);
|
502
|
-
VALUE
|
503
|
-
char *globalize
|
601
|
+
VALUE r_default_exposure = rb_ary_entry(r_import_settings, 1);
|
602
|
+
char *globalize;
|
603
|
+
if (RTEST(r_custom_exposure))
|
604
|
+
{
|
605
|
+
globalize = StringValueCStr(r_custom_exposure);
|
606
|
+
}
|
607
|
+
else
|
608
|
+
{
|
609
|
+
globalize = StringValueCStr(r_default_exposure);
|
610
|
+
}
|
504
611
|
|
505
612
|
const char *importAndGlobalizeModule = "import %s from '%s';\n"
|
506
613
|
"%s\n";
|
data/ext/quickjsrb/quickjsrb.h
CHANGED
@@ -183,7 +183,6 @@ static VALUE r_define_log_class(VALUE r_parent_class)
|
|
183
183
|
#define QUICKJSRB_ROOT_RUNTIME_ERROR "RuntimeError"
|
184
184
|
#define QUICKJSRB_INTERRUPTED_ERROR "InterruptedError"
|
185
185
|
#define QUICKJSRB_NO_AWAIT_ERROR "NoAwaitError"
|
186
|
-
#define QUICKJSRB_RUBY_FUNCTION_ERROR "RubyFunctionError"
|
187
186
|
|
188
187
|
#define QUICKJSRB_ERROR_FOR(name) \
|
189
188
|
(VALUE) { rb_const_get(rb_const_get(rb_cClass, rb_intern("Quickjs")), rb_intern(name)) }
|
@@ -212,7 +211,6 @@ static void r_define_exception_classes(VALUE r_parent_class)
|
|
212
211
|
// quickjsrb specific errors
|
213
212
|
rb_define_class_under(r_parent_class, QUICKJSRB_INTERRUPTED_ERROR, r_runtime_error);
|
214
213
|
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
214
|
}
|
217
215
|
|
218
216
|
#endif /* QUICKJSRB_H */
|
data/lib/quickjs/version.rb
CHANGED
data/lib/quickjs.rb
CHANGED
@@ -16,7 +16,7 @@ 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)
|
19
|
+
raise Quickjs::InterruptedError.new('Ruby runtime got timeout', nil)
|
20
20
|
rescue
|
21
21
|
raise
|
22
22
|
end
|
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.4.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-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: json
|