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.
@@ -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 eContextError;
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 *ctx)
45
+ static void ctx_dealloc(void *ptr)
10
46
  {
11
- duk_destroy_heap((duk_context *)ctx);
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
- return Data_Wrap_Struct(klass, NULL, ctx_dealloc, ctx);
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(duk_context *ctx, int index)
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
- return rb_str_new(buf, len);
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
- rb_raise(eContextError, "cannot convert complex object");
237
+ return state->complex_object;
47
238
  }
48
239
 
49
240
  return Qnil;
50
241
  }
51
242
 
52
- static int ctx_push_ruby_object(duk_context *ctx, VALUE obj)
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
- break;
252
+ return;
58
253
 
59
254
  case T_FLOAT:
60
255
  duk_push_number(ctx, NUM2DBL(obj));
61
- break;
256
+ return;
62
257
 
63
258
  case T_STRING:
64
- duk_push_lstring(ctx, RSTRING_PTR(obj), RSTRING_LEN(obj));
65
- break;
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
- break;
265
+ return;
70
266
 
71
267
  case T_FALSE:
72
268
  duk_push_false(ctx);
73
- break;
269
+ return;
74
270
 
75
271
  case T_NIL:
76
272
  duk_push_null(ctx);
77
- break;
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
- return 0;
290
+ break;
82
291
  }
83
292
 
84
- // Everything is fine
85
- return 1;
293
+ clean_raise(ctx, rb_eTypeError, "cannot convert %s", rb_obj_classname(obj));
86
294
  }
87
295
 
88
- static VALUE ctx_eval_string(VALUE self, VALUE source, VALUE filename)
296
+ static int ctx_push_hash_element(VALUE key, VALUE val, VALUE extra)
89
297
  {
90
- duk_context *ctx;
91
- Data_Get_Struct(self, duk_context, ctx);
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
- duk_push_lstring(ctx, RSTRING_PTR(source), RSTRING_LEN(source));
94
- duk_push_lstring(ctx, RSTRING_PTR(filename), RSTRING_LEN(filename));
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 res = ctx_stack_to_value(ctx, -1);
99
- duk_set_top(ctx, 0);
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
- static VALUE ctx_exec_string(VALUE self, VALUE source, VALUE filename)
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
- duk_context *ctx;
106
- Data_Get_Struct(self, duk_context, ctx);
378
+ struct state *state;
379
+ Data_Get_Struct(self, struct state, state);
107
380
 
108
- duk_push_lstring(ctx, RSTRING_PTR(source), RSTRING_LEN(source));
109
- duk_push_lstring(ctx, RSTRING_PTR(filename), RSTRING_LEN(filename));
110
- duk_compile(ctx, 0);
111
- duk_call(ctx, 0);
112
- duk_set_top(ctx, 0);
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 VALUE ctx_get_prop(VALUE self, VALUE prop)
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
- Check_Type(prop, T_STRING);
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
- duk_push_global_object(ctx);
124
- duk_push_lstring(ctx, RSTRING_PTR(prop), RSTRING_LEN(prop));
125
- if (!duk_get_prop(ctx, -2)) {
126
- duk_set_top(ctx, 0);
127
- const char *str = StringValueCStr(prop);
128
- rb_raise(eContextError, "no such prop: %s", str);
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
- VALUE res = ctx_stack_to_value(ctx, -1);
132
- duk_set_top(ctx, 0);
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
- duk_context *ctx;
139
- Data_Get_Struct(self, duk_context, ctx);
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
- Check_Type(prop, T_STRING);
503
+ ctx_get_nested_prop(state, prop);
146
504
 
147
- duk_push_global_object(ctx);
148
- duk_push_lstring(ctx, RSTRING_PTR(prop), RSTRING_LEN(prop));
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
- if (!ctx_push_ruby_object(ctx, argv[i])) {
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
- duk_call_prop(ctx, -(argc + 1), (argc - 1));
160
- VALUE res = ctx_stack_to_value(ctx, -1);
161
- duk_set_top(ctx, 0);
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
- duk_set_top(ctx, 0);
168
- rb_raise(eContextError, "fatal duktape error: %s (%d)", msg, code);
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
- eContextError = rb_define_class_under(mDuktape, "ContextError", rb_eStandardError);
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, "eval_string", ctx_eval_string, 2);
180
- rb_define_method(cContext, "exec_string", ctx_exec_string, 2);
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
  }