mirror of
https://github.com/servo/servo.git
synced 2025-07-24 15:50:21 +01:00
Implement WebIDL namespaces
This commit is contained in:
parent
8ba0cf30a1
commit
0b689a8a31
5 changed files with 123 additions and 30 deletions
|
@ -26,6 +26,7 @@ from WebIDL import (
|
|||
)
|
||||
|
||||
from Configuration import (
|
||||
MakeNativeName,
|
||||
MemberIsUnforgeable,
|
||||
getModuleFromObject,
|
||||
getTypesFromCallback,
|
||||
|
@ -80,7 +81,7 @@ def toStringBool(arg):
|
|||
|
||||
|
||||
def toBindingNamespace(arg):
|
||||
return re.sub("((_workers)?$)", "Binding\\1", arg)
|
||||
return re.sub("((_workers)?$)", "Binding\\1", MakeNativeName(arg))
|
||||
|
||||
|
||||
def stripTrailingWhitespace(text):
|
||||
|
@ -96,9 +97,6 @@ def innerSequenceType(type):
|
|||
return type.inner.inner if type.nullable() else type.inner
|
||||
|
||||
|
||||
def MakeNativeName(name):
|
||||
return name[0].upper() + name[1:]
|
||||
|
||||
builtinNames = {
|
||||
IDLType.Tags.bool: 'bool',
|
||||
IDLType.Tags.int8: 'i8',
|
||||
|
@ -1811,7 +1809,8 @@ class CGImports(CGWrapper):
|
|||
|
||||
def isImportable(type):
|
||||
if not type.isType():
|
||||
assert type.isInterface() or type.isDictionary() or type.isEnum()
|
||||
assert (type.isInterface() or type.isDictionary() or
|
||||
type.isEnum() or type.isNamespace())
|
||||
return True
|
||||
return not (type.builtin or type.isSequence() or type.isUnion())
|
||||
|
||||
|
@ -1830,7 +1829,7 @@ class CGImports(CGWrapper):
|
|||
if t.isCallback():
|
||||
return t.callback.identifier
|
||||
return t.identifier
|
||||
assert t.isInterface() or t.isDictionary() or t.isEnum()
|
||||
assert t.isInterface() or t.isDictionary() or t.isEnum() or t.isNamespace()
|
||||
return t.identifier
|
||||
|
||||
def removeWrapperAndNullableTypes(types):
|
||||
|
@ -1881,7 +1880,7 @@ class CGImports(CGWrapper):
|
|||
# Importing these types in the same module that defines them is an error.
|
||||
if t in dictionaries or t in enums:
|
||||
continue
|
||||
if t.isInterface():
|
||||
if t.isInterface() or t.isNamespace():
|
||||
descriptor = descriptorProvider.getDescriptor(getIdentifier(t).name)
|
||||
extras += [descriptor.path]
|
||||
if descriptor.interface.parent:
|
||||
|
@ -2060,6 +2059,17 @@ class CGInterfaceObjectJSClass(CGThing):
|
|||
self.descriptor = descriptor
|
||||
|
||||
def define(self):
|
||||
if self.descriptor.interface.isNamespace():
|
||||
classString = self.descriptor.interface.getExtendedAttribute("ClassString")
|
||||
if classString:
|
||||
classString = classString[0]
|
||||
else:
|
||||
classString = "Object"
|
||||
return """\
|
||||
static NAMESPACE_OBJECT_CLASS: NamespaceObjectClass = unsafe {
|
||||
NamespaceObjectClass::new(%s)
|
||||
};
|
||||
""" % str_to_const_array(classString)
|
||||
if self.descriptor.interface.ctor():
|
||||
constructorBehavior = "InterfaceConstructorBehavior::call(%s)" % CONSTRUCT_HOOK_NAME
|
||||
else:
|
||||
|
@ -2657,6 +2667,28 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
|
|||
|
||||
def definition_body(self):
|
||||
name = self.descriptor.interface.identifier.name
|
||||
if self.descriptor.interface.isNamespace():
|
||||
if self.descriptor.interface.getExtendedAttribute("ProtoObjectHack"):
|
||||
proto = "JS_GetObjectPrototype(cx, global)"
|
||||
else:
|
||||
proto = "JS_NewPlainObject(cx)"
|
||||
if self.properties.static_methods.length():
|
||||
methods = self.properties.static_methods.variableName()
|
||||
else:
|
||||
methods = "&[]"
|
||||
return CGGeneric("""\
|
||||
rooted!(in(cx) let proto = %(proto)s);
|
||||
assert!(!proto.is_null());
|
||||
rooted!(in(cx) let mut namespace = ptr::null_mut());
|
||||
create_namespace_object(cx, global, proto.handle(), &NAMESPACE_OBJECT_CLASS,
|
||||
%(methods)s, %(name)s, namespace.handle_mut());
|
||||
assert!(!namespace.is_null());
|
||||
assert!((*cache)[PrototypeList::Constructor::%(id)s as usize].is_null());
|
||||
(*cache)[PrototypeList::Constructor::%(id)s as usize] = namespace.get();
|
||||
<*mut JSObject>::post_barrier((*cache).as_mut_ptr().offset(PrototypeList::Constructor::%(id)s as isize),
|
||||
ptr::null_mut(),
|
||||
namespace.get());
|
||||
""" % {"id": MakeNativeName(name), "methods": methods, "name": str_to_const_array(name), "proto": proto})
|
||||
if self.descriptor.interface.isCallback():
|
||||
assert not self.descriptor.interface.ctor() and self.descriptor.interface.hasConstants()
|
||||
return CGGeneric("""\
|
||||
|
@ -2871,7 +2903,7 @@ class CGGetPerInterfaceObject(CGAbstractMethod):
|
|||
Argument('MutableHandleObject', 'rval')]
|
||||
CGAbstractMethod.__init__(self, descriptor, name,
|
||||
'void', args, pub=pub, unsafe=True)
|
||||
self.id = idPrefix + "::" + self.descriptor.name
|
||||
self.id = idPrefix + "::" + MakeNativeName(self.descriptor.name)
|
||||
|
||||
def definition_body(self):
|
||||
return CGGeneric("""
|
||||
|
@ -3014,7 +3046,7 @@ class CGDefineDOMInterfaceMethod(CGAbstractMethod):
|
|||
return CGAbstractMethod.define(self)
|
||||
|
||||
def definition_body(self):
|
||||
if self.descriptor.interface.isCallback():
|
||||
if self.descriptor.interface.isCallback() or self.descriptor.interface.isNamespace():
|
||||
function = "GetConstructorObject"
|
||||
else:
|
||||
function = "GetProtoObject"
|
||||
|
@ -3074,7 +3106,7 @@ class CGCallGenerator(CGThing):
|
|||
|
||||
call = CGGeneric(nativeMethodName)
|
||||
if static:
|
||||
call = CGWrapper(call, pre="%s::" % descriptor.interface.identifier.name)
|
||||
call = CGWrapper(call, pre="%s::" % MakeNativeName(descriptor.interface.identifier.name))
|
||||
else:
|
||||
call = CGWrapper(call, pre="%s." % object)
|
||||
call = CGList([call, CGWrapper(args, pre="(", post=")")])
|
||||
|
@ -5452,6 +5484,8 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries
|
|||
'dom::bindings::js::OptionalRootedReference',
|
||||
'dom::bindings::js::Root',
|
||||
'dom::bindings::js::RootedReference',
|
||||
'dom::bindings::namespace::NamespaceObjectClass',
|
||||
'dom::bindings::namespace::create_namespace_object',
|
||||
'dom::bindings::reflector::MutReflectable',
|
||||
'dom::bindings::reflector::Reflectable',
|
||||
'dom::bindings::utils::DOMClass',
|
||||
|
@ -5559,7 +5593,7 @@ class CGDescriptor(CGThing):
|
|||
return name
|
||||
|
||||
cgThings = []
|
||||
if not descriptor.interface.isCallback():
|
||||
if not descriptor.interface.isCallback() and not descriptor.interface.isNamespace():
|
||||
cgThings.append(CGGetProtoObjectMethod(descriptor))
|
||||
reexports.append('GetProtoObject')
|
||||
if (descriptor.interface.hasInterfaceObject() and
|
||||
|
@ -5620,7 +5654,7 @@ class CGDescriptor(CGThing):
|
|||
if not descriptor.interface.isCallback():
|
||||
cgThings.append(CGInterfaceObjectJSClass(descriptor))
|
||||
|
||||
if not descriptor.interface.isCallback():
|
||||
if not descriptor.interface.isCallback() and not descriptor.interface.isNamespace():
|
||||
cgThings.append(CGPrototypeJSClass(descriptor))
|
||||
|
||||
# If there are no constant members, don't make a module for constants
|
||||
|
@ -5677,7 +5711,7 @@ class CGDescriptor(CGThing):
|
|||
reexports.append('Wrap')
|
||||
|
||||
haveUnscopables = False
|
||||
if not descriptor.interface.isCallback():
|
||||
if not descriptor.interface.isCallback() and not descriptor.interface.isNamespace():
|
||||
if unscopableNames:
|
||||
haveUnscopables = True
|
||||
cgThings.append(
|
||||
|
@ -5704,7 +5738,7 @@ class CGDescriptor(CGThing):
|
|||
cgThings, public=True),
|
||||
post='\n')
|
||||
reexports = ', '.join(map(lambda name: reexportedName(name), reexports))
|
||||
self.cgRoot = CGList([CGGeneric('pub use self::%sBinding::{%s};' % (descriptor.name, reexports)),
|
||||
self.cgRoot = CGList([CGGeneric('pub use self::%s::{%s};' % (toBindingNamespace(descriptor.name), reexports)),
|
||||
cgThings], '\n')
|
||||
|
||||
def define(self):
|
||||
|
@ -6758,10 +6792,12 @@ class GlobalGenRoots():
|
|||
@staticmethod
|
||||
def PrototypeList(config):
|
||||
# Prototype ID enum.
|
||||
interfaces = config.getDescriptors(isCallback=False)
|
||||
interfaces = config.getDescriptors(isCallback=False, isNamespace=False)
|
||||
protos = [d.name for d in interfaces]
|
||||
constructors = [d.name for d in config.getDescriptors(hasInterfaceObject=True)
|
||||
if d.shouldHaveGetConstructorObjectMethod()]
|
||||
constructors = sorted([MakeNativeName(d.name)
|
||||
for d in config.getDescriptors(hasInterfaceObject=True)
|
||||
if d.shouldHaveGetConstructorObjectMethod()])
|
||||
|
||||
proxies = [d.name for d in config.getDescriptors(proxy=True)]
|
||||
|
||||
return CGList([
|
||||
|
@ -6798,10 +6834,13 @@ class GlobalGenRoots():
|
|||
|
||||
@staticmethod
|
||||
def InterfaceTypes(config):
|
||||
descriptors = [d.name for d in config.getDescriptors(register=True,
|
||||
descriptors = sorted([MakeNativeName(d.name)
|
||||
for d in config.getDescriptors(register=True,
|
||||
isCallback=False,
|
||||
isIteratorInterface=False)]
|
||||
curr = CGList([CGGeneric("pub use dom::%s::%s;\n" % (name.lower(), name)) for name in descriptors])
|
||||
isIteratorInterface=False)])
|
||||
curr = CGList([CGGeneric("pub use dom::%s::%s;\n" % (name.lower(),
|
||||
MakeNativeName(name)))
|
||||
for name in descriptors])
|
||||
curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
|
||||
return curr
|
||||
|
||||
|
@ -6812,7 +6851,7 @@ class GlobalGenRoots():
|
|||
return getModuleFromObject(d).split('::')[-1]
|
||||
|
||||
descriptors = config.getDescriptors(register=True, isIteratorInterface=False)
|
||||
descriptors = (set(d.name + "Binding" for d in descriptors) |
|
||||
descriptors = (set(toBindingNamespace(d.name) for d in descriptors) |
|
||||
set(leafModule(d) for d in config.callbacks) |
|
||||
set(leafModule(d) for d in config.getDictionaries()))
|
||||
curr = CGList([CGGeneric("pub mod %s;\n" % name) for name in sorted(descriptors)])
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
import os
|
||||
|
||||
from WebIDL import IDLExternalInterface, IDLInterface, IDLWrapperType, WebIDLError
|
||||
from WebIDL import IDLExternalInterface, IDLWrapperType, WebIDLError
|
||||
|
||||
|
||||
class Configuration:
|
||||
|
@ -30,10 +30,9 @@ class Configuration:
|
|||
raise WebIDLError("Servo does not support external interfaces.",
|
||||
[thing.location])
|
||||
|
||||
# Some toplevel things are sadly types, and those have an
|
||||
# isInterface that doesn't mean the same thing as IDLObject's
|
||||
# isInterface()...
|
||||
if not isinstance(thing, IDLInterface):
|
||||
assert not thing.isType()
|
||||
|
||||
if not thing.isInterface() and not thing.isNamespace():
|
||||
continue
|
||||
|
||||
iface = thing
|
||||
|
@ -83,6 +82,8 @@ class Configuration:
|
|||
getter = lambda x: x.interface.hasInterfaceObject()
|
||||
elif key == 'isCallback':
|
||||
getter = lambda x: x.interface.isCallback()
|
||||
elif key == 'isNamespace':
|
||||
getter = lambda x: x.interface.isNamespace()
|
||||
elif key == 'isJSImplemented':
|
||||
getter = lambda x: x.interface.isJSImplemented()
|
||||
elif key == 'isGlobal':
|
||||
|
@ -210,7 +211,7 @@ class Descriptor(DescriptorProvider):
|
|||
if self.interface.isIteratorInterface():
|
||||
pathDefault = 'dom::bindings::iterable::IterableIterator'
|
||||
else:
|
||||
pathDefault = 'dom::types::%s' % typeName
|
||||
pathDefault = 'dom::types::%s' % MakeNativeName(typeName)
|
||||
|
||||
self.concreteType = typeName
|
||||
self.register = desc.get('register', True)
|
||||
|
@ -223,6 +224,7 @@ class Descriptor(DescriptorProvider):
|
|||
# If we're concrete, we need to crawl our ancestor interfaces and mark
|
||||
# them as having a concrete descendant.
|
||||
self.concrete = (not self.interface.isCallback() and
|
||||
not self.interface.isNamespace() and
|
||||
not self.interface.getExtendedAttribute("Abstract"))
|
||||
self.hasUnforgeableMembers = (self.concrete and
|
||||
any(MemberIsUnforgeable(m, self) for m in
|
||||
|
@ -381,7 +383,7 @@ class Descriptor(DescriptorProvider):
|
|||
|
||||
def shouldHaveGetConstructorObjectMethod(self):
|
||||
assert self.interface.hasInterfaceObject()
|
||||
return self.interface.isCallback() or self.hasDescendants()
|
||||
return self.interface.isCallback() or self.interface.isNamespace() or self.hasDescendants()
|
||||
|
||||
def isExposedConditionally(self):
|
||||
return self.interface.isExposedConditionally()
|
||||
|
@ -396,6 +398,12 @@ class Descriptor(DescriptorProvider):
|
|||
|
||||
|
||||
# Some utility methods
|
||||
|
||||
|
||||
def MakeNativeName(name):
|
||||
return name[0].upper() + name[1:]
|
||||
|
||||
|
||||
def getModuleFromObject(object):
|
||||
return ('dom::bindings::codegen::Bindings::' +
|
||||
os.path.basename(object.location.filename()).split('.webidl')[0] + 'Binding')
|
||||
|
|
|
@ -257,7 +257,8 @@ pub unsafe fn create_named_constructors(
|
|||
}
|
||||
}
|
||||
|
||||
unsafe fn create_object(
|
||||
/// Create a new object with a unique type.
|
||||
pub unsafe fn create_object(
|
||||
cx: *mut JSContext,
|
||||
proto: HandleObject,
|
||||
class: &'static JSClass,
|
||||
|
@ -316,7 +317,9 @@ pub unsafe fn is_exposed_in(object: HandleObject, globals: Globals) -> bool {
|
|||
globals.contains(dom_class.global)
|
||||
}
|
||||
|
||||
unsafe fn define_on_global_object(
|
||||
/// Define a property with a given name on the global object. Should be called
|
||||
/// through the resolve hook.
|
||||
pub unsafe fn define_on_global_object(
|
||||
cx: *mut JSContext,
|
||||
global: HandleObject,
|
||||
name: &[u8],
|
||||
|
|
|
@ -140,6 +140,7 @@ pub mod inheritance;
|
|||
pub mod interface;
|
||||
pub mod iterable;
|
||||
pub mod js;
|
||||
pub mod namespace;
|
||||
pub mod num;
|
||||
pub mod proxyhandler;
|
||||
pub mod refcounted;
|
||||
|
|
42
components/script/dom/bindings/namespace.rs
Normal file
42
components/script/dom/bindings/namespace.rs
Normal file
|
@ -0,0 +1,42 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
//! Machinery to initialise namespace objects.
|
||||
|
||||
use dom::bindings::guard::Guard;
|
||||
use dom::bindings::interface::{create_object, define_on_global_object};
|
||||
use js::jsapi::{HandleObject, JSClass, JSContext, JSFunctionSpec, MutableHandleObject};
|
||||
use libc;
|
||||
use std::ptr;
|
||||
|
||||
/// The class of a namespace object.
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct NamespaceObjectClass(JSClass);
|
||||
|
||||
unsafe impl Sync for NamespaceObjectClass {}
|
||||
|
||||
impl NamespaceObjectClass {
|
||||
/// Create a new `NamespaceObjectClass` structure.
|
||||
pub const unsafe fn new(name: &'static [u8]) -> Self {
|
||||
NamespaceObjectClass(JSClass {
|
||||
name: name as *const _ as *const libc::c_char,
|
||||
flags: 0,
|
||||
cOps: ptr::null_mut(),
|
||||
reserved: [ptr::null_mut(); 3],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new namespace object.
|
||||
pub unsafe fn create_namespace_object(
|
||||
cx: *mut JSContext,
|
||||
global: HandleObject,
|
||||
proto: HandleObject,
|
||||
class: &'static NamespaceObjectClass,
|
||||
methods: &[Guard<&'static [JSFunctionSpec]>],
|
||||
name: &[u8],
|
||||
rval: MutableHandleObject) {
|
||||
create_object(cx, proto, &class.0, methods, &[], &[], rval);
|
||||
define_on_global_object(cx, global, name, rval.handle());
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue