duktape 1.0.2.0 → 1.1.2.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/CHANGELOG.md +17 -0
- data/README.md +50 -19
- data/ext/duktape/duktape.c +18317 -16099
- data/ext/duktape/duktape.h +384 -72
- data/ext/duktape/duktape_ext.c +577 -66
- data/ext/duktape/extconf.rb +1 -0
- data/lib/duktape/version.rb +1 -1
- metadata +2 -2
data/ext/duktape/duktape_ext.c
CHANGED
@@ -1,28 +1,188 @@
|
|
1
1
|
#include "ruby.h"
|
2
|
+
#include "ruby/encoding.h"
|
2
3
|
#include "duktape.h"
|
3
4
|
|
4
5
|
static VALUE mDuktape;
|
5
6
|
static VALUE cContext;
|
6
|
-
static VALUE
|
7
|
+
static VALUE cComplexObject;
|
8
|
+
static VALUE oComplexObject;
|
9
|
+
|
10
|
+
static VALUE eUnimplementedError;
|
11
|
+
static VALUE eUnsupportedError;
|
12
|
+
static VALUE eInternalError;
|
13
|
+
static VALUE eAllocError;
|
14
|
+
static VALUE eAssertionError;
|
15
|
+
static VALUE eAPIError;
|
16
|
+
static VALUE eUncaughtError;
|
17
|
+
|
18
|
+
static VALUE eError;
|
19
|
+
static VALUE eEvalError;
|
20
|
+
static VALUE eRangeError;
|
21
|
+
static VALUE eReferenceError;
|
22
|
+
static VALUE eSyntaxError;
|
23
|
+
static VALUE eTypeError;
|
24
|
+
static VALUE eURIError;
|
25
|
+
static rb_encoding *utf16enc;
|
26
|
+
|
27
|
+
static VALUE sDefaultFilename;
|
28
|
+
static ID id_complex_object;
|
29
|
+
|
7
30
|
static void error_handler(duk_context *, int, const char *);
|
31
|
+
static int ctx_push_hash_element(VALUE key, VALUE val, VALUE extra);
|
32
|
+
|
33
|
+
static unsigned long
|
34
|
+
utf8_to_uv(const char *p, long *lenp);
|
35
|
+
|
36
|
+
#define clean_raise(ctx, ...) (duk_set_top(ctx, 0), rb_raise(__VA_ARGS__))
|
37
|
+
#define clean_raise_exc(ctx, ...) (duk_set_top(ctx, 0), rb_exc_raise(__VA_ARGS__))
|
38
|
+
|
39
|
+
struct state {
|
40
|
+
duk_context *ctx;
|
41
|
+
VALUE complex_object;
|
42
|
+
int was_complex;
|
43
|
+
};
|
8
44
|
|
9
|
-
static void ctx_dealloc(void *
|
45
|
+
static void ctx_dealloc(void *ptr)
|
10
46
|
{
|
11
|
-
|
47
|
+
struct state *state = (struct state *)ptr;
|
48
|
+
duk_destroy_heap(state->ctx);
|
49
|
+
free(state);
|
50
|
+
}
|
51
|
+
|
52
|
+
static void ctx_mark(struct state *state)
|
53
|
+
{
|
54
|
+
rb_gc_mark(state->complex_object);
|
12
55
|
}
|
13
56
|
|
14
57
|
static VALUE ctx_alloc(VALUE klass)
|
15
58
|
{
|
16
59
|
duk_context *ctx = duk_create_heap(NULL, NULL, NULL, NULL, error_handler);
|
17
|
-
|
60
|
+
|
61
|
+
// Undefine require property
|
62
|
+
duk_push_global_object(ctx);
|
63
|
+
duk_push_string(ctx, "require");
|
64
|
+
duk_del_prop(ctx, -2);
|
65
|
+
duk_set_top(ctx, 0);
|
66
|
+
|
67
|
+
struct state *state = malloc(sizeof(struct state));
|
68
|
+
state->ctx = ctx;
|
69
|
+
state->complex_object = oComplexObject;
|
70
|
+
return Data_Wrap_Struct(klass, ctx_mark, ctx_dealloc, state);
|
71
|
+
}
|
72
|
+
|
73
|
+
static VALUE error_code_class(int code) {
|
74
|
+
switch (code) {
|
75
|
+
case DUK_ERR_UNIMPLEMENTED_ERROR:
|
76
|
+
return eUnimplementedError;
|
77
|
+
case DUK_ERR_UNSUPPORTED_ERROR:
|
78
|
+
return eUnsupportedError;
|
79
|
+
case DUK_ERR_INTERNAL_ERROR:
|
80
|
+
return eInternalError;
|
81
|
+
case DUK_ERR_ALLOC_ERROR:
|
82
|
+
return eAllocError;
|
83
|
+
case DUK_ERR_ASSERTION_ERROR:
|
84
|
+
return eAssertionError;
|
85
|
+
case DUK_ERR_API_ERROR:
|
86
|
+
return eAPIError;
|
87
|
+
case DUK_ERR_UNCAUGHT_ERROR:
|
88
|
+
return eUncaughtError;
|
89
|
+
|
90
|
+
case DUK_ERR_ERROR:
|
91
|
+
return eError;
|
92
|
+
case DUK_ERR_EVAL_ERROR:
|
93
|
+
return eEvalError;
|
94
|
+
case DUK_ERR_RANGE_ERROR:
|
95
|
+
return eRangeError;
|
96
|
+
case DUK_ERR_REFERENCE_ERROR:
|
97
|
+
return eReferenceError;
|
98
|
+
case DUK_ERR_SYNTAX_ERROR:
|
99
|
+
return eSyntaxError;
|
100
|
+
case DUK_ERR_TYPE_ERROR:
|
101
|
+
return eTypeError;
|
102
|
+
case DUK_ERR_URI_ERROR:
|
103
|
+
return eURIError;
|
104
|
+
|
105
|
+
default:
|
106
|
+
return eInternalError;
|
107
|
+
}
|
108
|
+
}
|
109
|
+
|
110
|
+
static VALUE error_name_class(const char* name)
|
111
|
+
{
|
112
|
+
if (strcmp(name, "EvalError") == 0) {
|
113
|
+
return eEvalError;
|
114
|
+
} else if (strcmp(name, "RangeError") == 0) {
|
115
|
+
return eRangeError;
|
116
|
+
} else if (strcmp(name, "ReferenceError") == 0) {
|
117
|
+
return eReferenceError;
|
118
|
+
} else if (strcmp(name, "SyntaxError") == 0) {
|
119
|
+
return eSyntaxError;
|
120
|
+
} else if (strcmp(name, "TypeError") == 0) {
|
121
|
+
return eTypeError;
|
122
|
+
} else if (strcmp(name, "URIError") == 0) {
|
123
|
+
return eURIError;
|
124
|
+
} else {
|
125
|
+
return eError;
|
126
|
+
}
|
127
|
+
}
|
128
|
+
|
129
|
+
static VALUE encode_cesu8(struct state *state, VALUE str)
|
130
|
+
{
|
131
|
+
duk_context *ctx = state->ctx;
|
132
|
+
VALUE res = rb_str_new(0, 0);
|
133
|
+
|
134
|
+
VALUE utf16 = rb_str_conv_enc(str, rb_enc_get(str), utf16enc);
|
135
|
+
if (utf16 == str && rb_enc_get(str) != utf16enc) {
|
136
|
+
clean_raise(ctx, rb_eEncodingError, "cannot convert Ruby string to UTF-16");
|
137
|
+
}
|
138
|
+
|
139
|
+
long len = RSTRING_LEN(utf16) / 2;
|
140
|
+
unsigned short *bytes = (unsigned short *)RSTRING_PTR(utf16);
|
141
|
+
|
142
|
+
char buf[8];
|
143
|
+
|
144
|
+
for (int i = 0; i < len; i++) {
|
145
|
+
int length = rb_uv_to_utf8(buf, bytes[i]);
|
146
|
+
rb_str_buf_cat(res, (char*)buf, length);
|
147
|
+
}
|
148
|
+
|
149
|
+
return res;
|
150
|
+
}
|
151
|
+
|
152
|
+
static VALUE decode_cesu8(struct state *state, VALUE str)
|
153
|
+
{
|
154
|
+
duk_context *ctx = state->ctx;
|
155
|
+
VALUE res = rb_str_new(0, 0);
|
156
|
+
|
157
|
+
const char *ptr = RSTRING_PTR(str);
|
158
|
+
const char *end = RSTRING_END(str);
|
159
|
+
long len;
|
160
|
+
|
161
|
+
while (ptr < end) {
|
162
|
+
len = (end - ptr);
|
163
|
+
unsigned short code = utf8_to_uv(ptr, &len);
|
164
|
+
rb_str_buf_cat(res, (char*)&code, 2);
|
165
|
+
ptr += len;
|
166
|
+
}
|
167
|
+
|
168
|
+
rb_enc_associate(res, utf16enc);
|
169
|
+
VALUE utf8res = rb_str_conv_enc(res, utf16enc, rb_utf8_encoding());
|
170
|
+
if (utf8res == res) {
|
171
|
+
clean_raise(ctx, rb_eEncodingError, "cannot convert JavaScript string to UTF-16");
|
172
|
+
}
|
173
|
+
|
174
|
+
return utf8res;
|
18
175
|
}
|
19
176
|
|
20
|
-
static VALUE ctx_stack_to_value(
|
177
|
+
static VALUE ctx_stack_to_value(struct state *state, int index)
|
21
178
|
{
|
179
|
+
duk_context *ctx = state->ctx;
|
22
180
|
size_t len;
|
23
181
|
const char *buf;
|
24
182
|
int type;
|
25
183
|
|
184
|
+
state->was_complex = 0;
|
185
|
+
|
26
186
|
type = duk_get_type(ctx, index);
|
27
187
|
switch (type) {
|
28
188
|
case DUK_TYPE_NULL:
|
@@ -37,147 +197,498 @@ static VALUE ctx_stack_to_value(duk_context *ctx, int index)
|
|
37
197
|
|
38
198
|
case DUK_TYPE_STRING:
|
39
199
|
buf = duk_get_lstring(ctx, index, &len);
|
40
|
-
|
200
|
+
VALUE str = rb_str_new(buf, len);
|
201
|
+
return decode_cesu8(state, str);
|
41
202
|
|
42
203
|
case DUK_TYPE_OBJECT:
|
204
|
+
if (duk_is_function(ctx, index)) {
|
205
|
+
state->was_complex = 1;
|
206
|
+
return state->complex_object;
|
207
|
+
} else if (duk_is_array(ctx, index)) {
|
208
|
+
VALUE ary = rb_ary_new();
|
209
|
+
duk_enum(ctx, index, DUK_ENUM_ARRAY_INDICES_ONLY);
|
210
|
+
while (duk_next(ctx, -1, 1)) {
|
211
|
+
rb_ary_store(ary, duk_to_int(ctx, -2), ctx_stack_to_value(state, -1));
|
212
|
+
duk_pop_2(ctx);
|
213
|
+
}
|
214
|
+
duk_pop(ctx);
|
215
|
+
return ary;
|
216
|
+
} else if (duk_is_object(ctx, index)) {
|
217
|
+
VALUE hash = rb_hash_new();
|
218
|
+
duk_enum(ctx, index, DUK_ENUM_OWN_PROPERTIES_ONLY);
|
219
|
+
while (duk_next(ctx, -1, 1)) {
|
220
|
+
VALUE key = ctx_stack_to_value(state, -2);
|
221
|
+
VALUE val = ctx_stack_to_value(state, -1);
|
222
|
+
duk_pop_2(ctx);
|
223
|
+
if (state->was_complex)
|
224
|
+
continue;
|
225
|
+
rb_hash_aset(hash, key, val);
|
226
|
+
}
|
227
|
+
duk_pop(ctx);
|
228
|
+
return hash;
|
229
|
+
} else {
|
230
|
+
state->was_complex = 1;
|
231
|
+
return state->complex_object;
|
232
|
+
}
|
233
|
+
|
43
234
|
case DUK_TYPE_BUFFER:
|
44
235
|
case DUK_TYPE_POINTER:
|
45
236
|
default:
|
46
|
-
|
237
|
+
return state->complex_object;
|
47
238
|
}
|
48
239
|
|
49
240
|
return Qnil;
|
50
241
|
}
|
51
242
|
|
52
|
-
static
|
243
|
+
static void ctx_push_ruby_object(struct state *state, VALUE obj)
|
53
244
|
{
|
245
|
+
duk_context *ctx = state->ctx;
|
246
|
+
duk_idx_t arr_idx;
|
247
|
+
VALUE str;
|
248
|
+
|
54
249
|
switch (TYPE(obj)) {
|
55
250
|
case T_FIXNUM:
|
56
251
|
duk_push_int(ctx, NUM2INT(obj));
|
57
|
-
|
252
|
+
return;
|
58
253
|
|
59
254
|
case T_FLOAT:
|
60
255
|
duk_push_number(ctx, NUM2DBL(obj));
|
61
|
-
|
256
|
+
return;
|
62
257
|
|
63
258
|
case T_STRING:
|
64
|
-
|
65
|
-
|
259
|
+
str = encode_cesu8(state, obj);
|
260
|
+
duk_push_lstring(ctx, RSTRING_PTR(str), RSTRING_LEN(str));
|
261
|
+
return;
|
66
262
|
|
67
263
|
case T_TRUE:
|
68
264
|
duk_push_true(ctx);
|
69
|
-
|
265
|
+
return;
|
70
266
|
|
71
267
|
case T_FALSE:
|
72
268
|
duk_push_false(ctx);
|
73
|
-
|
269
|
+
return;
|
74
270
|
|
75
271
|
case T_NIL:
|
76
272
|
duk_push_null(ctx);
|
77
|
-
|
273
|
+
return;
|
274
|
+
|
275
|
+
case T_ARRAY:
|
276
|
+
arr_idx = duk_push_array(ctx);
|
277
|
+
for (int idx = 0; idx < RARRAY_LEN(obj); idx++) {
|
278
|
+
ctx_push_ruby_object(state, rb_ary_entry(obj, idx));
|
279
|
+
duk_put_prop_index(ctx, arr_idx, idx);
|
280
|
+
}
|
281
|
+
return;
|
282
|
+
|
283
|
+
case T_HASH:
|
284
|
+
duk_push_object(ctx);
|
285
|
+
rb_hash_foreach(obj, ctx_push_hash_element, (VALUE)state);
|
286
|
+
return;
|
78
287
|
|
79
288
|
default:
|
80
289
|
// Cannot convert
|
81
|
-
|
290
|
+
break;
|
82
291
|
}
|
83
292
|
|
84
|
-
|
85
|
-
return 1;
|
293
|
+
clean_raise(ctx, rb_eTypeError, "cannot convert %s", rb_obj_classname(obj));
|
86
294
|
}
|
87
295
|
|
88
|
-
static
|
296
|
+
static int ctx_push_hash_element(VALUE key, VALUE val, VALUE extra)
|
89
297
|
{
|
90
|
-
|
91
|
-
|
298
|
+
struct state *state = (struct state*) extra;
|
299
|
+
duk_context *ctx = state->ctx;
|
300
|
+
|
301
|
+
Check_Type(key, T_STRING);
|
302
|
+
duk_push_lstring(ctx, RSTRING_PTR(key), RSTRING_LEN(key));
|
303
|
+
ctx_push_ruby_object(state, val);
|
304
|
+
duk_put_prop(ctx, -3);
|
305
|
+
return ST_CONTINUE;
|
306
|
+
}
|
307
|
+
|
308
|
+
static void raise_ctx_error(struct state *state)
|
309
|
+
{
|
310
|
+
duk_context *ctx = state->ctx;
|
311
|
+
duk_get_prop_string(ctx, -1, "name");
|
312
|
+
const char *name = duk_safe_to_string(ctx, -1);
|
92
313
|
|
93
|
-
|
94
|
-
|
95
|
-
duk_compile(ctx, DUK_COMPILE_EVAL);
|
96
|
-
duk_call(ctx, 0);
|
314
|
+
duk_get_prop_string(ctx, -2, "message");
|
315
|
+
const char *message = duk_to_string(ctx, -1);
|
97
316
|
|
98
|
-
VALUE
|
99
|
-
|
317
|
+
VALUE exc_class = error_name_class(name);
|
318
|
+
VALUE exc = rb_exc_new2(exc_class, message);
|
319
|
+
clean_raise_exc(ctx, exc);
|
320
|
+
}
|
321
|
+
|
322
|
+
/*
|
323
|
+
* call-seq:
|
324
|
+
* eval_string(string[, filename]) -> obj
|
325
|
+
*
|
326
|
+
* Evaluate JavaScript expression within context returning the value as a Ruby
|
327
|
+
* object.
|
328
|
+
*
|
329
|
+
* ctx.eval_string("40 + 2") #=> 42
|
330
|
+
*
|
331
|
+
*/
|
332
|
+
static VALUE ctx_eval_string(int argc, VALUE *argv, VALUE self)
|
333
|
+
{
|
334
|
+
struct state *state;
|
335
|
+
Data_Get_Struct(self, struct state, state);
|
336
|
+
|
337
|
+
VALUE source;
|
338
|
+
VALUE filename;
|
339
|
+
|
340
|
+
rb_scan_args(argc, argv, "11", &source, &filename);
|
341
|
+
|
342
|
+
if (NIL_P(filename)) {
|
343
|
+
filename = sDefaultFilename;
|
344
|
+
}
|
345
|
+
|
346
|
+
StringValue(source);
|
347
|
+
StringValue(filename);
|
348
|
+
|
349
|
+
ctx_push_ruby_object(state, source);
|
350
|
+
ctx_push_ruby_object(state, filename);
|
351
|
+
|
352
|
+
if (duk_pcompile(state->ctx, DUK_COMPILE_EVAL) == DUK_EXEC_ERROR) {
|
353
|
+
raise_ctx_error(state);
|
354
|
+
}
|
355
|
+
|
356
|
+
if (duk_pcall(state->ctx, 0) == DUK_EXEC_ERROR) {
|
357
|
+
raise_ctx_error(state);
|
358
|
+
}
|
359
|
+
|
360
|
+
VALUE res = ctx_stack_to_value(state, -1);
|
361
|
+
duk_set_top(state->ctx, 0);
|
100
362
|
return res;
|
101
363
|
}
|
102
364
|
|
103
|
-
|
365
|
+
/*
|
366
|
+
* call-seq:
|
367
|
+
* exec_string(string[, filename]) -> nil
|
368
|
+
*
|
369
|
+
* Evaluate JavaScript expression within context returning the value as a Ruby
|
370
|
+
* object.
|
371
|
+
*
|
372
|
+
* ctx.exec_string("var foo = 42")
|
373
|
+
* ctx.eval_string("foo") #=> 42
|
374
|
+
*
|
375
|
+
*/
|
376
|
+
static VALUE ctx_exec_string(int argc, VALUE *argv, VALUE self)
|
104
377
|
{
|
105
|
-
|
106
|
-
Data_Get_Struct(self,
|
378
|
+
struct state *state;
|
379
|
+
Data_Get_Struct(self, struct state, state);
|
107
380
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
381
|
+
VALUE source;
|
382
|
+
VALUE filename;
|
383
|
+
|
384
|
+
rb_scan_args(argc, argv, "11", &source, &filename);
|
385
|
+
|
386
|
+
if (NIL_P(filename)) {
|
387
|
+
filename = sDefaultFilename;
|
388
|
+
}
|
389
|
+
|
390
|
+
StringValue(source);
|
391
|
+
StringValue(filename);
|
392
|
+
|
393
|
+
ctx_push_ruby_object(state, source);
|
394
|
+
ctx_push_ruby_object(state, filename);
|
395
|
+
|
396
|
+
if (duk_pcompile(state->ctx, 0) == DUK_EXEC_ERROR) {
|
397
|
+
raise_ctx_error(state);
|
398
|
+
}
|
399
|
+
|
400
|
+
if (duk_pcall(state->ctx, 0) == DUK_EXEC_ERROR) {
|
401
|
+
raise_ctx_error(state);
|
402
|
+
}
|
403
|
+
|
404
|
+
duk_set_top(state->ctx, 0);
|
113
405
|
return Qnil;
|
114
406
|
}
|
115
407
|
|
116
|
-
static
|
408
|
+
static void ctx_get_one_prop(struct state *state, VALUE name, int strict)
|
117
409
|
{
|
118
|
-
duk_context *ctx;
|
119
|
-
Data_Get_Struct(self, duk_context, ctx);
|
410
|
+
duk_context *ctx = state->ctx;
|
120
411
|
|
121
|
-
|
412
|
+
// Don't allow prop access on undefined/null
|
413
|
+
if (duk_check_type_mask(ctx, -1, DUK_TYPE_MASK_UNDEFINED | DUK_TYPE_MASK_NULL)) {
|
414
|
+
clean_raise(ctx, eTypeError, "invalid base value");
|
415
|
+
}
|
122
416
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
const char *str = StringValueCStr(
|
128
|
-
|
417
|
+
duk_push_lstring(ctx, RSTRING_PTR(name), RSTRING_LEN(name));
|
418
|
+
duk_bool_t exists = duk_get_prop(ctx, -2);
|
419
|
+
|
420
|
+
if (!exists && strict) {
|
421
|
+
const char *str = StringValueCStr(name);
|
422
|
+
clean_raise(ctx, eReferenceError, "identifier '%s' undefined", str);
|
129
423
|
}
|
424
|
+
}
|
130
425
|
|
131
|
-
|
132
|
-
|
426
|
+
static void ctx_get_nested_prop(struct state *state, VALUE props)
|
427
|
+
{
|
428
|
+
duk_context *ctx = state->ctx;
|
429
|
+
|
430
|
+
switch (TYPE(props)) {
|
431
|
+
case T_STRING:
|
432
|
+
duk_push_global_object(ctx);
|
433
|
+
ctx_get_one_prop(state, props, 1);
|
434
|
+
return;
|
435
|
+
|
436
|
+
case T_ARRAY:
|
437
|
+
duk_push_global_object(ctx);
|
438
|
+
|
439
|
+
long len = RARRAY_LEN(props);
|
440
|
+
for (int i = 0; i < len; i++) {
|
441
|
+
VALUE item = rb_ary_entry(props, i);
|
442
|
+
Check_Type(item, T_STRING);
|
443
|
+
|
444
|
+
// Only do a strict check on the first item
|
445
|
+
ctx_get_one_prop(state, item, i == 0);
|
446
|
+
}
|
447
|
+
return;
|
448
|
+
|
449
|
+
default:
|
450
|
+
clean_raise(ctx, rb_eTypeError, "wrong argument type %s (expected String or Array)", rb_obj_classname(props));
|
451
|
+
return;
|
452
|
+
}
|
453
|
+
}
|
454
|
+
|
455
|
+
/*
|
456
|
+
* call-seq:
|
457
|
+
* get_prop(name) -> obj
|
458
|
+
* get_prop([names,...]) -> obj
|
459
|
+
*
|
460
|
+
* Access the property of the global object. An Array of names can be given
|
461
|
+
* to access the property on a nested object.
|
462
|
+
*
|
463
|
+
* ctx.exec_string("var n = 42", "foo.js")
|
464
|
+
* ctx.get_prop("n") #=> 42
|
465
|
+
*
|
466
|
+
* ctx.get_prop(["Math", "PI"]) #=> 3.14
|
467
|
+
*
|
468
|
+
*/
|
469
|
+
static VALUE ctx_get_prop(VALUE self, VALUE prop)
|
470
|
+
{
|
471
|
+
struct state *state;
|
472
|
+
Data_Get_Struct(self, struct state, state);
|
473
|
+
|
474
|
+
ctx_get_nested_prop(state, prop);
|
475
|
+
|
476
|
+
VALUE res = ctx_stack_to_value(state, -1);
|
477
|
+
duk_set_top(state->ctx, 0);
|
133
478
|
return res;
|
134
479
|
}
|
135
480
|
|
481
|
+
|
482
|
+
/*
|
483
|
+
* call-seq:
|
484
|
+
* call_prop(name, params,...) -> obj
|
485
|
+
* call_prop([names,...], params,...) -> obj
|
486
|
+
*
|
487
|
+
* Call a function defined in the global scope with the given parameters. An
|
488
|
+
* Array of names can be given to call a function on a nested object.
|
489
|
+
*
|
490
|
+
* ctx.call_prop("parseInt", "42") #=> 42
|
491
|
+
* ctx.call_prop(["Math", "pow"], 2, 10) #=> 1024
|
492
|
+
*
|
493
|
+
*/
|
136
494
|
static VALUE ctx_call_prop(int argc, VALUE* argv, VALUE self)
|
137
495
|
{
|
138
|
-
|
139
|
-
Data_Get_Struct(self,
|
496
|
+
struct state *state;
|
497
|
+
Data_Get_Struct(self, struct state, state);
|
140
498
|
|
141
499
|
VALUE prop;
|
142
500
|
VALUE *prop_args;
|
143
501
|
rb_scan_args(argc, argv, "1*", &prop, &prop_args);
|
144
502
|
|
145
|
-
|
503
|
+
ctx_get_nested_prop(state, prop);
|
146
504
|
|
147
|
-
|
148
|
-
|
505
|
+
// Swap receiver and function
|
506
|
+
duk_swap_top(state->ctx, -2);
|
149
507
|
|
508
|
+
// Push arguments
|
150
509
|
for (int i = 1; i < argc; i++) {
|
151
|
-
|
152
|
-
duk_set_top(ctx, 0);
|
153
|
-
VALUE tmp = rb_inspect(argv[i]);
|
154
|
-
const char *str = StringValueCStr(tmp);
|
155
|
-
rb_raise(eContextError, "unknown object: %s", str);
|
156
|
-
}
|
510
|
+
ctx_push_ruby_object(state, argv[i]);
|
157
511
|
}
|
158
512
|
|
159
|
-
|
160
|
-
|
161
|
-
|
513
|
+
if (duk_pcall_method(state->ctx, (argc - 1)) == DUK_EXEC_ERROR) {
|
514
|
+
raise_ctx_error(state);
|
515
|
+
}
|
516
|
+
|
517
|
+
VALUE res = ctx_stack_to_value(state, -1);
|
518
|
+
duk_set_top(state->ctx, 0);
|
162
519
|
return res;
|
163
520
|
}
|
164
521
|
|
522
|
+
/*
|
523
|
+
* :nodoc:
|
524
|
+
*
|
525
|
+
* Checks that we are in a fine state
|
526
|
+
*/
|
527
|
+
static VALUE ctx_is_valid(VALUE self)
|
528
|
+
{
|
529
|
+
struct state *state;
|
530
|
+
Data_Get_Struct(self, struct state, state);
|
531
|
+
|
532
|
+
if (duk_is_valid_index(state->ctx, -1)) {
|
533
|
+
return Qfalse;
|
534
|
+
} else {
|
535
|
+
return Qtrue;
|
536
|
+
}
|
537
|
+
}
|
538
|
+
|
165
539
|
static void error_handler(duk_context *ctx, int code, const char *msg)
|
166
540
|
{
|
167
|
-
|
168
|
-
|
541
|
+
clean_raise(ctx, error_code_class(code), "%s", msg);
|
542
|
+
}
|
543
|
+
|
544
|
+
VALUE complex_object_instance(VALUE self)
|
545
|
+
{
|
546
|
+
return oComplexObject;
|
547
|
+
}
|
548
|
+
|
549
|
+
/*
|
550
|
+
* call-seq:
|
551
|
+
* Context.new
|
552
|
+
* Context.new(complex_object: obj)
|
553
|
+
*
|
554
|
+
* Returns a new JavaScript evaluation context.
|
555
|
+
*
|
556
|
+
*/
|
557
|
+
static VALUE ctx_initialize(int argc, VALUE *argv, VALUE self)
|
558
|
+
{
|
559
|
+
struct state *state;
|
560
|
+
Data_Get_Struct(self, struct state, state);
|
561
|
+
|
562
|
+
VALUE options;
|
563
|
+
rb_scan_args(argc, argv, ":", &options);
|
564
|
+
if (!NIL_P(options))
|
565
|
+
state->complex_object = rb_hash_lookup2(options, ID2SYM(id_complex_object), state->complex_object);
|
566
|
+
|
567
|
+
return Qnil;
|
568
|
+
}
|
569
|
+
|
570
|
+
/*
|
571
|
+
* call-seq:
|
572
|
+
* complex_object -> obj
|
573
|
+
*
|
574
|
+
* Returns the default complex object, the value that would be returned if a
|
575
|
+
* JavaScript object had no representation in Ruby, such as a JavaScript
|
576
|
+
* Function. See also Context::new.
|
577
|
+
*
|
578
|
+
* ctx.complex_object #=> #<Duktape::ComplexObject>
|
579
|
+
*
|
580
|
+
*/
|
581
|
+
static VALUE ctx_complex_object(VALUE self)
|
582
|
+
{
|
583
|
+
struct state *state;
|
584
|
+
Data_Get_Struct(self, struct state, state);
|
585
|
+
|
586
|
+
return state->complex_object;
|
169
587
|
}
|
170
588
|
|
171
589
|
void Init_duktape_ext()
|
172
590
|
{
|
591
|
+
utf16enc = rb_enc_find("UTF-16LE");
|
592
|
+
id_complex_object = rb_intern("complex_object");
|
593
|
+
|
173
594
|
mDuktape = rb_define_module("Duktape");
|
174
595
|
cContext = rb_define_class_under(mDuktape, "Context", rb_cObject);
|
175
|
-
|
596
|
+
cComplexObject = rb_define_class_under(mDuktape, "ComplexObject", rb_cObject);
|
597
|
+
|
598
|
+
eInternalError = rb_define_class_under(mDuktape, "InternalError", rb_eStandardError);
|
599
|
+
eUnimplementedError = rb_define_class_under(mDuktape, "UnimplementedError", eInternalError);
|
600
|
+
eUnsupportedError = rb_define_class_under(mDuktape, "UnsupportedError", eInternalError);
|
601
|
+
eAllocError = rb_define_class_under(mDuktape, "AllocError", eInternalError);
|
602
|
+
eAssertionError = rb_define_class_under(mDuktape, "AssertionError", eInternalError);
|
603
|
+
eAPIError = rb_define_class_under(mDuktape, "APIError", eInternalError);
|
604
|
+
eUncaughtError = rb_define_class_under(mDuktape, "UncaughtError", eInternalError);
|
605
|
+
|
606
|
+
eError = rb_define_class_under(mDuktape, "Error", rb_eStandardError);
|
607
|
+
eEvalError = rb_define_class_under(mDuktape, "EvalError", eError);
|
608
|
+
eRangeError = rb_define_class_under(mDuktape, "RangeError", eError);
|
609
|
+
eReferenceError = rb_define_class_under(mDuktape, "ReferenceError", eError);
|
610
|
+
eSyntaxError = rb_define_class_under(mDuktape, "SyntaxError", eError);
|
611
|
+
eTypeError = rb_define_class_under(mDuktape, "TypeError", eError);
|
612
|
+
eURIError = rb_define_class_under(mDuktape, "URIError", eError);
|
176
613
|
|
177
614
|
rb_define_alloc_func(cContext, ctx_alloc);
|
178
615
|
|
179
|
-
rb_define_method(cContext, "
|
180
|
-
rb_define_method(cContext, "
|
616
|
+
rb_define_method(cContext, "initialize", ctx_initialize, -1);
|
617
|
+
rb_define_method(cContext, "complex_object", ctx_complex_object, 0);
|
618
|
+
rb_define_method(cContext, "eval_string", ctx_eval_string, -1);
|
619
|
+
rb_define_method(cContext, "exec_string", ctx_exec_string, -1);
|
181
620
|
rb_define_method(cContext, "get_prop", ctx_get_prop, 1);
|
182
621
|
rb_define_method(cContext, "call_prop", ctx_call_prop, -1);
|
622
|
+
rb_define_method(cContext, "_valid?", ctx_is_valid, 0);
|
623
|
+
|
624
|
+
oComplexObject = rb_obj_alloc(cComplexObject);
|
625
|
+
rb_define_singleton_method(cComplexObject, "instance", complex_object_instance, 0);
|
626
|
+
rb_ivar_set(cComplexObject, rb_intern("duktape.instance"), oComplexObject);
|
627
|
+
|
628
|
+
sDefaultFilename = rb_str_new2("(duktape)");
|
629
|
+
OBJ_FREEZE(sDefaultFilename);
|
630
|
+
rb_global_variable(&sDefaultFilename);
|
631
|
+
}
|
632
|
+
|
633
|
+
|
634
|
+
/* UTF8 crap which is not exposed by Ruby */
|
635
|
+
|
636
|
+
static const unsigned long utf8_limits[] = {
|
637
|
+
0x0, /* 1 */
|
638
|
+
0x80, /* 2 */
|
639
|
+
0x800, /* 3 */
|
640
|
+
0x10000, /* 4 */
|
641
|
+
0x200000, /* 5 */
|
642
|
+
0x4000000, /* 6 */
|
643
|
+
0x80000000, /* 7 */
|
644
|
+
};
|
645
|
+
|
646
|
+
static unsigned long
|
647
|
+
utf8_to_uv(const char *p, long *lenp)
|
648
|
+
{
|
649
|
+
int c = *p++ & 0xff;
|
650
|
+
unsigned long uv = c;
|
651
|
+
long n;
|
652
|
+
|
653
|
+
if (!(uv & 0x80)) {
|
654
|
+
*lenp = 1;
|
655
|
+
return uv;
|
656
|
+
}
|
657
|
+
if (!(uv & 0x40)) {
|
658
|
+
*lenp = 1;
|
659
|
+
rb_raise(rb_eArgError, "malformed UTF-8 character");
|
660
|
+
}
|
661
|
+
|
662
|
+
if (!(uv & 0x20)) { n = 2; uv &= 0x1f; }
|
663
|
+
else if (!(uv & 0x10)) { n = 3; uv &= 0x0f; }
|
664
|
+
else if (!(uv & 0x08)) { n = 4; uv &= 0x07; }
|
665
|
+
else if (!(uv & 0x04)) { n = 5; uv &= 0x03; }
|
666
|
+
else if (!(uv & 0x02)) { n = 6; uv &= 0x01; }
|
667
|
+
else {
|
668
|
+
*lenp = 1;
|
669
|
+
rb_raise(rb_eArgError, "malformed UTF-8 character");
|
670
|
+
}
|
671
|
+
if (n > *lenp) {
|
672
|
+
rb_raise(rb_eArgError, "malformed UTF-8 character (expected %ld bytes, given %ld bytes)",
|
673
|
+
n, *lenp);
|
674
|
+
}
|
675
|
+
*lenp = n--;
|
676
|
+
if (n != 0) {
|
677
|
+
while (n--) {
|
678
|
+
c = *p++ & 0xff;
|
679
|
+
if ((c & 0xc0) != 0x80) {
|
680
|
+
*lenp -= n + 1;
|
681
|
+
rb_raise(rb_eArgError, "malformed UTF-8 character");
|
682
|
+
}
|
683
|
+
else {
|
684
|
+
c &= 0x3f;
|
685
|
+
uv = uv << 6 | c;
|
686
|
+
}
|
687
|
+
}
|
688
|
+
}
|
689
|
+
n = *lenp - 1;
|
690
|
+
if (uv < utf8_limits[n]) {
|
691
|
+
rb_raise(rb_eArgError, "redundant UTF-8 sequence");
|
692
|
+
}
|
693
|
+
return uv;
|
183
694
|
}
|