OLD | NEW |
---|---|
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright 2016 The Chromium Authors. All rights reserved. | 2 # Copyright 2016 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 import math | 6 import math |
7 import sys | 7 import sys |
8 | 8 |
9 import json5_generator | 9 import json5_generator |
10 import template_expander | 10 import template_expander |
(...skipping 27 matching lines...) Expand all Loading... | |
38 inherited by this style or set explicitly | 38 inherited by this style or set explicitly |
39 """ | 39 """ |
40 | 40 |
41 # List of required attributes for a field which need to be passed in by | 41 # List of required attributes for a field which need to be passed in by |
42 # keyword arguments | 42 # keyword arguments |
43 REQUIRED_ATTRIBUTES = set([ | 43 REQUIRED_ATTRIBUTES = set([ |
44 # Name of field | 44 # Name of field |
45 'name', | 45 'name', |
46 # Name of property field is for | 46 # Name of property field is for |
47 'property_name', | 47 'property_name', |
48 # Internal field storage type (storage_type_path can be None) | 48 # Affects how the field is generated (keyword, primitive, external) |
meade_UTC10
2017/02/16 00:56:29
You didn't address the comment about how does this
shend
2017/02/16 02:48:58
Pointed to the JSON5. Since the attribute names ar
| |
49 'storage_type', | 49 'template', |
50 'storage_type_path', | 50 # Path to predefined class for overriding generated types. |
51 'type_path', | |
52 # Name of the type (e.g. EClear, int) | |
53 'type_name', | |
51 # Bits needed for storage | 54 # Bits needed for storage |
52 'size', | 55 'size', |
53 # Default value for field | 56 # Default value for field |
54 'default_value', | 57 'default_value', |
55 # Method names | 58 # Method names |
56 'getter_method_name', | 59 'getter_method_name', |
57 'setter_method_name', | 60 'setter_method_name', |
58 'initial_method_name', | 61 'initial_method_name', |
59 'resetter_method_name', | 62 'resetter_method_name', |
60 ]) | 63 ]) |
61 | 64 |
62 def __init__(self, field_family, **kwargs): | 65 def __init__(self, role, **kwargs): |
63 # Values common to all fields | 66 # Values common to all fields |
64 # Set attributes from the keyword arguments | 67 # Set attributes from the keyword arguments |
65 for attrib in Field.REQUIRED_ATTRIBUTES: | 68 for attrib in Field.REQUIRED_ATTRIBUTES: |
66 setattr(self, attrib, kwargs.pop(attrib)) | 69 setattr(self, attrib, kwargs.pop(attrib)) |
67 | 70 |
68 # Field family: one of these must be true | 71 # Field role: one of these must be true |
69 self.is_property = field_family == 'property' | 72 self.is_property = role == 'property' |
70 self.is_inherited_flag = field_family == 'inherited_flag' | 73 self.is_inherited_flag = role == 'inherited_flag' |
71 self.is_nonproperty = field_family == 'nonproperty' | 74 self.is_nonproperty = role == 'nonproperty' |
72 assert (self.is_property, self.is_inherited_flag, self.is_nonproperty).c ount(True) == 1, \ | 75 assert (self.is_property, self.is_inherited_flag, self.is_nonproperty).c ount(True) == 1, \ |
73 'Field family has to be exactly one of: property, inherited_flag, no nproperty' | 76 'Field role has to be exactly one of: property, inherited_flag, nonp roperty' |
74 | 77 |
75 if self.is_property: | 78 if self.is_property: |
76 self.is_inherited = kwargs.pop('inherited') | 79 self.is_inherited = kwargs.pop('inherited') |
77 self.is_independent = kwargs.pop('independent') | 80 self.is_independent = kwargs.pop('independent') |
78 assert self.is_inherited or not self.is_independent, 'Only inherited fields can be independent' | 81 assert self.is_inherited or not self.is_independent, 'Only inherited fields can be independent' |
79 | 82 |
80 self.is_inherited_method_name = kwargs.pop('is_inherited_method_name ') | 83 self.is_inherited_method_name = kwargs.pop('is_inherited_method_name ') |
81 elif self.is_inherited_flag: | 84 elif self.is_inherited_flag: |
82 # Inherited flag-only fields | 85 # Inherited flag-only fields |
83 pass | 86 pass |
84 | 87 |
85 assert len(kwargs) == 0, 'Unexpected arguments provided to Field: ' + st r(kwargs) | 88 assert len(kwargs) == 0, 'Unexpected arguments provided to Field: ' + st r(kwargs) |
86 | 89 |
87 | 90 |
88 def _create_enums(properties): | 91 def _create_enums(properties): |
89 """ | 92 """ |
90 Returns a dictionary of enums to be generated, enum name -> [list of enum va lues] | 93 Returns a dictionary of enums to be generated, enum name -> [list of enum va lues] |
91 """ | 94 """ |
92 enums = {} | 95 enums = {} |
93 for property_ in properties: | 96 for property_ in properties: |
94 # Only generate enums for keyword properties that use the default field_ storage_type. | 97 # Only generate enums for keyword properties that use the default field_ type_path. |
95 if property_['keyword_only'] and property_['field_storage_type'] is None : | 98 if property_['field_template'] == 'keyword' and property_['field_type_pa th'] is None: |
96 enum_name = property_['type_name'] | 99 enum_name = property_['type_name'] |
97 # From the Blink style guide: Enum members should use InterCaps with an initial capital letter. [names-enum-members] | 100 # From the Blink style guide: Enum members should use InterCaps with an initial capital letter. [names-enum-members] |
98 enum_values = [('k' + camel_case(k)) for k in property_['keywords']] | 101 enum_values = [('k' + camel_case(k)) for k in property_['keywords']] |
99 | 102 |
100 if enum_name in enums: | 103 if enum_name in enums: |
101 # There's an enum with the same name, check if the enum values a re the same | 104 # There's an enum with the same name, check if the enum values a re the same |
102 assert set(enums[enum_name]) == set(enum_values), \ | 105 assert set(enums[enum_name]) == set(enum_values), \ |
103 ("'" + property_['name'] + "' can't have type_name '" + enum _name + "' " | 106 ("'" + property_['name'] + "' can't have type_name '" + enum _name + "' " |
104 "because it was used by a previous property, but with a dif ferent set of keywords. " | 107 "because it was used by a previous property, but with a dif ferent set of keywords. " |
105 "Either give it a different name or ensure the keywords are the same.") | 108 "Either give it a different name or ensure the keywords are the same.") |
106 | 109 |
107 enums[enum_name] = enum_values | 110 enums[enum_name] = enum_values |
108 | 111 |
109 return enums | 112 return enums |
110 | 113 |
111 | 114 |
112 def _create_property_field(property_): | 115 def _create_property_field(property_): |
113 """ | 116 """ |
114 Create a property field from a CSS property and return the Field object. | 117 Create a property field from a CSS property and return the Field object. |
115 """ | 118 """ |
116 property_name = property_['name_for_methods'] | 119 property_name = property_['name_for_methods'] |
117 property_name_lower = lower_first(property_name) | 120 property_name_lower = lower_first(property_name) |
118 | 121 |
119 # From the Blink style guide: Other data members should be prefixed by "m_". [names-data-members] | 122 # From the Blink style guide: Other data members should be prefixed by "m_". [names-data-members] |
120 field_name = 'm_' + property_name_lower | 123 field_name = 'm_' + property_name_lower |
121 bits_needed = math.log(len(property_['keywords']), 2) | 124 bits_needed = math.log(len(property_['keywords']), 2) # TODO: implement for non-enums |
122 | 125 |
123 # Separate the type path from the type name, if specified. | 126 # Separate the type path from the type name, if specified. |
124 if property_['field_storage_type']: | 127 if property_['field_type_path']: |
125 type_path = property_['field_storage_type'] | 128 type_path = property_['field_type_path'] |
126 type_name = type_path.split('/')[-1] | 129 type_name = type_path.split('/')[-1] |
127 else: | 130 else: |
131 type_path = None | |
128 type_name = property_['type_name'] | 132 type_name = property_['type_name'] |
129 type_path = None | |
130 | 133 |
131 # For now, the getter name should match the field name. Later, getter names | 134 # For now, the getter name should match the field name. Later, getter names |
132 # will start with an uppercase letter, so if they conflict with the type nam e, | 135 # will start with an uppercase letter, so if they conflict with the type nam e, |
133 # add 'get' to the front. | 136 # add 'get' to the front. |
134 getter_method_name = property_name_lower | 137 getter_method_name = property_name_lower |
135 if type_name == property_name: | 138 if type_name == property_name: |
136 getter_method_name = 'get' + property_name | 139 getter_method_name = 'get' + property_name |
137 | 140 |
138 assert property_['initial_keyword'] is not None, \ | 141 assert property_['initial_keyword'] is not None, \ |
139 ('MakeComputedStyleBase requires an initial keyword for keyword_only val ues, none specified ' | 142 ('MakeComputedStyleBase requires an initial keyword for keyword fields, none specified ' |
140 'for property ' + property_['name']) | 143 'for property ' + property_['name']) |
141 default_value = type_name + '::k' + camel_case(property_['initial_keyword']) | 144 default_value = type_name + '::k' + camel_case(property_['initial_keyword']) |
142 | 145 |
143 # Add the property itself as a member variable. | |
144 return Field( | 146 return Field( |
145 'property', | 147 'property', |
146 name=field_name, | 148 name=field_name, |
147 property_name=property_['name'], | 149 property_name=property_['name'], |
148 inherited=property_['inherited'], | 150 inherited=property_['inherited'], |
149 independent=property_['independent'], | 151 independent=property_['independent'], |
150 storage_type=type_name, | 152 template=property_['field_template'], |
151 storage_type_path=type_path, | 153 type_path=type_path, |
154 type_name=type_name, | |
152 size=int(math.ceil(bits_needed)), | 155 size=int(math.ceil(bits_needed)), |
153 default_value=default_value, | 156 default_value=default_value, |
154 getter_method_name=getter_method_name, | 157 getter_method_name=getter_method_name, |
155 setter_method_name='set' + property_name, | 158 setter_method_name='set' + property_name, |
156 initial_method_name='initial' + property_name, | 159 initial_method_name='initial' + property_name, |
157 resetter_method_name='reset' + property_name, | 160 resetter_method_name='reset' + property_name, |
158 is_inherited_method_name=property_name_lower + 'IsInherited', | 161 is_inherited_method_name=property_name_lower + 'IsInherited', |
159 ) | 162 ) |
160 | 163 |
161 | 164 |
162 def _create_inherited_flag_field(property_): | 165 def _create_inherited_flag_field(property_): |
163 """ | 166 """ |
164 Create the field used for an inheritance fast path from an independent CSS p roperty, | 167 Create the field used for an inheritance fast path from an independent CSS p roperty, |
165 and return the Field object. | 168 and return the Field object. |
166 """ | 169 """ |
167 property_name = property_['name_for_methods'] | 170 property_name = property_['name_for_methods'] |
168 property_name_lower = lower_first(property_name) | 171 property_name_lower = lower_first(property_name) |
169 | 172 |
170 field_name_suffix_upper = property_name + 'IsInherited' | 173 field_name_suffix_upper = property_name + 'IsInherited' |
171 field_name_suffix_lower = property_name_lower + 'IsInherited' | 174 field_name_suffix_lower = property_name_lower + 'IsInherited' |
172 | 175 |
173 return Field( | 176 return Field( |
174 'inherited_flag', | 177 'inherited_flag', |
175 name='m_' + field_name_suffix_lower, | 178 name='m_' + field_name_suffix_lower, |
176 property_name=property_['name'], | 179 property_name=property_['name'], |
177 storage_type='bool', | 180 template='primitive', |
178 storage_type_path=None, | 181 type_path=None, |
182 type_name='bool', | |
179 size=1, | 183 size=1, |
180 default_value='true', | 184 default_value='true', |
181 getter_method_name=field_name_suffix_lower, | 185 getter_method_name=field_name_suffix_lower, |
182 setter_method_name='set' + field_name_suffix_upper, | 186 setter_method_name='set' + field_name_suffix_upper, |
183 initial_method_name='initial' + field_name_suffix_upper, | 187 initial_method_name='initial' + field_name_suffix_upper, |
184 resetter_method_name='reset' + field_name_suffix_upper, | 188 resetter_method_name='reset' + field_name_suffix_upper, |
185 ) | 189 ) |
186 | 190 |
187 | 191 |
188 def _create_nonproperty_field(field_name): | 192 def _create_nonproperty_field(field_name): |
189 """ | 193 """ |
190 Create a nonproperty field from its name and return the Field object. | 194 Create a nonproperty field from its name and return the Field object. |
191 """ | 195 """ |
192 member_name = 'm_' + field_name | 196 member_name = 'm_' + field_name |
193 field_name_upper = upper_first_letter(field_name) | 197 field_name_upper = upper_first_letter(field_name) |
194 | 198 |
195 return Field( | 199 return Field( |
196 'nonproperty', | 200 'nonproperty', |
197 name=member_name, | 201 name=member_name, |
198 property_name=field_name, | 202 property_name=field_name, |
199 storage_type='bool', | 203 template='primitive', |
200 storage_type_path=None, | 204 type_path=None, |
205 type_name='bool', | |
201 size=1, | 206 size=1, |
202 default_value='false', | 207 default_value='false', |
203 getter_method_name=field_name, | 208 getter_method_name=field_name, |
204 setter_method_name='set' + field_name_upper, | 209 setter_method_name='set' + field_name_upper, |
205 initial_method_name='initial' + field_name_upper, | 210 initial_method_name='initial' + field_name_upper, |
206 resetter_method_name='reset' + field_name_upper, | 211 resetter_method_name='reset' + field_name_upper, |
207 ) | 212 ) |
208 | 213 |
209 | 214 |
210 def _create_fields(properties): | 215 def _create_fields(properties): |
211 """ | 216 """ |
212 Create ComputedStyle fields from CSS properties and return a list of Field o bjects. | 217 Create ComputedStyle fields from CSS properties and return a list of Field o bjects. |
213 """ | 218 """ |
214 fields = [] | 219 fields = [] |
215 for property_ in properties: | 220 for property_ in properties: |
216 # Keywords only means we generate an enum field. | 221 # Only generate properties that have a field template |
217 if property_['keyword_only']: | 222 if property_['field_template'] is not None: |
218 # If the property is independent, add the single-bit sized isInherit ed flag | 223 # If the property is independent, add the single-bit sized isInherit ed flag |
219 # to the list of Fields as well. | 224 # to the list of Fields as well. |
220 if property_['independent']: | 225 if property_['independent']: |
221 fields.append(_create_inherited_flag_field(property_)) | 226 fields.append(_create_inherited_flag_field(property_)) |
222 | 227 |
223 fields.append(_create_property_field(property_)) | 228 fields.append(_create_property_field(property_)) |
224 | 229 |
225 for field_name in NONPROPERTY_FIELDS: | 230 for field_name in NONPROPERTY_FIELDS: |
226 fields.append(_create_nonproperty_field(field_name)) | 231 fields.append(_create_nonproperty_field(field_name)) |
227 | 232 |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
328 def generate_base_computed_style_constants(self): | 333 def generate_base_computed_style_constants(self): |
329 return { | 334 return { |
330 'properties': self._properties, | 335 'properties': self._properties, |
331 'enums': self._generated_enums, | 336 'enums': self._generated_enums, |
332 'fields': self._fields, | 337 'fields': self._fields, |
333 'expected_total_field_bytes': self._expected_total_field_bytes, | 338 'expected_total_field_bytes': self._expected_total_field_bytes, |
334 } | 339 } |
335 | 340 |
336 if __name__ == '__main__': | 341 if __name__ == '__main__': |
337 json5_generator.Maker(ComputedStyleBaseWriter).main() | 342 json5_generator.Maker(ComputedStyleBaseWriter).main() |
OLD | NEW |