quickjs 0.1.5 → 0.1.7

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 16b9d276d5d05c5f7cf5ff981573283fa990064d55e60b02dc86f773c892c9a0
4
- data.tar.gz: bf3e2ebee03197fdead070a974d40485c77bab90a7ab5153274a3cfb48a7ea4b
3
+ metadata.gz: 9a639b7afafb5c155725cba8d7927b7f4e146e21369a65a3902e8fe23ef1e3dd
4
+ data.tar.gz: b0e098ae6c193e761f456642cdcaf5396251785d5bc56b5e807fd540a0615f87
5
5
  SHA512:
6
- metadata.gz: 4f9431993a243c908c905c25a13c8679f17d3404699a87868c6a195f2eeb0b0e2f1c76716bf4564e076a189f20302ef1d6ade01a763e7827fdc5a4229f23be2c
7
- data.tar.gz: 85505319f063a8f1e5c8c42dc4de7d483f9a3e3deb4599203d2d55d2c79d206d26385f8a139a67a87f753cab67fa74f2a74b0ed6f2a864fd5bd37c2588762881
6
+ metadata.gz: 9ad93ee1c056d68409daeba63515b8afa8555150044e0543a97bb2f3cb64abf5b8f5a5b1fce75e952721b0277a7807ce521289b70b63157cc489032da7da8f7c
7
+ data.tar.gz: b36a5f2e7402156e94403c5110ec1acc6141d657b236562b18b57c63c68fd966d4ef25096e3b515f9633093bee2e2a89f65578b4426e0c4184197078c9c2c578
data/README.md CHANGED
@@ -40,10 +40,10 @@ Quickjs.eval_code("Number('whatever')") #=> :NaN (Quickjs::Value::NAN)
40
40
 
41
41
  ```rb
42
42
  # 1GB memory limit
43
- Quickjs.eval_code(code, { memoryLimit: 1024 ** 3 })
43
+ Quickjs.eval_code(code, { memory_limit: 1024 ** 3 })
44
44
 
45
45
  # 1MB max stack size
46
- Quickjs.eval_code(code, { memoryLimit: 1024 ** 2 })
46
+ Quickjs.eval_code(code, { max_stack_size: 1024 ** 2 })
47
47
  ```
48
48
 
49
49
  #### Enable built-in modules
@@ -58,7 +58,7 @@ Quickjs.eval_code(code, { features: [Quickjs::MODULE_STD] })
58
58
  Quickjs.eval_code(code, { features: [Quickjs::MODULE_OS] })
59
59
  ```
60
60
 
61
- ### Maintain a consistent VM/runtime
61
+ ### `Quickjs::VM`: Maintain a consistent VM/runtime
62
62
 
63
63
  ```rb
64
64
  vm = Quickjs::VM.new
@@ -72,15 +72,20 @@ vm.eval_code('a.b;') #=> "d"
72
72
 
73
73
  ```rb
74
74
  vm = Quickjs::VM.new(
75
- memory_limit: 1024 * 1024,
76
- max_stack_size: 1024 * 1024,
75
+ memory_limit: 1024 ** 3,
76
+ max_stack_size: 1024 ** 2,
77
77
  )
78
78
  ```
79
79
 
80
80
  ```rb
81
+ # enable std module
82
+ # https://bellard.org/quickjs/quickjs.html#std-module
81
83
  vm = Quickjs::VM.new(
82
84
  features: [::Quickjs::MODULE_STD],
83
85
  )
86
+
87
+ # enable os module
88
+ # https://bellard.org/quickjs/quickjs.html#os-module
84
89
  vm = Quickjs::VM.new(
85
90
  features: [::Quickjs::MODULE_OS],
86
91
  )
@@ -92,6 +97,17 @@ vm = Quickjs::VM.new(
92
97
  vm.dispose!
93
98
  ```
94
99
 
100
+ #### Define a global function for JS
101
+
102
+ ```rb
103
+ vm = Quickjs::VM.new
104
+ vm.define_function("greetingTo") do |arg1|
105
+ ['Hello!', arg1].join(' ')
106
+ end
107
+
108
+ vm.eval_code("greetingTo('Rick')") #=> 'Hello! Rick'
109
+ ```
110
+
95
111
  ## License
96
112
 
97
113
  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).
@@ -11,6 +11,7 @@ $srcs = [
11
11
  'cutils.c',
12
12
  'quickjs.c',
13
13
  'quickjs-libc.c',
14
+ 'procs.c',
14
15
  'quickjsrb.c',
15
16
  ]
16
17
 
@@ -0,0 +1,80 @@
1
+ #include "procs.h"
2
+
3
+ unsigned int hash(const char *key) {
4
+ unsigned long int value = 0;
5
+ unsigned int i = 0;
6
+ unsigned int key_len = strlen(key);
7
+
8
+ for (; i < key_len; ++i) {
9
+ value = value * 37 + key[i];
10
+ }
11
+ return value % MAX_NUM_OF_PROCS;
12
+ }
13
+
14
+ ProcEntry *create_proc_entry(const char *key, VALUE proc) {
15
+ ProcEntry *entry = malloc(sizeof(ProcEntry));
16
+ entry->key = strdup(key);
17
+ entry->proc = proc;
18
+ entry->next = NULL;
19
+ return entry;
20
+ }
21
+
22
+ ProcEntryMap *create_proc_entries() {
23
+ ProcEntryMap *entryMap = malloc(sizeof(ProcEntryMap));
24
+ entryMap->entries = malloc(sizeof(ProcEntry *) * MAX_NUM_OF_PROCS);
25
+ for (int i = 0; i < MAX_NUM_OF_PROCS; ++i) {
26
+ entryMap->entries[i] = NULL;
27
+ }
28
+ return entryMap;
29
+ }
30
+
31
+ void set_proc(ProcEntryMap *entryMap, const char *key, VALUE proc) {
32
+ unsigned int slot = hash(key);
33
+ ProcEntry *entry = entryMap->entries[slot];
34
+
35
+ if (entry == NULL) {
36
+ entryMap->entries[slot] = create_proc_entry(key, proc);
37
+ return;
38
+ }
39
+
40
+ ProcEntry *prev;
41
+ while (entry != NULL) {
42
+ if (strcmp(entry->key, key) == 0) {
43
+ entry->proc = proc;
44
+ return;
45
+ }
46
+ prev = entry;
47
+ entry = prev->next;
48
+ }
49
+
50
+ prev->next = create_proc_entry(key, proc);
51
+ }
52
+
53
+ VALUE get_proc(ProcEntryMap *entryMap, const char *key) {
54
+ unsigned int slot = hash(key);
55
+
56
+ ProcEntry *entry = entryMap->entries[slot];
57
+
58
+ while (entry != NULL) {
59
+ if (strcmp(entry->key, key) == 0) {
60
+ return entry->proc;
61
+ }
62
+ entry = entry->next;
63
+ }
64
+
65
+ return Qnil;
66
+ }
67
+
68
+ void free_proc_entry_map(ProcEntryMap *entryMap) {
69
+ for (int i = 0; i < MAX_NUM_OF_PROCS; ++i) {
70
+ ProcEntry *entry = entryMap->entries[i];
71
+ while (entry != NULL) {
72
+ ProcEntry *temp = entry;
73
+ entry = entry->next;
74
+ free(temp->key);
75
+ free(temp);
76
+ }
77
+ }
78
+ free(entryMap->entries);
79
+ free(entryMap);
80
+ }
@@ -0,0 +1,18 @@
1
+ #include "ruby.h"
2
+
3
+ #define MAX_NUM_OF_PROCS 100
4
+
5
+ typedef struct ProcEntry {
6
+ char *key;
7
+ VALUE proc;
8
+ struct ProcEntry *next;
9
+ } ProcEntry;
10
+
11
+ typedef struct ProcEntryMap {
12
+ ProcEntry **entries;
13
+ } ProcEntryMap;
14
+
15
+ ProcEntryMap *create_proc_entries();
16
+ void set_proc(ProcEntryMap *entryMap, const char *key, VALUE proc);
17
+ VALUE get_proc(ProcEntryMap *entryMap, const char *key);
18
+ void free_proc_entry_map(ProcEntryMap *entryMap);
@@ -1,5 +1,39 @@
1
1
  #include "quickjsrb.h"
2
2
 
3
+ typedef struct VMData {
4
+ char alive;
5
+ struct JSContext *context;
6
+ struct QuickjsrbRuntimeState *state;
7
+ struct ProcEntryMap *procs;
8
+ } VMData;
9
+
10
+ void vm_free(void* data)
11
+ {
12
+ free(data);
13
+ }
14
+
15
+ size_t vm_size(const void* data)
16
+ {
17
+ return sizeof(data);
18
+ }
19
+
20
+ static const rb_data_type_t vm_type = {
21
+ .wrap_struct_name = "vm",
22
+ .function = {
23
+ .dmark = NULL,
24
+ .dfree = vm_free,
25
+ .dsize = vm_size,
26
+ },
27
+ .data = NULL,
28
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
29
+ };
30
+
31
+ VALUE vm_alloc(VALUE self)
32
+ {
33
+ VMData *data;
34
+ return TypedData_Make_Struct(self, VMData, &vm_type, data);
35
+ }
36
+
3
37
  VALUE rb_mQuickjs;
4
38
  const char *undefinedId = "undefined";
5
39
  const char *nanId = "NaN";
@@ -7,7 +41,63 @@ const char *nanId = "NaN";
7
41
  const char *featureStdId = "feature_std";
8
42
  const char *featureOsId = "feature_os";
9
43
 
10
- VALUE to_rb_value (JSValue jsv, JSContext *ctx) {
44
+ JSValue to_js_value(JSContext *ctx, VALUE r_value) {
45
+ switch (TYPE(r_value)) {
46
+ case T_NIL:
47
+ return JS_NULL;
48
+ case T_FIXNUM:
49
+ case T_FLOAT: {
50
+ VALUE r_str = rb_funcall(r_value, rb_intern("to_s"), 0, NULL);
51
+ char *str = StringValueCStr(r_str);
52
+ JSValue global = JS_GetGlobalObject(ctx);
53
+ JSValue numberClass = JS_GetPropertyStr(ctx, global, "Number");
54
+ JSValue j_str = JS_NewString(ctx, str);
55
+ JSValue stringified = JS_Call(ctx, numberClass, JS_UNDEFINED, 1, &j_str);
56
+ JS_FreeValue(ctx, global);
57
+ JS_FreeValue(ctx, numberClass);
58
+
59
+ return stringified;
60
+ }
61
+ case T_STRING: {
62
+ char *str = StringValueCStr(r_value);
63
+
64
+ return JS_NewString(ctx, str);
65
+ }
66
+ case T_SYMBOL: {
67
+ VALUE r_str = rb_funcall(r_value, rb_intern("to_s"), 0, NULL);
68
+ char *str = StringValueCStr(r_str);
69
+
70
+ return JS_NewString(ctx, str);
71
+ }
72
+ case T_TRUE:
73
+ return JS_TRUE;
74
+ case T_FALSE:
75
+ return JS_FALSE;
76
+ case T_HASH:
77
+ case T_ARRAY: {
78
+ VALUE r_json_str = rb_funcall(r_value, rb_intern("to_json"), 0, NULL);
79
+ char *str = StringValueCStr(r_json_str);
80
+ JSValue global = JS_GetGlobalObject(ctx);
81
+ JSValue jsonClass = JS_GetPropertyStr(ctx, global, "JSON");
82
+ JSValue parseFunc = JS_GetPropertyStr(ctx, jsonClass, "parse");
83
+ JSValue j_str = JS_NewString(ctx, str);
84
+ JSValue stringified = JS_Call(ctx, parseFunc, jsonClass, 1, &j_str);
85
+ JS_FreeValue(ctx, global);
86
+ JS_FreeValue(ctx, parseFunc);
87
+ JS_FreeValue(ctx, jsonClass);
88
+
89
+ return stringified;
90
+ }
91
+ default: {
92
+ VALUE r_inspect_str = rb_funcall(r_value, rb_intern("inspect"), 0, NULL);
93
+ char *str = StringValueCStr(r_inspect_str);
94
+
95
+ return JS_NewString(ctx, str);
96
+ }
97
+ }
98
+ }
99
+
100
+ VALUE to_rb_value(JSValue jsv, JSContext *ctx) {
11
101
  switch(JS_VALUE_GET_NORM_TAG(jsv)) {
12
102
  case JS_TAG_INT: {
13
103
  int int_res = 0;
@@ -31,6 +121,13 @@ VALUE to_rb_value (JSValue jsv, JSContext *ctx) {
31
121
  return rb_str_new2(msg);
32
122
  }
33
123
  case JS_TAG_OBJECT: {
124
+ int promiseState = JS_PromiseState(ctx, jsv);
125
+ if (promiseState == JS_PROMISE_FULFILLED || promiseState == JS_PROMISE_PENDING) {
126
+ return to_rb_value(js_std_await(ctx, jsv), ctx);
127
+ } else if (promiseState == JS_PROMISE_REJECTED) {
128
+ return to_rb_value(JS_Throw(ctx, JS_PromiseResult(ctx, jsv)), ctx);
129
+ }
130
+
34
131
  JSValue global = JS_GetGlobalObject(ctx);
35
132
  JSValue jsonClass = JS_GetPropertyStr(ctx, global, "JSON");
36
133
  JSValue stringifyFunc = JS_GetPropertyStr(ctx, jsonClass, "stringify");
@@ -50,9 +147,28 @@ VALUE to_rb_value (JSValue jsv, JSContext *ctx) {
50
147
  return Qnil;
51
148
  case JS_TAG_UNDEFINED:
52
149
  return ID2SYM(rb_intern(undefinedId));
53
- case JS_TAG_EXCEPTION:
54
- rb_raise(rb_eRuntimeError, "Something happened by evaluating as JavaScript code");
150
+ case JS_TAG_EXCEPTION: {
151
+ JSValue exceptionVal = JS_GetException(ctx);
152
+ if (JS_IsError(ctx, exceptionVal)) {
153
+ JSValue jsErrorClassName = JS_GetPropertyStr(ctx, exceptionVal, "name");
154
+ const char *errorClassName = JS_ToCString(ctx, jsErrorClassName);
155
+
156
+ JSValue jsErrorClassMessage = JS_GetPropertyStr(ctx, exceptionVal, "message");
157
+ const char *errorClassMessage = JS_ToCString(ctx, jsErrorClassMessage);
158
+
159
+ JS_FreeValue(ctx, jsErrorClassMessage);
160
+ JS_FreeValue(ctx, jsErrorClassName);
161
+
162
+ rb_raise(rb_eRuntimeError, "%s: %s", errorClassName, errorClassMessage);
163
+ } else {
164
+ const char *errorMessage = JS_ToCString(ctx, exceptionVal);
165
+
166
+ rb_raise(rb_eRuntimeError, "%s", errorMessage);
167
+ }
168
+
169
+ JS_FreeValue(ctx, exceptionVal);
55
170
  return Qnil;
171
+ }
56
172
  case JS_TAG_BIG_INT: {
57
173
  JSValue toStringFunc = JS_GetPropertyStr(ctx, jsv, "toString");
58
174
  JSValue strigified = JS_Call(ctx, toStringFunc, jsv, 0, NULL);
@@ -72,40 +188,22 @@ VALUE to_rb_value (JSValue jsv, JSContext *ctx) {
72
188
  }
73
189
  }
74
190
 
75
- struct qvmdata {
76
- struct JSContext *context;
77
- char alive;
78
- };
79
-
80
- void qvm_free(void* data)
81
- {
82
- free(data);
83
- }
84
-
85
- size_t qvm_size(const void* data)
86
- {
87
- return sizeof(data);
88
- }
89
-
90
- static const rb_data_type_t qvm_type = {
91
- .wrap_struct_name = "qvm",
92
- .function = {
93
- .dmark = NULL,
94
- .dfree = qvm_free,
95
- .dsize = qvm_size,
96
- },
97
- .data = NULL,
98
- .flags = RUBY_TYPED_FREE_IMMEDIATELY,
99
- };
191
+ static JSValue js_quickjsrb_call_global(JSContext *ctx, JSValueConst _this, int _argc, JSValueConst *argv) {
192
+ VMData *data = JS_GetContextOpaque(ctx);
193
+ JSValue maybeFuncName = JS_ToString(ctx, argv[0]);
194
+ const char *funcName = JS_ToCString(ctx, maybeFuncName);
195
+ JS_FreeValue(ctx, maybeFuncName);
100
196
 
101
- VALUE qvm_alloc(VALUE self)
102
- {
103
- struct qvmdata *data;
197
+ VALUE proc = get_proc(data->procs, funcName);
198
+ if (proc == Qnil) { // Shouldn't happen
199
+ return JS_ThrowReferenceError(ctx, "Proc `%s` is not defined", funcName);
200
+ }
104
201
 
105
- return TypedData_Make_Struct(self, struct qvmdata, &qvm_type, data);
202
+ VALUE r_result = rb_apply(proc, rb_intern("call"), to_rb_value(argv[1], ctx));
203
+ return to_js_value(ctx, r_result);
106
204
  }
107
205
 
108
- VALUE qvm_m_initialize(int argc, VALUE* argv, VALUE self)
206
+ VALUE vm_m_initialize(int argc, VALUE* argv, VALUE self)
109
207
  {
110
208
  VALUE r_opts;
111
209
  rb_scan_args(argc, argv, ":", &r_opts);
@@ -118,11 +216,14 @@ VALUE qvm_m_initialize(int argc, VALUE* argv, VALUE self)
118
216
  VALUE r_features = rb_hash_aref(r_opts, ID2SYM(rb_intern("features")));
119
217
  if (NIL_P(r_features)) r_features = rb_ary_new();
120
218
 
121
- struct qvmdata *data;
122
- TypedData_Get_Struct(self, struct qvmdata, &qvm_type, data);
219
+ VMData *data;
220
+ TypedData_Get_Struct(self, VMData, &vm_type, data);
221
+
123
222
  JSRuntime *runtime = JS_NewRuntime();
124
223
  data->context = JS_NewContext(runtime);
224
+ data->procs = create_proc_entries();
125
225
  data->alive = 1;
226
+ JS_SetContextOpaque(data->context, data);
126
227
 
127
228
  JS_SetMemoryLimit(runtime, NUM2UINT(r_memoryLimit));
128
229
  JS_SetMaxStackSize(runtime, NUM2UINT(r_maxStackSize));
@@ -152,13 +253,22 @@ VALUE qvm_m_initialize(int argc, VALUE* argv, VALUE self)
152
253
  JS_FreeValue(data->context, osEval);
153
254
  }
154
255
 
256
+ const char *setupGlobalRuby = "globalThis.__ruby = {};\n";
257
+ JSValue rubyEval = JS_Eval(data->context, setupGlobalRuby, strlen(setupGlobalRuby), "<vm>", JS_EVAL_TYPE_MODULE);
258
+ JS_FreeValue(data->context, rubyEval);
259
+
260
+ JSValue global = JS_GetGlobalObject(data->context);
261
+ JSValue func = JS_NewCFunction(data->context, js_quickjsrb_call_global, "rubyGlobal", 2);
262
+ JS_SetPropertyStr(data->context, global, "rubyGlobal", func);
263
+ JS_FreeValue(data->context, global);
264
+
155
265
  return self;
156
266
  }
157
267
 
158
- VALUE qvm_m_evalCode(VALUE self, VALUE r_code)
268
+ VALUE vm_m_evalCode(VALUE self, VALUE r_code)
159
269
  {
160
- struct qvmdata *data;
161
- TypedData_Get_Struct(self, struct qvmdata, &qvm_type, data);
270
+ VMData *data;
271
+ TypedData_Get_Struct(self, VMData, &vm_type, data);
162
272
 
163
273
  if (data->alive < 1) {
164
274
  rb_raise(rb_eRuntimeError, "Quickjs::VM was disposed");
@@ -172,13 +282,43 @@ VALUE qvm_m_evalCode(VALUE self, VALUE r_code)
172
282
  return result;
173
283
  }
174
284
 
175
- VALUE qvm_m_dispose(VALUE self)
285
+ VALUE vm_m_defineGlobalFunction(VALUE self, VALUE r_name)
286
+ {
287
+ rb_need_block();
288
+
289
+ VMData *data;
290
+ TypedData_Get_Struct(self, VMData, &vm_type, data);
291
+
292
+ if (rb_block_given_p()) {
293
+ VALUE proc = rb_block_proc();
294
+
295
+ char *funcName = StringValueCStr(r_name);
296
+
297
+ set_proc(data->procs, funcName, proc);
298
+
299
+ const char* template = "globalThis.__ruby['%s'] = (...args) => rubyGlobal('%s', args);\nglobalThis['%s'] = globalThis.__ruby['%s'];\n";
300
+ int length = snprintf(NULL, 0, template, funcName, funcName, funcName, funcName);
301
+ char* result = (char*)malloc(length + 1);
302
+ snprintf(result, length + 1, template, funcName, funcName, funcName, funcName);
303
+
304
+ JSValue codeResult = JS_Eval(data->context, result, strlen(result), "<vm>", JS_EVAL_TYPE_MODULE);
305
+
306
+ JS_FreeValue(data->context, codeResult);
307
+ free(result);
308
+ return rb_funcall(r_name, rb_intern("to_sym"), 0, NULL);
309
+ }
310
+
311
+ return Qnil;
312
+ }
313
+
314
+ VALUE vm_m_dispose(VALUE self)
176
315
  {
177
- struct qvmdata *data;
178
- TypedData_Get_Struct(self, struct qvmdata, &qvm_type, data);
316
+ VMData *data;
317
+ TypedData_Get_Struct(self, VMData, &vm_type, data);
179
318
 
180
319
  JSRuntime *runtime = JS_GetRuntime(data->context);
181
320
  js_std_free_handlers(runtime);
321
+ free_proc_entry_map(data->procs);
182
322
  JS_FreeContext(data->context);
183
323
  JS_FreeRuntime(runtime);
184
324
  data->alive = 0;
@@ -198,8 +338,9 @@ Init_quickjsrb(void)
198
338
  rb_define_const(valueClass, "NAN", ID2SYM(rb_intern(nanId)));
199
339
 
200
340
  VALUE vmClass = rb_define_class_under(rb_mQuickjs, "VM", rb_cObject);
201
- rb_define_alloc_func(vmClass, qvm_alloc);
202
- rb_define_method(vmClass, "initialize", qvm_m_initialize, -1);
203
- rb_define_method(vmClass, "eval_code", qvm_m_evalCode, 1);
204
- rb_define_method(vmClass, "dispose!", qvm_m_dispose, 0);
341
+ rb_define_alloc_func(vmClass, vm_alloc);
342
+ rb_define_method(vmClass, "initialize", vm_m_initialize, -1);
343
+ rb_define_method(vmClass, "eval_code", vm_m_evalCode, 1);
344
+ rb_define_method(vmClass, "define_function", vm_m_defineGlobalFunction, 1);
345
+ rb_define_method(vmClass, "dispose!", vm_m_dispose, 0);
205
346
  }
@@ -11,4 +11,6 @@
11
11
  #include <stdio.h>
12
12
  #include <string.h>
13
13
 
14
+ #include "procs.h"
15
+
14
16
  #endif /* QUICKJSRB_H */
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Quickjs
4
- VERSION = "0.1.5"
4
+ VERSION = "0.1.7"
5
5
  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.1.5
4
+ version: 0.1.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - hmsk
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-07-01 00:00:00.000000000 Z
11
+ date: 2024-07-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json
@@ -37,6 +37,8 @@ files:
37
37
  - README.md
38
38
  - Rakefile
39
39
  - ext/quickjsrb/extconf.rb
40
+ - ext/quickjsrb/procs.c
41
+ - ext/quickjsrb/procs.h
40
42
  - ext/quickjsrb/quickjs/LICENSE
41
43
  - ext/quickjsrb/quickjs/cutils.c
42
44
  - ext/quickjsrb/quickjs/cutils.h