Bug 1454591 part 1 - Generate more structured data in ServoCSSPropList.py. r=heycam

This patch changes ServoCSSPropList.py to use classes for properties.
This allows extending the data in the file without needing to update all
users of this file.

Sorting in GenerateCSSPropsGenerated.py is removed because the data file
has the right order already.

MozReview-Commit-ID: D74bItCfpPH

--HG--
extra : rebase_source : e0138c255f77515f491496fcb8680686362f4e9e
This commit is contained in:
Xidorn Quan 2018-05-04 13:44:51 +10:00
parent 3b95cfc89e
commit 7db648bdec
6 changed files with 110 additions and 101 deletions

View File

@ -10,6 +10,7 @@ This information is used to generate the properties-db.js file.
import json
import os
import runpy
import sys
import string
import subprocess
@ -53,15 +54,12 @@ class MachCommands(MachCommandBase):
# The data takes the following form:
# [ (name, prop, id, flags, pref, proptype), ... ]
dataPath = resolve_path(self.topobjdir, 'layout/style/ServoCSSPropList.py')
with open(dataPath, "r") as f:
data = eval(f.read())
data = runpy.run_path(dataPath)['data']
# Map this list
# (name, prop, id, flags, pref, proptype) => (name, pref)
preferences = [
(name, pref)
for name, prop, id, flags, pref, proptype in data
if 'CSSPropFlags::Internal' not in flags and pref]
(p.name, p.pref) for p in data
if 'CSSPropFlags::Internal' not in p.flags and p.pref]
return preferences

View File

@ -5,6 +5,7 @@
import sys
import string
import argparse
import runpy
# Generates a line of WebIDL with the given spelling of the property name
# (whether camelCase, _underscorePrefixed, etc.) and the given array of
@ -13,18 +14,19 @@ def generateLine(propName, extendedAttrs):
return " [%s] attribute DOMString %s;\n" % (", ".join(extendedAttrs),
propName)
def generate(output, idlFilename, dataFile):
with open(dataFile, "r") as f:
propList = eval(f.read())
propList = runpy.run_path(dataFile)["data"]
props = ""
for name, prop, id, flags, pref, proptype in propList:
if "CSSPropFlags::Internal" in flags:
for p in propList:
if "CSSPropFlags::Internal" in p.flags:
continue
# Unfortunately, even some of the getters here are fallible
# (e.g. on nsComputedDOMStyle).
extendedAttrs = ["CEReactions", "Throws", "TreatNullAs=EmptyString",
"SetterNeedsSubjectPrincipal=NonSystem"]
if pref is not "":
extendedAttrs.append('Pref="%s"' % pref)
if p.pref is not "":
extendedAttrs.append('Pref="%s"' % p.pref)
prop = p.method
# webkit properties get a camelcase "webkitFoo" accessor
# as well as a capitalized "WebkitFoo" alias (added here).
@ -52,8 +54,8 @@ def generate(output, idlFilename, dataFile):
# cover (3) and all of (1) except "float". If we now add an alias
# for all the cases where "name" doesn't match "prop", that will cover
# "float" and (2).
if prop != name:
extendedAttrs.append('BindingAlias="%s"' % name)
if prop != p.name:
extendedAttrs.append('BindingAlias="%s"' % p.name)
props += generateLine(prop, extendedAttrs)

View File

@ -2,30 +2,30 @@
# 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/.
import runpy
import string
def generate(output, template, dataFile):
with open(template, "r") as f:
template = string.Template(f.read())
with open(dataFile, "r") as f:
data = eval(f.read())
data = runpy.run_path(dataFile)["data"]
longhand_count = 0
shorthand_count = 0
alias_count = 0
property_ids = []
for name, method, id, flags, pref, prototype in data:
if prototype != "alias":
if prototype == "longhand":
for prop in data:
if prop.type() != "alias":
if prop.type() == "longhand":
assert shorthand_count == 0
longhand_count += 1
else:
assert alias_count == 0
shorthand_count += 1
property_ids.append("eCSSProperty_{}".format(id))
property_ids.append("eCSSProperty_{}".format(prop.id))
else:
alias_count += 1
property_ids.append("eCSSPropertyAlias_{}".format(id[0]))
property_ids.append("eCSSPropertyAlias_{}".format(prop.alias_id))
output.write("/* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT */\n\n")
output.write(template.substitute({

View File

@ -2,75 +2,66 @@
# 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/.
import runpy
import sys
import string
import argparse
def get_properties(dataFile):
with open(dataFile, "r") as f:
properties = eval(f.read())
properties = [{"name":p[0], "prop":p[1], "id":p[2],
"flags":p[3], "pref":p[4], "proptype":p[5]}
for (i, p) in enumerate(properties)]
class PropertyWrapper(object):
__slots__ = ["index", "prop", "idlname"]
# Sort the list so that longhand properties are intermingled first,
# shorthand properties follow, then aliases appear last.
# This matches the order of the nsCSSPropertyID enum.
def property_compare(x, y):
property_order = {"longhand": 0, "shorthand": 1, "alias": 2}
return property_order[x["proptype"]] - property_order[y["proptype"]]
properties = sorted(properties, cmp=property_compare)
for i, p in enumerate(properties):
p["index"] = i
# Record each property's IDL name.
for p in properties:
if "CSSPropFlags::Internal" in p["flags"]:
p["idlname"] = None
def __init__(self, index, prop):
self.index = index
self.prop = prop
if "CSSPropFlags::Internal" in prop.flags:
self.idlname = None
else:
idl_name = p["prop"]
idl_name = prop.method
if not idl_name.startswith("Moz"):
idl_name = idl_name[0].lower() + idl_name[1:]
p["idlname"] = idl_name
self.idlname = idl_name
return properties
def __getattr__(self, name):
return getattr(self.prop, name)
def get_properties(dataFile):
properties = runpy.run_path(dataFile)["data"]
return [PropertyWrapper(i, p) for i, p in enumerate(properties)]
def generate_idl_names(properties):
names = []
for p in properties:
if p["proptype"] is "alias":
if p.type() == "alias":
continue
if p["idlname"] is None:
names.append(" nullptr, // %s" % p["name"])
if p.idlname is None:
names.append(" nullptr, // %s" % p.name)
else:
names.append(' "%s",' % p["idlname"])
names.append(' "%s",' % p.idlname)
return "\n".join(names)
def generate_assertions(properties):
def enum(p):
if p["proptype"] is "alias":
return "eCSSPropertyAlias_%s" % p["id"][0]
if p.type() == "alias":
return "eCSSPropertyAlias_%s" % p.alias_id
else:
return "eCSSProperty_%s" % p["id"]
return "eCSSProperty_%s" % p.id
msg = ('static_assert(%s == %d, "GenerateCSSPropsGenerated.py did not list '
'properties in nsCSSPropertyID order");')
return "\n".join(map(lambda p: msg % (enum(p), p["index"]), properties))
return "\n".join(map(lambda p: msg % (enum(p), p.index), properties))
def generate_idl_name_positions(properties):
# Skip aliases.
ps = filter(lambda p: p["proptype"] is not "alias", properties)
ps = filter(lambda p: p.type() != "alias", properties)
# Sort alphabetically by IDL name.
ps = sorted(ps, key=lambda p: p["idlname"])
ps = sorted(ps, key=lambda p: p.idlname)
# Annotate entries with the sorted position.
ps = [(p, position) for position, p in enumerate(ps)]
# Sort back to nsCSSPropertyID order.
ps = sorted(ps, key=lambda (p, position): p["index"])
ps = sorted(ps, key=lambda (p, position): p.index)
return ",\n".join(map(lambda (p, position): " %d" % position, ps))

View File

@ -5,6 +5,7 @@
import buildconfig
import mozpack.path as mozpath
import os
import runpy
import subprocess
import string
import sys
@ -32,8 +33,7 @@ def generate_data(output, template):
def generate_header(output, data):
with open(data, "r") as f:
data = eval(f.read())
data = runpy.run_path(data)["data"]
output.write("""/* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT */
@ -68,28 +68,29 @@ def generate_header(output, data):
"shorthand": "CSS_PROP_SHORTHAND",
"alias": "CSS_PROP_ALIAS",
}
for name, method, id, flags, pref, proptype in data:
is_internal = "CSSPropFlags::Internal" in flags
pref = '"' + pref + '"'
if proptype == "alias":
params = [name, id[0], id[1], method, pref]
for prop in data:
is_internal = "CSSPropFlags::Internal" in prop.flags
pref = '"' + prop.pref + '"'
if prop.type() == "alias":
params = [prop.name, prop.alias_id, prop.prop_id, prop.method, pref]
else:
method = prop.method
if method == "CssFloat":
method = "CSS_PROP_PUBLIC_OR_PRIVATE(CssFloat, Float)"
elif method.startswith("Moz"):
method = "CSS_PROP_DOMPROP_PREFIXED({})".format(method[3:])
if flags:
flags = " | ".join(flags)
if prop.flags:
flags = " | ".join(prop.flags)
else:
flags = "CSSPropFlags(0)"
params = [name, id, method, flags, pref]
params = [prop.name, prop.id, method, flags, pref]
is_component_of_all = not is_internal and name not in ["direction", "unicode-bidi"]
is_component_of_all = not is_internal and prop.name not in ["direction", "unicode-bidi"]
if not is_component_of_all:
output.write("#ifndef CSS_PROP_LIST_ONLY_COMPONENTS_OF_ALL_SHORTHAND\n")
if is_internal:
output.write("#ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL\n")
output.write("{}({})\n".format(MACRO_NAMES[proptype], ", ".join(params)))
output.write("{}({})\n".format(MACRO_NAMES[prop.type()], ", ".join(params)))
if is_internal:
output.write("#endif\n")
if not is_component_of_all:

View File

@ -2,6 +2,43 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
def _assign_slots(obj, args):
for i, attr in enumerate(obj.__slots__):
setattr(obj, attr, args[i])
class Longhand(object):
__slots__ = ["name", "method", "id", "flags", "pref"]
def __init__(self, *args):
_assign_slots(self, args)
@staticmethod
def type():
return "longhand"
class Shorthand(object):
__slots__ = ["name", "method", "id", "flags", "pref"]
def __init__(self, *args):
_assign_slots(self, args)
@staticmethod
def type():
return "shorthand"
class Alias(object):
__slots__ = ["name", "method", "alias_id", "prop_id", "flags", "pref"]
def __init__(self, *args):
_assign_slots(self, args)
@staticmethod
def type():
return "alias"
<%!
# nsCSSPropertyID of longhands and shorthands is ordered alphabetically
# with vendor prefixes removed. Note that aliases use their alias name
@ -27,6 +64,13 @@ def is_internal(prop):
]
return prop.name in OTHER_INTERNALS
def method(prop):
if prop.name == "float":
return "CssFloat"
if prop.name.startswith("-x-"):
return prop.camel_case[1:]
return prop.camel_case
def flags(prop):
result = []
if prop.explicitly_enabled_in_chrome():
@ -49,43 +93,16 @@ def pref(prop):
return '""'
%>
[
data = [
% for prop in sorted(data.longhands, key=order_key):
(
"${prop.name}",
% if prop.name == "float":
"CssFloat",
% elif prop.name.startswith("-x-"):
"${prop.camel_case[1:]}",
% else:
"${prop.camel_case}",
% endif
"${prop.ident}",
[${flags(prop)}],
${pref(prop)},
"longhand",
),
Longhand("${prop.name}", "${method(prop)}", "${prop.ident}", [${flags(prop)}], ${pref(prop)}),
% endfor
% for prop in sorted(data.shorthands, key=order_key):
(
"${prop.name}",
"${prop.camel_case}",
"${prop.ident}",
[${flags(prop)}],
${pref(prop)},
"shorthand",
),
Shorthand("${prop.name}", "${prop.camel_case}", "${prop.ident}", [${flags(prop)}], ${pref(prop)}),
% endfor
% for prop in sorted(data.all_aliases(), key=lambda x: x.name):
(
"${prop.name}",
"${prop.camel_case}",
("${prop.ident}", "${prop.original.ident}"),
[],
${pref(prop)},
"alias",
),
Alias("${prop.name}", "${prop.camel_case}", "${prop.ident}", "${prop.original.ident}", [], ${pref(prop)}),
% endfor
]