Add support for NamedConstructor in webidls

This commit is contained in:
Joel Teichroeb 2015-05-17 23:47:15 +00:00
parent 3e90a60170
commit 012be81eab
2 changed files with 107 additions and 28 deletions

View file

@ -2286,11 +2286,25 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
call = """\ call = """\
do_create_interface_objects(cx, receiver, parent_proto.handle(), do_create_interface_objects(cx, receiver, parent_proto.handle(),
%s, %s, %s, %s,
&named_constructors,
%s, %s,
&sNativeProperties, rval);""" % (protoClass, constructor, domClass) &sNativeProperties, rval);""" % (protoClass, constructor, domClass)
createArray = """\
let named_constructors: [(NonNullJSNative, &'static str, u32); %d] = [
""" % len(self.descriptor.interface.namedConstructors)
for ctor in self.descriptor.interface.namedConstructors:
constructHook = CONSTRUCT_HOOK_NAME + "_" + ctor.identifier.name;
constructArgs = methodLength(ctor)
constructor = '(%s as NonNullJSNative, "%s", %d)' % (
constructHook, ctor.identifier.name, constructArgs)
createArray += constructor
createArray += ","
createArray += "];"
return CGList([ return CGList([
CGGeneric(getParentProto), CGGeneric(getParentProto),
CGGeneric(createArray),
CGGeneric(call % self.properties.variableNames()) CGGeneric(call % self.properties.variableNames())
], "\n") ], "\n")
@ -4422,6 +4436,30 @@ let args = CallArgs::from_vp(vp, argc);
self.descriptor, self._ctor) self.descriptor, self._ctor)
return CGList([preamble, callGenerator]) return CGList([preamble, callGenerator])
class CGClassNameConstructHook(CGAbstractExternMethod):
"""
JS-visible named constructor for our objects
"""
def __init__(self, descriptor, ctor):
args = [Argument('*mut JSContext', 'cx'), Argument('u32', 'argc'), Argument('*mut JSVal', 'vp')]
self._ctor = ctor
CGAbstractExternMethod.__init__(self, descriptor,
CONSTRUCT_HOOK_NAME + "_" +
self._ctor.identifier.name,
'u8', args)
def definition_body(self):
preamble = CGGeneric("""\
let global = global_object_for_js_object(JS_CALLEE(cx, vp).to_object());
let args = CallArgs::from_vp(vp, argc);
""")
name = self._ctor.identifier.name
nativeName = MakeNativeName(self.descriptor.binaryNameFor(name))
callGenerator = CGMethodCall(["global.r()"], nativeName, True,
self.descriptor, self._ctor)
return CGList([preamble, callGenerator])
class CGClassFinalizeHook(CGAbstractClassHook): class CGClassFinalizeHook(CGAbstractClassHook):
""" """
A hook for finalize, used to release our native object. A hook for finalize, used to release our native object.
@ -4568,6 +4606,8 @@ class CGDescriptor(CGThing):
if descriptor.interface.hasInterfaceObject(): if descriptor.interface.hasInterfaceObject():
cgThings.append(CGClassConstructHook(descriptor)) cgThings.append(CGClassConstructHook(descriptor))
for ctor in descriptor.interface.namedConstructors:
cgThings.append(CGClassNameConstructHook(descriptor, ctor))
cgThings.append(CGInterfaceObjectJSClass(descriptor)) cgThings.append(CGInterfaceObjectJSClass(descriptor))
if not descriptor.interface.isCallback(): if not descriptor.interface.isCallback():

View file

@ -205,6 +205,7 @@ pub fn do_create_interface_objects(cx: *mut JSContext,
proto_proto: HandleObject, proto_proto: HandleObject,
proto_class: Option<&'static JSClass>, proto_class: Option<&'static JSClass>,
constructor: Option<(NonNullJSNative, &'static str, u32)>, constructor: Option<(NonNullJSNative, &'static str, u32)>,
named_constructors: &[(NonNullJSNative, &'static str, u32)],
dom_class: *const DOMClass, dom_class: *const DOMClass,
members: &'static NativeProperties, members: &'static NativeProperties,
rval: MutableHandleObject) { rval: MutableHandleObject) {
@ -226,6 +227,55 @@ pub fn do_create_interface_objects(cx: *mut JSContext,
native, nargs, rval.handle(), native, nargs, rval.handle(),
members, s.as_ptr()) members, s.as_ptr())
} }
for ctor in named_constructors.iter() {
let (cnative, cname, cnargs) = *ctor;
let cs = CString::new(cname).unwrap();
let constructor = RootedObject::new(cx, create_constructor(cx, cnative, cnargs, cs.as_ptr()));
assert!(!constructor.ptr.is_null());
unsafe {
assert!(JS_DefineProperty1(cx, constructor.handle(), "prototype".as_ptr() as *const i8,
rval.handle(),
JSPROP_PERMANENT | JSPROP_READONLY,
None, None) != 0);
}
define_constructor(cx, receiver, cs.as_ptr(), constructor.handle());
}
}
fn create_constructor(cx: *mut JSContext,
constructor_native: NonNullJSNative,
ctor_nargs: u32,
name: *const libc::c_char) -> *mut JSObject {
unsafe {
let fun = JS_NewFunction(cx, Some(constructor_native), ctor_nargs,
JSFUN_CONSTRUCTOR, name);
assert!(!fun.is_null());
let constructor = JS_GetFunctionObject(fun);
assert!(!constructor.is_null());
constructor
}
}
fn define_constructor(cx: *mut JSContext,
receiver: HandleObject,
name: *const libc::c_char,
constructor: HandleObject) {
unsafe {
let mut already_defined = 0;
assert!(JS_AlreadyHasOwnProperty(cx, receiver, name, &mut already_defined) != 0);
if already_defined == 0 {
assert!(JS_DefineProperty1(cx, receiver, name,
constructor,
0, None, None) != 0);
}
}
} }
/// Creates the *interface object*. /// Creates the *interface object*.
@ -236,12 +286,7 @@ fn create_interface_object(cx: *mut JSContext,
ctor_nargs: u32, proto: HandleObject, ctor_nargs: u32, proto: HandleObject,
members: &'static NativeProperties, members: &'static NativeProperties,
name: *const libc::c_char) { name: *const libc::c_char) {
unsafe { let constructor = RootedObject::new(cx, create_constructor(cx, constructor_native, ctor_nargs, name));
let fun = JS_NewFunction(cx, Some(constructor_native), ctor_nargs,
JSFUN_CONSTRUCTOR, name);
assert!(!fun.is_null());
let constructor = RootedObject::new(cx, JS_GetFunctionObject(fun));
assert!(!constructor.ptr.is_null()); assert!(!constructor.ptr.is_null());
if let Some(static_methods) = members.static_methods { if let Some(static_methods) = members.static_methods {
@ -256,19 +301,13 @@ fn create_interface_object(cx: *mut JSContext,
define_constants(cx, constructor.handle(), constants); define_constants(cx, constructor.handle(), constants);
} }
unsafe {
if !proto.get().is_null() { if !proto.get().is_null() {
assert!(JS_LinkConstructorAndPrototype(cx, constructor.handle(), proto) != 0); assert!(JS_LinkConstructorAndPrototype(cx, constructor.handle(), proto) != 0);
} }
let mut already_defined = 0;
assert!(JS_AlreadyHasOwnProperty(cx, receiver, name, &mut already_defined) != 0);
if already_defined == 0 {
assert!(JS_DefineProperty1(cx, receiver, name,
constructor.handle(),
0, None, None) != 0);
}
} }
define_constructor(cx, receiver, name, constructor.handle());
} }
/// Defines constants on `obj`. /// Defines constants on `obj`.