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):
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:
"""
A common superclass for defining things on prototype objects.
@ -1042,17 +1063,24 @@ class PropertyDefiner:
return str
@staticmethod
def getControllingPref(interfaceMember):
prefName = interfaceMember.getExtendedAttribute("Pref")
if prefName is None:
def getStringAttr(member, name):
attr = member.getExtendedAttribute(name)
if attr is None:
return None
# It's a list of strings
assert(len(prefName) is 1)
assert(prefName[0] is not None)
return prefName[0]
assert(len(attr) is 1)
assert(attr[0] is not None)
return attr[0]
@staticmethod
def getControllingCondition(interfaceMember):
return MemberCondition(PropertyDefiner.getStringAttr(interfaceMember,
"Pref"),
PropertyDefiner.getStringAttr(interfaceMember,
"Func"))
def generatePrefableArray(self, array, name, specTemplate, specTerminator,
specType, getPref, getDataTuple, doIdArrays):
specType, getCondition, getDataTuple, doIdArrays):
"""
This method generates our various arrays.
@ -1067,8 +1095,8 @@ class PropertyDefiner:
specType is the actual typename of our spec
getPref is a callback function that takes an array entry and returns
the corresponding pref value.
getCondition is a callback function that takes an array entry and
returns the corresponding MemberCondition.
getDataTuple is a callback function that takes an array entry and
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
# the members in the smallest number of JSAPI calls.
assert(len(array) is not 0)
lastPref = getPref(array[0]) # So we won't put a specTerminator
# at the very front of the list.
lastCondition = getCondition(array[0]) # So we won't put a specTerminator
# at the very front of the list.
specs = []
prefableSpecs = []
prefableTemplate = ' { true, nullptr, &%s[%d] }'
prefableTemplate = ' { true, %s, &%s[%d] }'
prefCacheTemplate = '&%s[%d].enabled'
def switchToPref(props, pref):
def switchToCondition(props, condition):
# Remember the info about where our pref-controlled
# booleans live.
if pref is not None:
if condition.pref is not None:
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
prefableSpecs.append(prefableTemplate %
(name + "_specs", len(specs)))
(condition.func, name + "_specs", len(specs)))
switchToPref(self, lastPref)
switchToCondition(self, lastCondition)
for member in array:
curPref = getPref(member)
if lastPref != curPref:
curCondition = getCondition(member)
if lastCondition != curCondition:
# Terminate previous list
specs.append(specTerminator)
# And switch to our new pref
switchToPref(self, curPref)
lastPref = curPref
switchToCondition(self, curCondition)
lastCondition = curCondition
# And the actual spec
specs.append(specTemplate % getDataTuple(member))
specs.append(specTerminator)
@ -1162,7 +1191,7 @@ class MethodDefiner(PropertyDefiner):
"methodInfo": not m.isStatic(),
"length": methodLength(m),
"flags": "JSPROP_ENUMERATE",
"pref": PropertyDefiner.getControllingPref(m) }
"condition": PropertyDefiner.getControllingCondition(m) }
if isChromeOnly(m):
self.chrome.append(method)
else:
@ -1175,7 +1204,7 @@ class MethodDefiner(PropertyDefiner):
"nativeName": "JS_ArrayIterator",
"length": 0,
"flags": "JSPROP_ENUMERATE",
"pref": None })
"condition": MemberCondition(None, None) })
if (not descriptor.interface.parent and not static and
descriptor.nativeOwnership == 'nsisupports' and
@ -1184,7 +1213,7 @@ class MethodDefiner(PropertyDefiner):
"methodInfo": False,
"length": 1,
"flags": "0",
"pref": None })
"condition": MemberCondition(None, None) })
if not static:
stringifier = descriptor.operations['Stringifier']
@ -1193,7 +1222,7 @@ class MethodDefiner(PropertyDefiner):
"nativeName": stringifier.identifier.name,
"length": 0,
"flags": "JSPROP_ENUMERATE",
"pref": PropertyDefiner.getControllingPref(stringifier) }
"condition": PropertyDefiner.getControllingCondition(stringifier) }
if isChromeOnly(stringifier):
self.chrome.append(toStringDesc)
else:
@ -1212,8 +1241,8 @@ class MethodDefiner(PropertyDefiner):
if len(array) == 0:
return ""
def pref(m):
return m["pref"]
def condition(m):
return m["condition"]
def specData(m):
accessor = m.get("nativeName", m["name"])
@ -1229,7 +1258,7 @@ class MethodDefiner(PropertyDefiner):
' JS_FNINFO("%s", %s, %s, %s, %s)',
' JS_FS_END',
'JSFunctionSpec',
pref, specData, doIdArrays)
condition, specData, doIdArrays)
class AttrDefiner(PropertyDefiner):
def __init__(self, descriptor, name, static, unforgeable=False):
@ -1304,7 +1333,7 @@ class AttrDefiner(PropertyDefiner):
' { "%s", 0, %s, %s, %s}',
' { 0, 0, 0, JSOP_NULLWRAPPER, JSOP_NULLWRAPPER }',
'JSPropertySpec',
PropertyDefiner.getControllingPref, specData, doIdArrays)
PropertyDefiner.getControllingCondition, specData, doIdArrays)
class ConstDefiner(PropertyDefiner):
"""
@ -1330,7 +1359,7 @@ class ConstDefiner(PropertyDefiner):
' { "%s", %s }',
' { 0, JSVAL_VOID }',
'ConstantSpec',
PropertyDefiner.getControllingPref, specData, doIdArrays)
PropertyDefiner.getControllingCondition, specData, doIdArrays)
class PropertyArrays():
def __init__(self, descriptor):