Bug 838691 part 2. Add codegen support for calling a function to determine whether a property should be exposed in a WebIDL binding. r=peterv

This commit is contained in:
Boris Zbarsky 2013-02-19 11:54:40 -05:00
parent 5cee1946fc
commit 09220020af

View File

@ -999,6 +999,27 @@ class CGClassHasInstanceHook(CGAbstractStaticMethod):
def isChromeOnly(m): def isChromeOnly(m):
return m.getExtendedAttribute("ChromeOnly") return m.getExtendedAttribute("ChromeOnly")
class MemberCondition:
"""
An object representing the condition for a member to actually be
exposed. Either pref or func or both can be None. If not None,
they should be strings that have the pref name or function name.
"""
def __init__(self, pref, func):
assert pref is None or isinstance(pref, str)
assert func is None or isinstance(func, str)
self.pref = pref
if func is None:
self.func = "nullptr"
else:
self.func = "&" + func
def __eq__(self, other):
return self.pref == other.pref and self.func == other.func
def __ne__(self, other):
return not self.__eq__(other)
class PropertyDefiner: class PropertyDefiner:
""" """
A common superclass for defining things on prototype objects. A common superclass for defining things on prototype objects.
@ -1042,17 +1063,24 @@ class PropertyDefiner:
return str return str
@staticmethod @staticmethod
def getControllingPref(interfaceMember): def getStringAttr(member, name):
prefName = interfaceMember.getExtendedAttribute("Pref") attr = member.getExtendedAttribute(name)
if prefName is None: if attr is None:
return None return None
# It's a list of strings # It's a list of strings
assert(len(prefName) is 1) assert(len(attr) is 1)
assert(prefName[0] is not None) assert(attr[0] is not None)
return prefName[0] return attr[0]
@staticmethod
def getControllingCondition(interfaceMember):
return MemberCondition(PropertyDefiner.getStringAttr(interfaceMember,
"Pref"),
PropertyDefiner.getStringAttr(interfaceMember,
"Func"))
def generatePrefableArray(self, array, name, specTemplate, specTerminator, def generatePrefableArray(self, array, name, specTemplate, specTerminator,
specType, getPref, getDataTuple, doIdArrays): specType, getCondition, getDataTuple, doIdArrays):
""" """
This method generates our various arrays. This method generates our various arrays.
@ -1067,8 +1095,8 @@ class PropertyDefiner:
specType is the actual typename of our spec specType is the actual typename of our spec
getPref is a callback function that takes an array entry and returns getCondition is a callback function that takes an array entry and
the corresponding pref value. returns the corresponding MemberCondition.
getDataTuple is a callback function that takes an array entry and getDataTuple is a callback function that takes an array entry and
returns a tuple suitable for substitution into specTemplate. returns a tuple suitable for substitution into specTemplate.
@ -1081,34 +1109,35 @@ class PropertyDefiner:
# pref control is added to members while still allowing us to define all # pref control is added to members while still allowing us to define all
# the members in the smallest number of JSAPI calls. # the members in the smallest number of JSAPI calls.
assert(len(array) is not 0) assert(len(array) is not 0)
lastPref = getPref(array[0]) # So we won't put a specTerminator lastCondition = getCondition(array[0]) # So we won't put a specTerminator
# at the very front of the list. # at the very front of the list.
specs = [] specs = []
prefableSpecs = [] prefableSpecs = []
prefableTemplate = ' { true, nullptr, &%s[%d] }' prefableTemplate = ' { true, %s, &%s[%d] }'
prefCacheTemplate = '&%s[%d].enabled' prefCacheTemplate = '&%s[%d].enabled'
def switchToPref(props, pref): def switchToCondition(props, condition):
# Remember the info about where our pref-controlled # Remember the info about where our pref-controlled
# booleans live. # booleans live.
if pref is not None: if condition.pref is not None:
props.prefCacheData.append( props.prefCacheData.append(
(pref, prefCacheTemplate % (name, len(prefableSpecs))) (condition.pref,
prefCacheTemplate % (name, len(prefableSpecs)))
) )
# Set up pointers to the new sets of specs inside prefableSpecs # Set up pointers to the new sets of specs inside prefableSpecs
prefableSpecs.append(prefableTemplate % prefableSpecs.append(prefableTemplate %
(name + "_specs", len(specs))) (condition.func, name + "_specs", len(specs)))
switchToPref(self, lastPref) switchToCondition(self, lastCondition)
for member in array: for member in array:
curPref = getPref(member) curCondition = getCondition(member)
if lastPref != curPref: if lastCondition != curCondition:
# Terminate previous list # Terminate previous list
specs.append(specTerminator) specs.append(specTerminator)
# And switch to our new pref # And switch to our new pref
switchToPref(self, curPref) switchToCondition(self, curCondition)
lastPref = curPref lastCondition = curCondition
# And the actual spec # And the actual spec
specs.append(specTemplate % getDataTuple(member)) specs.append(specTemplate % getDataTuple(member))
specs.append(specTerminator) specs.append(specTerminator)
@ -1162,7 +1191,7 @@ class MethodDefiner(PropertyDefiner):
"methodInfo": not m.isStatic(), "methodInfo": not m.isStatic(),
"length": methodLength(m), "length": methodLength(m),
"flags": "JSPROP_ENUMERATE", "flags": "JSPROP_ENUMERATE",
"pref": PropertyDefiner.getControllingPref(m) } "condition": PropertyDefiner.getControllingCondition(m) }
if isChromeOnly(m): if isChromeOnly(m):
self.chrome.append(method) self.chrome.append(method)
else: else:
@ -1175,7 +1204,7 @@ class MethodDefiner(PropertyDefiner):
"nativeName": "JS_ArrayIterator", "nativeName": "JS_ArrayIterator",
"length": 0, "length": 0,
"flags": "JSPROP_ENUMERATE", "flags": "JSPROP_ENUMERATE",
"pref": None }) "condition": MemberCondition(None, None) })
if (not descriptor.interface.parent and not static and if (not descriptor.interface.parent and not static and
descriptor.nativeOwnership == 'nsisupports' and descriptor.nativeOwnership == 'nsisupports' and
@ -1184,7 +1213,7 @@ class MethodDefiner(PropertyDefiner):
"methodInfo": False, "methodInfo": False,
"length": 1, "length": 1,
"flags": "0", "flags": "0",
"pref": None }) "condition": MemberCondition(None, None) })
if not static: if not static:
stringifier = descriptor.operations['Stringifier'] stringifier = descriptor.operations['Stringifier']
@ -1193,7 +1222,7 @@ class MethodDefiner(PropertyDefiner):
"nativeName": stringifier.identifier.name, "nativeName": stringifier.identifier.name,
"length": 0, "length": 0,
"flags": "JSPROP_ENUMERATE", "flags": "JSPROP_ENUMERATE",
"pref": PropertyDefiner.getControllingPref(stringifier) } "condition": PropertyDefiner.getControllingCondition(stringifier) }
if isChromeOnly(stringifier): if isChromeOnly(stringifier):
self.chrome.append(toStringDesc) self.chrome.append(toStringDesc)
else: else:
@ -1212,8 +1241,8 @@ class MethodDefiner(PropertyDefiner):
if len(array) == 0: if len(array) == 0:
return "" return ""
def pref(m): def condition(m):
return m["pref"] return m["condition"]
def specData(m): def specData(m):
accessor = m.get("nativeName", m["name"]) accessor = m.get("nativeName", m["name"])
@ -1229,7 +1258,7 @@ class MethodDefiner(PropertyDefiner):
' JS_FNINFO("%s", %s, %s, %s, %s)', ' JS_FNINFO("%s", %s, %s, %s, %s)',
' JS_FS_END', ' JS_FS_END',
'JSFunctionSpec', 'JSFunctionSpec',
pref, specData, doIdArrays) condition, specData, doIdArrays)
class AttrDefiner(PropertyDefiner): class AttrDefiner(PropertyDefiner):
def __init__(self, descriptor, name, static, unforgeable=False): def __init__(self, descriptor, name, static, unforgeable=False):
@ -1304,7 +1333,7 @@ class AttrDefiner(PropertyDefiner):
' { "%s", 0, %s, %s, %s}', ' { "%s", 0, %s, %s, %s}',
' { 0, 0, 0, JSOP_NULLWRAPPER, JSOP_NULLWRAPPER }', ' { 0, 0, 0, JSOP_NULLWRAPPER, JSOP_NULLWRAPPER }',
'JSPropertySpec', 'JSPropertySpec',
PropertyDefiner.getControllingPref, specData, doIdArrays) PropertyDefiner.getControllingCondition, specData, doIdArrays)
class ConstDefiner(PropertyDefiner): class ConstDefiner(PropertyDefiner):
""" """
@ -1330,7 +1359,7 @@ class ConstDefiner(PropertyDefiner):
' { "%s", %s }', ' { "%s", %s }',
' { 0, JSVAL_VOID }', ' { 0, JSVAL_VOID }',
'ConstantSpec', 'ConstantSpec',
PropertyDefiner.getControllingPref, specData, doIdArrays) PropertyDefiner.getControllingCondition, specData, doIdArrays)
class PropertyArrays(): class PropertyArrays():
def __init__(self, descriptor): def __init__(self, descriptor):