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 19 matching lines...) Expand all Loading... | |
30 inherited by this style or set explicitly | 30 inherited by this style or set explicitly |
31 """ | 31 """ |
32 | 32 |
33 # List of required attributes for a field which need to be passed in by | 33 # List of required attributes for a field which need to be passed in by |
34 # keyword arguments | 34 # keyword arguments |
35 REQUIRED_ATTRIBUTES = set([ | 35 REQUIRED_ATTRIBUTES = set([ |
36 # Name of field | 36 # Name of field |
37 'name', | 37 'name', |
38 # Name of property field is for | 38 # Name of property field is for |
39 'property_name', | 39 'property_name', |
40 # Internal field storage type (storage_type_path can be None) | 40 # Affects how the field is generated (keyword, primitive, external) |
meade_UTC10
2017/02/13 06:46:24
How does it affect it? What are the valid values?
shend
2017/02/16 02:48:58
Added explanations in the JSON5. Made naming consi
| |
41 'storage_type', | 41 'template', |
42 'storage_type_path', | 42 # Path to predefined class for overriding generated types. |
43 'type_path', | |
44 # Name of the type (e.g. EClear, int) | |
45 'type_name', | |
meade_UTC10
2017/02/13 06:46:24
Could you describe the relationship between these?
shend
2017/02/16 02:48:58
Added comment to refer readers to the JSON5 file,
| |
43 # Bits needed for storage | 46 # Bits needed for storage |
44 'size', | 47 'size', |
45 # Default value for field | 48 # Default value for field |
46 'default_value', | 49 'default_value', |
47 # Method names | 50 # Method names |
48 'getter_method_name', | 51 'getter_method_name', |
49 'setter_method_name', | 52 'setter_method_name', |
50 'initial_method_name', | 53 'initial_method_name', |
51 'resetter_method_name', | 54 'resetter_method_name', |
52 ]) | 55 ]) |
53 | 56 |
54 def __init__(self, field_family, **kwargs): | 57 def __init__(self, role, **kwargs): |
55 # Values common to all fields | 58 # Values common to all fields |
56 # Set attributes from the keyword arguments | 59 # Set attributes from the keyword arguments |
57 for attrib in Field.REQUIRED_ATTRIBUTES: | 60 for attrib in Field.REQUIRED_ATTRIBUTES: |
58 setattr(self, attrib, kwargs.pop(attrib)) | 61 setattr(self, attrib, kwargs.pop(attrib)) |
59 | 62 |
60 # Field family: one of these must be true | 63 # Field role: one of these must be true |
61 self.is_property = field_family == 'property' | 64 self.is_property = role == 'property' |
62 self.is_inherited_flag = field_family == 'inherited_flag' | 65 self.is_inherited_flag = role == 'inherited_flag' |
63 assert (self.is_property, self.is_inherited_flag).count(True) == 1, \ | 66 assert (self.is_property, self.is_inherited_flag).count(True) == 1, \ |
64 'Field family has to be exactly one of: property, inherited_flag' | 67 'Field role has to be exactly one of: property, inherited_flag' |
65 | 68 |
66 if self.is_property: | 69 if self.is_property: |
67 self.is_inherited = kwargs.pop('inherited') | 70 self.is_inherited = kwargs.pop('inherited') |
68 self.is_independent = kwargs.pop('independent') | 71 self.is_independent = kwargs.pop('independent') |
69 assert self.is_inherited or not self.is_independent, 'Only inherited fields can be independent' | 72 assert self.is_inherited or not self.is_independent, 'Only inherited fields can be independent' |
70 | 73 |
71 self.is_inherited_method_name = kwargs.pop('is_inherited_method_name ') | 74 self.is_inherited_method_name = kwargs.pop('is_inherited_method_name ') |
72 elif self.is_inherited_flag: | 75 elif self.is_inherited_flag: |
73 # Inherited flag-only fields | 76 # Inherited flag-only fields |
74 pass | 77 pass |
75 | 78 |
76 assert len(kwargs) == 0, 'Unexpected arguments provided to Field: ' + st r(kwargs) | 79 assert len(kwargs) == 0, 'Unexpected arguments provided to Field: ' + st r(kwargs) |
77 | 80 |
78 | 81 |
79 def _create_enums(properties): | 82 def _create_enums(properties): |
80 """ | 83 """ |
81 Returns a dictionary of enums to be generated, enum name -> [list of enum va lues] | 84 Returns a dictionary of enums to be generated, enum name -> [list of enum va lues] |
82 """ | 85 """ |
83 enums = {} | 86 enums = {} |
84 for property_ in properties: | 87 for property_ in properties: |
85 # Only generate enums for keyword properties that use the default field_ storage_type. | 88 # Only generate enums for keyword properties that use the default field_ type_path. |
86 if property_['keyword_only'] and property_['field_storage_type'] is None : | 89 if property_['field_template'] == 'keyword' and property_['field_type_pa th'] is None: |
87 enum_name = property_['type_name'] | 90 enum_name = property_['type_name'] |
88 # From the Blink style guide: Enum members should use InterCaps with an initial capital letter. [names-enum-members] | 91 # From the Blink style guide: Enum members should use InterCaps with an initial capital letter. [names-enum-members] |
89 enum_values = [('k' + camel_case(k)) for k in property_['keywords']] | 92 enum_values = [('k' + camel_case(k)) for k in property_['keywords']] |
90 | 93 |
91 if enum_name in enums: | 94 if enum_name in enums: |
92 # There's an enum with the same name, check if the enum values a re the same | 95 # There's an enum with the same name, check if the enum values a re the same |
93 assert set(enums[enum_name]) == set(enum_values), \ | 96 assert set(enums[enum_name]) == set(enum_values), \ |
94 ("'" + property_['name'] + "' can't have type_name '" + enum _name + "' " | 97 ("'" + property_['name'] + "' can't have type_name '" + enum _name + "' " |
95 "because it was used by a previous property, but with a dif ferent set of keywords. " | 98 "because it was used by a previous property, but with a dif ferent set of keywords. " |
96 "Either give it a different name or ensure the keywords are the same.") | 99 "Either give it a different name or ensure the keywords are the same.") |
97 | 100 |
98 enums[enum_name] = enum_values | 101 enums[enum_name] = enum_values |
99 | 102 |
100 return enums | 103 return enums |
101 | 104 |
102 | 105 |
103 def _create_property_field(property_): | 106 def _create_property_field(property_): |
104 """ | 107 """ |
105 Create a property field from a CSS property and return the Field object. | 108 Create a property field from a CSS property and return the Field object. |
106 """ | 109 """ |
107 property_name = property_['name_for_methods'] | 110 property_name = property_['name_for_methods'] |
108 property_name_lower = lower_first(property_name) | 111 property_name_lower = lower_first(property_name) |
109 | 112 |
110 # From the Blink style guide: Other data members should be prefixed by "m_". [names-data-members] | 113 # From the Blink style guide: Other data members should be prefixed by "m_". [names-data-members] |
111 field_name = 'm_' + property_name_lower | 114 field_name = 'm_' + property_name_lower |
112 bits_needed = math.log(len(property_['keywords']), 2) | 115 bits_needed = math.log(len(property_['keywords']), 2) # TODO: implement for non-enums |
113 | 116 |
114 # Separate the type path from the type name, if specified. | 117 # Separate the type path from the type name, if specified. |
115 if property_['field_storage_type']: | 118 if property_['field_type_path']: |
116 type_path = property_['field_storage_type'] | 119 type_path = property_['field_type_path'] |
117 type_name = type_path.split('/')[-1] | 120 type_name = type_path.split('/')[-1] |
118 else: | 121 else: |
122 type_path = None | |
119 type_name = property_['type_name'] | 123 type_name = property_['type_name'] |
120 type_path = None | |
121 | 124 |
122 # For now, the getter name should match the field name. Later, getter names | 125 # For now, the getter name should match the field name. Later, getter names |
123 # will start with an uppercase letter, so if they conflict with the type nam e, | 126 # will start with an uppercase letter, so if they conflict with the type nam e, |
124 # add 'get' to the front. | 127 # add 'get' to the front. |
125 getter_method_name = property_name_lower | 128 getter_method_name = property_name_lower |
126 if type_name == property_name: | 129 if type_name == property_name: |
127 getter_method_name = 'get' + property_name | 130 getter_method_name = 'get' + property_name |
128 | 131 |
129 assert property_['initial_keyword'] is not None, \ | 132 assert property_['initial_keyword'] is not None, \ |
130 ('MakeComputedStyleBase requires an initial keyword for keyword_only val ues, none specified ' | 133 ('MakeComputedStyleBase requires an initial keyword for keyword fields, none specified ' |
131 'for property ' + property_['name']) | 134 'for property ' + property_['name']) |
132 default_value = type_name + '::k' + camel_case(property_['initial_keyword']) | 135 default_value = type_name + '::k' + camel_case(property_['initial_keyword']) |
133 | 136 |
134 # Add the property itself as a member variable. | |
135 return Field( | 137 return Field( |
136 'property', | 138 'property', |
137 name=field_name, | 139 name=field_name, |
138 property_name=property_['name'], | 140 property_name=property_['name'], |
139 inherited=property_['inherited'], | 141 inherited=property_['inherited'], |
140 independent=property_['independent'], | 142 independent=property_['independent'], |
141 storage_type=type_name, | 143 template=property_['field_template'], |
142 storage_type_path=type_path, | 144 type_path=type_path, |
145 type_name=type_name, | |
143 size=int(math.ceil(bits_needed)), | 146 size=int(math.ceil(bits_needed)), |
144 default_value=default_value, | 147 default_value=default_value, |
145 getter_method_name=getter_method_name, | 148 getter_method_name=getter_method_name, |
146 setter_method_name='set' + property_name, | 149 setter_method_name='set' + property_name, |
147 initial_method_name='initial' + property_name, | 150 initial_method_name='initial' + property_name, |
148 resetter_method_name='reset' + property_name, | 151 resetter_method_name='reset' + property_name, |
149 is_inherited_method_name=property_name_lower + 'IsInherited', | 152 is_inherited_method_name=property_name_lower + 'IsInherited', |
150 ) | 153 ) |
151 | 154 |
152 | 155 |
153 def _create_inherited_flag_field(property_): | 156 def _create_inherited_flag_field(property_): |
154 """ | 157 """ |
155 Create the field used for an inheritance fast path from an independent CSS p roperty, | 158 Create the field used for an inheritance fast path from an independent CSS p roperty, |
156 and return the Field object. | 159 and return the Field object. |
157 """ | 160 """ |
158 property_name = property_['name_for_methods'] | 161 property_name = property_['name_for_methods'] |
159 property_name_lower = lower_first(property_name) | 162 property_name_lower = lower_first(property_name) |
160 | 163 |
161 field_name_suffix_upper = property_name + 'IsInherited' | 164 field_name_suffix_upper = property_name + 'IsInherited' |
162 field_name_suffix_lower = property_name_lower + 'IsInherited' | 165 field_name_suffix_lower = property_name_lower + 'IsInherited' |
163 | 166 |
164 return Field( | 167 return Field( |
165 'inherited_flag', | 168 'inherited_flag', |
166 name='m_' + field_name_suffix_lower, | 169 name='m_' + field_name_suffix_lower, |
167 property_name=property_['name'], | 170 property_name=property_['name'], |
168 storage_type='bool', | 171 template='primitive', |
169 storage_type_path=None, | 172 type_path=None, |
173 type_name='bool', | |
170 size=1, | 174 size=1, |
171 default_value='true', | 175 default_value='true', |
172 getter_method_name=field_name_suffix_lower, | 176 getter_method_name=field_name_suffix_lower, |
173 setter_method_name='set' + field_name_suffix_upper, | 177 setter_method_name='set' + field_name_suffix_upper, |
174 initial_method_name='initial' + field_name_suffix_upper, | 178 initial_method_name='initial' + field_name_suffix_upper, |
175 resetter_method_name='reset' + field_name_suffix_upper, | 179 resetter_method_name='reset' + field_name_suffix_upper, |
176 ) | 180 ) |
177 | 181 |
178 | 182 |
179 def _create_fields(properties): | 183 def _create_fields(properties): |
180 """ | 184 """ |
181 Create ComputedStyle fields from CSS properties and return a list of Field o bjects. | 185 Create ComputedStyle fields from CSS properties and return a list of Field o bjects. |
182 """ | 186 """ |
183 fields = [] | 187 fields = [] |
184 for property_ in properties: | 188 for property_ in properties: |
185 # Keywords only means we generate an enum field. | 189 # Only generate properties that have a field type |
186 if property_['keyword_only']: | 190 if property_['field_template'] is not None: |
187 # If the property is independent, add the single-bit sized isInherit ed flag | 191 # If the property is independent, add the single-bit sized isInherit ed flag |
188 # to the list of Fields as well. | 192 # to the list of Fields as well. |
189 if property_['independent']: | 193 if property_['independent']: |
190 fields.append(_create_inherited_flag_field(property_)) | 194 fields.append(_create_inherited_flag_field(property_)) |
191 | 195 |
192 fields.append(_create_property_field(property_)) | 196 fields.append(_create_property_field(property_)) |
193 | 197 |
194 return fields | 198 return fields |
195 | 199 |
196 | 200 |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
294 def generate_base_computed_style_constants(self): | 298 def generate_base_computed_style_constants(self): |
295 return { | 299 return { |
296 'properties': self._properties, | 300 'properties': self._properties, |
297 'enums': self._generated_enums, | 301 'enums': self._generated_enums, |
298 'fields': self._fields, | 302 'fields': self._fields, |
299 'expected_total_field_bytes': self._expected_total_field_bytes, | 303 'expected_total_field_bytes': self._expected_total_field_bytes, |
300 } | 304 } |
301 | 305 |
302 if __name__ == '__main__': | 306 if __name__ == '__main__': |
303 json5_generator.Maker(ComputedStyleBaseWriter).main() | 307 json5_generator.Maker(ComputedStyleBaseWriter).main() |
OLD | NEW |