From a03db46d27605e8f3281d023c79b29c361aadaad Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Sun, 22 Jun 2014 15:55:10 +0200 Subject: [PATCH] servo: Merge #2699 - Implement static IDL members; r=jdm (from Ms2ger:static-methods) Source-Repo: https://github.com/servo/servo Source-Revision: edba815cf5330294061c1f9a560785c6466f6f3f --- .../dom/bindings/codegen/CodegenRust.py | 223 ++++++++++++++---- .../components/script/dom/bindings/utils.rs | 6 + .../src/components/script/dom/testbinding.rs | 6 + .../script/dom/webidls/TestBinding.webidl | 3 + 4 files changed, 194 insertions(+), 44 deletions(-) diff --git a/servo/src/components/script/dom/bindings/codegen/CodegenRust.py b/servo/src/components/script/dom/bindings/codegen/CodegenRust.py index 69bf5c87335e..7e4af465f9e8 100644 --- a/servo/src/components/script/dom/bindings/codegen/CodegenRust.py +++ b/servo/src/components/script/dom/bindings/codegen/CodegenRust.py @@ -1126,6 +1126,7 @@ class MethodDefiner(PropertyDefiner): m.isMethod() and m.isStatic() == static and not m.isIdentifierLess()] self.regular = [{"name": m.identifier.name, + "methodInfo": not m.isStatic(), "length": methodLength(m), "flags": "JSPROP_ENUMERATE" } for m in methods] @@ -1164,10 +1165,15 @@ class MethodDefiner(PropertyDefiner): specData) class AttrDefiner(PropertyDefiner): - def __init__(self, descriptor, name): + def __init__(self, descriptor, name, static): PropertyDefiner.__init__(self, descriptor, name) self.name = name - self.regular = [m for m in descriptor.interface.members if m.isAttr()] + self.regular = [ + m + for m in descriptor.interface.members + if m.isAttr() and m.isStatic() == static + ] + self.static = static def generateArray(self, array, name): if len(array) == 0: @@ -1177,20 +1183,37 @@ class AttrDefiner(PropertyDefiner): return "JSPROP_SHARED | JSPROP_ENUMERATE | JSPROP_NATIVE_ACCESSORS" def getter(attr): - native = ("genericLenientGetter" if attr.hasLenientThis() - else "genericGetter") - return ("JSPropertyOpWrapper {op: Some(%(native)s), info: &%(name)s_getterinfo as *JSJitInfo}" - % {"name" : attr.identifier.name, - "native" : native}) + if self.static: + accessor = 'get_' + attr.identifier.name + jitinfo = "0" + else: + if attr.hasLenientThis(): + accessor = "genericLenientGetter" + else: + accessor = "genericGetter" + jitinfo = "&%s_getterinfo" % attr.identifier.name + + return ("JSPropertyOpWrapper {op: Some(%(native)s), info: %(info)s as *JSJitInfo}" + % {"info" : jitinfo, + "native" : accessor}) def setter(attr): if attr.readonly: return "JSStrictPropertyOpWrapper {op: None, info: 0 as *JSJitInfo}" - native = ("genericLenientSetter" if attr.hasLenientThis() - else "genericSetter") - return ("JSStrictPropertyOpWrapper {op: Some(%(native)s), info: &%(name)s_setterinfo as *JSJitInfo}" - % {"name" : attr.identifier.name, - "native" : native}) + + if self.static: + accessor = 'set_' + attr.identifier.name + jitinfo = "0" + else: + if attr.hasLenientThis(): + accessor = "genericLenientSetter" + else: + accessor = "genericSetter" + jitinfo = "&%s_setterinfo" % attr.identifier.name + + return ("JSStrictPropertyOpWrapper {op: Some(%(native)s), info: %(info)s as *JSJitInfo}" + % {"info" : jitinfo, + "native" : accessor}) def specData(attr): return (attr.identifier.name, flags(attr), getter(attr), @@ -1833,15 +1856,18 @@ class CGAbstractExternMethod(CGAbstractMethod): class PropertyArrays(): def __init__(self, descriptor): - self.staticMethods = MethodDefiner(descriptor, "StaticMethods", True) - self.methods = MethodDefiner(descriptor, "Methods", False) - self.attrs = AttrDefiner(descriptor, "Attributes") + self.staticMethods = MethodDefiner(descriptor, "StaticMethods", + static=True) + self.staticAttrs = AttrDefiner(descriptor, "StaticAttributes", + static=True) + self.methods = MethodDefiner(descriptor, "Methods", static=False) + self.attrs = AttrDefiner(descriptor, "Attributes", static=False) self.consts = ConstDefiner(descriptor, "Constants") pass @staticmethod def arrayNames(): - return [ "staticMethods", "methods", "attrs", "consts" ] + return [ "staticMethods", "staticAttrs", "methods", "attrs", "consts" ] def variableNames(self): names = {} @@ -2292,7 +2318,7 @@ class CGGetterCall(CGPerSignatureCall): """ def __init__(self, argsPre, returnType, nativeMethodName, descriptor, attr): CGPerSignatureCall.__init__(self, returnType, argsPre, [], - nativeMethodName, False, descriptor, + nativeMethodName, attr.isStatic(), descriptor, attr, getter=True) class FakeArgument(): @@ -2321,7 +2347,7 @@ class CGSetterCall(CGPerSignatureCall): def __init__(self, argsPre, argType, nativeMethodName, descriptor, attr): CGPerSignatureCall.__init__(self, None, argsPre, [FakeArgument(argType, attr, allowTreatNonObjectAsNull=True)], - nativeMethodName, False, descriptor, attr, + nativeMethodName, attr.isStatic(), descriptor, attr, setter=True) def wrap_return_value(self): # We have no return value @@ -2368,6 +2394,30 @@ class CGAbstractBindingMethod(CGAbstractExternMethod): def generate_code(self): assert(False) # Override me + +class CGAbstractStaticBindingMethod(CGAbstractMethod): + """ + Common class to generate the JSNatives for all our static methods, getters + and setters. This will generate the function declaration and unwrap the + global object. Subclasses are expected to override the generate_code + function to do the rest of the work. This function should return a + CGThing which is already properly indented. + """ + def __init__(self, descriptor, name): + args = [ + Argument('*mut JSContext', 'cx'), + Argument('libc::c_uint', 'argc'), + Argument('*mut JSVal', 'vp'), + ] + CGAbstractMethod.__init__(self, descriptor, name, "JSBool", args, extern=True) + + def definition_body(self): + return self.generate_code() + + def generate_code(self): + assert False # Override me + + class CGGenericMethod(CGAbstractBindingMethod): """ A class for generating the C++ code for an IDL method.. @@ -2396,12 +2446,32 @@ class CGSpecializedMethod(CGAbstractExternMethod): CGAbstractExternMethod.__init__(self, descriptor, name, 'JSBool', args) def definition_body(self): - name = self.method.identifier.name - return CGWrapper(CGMethodCall([], MakeNativeName(name), self.method.isStatic(), + nativeName = CGSpecializedMethod.makeNativeName(self.descriptor, + self.method) + return CGWrapper(CGMethodCall([], nativeName, self.method.isStatic(), self.descriptor, self.method), pre="let this = JS::from_raw(this);\n" "let mut this = this.root();\n") + @staticmethod + def makeNativeName(descriptor, method): + return MakeNativeName(method.identifier.name) + +class CGStaticMethod(CGAbstractStaticBindingMethod): + """ + A class for generating the Rust code for an IDL static method. + """ + def __init__(self, descriptor, method): + self.method = method + name = method.identifier.name + CGAbstractStaticBindingMethod.__init__(self, descriptor, name) + + def generate_code(self): + nativeName = CGSpecializedMethod.makeNativeName(self.descriptor, + self.method) + return CGMethodCall([], nativeName, True, self.descriptor, self.method) + + class CGGenericGetter(CGAbstractBindingMethod): """ A class for generating the C++ code for an IDL attribute getter. @@ -2441,18 +2511,41 @@ class CGSpecializedGetter(CGAbstractExternMethod): CGAbstractExternMethod.__init__(self, descriptor, name, "JSBool", args) def definition_body(self): - name = self.attr.identifier.name - nativeName = MakeNativeName(name) - infallible = ('infallible' in - self.descriptor.getExtendedAttributes(self.attr, - getter=True)) - if self.attr.type.nullable() or not infallible: - nativeName = "Get" + nativeName + nativeName = CGSpecializedGetter.makeNativeName(self.descriptor, + self.attr) + return CGWrapper(CGGetterCall([], self.attr.type, nativeName, self.descriptor, self.attr), pre="let this = JS::from_raw(this);\n" "let mut this = this.root();\n") + @staticmethod + def makeNativeName(descriptor, attr): + nativeName = MakeNativeName(attr.identifier.name) + infallible = ('infallible' in + descriptor.getExtendedAttributes(attr, getter=True)) + if attr.type.nullable() or not infallible: + return "Get" + nativeName + + return nativeName + + +class CGStaticGetter(CGAbstractStaticBindingMethod): + """ + A class for generating the C++ code for an IDL static attribute getter. + """ + def __init__(self, descriptor, attr): + self.attr = attr + name = 'get_' + attr.identifier.name + CGAbstractStaticBindingMethod.__init__(self, descriptor, name) + + def generate_code(self): + nativeName = CGSpecializedGetter.makeNativeName(self.descriptor, + self.attr) + return CGGetterCall([], self.attr.type, nativeName, self.descriptor, + self.attr) + + class CGGenericSetter(CGAbstractBindingMethod): """ A class for generating the Rust code for an IDL attribute setter. @@ -2497,13 +2590,40 @@ class CGSpecializedSetter(CGAbstractExternMethod): CGAbstractExternMethod.__init__(self, descriptor, name, "JSBool", args) def definition_body(self): - name = self.attr.identifier.name - return CGWrapper(CGSetterCall([], self.attr.type, - "Set" + MakeNativeName(name), + nativeName = CGSpecializedSetter.makeNativeName(self.descriptor, + self.attr) + return CGWrapper(CGSetterCall([], self.attr.type, nativeName, self.descriptor, self.attr), pre="let this = JS::from_raw(this);\n" "let mut this = this.root();\n") + @staticmethod + def makeNativeName(descriptor, attr): + return "Set" + MakeNativeName(attr.identifier.name) + + +class CGStaticSetter(CGAbstractStaticBindingMethod): + """ + A class for generating the C++ code for an IDL static attribute setter. + """ + def __init__(self, descriptor, attr): + self.attr = attr + name = 'set_' + attr.identifier.name + CGAbstractStaticBindingMethod.__init__(self, descriptor, name) + + def generate_code(self): + nativeName = CGSpecializedSetter.makeNativeName(self.descriptor, + self.attr) + checkForArg = CGGeneric( + "let argv = JS_ARGV(cx, vp);\n" + "if (argc == 0) {\n" + " // XXXjdmreturn ThrowErrorMessage(cx, MSG_MISSING_ARGUMENTS, \"%s setter\");\n" + " return 0;\n" + "}\n" % self.attr.identifier.name) + call = CGSetterCall([], self.attr.type, nativeName, self.descriptor, + self.attr) + return CGList([checkForArg, call]) + class CGMemberJITInfo(CGThing): """ @@ -3835,23 +3955,38 @@ class CGDescriptor(CGThing): (hasMethod, hasGetter, hasLenientGetter, hasSetter, hasLenientSetter) = False, False, False, False, False for m in descriptor.interface.members: - if m.isMethod() and not m.isStatic() and not m.isIdentifierLess(): - cgThings.append(CGSpecializedMethod(descriptor, m)) - cgThings.append(CGMemberJITInfo(descriptor, m)) - hasMethod = True + if m.isMethod() and not m.isIdentifierLess(): + if m.isStatic(): + assert descriptor.interface.hasInterfaceObject() + cgThings.append(CGStaticMethod(descriptor, m)) + elif descriptor.interface.hasInterfacePrototypeObject(): + cgThings.append(CGSpecializedMethod(descriptor, m)) + cgThings.append(CGMemberJITInfo(descriptor, m)) + hasMethod = True elif m.isAttr(): - cgThings.append(CGSpecializedGetter(descriptor, m)) - if m.hasLenientThis(): - hasLenientGetter = True - else: - hasGetter = True - if not m.readonly: - cgThings.append(CGSpecializedSetter(descriptor, m)) + if m.isStatic(): + assert descriptor.interface.hasInterfaceObject() + cgThings.append(CGStaticGetter(descriptor, m)) + elif descriptor.interface.hasInterfacePrototypeObject(): + cgThings.append(CGSpecializedGetter(descriptor, m)) if m.hasLenientThis(): - hasLenientSetter = True + hasLenientGetter = True else: - hasSetter = True - cgThings.append(CGMemberJITInfo(descriptor, m)) + hasGetter = True + + if not m.readonly: + if m.isStatic(): + assert descriptor.interface.hasInterfaceObject() + cgThings.append(CGStaticSetter(descriptor, m)) + elif descriptor.interface.hasInterfacePrototypeObject(): + cgThings.append(CGSpecializedSetter(descriptor, m)) + if m.hasLenientThis(): + hasLenientSetter = True + else: + hasSetter = True + + if not m.isStatic() and descriptor.interface.hasInterfacePrototypeObject(): + cgThings.append(CGMemberJITInfo(descriptor, m)) if hasMethod: cgThings.append(CGGenericMethod(descriptor)) if hasGetter: diff --git a/servo/src/components/script/dom/bindings/utils.rs b/servo/src/components/script/dom/bindings/utils.rs index d9be42433d9e..370b34f048ac 100644 --- a/servo/src/components/script/dom/bindings/utils.rs +++ b/servo/src/components/script/dom/bindings/utils.rs @@ -220,6 +220,7 @@ pub struct NativeProperties { pub attrs: Option<&'static [JSPropertySpec]>, pub consts: Option<&'static [ConstantSpec]>, pub staticMethods: Option<&'static [JSFunctionSpec]>, + pub staticAttrs: Option<&'static [JSPropertySpec]>, } pub type NonNullJSNative = @@ -271,6 +272,11 @@ fn CreateInterfaceObject(cx: *mut JSContext, global: *mut JSObject, receiver: *m _ => (), } + match members.staticAttrs { + Some(staticProperties) => DefineProperties(cx, constructor, staticProperties), + _ => (), + } + match members.consts { Some(constants) => DefineConstants(cx, constructor, constants), _ => (), diff --git a/servo/src/components/script/dom/testbinding.rs b/servo/src/components/script/dom/testbinding.rs index d4826d881b9e..72d2f68dd88f 100644 --- a/servo/src/components/script/dom/testbinding.rs +++ b/servo/src/components/script/dom/testbinding.rs @@ -296,6 +296,12 @@ impl<'a> TestBindingMethods for JSRef<'a, TestBinding> { } } +impl TestBinding { + pub fn BooleanAttributeStatic() -> bool { false } + pub fn SetBooleanAttributeStatic(_: bool) {} + pub fn ReceiveVoidStatic() {} +} + impl Reflectable for TestBinding { fn reflector<'a>(&'a self) -> &'a Reflector { &self.reflector diff --git a/servo/src/components/script/dom/webidls/TestBinding.webidl b/servo/src/components/script/dom/webidls/TestBinding.webidl index 2437514a2c1d..deae80744e8e 100644 --- a/servo/src/components/script/dom/webidls/TestBinding.webidl +++ b/servo/src/components/script/dom/webidls/TestBinding.webidl @@ -266,4 +266,7 @@ interface TestBinding { void passVariadicUnion2((Event or DOMString)... args); void passVariadicUnion3((Blob or DOMString)... args); void passVariadicAny(any... args); + + static attribute boolean booleanAttributeStatic; + static void receiveVoidStatic(); };