quickjs 0.2.0 → 0.2.2
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 +55 -24
- 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 +63 -203
- data/ext/quickjsrb/quickjsrb.h +201 -0
- data/lib/quickjs/version.rb +1 -1
- data/lib/quickjs.rb +23 -9
- 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: 0c2a481a2ea280bc0d4a9c7778b62035991bd08293ddef98b4824a40a6a6ccd9
|
4
|
+
data.tar.gz: a40b2f11813f2f82db4c5b9e0931199013671e0983e80566f0b6645709deece7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f509a918c4e5ff7d19bdaa8873ee62ede64cfd98e405a7ea6f4eb00a724fc79fc2cd928e2388d0f8e07dcd455834ba1f60ec2a9990b4781bd0012ec5f72a9c16
|
7
|
+
data.tar.gz: b7604b888bc62fe12f6a5b30387891108a24cf1de55e77934cabeeab20fe9ae27f494098448a32a975e9fde99cee9a9af5bdd58c258a0bafb60adc125cedf206
|
data/README.md
CHANGED
@@ -36,7 +36,10 @@ Quickjs.eval_code('const obj = {}; obj.missingKey;') # => :undefined (Quickjs::V
|
|
36
36
|
Quickjs.eval_code("Number('whatever')") #=> :NaN (Quickjs::Value::NAN)
|
37
37
|
```
|
38
38
|
|
39
|
-
|
39
|
+
<details>
|
40
|
+
<summary>Options</summary>
|
41
|
+
|
42
|
+
#### Resources
|
40
43
|
|
41
44
|
```rb
|
42
45
|
# 1GB memory limit
|
@@ -46,20 +49,21 @@ Quickjs.eval_code(code, { memory_limit: 1024 ** 3 })
|
|
46
49
|
Quickjs.eval_code(code, { max_stack_size: 1024 ** 2 })
|
47
50
|
```
|
48
51
|
|
49
|
-
####
|
52
|
+
#### Built-in modules
|
53
|
+
|
54
|
+
To enable [std module](https://bellard.org/quickjs/quickjs.html#std-module) and [os module](https://bellard.org/quickjs/quickjs.html#os-module) selectively.
|
50
55
|
|
51
56
|
```rb
|
52
57
|
# enable std module
|
53
|
-
# https://bellard.org/quickjs/quickjs.html#std-module
|
54
58
|
Quickjs.eval_code(code, { features: [Quickjs::MODULE_STD] })
|
55
59
|
|
56
60
|
# enable os module
|
57
|
-
# https://bellard.org/quickjs/quickjs.html#os-module
|
58
61
|
Quickjs.eval_code(code, { features: [Quickjs::MODULE_OS] })
|
59
62
|
|
60
|
-
# enable timeout features `setTimeout`, `clearTimeout`
|
63
|
+
# enable timeout features `setTimeout`, `clearTimeout` from os module specifically
|
61
64
|
Quickjs.eval_code(code, { features: [Quickjs::FEATURES_TIMEOUT] })
|
62
65
|
```
|
66
|
+
</details>
|
63
67
|
|
64
68
|
### `Quickjs::VM`: Maintain a consistent VM/runtime
|
65
69
|
|
@@ -71,7 +75,10 @@ vm.eval_code('a.b = "d";')
|
|
71
75
|
vm.eval_code('a.b;') #=> "d"
|
72
76
|
```
|
73
77
|
|
74
|
-
|
78
|
+
<details>
|
79
|
+
<summary>Config VM/runtime</summary>
|
80
|
+
|
81
|
+
#### Resources
|
75
82
|
|
76
83
|
```rb
|
77
84
|
vm = Quickjs::VM.new(
|
@@ -80,41 +87,51 @@ vm = Quickjs::VM.new(
|
|
80
87
|
)
|
81
88
|
```
|
82
89
|
|
90
|
+
#### Built-in modules
|
91
|
+
|
92
|
+
To enable [std module](https://bellard.org/quickjs/quickjs.html#std-module) and [os module](https://bellard.org/quickjs/quickjs.html#os-module) selectively.
|
93
|
+
|
83
94
|
```rb
|
84
95
|
# enable std module
|
85
|
-
|
86
|
-
vm = Quickjs::VM.new(
|
87
|
-
features: [::Quickjs::MODULE_STD],
|
88
|
-
)
|
96
|
+
vm = Quickjs::VM.new(features: [::Quickjs::MODULE_STD])
|
89
97
|
|
90
98
|
# enable os module
|
91
|
-
|
92
|
-
vm = Quickjs::VM.new(
|
93
|
-
features: [::Quickjs::MODULE_OS],
|
94
|
-
)
|
95
|
-
|
96
|
-
# `eval_code` will be interrupted after 1 sec (default: 100 msec)
|
97
|
-
vm = Quickjs::VM.new(
|
98
|
-
timeout_msec: 1_000,
|
99
|
-
)
|
99
|
+
vm = Quickjs::VM.new(features: [::Quickjs::MODULE_OS])
|
100
100
|
|
101
101
|
# enable timeout features `setTimeout`, `clearTimeout`
|
102
|
-
vm = Quickjs::VM.new(
|
103
|
-
features: [::Quickjs::FEATURES_TIMEOUT],
|
104
|
-
)
|
102
|
+
vm = Quickjs::VM.new(features: [::Quickjs::FEATURES_TIMEOUT])
|
105
103
|
```
|
106
104
|
|
107
|
-
####
|
105
|
+
#### VM timeout
|
106
|
+
|
107
|
+
```rb
|
108
|
+
# `eval_code` will be interrupted after 1 sec (default: 100 msec)
|
109
|
+
vm = Quickjs::VM.new(timeout_msec: 1_000)
|
110
|
+
```
|
111
|
+
</details>
|
112
|
+
|
113
|
+
#### `Quickjs::VM#import`: 🔌 Import ESM from a source code
|
108
114
|
|
109
115
|
```rb
|
110
116
|
vm = Quickjs::VM.new
|
117
|
+
|
118
|
+
# Equivalent to `import { default: aliasedDefault, member: member } from './exports.esm.js';`
|
111
119
|
vm.import({ default: 'aliasedDefault', member: 'member' }, from: File.read('exports.esm.js'))
|
112
120
|
|
113
121
|
vm.eval_code("aliasedDefault()") #=> Exported `default` of the ESM is called
|
114
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'))
|
115
132
|
```
|
116
133
|
|
117
|
-
####
|
134
|
+
#### `Quickjs::VM#define_function`: 💎 Define a global function for JS by Ruby
|
118
135
|
|
119
136
|
```rb
|
120
137
|
vm = Quickjs::VM.new
|
@@ -125,6 +142,20 @@ end
|
|
125
142
|
vm.eval_code("greetingTo('Rick')") #=> 'Hello! Rick'
|
126
143
|
```
|
127
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
|
+
|
128
159
|
## License
|
129
160
|
|
130
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,22 @@ 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)
|
159
|
+
if (is_native_error_name(errorClassName))
|
235
160
|
{
|
236
|
-
r_error_class =
|
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)
|
255
|
-
{
|
256
|
-
r_error_class = rb_cQuickjsURIError;
|
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
|
}
|
267
168
|
else if (strcmp(errorClassName, "Quickjs::InterruptedError") == 0)
|
268
169
|
{
|
269
|
-
r_error_class =
|
170
|
+
r_error_class = QUICKJSRB_ERROR_FOR(QUICKJSRB_INTERRUPTED_ERROR);
|
270
171
|
}
|
271
172
|
else
|
272
173
|
{
|
273
|
-
r_error_class =
|
174
|
+
r_error_class = QUICKJSRB_ERROR_FOR(QUICKJSRB_ROOT_RUNTIME_ERROR);
|
274
175
|
}
|
275
176
|
JS_FreeCString(ctx, errorClassName);
|
276
177
|
JS_FreeCString(ctx, errorClassMessage);
|
@@ -285,7 +186,7 @@ VALUE to_rb_value(JSContext *ctx, JSValue j_val)
|
|
285
186
|
|
286
187
|
JS_FreeCString(ctx, errorMessage);
|
287
188
|
JS_FreeValue(ctx, j_exceptionVal);
|
288
|
-
rb_exc_raise(rb_funcall(
|
189
|
+
rb_exc_raise(rb_funcall(QUICKJSRB_ERROR_FOR(QUICKJSRB_ROOT_RUNTIME_ERROR), rb_intern("new"), 2, r_error_message, Qnil));
|
289
190
|
}
|
290
191
|
return Qnil;
|
291
192
|
}
|
@@ -342,8 +243,10 @@ static JSValue js_quickjsrb_log(JSContext *ctx, JSValueConst _this, int _argc, J
|
|
342
243
|
const char *severity = JS_ToCString(ctx, j_severity);
|
343
244
|
JS_FreeValue(ctx, j_severity);
|
344
245
|
|
345
|
-
VALUE
|
246
|
+
VALUE r_log_class = rb_const_get(rb_const_get(rb_const_get(rb_cClass, rb_intern("Quickjs")), rb_intern("VM")), rb_intern("Log"));
|
247
|
+
VALUE r_log = rb_funcall(r_log_class, rb_intern("new"), 0);
|
346
248
|
rb_iv_set(r_log, "@severity", ID2SYM(rb_intern(severity)));
|
249
|
+
JS_FreeCString(ctx, severity);
|
347
250
|
|
348
251
|
VALUE r_row = rb_ary_new();
|
349
252
|
int i;
|
@@ -351,22 +254,28 @@ static JSValue js_quickjsrb_log(JSContext *ctx, JSValueConst _this, int _argc, J
|
|
351
254
|
int count;
|
352
255
|
JS_ToInt32(ctx, &count, j_length);
|
353
256
|
JS_FreeValue(ctx, j_length);
|
257
|
+
|
354
258
|
for (i = 0; i < count; i++)
|
355
259
|
{
|
260
|
+
VALUE r_loghash = rb_hash_new();
|
356
261
|
JSValue j_logged = JS_GetPropertyUint32(ctx, argv[1], i);
|
262
|
+
if (JS_VALUE_GET_NORM_TAG(j_logged) == JS_TAG_OBJECT && JS_PromiseState(ctx, j_logged) != -1)
|
263
|
+
{
|
264
|
+
rb_hash_aset(r_loghash, ID2SYM(rb_intern("raw")), rb_str_new2("Promise"));
|
265
|
+
}
|
266
|
+
else
|
267
|
+
{
|
268
|
+
rb_hash_aset(r_loghash, ID2SYM(rb_intern("raw")), to_rb_value(ctx, j_logged));
|
269
|
+
}
|
357
270
|
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
271
|
JS_FreeValue(ctx, j_logged);
|
272
|
+
rb_hash_aset(r_loghash, ID2SYM(rb_intern("c")), rb_str_new2(body));
|
363
273
|
JS_FreeCString(ctx, body);
|
274
|
+
rb_ary_push(r_row, r_loghash);
|
364
275
|
}
|
365
276
|
|
366
277
|
rb_iv_set(r_log, "@row", r_row);
|
367
278
|
rb_ary_push(data->logs, r_log);
|
368
|
-
JS_FreeCString(ctx, severity);
|
369
|
-
|
370
279
|
return JS_UNDEFINED;
|
371
280
|
}
|
372
281
|
|
@@ -408,7 +317,7 @@ static VALUE vm_m_initialize(int argc, VALUE *argv, VALUE r_self)
|
|
408
317
|
JS_SetModuleLoaderFunc(runtime, NULL, js_module_loader, NULL);
|
409
318
|
js_std_init_handlers(runtime);
|
410
319
|
|
411
|
-
if (RTEST(rb_funcall(r_features, rb_intern("include?"), 1,
|
320
|
+
if (RTEST(rb_funcall(r_features, rb_intern("include?"), 1, QUICKJSRB_SYM(featureStdId))))
|
412
321
|
{
|
413
322
|
js_init_module_std(data->context, "std");
|
414
323
|
const char *enableStd = "import * as std from 'std';\n"
|
@@ -417,7 +326,7 @@ static VALUE vm_m_initialize(int argc, VALUE *argv, VALUE r_self)
|
|
417
326
|
JS_FreeValue(data->context, j_stdEval);
|
418
327
|
}
|
419
328
|
|
420
|
-
if (RTEST(rb_funcall(r_features, rb_intern("include?"), 1,
|
329
|
+
if (RTEST(rb_funcall(r_features, rb_intern("include?"), 1, QUICKJSRB_SYM(featureOsId))))
|
421
330
|
{
|
422
331
|
js_init_module_os(data->context, "os");
|
423
332
|
const char *enableOs = "import * as os from 'os';\n"
|
@@ -425,13 +334,19 @@ static VALUE vm_m_initialize(int argc, VALUE *argv, VALUE r_self)
|
|
425
334
|
JSValue j_osEval = JS_Eval(data->context, enableOs, strlen(enableOs), "<vm>", JS_EVAL_TYPE_MODULE);
|
426
335
|
JS_FreeValue(data->context, j_osEval);
|
427
336
|
}
|
428
|
-
else if (RTEST(rb_funcall(r_features, rb_intern("include?"), 1,
|
337
|
+
else if (RTEST(rb_funcall(r_features, rb_intern("include?"), 1, QUICKJSRB_SYM(featureOsTimeoutId))))
|
429
338
|
{
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
339
|
+
char *filename = random_string();
|
340
|
+
js_init_module_os(data->context, filename); // Better if this is limited just only for setTimeout and clearTimeout
|
341
|
+
const char *enableTimeoutTemplate = "import * as _os from '%s';\n"
|
342
|
+
"globalThis.setTimeout = _os.setTimeout;\n"
|
343
|
+
"globalThis.clearTimeout = _os.clearTimeout;\n";
|
344
|
+
int length = snprintf(NULL, 0, enableTimeoutTemplate, filename);
|
345
|
+
char *enableTimeout = (char *)malloc(length + 1);
|
346
|
+
snprintf(enableTimeout, length + 1, enableTimeoutTemplate, filename);
|
347
|
+
|
434
348
|
JSValue j_timeoutEval = JS_Eval(data->context, enableTimeout, strlen(enableTimeout), "<vm>", JS_EVAL_TYPE_MODULE);
|
349
|
+
free(enableTimeout);
|
435
350
|
JS_FreeValue(data->context, j_timeoutEval);
|
436
351
|
}
|
437
352
|
|
@@ -477,7 +392,7 @@ static VALUE vm_m_evalCode(VALUE r_self, VALUE r_code)
|
|
477
392
|
|
478
393
|
char *code = StringValueCStr(r_code);
|
479
394
|
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);
|
395
|
+
JSValue j_awaitedResult = js_std_await(data->context, j_codeResult); // This frees j_codeResult
|
481
396
|
JSValue j_returnedValue = JS_GetPropertyStr(data->context, j_awaitedResult, "value");
|
482
397
|
// Do this by rescuing to_rb_value
|
483
398
|
if (JS_VALUE_GET_NORM_TAG(j_returnedValue) == JS_TAG_OBJECT && JS_PromiseState(data->context, j_returnedValue) != -1)
|
@@ -485,7 +400,7 @@ static VALUE vm_m_evalCode(VALUE r_self, VALUE r_code)
|
|
485
400
|
JS_FreeValue(data->context, j_returnedValue);
|
486
401
|
JS_FreeValue(data->context, j_awaitedResult);
|
487
402
|
VALUE r_error_message = rb_str_new2("An unawaited Promise was returned to the top-level");
|
488
|
-
rb_exc_raise(rb_funcall(
|
403
|
+
rb_exc_raise(rb_funcall(QUICKJSRB_ERROR_FOR(QUICKJSRB_NO_AWAIT_ERROR), rb_intern("new"), 2, r_error_message, Qnil));
|
489
404
|
return Qnil;
|
490
405
|
}
|
491
406
|
else
|
@@ -531,19 +446,20 @@ static VALUE vm_m_import(int argc, VALUE *argv, VALUE r_self)
|
|
531
446
|
rb_scan_args(argc, argv, "10:", &r_import_string, &r_opts);
|
532
447
|
if (NIL_P(r_opts))
|
533
448
|
r_opts = rb_hash_new();
|
534
|
-
VALUE r_from = rb_hash_aref(r_opts, ID2SYM(rb_intern("from")));
|
449
|
+
VALUE r_from = rb_hash_aref(r_opts, ID2SYM(rb_intern("from"))); // TODO: Use kwargs instead
|
535
450
|
if (NIL_P(r_from))
|
536
451
|
{
|
537
452
|
VALUE r_error_message = rb_str_new2("missing import source");
|
538
|
-
rb_exc_raise(rb_funcall(
|
453
|
+
rb_exc_raise(rb_funcall(QUICKJSRB_ERROR_FOR(QUICKJSRB_ROOT_RUNTIME_ERROR), rb_intern("new"), 2, r_error_message, Qnil));
|
539
454
|
return Qnil;
|
540
455
|
}
|
541
456
|
|
542
457
|
VMData *data;
|
543
458
|
TypedData_Get_Struct(r_self, VMData, &vm_type, data);
|
544
459
|
|
460
|
+
char *filename = random_string();
|
545
461
|
char *source = StringValueCStr(r_from);
|
546
|
-
JSValue func = JS_Eval(data->context, source, strlen(source),
|
462
|
+
JSValue func = JS_Eval(data->context, source, strlen(source), filename, JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY);
|
547
463
|
js_module_set_import_meta(data->context, func, TRUE, FALSE);
|
548
464
|
JS_FreeValue(data->context, func);
|
549
465
|
|
@@ -557,11 +473,11 @@ static VALUE vm_m_import(int argc, VALUE *argv, VALUE r_self)
|
|
557
473
|
VALUE r_globalize = rb_ary_entry(r_import_settings, 1);
|
558
474
|
char *globalize = StringValueCStr(r_globalize);
|
559
475
|
|
560
|
-
const char *importAndGlobalizeModule = "import %s from '
|
476
|
+
const char *importAndGlobalizeModule = "import %s from '%s';\n"
|
561
477
|
"%s\n";
|
562
|
-
int length = snprintf(NULL, 0, importAndGlobalizeModule, import_name, globalize);
|
478
|
+
int length = snprintf(NULL, 0, importAndGlobalizeModule, import_name, filename, globalize);
|
563
479
|
char *result = (char *)malloc(length + 1);
|
564
|
-
snprintf(result, length + 1, importAndGlobalizeModule, import_name, globalize);
|
480
|
+
snprintf(result, length + 1, importAndGlobalizeModule, import_name, filename, globalize);
|
565
481
|
|
566
482
|
JSValue j_codeResult = JS_Eval(data->context, result, strlen(result), "<vm>", JS_EVAL_TYPE_MODULE);
|
567
483
|
free(result);
|
@@ -570,7 +486,7 @@ static VALUE vm_m_import(int argc, VALUE *argv, VALUE r_self)
|
|
570
486
|
return Qtrue;
|
571
487
|
}
|
572
488
|
|
573
|
-
static VALUE
|
489
|
+
static VALUE vm_m_logs(VALUE r_self)
|
574
490
|
{
|
575
491
|
VMData *data;
|
576
492
|
TypedData_Get_Struct(r_self, VMData, &vm_type, data);
|
@@ -578,77 +494,21 @@ static VALUE vm_m_getLogs(VALUE r_self)
|
|
578
494
|
return data->logs;
|
579
495
|
}
|
580
496
|
|
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
497
|
RUBY_FUNC_EXPORTED void Init_quickjsrb(void)
|
616
498
|
{
|
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);
|
499
|
+
rb_require("json");
|
500
|
+
rb_require("securerandom");
|
501
|
+
|
502
|
+
VALUE r_module_quickjs = rb_define_module("Quickjs");
|
503
|
+
r_define_constants(r_module_quickjs);
|
504
|
+
r_define_exception_classes(r_module_quickjs);
|
505
|
+
|
506
|
+
VALUE r_class_vm = rb_define_class_under(r_module_quickjs, "VM", rb_cObject);
|
507
|
+
rb_define_alloc_func(r_class_vm, vm_alloc);
|
508
|
+
rb_define_method(r_class_vm, "initialize", vm_m_initialize, -1);
|
509
|
+
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);
|
511
|
+
rb_define_method(r_class_vm, "import", vm_m_import, -1);
|
512
|
+
rb_define_method(r_class_vm, "logs", vm_m_logs, 0);
|
513
|
+
r_define_log_class(r_class_vm);
|
654
514
|
}
|
data/ext/quickjsrb/quickjsrb.h
CHANGED
@@ -12,4 +12,205 @@
|
|
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
|
+
|
187
|
+
#define QUICKJSRB_ERROR_FOR(name) \
|
188
|
+
(VALUE) { rb_const_get(rb_const_get(rb_cClass, rb_intern("Quickjs")), rb_intern(name)) }
|
189
|
+
|
190
|
+
VALUE vm_m_initialize_quickjs_error(VALUE self, VALUE r_message, VALUE r_js_name)
|
191
|
+
{
|
192
|
+
rb_call_super(1, &r_message);
|
193
|
+
rb_iv_set(self, "@js_name", r_js_name);
|
194
|
+
|
195
|
+
return self;
|
196
|
+
}
|
197
|
+
|
198
|
+
static void r_define_exception_classes(VALUE r_parent_class)
|
199
|
+
{
|
200
|
+
VALUE r_runtime_error = rb_define_class_under(r_parent_class, QUICKJSRB_ROOT_RUNTIME_ERROR, rb_eRuntimeError);
|
201
|
+
rb_define_method(r_runtime_error, "initialize", vm_m_initialize_quickjs_error, 2);
|
202
|
+
rb_define_attr(r_runtime_error, "js_name", 1, 0);
|
203
|
+
|
204
|
+
// JS native errors
|
205
|
+
int numStrings = sizeof(native_errors) / sizeof(native_errors[0]);
|
206
|
+
for (int i = 0; i < numStrings; i++)
|
207
|
+
{
|
208
|
+
rb_define_class_under(r_parent_class, native_errors[i], r_runtime_error);
|
209
|
+
}
|
210
|
+
|
211
|
+
// quickjsrb specific errors
|
212
|
+
rb_define_class_under(r_parent_class, QUICKJSRB_INTERRUPTED_ERROR, r_runtime_error);
|
213
|
+
rb_define_class_under(r_parent_class, QUICKJSRB_NO_AWAIT_ERROR, r_runtime_error);
|
214
|
+
}
|
215
|
+
|
15
216
|
#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
|
|
@@ -23,15 +22,30 @@ module Quickjs
|
|
23
22
|
end
|
24
23
|
module_function :_with_timeout
|
25
24
|
|
26
|
-
def _build_import(
|
27
|
-
|
28
|
-
|
29
|
-
|
25
|
+
def _build_import(imported)
|
26
|
+
code_define_global = ->(name) { "globalThis['#{name}'] = #{name};" }
|
27
|
+
case imported
|
28
|
+
in String if matched = imported.match(/\* as (.+)/)
|
29
|
+
[imported, code_define_global.call(matched[1])]
|
30
|
+
in String
|
31
|
+
[imported, code_define_global.call(imported)]
|
32
|
+
in [*all] if all.all? {|e| e.is_a? String }
|
33
|
+
[
|
34
|
+
imported.join(', ').yield_self{|s| '{ %s }' % s },
|
35
|
+
imported.map(&code_define_global).join("\n")
|
36
|
+
]
|
37
|
+
in { ** }
|
38
|
+
imports, aliases = imported.to_a.map do |imp|
|
39
|
+
["#{imp[0]} as #{imp[1]}", imp[1].to_s]
|
40
|
+
end.transpose
|
30
41
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
42
|
+
[
|
43
|
+
imports.join(', ').yield_self{|s| '{ %s }' % s },
|
44
|
+
aliases.map(&code_define_global).join("\n")
|
45
|
+
]
|
46
|
+
else
|
47
|
+
raise 'Unsupported importing style'
|
48
|
+
end
|
35
49
|
end
|
36
50
|
module_function :_build_import
|
37
51
|
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.2.
|
4
|
+
version: 0.2.2
|
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-29 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
|