Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 476 lines (366 sloc) 14.597 kB
e18f74d @jbarnette Renaming proxies for clarity.
authored
1 #include "js_land_proxy.h"
dc42336 @matthewd Deal with a couple of minor warnings.
matthewd authored
2 #include "conversions.h"
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
3
4 static JSBool get(JSContext* js_context, JSObject* obj, jsval id, jsval* retval);
5 static JSBool set(JSContext* context, JSObject* obj, jsval id, jsval* retval);
b77b3ad @jbarnette Make sure multiple proxy classes are supported.
authored
6 static JSBool construct(JSContext* js_context, JSObject* obj, uintN argc, jsval* argv, jsval* retval);
6b3683d @jbarnette Make with() work. [#31 state:resolved]
authored
7 static JSBool resolve(JSContext *js_context, JSObject *obj, jsval id, uintN flags, JSObject **objp);
73ad637 @jbarnette Cleaned up proxying of callable (Proc, Method) Ruby objects.
authored
8 static JSBool call(JSContext* js_context, JSObject* obj, uintN argc, jsval* argv, jsval* retval);
b77b3ad @jbarnette Make sure multiple proxy classes are supported.
authored
9 static void finalize(JSContext* context, JSObject* obj);
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
10
510f1b5 @jbarnette Fix some vestigal renaming issues.
authored
11 static JSClass JSLandProxyClass = {
6b3683d @jbarnette Make with() work. [#31 state:resolved]
authored
12 "JSLandProxy", JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE,
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
13 JS_PropertyStub,
14 JS_PropertyStub,
15 get,
16 set,
17 JS_EnumerateStub,
a5d745e @matthewd Make convert_to_js() return a JSBool, to allow error reporting.
matthewd authored
18 (JSResolveOp)resolve,
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
19 JS_ConvertStub,
20 finalize
21 };
22
b77b3ad @jbarnette Make sure multiple proxy classes are supported.
authored
23 static JSClass JSLandClassProxyClass = {
24 "JSLandClassProxy", JSCLASS_HAS_PRIVATE,
25 JS_PropertyStub,
26 JS_PropertyStub,
27 get,
28 set,
29 JS_EnumerateStub,
30 JS_ResolveStub,
31 JS_ConvertStub,
32 finalize,
33 NULL,
34 NULL,
35 NULL,
36 construct
37 };
38
73ad637 @jbarnette Cleaned up proxying of callable (Proc, Method) Ruby objects.
authored
39 static JSClass JSLandCallableProxyClass = {
40 "JSLandCallableProxy", JSCLASS_HAS_PRIVATE,
41 JS_PropertyStub,
42 JS_PropertyStub,
43 JS_PropertyStub,
44 JS_PropertyStub,
45 JS_EnumerateStub,
46 JS_ResolveStub,
47 JS_ConvertStub,
48 finalize,
49 NULL,
50 NULL,
51 call
52 };
53
0746d92 @matthewd Use C99 bool for simple conditionals, and JSBool only for JS engine.
matthewd authored
54 static bool autovivified_p(VALUE ruby_context, VALUE self, char* name)
6b3683d @jbarnette Make with() work. [#31 state:resolved]
authored
55 {
0746d92 @matthewd Use C99 bool for simple conditionals, and JSBool only for JS engine.
matthewd authored
56 return RTEST(rb_funcall(Johnson_SpiderMonkey_JSLandProxy(), rb_intern("autovivified?"), 2,
57 self, rb_str_new2(name)));
6b3683d @jbarnette Make with() work. [#31 state:resolved]
authored
58 }
59
0746d92 @matthewd Use C99 bool for simple conditionals, and JSBool only for JS engine.
matthewd authored
60 static bool const_p(VALUE self, char* name)
6b3683d @jbarnette Make with() work. [#31 state:resolved]
authored
61 {
62 return rb_obj_is_kind_of(self, rb_cModule)
63 && rb_is_const_id(rb_intern(name))
0746d92 @matthewd Use C99 bool for simple conditionals, and JSBool only for JS engine.
matthewd authored
64 && RTEST( rb_funcall(self, rb_intern("const_defined?"), 1, ID2SYM(rb_intern(name))) );
6b3683d @jbarnette Make with() work. [#31 state:resolved]
authored
65 }
66
0746d92 @matthewd Use C99 bool for simple conditionals, and JSBool only for JS engine.
matthewd authored
67 static bool global_p(char* name)
6b3683d @jbarnette Make with() work. [#31 state:resolved]
authored
68 {
69 return rb_ary_includes(rb_f_global_variables(), rb_str_new2(name));
70 }
71
0746d92 @matthewd Use C99 bool for simple conditionals, and JSBool only for JS engine.
matthewd authored
72 static bool method_p(VALUE self, char* name)
6b3683d @jbarnette Make with() work. [#31 state:resolved]
authored
73 {
0746d92 @matthewd Use C99 bool for simple conditionals, and JSBool only for JS engine.
matthewd authored
74 return RTEST( rb_funcall(self, rb_intern("respond_to?"), 1, ID2SYM(rb_intern(name))) );
6b3683d @jbarnette Make with() work. [#31 state:resolved]
authored
75 }
76
0746d92 @matthewd Use C99 bool for simple conditionals, and JSBool only for JS engine.
matthewd authored
77 static bool attribute_p(VALUE self, char* name)
b7616dd @jbarnette Reimplement property and method access. Mostly.
authored
78 {
79 if (!method_p(self, name))
0746d92 @matthewd Use C99 bool for simple conditionals, and JSBool only for JS engine.
matthewd authored
80 return false;
b7616dd @jbarnette Reimplement property and method access. Mostly.
authored
81
82 VALUE rb_id = rb_intern(name);
83 VALUE rb_method = rb_funcall(self, rb_intern("method"), 1, ID2SYM(rb_id));
84
85 METHOD* method;
86 Data_Get_Struct(rb_method, METHOD, method);
87
88 return nd_type(method->body) == NODE_IVAR
0746d92 @matthewd Use C99 bool for simple conditionals, and JSBool only for JS engine.
matthewd authored
89 || RTEST(rb_funcall(Johnson_SpiderMonkey_JSLandProxy(),
90 rb_intern("js_property?"), 2, self, ID2SYM(rb_id)));
b7616dd @jbarnette Reimplement property and method access. Mostly.
authored
91 }
92
0746d92 @matthewd Use C99 bool for simple conditionals, and JSBool only for JS engine.
matthewd authored
93 static bool indexable_p(VALUE self)
e0d5bf2 @jbarnette Simple implementation for working numeric array indexes.
authored
94 {
0746d92 @matthewd Use C99 bool for simple conditionals, and JSBool only for JS engine.
matthewd authored
95 return RTEST(rb_funcall(self, rb_intern("respond_to?"), 1, ID2SYM(rb_intern("[]"))));
e0d5bf2 @jbarnette Simple implementation for working numeric array indexes.
authored
96 }
97
0746d92 @matthewd Use C99 bool for simple conditionals, and JSBool only for JS engine.
matthewd authored
98 static bool has_key_p(VALUE self, char* name)
6b3683d @jbarnette Make with() work. [#31 state:resolved]
authored
99 {
0746d92 @matthewd Use C99 bool for simple conditionals, and JSBool only for JS engine.
matthewd authored
100 return RTEST(rb_funcall(self, rb_intern("respond_to?"), 1, ID2SYM(rb_intern("[]"))))
101 && RTEST(rb_funcall(self, rb_intern("respond_to?"), 1, ID2SYM(rb_intern("key?"))))
102 && RTEST(rb_funcall(self, rb_intern("key?"), 1, rb_str_new2(name)));
6b3683d @jbarnette Make with() work. [#31 state:resolved]
authored
103 }
104
0746d92 @matthewd Use C99 bool for simple conditionals, and JSBool only for JS engine.
matthewd authored
105 static bool respond_to_p(JSContext* js_context, JSObject* obj, char* name)
6b3683d @jbarnette Make with() work. [#31 state:resolved]
authored
106 {
107 VALUE ruby_context;
108 assert(ruby_context = (VALUE)JS_GetContextPrivate(js_context));
109
110 OurContext* context;
111 Data_Get_Struct(ruby_context, OurContext, context);
112
113 VALUE self;
114
115 assert(self = (VALUE)JS_GetInstancePrivate(
116 context->js, obj, JS_GET_CLASS(context->js, obj), NULL));
117
118 return autovivified_p(ruby_context, self, name)
119 || const_p(self, name)
120 || global_p(name)
b7616dd @jbarnette Reimplement property and method access. Mostly.
authored
121 || attribute_p(self, name)
6b3683d @jbarnette Make with() work. [#31 state:resolved]
authored
122 || method_p(self, name)
123 || has_key_p(self, name);
124 }
125
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
126 static JSBool get(JSContext* js_context, JSObject* obj, jsval id, jsval* retval)
127 {
6b3683d @jbarnette Make with() work. [#31 state:resolved]
authored
128 // pull out our Ruby context, which is embedded in js_context
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
129
130 VALUE ruby_context;
131 assert(ruby_context = (VALUE)JS_GetContextPrivate(js_context));
132
133 // get our struct, which is embedded in ruby_context
134
135 OurContext* context;
136 Data_Get_Struct(ruby_context, OurContext, context);
137
138 // get the Ruby object that backs this proxy
139
140 VALUE self;
109858e @jbarnette Make JSLandProxyClass more easily parameterizable.
authored
141 assert(self = (VALUE)JS_GetInstancePrivate(context->js, obj, JS_GET_CLASS(context->js, obj), NULL));
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
142
e0d5bf2 @jbarnette Simple implementation for working numeric array indexes.
authored
143 // Short-circuit for numeric indexes
144
145 if (JSVAL_IS_INT(id))
146 {
147 if (indexable_p(self))
a5d745e @matthewd Make convert_to_js() return a JSBool, to allow error reporting.
matthewd authored
148 return convert_to_js(context,
149 rb_funcall(self, rb_intern("[]"), 1, INT2FIX(JSVAL_TO_INT(id))), retval);
e0d5bf2 @jbarnette Simple implementation for working numeric array indexes.
authored
150
151 return JS_TRUE;
152 }
153
6b3683d @jbarnette Make with() work. [#31 state:resolved]
authored
154 char* name = JS_GetStringBytes(JSVAL_TO_STRING(id));
155 VALUE ruby_id = rb_intern(name);
156
d45a2d5 @jbarnette Added some notes for the future.
authored
157 // FIXME: this is necessarily ugly. Maybe we should write something like
158 // jsval foo = property_expression(context->js, context->global, "Johnson.Generator.create")
159 // this would make the code where we look up Johnson.Symbol cleaner too (in conversions.c)
160
161 // FIXME: we should probably just JS_DefineProperty this, and it shouldn't be enumerable
162
b7616dd @jbarnette Reimplement property and method access. Mostly.
authored
163 if (!strcasecmp("__iterator__", name)) {
576e1fe #28 #23 arrays work in js land and so does for .. in
Aaron Patterson authored
164 jsval nsJohnson;
165 assert(JS_GetProperty(context->js, context->global, "Johnson", &nsJohnson) || JSVAL_VOID == nsJohnson);
166
167 jsval nsGenerator;
168 assert(JS_GetProperty(context->js, JSVAL_TO_OBJECT(nsJohnson), "Generator", &nsGenerator) || JSVAL_VOID == nsGenerator);
169
170 jsval create;
171 assert(JS_GetProperty(context->js, JSVAL_TO_OBJECT(nsGenerator), "create", &create) || JSVAL_VOID == create);
172 *retval = create;
173 return JS_TRUE;
174 }
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
175
204c021 switching to hash based dynamic properties
Aaron Patterson authored
176 // if the Ruby object has a dynamic js property with a key
177 // matching the property we're looking for, pull the value out of
178 // that map.
78f8bf9 @jbarnette Naming and formatting nitpicks.
authored
179
b7616dd @jbarnette Reimplement property and method access. Mostly.
authored
180 else if (autovivified_p(ruby_context, self, name))
204c021 switching to hash based dynamic properties
Aaron Patterson authored
181 {
a5d745e @matthewd Make convert_to_js() return a JSBool, to allow error reporting.
matthewd authored
182 return convert_to_js(context,
b7616dd @jbarnette Reimplement property and method access. Mostly.
authored
183 rb_funcall(Johnson_SpiderMonkey_JSLandProxy(),
a5d745e @matthewd Make convert_to_js() return a JSBool, to allow error reporting.
matthewd authored
184 rb_intern("autovivified"), 2, self, rb_str_new2(name)), retval);
204c021 switching to hash based dynamic properties
Aaron Patterson authored
185 }
186
5ccbbfa Constants can be accessed as properties in JSLand.
jbarnette authored
187 // if the Ruby object is a Module or Class and has a matching
188 // const defined, return the converted result of const_get
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
189
6b3683d @jbarnette Make with() work. [#31 state:resolved]
authored
190 else if (const_p(self, name))
5ccbbfa Constants can be accessed as properties in JSLand.
jbarnette authored
191 {
a5d745e @matthewd Make convert_to_js() return a JSBool, to allow error reporting.
matthewd authored
192 return convert_to_js(context,
193 rb_funcall(self, rb_intern("const_get"), 1, ID2SYM(ruby_id)), retval);
5ccbbfa Constants can be accessed as properties in JSLand.
jbarnette authored
194 }
1f9f150 @tenderlove giving spidermonkey access to ruby constants
tenderlove authored
195
6b3683d @jbarnette Make with() work. [#31 state:resolved]
authored
196 // otherwise, if it's a global, return the global
197 else if (global_p(name))
1f9f150 @tenderlove giving spidermonkey access to ruby constants
tenderlove authored
198 {
a5d745e @matthewd Make convert_to_js() return a JSBool, to allow error reporting.
matthewd authored
199 return convert_to_js(context, rb_gv_get(name), retval);
1f9f150 @tenderlove giving spidermonkey access to ruby constants
tenderlove authored
200 }
5ccbbfa Constants can be accessed as properties in JSLand.
jbarnette authored
201
b7616dd @jbarnette Reimplement property and method access. Mostly.
authored
202 // otherwise, if the Ruby object has a an attribute method matching
5ccbbfa Constants can be accessed as properties in JSLand.
jbarnette authored
203 // the property we're trying to get, call it and return the converted result
204
b7616dd @jbarnette Reimplement property and method access. Mostly.
authored
205 else if (attribute_p(self, name))
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
206 {
a5d745e @matthewd Make convert_to_js() return a JSBool, to allow error reporting.
matthewd authored
207 return convert_to_js(context, rb_funcall(self, ruby_id, 0), retval);
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
208 }
5ccbbfa Constants can be accessed as properties in JSLand.
jbarnette authored
209
6b3683d @jbarnette Make with() work. [#31 state:resolved]
authored
210 // otherwise, if the Ruby object quacks sorta like a hash (it responds to
211 // "[]" and "key?"), index it by key and return the converted result
212
213 else if (has_key_p(self, name))
214 {
a5d745e @matthewd Make convert_to_js() return a JSBool, to allow error reporting.
matthewd authored
215 return convert_to_js(context, rb_funcall(self, rb_intern("[]"), 1, rb_str_new2(name)), retval);
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
216 }
217
b7616dd @jbarnette Reimplement property and method access. Mostly.
authored
218 // otherwise, it's a method being accessed as a property, which means
219 // we need to return a lambda
220
cfcba6d @jbarnette Added a few more FIXMEs.
authored
221 // FIXME: this should really wrap the Method for 'name' in a JS class
222 // rather than generating a wrapper Proc
223
b7616dd @jbarnette Reimplement property and method access. Mostly.
authored
224 else if (method_p(self, name))
225 {
a5d745e @matthewd Make convert_to_js() return a JSBool, to allow error reporting.
matthewd authored
226 convert_to_js(context,
227 rb_funcall(self, rb_intern("method"), 1, rb_str_new2(name)), retval);
b7616dd @jbarnette Reimplement property and method access. Mostly.
authored
228 }
229
230 // else it's undefined (JS_VOID) by default
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
231 return JS_TRUE;
232 }
233
6b3683d @jbarnette Make with() work. [#31 state:resolved]
authored
234 // called for lazily resolved properties, which should go away
235 static JSBool get_and_destroy_resolved_property(
236 JSContext* js_context, JSObject* obj, jsval id, jsval* retval)
237 {
238 char* name = JS_GetStringBytes(JSVAL_TO_STRING(id));
239 JS_DeleteProperty(js_context, obj, name);
240 return get(js_context, obj, id, retval);
241 }
242
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
243 static JSBool set(JSContext* js_context, JSObject* obj, jsval id, jsval* value)
244 {
245 VALUE ruby_context;
246 assert(ruby_context = (VALUE)JS_GetContextPrivate(js_context));
247
248 OurContext* context;
249 Data_Get_Struct(ruby_context, OurContext, context);
250
251 VALUE self;
109858e @jbarnette Make JSLandProxyClass more easily parameterizable.
authored
252 assert(self = (VALUE)JS_GetInstancePrivate(context->js, obj, JS_GET_CLASS(context->js, obj), NULL));
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
253
e0d5bf2 @jbarnette Simple implementation for working numeric array indexes.
authored
254 // Short-circuit for numeric indexes
255
256 if (JSVAL_IS_INT(id))
257 {
258 if (indexable_p(self))
259 rb_funcall(self, rb_intern("[]="),
260 2, INT2FIX(JSVAL_TO_INT(id)), convert_to_ruby(context, *value));
261
262 return JS_TRUE;
263 }
264
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
265 char* key = JS_GetStringBytes(JSVAL_TO_STRING(id));
266 VALUE ruby_key = rb_str_new2(key);
267
268 VALUE setter = rb_str_append(rb_str_new3(ruby_key), rb_str_new2("="));
269 VALUE setter_id = rb_intern(StringValuePtr(setter));
270
46ffbc1 @jbarnette JSland proxies of Ruby classes have working constructors. [#29 state:…
authored
271 VALUE settable_p = rb_funcall(self, rb_intern("respond_to?"), 1, ID2SYM(setter_id));
272 VALUE indexable_p = rb_funcall(self, rb_intern("respond_to?"), 1, ID2SYM(rb_intern("[]=")));
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
273
46ffbc1 @jbarnette JSland proxies of Ruby classes have working constructors. [#29 state:…
authored
274 if (settable_p)
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
275 {
276 VALUE method = rb_funcall(self, rb_intern("method"), 1, ID2SYM(setter_id));
277 int arity = NUM2INT(rb_funcall(method, rb_intern("arity"), 0));
278
279 // if the Ruby object has a 1-arity method named "property=",
280 // call it with the converted value
281
282 if (arity == 1)
283 rb_funcall(self, setter_id, 1, convert_to_ruby(context, *value));
284 }
46ffbc1 @jbarnette JSland proxies of Ruby classes have working constructors. [#29 state:…
authored
285 else if(indexable_p)
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
286 {
287 // otherwise, if the Ruby object quacks sorta like a hash for assignment
288 // (it responds to "[]="), assign it by key
289
7329bb5 autovivifying attributes from js land
Aaron Patterson authored
290 rb_funcall(self, rb_intern("[]="), 2, ruby_key, convert_to_ruby(context, *value));
78f8bf9 @jbarnette Naming and formatting nitpicks.
authored
291 }
292 else
293 {
b7616dd @jbarnette Reimplement property and method access. Mostly.
authored
294 rb_funcall(Johnson_SpiderMonkey_JSLandProxy(), rb_intern("autovivify"),
295 3, self, ruby_key, convert_to_ruby(context, *value));
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
296 }
297
298 return JS_TRUE;
299 }
300
b77b3ad @jbarnette Make sure multiple proxy classes are supported.
authored
301 static JSBool construct(JSContext* js_context, JSObject* obj, uintN argc, jsval* argv, jsval* retval)
302 {
46ffbc1 @jbarnette JSland proxies of Ruby classes have working constructors. [#29 state:…
authored
303 VALUE ruby_context;
304 assert(ruby_context = (VALUE)JS_GetContextPrivate(js_context));
305
306 OurContext* context;
307 Data_Get_Struct(ruby_context, OurContext, context);
308
309 VALUE klass = convert_to_ruby(context, JS_ARGV_CALLEE(argv));
310 VALUE args = rb_ary_new();
311
312 int i;
313
314 for (i = 0; i < argc; ++i)
315 rb_ary_push(args, convert_to_ruby(context, argv[i]));
316
a5d745e @matthewd Make convert_to_js() return a JSBool, to allow error reporting.
matthewd authored
317 return convert_to_js(context,
b7616dd @jbarnette Reimplement property and method access. Mostly.
authored
318 rb_funcall(Johnson_SpiderMonkey_JSLandProxy(), rb_intern("send_with_possible_block"),
a5d745e @matthewd Make convert_to_js() return a JSBool, to allow error reporting.
matthewd authored
319 3, klass, ID2SYM(rb_intern("new")), args), retval);
b77b3ad @jbarnette Make sure multiple proxy classes are supported.
authored
320 }
321
6b3683d @jbarnette Make with() work. [#31 state:resolved]
authored
322 static JSBool resolve(JSContext *js_context, JSObject *obj, jsval id, uintN flags, JSObject **objp)
323 {
324 VALUE ruby_context;
325 assert(ruby_context = (VALUE)JS_GetContextPrivate(js_context));
326
327 OurContext* context;
328 Data_Get_Struct(ruby_context, OurContext, context);
329
330 char* name = JS_GetStringBytes(JS_ValueToString(js_context, id));
331
332 if (respond_to_p(js_context, obj, name))
333 {
b7616dd @jbarnette Reimplement property and method access. Mostly.
authored
334 assert(JS_DefineProperty(js_context, obj, name, JSVAL_VOID,
6b3683d @jbarnette Make with() work. [#31 state:resolved]
authored
335 get_and_destroy_resolved_property, set, JSPROP_ENUMERATE));
336
337 *objp = obj;
338 }
339
340 return JS_TRUE;
341 }
342
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
343 static JSBool method_missing(JSContext* js_context, JSObject* obj, uintN argc, jsval* argv, jsval* retval)
344 {
345 VALUE ruby_context;
346 assert(ruby_context = (VALUE)JS_GetContextPrivate(js_context));
347
348 OurContext* context;
349 Data_Get_Struct(ruby_context, OurContext, context);
350
351 VALUE self;
109858e @jbarnette Make JSLandProxyClass more easily parameterizable.
authored
352 assert(self = (VALUE)JS_GetInstancePrivate(context->js, obj, JS_GET_CLASS(context->js, obj), NULL));
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
353
354 char* key = JS_GetStringBytes(JSVAL_TO_STRING(argv[0]));
355 VALUE ruby_id = rb_intern(key);
356
78f8bf9 @jbarnette Naming and formatting nitpicks.
authored
357 // FIXME: this is horrible and lazy, to_a comes from enumerable on proxy (argv[1] is a JSArray)
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
358 VALUE args = rb_funcall(convert_to_ruby(context, argv[1]), rb_intern("to_a"), 0);
359
a5d745e @matthewd Make convert_to_js() return a JSBool, to allow error reporting.
matthewd authored
360 return convert_to_js(context,
b7616dd @jbarnette Reimplement property and method access. Mostly.
authored
361 rb_funcall(Johnson_SpiderMonkey_JSLandProxy(), rb_intern("send_with_possible_block"),
a5d745e @matthewd Make convert_to_js() return a JSBool, to allow error reporting.
matthewd authored
362 3, self, ID2SYM(ruby_id), args), retval);
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
363 }
364
73ad637 @jbarnette Cleaned up proxying of callable (Proc, Method) Ruby objects.
authored
365 static JSBool call(JSContext* js_context, JSObject* obj, uintN argc, jsval* argv, jsval* retval)
366 {
367 VALUE ruby_context;
368 assert(ruby_context = (VALUE)JS_GetContextPrivate(js_context));
369
370 OurContext* context;
371 Data_Get_Struct(ruby_context, OurContext, context);
372
373 VALUE self;// = convert_to_ruby(context, JS_ARGV_CALLEE(argv));
374 assert(self = (VALUE)JS_GetInstancePrivate(context->js, JSVAL_TO_OBJECT(JS_ARGV_CALLEE(argv)), &JSLandCallableProxyClass, NULL));
375
376 VALUE args = rb_ary_new();
377 int i;
378
379 for (i = 0; i < argc; ++i)
380 rb_ary_push(args, convert_to_ruby(context, argv[i]));
381
a5d745e @matthewd Make convert_to_js() return a JSBool, to allow error reporting.
matthewd authored
382 return convert_to_js(context,
73ad637 @jbarnette Cleaned up proxying of callable (Proc, Method) Ruby objects.
authored
383 rb_funcall(Johnson_SpiderMonkey_JSLandProxy(), rb_intern("send_with_possible_block"),
a5d745e @matthewd Make convert_to_js() return a JSBool, to allow error reporting.
matthewd authored
384 3, self, ID2SYM(rb_intern("call")), args), retval);
73ad637 @jbarnette Cleaned up proxying of callable (Proc, Method) Ruby objects.
authored
385 }
386
0746d92 @matthewd Use C99 bool for simple conditionals, and JSBool only for JS engine.
matthewd authored
387 bool js_value_is_proxy(OurContext* context, jsval maybe_proxy)
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
388 {
b77b3ad @jbarnette Make sure multiple proxy classes are supported.
authored
389 JSClass* klass = JS_GET_CLASS(context->js, JSVAL_TO_OBJECT(maybe_proxy));
73ad637 @jbarnette Cleaned up proxying of callable (Proc, Method) Ruby objects.
authored
390
391 return &JSLandProxyClass == klass
392 || &JSLandClassProxyClass == klass
393 || &JSLandCallableProxyClass == klass;
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
394 }
395
e18f74d @jbarnette Renaming proxies for clarity.
authored
396 VALUE unwrap_js_land_proxy(OurContext* context, jsval proxy)
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
397 {
01b0682 @jbarnette JS proxies roundtrip.
authored
398 VALUE value;
109858e @jbarnette Make JSLandProxyClass more easily parameterizable.
authored
399 JSObject *proxy_object = JSVAL_TO_OBJECT(proxy);
400
401 assert(value = (VALUE)JS_GetInstancePrivate(context->js, proxy_object,
402 JS_GET_CLASS(context->js, proxy_object), NULL));
403
f0cc336 js proxies roundtrip correctly. still no gc root.
jbarnette authored
404 return value;
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
405 }
406
3c24fe9 Fixed Ruby value tracking/GC rooting.
jbarnette authored
407 static void finalize(JSContext* js_context, JSObject* obj)
408 {
409 VALUE ruby_context = (VALUE)JS_GetContextPrivate(js_context);
410
411 if (ruby_context)
412 {
413 OurContext* context;
414 Data_Get_Struct(ruby_context, OurContext, context);
415
416 VALUE self;
109858e @jbarnette Make JSLandProxyClass more easily parameterizable.
authored
417 assert(self = (VALUE)JS_GetInstancePrivate(context->js, obj,
418 JS_GET_CLASS(context->js, obj), NULL));
3c24fe9 Fixed Ruby value tracking/GC rooting.
jbarnette authored
419
420 // remove the proxy OID from the id map
421 JS_HashTableRemove(context->rbids, (void *)rb_obj_id(self));
422
423 // free up the ruby value for GC
424 rb_funcall(ruby_context, rb_intern("remove_gcthing"), 1, self);
425 }
426 }
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
427
9149af0 @matthewd More JSBool conversions.
matthewd authored
428 JSBool make_js_land_proxy(OurContext* context, VALUE value, jsval* retval)
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
429 {
3c24fe9 Fixed Ruby value tracking/GC rooting.
jbarnette authored
430 jsid id = (jsid)JS_HashTableLookup(context->rbids, (void *)rb_obj_id(value));
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
431
3c24fe9 Fixed Ruby value tracking/GC rooting.
jbarnette authored
432 if (id)
433 {
9149af0 @matthewd More JSBool conversions.
matthewd authored
434 return JS_IdToValue(context->js, id, retval);
3c24fe9 Fixed Ruby value tracking/GC rooting.
jbarnette authored
435 }
436 else
437 {
438 JSObject *jsobj;
b77b3ad @jbarnette Make sure multiple proxy classes are supported.
authored
439
440 JSClass *klass = &JSLandProxyClass;
441 if (T_CLASS == TYPE(value)) klass = &JSLandClassProxyClass;
442
73ad637 @jbarnette Cleaned up proxying of callable (Proc, Method) Ruby objects.
authored
443 // FIXME: hack; should happen in Rubyland
b7616dd @jbarnette Reimplement property and method access. Mostly.
authored
444 if (T_STRUCT == TYPE(value))
445 rb_funcall(Johnson_SpiderMonkey_JSLandProxy(),
446 rb_intern("treat_all_properties_as_methods"), 1, value);
73ad637 @jbarnette Cleaned up proxying of callable (Proc, Method) Ruby objects.
authored
447
0746d92 @matthewd Use C99 bool for simple conditionals, and JSBool only for JS engine.
matthewd authored
448 bool callable_p = rb_class_of(value) == rb_cMethod
73ad637 @jbarnette Cleaned up proxying of callable (Proc, Method) Ruby objects.
authored
449 || rb_class_of(value) == rb_cProc;
b7616dd @jbarnette Reimplement property and method access. Mostly.
authored
450
73ad637 @jbarnette Cleaned up proxying of callable (Proc, Method) Ruby objects.
authored
451 if (callable_p)
452 klass = &JSLandCallableProxyClass;
453
b77b3ad @jbarnette Make sure multiple proxy classes are supported.
authored
454 assert(jsobj = JS_NewObject(context->js, klass, NULL, NULL));
3c24fe9 Fixed Ruby value tracking/GC rooting.
jbarnette authored
455 assert(JS_SetPrivate(context->js, jsobj, (void*)value));
576e1fe #28 #23 arrays work in js land and so does for .. in
Aaron Patterson authored
456
73ad637 @jbarnette Cleaned up proxying of callable (Proc, Method) Ruby objects.
authored
457 if (!callable_p)
458 assert(JS_DefineFunction(context->js, jsobj,
459 "__noSuchMethod__", method_missing, 2, 0));
3c24fe9 Fixed Ruby value tracking/GC rooting.
jbarnette authored
460
9149af0 @matthewd More JSBool conversions.
matthewd authored
461 *retval = OBJECT_TO_JSVAL(jsobj);
3c24fe9 Fixed Ruby value tracking/GC rooting.
jbarnette authored
462
463 jsval newid;
9149af0 @matthewd More JSBool conversions.
matthewd authored
464 assert(JS_ValueToId(context->js, *retval, &newid));
3c24fe9 Fixed Ruby value tracking/GC rooting.
jbarnette authored
465
466 // put the proxy OID in the id map
467 assert(JS_HashTableAdd(context->rbids, (void *)rb_obj_id(value), (void *)newid));
468
469 // root the ruby value for GC
470 VALUE ruby_context = (VALUE)JS_GetContextPrivate(context->js);
471 rb_funcall(ruby_context, rb_intern("add_gcthing"), 1, value);
9149af0 @matthewd More JSBool conversions.
matthewd authored
472
473 return JS_TRUE;
3c24fe9 Fixed Ruby value tracking/GC rooting.
jbarnette authored
474 }
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
475 }
Something went wrong with that request. Please try again.