duktape 1.0.2.0 → 1.1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
  }